what-core 0.12.3 → 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/chunk-ENARGHSD.min.js +11 -0
- package/dist/chunk-OKM3GKVP.min.js +1 -0
- package/dist/index.min.js +82 -5
- package/dist/render.min.js +1 -1
- package/dist/testing.min.js +1 -1
- package/index.d.ts +369 -43
- package/package.json +1 -1
- package/render.d.ts +7 -0
- package/src/a11y.js +237 -26
- package/src/agent-context.js +1 -1
- package/src/animation.js +13 -6
- package/src/components.js +1 -1
- package/src/data.js +643 -93
- package/src/dom.js +29 -19
- package/src/errors.js +333 -1
- package/src/form.js +330 -31
- package/src/head.js +2 -1
- package/src/hooks.js +30 -20
- package/src/index.js +1 -0
- package/src/reactive.js +31 -14
- package/src/render.js +502 -36
- package/src/scheduler.js +24 -7
- package/src/skeleton.js +16 -1
- package/src/store.js +0 -1
- package/src/testing.js +101 -50
- package/src/warnings.js +83 -0
- package/testing.d.ts +17 -1
- package/dist/chunk-JVEPLFIB.min.js +0 -11
- package/dist/chunk-VTPLA4AS.min.js +0 -1
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;
|
|
@@ -46,10 +52,17 @@ export function onRootCleanup(fn: () => void): void;
|
|
|
46
52
|
// --- Virtual DOM ---
|
|
47
53
|
|
|
48
54
|
export type PrimitiveChild = string | number | boolean | null | undefined;
|
|
49
|
-
|
|
55
|
+
|
|
56
|
+
// `VNode<any>`, not `VNode`. VNode is invariant in P (its `tag` holds a
|
|
57
|
+
// `Component<P>`, whose parameter position is contravariant under
|
|
58
|
+
// strictFunctionTypes), so `VNode` — which means `VNode<Record<string, any>>` —
|
|
59
|
+
// rejects every specifically-typed node. `h('div', {}, h('h1', { style: '' }))`
|
|
60
|
+
// did not compile for any TypeScript user before 0.12.5, and neither did
|
|
61
|
+
// passing that tree to mount().
|
|
62
|
+
export type VNodeChild = PrimitiveChild | VNode<any> | (() => VNodeChild) | VNodeChild[];
|
|
50
63
|
|
|
51
64
|
/** A component may legitimately render nothing, so `null` is part of the contract. */
|
|
52
|
-
export type Component<P = {}> = ((props: P & { children?: VNodeChild }) => VNode | null) & {
|
|
65
|
+
export type Component<P = {}> = ((props: P & { children?: VNodeChild }) => VNode<any> | null) & {
|
|
53
66
|
/**
|
|
54
67
|
* Opt out of realizing compiled children before the component runs.
|
|
55
68
|
*
|
|
@@ -83,7 +96,7 @@ export function html(strings: TemplateStringsArray, ...values: any[]): VNode | V
|
|
|
83
96
|
|
|
84
97
|
// --- DOM ---
|
|
85
98
|
|
|
86
|
-
export function mount(vnode: VNodeChild, container: string | Element): () => void;
|
|
99
|
+
export function mount(vnode: VNodeChild, container: string | Element | DocumentFragment): () => void;
|
|
87
100
|
|
|
88
101
|
/** Attach reactive bindings to server-rendered DOM instead of creating it. */
|
|
89
102
|
export function hydrate(vnode: VNodeChild, container: Element): Node | null;
|
|
@@ -106,11 +119,33 @@ export function classList(el: Element, classes: Record<string, boolean | (() =>
|
|
|
106
119
|
|
|
107
120
|
// --- Hooks ---
|
|
108
121
|
|
|
109
|
-
|
|
122
|
+
/**
|
|
123
|
+
* Returns [signal, setter]. The first element is the SIGNAL ITSELF, not a
|
|
124
|
+
* snapshot value: components run once, so there is no re-render to hand a new
|
|
125
|
+
* `T` to. Read it by calling it (`count()`), or pass it straight into JSX where
|
|
126
|
+
* insert() binds it reactively.
|
|
127
|
+
*
|
|
128
|
+
* It was declared as `[T, setter]`, which made the correct code (`count()`) a
|
|
129
|
+
* type error and the wrong code (`count + 1`) type-check.
|
|
130
|
+
*/
|
|
131
|
+
export function useState<T>(initial: T | (() => T)): [Signal<T>, (value: Updater<T>) => void];
|
|
110
132
|
export function useSignal<T>(initial: T | (() => T)): Signal<T>;
|
|
111
133
|
export function useComputed<T>(fn: () => T): Computed<T>;
|
|
112
134
|
export function useEffect(fn: () => void | (() => void), deps?: unknown[]): void;
|
|
113
|
-
|
|
135
|
+
/**
|
|
136
|
+
* Returns a COMPUTED ACCESSOR, not the value. Same reason as useState: the
|
|
137
|
+
* component body runs once, so nothing would ever hand back a refreshed `T`.
|
|
138
|
+
* Read it by calling it (`total()`), or pass the accessor straight into JSX
|
|
139
|
+
* where insert() tracks it.
|
|
140
|
+
*
|
|
141
|
+
* `deps` is accepted for React familiarity and ignored at runtime: computed()
|
|
142
|
+
* tracks whatever signals the callback actually reads.
|
|
143
|
+
*
|
|
144
|
+
* It was declared as `T`, which inverted both halves: `useMemo(...) * 2`
|
|
145
|
+
* type-checked and produced NaN, while the correct `useMemo(...)()` was the
|
|
146
|
+
* type error.
|
|
147
|
+
*/
|
|
148
|
+
export function useMemo<T>(fn: () => T, deps?: unknown[]): Computed<T>;
|
|
114
149
|
export function useCallback<T extends (...args: any[]) => any>(fn: T, deps?: unknown[]): T;
|
|
115
150
|
export function useRef<T>(initial: T): { current: T };
|
|
116
151
|
|
|
@@ -121,11 +156,19 @@ export interface Context<T> {
|
|
|
121
156
|
|
|
122
157
|
export function createContext<T>(defaultValue: T): Context<T>;
|
|
123
158
|
export function useContext<T>(context: Context<T>): T;
|
|
159
|
+
/**
|
|
160
|
+
* Returns [signal, dispatch]. The first element is the SIGNAL ITSELF, exactly
|
|
161
|
+
* as useState returns it and for the same run-once reason. Read it with
|
|
162
|
+
* `state()`.
|
|
163
|
+
*
|
|
164
|
+
* It was declared as `[S, dispatch]`, so `state.items` type-checked (and read
|
|
165
|
+
* `undefined` off a function object) while `state()` did not.
|
|
166
|
+
*/
|
|
124
167
|
export function useReducer<S, A>(
|
|
125
168
|
reducer: (state: S, action: A) => S,
|
|
126
169
|
initialState: S,
|
|
127
170
|
init?: (initial: S) => S,
|
|
128
|
-
): [S
|
|
171
|
+
): [Signal<S>, (action: A) => void];
|
|
129
172
|
export function onMount(fn: () => void): void;
|
|
130
173
|
export function onCleanup(fn: () => void): void;
|
|
131
174
|
|
|
@@ -190,11 +233,22 @@ export function Island(props: IslandProps): VNode;
|
|
|
190
233
|
|
|
191
234
|
// --- State ---
|
|
192
235
|
|
|
193
|
-
|
|
236
|
+
/** `_storeComputed` is the marker createStore() actually reads to tell a derived value from an action. */
|
|
237
|
+
export type DerivedFn<T> = ((state: any) => T) & { _storeComputed: true };
|
|
194
238
|
export function derived<T>(fn: (state: any) => T): DerivedFn<T>;
|
|
239
|
+
/** @deprecated Use derived(). Warns once at runtime. */
|
|
195
240
|
export function storeComputed<T>(fn: (state: any) => T): DerivedFn<T>;
|
|
196
241
|
export type StoreDefinition = Record<string, any>;
|
|
197
|
-
|
|
242
|
+
/**
|
|
243
|
+
* The store hook resolves every derived key to its VALUE. State and derived
|
|
244
|
+
* keys are both getters on the returned object, only actions stay callable.
|
|
245
|
+
* `Store<T> = T` left a derived key typed as the DerivedFn you wrote in the
|
|
246
|
+
* definition, so `store.total` looked callable and `store.total * 2` was the
|
|
247
|
+
* type error, which is backwards from the runtime.
|
|
248
|
+
*/
|
|
249
|
+
export type Store<T extends StoreDefinition> = {
|
|
250
|
+
[K in keyof T]: T[K] extends DerivedFn<infer U> ? U : T[K];
|
|
251
|
+
};
|
|
198
252
|
export function createStore<T extends StoreDefinition>(definition: T): () => Store<T>;
|
|
199
253
|
export function atom<T>(initial: T): Signal<T>;
|
|
200
254
|
|
|
@@ -280,31 +334,153 @@ export function smoothScrollTo(
|
|
|
280
334
|
): Promise<void>;
|
|
281
335
|
|
|
282
336
|
// --- Animation ---
|
|
337
|
+
//
|
|
338
|
+
// Every accessor below is a plain getter function, NOT a Signal: the objects
|
|
339
|
+
// these factories return expose reads through closures and offer writes as
|
|
340
|
+
// named methods (set/snap/setValue), so nothing here carries .set/.peek. The
|
|
341
|
+
// declarations used to promise Signal<number> and a single shared SpringValue
|
|
342
|
+
// shape for both spring() and tween(), which are two different objects.
|
|
343
|
+
|
|
344
|
+
export interface SpringConfig {
|
|
345
|
+
stiffness?: number;
|
|
346
|
+
damping?: number;
|
|
347
|
+
mass?: number;
|
|
348
|
+
precision?: number;
|
|
349
|
+
}
|
|
283
350
|
|
|
351
|
+
/** Physics-based value. `set()` retargets and animates; `snap()` jumps without animating. */
|
|
284
352
|
export interface SpringValue {
|
|
285
353
|
current(): number;
|
|
286
|
-
|
|
354
|
+
target(): number;
|
|
355
|
+
velocity(): number;
|
|
356
|
+
isAnimating(): boolean;
|
|
357
|
+
set(target: number): void;
|
|
287
358
|
stop(): void;
|
|
288
|
-
|
|
359
|
+
snap(value: number): void;
|
|
360
|
+
subscribe(fn: (value: number) => void): () => void;
|
|
361
|
+
}
|
|
362
|
+
|
|
363
|
+
export interface TweenConfig {
|
|
364
|
+
duration?: number;
|
|
365
|
+
easing?: (t: number) => number;
|
|
366
|
+
onUpdate?: (value: number, progress: number) => void;
|
|
367
|
+
onComplete?: () => void;
|
|
368
|
+
}
|
|
369
|
+
|
|
370
|
+
/**
|
|
371
|
+
* Easing-based interpolation from `from` to `to`. Starts immediately on
|
|
372
|
+
* creation and runs to completion, so it exposes `cancel()` rather than the
|
|
373
|
+
* spring's retargeting `set()`/`stop()`.
|
|
374
|
+
*/
|
|
375
|
+
export interface TweenValue {
|
|
376
|
+
progress(): number;
|
|
377
|
+
value(): number;
|
|
378
|
+
isAnimating(): boolean;
|
|
379
|
+
cancel(): void;
|
|
380
|
+
subscribe(fn: (value: number) => void): () => void;
|
|
289
381
|
}
|
|
290
382
|
|
|
291
|
-
export function spring(initialValue
|
|
292
|
-
|
|
383
|
+
export function spring(initialValue: number, config?: SpringConfig): SpringValue;
|
|
384
|
+
/**
|
|
385
|
+
* Both endpoints are required and positional. This was declared as
|
|
386
|
+
* `tween(initialValue?, config?)` returning a SpringValue, so the documented
|
|
387
|
+
* call `tween(0, 100, { duration: 300 })` was a type error, while
|
|
388
|
+
* `tween(0).current()` type-checked and threw (`current` does not exist, and a
|
|
389
|
+
* missing `to` interpolates toward undefined).
|
|
390
|
+
*/
|
|
391
|
+
export function tween(from: number, to: number, config?: TweenConfig): TweenValue;
|
|
293
392
|
export const easings: Record<string, (t: number) => number>;
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
393
|
+
/**
|
|
394
|
+
* Drives a 0..1 progress value over `duration`. This is NOT React's
|
|
395
|
+
* useTransition, and it never had the mounted/styles/show/hide members that
|
|
396
|
+
* were declared here, and all four were undefined at runtime.
|
|
397
|
+
*/
|
|
398
|
+
export function useTransition(options?: { duration?: number; easing?: (t: number) => number }): {
|
|
399
|
+
isTransitioning: () => boolean;
|
|
400
|
+
progress: () => number;
|
|
401
|
+
start: (callback?: () => void) => Promise<void>;
|
|
299
402
|
};
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
403
|
+
|
|
404
|
+
/** Live gesture state. `startX`/`startY` are plain numbers rewritten in place at gesture start. */
|
|
405
|
+
export interface GestureState {
|
|
406
|
+
isDragging: Signal<boolean>;
|
|
407
|
+
startX: number;
|
|
408
|
+
startY: number;
|
|
409
|
+
currentX: Signal<number>;
|
|
410
|
+
currentY: Signal<number>;
|
|
411
|
+
deltaX: Signal<number>;
|
|
412
|
+
deltaY: Signal<number>;
|
|
413
|
+
velocity: Signal<GestureVelocity>;
|
|
414
|
+
}
|
|
415
|
+
|
|
416
|
+
export interface GestureVelocity {
|
|
417
|
+
x: number;
|
|
418
|
+
y: number;
|
|
419
|
+
}
|
|
420
|
+
|
|
421
|
+
/**
|
|
422
|
+
* `preventDefault` is why this cannot be a `Record<string, (payload) => void>`:
|
|
423
|
+
* it sits in the same object as the callbacks and is a boolean.
|
|
424
|
+
*/
|
|
425
|
+
export interface GestureHandlers {
|
|
426
|
+
onDragStart?: (payload: { x: number; y: number }) => void;
|
|
427
|
+
onDrag?: (payload: {
|
|
428
|
+
x: number; y: number; deltaX: number; deltaY: number; velocity: GestureVelocity;
|
|
429
|
+
}) => void;
|
|
430
|
+
onDragEnd?: (payload: { deltaX: number; deltaY: number; velocity: GestureVelocity }) => void;
|
|
431
|
+
onPinch?: (payload: { scale: number; centerX: number; centerY: number }) => void;
|
|
432
|
+
onSwipe?: (payload: { direction: 'up' | 'down' | 'left' | 'right'; velocity: GestureVelocity }) => void;
|
|
433
|
+
onTap?: (payload: { x: number; y: number }) => void;
|
|
434
|
+
onLongPress?: (payload: { x: number; y: number }) => void;
|
|
435
|
+
/** Opt in to e.preventDefault() in the touch handlers (listeners become non-passive). */
|
|
436
|
+
preventDefault?: boolean;
|
|
437
|
+
}
|
|
438
|
+
|
|
439
|
+
/** Returns the gesture state. It was declared `void`, so the state was unreachable from TypeScript. */
|
|
440
|
+
export function useGesture(
|
|
441
|
+
ref: { current?: Element | null } | Element | (() => Element | null),
|
|
442
|
+
handlers?: GestureHandlers,
|
|
443
|
+
): GestureState;
|
|
444
|
+
|
|
445
|
+
/** Handle for one running animation started by useAnimatedValue. */
|
|
446
|
+
export interface AnimationHandle {
|
|
304
447
|
stop: () => void;
|
|
448
|
+
}
|
|
449
|
+
|
|
450
|
+
/**
|
|
451
|
+
* `animateTo` and `stop` were declared here and have never existed. Animations
|
|
452
|
+
* are started with spring()/timing(), each returning its own handle to stop.
|
|
453
|
+
*/
|
|
454
|
+
export function useAnimatedValue(initialValue: number): {
|
|
455
|
+
value: () => number;
|
|
456
|
+
setValue: (value: number) => void;
|
|
457
|
+
spring: (toValue: number, config?: SpringConfig) => AnimationHandle;
|
|
458
|
+
timing: (toValue: number, config?: TweenConfig) => AnimationHandle;
|
|
459
|
+
interpolate: (inputRange: number[], outputRange: number[]) => () => number;
|
|
460
|
+
subscribe: (fn: (value: number) => void) => () => void;
|
|
305
461
|
};
|
|
306
|
-
|
|
307
|
-
export
|
|
462
|
+
|
|
463
|
+
export interface TransitionClasses {
|
|
464
|
+
enter: string;
|
|
465
|
+
enterActive: string;
|
|
466
|
+
enterDone: string;
|
|
467
|
+
exit: string;
|
|
468
|
+
exitActive: string;
|
|
469
|
+
exitDone: string;
|
|
470
|
+
}
|
|
471
|
+
|
|
472
|
+
/** Returns the six class NAMES for `name`, not a single string. */
|
|
473
|
+
export function createTransitionClasses(name: string): TransitionClasses;
|
|
474
|
+
/**
|
|
475
|
+
* Applies the enter/exit class sequence to an element and resolves when the
|
|
476
|
+
* transition is done. It was declared as a synchronous `(config) => object`.
|
|
477
|
+
*/
|
|
478
|
+
export function cssTransition(
|
|
479
|
+
element: Element,
|
|
480
|
+
name: string,
|
|
481
|
+
type?: 'enter' | 'exit',
|
|
482
|
+
duration?: number,
|
|
483
|
+
): Promise<void>;
|
|
308
484
|
|
|
309
485
|
// --- Accessibility ---
|
|
310
486
|
|
|
@@ -353,11 +529,51 @@ export function useAriaChecked(initialChecked?: boolean): {
|
|
|
353
529
|
checkboxProps: () => Record<string, any>;
|
|
354
530
|
};
|
|
355
531
|
|
|
356
|
-
export
|
|
532
|
+
export interface RovingTabIndexOptions {
|
|
533
|
+
/**
|
|
534
|
+
* Container role, emitted by containerProps(). The hook emits NO role by
|
|
535
|
+
* default: roving tabindex is the shared keyboard mechanic of toolbars,
|
|
536
|
+
* menus, trees, grids, tablists, radiogroups and listboxes, and a default
|
|
537
|
+
* spread last would silently overwrite the role the caller wrote beside it.
|
|
538
|
+
*/
|
|
539
|
+
role?: string;
|
|
540
|
+
}
|
|
541
|
+
|
|
542
|
+
/**
|
|
543
|
+
* Props for one roving item. `ref` is the item's REGISTRATION (the hook holds
|
|
544
|
+
* the node through it and cannot move focus without it), so a `ref` passed via
|
|
545
|
+
* `overrides` is chained rather than replaced. `tabIndex` is an accessor, not a
|
|
546
|
+
* number: exactly one item is tabbable at a time and which one changes as focus
|
|
547
|
+
* roves, so a resolved value could not survive the spread.
|
|
548
|
+
*/
|
|
549
|
+
export interface RovingItemProps {
|
|
550
|
+
ref: { current: Element | null };
|
|
551
|
+
tabIndex: () => number;
|
|
552
|
+
onKeyDown: (e: KeyboardEvent) => void;
|
|
553
|
+
onFocus: (e: Event) => void;
|
|
554
|
+
[prop: string]: any;
|
|
555
|
+
}
|
|
556
|
+
|
|
557
|
+
export function useRovingTabIndex(
|
|
558
|
+
itemCountOrSignal: number | (() => number),
|
|
559
|
+
options?: RovingTabIndexOptions,
|
|
560
|
+
): {
|
|
561
|
+
/** Active index, clamped to the current count so the group is never untabbable. */
|
|
357
562
|
focusIndex: () => number;
|
|
563
|
+
/**
|
|
564
|
+
* Set the active index. Out-of-range indexes are REFUSED, not clamped. Moves
|
|
565
|
+
* real focus only when the group already owns it, so syncing from application
|
|
566
|
+
* state cannot steal focus from elsewhere on the page.
|
|
567
|
+
*/
|
|
358
568
|
setFocusIndex: (index: number) => void;
|
|
359
|
-
|
|
360
|
-
|
|
569
|
+
/**
|
|
570
|
+
* Explicitly move focus to an item (a menu focusing its first item on open).
|
|
571
|
+
* Returns the element it focused, or null when the index is out of range or
|
|
572
|
+
* the item is not in the DOM.
|
|
573
|
+
*/
|
|
574
|
+
focusItem: (index: number) => Element | null;
|
|
575
|
+
getItemProps: (index: number, overrides?: Record<string, any>) => RovingItemProps;
|
|
576
|
+
containerProps: (overrides?: Record<string, any>) => Record<string, any>;
|
|
361
577
|
};
|
|
362
578
|
|
|
363
579
|
export function VisuallyHidden(props: { children?: VNodeChild; as?: string }): VNode;
|
|
@@ -413,7 +629,8 @@ export function Spinner(props?: Record<string, any>): VNode;
|
|
|
413
629
|
// --- Data Fetching ---
|
|
414
630
|
|
|
415
631
|
export function useFetch<T = any>(url: string, options?: Record<string, any>): {
|
|
416
|
-
|
|
632
|
+
/** null until the first response lands. It was declared as bare `T`, so strict-mode callers skipped the check they need. */
|
|
633
|
+
data: () => T | null;
|
|
417
634
|
error: () => any;
|
|
418
635
|
isLoading: () => boolean;
|
|
419
636
|
refetch: () => Promise<void>;
|
|
@@ -429,36 +646,88 @@ export function useSWR<T = any>(key: string | null | false, fetcher: (key: strin
|
|
|
429
646
|
revalidate: () => Promise<T | void>;
|
|
430
647
|
};
|
|
431
648
|
|
|
649
|
+
/**
|
|
650
|
+
* 'idle' is a real state, not a placeholder: a query with `enabled: false` and
|
|
651
|
+
* nothing cached is idle, and reporting it as loading is what renders a spinner
|
|
652
|
+
* that never comes down.
|
|
653
|
+
*/
|
|
654
|
+
export type QueryStatus = 'idle' | 'loading' | 'success' | 'error';
|
|
655
|
+
/** Whether a request is on the wire, independent of whether data exists. */
|
|
656
|
+
export type FetchStatus = 'idle' | 'fetching';
|
|
657
|
+
|
|
658
|
+
/**
|
|
659
|
+
* Any array key is joined into a single normalized string, so an array and its
|
|
660
|
+
* normalization address the same cache entry everywhere a key is accepted.
|
|
661
|
+
*/
|
|
662
|
+
export type QueryKey = string | readonly unknown[];
|
|
663
|
+
|
|
432
664
|
export function useQuery<T = any>(options: Record<string, any>): {
|
|
433
665
|
data: () => T | null;
|
|
434
666
|
error: () => any;
|
|
435
|
-
status: () =>
|
|
667
|
+
status: () => QueryStatus;
|
|
668
|
+
fetchStatus: () => FetchStatus;
|
|
436
669
|
isLoading: () => boolean;
|
|
437
670
|
isFetching: () => boolean;
|
|
438
671
|
isError: () => boolean;
|
|
439
672
|
isSuccess: () => boolean;
|
|
673
|
+
isIdle: () => boolean;
|
|
674
|
+
/** Whether the `enabled` gate is currently open. */
|
|
675
|
+
isEnabled: () => boolean;
|
|
440
676
|
refetch: () => Promise<T | void>;
|
|
441
677
|
};
|
|
442
678
|
|
|
679
|
+
/**
|
|
680
|
+
* Pages, plus the param each was fetched with. `pageParams[i]` names `pages[i]`.
|
|
681
|
+
*/
|
|
682
|
+
export interface InfiniteData<T> {
|
|
683
|
+
pages: T[];
|
|
684
|
+
pageParams: unknown[];
|
|
685
|
+
}
|
|
686
|
+
|
|
687
|
+
/**
|
|
688
|
+
* `data()` hands back the page CONTAINER, not a flat array. It was declared as
|
|
689
|
+
* `T[]`, so `data().map(...)` type-checked and threw. The rows are in
|
|
690
|
+
* `data().pages`. A `select` option replaces the container wholesale, and that
|
|
691
|
+
* transformation is not expressible here.
|
|
692
|
+
*/
|
|
443
693
|
export function useInfiniteQuery<T = any>(options: Record<string, any>): {
|
|
444
|
-
data: () => T
|
|
694
|
+
data: () => InfiniteData<T>;
|
|
445
695
|
error: () => any;
|
|
446
|
-
status: () =>
|
|
696
|
+
status: () => QueryStatus;
|
|
447
697
|
isLoading: () => boolean;
|
|
448
|
-
|
|
698
|
+
isError: () => boolean;
|
|
699
|
+
isSuccess: () => boolean;
|
|
700
|
+
isIdle: () => boolean;
|
|
701
|
+
isFetching: () => boolean;
|
|
702
|
+
isEnabled: () => boolean;
|
|
449
703
|
hasNextPage: () => boolean;
|
|
704
|
+
hasPreviousPage: () => boolean;
|
|
705
|
+
isFetchingNextPage: () => boolean;
|
|
706
|
+
isFetchingPreviousPage: () => boolean;
|
|
450
707
|
fetchNextPage: () => Promise<void>;
|
|
708
|
+
fetchPreviousPage: () => Promise<void>;
|
|
451
709
|
refetch: () => Promise<void>;
|
|
452
710
|
};
|
|
453
711
|
|
|
712
|
+
/**
|
|
713
|
+
* Synchronous. It was declared as returning Promise<void>, so `await
|
|
714
|
+
* invalidateQueries(...)` awaited undefined and read as "the refetches are
|
|
715
|
+
* done" when they had only been kicked off. The subscribers it wakes fetch on
|
|
716
|
+
* their own.
|
|
717
|
+
*
|
|
718
|
+
* An array key is a PREFIX unless `exact` is set: invalidateQueries(['todos'])
|
|
719
|
+
* also invalidates ['todos', 1]. `hard` clears the cached value immediately
|
|
720
|
+
* (loading state); the default keeps stale data on screen while it refetches.
|
|
721
|
+
*/
|
|
454
722
|
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
|
-
|
|
723
|
+
keyOrPredicate: QueryKey | ((key: string) => boolean),
|
|
724
|
+
options?: { exact?: boolean; hard?: boolean },
|
|
725
|
+
): void;
|
|
726
|
+
|
|
727
|
+
export function prefetchQuery<T = any>(key: QueryKey, fetcher: (key: string) => Promise<T>): Promise<T>;
|
|
728
|
+
export function setQueryData<T = any>(key: QueryKey, updater: T | ((prev: T | null) => T)): void;
|
|
729
|
+
/** `undefined` for a key the cache has never held; `null` for one that was emptied. */
|
|
730
|
+
export function getQueryData<T = any>(key: QueryKey): T | null | undefined;
|
|
462
731
|
export function clearCache(): void;
|
|
463
732
|
|
|
464
733
|
// --- Forms ---
|
|
@@ -469,14 +738,39 @@ export interface FieldError {
|
|
|
469
738
|
[key: string]: any;
|
|
470
739
|
}
|
|
471
740
|
|
|
472
|
-
|
|
741
|
+
/**
|
|
742
|
+
* What register() actually hands back, which varies by control type. The event
|
|
743
|
+
* handlers are LOWERCASE (`oninput`, `onchange`), because that is the key the
|
|
744
|
+
* DOM binding and the merge in <Input>/<Radio> look for; `onInput` was declared
|
|
745
|
+
* here and register() has never defined it, so `register('email').onInput(e)`
|
|
746
|
+
* type-checked and threw at the first keystroke.
|
|
747
|
+
*
|
|
748
|
+
* `value` and `checked` are reactive rather than snapshots: `value` and the
|
|
749
|
+
* checkbox `checked` are getters, and the radio `checked` is a thunk, so that a
|
|
750
|
+
* spread (`{...register('email')}`) binds instead of freezing the value at
|
|
751
|
+
* mount.
|
|
752
|
+
*
|
|
753
|
+
* A closed type alias rather than an interface: the key set really is closed
|
|
754
|
+
* (this is the whole object register() builds), and closing it is what makes
|
|
755
|
+
* the phantom `onInput` an error again instead of an `any` off an index
|
|
756
|
+
* signature. It must stay a `type`, not an `interface`, because only a type
|
|
757
|
+
* alias gets the implicit index signature that `h('input', register(name))`
|
|
758
|
+
* needs to be assignable to Record<string, any>.
|
|
759
|
+
*/
|
|
760
|
+
export type RegisterProps = {
|
|
473
761
|
name: string;
|
|
474
|
-
value: any;
|
|
475
|
-
onInput: (e: any) => void;
|
|
476
762
|
onBlur: () => void;
|
|
477
763
|
onFocus: () => void;
|
|
478
764
|
ref?: any;
|
|
479
|
-
|
|
765
|
+
/** text/select/textarea, and the option's own value on a radio. */
|
|
766
|
+
value?: any;
|
|
767
|
+
/** checkbox/radio only. */
|
|
768
|
+
checked?: boolean | (() => boolean);
|
|
769
|
+
/** text/select/textarea only. */
|
|
770
|
+
oninput?: (e: any) => void;
|
|
771
|
+
/** checkbox/radio only. */
|
|
772
|
+
onchange?: (e: any) => void;
|
|
773
|
+
};
|
|
480
774
|
|
|
481
775
|
export interface FormState {
|
|
482
776
|
readonly values: Record<string, any>;
|
|
@@ -485,6 +779,8 @@ export interface FormState {
|
|
|
485
779
|
readonly touched: Record<string, boolean>;
|
|
486
780
|
isDirty: () => boolean;
|
|
487
781
|
isValid: Computed<boolean>;
|
|
782
|
+
/** True while the resolver is running. Present since resolvers went async; never declared. */
|
|
783
|
+
isValidating: () => boolean;
|
|
488
784
|
isSubmitting: () => boolean;
|
|
489
785
|
isSubmitted: () => boolean;
|
|
490
786
|
submitCount: () => number;
|
|
@@ -578,6 +874,15 @@ export interface ErrorCodeDefinition {
|
|
|
578
874
|
|
|
579
875
|
export const ERROR_CODES: Record<string, ErrorCodeDefinition>;
|
|
580
876
|
|
|
877
|
+
/**
|
|
878
|
+
* Look up a catalogue entry by its `ERR_*` code.
|
|
879
|
+
*
|
|
880
|
+
* Errors thrown outside what-core carry only their code — the suggestion and
|
|
881
|
+
* the worked example live once, in the catalogue, so that the client bundle
|
|
882
|
+
* does not have to ship the prose. This is how they are recovered.
|
|
883
|
+
*/
|
|
884
|
+
export function getErrorDefinition(code: string): ErrorCodeDefinition | undefined;
|
|
885
|
+
|
|
581
886
|
export interface WhatErrorJSON {
|
|
582
887
|
code: string;
|
|
583
888
|
message: string;
|
|
@@ -676,3 +981,24 @@ export function getMountedComponents(): unknown[];
|
|
|
676
981
|
export function registerSignal(sig: unknown): void;
|
|
677
982
|
export function unregisterSignal(sig: unknown): void;
|
|
678
983
|
export function getActiveSignals(): unknown[];
|
|
984
|
+
|
|
985
|
+
// --- Internal cross-package exports ---
|
|
986
|
+
// Underscore-prefixed names are not public API and carry no compatibility
|
|
987
|
+
// promise. They are declared here because sibling packages in this repo import
|
|
988
|
+
// them across the package boundary (what-server, what-text), and an
|
|
989
|
+
// undeclared cross-package import is exactly the rename that ships broken:
|
|
990
|
+
// `hygiene:types` skips `_`-prefixed names in its reverse direction, so
|
|
991
|
+
// nothing else would have caught it. Application code should not use these.
|
|
992
|
+
|
|
993
|
+
/** @internal Used by what-server. True for `aria-*` and `data-*` attribute names. */
|
|
994
|
+
export function _isAriaAttr(name: string): boolean;
|
|
995
|
+
/** @internal Used by what-server. Opens an SSR component scope. */
|
|
996
|
+
export function _beginComponentSSR(...args: unknown[]): unknown;
|
|
997
|
+
/** @internal Used by what-server. Closes the scope opened by `_beginComponentSSR`. */
|
|
998
|
+
export function _endComponentSSR(...args: unknown[]): unknown;
|
|
999
|
+
/** @internal Used by what-server. The keyed-array mapping `<For>` compiles down to. */
|
|
1000
|
+
export function _mapArrayToArray(...args: unknown[]): unknown;
|
|
1001
|
+
/** @internal Used by what-server/node. Installs the Node AsyncLocalStorage backend. */
|
|
1002
|
+
export function __installServerContextStorage(storage: unknown): void;
|
|
1003
|
+
/** @internal Used by what-text. Lets the text engine intercept text-node insertion. */
|
|
1004
|
+
export function _setTextInsertHook(hook: unknown): void;
|
package/package.json
CHANGED
package/render.d.ts
CHANGED
|
@@ -42,3 +42,10 @@ export function isHydrating(): boolean;
|
|
|
42
42
|
// SVG counterpart to template(): elements are created in the SVG namespace, which
|
|
43
43
|
// a plain innerHTML template cannot do.
|
|
44
44
|
export function svgTemplate(html: string): () => Element;
|
|
45
|
+
|
|
46
|
+
/**
|
|
47
|
+
* @internal The component-call helper the compiler emits for `<Component />`.
|
|
48
|
+
* Re-exported by what-framework/render so compiled output can import it from
|
|
49
|
+
* the package a scaffolded app actually depends on.
|
|
50
|
+
*/
|
|
51
|
+
export function _$createComponent(component: unknown, props?: unknown, ...args: unknown[]): unknown;
|