Skip to content

Commit

Permalink
feat: add dynamic root to useQuerySelector
Browse files Browse the repository at this point in the history
  • Loading branch information
F0rsaken committed Aug 29, 2024
1 parent d532f9d commit 92c51e3
Show file tree
Hide file tree
Showing 15 changed files with 178 additions and 139 deletions.
2 changes: 1 addition & 1 deletion docs/guide/built-in/use-element-ref.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# Use Element Ref

Returns `OveeRef` with elements instance, matching `ref="..."` value.
Returns `OveeRef` with elements instance, matching `ref="..."` value. It only will search for refs inside a component.

::: code-group
```ts [MyComponent.ts]
Expand Down
10 changes: 8 additions & 2 deletions docs/guide/built-in/use-query-selector.md
Original file line number Diff line number Diff line change
@@ -1,13 +1,17 @@
# Use Query Selector

Returns an Ovee Ref, which reactively tracks an element, that matches the used selector. If an element is modified, those changes will be reflected.
# Single Element

Returns an Ovee Ref, which reactively tracks an element, that matches the used selector. If an element is modified, those changes will be reflected. It optionally accepts a dynamic root, against which the query will be run. Root can be a plain value, a getter function or a computed.

```ts
import { useQuerySelector } from 'ovee.js'

export const MyComponent = defineComponent(() => {
const header = document.querySelector('header')
const submitButton = useQuerySelector('.my-component__submit')
const audio = useQuerySelector<HTMLAudioElement>('audio')
const burger = useQuerySelector('.heading__burger', header)

onMounted(() => {
audio.value?.play()
Expand All @@ -17,14 +21,16 @@ export const MyComponent = defineComponent(() => {

## Multiple Elements

If you want to match the selector against multiple components.
If you want to match the selector against multiple elements. It also accepts optional a dynamic root.

```ts
import { useQuerySelectorAll } from 'ovee.js'

export const MyComponent = defineComponent((_, { on }) => {
const header = () => document.querySelector('header')
const inputs = useQuerySelectorAll('input')
const headings = useQuerySelectorAll('h2')
const links = useQuerySelectorAll('.header__link', header)

watchEffect(() => {
console.log(`headings amount: ${headings.value.length}`)
Expand Down
25 changes: 12 additions & 13 deletions packages/ovee/src/composables/utils/useAttribute.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { ref } from '@vue/reactivity';
import { computed, Ref, ref } from '@vue/reactivity';

import { injectComponentContext } from '@/core';
import { Logger } from '@/errors';
Expand All @@ -12,7 +12,6 @@ import {
isNil,
isString,
ObjectNotationMapValues,
OveeRef,
} from '@/utils';

import { onMounted, onUnmounted } from '../hooks';
Expand All @@ -24,7 +23,7 @@ const logger = new Logger('useAttribute');
export function useAttribute<Keys extends Record<string, ObjectNotationMapValues>>(
keys: Keys
): {
[Key in keyof Keys]: OveeRef<
[Key in keyof Keys]: Ref<
Keys[Key] extends AttributeMap
? ReturnType<Keys[Key]['get']>
: Keys[Key] extends AttributeMapType
Expand All @@ -35,26 +34,26 @@ export function useAttribute<Keys extends Record<string, ObjectNotationMapValues

export function useAttribute<Keys extends string[]>(
keys: [...Keys]
): { [Key in keyof Keys]: OveeRef<string | null> };
): { [Key in keyof Keys]: Ref<string | null> };

export function useAttribute(key: string): OveeRef<string | null>;
export function useAttribute(key: string): Ref<string | null>;

export function useAttribute<Type>(key: string, map: AttributeMap<Type>): OveeRef<Type>;
export function useAttribute<Type>(key: string, map: AttributeMap<Type>): Ref<Type>;
export function useAttribute<MapType extends AttributeMapType>(
key: string,
map: MapType
): OveeRef<GetTypeFromMapType<MapType>>;
): Ref<GetTypeFromMapType<MapType>>;

export function useAttribute(
key: string | string[] | Record<string, ObjectNotationMapValues>,
_map?: AttributeMap | AttributeMapType
): OveeRef<any> | OveeRef<any>[] | Record<string, OveeRef<any>> {
): Ref<any> | Ref<any>[] | Record<string, Ref<any>> {
const instance = injectComponentContext(true);

if (!instance) {
logger.warn(getNoContextWarning('useAttribute'));

return { value: null };
return ref(null);
}

if (Array.isArray(key)) {
Expand All @@ -76,14 +75,14 @@ export function useAttribute(
// TODO: log warning that there is no map
const map = typeof _map === 'string' ? attributeMaps[_map] : _map;
const cachedValue = ref();
const attributeRef: OveeRef<string | null> = {
get value() {
const attributeRef = computed<string | null>({
get() {
updateAttributeValue();

return cachedValue.value;
},

set value(v: string | null) {
set(v) {
const value = map ? map.set(v) : v;

if (isNil(value)) {
Expand All @@ -92,7 +91,7 @@ export function useAttribute(
instance.element.setAttribute(key, value);
}
},
};
});

const { observe, disconnect } = attachAttributeObserver(key, () => {
updateAttributeValue();
Expand Down
25 changes: 12 additions & 13 deletions packages/ovee/src/composables/utils/useDataAttr.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { ref } from '@vue/reactivity';
import { computed, Ref, ref } from '@vue/reactivity';

import { injectComponentContext } from '@/core';
import { Logger } from '@/errors';
Expand All @@ -12,7 +12,6 @@ import {
isNil,
isString,
ObjectNotationMapValues,
OveeRef,
toKebabCase,
} from '@/utils';

Expand All @@ -23,7 +22,7 @@ const logger = new Logger('useDataAttr');
export function useDataAttr<Keys extends Record<string, ObjectNotationMapValues>>(
keys: Keys
): {
[Key in keyof Keys]: OveeRef<
[Key in keyof Keys]: Ref<
Keys[Key] extends AttributeMap
? ReturnType<Keys[Key]['get']>
: Keys[Key] extends AttributeMapType
Expand All @@ -34,26 +33,26 @@ export function useDataAttr<Keys extends Record<string, ObjectNotationMapValues>

export function useDataAttr<Keys extends string[]>(
keys: [...Keys]
): { [Key in keyof Keys]: OveeRef<string | null> };
): { [Key in keyof Keys]: Ref<string | null> };

export function useDataAttr(key: string): OveeRef<string | undefined>;
export function useDataAttr(key: string): Ref<string | undefined>;

export function useDataAttr<Type>(key: string, map: AttributeMap<Type>): OveeRef<Type>;
export function useDataAttr<Type>(key: string, map: AttributeMap<Type>): Ref<Type>;
export function useDataAttr<MapType extends AttributeMapType>(
key: string,
map: MapType
): OveeRef<GetTypeFromMapType<MapType>>;
): Ref<GetTypeFromMapType<MapType>>;

export function useDataAttr(
key: string | string[] | Record<string, ObjectNotationMapValues>,
_map?: AttributeMap | AttributeMapType
): OveeRef<any> | OveeRef<any>[] | Record<string, OveeRef<any>> {
): Ref<any> | Ref<any>[] | Record<string, Ref<any>> {
const instance = injectComponentContext(true);

if (!instance) {
logger.warn(getNoContextWarning('useDataAttr'));

return { value: undefined };
return ref(null);
}

if (Array.isArray(key)) {
Expand All @@ -76,14 +75,14 @@ export function useDataAttr(
const map = typeof _map === 'string' ? attributeMaps[_map] : _map;
const domKey = `data-${toKebabCase(key)}`;

const dataRef: OveeRef<string | undefined> = {
get value() {
const dataRef = computed<string | undefined>({
get() {
updateDatasetValue();

return cachedValue.value;
},

set value(v: string | undefined) {
set(v) {
const dataValue = map ? map.set(v) : v;

if (isNil(dataValue)) {
Expand All @@ -92,7 +91,7 @@ export function useDataAttr(
instance.element.dataset[key] = dataValue;
}
},
};
});

const { observe, disconnect } = attachAttributeObserver(domKey, () => updateDatasetValue());

Expand Down
10 changes: 6 additions & 4 deletions packages/ovee/src/composables/utils/useElementRef.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
import { computed, ComputedRef } from '@vue/reactivity';

import { useQuerySelector, useQuerySelectorAll } from '@/composables';
import { injectComponentContext } from '@/core';
import { Logger } from '@/errors';
import { getNoContextWarning, OveeReadonlyRef } from '@/utils';
import { getNoContextWarning } from '@/utils';

export type ElementRef<E = HTMLElement | null> = OveeReadonlyRef<E>;
export type ElementRef<E = HTMLElement | null> = ComputedRef<E>;

const logger = new Logger('useElementRef');
const loggerMultiple = new Logger('useElementRefs');
Expand All @@ -16,7 +18,7 @@ export function useElementRef<E extends HTMLElement = HTMLElement>(
if (!instance) {
logger.warn(getNoContextWarning('useElementRef'));

return { value: null };
return computed(() => null);
}

return useQuerySelector(`[ref="${name}"]`);
Expand All @@ -28,7 +30,7 @@ export function useElementRefs<E extends HTMLElement = HTMLElement>(name: string
if (!instance) {
loggerMultiple.warn(getNoContextWarning('useElementRefs'));

return { value: [] };
return computed(() => []);
}

return useQuerySelectorAll(`[ref="${name}"]`);
Expand Down
20 changes: 11 additions & 9 deletions packages/ovee/src/composables/utils/useProp.ts
Original file line number Diff line number Diff line change
@@ -1,17 +1,19 @@
import { computed, Ref } from '@vue/reactivity';

import { injectComponentContext } from '@/core';
import { Logger } from '@/errors';
import { ClassConstructor, getNoContextWarning, OveeRef } from '@/utils';
import { ClassConstructor, getNoContextWarning } from '@/utils';

const logger = new Logger('useProp');

export function useProp<El extends HTMLElement, Key extends keyof El>(
propName: Key,
base: ClassConstructor<El> | El
): OveeRef<El[Key]>;
export function useProp<Key extends keyof HTMLElement>(propName: Key): OveeRef<HTMLElement[Key]>;
export function useProp<R = any>(propName: string): OveeRef<R>;
): Ref<El[Key]>;
export function useProp<Key extends keyof HTMLElement>(propName: Key): Ref<HTMLElement[Key]>;
export function useProp<R = any>(propName: string): Ref<R>;

export function useProp(propName: string): OveeRef<any> {
export function useProp(propName: string): Ref<any> {
const instance = injectComponentContext(true);

if (!instance) {
Expand All @@ -20,15 +22,15 @@ export function useProp(propName: string): OveeRef<any> {
return { value: undefined } as any;
}

const propRef: OveeRef<any> = {
get value() {
const propRef = computed<any>({
get() {
return Reflect.get(instance.element, propName);
},

set value(v) {
set(v) {
Reflect.set(instance.element, propName, v);
},
};
});

return propRef;
}
Loading

0 comments on commit 92c51e3

Please sign in to comment.