@diskette/use-render 0.11.1 → 0.13.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/fns/render-slot.d.ts +1 -1
- package/dist/fns/render-slot.js +9 -6
- package/dist/use-composed-ref.d.ts +2 -9
- package/dist/use-composed-ref.js +2 -28
- package/dist/use-render-container.js +6 -6
- package/dist/use-render.js +3 -3
- package/dist/utils.d.ts +17 -1
- package/dist/utils.js +52 -0
- package/package.json +1 -1
|
@@ -12,7 +12,7 @@ export interface RenderSlotOptions<T extends ElementType> {
|
|
|
12
12
|
}
|
|
13
13
|
/**
|
|
14
14
|
* Pure function for rendering slot elements with render prop support and prop merging.
|
|
15
|
-
* RSC-compatible version of useRenderSlot
|
|
15
|
+
* RSC-compatible version of useRenderSlot. Composes refs from baseProps and props via mergeRefs.
|
|
16
16
|
*
|
|
17
17
|
* @example
|
|
18
18
|
* ```tsx
|
package/dist/fns/render-slot.js
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { cx, isFunction, isString, mergeProps } from "../utils.js";
|
|
1
|
+
import { createElement, isValidElement } from 'react';
|
|
2
|
+
import { cloneRenderElement, cx, isFunction, isString, mergeProps, mergeRefs } from "../utils.js";
|
|
3
3
|
/**
|
|
4
4
|
* Pure function for rendering slot elements with render prop support and prop merging.
|
|
5
|
-
* RSC-compatible version of useRenderSlot
|
|
5
|
+
* RSC-compatible version of useRenderSlot. Composes refs from baseProps and props via mergeRefs.
|
|
6
6
|
*
|
|
7
7
|
* @example
|
|
8
8
|
* ```tsx
|
|
@@ -26,8 +26,8 @@ import { cx, isFunction, isString, mergeProps } from "../utils.js";
|
|
|
26
26
|
export function renderSlot(tag, options = {}) {
|
|
27
27
|
const baseProps = (options.baseProps ?? {});
|
|
28
28
|
const props = (options.props ?? {});
|
|
29
|
-
const { className: baseClassName, style: baseStyle, children: baseChildren, ...base } = baseProps;
|
|
30
|
-
const { className, style, children, render, ...rest } = props;
|
|
29
|
+
const { className: baseClassName, style: baseStyle, children: baseChildren, ref: baseRef, ...base } = baseProps;
|
|
30
|
+
const { className, style, children, render, ref, ...rest } = props;
|
|
31
31
|
const resolvedClassName = cx(baseClassName, className);
|
|
32
32
|
const resolvedStyle = baseStyle || style ? { ...baseStyle, ...style } : undefined;
|
|
33
33
|
const resolvedProps = {
|
|
@@ -39,10 +39,13 @@ export function renderSlot(tag, options = {}) {
|
|
|
39
39
|
if (typeof resolvedStyle === 'object') {
|
|
40
40
|
resolvedProps.style = resolvedStyle;
|
|
41
41
|
}
|
|
42
|
+
if (baseRef || ref) {
|
|
43
|
+
resolvedProps.ref = mergeRefs([baseRef, ref]);
|
|
44
|
+
}
|
|
42
45
|
const resolvedChildren = children ?? baseChildren;
|
|
43
46
|
// For `<Component render={<a />} />`
|
|
44
47
|
if (isValidElement(render)) {
|
|
45
|
-
return
|
|
48
|
+
return cloneRenderElement(render, resolvedProps, resolvedChildren);
|
|
46
49
|
}
|
|
47
50
|
// For `<Component render={(props) => <a {...props} />)} />`
|
|
48
51
|
if (isFunction(render)) {
|
|
@@ -1,11 +1,5 @@
|
|
|
1
|
-
import { type Ref
|
|
2
|
-
|
|
3
|
-
* Assigns a value to a ref.
|
|
4
|
-
* @param ref The ref to assign the value to.
|
|
5
|
-
* @param value The value to assign to the ref.
|
|
6
|
-
* @returns The ref cleanup callback, if any.
|
|
7
|
-
*/
|
|
8
|
-
export declare function assignRef<T>(ref: Ref<T> | undefined | null, value: T | null): ReturnType<RefCallback<T>>;
|
|
1
|
+
import { type Ref } from 'react';
|
|
2
|
+
export { assignRef } from './utils.ts';
|
|
9
3
|
type RefInput<T> = Ref<T> | undefined | (Ref<T> | undefined)[];
|
|
10
4
|
/**
|
|
11
5
|
* Composes multiple refs into a single one and memoizes the result to avoid refs execution on each render.
|
|
@@ -14,4 +8,3 @@ type RefInput<T> = Ref<T> | undefined | (Ref<T> | undefined)[];
|
|
|
14
8
|
* @returns Merged ref.
|
|
15
9
|
*/
|
|
16
10
|
export declare function useComposedRef<T>(...refs: RefInput<T>[]): Ref<T>;
|
|
17
|
-
export {};
|
package/dist/use-composed-ref.js
CHANGED
|
@@ -1,32 +1,6 @@
|
|
|
1
1
|
import { useMemo } from 'react';
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
* @param ref The ref to assign the value to.
|
|
5
|
-
* @param value The value to assign to the ref.
|
|
6
|
-
* @returns The ref cleanup callback, if any.
|
|
7
|
-
*/
|
|
8
|
-
export function assignRef(ref, value) {
|
|
9
|
-
if (typeof ref === 'function') {
|
|
10
|
-
return ref(value);
|
|
11
|
-
}
|
|
12
|
-
else if (ref) {
|
|
13
|
-
ref.current = value;
|
|
14
|
-
}
|
|
15
|
-
}
|
|
16
|
-
function mergeRefs(refs) {
|
|
17
|
-
return (value) => {
|
|
18
|
-
const cleanups = [];
|
|
19
|
-
for (const ref of refs) {
|
|
20
|
-
const cleanup = assignRef(ref, value);
|
|
21
|
-
const isCleanup = typeof cleanup === 'function';
|
|
22
|
-
cleanups.push(isCleanup ? cleanup : () => assignRef(ref, null));
|
|
23
|
-
}
|
|
24
|
-
return () => {
|
|
25
|
-
for (const cleanup of cleanups)
|
|
26
|
-
cleanup();
|
|
27
|
-
};
|
|
28
|
-
};
|
|
29
|
-
}
|
|
2
|
+
import { mergeRefs } from "./utils.js";
|
|
3
|
+
export { assignRef } from "./utils.js";
|
|
30
4
|
/**
|
|
31
5
|
* Composes multiple refs into a single one and memoizes the result to avoid refs execution on each render.
|
|
32
6
|
* Accepts individual refs or arrays of refs, which are flattened automatically.
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { createElement, isValidElement, useCallback, useMemo, } from 'react';
|
|
2
2
|
import { useComposedRef } from "./use-composed-ref.js";
|
|
3
|
-
import { isFunction, isString, mergeProps, resolveClassName, resolveStyle, } from "./utils.js";
|
|
3
|
+
import { cloneRenderElement, isFunction, isString, mergeProps, resolveClassName, resolveStyle, } from "./utils.js";
|
|
4
4
|
/**
|
|
5
5
|
* Hook for rendering container elements with item-level render control.
|
|
6
6
|
*
|
|
@@ -68,14 +68,14 @@ export function useRenderContainer(tag, containerState, options = {}) {
|
|
|
68
68
|
}, [base, rest, mergedRef, resolvedClassName, resolvedStyle]);
|
|
69
69
|
// Container component that handles render prop
|
|
70
70
|
const Container = useCallback(({ children: containerChildren }) => {
|
|
71
|
+
// For `<Component render={<section />} />`
|
|
72
|
+
if (isValidElement(render)) {
|
|
73
|
+
return cloneRenderElement(render, resolvedProps, containerChildren);
|
|
74
|
+
}
|
|
71
75
|
const propsWithChildren = {
|
|
72
76
|
...resolvedProps,
|
|
73
77
|
children: containerChildren,
|
|
74
78
|
};
|
|
75
|
-
// For `<Component render={<section />} />`
|
|
76
|
-
if (isValidElement(render)) {
|
|
77
|
-
return cloneElement(render, propsWithChildren);
|
|
78
|
-
}
|
|
79
79
|
// For `<Component render={(props, state) => <section {...props} />} />`
|
|
80
80
|
if (isFunction(render)) {
|
|
81
81
|
return render(propsWithChildren, containerState);
|
package/dist/use-render.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { createElement, isValidElement } from 'react';
|
|
2
2
|
import { useComposedRef } from "./use-composed-ref.js";
|
|
3
|
-
import { isFunction, isString, mergeProps, resolveClassName, resolveStyle, } from "./utils.js";
|
|
3
|
+
import { cloneRenderElement, isFunction, isString, mergeProps, resolveClassName, resolveStyle, } from "./utils.js";
|
|
4
4
|
/**
|
|
5
5
|
* Hook for rendering elements with render prop support, prop merging, and state-driven className/style resolution.
|
|
6
6
|
*
|
|
@@ -44,7 +44,7 @@ export function useRender(tag, state, options = {}) {
|
|
|
44
44
|
const resolvedChildren = isFunction(children) ? children(state) : children;
|
|
45
45
|
// For `<Component render={<a />} />`
|
|
46
46
|
if (isValidElement(render)) {
|
|
47
|
-
return
|
|
47
|
+
return cloneRenderElement(render, resolvedProps, resolvedChildren);
|
|
48
48
|
}
|
|
49
49
|
// For `<Component render={(props) => <a {...props} />)} />`
|
|
50
50
|
if (isFunction(render)) {
|
package/dist/utils.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { CSSProperties } from 'react';
|
|
1
|
+
import type { CSSProperties, ReactElement, ReactNode, Ref, RefCallback } from 'react';
|
|
2
2
|
import type { ClassName, Style } from './types.ts';
|
|
3
3
|
export declare const isString: (value: unknown) => value is string;
|
|
4
4
|
export declare const isFunction: (value: unknown) => value is Function;
|
|
@@ -27,3 +27,19 @@ export declare function resolveStyle<State>(state: State, defaultStyle?: Style<S
|
|
|
27
27
|
* Returns a string with the truthy values of `args` separated by space.
|
|
28
28
|
*/
|
|
29
29
|
export declare function cx(...args: Array<string | null | false | 0 | undefined>): string | undefined;
|
|
30
|
+
/**
|
|
31
|
+
* Assigns a value to a ref.
|
|
32
|
+
*/
|
|
33
|
+
export declare function assignRef<T>(ref: Ref<T> | undefined | null, value: T | null): ReturnType<RefCallback<T>>;
|
|
34
|
+
/**
|
|
35
|
+
* Composes multiple refs into a single ref callback.
|
|
36
|
+
*/
|
|
37
|
+
export declare function mergeRefs<T>(refs: (Ref<T> | undefined)[]): Ref<T>;
|
|
38
|
+
/**
|
|
39
|
+
* Clones a React element, merging its props with resolved props.
|
|
40
|
+
* - className values are merged via `cx`
|
|
41
|
+
* - style objects are spread-merged (render element styles as base, resolved styles on top)
|
|
42
|
+
* - event handlers are composed via `mergeProps`
|
|
43
|
+
* - children are set if provided
|
|
44
|
+
*/
|
|
45
|
+
export declare function cloneRenderElement(render: ReactElement, resolvedProps: React.ComponentProps<'div'>, children?: ReactNode): ReactNode;
|
package/dist/utils.js
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { cloneElement } from 'react';
|
|
1
2
|
export const isString = (value) => typeof value === 'string';
|
|
2
3
|
export const isFunction = (value) => typeof value === 'function';
|
|
3
4
|
export const isUndefined = (value) => typeof value === 'undefined';
|
|
@@ -73,3 +74,54 @@ export function resolveStyle(state, defaultStyle, propsStyle) {
|
|
|
73
74
|
export function cx(...args) {
|
|
74
75
|
return args.filter(Boolean).join(' ') || undefined;
|
|
75
76
|
}
|
|
77
|
+
/**
|
|
78
|
+
* Assigns a value to a ref.
|
|
79
|
+
*/
|
|
80
|
+
export function assignRef(ref, value) {
|
|
81
|
+
if (typeof ref === 'function') {
|
|
82
|
+
return ref(value);
|
|
83
|
+
}
|
|
84
|
+
else if (ref) {
|
|
85
|
+
ref.current = value;
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
/**
|
|
89
|
+
* Composes multiple refs into a single ref callback.
|
|
90
|
+
*/
|
|
91
|
+
export function mergeRefs(refs) {
|
|
92
|
+
return (value) => {
|
|
93
|
+
const cleanups = [];
|
|
94
|
+
for (const ref of refs) {
|
|
95
|
+
const cleanup = assignRef(ref, value);
|
|
96
|
+
const isCleanup = typeof cleanup === 'function';
|
|
97
|
+
cleanups.push(isCleanup ? cleanup : () => assignRef(ref, null));
|
|
98
|
+
}
|
|
99
|
+
return () => {
|
|
100
|
+
for (const cleanup of cleanups)
|
|
101
|
+
cleanup();
|
|
102
|
+
};
|
|
103
|
+
};
|
|
104
|
+
}
|
|
105
|
+
/**
|
|
106
|
+
* Clones a React element, merging its props with resolved props.
|
|
107
|
+
* - className values are merged via `cx`
|
|
108
|
+
* - style objects are spread-merged (render element styles as base, resolved styles on top)
|
|
109
|
+
* - event handlers are composed via `mergeProps`
|
|
110
|
+
* - children are set if provided
|
|
111
|
+
*/
|
|
112
|
+
export function cloneRenderElement(render, resolvedProps, children) {
|
|
113
|
+
const { className: renderClassName, style: renderStyle, children: _renderChildren, ...renderRest } = render.props;
|
|
114
|
+
const { className: resolvedClassName, style: resolvedStyle, children: _resolvedChildren, ...resolvedRest } = resolvedProps;
|
|
115
|
+
const merged = mergeProps(renderRest, resolvedRest);
|
|
116
|
+
const mergedClassName = cx(renderClassName, resolvedClassName);
|
|
117
|
+
if (isString(mergedClassName)) {
|
|
118
|
+
merged.className = mergedClassName;
|
|
119
|
+
}
|
|
120
|
+
if (renderStyle || resolvedStyle) {
|
|
121
|
+
merged.style = { ...renderStyle, ...resolvedStyle };
|
|
122
|
+
}
|
|
123
|
+
if (children !== undefined) {
|
|
124
|
+
merged.children = children;
|
|
125
|
+
}
|
|
126
|
+
return cloneElement(render, merged);
|
|
127
|
+
}
|