@diskette/use-render 0.8.0 → 0.9.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/README.md CHANGED
@@ -136,3 +136,54 @@ These extend the element's native props, adding `render` and (for stateful hooks
136
136
  - **Ref composition** — refs from consumer, base props, and options are merged
137
137
  - **Event handler chaining** — consumer handlers run first, then base handlers
138
138
  - **className/style merging** — static values combine; functions receive state and the resolved base value as parameters
139
+
140
+ ## Ref Composition
141
+
142
+ Component libraries often need internal ref access for focus management, measurements, or imperative APIs—while still letting consumers attach their own refs. The hooks handle this automatically.
143
+
144
+ **Component author:**
145
+
146
+ ```tsx
147
+ import { useRef, useImperativeHandle } from 'react'
148
+ import { useRender, ComponentProps } from '@diskette/use-render'
149
+
150
+ type State = { open: boolean }
151
+ type ComboboxProps = ComponentProps<'input', State>
152
+
153
+ export interface ComboboxRef {
154
+ focus: () => void
155
+ clear: () => void
156
+ }
157
+
158
+ function Combobox({ ref, ...props }: ComboboxProps & { ref?: React.Ref<ComboboxRef> }) {
159
+ const inputRef = useRef<HTMLInputElement>(null)
160
+ const state: State = { open: false }
161
+
162
+ // Expose imperative API to consumers
163
+ useImperativeHandle(ref, () => ({
164
+ focus: () => inputRef.current?.focus(),
165
+ clear: () => {
166
+ if (inputRef.current) inputRef.current.value = ''
167
+ },
168
+ }))
169
+
170
+ // Internal ref composes with any ref passed through props
171
+ return useRender('input', state, { props, ref: inputRef })
172
+ }
173
+ ```
174
+
175
+ **Consumer:**
176
+
177
+ ```tsx
178
+ const inputRef = useRef<HTMLInputElement>(null)
179
+ const comboboxRef = useRef<ComboboxRef>(null)
180
+
181
+ // Direct element access
182
+ <Combobox ref={inputRef} />
183
+
184
+ // Imperative handle access
185
+ <Combobox ref={comboboxRef} />
186
+ comboboxRef.current?.focus()
187
+ ```
188
+
189
+ The `options.ref` parameter accepts a single ref or an array of refs. All refs—from `options.ref`, `baseProps.ref`, and consumer `props.ref`—are composed into a single callback ref that updates all sources and handles cleanup.
package/dist/types.d.ts CHANGED
@@ -4,7 +4,7 @@ export type Style<State> = ((state: State, baseStyle?: CSSProperties) => CSSProp
4
4
  export type ComponentRenderer<S> = (props: HTMLAttributes<any> & {
5
5
  ref?: Ref<any> | undefined;
6
6
  }, state: S) => ReactNode;
7
- export type DataAttributes = Record<`data-${string}`, string | number | boolean>;
7
+ export type DataAttributes = Record<`data-${string}`, string | number | boolean | undefined>;
8
8
  export type BaseComponentProps<T extends ElementType> = Omit<ComponentPropsWithRef<T>, 'children' | 'className' | 'style'>;
9
9
  export type ComponentProps<T extends ElementType, S> = BaseComponentProps<T> & {
10
10
  children?: ReactNode | {
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@diskette/use-render",
3
3
  "type": "module",
4
- "version": "0.8.0",
4
+ "version": "0.9.0",
5
5
  "exports": "./dist/index.js",
6
6
  "files": [
7
7
  "dist"
@@ -21,18 +21,18 @@
21
21
  }
22
22
  },
23
23
  "devDependencies": {
24
- "@changesets/cli": "^2.29.7",
25
- "@types/react": "^19.2.6",
24
+ "@changesets/cli": "^2.29.8",
25
+ "@types/react": "^19.2.7",
26
26
  "@types/react-dom": "^19.2.3",
27
- "@vitejs/plugin-react": "^5.1.1",
28
- "@vitest/browser-playwright": "^4.0.13",
29
- "oxlint": "^1.29.0",
30
- "oxlint-tsgolint": "^0.8.1",
31
- "prettier": "^3.6.2",
32
- "react": "^19.2.0",
33
- "react-dom": "^19.2.0",
27
+ "@vitejs/plugin-react": "^5.1.2",
28
+ "@vitest/browser-playwright": "^4.0.15",
29
+ "oxlint": "^1.32.0",
30
+ "oxlint-tsgolint": "^0.8.6",
31
+ "prettier": "^3.7.4",
32
+ "react": "^19.2.3",
33
+ "react-dom": "^19.2.3",
34
34
  "typescript": "^5.9.3",
35
- "vitest": "^4.0.13",
35
+ "vitest": "^4.0.15",
36
36
  "vitest-browser-react": "^2.0.2"
37
37
  },
38
38
  "description": "_description_",