@ngrok/mantle 0.70.2 → 0.71.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/alert-dialog.d.ts +337 -90
- package/dist/alert-dialog.js.map +1 -1
- package/dist/alert.js.map +1 -1
- package/dist/anchor-2stEauOz.js.map +1 -1
- package/dist/anchor.d.ts +45 -4
- package/dist/badge.d.ts +32 -3
- package/dist/badge.js.map +1 -1
- package/dist/{button-BMgAxAwM.d.ts → button-Bq0x5Pv4.d.ts} +4 -4
- package/dist/button.d.ts +1 -1
- package/dist/checkbox.d.ts +1 -1
- package/dist/code-block.d.ts +1 -1
- package/dist/code-block_highlight-utils.d.ts +1 -1
- package/dist/code.d.ts +22 -1
- package/dist/code.js.map +1 -1
- package/dist/combobox.d.ts +10 -0
- package/dist/combobox.js.map +1 -1
- package/dist/command.js.map +1 -1
- package/dist/copy-to-clipboard-DjOD_Mwb.js.map +1 -1
- package/dist/data-table.d.ts +303 -22
- package/dist/data-table.js.map +1 -1
- package/dist/dialog-BHzl9eye.js.map +1 -1
- package/dist/dialog.d.ts +6 -1
- package/dist/flag.d.ts +33 -4
- package/dist/flag.js.map +1 -1
- package/dist/hooks.d.ts +299 -74
- package/dist/hooks.js.map +1 -1
- package/dist/hover-card.d.ts +15 -10
- package/dist/hover-card.js.map +1 -1
- package/dist/icons.js.map +1 -1
- package/dist/{index-DMAkXvFI.d.ts → index-C91lxoX9.d.ts} +55 -12
- package/dist/input.d.ts +1 -1
- package/dist/input.js.map +1 -1
- package/dist/kbd-CAVUiqBT.js.map +1 -1
- package/dist/kbd.d.ts +37 -8
- package/dist/label.d.ts +40 -9
- package/dist/label.js.map +1 -1
- package/dist/media-object.d.ts +26 -10
- package/dist/media-object.js.map +1 -1
- package/dist/multi-select.d.ts +185 -34
- package/dist/multi-select.js.map +1 -1
- package/dist/otp-input.d.ts +167 -0
- package/dist/otp-input.js +2 -0
- package/dist/otp-input.js.map +1 -0
- package/dist/pagination.d.ts +1 -1
- package/dist/pagination.js.map +1 -1
- package/dist/popover.d.ts +7 -5
- package/dist/popover.js.map +1 -1
- package/dist/primitive-tXm_8n_t.js.map +1 -1
- package/dist/progress.js.map +1 -1
- package/dist/resolve-pre-rendered-props-C-kiaLHj.js.map +1 -1
- package/dist/{resolve-pre-rendered-props-x-52gvQ1.d.ts → resolve-pre-rendered-props-CNUnH1fU.d.ts} +2 -2
- package/dist/select-DOgdZO0Q.js.map +1 -1
- package/dist/{select-BjpP51vO.d.ts → select-DZutJxyr.d.ts} +9 -1
- package/dist/select.d.ts +1 -1
- package/dist/separator-DSOIrnhj.js.map +1 -1
- package/dist/sheet.d.ts +5 -1
- package/dist/sheet.js.map +1 -1
- package/dist/skeleton.d.ts +32 -5
- package/dist/skeleton.js.map +1 -1
- package/dist/sort-DzCsa6Qj.js.map +1 -1
- package/dist/split-button.d.ts +1 -1
- package/dist/{table--DsTqaWO.d.ts → table-BsNJBKiq.d.ts} +7 -3
- package/dist/table-Cl4nlRMR.js.map +1 -1
- package/dist/table.d.ts +1 -1
- package/dist/theme-provider-BFcnjeME.js.map +1 -1
- package/dist/theme.d.ts +1 -1
- package/dist/theme.js.map +1 -1
- package/dist/tooltip.d.ts +31 -14
- package/dist/tooltip.js.map +1 -1
- package/dist/use-copy-to-clipboard-C7vsjJe-.js.map +1 -1
- package/dist/use-matches-media-query-CojcYxlA.js.map +1 -1
- package/dist/use-prefers-reduced-motion-aXfsyo-k.js.map +1 -1
- package/package.json +12 -7
package/dist/hooks.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { n as MarginType, o as useComposedRefs, s as copyToClipboard } from "./in-view-Da08Bx6l.js";
|
|
2
|
-
import { RefObject,
|
|
2
|
+
import { RefObject, useLayoutEffect } from "react";
|
|
3
3
|
|
|
4
4
|
//#region src/hooks/use-breakpoint.d.ts
|
|
5
5
|
/**
|
|
@@ -106,42 +106,119 @@ declare function useIsBelowBreakpoint(breakpoint: TailwindBreakpoint): boolean;
|
|
|
106
106
|
//#endregion
|
|
107
107
|
//#region src/hooks/use-callback-ref.d.ts
|
|
108
108
|
/**
|
|
109
|
-
* Returns a memoized callback that
|
|
110
|
-
*
|
|
109
|
+
* Returns a memoized callback that always invokes the latest version of the
|
|
110
|
+
* provided callback, while preserving a stable function identity across
|
|
111
|
+
* renders.
|
|
112
|
+
*
|
|
113
|
+
* Use this when you need to pass a callback to a child component, an event
|
|
114
|
+
* handler, or a hook dependency array, but the consumer should not re-run /
|
|
115
|
+
* re-render simply because the callback's identity changed. The returned
|
|
116
|
+
* function never changes reference, but internally always calls through to
|
|
117
|
+
* the latest `callback` passed in.
|
|
118
|
+
*
|
|
119
|
+
* Most commonly used as an internal building block for other hooks (for
|
|
120
|
+
* example, {@link useDebouncedCallback}). It is also re-exported publicly
|
|
121
|
+
* for consumers that need the same pattern.
|
|
122
|
+
*
|
|
123
|
+
* @param callback - The callback to wrap. May be `undefined`, in which case
|
|
124
|
+
* invoking the returned function is a no-op until a callback is provided
|
|
125
|
+
* on a subsequent render.
|
|
126
|
+
* @returns A stable function with the same signature as `callback` that
|
|
127
|
+
* forwards its arguments to the most recent `callback` value.
|
|
111
128
|
*
|
|
112
|
-
*
|
|
113
|
-
*
|
|
114
|
-
*
|
|
129
|
+
* @example
|
|
130
|
+
* // Pass a stable handler to a memoized child without re-rendering it
|
|
131
|
+
* const onSelect = useCallbackRef((id: string) => {
|
|
132
|
+
* // reads the latest `props.items` without being in deps
|
|
133
|
+
* props.onSelectItem(id, props.items);
|
|
134
|
+
* });
|
|
135
|
+
*
|
|
136
|
+
* return <MemoizedList onSelect={onSelect} />;
|
|
115
137
|
*/
|
|
116
138
|
declare function useCallbackRef<T extends (...args: unknown[]) => unknown>(callback: T | undefined): T;
|
|
117
139
|
//#endregion
|
|
118
140
|
//#region src/hooks/use-copy-to-clipboard.d.ts
|
|
119
141
|
/**
|
|
120
|
-
*
|
|
142
|
+
* React hook that returns a stable async function for copying a string to
|
|
143
|
+
* the system clipboard.
|
|
121
144
|
*
|
|
122
|
-
*
|
|
123
|
-
*
|
|
145
|
+
* The returned function uses the Clipboard API when available and falls back
|
|
146
|
+
* to a `document.execCommand("copy")` polyfill for older browsers. `await`
|
|
147
|
+
* the call (or attach a `.then()` / `.catch()`) to observe whether the copy
|
|
148
|
+
* succeeded — the function throws when both the Clipboard API and the
|
|
149
|
+
* polyfill fail, or when called outside of a DOM environment.
|
|
124
150
|
*
|
|
125
151
|
* Inspired by: https://usehooks.com/usecopytoclipboard
|
|
152
|
+
*
|
|
153
|
+
* @returns An async function `(value: string) => Promise<void>` that writes
|
|
154
|
+
* `value` to the clipboard and rejects on failure.
|
|
155
|
+
*
|
|
156
|
+
* @example
|
|
157
|
+
* // Copy a token on click and surface a toast on success/failure
|
|
158
|
+
* const copy = useCopyToClipboard();
|
|
159
|
+
*
|
|
160
|
+
* async function handleCopy() {
|
|
161
|
+
* try {
|
|
162
|
+
* await copy(token);
|
|
163
|
+
* toast.success("Copied!");
|
|
164
|
+
* } catch {
|
|
165
|
+
* toast.error("Could not copy to clipboard");
|
|
166
|
+
* }
|
|
167
|
+
* }
|
|
168
|
+
*
|
|
169
|
+
* return <button onClick={handleCopy}>Copy token</button>;
|
|
126
170
|
*/
|
|
127
171
|
declare function useCopyToClipboard(): typeof copyToClipboard;
|
|
128
172
|
//#endregion
|
|
129
173
|
//#region src/hooks/use-debounced-callback.d.ts
|
|
174
|
+
/**
|
|
175
|
+
* Options for {@link useDebouncedCallback}.
|
|
176
|
+
*/
|
|
130
177
|
type Options = {
|
|
131
178
|
/**
|
|
132
|
-
* The delay in milliseconds to wait
|
|
179
|
+
* The delay in milliseconds to wait between the last invocation and
|
|
180
|
+
* actually running the callback.
|
|
133
181
|
*/
|
|
134
182
|
waitMs: number;
|
|
135
183
|
};
|
|
136
184
|
/**
|
|
137
|
-
*
|
|
185
|
+
* Returns a debounced version of the provided callback. Each call resets a
|
|
186
|
+
* timer; the underlying callback only runs after `options.waitMs` of
|
|
187
|
+
* inactivity has elapsed.
|
|
188
|
+
*
|
|
189
|
+
* Useful for limiting rapid invocations such as search-as-you-type inputs,
|
|
190
|
+
* window resize handlers, or expensive button-press handlers. The pending
|
|
191
|
+
* timer is automatically cleared on unmount.
|
|
192
|
+
*
|
|
193
|
+
* The debounced function always invokes the latest version of `callbackFn`,
|
|
194
|
+
* so callers do not need to memoize it. The returned function's identity
|
|
195
|
+
* only changes when `options.waitMs` changes, so it is safe to include in
|
|
196
|
+
* dependency arrays.
|
|
197
|
+
*
|
|
198
|
+
* @param callbackFn - The function to debounce. The latest reference passed
|
|
199
|
+
* on each render is always used when the timer fires.
|
|
200
|
+
* @param options - Debounce options.
|
|
201
|
+
* @param options.waitMs - Milliseconds of inactivity to wait before calling
|
|
202
|
+
* `callbackFn`.
|
|
203
|
+
* @returns A function with the same parameter list as `callbackFn` that
|
|
204
|
+
* schedules (or reschedules) the underlying call.
|
|
138
205
|
*
|
|
139
|
-
*
|
|
140
|
-
*
|
|
141
|
-
*
|
|
206
|
+
* @example
|
|
207
|
+
* // Debounce a search input by 300ms
|
|
208
|
+
* const [query, setQuery] = useState("");
|
|
209
|
+
* const search = useDebouncedCallback((value: string) => {
|
|
210
|
+
* fetchResults(value);
|
|
211
|
+
* }, { waitMs: 300 });
|
|
142
212
|
*
|
|
143
|
-
*
|
|
144
|
-
*
|
|
213
|
+
* return (
|
|
214
|
+
* <input
|
|
215
|
+
* value={query}
|
|
216
|
+
* onChange={(event) => {
|
|
217
|
+
* setQuery(event.target.value);
|
|
218
|
+
* search(event.target.value);
|
|
219
|
+
* }}
|
|
220
|
+
* />
|
|
221
|
+
* );
|
|
145
222
|
*/
|
|
146
223
|
declare function useDebouncedCallback<T extends (...args: unknown[]) => unknown>(callbackFn: T, options: Options): (...args: Parameters<T>) => void;
|
|
147
224
|
//#endregion
|
|
@@ -174,71 +251,171 @@ declare function useIsHydrated(): boolean;
|
|
|
174
251
|
//#endregion
|
|
175
252
|
//#region src/hooks/use-isomorphic-layout-effect.d.ts
|
|
176
253
|
/**
|
|
177
|
-
*
|
|
254
|
+
* A drop-in replacement for `useLayoutEffect` that does not warn during
|
|
255
|
+
* server-side rendering.
|
|
256
|
+
*
|
|
257
|
+
* Resolves to `useLayoutEffect` in the browser (where it can read layout and
|
|
258
|
+
* synchronously re-render before paint) and to `useEffect` on the server
|
|
259
|
+
* (where layout effects are a no-op and React would otherwise log a
|
|
260
|
+
* "useLayoutEffect does nothing on the server" warning).
|
|
261
|
+
*
|
|
262
|
+
* Use this whenever you need the timing semantics of `useLayoutEffect` in
|
|
263
|
+
* code that may also execute during SSR. It is most often used internally
|
|
264
|
+
* by other Mantle hooks and components.
|
|
265
|
+
*
|
|
266
|
+
* @param effect - The imperative function that may return a cleanup
|
|
267
|
+
* function — same signature as React's `useLayoutEffect` / `useEffect`.
|
|
268
|
+
* @param deps - Optional dependency list, same semantics as
|
|
269
|
+
* `useLayoutEffect`.
|
|
270
|
+
* @returns Nothing.
|
|
271
|
+
*
|
|
272
|
+
* @example
|
|
273
|
+
* // Measure an element synchronously after layout
|
|
274
|
+
* const ref = useRef<HTMLDivElement>(null);
|
|
275
|
+
* const [width, setWidth] = useState(0);
|
|
276
|
+
*
|
|
277
|
+
* useIsomorphicLayoutEffect(() => {
|
|
278
|
+
* if (ref.current) {
|
|
279
|
+
* setWidth(ref.current.getBoundingClientRect().width);
|
|
280
|
+
* }
|
|
281
|
+
* }, []);
|
|
282
|
+
*
|
|
283
|
+
* return <div ref={ref}>Width: {width}</div>;
|
|
178
284
|
*/
|
|
179
|
-
declare const useIsomorphicLayoutEffect: typeof
|
|
285
|
+
declare const useIsomorphicLayoutEffect: typeof useLayoutEffect;
|
|
180
286
|
//#endregion
|
|
181
287
|
//#region src/hooks/use-matches-media-query.d.ts
|
|
182
288
|
/**
|
|
183
|
-
* React hook that subscribes to
|
|
289
|
+
* React hook that subscribes to a CSS media query and returns whether it
|
|
290
|
+
* currently matches, re-rendering whenever the result changes.
|
|
184
291
|
*
|
|
185
|
-
*
|
|
186
|
-
*
|
|
292
|
+
* Uses `window.matchMedia` under the hood and `useSyncExternalStore` for
|
|
293
|
+
* compatibility with React's concurrent rendering model. Returns `false`
|
|
294
|
+
* on the server; during hydration React uses that server snapshot before
|
|
295
|
+
* updating to the client media-query value.
|
|
187
296
|
*
|
|
188
|
-
*
|
|
297
|
+
* For common viewport breakpoint checks, prefer the more specific
|
|
298
|
+
* {@link useBreakpoint} or {@link useIsBelowBreakpoint} hooks.
|
|
189
299
|
*
|
|
190
|
-
* @
|
|
300
|
+
* @param query - A valid CSS media query string
|
|
301
|
+
* (e.g. `"(max-width: 768px)"`, `"(prefers-color-scheme: dark)"`).
|
|
302
|
+
* @returns `true` if the media query currently matches, otherwise `false`.
|
|
191
303
|
*
|
|
192
304
|
* @example
|
|
193
|
-
* // Detect if the user prefers a dark color scheme
|
|
194
|
-
* const
|
|
305
|
+
* // Detect if the user prefers a dark color scheme
|
|
306
|
+
* const prefersDark = useMatchesMediaQuery("(prefers-color-scheme: dark)");
|
|
195
307
|
*
|
|
196
|
-
*
|
|
197
|
-
*
|
|
198
|
-
*
|
|
199
|
-
*
|
|
200
|
-
*
|
|
308
|
+
* return <div className={prefersDark ? "dark" : "light"}>Hello</div>;
|
|
309
|
+
*
|
|
310
|
+
* @example
|
|
311
|
+
* // Show a different layout on portrait orientation
|
|
312
|
+
* const isPortrait = useMatchesMediaQuery("(orientation: portrait)");
|
|
313
|
+
*
|
|
314
|
+
* return isPortrait ? <PortraitLayout /> : <LandscapeLayout />;
|
|
201
315
|
*/
|
|
202
316
|
declare function useMatchesMediaQuery(query: string): boolean;
|
|
203
317
|
//#endregion
|
|
204
318
|
//#region src/hooks/use-prefers-reduced-motion.d.ts
|
|
205
319
|
/**
|
|
206
|
-
* Imperatively reads the current `prefers-reduced-motion` preference
|
|
207
|
-
*
|
|
320
|
+
* Imperatively reads the current `prefers-reduced-motion` preference once at
|
|
321
|
+
* the time of the call.
|
|
322
|
+
*
|
|
323
|
+
* Useful in event handlers, animation entrypoints, or plain functions where
|
|
324
|
+
* a React hook cannot be called. Prefer {@link usePrefersReducedMotion}
|
|
325
|
+
* inside components — it subscribes to live changes.
|
|
208
326
|
*
|
|
209
|
-
*
|
|
327
|
+
* @returns `true` when the user has opted out of animations or when called
|
|
328
|
+
* outside a browser environment (SSR), `false` when motion is allowed.
|
|
210
329
|
*
|
|
211
330
|
* @remarks
|
|
212
|
-
*
|
|
213
|
-
*
|
|
331
|
+
* The conservative SSR default of `true` matches
|
|
332
|
+
* {@link usePrefersReducedMotion}: animations stay off until we can verify
|
|
333
|
+
* the user's preference on the client.
|
|
334
|
+
*
|
|
335
|
+
* @example
|
|
336
|
+
* // Skip a one-off entrance animation in a click handler
|
|
337
|
+
* function onOpen() {
|
|
338
|
+
* if (getPrefersReducedMotion()) {
|
|
339
|
+
* element.style.opacity = "1";
|
|
340
|
+
* return;
|
|
341
|
+
* }
|
|
342
|
+
* element.animate([{ opacity: 0 }, { opacity: 1 }], { duration: 200 });
|
|
343
|
+
* }
|
|
214
344
|
*/
|
|
215
345
|
declare function getPrefersReducedMotion(): boolean;
|
|
216
346
|
/**
|
|
217
|
-
*
|
|
347
|
+
* React hook that subscribes to the user's `prefers-reduced-motion` media
|
|
348
|
+
* query and re-renders when it changes.
|
|
349
|
+
*
|
|
350
|
+
* Defaults to `true` (reduce motion) on the server and during the first
|
|
351
|
+
* client render to avoid animating before hydration. The initial client
|
|
352
|
+
* effect reads the *real* preference and updates state. The underlying
|
|
353
|
+
* media query used is `(prefers-reduced-motion: no-preference)` inverted —
|
|
354
|
+
* "if the system hasn't opted out, animations are allowed."
|
|
218
355
|
*
|
|
219
|
-
*
|
|
220
|
-
*
|
|
221
|
-
*
|
|
222
|
-
*
|
|
223
|
-
*
|
|
224
|
-
*
|
|
356
|
+
* @returns `true` when the user prefers reduced motion (animations should be
|
|
357
|
+
* shortened or skipped), `false` when full motion is acceptable.
|
|
358
|
+
*
|
|
359
|
+
* @remarks
|
|
360
|
+
* If you need to support very old browsers that lack
|
|
361
|
+
* `MediaQueryList.addEventListener`, consider falling back to
|
|
362
|
+
* `addListener` / `removeListener`.
|
|
225
363
|
*
|
|
226
364
|
* @example
|
|
227
365
|
* // Conditionally shorten or skip transitions
|
|
228
|
-
* const
|
|
229
|
-
* const duration =
|
|
366
|
+
* const prefersReducedMotion = usePrefersReducedMotion();
|
|
367
|
+
* const duration = prefersReducedMotion ? 0 : 200;
|
|
230
368
|
*
|
|
231
|
-
*
|
|
232
|
-
*
|
|
233
|
-
*
|
|
369
|
+
* return <Modal transitionDuration={duration} />;
|
|
370
|
+
*
|
|
371
|
+
* @example
|
|
372
|
+
* // Disable an autoplaying carousel when motion is reduced
|
|
373
|
+
* const prefersReducedMotion = usePrefersReducedMotion();
|
|
374
|
+
*
|
|
375
|
+
* return <Carousel autoplay={!prefersReducedMotion} />;
|
|
234
376
|
*/
|
|
235
377
|
declare function usePrefersReducedMotion(): boolean;
|
|
236
378
|
//#endregion
|
|
237
379
|
//#region src/hooks/use-random-stable-id.d.ts
|
|
238
380
|
/**
|
|
239
|
-
*
|
|
240
|
-
*
|
|
241
|
-
*
|
|
381
|
+
* React hook that returns a random, stable id (e.g. `"mantle-a3f9k7q"`)
|
|
382
|
+
* suitable for DOM `id` attributes and `aria-*` references.
|
|
383
|
+
*
|
|
384
|
+
* Unlike React's built-in `useId`, the generated suffix does not contain
|
|
385
|
+
* special characters (`:`). The default id is safe to use directly in CSS
|
|
386
|
+
* selectors and `querySelector` calls; if you provide a custom `prefix`,
|
|
387
|
+
* keep it selector-safe or escape the final id with `CSS.escape()` before
|
|
388
|
+
* querying. The id is generated once for the lifetime of the component and
|
|
389
|
+
* is stable across re-renders, but a new value is produced when `prefix`
|
|
390
|
+
* changes.
|
|
391
|
+
*
|
|
392
|
+
* @param prefix - Optional string prepended to the generated suffix.
|
|
393
|
+
* Whitespace-only or empty values fall back to `"mantle"`. Use a
|
|
394
|
+
* selector-safe prefix if you plan to reference the id in CSS selectors
|
|
395
|
+
* without escaping. Defaults to `"mantle"`.
|
|
396
|
+
* @returns A string of the form `"<prefix>-<7-char-random>"`.
|
|
397
|
+
*
|
|
398
|
+
* @example
|
|
399
|
+
* // Associate a label with a custom input
|
|
400
|
+
* const id = useRandomStableId("email-input");
|
|
401
|
+
*
|
|
402
|
+
* return (
|
|
403
|
+
* <>
|
|
404
|
+
* <label htmlFor={id}>Email</label>
|
|
405
|
+
* <input id={id} type="email" />
|
|
406
|
+
* </>
|
|
407
|
+
* );
|
|
408
|
+
*
|
|
409
|
+
* @example
|
|
410
|
+
* // Use as an aria-controls reference
|
|
411
|
+
* const panelId = useRandomStableId("panel");
|
|
412
|
+
*
|
|
413
|
+
* return (
|
|
414
|
+
* <>
|
|
415
|
+
* <button aria-controls={panelId}>Toggle</button>
|
|
416
|
+
* <div id={panelId}>Panel contents</div>
|
|
417
|
+
* </>
|
|
418
|
+
* );
|
|
242
419
|
*/
|
|
243
420
|
declare const useRandomStableId: (prefix?: string) => string;
|
|
244
421
|
//#endregion
|
|
@@ -253,24 +430,38 @@ declare const useRandomStableId: (prefix?: string) => string;
|
|
|
253
430
|
*/
|
|
254
431
|
type ScrollBehavior = "auto" | "smooth";
|
|
255
432
|
/**
|
|
256
|
-
*
|
|
433
|
+
* React hook that returns a {@link ScrollBehavior} value (`"auto"` or
|
|
434
|
+
* `"smooth"`) that respects the user's motion preference.
|
|
257
435
|
*
|
|
258
|
-
*
|
|
259
|
-
*
|
|
436
|
+
* Internally calls {@link usePrefersReducedMotion}: when reduced motion is
|
|
437
|
+
* preferred, this returns `"auto"` (no animated scroll); otherwise it
|
|
438
|
+
* returns `"smooth"`. Pair this with `window.scrollTo`,
|
|
439
|
+
* `Element.scrollIntoView`, or any other scroll API that accepts a
|
|
440
|
+
* `behavior` option to avoid forcing animations on users who have opted
|
|
441
|
+
* out of motion. The conservative SSR default also prevents "first paint"
|
|
442
|
+
* scroll animations.
|
|
260
443
|
*
|
|
261
|
-
*
|
|
262
|
-
*
|
|
263
|
-
* animations thanks to the hook’s conservative server default.
|
|
444
|
+
* @returns `"auto"` when the user prefers reduced motion, otherwise
|
|
445
|
+
* `"smooth"`.
|
|
264
446
|
*
|
|
265
447
|
* @example
|
|
266
|
-
* // Scroll to top
|
|
448
|
+
* // Scroll to the top of the page on a button click
|
|
267
449
|
* const behavior = useScrollBehavior();
|
|
268
|
-
*
|
|
450
|
+
*
|
|
451
|
+
* return (
|
|
452
|
+
* <button onClick={() => window.scrollTo({ top: 0, behavior })}>
|
|
453
|
+
* Back to top
|
|
454
|
+
* </button>
|
|
455
|
+
* );
|
|
269
456
|
*
|
|
270
457
|
* @example
|
|
271
|
-
* // Bring a section into view
|
|
458
|
+
* // Bring a referenced section into view
|
|
272
459
|
* const behavior = useScrollBehavior();
|
|
273
|
-
* sectionRef
|
|
460
|
+
* const sectionRef = useRef<HTMLElement>(null);
|
|
461
|
+
*
|
|
462
|
+
* function focusSection() {
|
|
463
|
+
* sectionRef.current?.scrollIntoView({ behavior, block: "start" });
|
|
464
|
+
* }
|
|
274
465
|
*
|
|
275
466
|
* @see {@link usePrefersReducedMotion}
|
|
276
467
|
* @see CSS `scroll-behavior` property (values: `"auto"`, `"smooth"`).
|
|
@@ -361,32 +552,66 @@ type UseUndoRedoReturn<T> = {
|
|
|
361
552
|
redo: (current: T) => T | undefined;
|
|
362
553
|
};
|
|
363
554
|
/**
|
|
364
|
-
*
|
|
365
|
-
*
|
|
366
|
-
*
|
|
367
|
-
*
|
|
368
|
-
*
|
|
555
|
+
* Generic undo/redo hook backed by a reducer that maintains two history
|
|
556
|
+
* stacks (undo and redo).
|
|
557
|
+
*
|
|
558
|
+
* The hook does not own your application state — instead it helps you
|
|
559
|
+
* snapshot it. Call `push(snapshot)` *before* mutating state to capture
|
|
560
|
+
* the current value, then call `undo(current)` or `redo(current)` to swap
|
|
561
|
+
* `current` with the previous/next snapshot. Both `undo` and `redo` return
|
|
562
|
+
* the snapshot to apply, or `undefined` if their stack is empty. Pushing a
|
|
563
|
+
* new snapshot clears the redo stack, matching standard editor semantics.
|
|
564
|
+
*
|
|
565
|
+
* @typeParam T - The type of the value being snapshotted (e.g. a list of
|
|
566
|
+
* items, a serialized form value, etc.).
|
|
567
|
+
*
|
|
568
|
+
* @returns An object with the current undo/redo capability flags and
|
|
569
|
+
* actions:
|
|
570
|
+
* - `canUndo`: `true` when there is at least one snapshot on the undo
|
|
571
|
+
* stack.
|
|
572
|
+
* - `canRedo`: `true` when there is at least one snapshot on the redo
|
|
573
|
+
* stack.
|
|
574
|
+
* - `push(snapshot)`: Push a snapshot onto the undo stack and clear the
|
|
575
|
+
* redo stack. Call this *before* mutating state.
|
|
576
|
+
* - `undo(current)`: Pop the latest undo snapshot and return it; returns
|
|
577
|
+
* `undefined` when the undo stack is empty. The supplied `current` is
|
|
578
|
+
* pushed onto the redo stack so you can redo back to it.
|
|
579
|
+
* - `redo(current)`: Pop the latest redo snapshot and return it; returns
|
|
580
|
+
* `undefined` when the redo stack is empty. The supplied `current` is
|
|
581
|
+
* pushed onto the undo stack.
|
|
369
582
|
*
|
|
370
583
|
* @example
|
|
371
|
-
*
|
|
584
|
+
* // Snapshot before mutating, then wire up keyboard shortcuts
|
|
585
|
+
* const [items, setItems] = useState<string[]>([]);
|
|
372
586
|
* const { push, undo, redo, canUndo, canRedo } = useUndoRedo<string[]>();
|
|
373
587
|
*
|
|
374
588
|
* function removeItem(item: string) {
|
|
375
|
-
* push(
|
|
376
|
-
* setItems(
|
|
589
|
+
* push(items); // snapshot before mutation
|
|
590
|
+
* setItems((prev) => prev.filter((entry) => entry !== item));
|
|
377
591
|
* }
|
|
378
592
|
*
|
|
379
|
-
* function handleKeyDown(event: KeyboardEvent) {
|
|
380
|
-
*
|
|
593
|
+
* function handleKeyDown(event: React.KeyboardEvent) {
|
|
594
|
+
* const cmd = event.metaKey || event.ctrlKey;
|
|
595
|
+
* if (cmd && event.key === "z" && !event.shiftKey) {
|
|
381
596
|
* const previous = undo(items);
|
|
382
|
-
* if (previous)
|
|
597
|
+
* if (previous) {
|
|
598
|
+
* setItems(previous);
|
|
599
|
+
* }
|
|
383
600
|
* }
|
|
384
|
-
* if (
|
|
601
|
+
* if (cmd && ((event.shiftKey && event.key === "z") || event.key === "y")) {
|
|
385
602
|
* const next = redo(items);
|
|
386
|
-
* if (next)
|
|
603
|
+
* if (next) {
|
|
604
|
+
* setItems(next);
|
|
605
|
+
* }
|
|
387
606
|
* }
|
|
388
607
|
* }
|
|
389
|
-
*
|
|
608
|
+
*
|
|
609
|
+
* return (
|
|
610
|
+
* <div tabIndex={0} onKeyDown={handleKeyDown}>
|
|
611
|
+
* <button disabled={!canUndo} onClick={() => { const previous = undo(items); if (previous) setItems(previous); }}>Undo</button>
|
|
612
|
+
* <button disabled={!canRedo} onClick={() => { const next = redo(items); if (next) setItems(next); }}>Redo</button>
|
|
613
|
+
* </div>
|
|
614
|
+
* );
|
|
390
615
|
*/
|
|
391
616
|
declare function useUndoRedo<T>(): UseUndoRedoReturn<T>;
|
|
392
617
|
//#endregion
|