@solid-primitives/refs
Advanced tools
Comparing version 1.0.8 to 1.1.0
@@ -1,5 +0,8 @@ | ||
import { JSX, Accessor } from 'solid-js'; | ||
export { ResolvedChildren, ResolvedJSXElement } from 'solid-js/types/reactive/signal.js'; | ||
import { Accessor, JSX } from "solid-js"; | ||
export type { ResolvedChildren, ResolvedJSXElement } from "solid-js/types/reactive/signal.js"; | ||
/** | ||
* Type for the `ref` prop | ||
*/ | ||
export type Ref<T> = T | ((el: T) => void) | undefined; | ||
/** | ||
* Component properties with types for `ref` prop | ||
@@ -12,3 +15,3 @@ * ```ts | ||
*/ | ||
interface RefProps<T> { | ||
export interface RefProps<T> { | ||
ref?: Ref<T>; | ||
@@ -37,3 +40,3 @@ } | ||
*/ | ||
declare function mergeRefs<T>(...refs: Ref<T>[]): (el: T) => void; | ||
export declare function mergeRefs<T>(...refs: Ref<T>[]): (el: T) => void; | ||
/** | ||
@@ -44,3 +47,3 @@ * Default predicate used in `resolveElements()` and `resolveFirst()` to filter Elements. | ||
*/ | ||
declare const defaultElementPredicate: (item: JSX.Element | Element) => item is Element; | ||
export declare const defaultElementPredicate: (item: JSX.Element | Element) => item is Element; | ||
/** | ||
@@ -55,4 +58,4 @@ * Utility for resolving recursively nested JSX children to a single element or an array of elements using a predicate. | ||
*/ | ||
declare function getResolvedElements<T extends object>(value: JSX.Element, predicate: (item: JSX.Element | T) => item is T): T | T[] | null; | ||
type ResolveChildrenReturn<T extends object> = Accessor<T | T[] | null> & { | ||
export declare function getResolvedElements<T extends object>(value: JSX.Element, predicate: (item: JSX.Element | T) => item is T): T | T[] | null; | ||
export type ResolveChildrenReturn<T extends object> = Accessor<T | T[] | null> & { | ||
toArray: () => T[]; | ||
@@ -84,5 +87,5 @@ }; | ||
*/ | ||
declare function resolveElements(fn: Accessor<JSX.Element>): ResolveChildrenReturn<Element>; | ||
declare function resolveElements<T extends object & JSX.Element>(fn: Accessor<JSX.Element>, predicate: (item: JSX.Element) => item is T, serverPredicate?: (item: JSX.Element) => item is T): ResolveChildrenReturn<T>; | ||
declare function resolveElements<T extends object>(fn: Accessor<JSX.Element>, predicate: (item: JSX.Element | T) => item is T, serverPredicate?: (item: JSX.Element | T) => item is T): ResolveChildrenReturn<T>; | ||
export declare function resolveElements(fn: Accessor<JSX.Element>): ResolveChildrenReturn<Element>; | ||
export declare function resolveElements<T extends object & JSX.Element>(fn: Accessor<JSX.Element>, predicate: (item: JSX.Element) => item is T, serverPredicate?: (item: JSX.Element) => item is T): ResolveChildrenReturn<T>; | ||
export declare function resolveElements<T extends object>(fn: Accessor<JSX.Element>, predicate: (item: JSX.Element | T) => item is T, serverPredicate?: (item: JSX.Element | T) => item is T): ResolveChildrenReturn<T>; | ||
/** | ||
@@ -97,3 +100,3 @@ * Utility for resolving recursively nested JSX children in search of the first element that matches a predicate. | ||
*/ | ||
declare function getFirstChild<T extends object>(value: JSX.Element, predicate: (item: JSX.Element | T) => item is T): T | null; | ||
export declare function getFirstChild<T extends object>(value: JSX.Element, predicate: (item: JSX.Element | T) => item is T): T | null; | ||
/** | ||
@@ -120,5 +123,5 @@ * Utility for resolving recursively nested JSX children in search of the first element that matches a predicate. | ||
*/ | ||
declare function resolveFirst(fn: Accessor<JSX.Element>): Accessor<Element | null>; | ||
declare function resolveFirst<T extends object & JSX.Element>(fn: Accessor<JSX.Element>, predicate: (item: JSX.Element) => item is T, serverPredicate?: (item: JSX.Element) => item is T): Accessor<T | null>; | ||
declare function resolveFirst<T extends object>(fn: Accessor<JSX.Element>, predicate: (item: JSX.Element | T) => item is T, serverPredicate?: (item: JSX.Element | T) => item is T): Accessor<T | null>; | ||
export declare function resolveFirst(fn: Accessor<JSX.Element>): Accessor<Element | null>; | ||
export declare function resolveFirst<T extends object & JSX.Element>(fn: Accessor<JSX.Element>, predicate: (item: JSX.Element) => item is T, serverPredicate?: (item: JSX.Element) => item is T): Accessor<T | null>; | ||
export declare function resolveFirst<T extends object>(fn: Accessor<JSX.Element>, predicate: (item: JSX.Element | T) => item is T, serverPredicate?: (item: JSX.Element | T) => item is T): Accessor<T | null>; | ||
/** | ||
@@ -136,3 +139,3 @@ * Get up-to-date references of the multiple children elements. | ||
*/ | ||
declare function Refs(props: { | ||
export declare function Refs(props: { | ||
ref: Ref<Element[]>; | ||
@@ -142,6 +145,2 @@ children: JSX.Element; | ||
/** | ||
* Type for the `ref` prop | ||
*/ | ||
type Ref<T> = T | ((el: T) => void) | undefined; | ||
/** | ||
* Get up-to-date reference to a single child element. | ||
@@ -158,7 +157,5 @@ * @param ref Getter of current element *(or `undefined` if not mounted)* | ||
*/ | ||
declare function Ref(props: { | ||
export declare function Ref(props: { | ||
ref: Ref<Element | undefined>; | ||
children: JSX.Element; | ||
}): JSX.Element; | ||
export { Ref, RefProps, Refs, ResolveChildrenReturn, defaultElementPredicate, getFirstChild, getResolvedElements, mergeRefs, resolveElements, resolveFirst }; |
@@ -1,86 +0,150 @@ | ||
import { chain, arrayEquals } from '@solid-primitives/utils'; | ||
import { createMemo, children, createComputed, untrack, onCleanup } from 'solid-js'; | ||
import { isServer } from 'solid-js/web'; | ||
// src/index.ts | ||
function mergeRefs(...refs) { | ||
return chain(refs); | ||
import { chain, arrayEquals } from "@solid-primitives/utils"; | ||
import { children, createComputed, createMemo, onCleanup, untrack } from "solid-js"; | ||
import { isServer } from "solid-js/web"; | ||
/** | ||
* Utility for chaining multiple `ref` assignments with `props.ref` forwarding. | ||
* @param refs list of ref setters. Can be a `props.ref` prop for ref forwarding or a setter to a local variable (`el => ref = el`). | ||
* @example | ||
* ```tsx | ||
* interface ButtonProps { | ||
* ref?: Ref<HTMLButtonElement> | ||
* } | ||
* function Button (props: ButtonProps) { | ||
* let ref: HTMLButtonElement | undefined | ||
* onMount(() => { | ||
* // use the local ref | ||
* }) | ||
* return <button ref={mergeRefs(props.ref, el => ref = el)} /> | ||
* } | ||
* | ||
* // in consumer's component: | ||
* let ref: HTMLButtonElement | undefined | ||
* <Button ref={ref} /> | ||
* ``` | ||
*/ | ||
export function mergeRefs(...refs) { | ||
return chain(refs); | ||
} | ||
var defaultElementPredicate = isServer ? (item) => item != null && typeof item === "object" && "t" in item : (item) => item instanceof Element; | ||
function getResolvedElements(value, predicate) { | ||
if (predicate(value)) | ||
return value; | ||
if (typeof value === "function" && !value.length) | ||
return getResolvedElements(value(), predicate); | ||
if (Array.isArray(value)) { | ||
const results = []; | ||
for (const item of value) { | ||
const result = getResolvedElements(item, predicate); | ||
if (result) | ||
Array.isArray(result) ? results.push.apply(results, result) : results.push(result); | ||
/** | ||
* Default predicate used in `resolveElements()` and `resolveFirst()` to filter Elements. | ||
* | ||
* On the client it uses `instanceof Element` check, on the server it checks for the object with `t` property. (generated by compiling JSX) | ||
*/ | ||
export const defaultElementPredicate = isServer | ||
? (item) => item != null && typeof item === "object" && "t" in item | ||
: (item) => item instanceof Element; | ||
/** | ||
* Utility for resolving recursively nested JSX children to a single element or an array of elements using a predicate. | ||
* | ||
* It does **not** create a computation - should be wrapped in one to repeat the resolution on changes. | ||
* | ||
* @param value JSX children | ||
* @param predicate predicate to filter elements | ||
* @returns single element or an array of elements or `null` if no elements were found | ||
*/ | ||
export function getResolvedElements(value, predicate) { | ||
if (predicate(value)) | ||
return value; | ||
if (typeof value === "function" && !value.length) | ||
return getResolvedElements(value(), predicate); | ||
if (Array.isArray(value)) { | ||
const results = []; | ||
for (const item of value) { | ||
const result = getResolvedElements(item, predicate); | ||
if (result) | ||
Array.isArray(result) ? results.push.apply(results, result) : results.push(result); | ||
} | ||
return results.length ? results : null; | ||
} | ||
return results.length ? results : null; | ||
} | ||
return null; | ||
return null; | ||
} | ||
function resolveElements(fn, predicate = defaultElementPredicate, serverPredicate = defaultElementPredicate) { | ||
const children2 = createMemo(fn); | ||
const memo = createMemo( | ||
() => getResolvedElements(children2(), isServer ? serverPredicate : predicate) | ||
); | ||
memo.toArray = () => { | ||
const value = memo(); | ||
return Array.isArray(value) ? value : value ? [value] : []; | ||
}; | ||
return memo; | ||
export function resolveElements(fn, predicate = defaultElementPredicate, serverPredicate = defaultElementPredicate) { | ||
const children = createMemo(fn); | ||
const memo = createMemo(() => getResolvedElements(children(), isServer ? serverPredicate : predicate)); | ||
memo.toArray = () => { | ||
const value = memo(); | ||
return Array.isArray(value) ? value : value ? [value] : []; | ||
}; | ||
return memo; | ||
} | ||
function getFirstChild(value, predicate) { | ||
if (predicate(value)) | ||
return value; | ||
if (typeof value === "function" && !value.length) | ||
return getFirstChild(value(), predicate); | ||
if (Array.isArray(value)) { | ||
for (const item of value) { | ||
const result = getFirstChild(item, predicate); | ||
if (result) | ||
return result; | ||
/** | ||
* Utility for resolving recursively nested JSX children in search of the first element that matches a predicate. | ||
* | ||
* It does **not** create a computation - should be wrapped in one to repeat the resolution on changes. | ||
* | ||
* @param value JSX children | ||
* @param predicate predicate to filter elements | ||
* @returns single found element or `null` if no elements were found | ||
*/ | ||
export function getFirstChild(value, predicate) { | ||
if (predicate(value)) | ||
return value; | ||
if (typeof value === "function" && !value.length) | ||
return getFirstChild(value(), predicate); | ||
if (Array.isArray(value)) { | ||
for (const item of value) { | ||
const result = getFirstChild(item, predicate); | ||
if (result) | ||
return result; | ||
} | ||
} | ||
} | ||
return null; | ||
return null; | ||
} | ||
function resolveFirst(fn, predicate = defaultElementPredicate, serverPredicate = defaultElementPredicate) { | ||
const children2 = createMemo(fn); | ||
return createMemo(() => getFirstChild(children2(), isServer ? serverPredicate : predicate)); | ||
export function resolveFirst(fn, predicate = defaultElementPredicate, serverPredicate = defaultElementPredicate) { | ||
const children = createMemo(fn); | ||
return createMemo(() => getFirstChild(children(), isServer ? serverPredicate : predicate)); | ||
} | ||
function Refs(props) { | ||
if (isServer) { | ||
return props.children; | ||
} | ||
const cb = props.ref, resolved = children(() => props.children); | ||
let prev = []; | ||
createComputed(() => { | ||
const els = resolved.toArray().filter(defaultElementPredicate); | ||
if (!arrayEquals(prev, els)) | ||
untrack(() => cb(els)); | ||
prev = els; | ||
}, []); | ||
onCleanup(() => prev.length && cb([])); | ||
return resolved; | ||
/** | ||
* Get up-to-date references of the multiple children elements. | ||
* @param ref Getter of current array of elements | ||
* @see https://github.com/solidjs-community/solid-primitives/tree/main/packages/refs#Refs | ||
* @example | ||
* ```tsx | ||
* const [refs, setRefs] = createSignal<Element[]>([]); | ||
* <Refs ref={setRefs}> | ||
* {props.children} | ||
* </Refs> | ||
* ``` | ||
*/ | ||
export function Refs(props) { | ||
if (isServer) { | ||
return props.children; | ||
} | ||
const cb = props.ref, resolved = children(() => props.children); | ||
let prev = []; | ||
createComputed(() => { | ||
const els = resolved.toArray().filter(defaultElementPredicate); | ||
if (!arrayEquals(prev, els)) | ||
untrack(() => cb(els)); | ||
prev = els; | ||
}, []); | ||
onCleanup(() => prev.length && cb([])); | ||
return resolved; | ||
} | ||
function Ref(props) { | ||
if (isServer) { | ||
return props.children; | ||
} | ||
const cb = props.ref, resolved = children(() => props.children); | ||
let prev; | ||
createComputed(() => { | ||
const el = resolved.toArray().find(defaultElementPredicate); | ||
if (el !== prev) | ||
untrack(() => cb(el)); | ||
prev = el; | ||
}); | ||
onCleanup(() => prev && cb(void 0)); | ||
return resolved; | ||
/** | ||
* Get up-to-date reference to a single child element. | ||
* @param ref Getter of current element *(or `undefined` if not mounted)* | ||
* @see https://github.com/solidjs-community/solid-primitives/tree/main/packages/refs#Ref | ||
* @example | ||
* ```tsx | ||
* const [ref, setRef] = createSignal<Element | undefined>(); | ||
* <Ref ref={setRef}> | ||
* {props.children} | ||
* </Ref> | ||
* ``` | ||
*/ | ||
export function Ref(props) { | ||
if (isServer) { | ||
return props.children; | ||
} | ||
const cb = props.ref, resolved = children(() => props.children); | ||
let prev; | ||
createComputed(() => { | ||
const el = resolved.toArray().find(defaultElementPredicate); | ||
if (el !== prev) | ||
untrack(() => cb(el)); | ||
prev = el; | ||
}); | ||
onCleanup(() => prev && cb(undefined)); | ||
return resolved; | ||
} | ||
export { Ref, Refs, defaultElementPredicate, getFirstChild, getResolvedElements, mergeRefs, resolveElements, resolveFirst }; |
{ | ||
"name": "@solid-primitives/refs", | ||
"version": "1.0.8", | ||
"version": "1.1.0", | ||
"description": "Library of primitives, components and directives for SolidJS that help managing references to JSX elements.", | ||
@@ -30,3 +30,2 @@ "author": "Damian Tarnawski @thetarnav <gthetarnav@gmail.com>", | ||
"type": "module", | ||
"main": "./dist/index.cjs", | ||
"module": "./dist/index.js", | ||
@@ -36,9 +35,6 @@ "types": "./dist/index.d.ts", | ||
"exports": { | ||
"@solid-primitives/source": "./src/index.ts", | ||
"import": { | ||
"types": "./dist/index.d.ts", | ||
"default": "./dist/index.js" | ||
}, | ||
"require": { | ||
"types": "./dist/index.d.cts", | ||
"default": "./dist/index.cjs" | ||
} | ||
@@ -54,6 +50,5 @@ }, | ||
"dependencies": { | ||
"@solid-primitives/utils": "^6.2.3" | ||
"@solid-primitives/utils": "^6.3.0" | ||
}, | ||
"devDependencies": { | ||
"solid-app-router": "^0.4.2", | ||
"solid-js": "^1.8.7", | ||
@@ -60,0 +55,0 @@ "solid-transition-group": "^0.2.3" |
@@ -7,3 +7,2 @@ <p> | ||
[![turborepo](https://img.shields.io/badge/built%20with-turborepo-cc00ff.svg?style=for-the-badge&logo=turborepo)](https://turborepo.org/) | ||
[![size](https://img.shields.io/bundlephobia/minzip/@solid-primitives/refs?style=for-the-badge&label=size)](https://bundlephobia.com/package/@solid-primitives/refs) | ||
@@ -17,5 +16,5 @@ [![version](https://img.shields.io/npm/v/@solid-primitives/refs?style=for-the-badge)](https://www.npmjs.com/package/@solid-primitives/refs) | ||
- [`mergeRefs`](#mergeRefs) - Utility for chaining multiple `ref` assignments with `props.ref` forwarding. | ||
- [`resolveElements`](#resolveElements) - Utility for resolving recursively nested JSX children to a single element or an array of elements. | ||
- [`resolveFirst`](#resolveFirst) - Utility for resolving recursively nested JSX children in search of the first element that matches a predicate. | ||
- [`mergeRefs`](#mergerefs) - Utility for chaining multiple `ref` assignments with `props.ref` forwarding. | ||
- [`resolveElements`](#resolveelements) - Utility for resolving recursively nested JSX children to a single element or an array of elements. | ||
- [`resolveFirst`](#resolvefirst) - Utility for resolving recursively nested JSX children in search of the first element that matches a predicate. | ||
- [`<Refs>`](#refs) - Get up-to-date references of the multiple children elements. | ||
@@ -116,3 +115,3 @@ - [`<Ref>`](#ref) - Get up-to-date reference to a single child element. | ||
`resolveFirst` matches the API of [`resolveElements`](#resolveElements) but returns only the first element that matches the predicate. | ||
`resolveFirst` matches the API of [`resolveElements`](#resolveelements) but returns only the first element that matches the predicate. | ||
@@ -119,0 +118,0 @@ ```tsx |
2
19634
5
301
196