what-core 0.12.2 → 0.12.4
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/{chunk-NCPX66TV.min.js → chunk-M5GDJRVX.min.js} +1 -1
- package/dist/chunk-T2SKNKT5.min.js +11 -0
- package/dist/index.min.js +5 -5
- package/dist/render.min.js +1 -1
- package/dist/testing.min.js +1 -1
- package/index.d.ts +329 -40
- package/package.json +1 -1
- package/src/a11y.js +234 -23
- package/src/agent-context.js +1 -1
- package/src/animation.js +8 -0
- package/src/data.js +730 -105
- package/src/dom.js +52 -0
- package/src/errors.js +12 -1
- package/src/form.js +329 -31
- package/src/hooks.js +20 -3
- package/src/index.js +6 -0
- package/src/render.js +872 -50
- package/src/scheduler.js +17 -0
- package/src/warnings.js +83 -0
- package/dist/chunk-RXISSKLI.min.js +0 -11
package/index.d.ts
CHANGED
|
@@ -28,7 +28,13 @@ export function signal<T>(initial: T, debugName?: string): Signal<T>;
|
|
|
28
28
|
export function computed<T>(fn: () => T): Computed<T>;
|
|
29
29
|
export function effect(fn: () => void | (() => void), opts?: { stable?: boolean }): () => void;
|
|
30
30
|
export function signalMemo<T>(fn: () => T): Computed<T>;
|
|
31
|
-
|
|
31
|
+
/**
|
|
32
|
+
* Group signal writes so effects run once at the end. The callback's return
|
|
33
|
+
* value is DISCARDED: batch() returns undefined. It was declared as `<T>(fn: ()
|
|
34
|
+
* => T) => T`, so `const rows = batch(() => compute())` typechecked and handed
|
|
35
|
+
* back undefined at runtime.
|
|
36
|
+
*/
|
|
37
|
+
export function batch(fn: () => unknown): void;
|
|
32
38
|
export function untrack<T>(fn: () => T): T;
|
|
33
39
|
export function flushSync(): void;
|
|
34
40
|
export function createRoot<T>(fn: (dispose: () => void) => T): T;
|
|
@@ -106,11 +112,33 @@ export function classList(el: Element, classes: Record<string, boolean | (() =>
|
|
|
106
112
|
|
|
107
113
|
// --- Hooks ---
|
|
108
114
|
|
|
109
|
-
|
|
115
|
+
/**
|
|
116
|
+
* Returns [signal, setter]. The first element is the SIGNAL ITSELF, not a
|
|
117
|
+
* snapshot value: components run once, so there is no re-render to hand a new
|
|
118
|
+
* `T` to. Read it by calling it (`count()`), or pass it straight into JSX where
|
|
119
|
+
* insert() binds it reactively.
|
|
120
|
+
*
|
|
121
|
+
* It was declared as `[T, setter]`, which made the correct code (`count()`) a
|
|
122
|
+
* type error and the wrong code (`count + 1`) type-check.
|
|
123
|
+
*/
|
|
124
|
+
export function useState<T>(initial: T | (() => T)): [Signal<T>, (value: Updater<T>) => void];
|
|
110
125
|
export function useSignal<T>(initial: T | (() => T)): Signal<T>;
|
|
111
126
|
export function useComputed<T>(fn: () => T): Computed<T>;
|
|
112
127
|
export function useEffect(fn: () => void | (() => void), deps?: unknown[]): void;
|
|
113
|
-
|
|
128
|
+
/**
|
|
129
|
+
* Returns a COMPUTED ACCESSOR, not the value. Same reason as useState: the
|
|
130
|
+
* component body runs once, so nothing would ever hand back a refreshed `T`.
|
|
131
|
+
* Read it by calling it (`total()`), or pass the accessor straight into JSX
|
|
132
|
+
* where insert() tracks it.
|
|
133
|
+
*
|
|
134
|
+
* `deps` is accepted for React familiarity and ignored at runtime: computed()
|
|
135
|
+
* tracks whatever signals the callback actually reads.
|
|
136
|
+
*
|
|
137
|
+
* It was declared as `T`, which inverted both halves: `useMemo(...) * 2`
|
|
138
|
+
* type-checked and produced NaN, while the correct `useMemo(...)()` was the
|
|
139
|
+
* type error.
|
|
140
|
+
*/
|
|
141
|
+
export function useMemo<T>(fn: () => T, deps?: unknown[]): Computed<T>;
|
|
114
142
|
export function useCallback<T extends (...args: any[]) => any>(fn: T, deps?: unknown[]): T;
|
|
115
143
|
export function useRef<T>(initial: T): { current: T };
|
|
116
144
|
|
|
@@ -121,11 +149,19 @@ export interface Context<T> {
|
|
|
121
149
|
|
|
122
150
|
export function createContext<T>(defaultValue: T): Context<T>;
|
|
123
151
|
export function useContext<T>(context: Context<T>): T;
|
|
152
|
+
/**
|
|
153
|
+
* Returns [signal, dispatch]. The first element is the SIGNAL ITSELF, exactly
|
|
154
|
+
* as useState returns it and for the same run-once reason. Read it with
|
|
155
|
+
* `state()`.
|
|
156
|
+
*
|
|
157
|
+
* It was declared as `[S, dispatch]`, so `state.items` type-checked (and read
|
|
158
|
+
* `undefined` off a function object) while `state()` did not.
|
|
159
|
+
*/
|
|
124
160
|
export function useReducer<S, A>(
|
|
125
161
|
reducer: (state: S, action: A) => S,
|
|
126
162
|
initialState: S,
|
|
127
163
|
init?: (initial: S) => S,
|
|
128
|
-
): [S
|
|
164
|
+
): [Signal<S>, (action: A) => void];
|
|
129
165
|
export function onMount(fn: () => void): void;
|
|
130
166
|
export function onCleanup(fn: () => void): void;
|
|
131
167
|
|
|
@@ -190,11 +226,22 @@ export function Island(props: IslandProps): VNode;
|
|
|
190
226
|
|
|
191
227
|
// --- State ---
|
|
192
228
|
|
|
193
|
-
|
|
229
|
+
/** `_storeComputed` is the marker createStore() actually reads to tell a derived value from an action. */
|
|
230
|
+
export type DerivedFn<T> = ((state: any) => T) & { _storeComputed: true };
|
|
194
231
|
export function derived<T>(fn: (state: any) => T): DerivedFn<T>;
|
|
232
|
+
/** @deprecated Use derived(). Warns once at runtime. */
|
|
195
233
|
export function storeComputed<T>(fn: (state: any) => T): DerivedFn<T>;
|
|
196
234
|
export type StoreDefinition = Record<string, any>;
|
|
197
|
-
|
|
235
|
+
/**
|
|
236
|
+
* The store hook resolves every derived key to its VALUE. State and derived
|
|
237
|
+
* keys are both getters on the returned object, only actions stay callable.
|
|
238
|
+
* `Store<T> = T` left a derived key typed as the DerivedFn you wrote in the
|
|
239
|
+
* definition, so `store.total` looked callable and `store.total * 2` was the
|
|
240
|
+
* type error, which is backwards from the runtime.
|
|
241
|
+
*/
|
|
242
|
+
export type Store<T extends StoreDefinition> = {
|
|
243
|
+
[K in keyof T]: T[K] extends DerivedFn<infer U> ? U : T[K];
|
|
244
|
+
};
|
|
198
245
|
export function createStore<T extends StoreDefinition>(definition: T): () => Store<T>;
|
|
199
246
|
export function atom<T>(initial: T): Signal<T>;
|
|
200
247
|
|
|
@@ -280,31 +327,153 @@ export function smoothScrollTo(
|
|
|
280
327
|
): Promise<void>;
|
|
281
328
|
|
|
282
329
|
// --- Animation ---
|
|
330
|
+
//
|
|
331
|
+
// Every accessor below is a plain getter function, NOT a Signal: the objects
|
|
332
|
+
// these factories return expose reads through closures and offer writes as
|
|
333
|
+
// named methods (set/snap/setValue), so nothing here carries .set/.peek. The
|
|
334
|
+
// declarations used to promise Signal<number> and a single shared SpringValue
|
|
335
|
+
// shape for both spring() and tween(), which are two different objects.
|
|
336
|
+
|
|
337
|
+
export interface SpringConfig {
|
|
338
|
+
stiffness?: number;
|
|
339
|
+
damping?: number;
|
|
340
|
+
mass?: number;
|
|
341
|
+
precision?: number;
|
|
342
|
+
}
|
|
283
343
|
|
|
344
|
+
/** Physics-based value. `set()` retargets and animates; `snap()` jumps without animating. */
|
|
284
345
|
export interface SpringValue {
|
|
285
346
|
current(): number;
|
|
286
|
-
|
|
347
|
+
target(): number;
|
|
348
|
+
velocity(): number;
|
|
349
|
+
isAnimating(): boolean;
|
|
350
|
+
set(target: number): void;
|
|
287
351
|
stop(): void;
|
|
288
|
-
|
|
352
|
+
snap(value: number): void;
|
|
353
|
+
subscribe(fn: (value: number) => void): () => void;
|
|
354
|
+
}
|
|
355
|
+
|
|
356
|
+
export interface TweenConfig {
|
|
357
|
+
duration?: number;
|
|
358
|
+
easing?: (t: number) => number;
|
|
359
|
+
onUpdate?: (value: number, progress: number) => void;
|
|
360
|
+
onComplete?: () => void;
|
|
361
|
+
}
|
|
362
|
+
|
|
363
|
+
/**
|
|
364
|
+
* Easing-based interpolation from `from` to `to`. Starts immediately on
|
|
365
|
+
* creation and runs to completion, so it exposes `cancel()` rather than the
|
|
366
|
+
* spring's retargeting `set()`/`stop()`.
|
|
367
|
+
*/
|
|
368
|
+
export interface TweenValue {
|
|
369
|
+
progress(): number;
|
|
370
|
+
value(): number;
|
|
371
|
+
isAnimating(): boolean;
|
|
372
|
+
cancel(): void;
|
|
373
|
+
subscribe(fn: (value: number) => void): () => void;
|
|
289
374
|
}
|
|
290
375
|
|
|
291
|
-
export function spring(initialValue
|
|
292
|
-
|
|
376
|
+
export function spring(initialValue: number, config?: SpringConfig): SpringValue;
|
|
377
|
+
/**
|
|
378
|
+
* Both endpoints are required and positional. This was declared as
|
|
379
|
+
* `tween(initialValue?, config?)` returning a SpringValue, so the documented
|
|
380
|
+
* call `tween(0, 100, { duration: 300 })` was a type error, while
|
|
381
|
+
* `tween(0).current()` type-checked and threw (`current` does not exist, and a
|
|
382
|
+
* missing `to` interpolates toward undefined).
|
|
383
|
+
*/
|
|
384
|
+
export function tween(from: number, to: number, config?: TweenConfig): TweenValue;
|
|
293
385
|
export const easings: Record<string, (t: number) => number>;
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
386
|
+
/**
|
|
387
|
+
* Drives a 0..1 progress value over `duration`. This is NOT React's
|
|
388
|
+
* useTransition, and it never had the mounted/styles/show/hide members that
|
|
389
|
+
* were declared here, and all four were undefined at runtime.
|
|
390
|
+
*/
|
|
391
|
+
export function useTransition(options?: { duration?: number; easing?: (t: number) => number }): {
|
|
392
|
+
isTransitioning: () => boolean;
|
|
393
|
+
progress: () => number;
|
|
394
|
+
start: (callback?: () => void) => Promise<void>;
|
|
299
395
|
};
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
396
|
+
|
|
397
|
+
/** Live gesture state. `startX`/`startY` are plain numbers rewritten in place at gesture start. */
|
|
398
|
+
export interface GestureState {
|
|
399
|
+
isDragging: Signal<boolean>;
|
|
400
|
+
startX: number;
|
|
401
|
+
startY: number;
|
|
402
|
+
currentX: Signal<number>;
|
|
403
|
+
currentY: Signal<number>;
|
|
404
|
+
deltaX: Signal<number>;
|
|
405
|
+
deltaY: Signal<number>;
|
|
406
|
+
velocity: Signal<GestureVelocity>;
|
|
407
|
+
}
|
|
408
|
+
|
|
409
|
+
export interface GestureVelocity {
|
|
410
|
+
x: number;
|
|
411
|
+
y: number;
|
|
412
|
+
}
|
|
413
|
+
|
|
414
|
+
/**
|
|
415
|
+
* `preventDefault` is why this cannot be a `Record<string, (payload) => void>`:
|
|
416
|
+
* it sits in the same object as the callbacks and is a boolean.
|
|
417
|
+
*/
|
|
418
|
+
export interface GestureHandlers {
|
|
419
|
+
onDragStart?: (payload: { x: number; y: number }) => void;
|
|
420
|
+
onDrag?: (payload: {
|
|
421
|
+
x: number; y: number; deltaX: number; deltaY: number; velocity: GestureVelocity;
|
|
422
|
+
}) => void;
|
|
423
|
+
onDragEnd?: (payload: { deltaX: number; deltaY: number; velocity: GestureVelocity }) => void;
|
|
424
|
+
onPinch?: (payload: { scale: number; centerX: number; centerY: number }) => void;
|
|
425
|
+
onSwipe?: (payload: { direction: 'up' | 'down' | 'left' | 'right'; velocity: GestureVelocity }) => void;
|
|
426
|
+
onTap?: (payload: { x: number; y: number }) => void;
|
|
427
|
+
onLongPress?: (payload: { x: number; y: number }) => void;
|
|
428
|
+
/** Opt in to e.preventDefault() in the touch handlers (listeners become non-passive). */
|
|
429
|
+
preventDefault?: boolean;
|
|
430
|
+
}
|
|
431
|
+
|
|
432
|
+
/** Returns the gesture state. It was declared `void`, so the state was unreachable from TypeScript. */
|
|
433
|
+
export function useGesture(
|
|
434
|
+
ref: { current?: Element | null } | Element | (() => Element | null),
|
|
435
|
+
handlers?: GestureHandlers,
|
|
436
|
+
): GestureState;
|
|
437
|
+
|
|
438
|
+
/** Handle for one running animation started by useAnimatedValue. */
|
|
439
|
+
export interface AnimationHandle {
|
|
304
440
|
stop: () => void;
|
|
441
|
+
}
|
|
442
|
+
|
|
443
|
+
/**
|
|
444
|
+
* `animateTo` and `stop` were declared here and have never existed. Animations
|
|
445
|
+
* are started with spring()/timing(), each returning its own handle to stop.
|
|
446
|
+
*/
|
|
447
|
+
export function useAnimatedValue(initialValue: number): {
|
|
448
|
+
value: () => number;
|
|
449
|
+
setValue: (value: number) => void;
|
|
450
|
+
spring: (toValue: number, config?: SpringConfig) => AnimationHandle;
|
|
451
|
+
timing: (toValue: number, config?: TweenConfig) => AnimationHandle;
|
|
452
|
+
interpolate: (inputRange: number[], outputRange: number[]) => () => number;
|
|
453
|
+
subscribe: (fn: (value: number) => void) => () => void;
|
|
305
454
|
};
|
|
306
|
-
|
|
307
|
-
export
|
|
455
|
+
|
|
456
|
+
export interface TransitionClasses {
|
|
457
|
+
enter: string;
|
|
458
|
+
enterActive: string;
|
|
459
|
+
enterDone: string;
|
|
460
|
+
exit: string;
|
|
461
|
+
exitActive: string;
|
|
462
|
+
exitDone: string;
|
|
463
|
+
}
|
|
464
|
+
|
|
465
|
+
/** Returns the six class NAMES for `name`, not a single string. */
|
|
466
|
+
export function createTransitionClasses(name: string): TransitionClasses;
|
|
467
|
+
/**
|
|
468
|
+
* Applies the enter/exit class sequence to an element and resolves when the
|
|
469
|
+
* transition is done. It was declared as a synchronous `(config) => object`.
|
|
470
|
+
*/
|
|
471
|
+
export function cssTransition(
|
|
472
|
+
element: Element,
|
|
473
|
+
name: string,
|
|
474
|
+
type?: 'enter' | 'exit',
|
|
475
|
+
duration?: number,
|
|
476
|
+
): Promise<void>;
|
|
308
477
|
|
|
309
478
|
// --- Accessibility ---
|
|
310
479
|
|
|
@@ -353,11 +522,51 @@ export function useAriaChecked(initialChecked?: boolean): {
|
|
|
353
522
|
checkboxProps: () => Record<string, any>;
|
|
354
523
|
};
|
|
355
524
|
|
|
356
|
-
export
|
|
525
|
+
export interface RovingTabIndexOptions {
|
|
526
|
+
/**
|
|
527
|
+
* Container role, emitted by containerProps(). The hook emits NO role by
|
|
528
|
+
* default: roving tabindex is the shared keyboard mechanic of toolbars,
|
|
529
|
+
* menus, trees, grids, tablists, radiogroups and listboxes, and a default
|
|
530
|
+
* spread last would silently overwrite the role the caller wrote beside it.
|
|
531
|
+
*/
|
|
532
|
+
role?: string;
|
|
533
|
+
}
|
|
534
|
+
|
|
535
|
+
/**
|
|
536
|
+
* Props for one roving item. `ref` is the item's REGISTRATION (the hook holds
|
|
537
|
+
* the node through it and cannot move focus without it), so a `ref` passed via
|
|
538
|
+
* `overrides` is chained rather than replaced. `tabIndex` is an accessor, not a
|
|
539
|
+
* number: exactly one item is tabbable at a time and which one changes as focus
|
|
540
|
+
* roves, so a resolved value could not survive the spread.
|
|
541
|
+
*/
|
|
542
|
+
export interface RovingItemProps {
|
|
543
|
+
ref: { current: Element | null };
|
|
544
|
+
tabIndex: () => number;
|
|
545
|
+
onKeyDown: (e: KeyboardEvent) => void;
|
|
546
|
+
onFocus: (e: Event) => void;
|
|
547
|
+
[prop: string]: any;
|
|
548
|
+
}
|
|
549
|
+
|
|
550
|
+
export function useRovingTabIndex(
|
|
551
|
+
itemCountOrSignal: number | (() => number),
|
|
552
|
+
options?: RovingTabIndexOptions,
|
|
553
|
+
): {
|
|
554
|
+
/** Active index, clamped to the current count so the group is never untabbable. */
|
|
357
555
|
focusIndex: () => number;
|
|
556
|
+
/**
|
|
557
|
+
* Set the active index. Out-of-range indexes are REFUSED, not clamped. Moves
|
|
558
|
+
* real focus only when the group already owns it, so syncing from application
|
|
559
|
+
* state cannot steal focus from elsewhere on the page.
|
|
560
|
+
*/
|
|
358
561
|
setFocusIndex: (index: number) => void;
|
|
359
|
-
|
|
360
|
-
|
|
562
|
+
/**
|
|
563
|
+
* Explicitly move focus to an item (a menu focusing its first item on open).
|
|
564
|
+
* Returns the element it focused, or null when the index is out of range or
|
|
565
|
+
* the item is not in the DOM.
|
|
566
|
+
*/
|
|
567
|
+
focusItem: (index: number) => Element | null;
|
|
568
|
+
getItemProps: (index: number, overrides?: Record<string, any>) => RovingItemProps;
|
|
569
|
+
containerProps: (overrides?: Record<string, any>) => Record<string, any>;
|
|
361
570
|
};
|
|
362
571
|
|
|
363
572
|
export function VisuallyHidden(props: { children?: VNodeChild; as?: string }): VNode;
|
|
@@ -413,7 +622,8 @@ export function Spinner(props?: Record<string, any>): VNode;
|
|
|
413
622
|
// --- Data Fetching ---
|
|
414
623
|
|
|
415
624
|
export function useFetch<T = any>(url: string, options?: Record<string, any>): {
|
|
416
|
-
|
|
625
|
+
/** null until the first response lands. It was declared as bare `T`, so strict-mode callers skipped the check they need. */
|
|
626
|
+
data: () => T | null;
|
|
417
627
|
error: () => any;
|
|
418
628
|
isLoading: () => boolean;
|
|
419
629
|
refetch: () => Promise<void>;
|
|
@@ -429,36 +639,88 @@ export function useSWR<T = any>(key: string | null | false, fetcher: (key: strin
|
|
|
429
639
|
revalidate: () => Promise<T | void>;
|
|
430
640
|
};
|
|
431
641
|
|
|
642
|
+
/**
|
|
643
|
+
* 'idle' is a real state, not a placeholder: a query with `enabled: false` and
|
|
644
|
+
* nothing cached is idle, and reporting it as loading is what renders a spinner
|
|
645
|
+
* that never comes down.
|
|
646
|
+
*/
|
|
647
|
+
export type QueryStatus = 'idle' | 'loading' | 'success' | 'error';
|
|
648
|
+
/** Whether a request is on the wire, independent of whether data exists. */
|
|
649
|
+
export type FetchStatus = 'idle' | 'fetching';
|
|
650
|
+
|
|
651
|
+
/**
|
|
652
|
+
* Any array key is joined into a single normalized string, so an array and its
|
|
653
|
+
* normalization address the same cache entry everywhere a key is accepted.
|
|
654
|
+
*/
|
|
655
|
+
export type QueryKey = string | readonly unknown[];
|
|
656
|
+
|
|
432
657
|
export function useQuery<T = any>(options: Record<string, any>): {
|
|
433
658
|
data: () => T | null;
|
|
434
659
|
error: () => any;
|
|
435
|
-
status: () =>
|
|
660
|
+
status: () => QueryStatus;
|
|
661
|
+
fetchStatus: () => FetchStatus;
|
|
436
662
|
isLoading: () => boolean;
|
|
437
663
|
isFetching: () => boolean;
|
|
438
664
|
isError: () => boolean;
|
|
439
665
|
isSuccess: () => boolean;
|
|
666
|
+
isIdle: () => boolean;
|
|
667
|
+
/** Whether the `enabled` gate is currently open. */
|
|
668
|
+
isEnabled: () => boolean;
|
|
440
669
|
refetch: () => Promise<T | void>;
|
|
441
670
|
};
|
|
442
671
|
|
|
672
|
+
/**
|
|
673
|
+
* Pages, plus the param each was fetched with. `pageParams[i]` names `pages[i]`.
|
|
674
|
+
*/
|
|
675
|
+
export interface InfiniteData<T> {
|
|
676
|
+
pages: T[];
|
|
677
|
+
pageParams: unknown[];
|
|
678
|
+
}
|
|
679
|
+
|
|
680
|
+
/**
|
|
681
|
+
* `data()` hands back the page CONTAINER, not a flat array. It was declared as
|
|
682
|
+
* `T[]`, so `data().map(...)` type-checked and threw. The rows are in
|
|
683
|
+
* `data().pages`. A `select` option replaces the container wholesale, and that
|
|
684
|
+
* transformation is not expressible here.
|
|
685
|
+
*/
|
|
443
686
|
export function useInfiniteQuery<T = any>(options: Record<string, any>): {
|
|
444
|
-
data: () => T
|
|
687
|
+
data: () => InfiniteData<T>;
|
|
445
688
|
error: () => any;
|
|
446
|
-
status: () =>
|
|
689
|
+
status: () => QueryStatus;
|
|
447
690
|
isLoading: () => boolean;
|
|
448
|
-
|
|
691
|
+
isError: () => boolean;
|
|
692
|
+
isSuccess: () => boolean;
|
|
693
|
+
isIdle: () => boolean;
|
|
694
|
+
isFetching: () => boolean;
|
|
695
|
+
isEnabled: () => boolean;
|
|
449
696
|
hasNextPage: () => boolean;
|
|
697
|
+
hasPreviousPage: () => boolean;
|
|
698
|
+
isFetchingNextPage: () => boolean;
|
|
699
|
+
isFetchingPreviousPage: () => boolean;
|
|
450
700
|
fetchNextPage: () => Promise<void>;
|
|
701
|
+
fetchPreviousPage: () => Promise<void>;
|
|
451
702
|
refetch: () => Promise<void>;
|
|
452
703
|
};
|
|
453
704
|
|
|
705
|
+
/**
|
|
706
|
+
* Synchronous. It was declared as returning Promise<void>, so `await
|
|
707
|
+
* invalidateQueries(...)` awaited undefined and read as "the refetches are
|
|
708
|
+
* done" when they had only been kicked off. The subscribers it wakes fetch on
|
|
709
|
+
* their own.
|
|
710
|
+
*
|
|
711
|
+
* An array key is a PREFIX unless `exact` is set: invalidateQueries(['todos'])
|
|
712
|
+
* also invalidates ['todos', 1]. `hard` clears the cached value immediately
|
|
713
|
+
* (loading state); the default keeps stale data on screen while it refetches.
|
|
714
|
+
*/
|
|
454
715
|
export function invalidateQueries(
|
|
455
|
-
keyOrPredicate:
|
|
456
|
-
options?: { exact?: boolean },
|
|
457
|
-
):
|
|
458
|
-
|
|
459
|
-
export function prefetchQuery<T = any>(key:
|
|
460
|
-
export function setQueryData<T = any>(key:
|
|
461
|
-
|
|
716
|
+
keyOrPredicate: QueryKey | ((key: string) => boolean),
|
|
717
|
+
options?: { exact?: boolean; hard?: boolean },
|
|
718
|
+
): void;
|
|
719
|
+
|
|
720
|
+
export function prefetchQuery<T = any>(key: QueryKey, fetcher: (key: string) => Promise<T>): Promise<T>;
|
|
721
|
+
export function setQueryData<T = any>(key: QueryKey, updater: T | ((prev: T | null) => T)): void;
|
|
722
|
+
/** `undefined` for a key the cache has never held; `null` for one that was emptied. */
|
|
723
|
+
export function getQueryData<T = any>(key: QueryKey): T | null | undefined;
|
|
462
724
|
export function clearCache(): void;
|
|
463
725
|
|
|
464
726
|
// --- Forms ---
|
|
@@ -469,14 +731,39 @@ export interface FieldError {
|
|
|
469
731
|
[key: string]: any;
|
|
470
732
|
}
|
|
471
733
|
|
|
472
|
-
|
|
734
|
+
/**
|
|
735
|
+
* What register() actually hands back, which varies by control type. The event
|
|
736
|
+
* handlers are LOWERCASE (`oninput`, `onchange`), because that is the key the
|
|
737
|
+
* DOM binding and the merge in <Input>/<Radio> look for; `onInput` was declared
|
|
738
|
+
* here and register() has never defined it, so `register('email').onInput(e)`
|
|
739
|
+
* type-checked and threw at the first keystroke.
|
|
740
|
+
*
|
|
741
|
+
* `value` and `checked` are reactive rather than snapshots: `value` and the
|
|
742
|
+
* checkbox `checked` are getters, and the radio `checked` is a thunk, so that a
|
|
743
|
+
* spread (`{...register('email')}`) binds instead of freezing the value at
|
|
744
|
+
* mount.
|
|
745
|
+
*
|
|
746
|
+
* A closed type alias rather than an interface: the key set really is closed
|
|
747
|
+
* (this is the whole object register() builds), and closing it is what makes
|
|
748
|
+
* the phantom `onInput` an error again instead of an `any` off an index
|
|
749
|
+
* signature. It must stay a `type`, not an `interface`, because only a type
|
|
750
|
+
* alias gets the implicit index signature that `h('input', register(name))`
|
|
751
|
+
* needs to be assignable to Record<string, any>.
|
|
752
|
+
*/
|
|
753
|
+
export type RegisterProps = {
|
|
473
754
|
name: string;
|
|
474
|
-
value: any;
|
|
475
|
-
onInput: (e: any) => void;
|
|
476
755
|
onBlur: () => void;
|
|
477
756
|
onFocus: () => void;
|
|
478
757
|
ref?: any;
|
|
479
|
-
|
|
758
|
+
/** text/select/textarea, and the option's own value on a radio. */
|
|
759
|
+
value?: any;
|
|
760
|
+
/** checkbox/radio only. */
|
|
761
|
+
checked?: boolean | (() => boolean);
|
|
762
|
+
/** text/select/textarea only. */
|
|
763
|
+
oninput?: (e: any) => void;
|
|
764
|
+
/** checkbox/radio only. */
|
|
765
|
+
onchange?: (e: any) => void;
|
|
766
|
+
};
|
|
480
767
|
|
|
481
768
|
export interface FormState {
|
|
482
769
|
readonly values: Record<string, any>;
|
|
@@ -485,6 +772,8 @@ export interface FormState {
|
|
|
485
772
|
readonly touched: Record<string, boolean>;
|
|
486
773
|
isDirty: () => boolean;
|
|
487
774
|
isValid: Computed<boolean>;
|
|
775
|
+
/** True while the resolver is running. Present since resolvers went async; never declared. */
|
|
776
|
+
isValidating: () => boolean;
|
|
488
777
|
isSubmitting: () => boolean;
|
|
489
778
|
isSubmitted: () => boolean;
|
|
490
779
|
submitCount: () => number;
|