From 1851d5c80c77bf7b20e0d48c732f28ac7f0668f9 Mon Sep 17 00:00:00 2001 From: robonen Date: Fri, 15 Aug 2025 04:33:47 +0700 Subject: [PATCH 1/4] feat(web/vue): add unrefElement function and tests for element handling --- .../composables/unrefElement/index.test.ts | 61 +++++++++++++++++++ web/vue/src/composables/unrefElement/index.ts | 15 +++++ 2 files changed, 76 insertions(+) create mode 100644 web/vue/src/composables/unrefElement/index.test.ts create mode 100644 web/vue/src/composables/unrefElement/index.ts diff --git a/web/vue/src/composables/unrefElement/index.test.ts b/web/vue/src/composables/unrefElement/index.test.ts new file mode 100644 index 0000000..5e247e0 --- /dev/null +++ b/web/vue/src/composables/unrefElement/index.test.ts @@ -0,0 +1,61 @@ +import { describe, expect, it } from 'vitest'; +import { computed, defineComponent, nextTick, ref, shallowRef } from 'vue'; +import { mount } from '@vue/test-utils' +import { unrefElement } from '.'; + +describe('unrefElement', () => { + it('returns a plain element when passed a raw element', () => { + const htmlEl = document.createElement('div'); + const svgEl = document.createElementNS('http://www.w3.org/2000/svg', 'svg'); + + expect(unrefElement(htmlEl)).toBe(htmlEl); + expect(unrefElement(svgEl)).toBe(svgEl); + }); + + it('returns element when passed a ref or shallowRef to an element', () => { + const el = document.createElement('div'); + const elRef = ref(el); + const shallowElRef = shallowRef(el); + + expect(unrefElement(elRef)).toBe(el); + expect(unrefElement(shallowElRef)).toBe(el); + }); + + it('returns element when passed a computed ref or getter function', () => { + const el = document.createElement('div'); + const computedElRef = computed(() => el); + const elGetter = () => el; + + expect(unrefElement(computedElRef)).toBe(el); + expect(unrefElement(elGetter)).toBe(el); + }); + + it('returns component $el when passed a component instance', async () => { + const Child = defineComponent({ + template: `child`, + }); + + const Parent = defineComponent({ + components: { Child }, + template: ``, + }); + + const wrapper = mount(Parent); + await nextTick(); + + const childInstance = (wrapper.vm as any).$refs.childRef; + const result = unrefElement(childInstance); + + expect(result).toBe(childInstance.$el); + expect((result as HTMLElement).classList.contains('child-el')).toBe(true); + }); + + it('handles null and undefined values', () => { + expect(unrefElement(undefined)).toBe(undefined); + expect(unrefElement(null)).toBe(null); + expect(unrefElement(ref(null))).toBe(null); + expect(unrefElement(ref(undefined))).toBe(undefined); + expect(unrefElement(() => null)).toBe(null); + expect(unrefElement(() => undefined)).toBe(undefined); + }); +}); diff --git a/web/vue/src/composables/unrefElement/index.ts b/web/vue/src/composables/unrefElement/index.ts new file mode 100644 index 0000000..d750541 --- /dev/null +++ b/web/vue/src/composables/unrefElement/index.ts @@ -0,0 +1,15 @@ +import type { ComponentPublicInstance, MaybeRef, MaybeRefOrGetter } from 'vue'; +import { toValue } from 'vue'; + +export type VueInstance = ComponentPublicInstance; +export type MaybeElement = HTMLElement | SVGElement | VueInstance | undefined | null; + +export type MaybeElementRef = MaybeRef; +export type MaybeComputedElementRef = MaybeRefOrGetter; + +export type UnRefElementReturn = T extends VueInstance ? Exclude : T | undefined; + +export function unrefElement(elRef: MaybeComputedElementRef): UnRefElementReturn { + const plain = toValue(elRef); + return (plain as VueInstance)?.$el ?? plain; +} \ No newline at end of file From e035d1abcaa5f404297251dad50a78fa063e5128 Mon Sep 17 00:00:00 2001 From: robonen Date: Fri, 15 Aug 2025 04:37:58 +0700 Subject: [PATCH 2/4] docs(web/vue): update documentation for unrefElement function --- web/vue/src/composables/unrefElement/index.ts | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/web/vue/src/composables/unrefElement/index.ts b/web/vue/src/composables/unrefElement/index.ts index d750541..3089e63 100644 --- a/web/vue/src/composables/unrefElement/index.ts +++ b/web/vue/src/composables/unrefElement/index.ts @@ -9,6 +9,24 @@ export type MaybeComputedElementRef = Ma export type UnRefElementReturn = T extends VueInstance ? Exclude : T | undefined; +/** + * @name unrefElement + * @category Components + * @description Unwraps a Vue element reference to get the underlying instance or DOM element. + * + * @param {MaybeComputedElementRef} elRef - The element reference to unwrap. + * @returns {UnRefElementReturn} - The unwrapped element or undefined. + * + * @example + * const element = useTemplateRef('element'); + * const result = unrefElement(element); // result is the element instance + * + * @example + * const component = useTemplateRef('component'); + * const result = unrefElement(component); // result is the component instance + * + * @since 0.0.11 + */ export function unrefElement(elRef: MaybeComputedElementRef): UnRefElementReturn { const plain = toValue(elRef); return (plain as VueInstance)?.$el ?? plain; From 0cfdce7456dd57dc503c01cc6496f5cfa98bd3e3 Mon Sep 17 00:00:00 2001 From: robonen Date: Fri, 15 Aug 2025 04:38:46 +0700 Subject: [PATCH 3/4] docs(web/vue): update examples in unrefElement documentation to include type parameters --- web/vue/src/composables/unrefElement/index.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/web/vue/src/composables/unrefElement/index.ts b/web/vue/src/composables/unrefElement/index.ts index 3089e63..2cca254 100644 --- a/web/vue/src/composables/unrefElement/index.ts +++ b/web/vue/src/composables/unrefElement/index.ts @@ -18,11 +18,11 @@ export type UnRefElementReturn = T extend * @returns {UnRefElementReturn} - The unwrapped element or undefined. * * @example - * const element = useTemplateRef('element'); + * const element = useTemplateRef('element'); * const result = unrefElement(element); // result is the element instance * * @example - * const component = useTemplateRef('component'); + * const component = useTemplateRef('component'); * const result = unrefElement(component); // result is the component instance * * @since 0.0.11 From 48a85dbae23edba49fb6c2353aa31ec526b3231f Mon Sep 17 00:00:00 2001 From: robonen Date: Fri, 15 Aug 2025 04:39:37 +0700 Subject: [PATCH 4/4] build(web/vue): bump version to 0.0.11 --- web/vue/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/web/vue/package.json b/web/vue/package.json index f6da998..6db9ad4 100644 --- a/web/vue/package.json +++ b/web/vue/package.json @@ -1,6 +1,6 @@ { "name": "@robonen/vue", - "version": "0.0.10", + "version": "0.0.11", "license": "Apache-2.0", "description": "Collection of powerful tools for Vue", "keywords": [