foldkit 0.100.1 → 0.102.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 +3 -2
- package/dist/canvas/view.d.ts +1 -1
- package/dist/canvas/view.d.ts.map +1 -1
- package/dist/canvas/view.js +5 -5
- package/dist/command/index.d.ts +71 -0
- package/dist/command/index.d.ts.map +1 -1
- package/dist/command/index.js +34 -1
- package/dist/command/public.d.ts +1 -1
- package/dist/command/public.d.ts.map +1 -1
- package/dist/command/public.js +1 -1
- package/dist/devTools/overlay.d.ts.map +1 -1
- package/dist/devTools/overlay.js +156 -149
- package/dist/dom/dom.d.ts +8 -11
- package/dist/dom/dom.d.ts.map +1 -1
- package/dist/dom/dom.js +8 -11
- package/dist/dom/elementMovement.d.ts +1 -3
- package/dist/dom/elementMovement.d.ts.map +1 -1
- package/dist/dom/elementMovement.js +1 -3
- package/dist/dom/inert.d.ts +2 -4
- package/dist/dom/inert.d.ts.map +1 -1
- package/dist/dom/inert.js +2 -4
- package/dist/dom/scrollLock.d.ts +2 -2
- package/dist/dom/scrollLock.js +2 -2
- package/dist/dom/waitForAnimation.d.ts +1 -1
- package/dist/dom/waitForAnimation.js +1 -1
- package/dist/html/boundary.d.ts +98 -0
- package/dist/html/boundary.d.ts.map +1 -0
- package/dist/html/boundary.js +176 -0
- package/dist/html/childAttribute.d.ts +44 -0
- package/dist/html/childAttribute.d.ts.map +1 -0
- package/dist/html/childAttribute.js +34 -0
- package/dist/html/index.d.ts +70 -23
- package/dist/html/index.d.ts.map +1 -1
- package/dist/html/index.js +639 -575
- package/dist/html/lazy.d.ts +12 -7
- package/dist/html/lazy.d.ts.map +1 -1
- package/dist/html/lazy.js +30 -11
- package/dist/html/public.d.ts +2 -2
- package/dist/html/public.d.ts.map +1 -1
- package/dist/html/public.js +1 -1
- package/dist/html/runtimeSingleton.d.ts +72 -0
- package/dist/html/runtimeSingleton.d.ts.map +1 -0
- package/dist/html/runtimeSingleton.js +112 -0
- package/dist/html/submodel.d.ts +98 -0
- package/dist/html/submodel.d.ts.map +1 -0
- package/dist/html/submodel.js +190 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -0
- package/dist/render/render.d.ts +1 -1
- package/dist/render/render.js +1 -1
- package/dist/runtime/messagePriority.d.ts +5 -1
- package/dist/runtime/messagePriority.d.ts.map +1 -1
- package/dist/runtime/messagePriority.js +25 -4
- package/dist/runtime/runtime.d.ts +11 -11
- package/dist/runtime/runtime.d.ts.map +1 -1
- package/dist/runtime/runtime.js +118 -63
- package/dist/runtime/subscription.d.ts +139 -19
- package/dist/runtime/subscription.d.ts.map +1 -1
- package/dist/runtime/subscription.js +90 -9
- package/dist/submodel/public.d.ts +4 -0
- package/dist/submodel/public.d.ts.map +1 -0
- package/dist/submodel/public.js +1 -0
- package/dist/submodel/submodel.d.ts +32 -0
- package/dist/submodel/submodel.d.ts.map +1 -0
- package/dist/submodel/submodel.js +1 -0
- package/dist/subscription/animationFrame.d.ts +23 -26
- package/dist/subscription/animationFrame.d.ts.map +1 -1
- package/dist/subscription/animationFrame.js +17 -18
- package/dist/subscription/public.d.ts +2 -2
- package/dist/subscription/public.d.ts.map +1 -1
- package/dist/subscription/public.js +1 -1
- package/dist/test/apps/disabledButton.d.ts +4 -5
- package/dist/test/apps/disabledButton.d.ts.map +1 -1
- package/dist/test/apps/disabledButton.js +16 -16
- package/dist/test/scene.d.ts +8 -8
- package/dist/test/scene.d.ts.map +1 -1
- package/dist/test/scene.js +25 -13
- package/dist/test/story.d.ts +15 -8
- package/dist/test/story.d.ts.map +1 -1
- package/dist/test/story.js +21 -9
- package/dist/ui/animation/index.d.ts +30 -14
- package/dist/ui/animation/index.d.ts.map +1 -1
- package/dist/ui/animation/index.js +9 -19
- package/dist/ui/animation/public.d.ts +2 -2
- package/dist/ui/animation/public.d.ts.map +1 -1
- package/dist/ui/animation/public.js +1 -1
- package/dist/ui/calendar/index.d.ts +199 -84
- package/dist/ui/calendar/index.d.ts.map +1 -1
- package/dist/ui/calendar/index.js +129 -140
- package/dist/ui/calendar/public.d.ts +2 -2
- package/dist/ui/calendar/public.d.ts.map +1 -1
- package/dist/ui/calendar/public.js +1 -1
- package/dist/ui/checkbox/index.d.ts +93 -21
- package/dist/ui/checkbox/index.d.ts.map +1 -1
- package/dist/ui/checkbox/index.js +62 -33
- package/dist/ui/checkbox/public.d.ts +2 -2
- package/dist/ui/checkbox/public.d.ts.map +1 -1
- package/dist/ui/checkbox/public.js +1 -1
- package/dist/ui/combobox/multi.d.ts +35 -91
- package/dist/ui/combobox/multi.d.ts.map +1 -1
- package/dist/ui/combobox/multi.js +34 -17
- package/dist/ui/combobox/multiPublic.d.ts +2 -2
- package/dist/ui/combobox/multiPublic.d.ts.map +1 -1
- package/dist/ui/combobox/multiPublic.js +1 -1
- package/dist/ui/combobox/public.d.ts +3 -3
- package/dist/ui/combobox/public.d.ts.map +1 -1
- package/dist/ui/combobox/public.js +2 -2
- package/dist/ui/combobox/shared.d.ts +56 -31
- package/dist/ui/combobox/shared.d.ts.map +1 -1
- package/dist/ui/combobox/shared.js +333 -322
- package/dist/ui/combobox/single.d.ts +46 -93
- package/dist/ui/combobox/single.d.ts.map +1 -1
- package/dist/ui/combobox/single.js +44 -17
- package/dist/ui/datePicker/index.d.ts +256 -48
- package/dist/ui/datePicker/index.d.ts.map +1 -1
- package/dist/ui/datePicker/index.js +149 -104
- package/dist/ui/datePicker/public.d.ts +2 -2
- package/dist/ui/datePicker/public.d.ts.map +1 -1
- package/dist/ui/datePicker/public.js +1 -1
- package/dist/ui/dialog/index.d.ts +95 -39
- package/dist/ui/dialog/index.d.ts.map +1 -1
- package/dist/ui/dialog/index.js +71 -62
- package/dist/ui/dialog/public.d.ts +2 -2
- package/dist/ui/dialog/public.d.ts.map +1 -1
- package/dist/ui/dialog/public.js +1 -1
- package/dist/ui/disclosure/index.d.ts +71 -31
- package/dist/ui/disclosure/index.d.ts.map +1 -1
- package/dist/ui/disclosure/index.js +57 -62
- package/dist/ui/disclosure/public.d.ts +2 -2
- package/dist/ui/disclosure/public.d.ts.map +1 -1
- package/dist/ui/disclosure/public.js +1 -1
- package/dist/ui/dragAndDrop/index.d.ts +385 -103
- package/dist/ui/dragAndDrop/index.d.ts.map +1 -1
- package/dist/ui/dragAndDrop/index.js +26 -31
- package/dist/ui/dragAndDrop/public.d.ts +1 -1
- package/dist/ui/dragAndDrop/public.d.ts.map +1 -1
- package/dist/ui/dragAndDrop/public.js +1 -1
- package/dist/ui/fileDrop/index.d.ts +42 -46
- package/dist/ui/fileDrop/index.d.ts.map +1 -1
- package/dist/ui/fileDrop/index.js +30 -46
- package/dist/ui/fileDrop/public.d.ts +2 -2
- package/dist/ui/fileDrop/public.d.ts.map +1 -1
- package/dist/ui/fileDrop/public.js +1 -1
- package/dist/ui/listbox/multi.d.ts +39 -84
- package/dist/ui/listbox/multi.d.ts.map +1 -1
- package/dist/ui/listbox/multi.js +38 -20
- package/dist/ui/listbox/multiPublic.d.ts +2 -2
- package/dist/ui/listbox/multiPublic.d.ts.map +1 -1
- package/dist/ui/listbox/multiPublic.js +1 -1
- package/dist/ui/listbox/public.d.ts +3 -3
- package/dist/ui/listbox/public.d.ts.map +1 -1
- package/dist/ui/listbox/public.js +2 -2
- package/dist/ui/listbox/shared.d.ts +71 -30
- package/dist/ui/listbox/shared.d.ts.map +1 -1
- package/dist/ui/listbox/shared.js +319 -296
- package/dist/ui/listbox/single.d.ts +57 -85
- package/dist/ui/listbox/single.d.ts.map +1 -1
- package/dist/ui/listbox/single.js +48 -24
- package/dist/ui/menu/index.d.ts +80 -36
- package/dist/ui/menu/index.d.ts.map +1 -1
- package/dist/ui/menu/index.js +117 -86
- package/dist/ui/menu/public.d.ts +2 -2
- package/dist/ui/menu/public.d.ts.map +1 -1
- package/dist/ui/menu/public.js +1 -1
- package/dist/ui/popover/index.d.ts +117 -44
- package/dist/ui/popover/index.d.ts.map +1 -1
- package/dist/ui/popover/index.js +88 -101
- package/dist/ui/popover/public.d.ts +2 -2
- package/dist/ui/popover/public.d.ts.map +1 -1
- package/dist/ui/popover/public.js +1 -1
- package/dist/ui/radioGroup/index.d.ts +122 -45
- package/dist/ui/radioGroup/index.d.ts.map +1 -1
- package/dist/ui/radioGroup/index.js +111 -72
- package/dist/ui/radioGroup/public.d.ts +2 -2
- package/dist/ui/radioGroup/public.d.ts.map +1 -1
- package/dist/ui/radioGroup/public.js +1 -1
- package/dist/ui/slider/index.d.ts +247 -103
- package/dist/ui/slider/index.d.ts.map +1 -1
- package/dist/ui/slider/index.js +52 -68
- package/dist/ui/slider/public.d.ts +2 -2
- package/dist/ui/slider/public.d.ts.map +1 -1
- package/dist/ui/slider/public.js +1 -1
- package/dist/ui/switch/index.d.ts +74 -21
- package/dist/ui/switch/index.d.ts.map +1 -1
- package/dist/ui/switch/index.js +62 -33
- package/dist/ui/switch/public.d.ts +2 -2
- package/dist/ui/switch/public.d.ts.map +1 -1
- package/dist/ui/switch/public.js +1 -1
- package/dist/ui/tabs/index.d.ts +107 -45
- package/dist/ui/tabs/index.d.ts.map +1 -1
- package/dist/ui/tabs/index.js +99 -81
- package/dist/ui/tabs/public.d.ts +2 -2
- package/dist/ui/tabs/public.d.ts.map +1 -1
- package/dist/ui/tabs/public.js +1 -1
- package/dist/ui/toast/index.d.ts +93 -109
- package/dist/ui/toast/index.d.ts.map +1 -1
- package/dist/ui/toast/index.js +16 -29
- package/dist/ui/toast/schema.d.ts +15 -4
- package/dist/ui/toast/schema.d.ts.map +1 -1
- package/dist/ui/toast/schema.js +11 -4
- package/dist/ui/toast/update.d.ts +36 -18
- package/dist/ui/toast/update.d.ts.map +1 -1
- package/dist/ui/toast/update.js +33 -14
- package/dist/ui/tooltip/index.d.ts +94 -42
- package/dist/ui/tooltip/index.d.ts.map +1 -1
- package/dist/ui/tooltip/index.js +64 -73
- package/dist/ui/tooltip/public.d.ts +2 -2
- package/dist/ui/tooltip/public.d.ts.map +1 -1
- package/dist/ui/tooltip/public.js +1 -1
- package/dist/ui/virtualList/index.d.ts +63 -80
- package/dist/ui/virtualList/index.d.ts.map +1 -1
- package/dist/ui/virtualList/index.js +22 -49
- package/dist/ui/virtualList/public.d.ts +2 -2
- package/dist/ui/virtualList/public.d.ts.map +1 -1
- package/dist/ui/virtualList/public.js +1 -1
- package/package.json +1 -1
package/dist/dom/inert.d.ts
CHANGED
|
@@ -7,9 +7,7 @@ import { Effect } from 'effect';
|
|
|
7
7
|
*
|
|
8
8
|
* @example
|
|
9
9
|
* ```typescript
|
|
10
|
-
* Dom.inertOthers('my-menu', ['#menu-button', '#menu-items'])
|
|
11
|
-
* Effect.as(CompletedSetupInert()),
|
|
12
|
-
* )
|
|
10
|
+
* Dom.inertOthers('my-menu', ['#menu-button', '#menu-items'])
|
|
13
11
|
* ```
|
|
14
12
|
*/
|
|
15
13
|
export declare const inertOthers: (id: string, allowedSelectors: ReadonlyArray<string>) => Effect.Effect<void>;
|
|
@@ -20,7 +18,7 @@ export declare const inertOthers: (id: string, allowedSelectors: ReadonlyArray<s
|
|
|
20
18
|
*
|
|
21
19
|
* @example
|
|
22
20
|
* ```typescript
|
|
23
|
-
* Dom.restoreInert('my-menu')
|
|
21
|
+
* Dom.restoreInert('my-menu')
|
|
24
22
|
* ```
|
|
25
23
|
*/
|
|
26
24
|
export declare const restoreInert: (id: string) => Effect.Effect<void>;
|
package/dist/dom/inert.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"inert.d.ts","sourceRoot":"","sources":["../../src/dom/inert.ts"],"names":[],"mappings":"AAAA,OAAO,EAAS,MAAM,EAA2C,MAAM,QAAQ,CAAA;AAuF/E
|
|
1
|
+
{"version":3,"file":"inert.d.ts","sourceRoot":"","sources":["../../src/dom/inert.ts"],"names":[],"mappings":"AAAA,OAAO,EAAS,MAAM,EAA2C,MAAM,QAAQ,CAAA;AAuF/E;;;;;;;;;;GAUG;AACH,eAAO,MAAM,WAAW,GACtB,IAAI,MAAM,EACV,kBAAkB,aAAa,CAAC,MAAM,CAAC,KACtC,MAAM,CAAC,MAAM,CAAC,IAAI,CAajB,CAAA;AAEJ;;;;;;;;;GASG;AACH,eAAO,MAAM,YAAY,GAAI,IAAI,MAAM,KAAG,MAAM,CAAC,MAAM,CAAC,IAAI,CAQxD,CAAA"}
|
package/dist/dom/inert.js
CHANGED
|
@@ -56,9 +56,7 @@ const inertableSiblings = (parent, allowedElements) => pipe(parent.children, Arr
|
|
|
56
56
|
*
|
|
57
57
|
* @example
|
|
58
58
|
* ```typescript
|
|
59
|
-
* Dom.inertOthers('my-menu', ['#menu-button', '#menu-items'])
|
|
60
|
-
* Effect.as(CompletedSetupInert()),
|
|
61
|
-
* )
|
|
59
|
+
* Dom.inertOthers('my-menu', ['#menu-button', '#menu-items'])
|
|
62
60
|
* ```
|
|
63
61
|
*/
|
|
64
62
|
export const inertOthers = (id, allowedSelectors) => Effect.sync(() => {
|
|
@@ -73,7 +71,7 @@ export const inertOthers = (id, allowedSelectors) => Effect.sync(() => {
|
|
|
73
71
|
*
|
|
74
72
|
* @example
|
|
75
73
|
* ```typescript
|
|
76
|
-
* Dom.restoreInert('my-menu')
|
|
74
|
+
* Dom.restoreInert('my-menu')
|
|
77
75
|
* ```
|
|
78
76
|
*/
|
|
79
77
|
export const restoreInert = (id) => Effect.sync(() => {
|
package/dist/dom/scrollLock.d.ts
CHANGED
|
@@ -9,7 +9,7 @@ import { Effect } from 'effect';
|
|
|
9
9
|
*
|
|
10
10
|
* @example
|
|
11
11
|
* ```typescript
|
|
12
|
-
* Dom.lockScroll
|
|
12
|
+
* Dom.lockScroll
|
|
13
13
|
* ```
|
|
14
14
|
*/
|
|
15
15
|
export declare const lockScroll: Effect.Effect<void>;
|
|
@@ -20,7 +20,7 @@ export declare const lockScroll: Effect.Effect<void>;
|
|
|
20
20
|
*
|
|
21
21
|
* @example
|
|
22
22
|
* ```typescript
|
|
23
|
-
* Dom.unlockScroll
|
|
23
|
+
* Dom.unlockScroll
|
|
24
24
|
* ```
|
|
25
25
|
*/
|
|
26
26
|
export declare const unlockScroll: Effect.Effect<void>;
|
package/dist/dom/scrollLock.js
CHANGED
|
@@ -46,7 +46,7 @@ const handleTouchMove = (event) => {
|
|
|
46
46
|
*
|
|
47
47
|
* @example
|
|
48
48
|
* ```typescript
|
|
49
|
-
* Dom.lockScroll
|
|
49
|
+
* Dom.lockScroll
|
|
50
50
|
* ```
|
|
51
51
|
*/
|
|
52
52
|
export const lockScroll = Effect.sync(() => {
|
|
@@ -73,7 +73,7 @@ export const lockScroll = Effect.sync(() => {
|
|
|
73
73
|
*
|
|
74
74
|
* @example
|
|
75
75
|
* ```typescript
|
|
76
|
-
* Dom.unlockScroll
|
|
76
|
+
* Dom.unlockScroll
|
|
77
77
|
* ```
|
|
78
78
|
*/
|
|
79
79
|
export const unlockScroll = Effect.sync(() => {
|
|
@@ -10,7 +10,7 @@ import { Effect } from 'effect';
|
|
|
10
10
|
*
|
|
11
11
|
* @example
|
|
12
12
|
* ```typescript
|
|
13
|
-
* Dom.waitForAnimationSettled('#menu-items')
|
|
13
|
+
* Dom.waitForAnimationSettled('#menu-items')
|
|
14
14
|
* ```
|
|
15
15
|
*/
|
|
16
16
|
export declare const waitForAnimationSettled: (selector: string) => Effect.Effect<void>;
|
|
@@ -10,7 +10,7 @@ import { Effect } from 'effect';
|
|
|
10
10
|
*
|
|
11
11
|
* @example
|
|
12
12
|
* ```typescript
|
|
13
|
-
* Dom.waitForAnimationSettled('#menu-items')
|
|
13
|
+
* Dom.waitForAnimationSettled('#menu-items')
|
|
14
14
|
* ```
|
|
15
15
|
*/
|
|
16
16
|
export const waitForAnimationSettled = (selector) => Effect.callback(resume => {
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
import type { DispatchSync } from './runtimeSingleton.js';
|
|
2
|
+
/** Wrapping descriptor stored per Submodel boundary. */
|
|
3
|
+
export type WrapDescriptor = Readonly<{
|
|
4
|
+
toParentMessage: (message: unknown) => unknown;
|
|
5
|
+
}>;
|
|
6
|
+
/** Boundary id is a `|`-joined chain of Submodel slot ids. Empty
|
|
7
|
+
* string represents the root boundary. Two-level example:
|
|
8
|
+
* `"work-history|entry-abc123"`. User-supplied slot ids must not
|
|
9
|
+
* contain the separator character; {@link composeBoundary} throws when
|
|
10
|
+
* they do. */
|
|
11
|
+
export type BoundaryId = string;
|
|
12
|
+
export declare const ROOT_BOUNDARY: BoundaryId;
|
|
13
|
+
export declare const composeBoundary: (parent: BoundaryId, childId: string) => BoundaryId;
|
|
14
|
+
/** Per-runtime registry of Submodel wrapping descriptors. The runtime
|
|
15
|
+
* creates one of these in `start` and reuses it across renders.
|
|
16
|
+
* `h.submodel` writes into `wraps` each render and attaches a snabbdom
|
|
17
|
+
* `destroy` hook that calls `deregisterBoundaryWrap` when the
|
|
18
|
+
* corresponding vnode is removed from the DOM tree. The dispatch path
|
|
19
|
+
* reads from `wraps` at event-fire time.
|
|
20
|
+
*
|
|
21
|
+
* `boundaryDispatches` caches per-(outerDispatch, boundaryId) dispatcher
|
|
22
|
+
* closures so `requireDispatch` returns a stable reference across
|
|
23
|
+
* repeated calls with the same outerDispatch (necessary for
|
|
24
|
+
* `createLazy`'s dispatch-identity check). Keyed by outerDispatch as a
|
|
25
|
+
* WeakMap so DevTools jump-to renders with a different
|
|
26
|
+
* outerDispatch (typically a noOpDispatch that drops messages) get
|
|
27
|
+
* their own per-boundary cache. Without this two-level keying, a
|
|
28
|
+
* dispatcher created during a live render would still close over the
|
|
29
|
+
* live outerDispatch after a jump-to and silently mutate the live app.
|
|
30
|
+
*
|
|
31
|
+
* `seenThisRender` tracks boundaries marked alive during the current
|
|
32
|
+
* render for duplicate-slotId detection: two `h.submodel` calls
|
|
33
|
+
* inside the same parent boundary must use different `slotId`s.
|
|
34
|
+
* Values are the call site captured at register time, surfaced when a
|
|
35
|
+
* second register collides so both locations land in the throw
|
|
36
|
+
* message. The map is cleared at the start of each render via
|
|
37
|
+
* `beginRender`. Boundaries behind a `createLazy`/`createKeyedLazy`
|
|
38
|
+
* cache hit are replayed into this map via {@link markSeenForLazyHit}
|
|
39
|
+
* so the duplicate-slotId guard catches collisions against memoized
|
|
40
|
+
* siblings, not just against siblings that re-ran this frame. It is
|
|
41
|
+
* NOT used for pruning; pruning is driven by VNode destroy hooks
|
|
42
|
+
* instead.
|
|
43
|
+
*
|
|
44
|
+
* `lazyTrackingStack` is a stack of sets used by `createLazy` and
|
|
45
|
+
* `createKeyedLazy` to capture which boundary ids were marked alive
|
|
46
|
+
* during the wrapped function's first execution. On a later cache
|
|
47
|
+
* hit, the lazy helper replays the captured ids into
|
|
48
|
+
* `seenThisRender` so the duplicate-slotId guard sees them. Each
|
|
49
|
+
* active lazy invocation pushes its own set; `registerBoundaryWrap`
|
|
50
|
+
* and `markSeenForLazyHit` write to every set on the stack so an
|
|
51
|
+
* outer lazy correctly captures ids contributed by inner lazies it
|
|
52
|
+
* wraps. */
|
|
53
|
+
export type BoundaryRegistry = {
|
|
54
|
+
readonly wraps: Map<BoundaryId, WrapDescriptor>;
|
|
55
|
+
readonly boundaryDispatches: WeakMap<DispatchSync, Map<BoundaryId, DispatchSync>>;
|
|
56
|
+
readonly seenThisRender: Map<BoundaryId, string>;
|
|
57
|
+
readonly lazyTrackingStack: Array<Map<BoundaryId, string>>;
|
|
58
|
+
};
|
|
59
|
+
export declare const createBoundaryRegistry: () => BoundaryRegistry;
|
|
60
|
+
export declare const registerBoundaryWrap: (registry: BoundaryRegistry, boundaryId: BoundaryId, descriptor: WrapDescriptor) => void;
|
|
61
|
+
/** Starts capturing boundary registrations on a fresh set pushed onto
|
|
62
|
+
* `lazyTrackingStack`. Used by `createLazy`/`createKeyedLazy` around the
|
|
63
|
+
* wrapped view function. Must be paired with {@link endLazyTracking} on
|
|
64
|
+
* the same call stack so an exception inside the view does not leak the
|
|
65
|
+
* tracking frame to a later render. */
|
|
66
|
+
export declare const beginLazyTracking: (registry: BoundaryRegistry) => Map<BoundaryId, string>;
|
|
67
|
+
/** Pops the most recent tracking set. Throws when called on an empty
|
|
68
|
+
* stack to surface unmatched begin/end pairs immediately rather than
|
|
69
|
+
* silently corrupting later renders. */
|
|
70
|
+
export declare const endLazyTracking: (registry: BoundaryRegistry) => void;
|
|
71
|
+
/** Replays a set of boundary ids captured during a previous lazy run
|
|
72
|
+
* into `seenThisRender` so the duplicate-slotId guard sees them. Also
|
|
73
|
+
* forwards them into any active tracking sets so an outer lazy
|
|
74
|
+
* wrapping this cache hit captures the ids in its own snapshot.
|
|
75
|
+
*
|
|
76
|
+
* Skips ids already present in `seenThisRender` to preserve the
|
|
77
|
+
* original call site of the live entry (the first registration this
|
|
78
|
+
* render still wins the error message). */
|
|
79
|
+
export declare const markSeenForLazyHit: (registry: BoundaryRegistry, trackedIds: ReadonlyMap<BoundaryId, string>) => void;
|
|
80
|
+
/** Removes a boundary's wrap. Called by `h.submodel`'s destroy hook when
|
|
81
|
+
* the corresponding vnode leaves the DOM.
|
|
82
|
+
*
|
|
83
|
+
* Does not touch `boundaryDispatches`: it is a WeakMap keyed by
|
|
84
|
+
* outerDispatch, so per-outerDispatch inner Maps become unreachable and
|
|
85
|
+
* are GC'd when their outerDispatch is. Cached dispatcher closures that
|
|
86
|
+
* outlive a deregister become inert. `dispatchAcrossBoundary` throws
|
|
87
|
+
* when it cannot find an ancestor wrap, which surfaces a clear error
|
|
88
|
+
* rather than letting events from a destroyed boundary silently
|
|
89
|
+
* misroute. */
|
|
90
|
+
export declare const deregisterBoundaryWrap: (registry: BoundaryRegistry, boundaryId: BoundaryId) => void;
|
|
91
|
+
export declare const getOrCreateBoundaryDispatch: (registry: BoundaryRegistry, outerDispatch: DispatchSync, boundaryId: BoundaryId) => DispatchSync;
|
|
92
|
+
/** Called at the start of each top-level render. Clears the
|
|
93
|
+
* per-render duplicate-slotId tracking map so siblings inside the
|
|
94
|
+
* same parent boundary can be re-validated. Does NOT touch `wraps`
|
|
95
|
+
* or `boundaryDispatches`. Those persist across renders and are
|
|
96
|
+
* evicted by vnode destroy hooks instead. */
|
|
97
|
+
export declare const beginRender: (registry: BoundaryRegistry) => void;
|
|
98
|
+
//# sourceMappingURL=boundary.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"boundary.d.ts","sourceRoot":"","sources":["../../src/html/boundary.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,uBAAuB,CAAA;AAEzD,wDAAwD;AACxD,MAAM,MAAM,cAAc,GAAG,QAAQ,CAAC;IACpC,eAAe,EAAE,CAAC,OAAO,EAAE,OAAO,KAAK,OAAO,CAAA;CAC/C,CAAC,CAAA;AAEF;;;;eAIe;AACf,MAAM,MAAM,UAAU,GAAG,MAAM,CAAA;AAI/B,eAAO,MAAM,aAAa,EAAE,UAAe,CAAA;AAE3C,eAAO,MAAM,eAAe,GAC1B,QAAQ,UAAU,EAClB,SAAS,MAAM,KACd,UAUF,CAAA;AAKD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;aAsCa;AACb,MAAM,MAAM,gBAAgB,GAAG;IAC7B,QAAQ,CAAC,KAAK,EAAE,GAAG,CAAC,UAAU,EAAE,cAAc,CAAC,CAAA;IAC/C,QAAQ,CAAC,kBAAkB,EAAE,OAAO,CAClC,YAAY,EACZ,GAAG,CAAC,UAAU,EAAE,YAAY,CAAC,CAC9B,CAAA;IACD,QAAQ,CAAC,cAAc,EAAE,GAAG,CAAC,UAAU,EAAE,MAAM,CAAC,CAAA;IAChD,QAAQ,CAAC,iBAAiB,EAAE,KAAK,CAAC,GAAG,CAAC,UAAU,EAAE,MAAM,CAAC,CAAC,CAAA;CAC3D,CAAA;AAED,eAAO,MAAM,sBAAsB,QAAO,gBAKxC,CAAA;AAqBF,eAAO,MAAM,oBAAoB,GAC/B,UAAU,gBAAgB,EAC1B,YAAY,UAAU,EACtB,YAAY,cAAc,KACzB,IA6BF,CAAA;AAED;;;;wCAIwC;AACxC,eAAO,MAAM,iBAAiB,GAC5B,UAAU,gBAAgB,KACzB,GAAG,CAAC,UAAU,EAAE,MAAM,CAIxB,CAAA;AAED;;yCAEyC;AACzC,eAAO,MAAM,eAAe,GAAI,UAAU,gBAAgB,KAAG,IAQ5D,CAAA;AAED;;;;;;;4CAO4C;AAC5C,eAAO,MAAM,kBAAkB,GAC7B,UAAU,gBAAgB,EAC1B,YAAY,WAAW,CAAC,UAAU,EAAE,MAAM,CAAC,KAC1C,IAWF,CAAA;AAED;;;;;;;;;gBASgB;AAChB,eAAO,MAAM,sBAAsB,GACjC,UAAU,gBAAgB,EAC1B,YAAY,UAAU,KACrB,IAEF,CAAA;AA4CD,eAAO,MAAM,2BAA2B,GACtC,UAAU,gBAAgB,EAC1B,eAAe,YAAY,EAC3B,YAAY,UAAU,KACrB,YAkBF,CAAA;AAED;;;;8CAI8C;AAC9C,eAAO,MAAM,WAAW,GAAI,UAAU,gBAAgB,KAAG,IAExD,CAAA"}
|
|
@@ -0,0 +1,176 @@
|
|
|
1
|
+
const BOUNDARY_SEPARATOR = '|';
|
|
2
|
+
export const ROOT_BOUNDARY = '';
|
|
3
|
+
export const composeBoundary = (parent, childId) => {
|
|
4
|
+
if (childId.includes(BOUNDARY_SEPARATOR)) {
|
|
5
|
+
throw new Error(`Foldkit: h.submodel slotId cannot contain the boundary separator ` +
|
|
6
|
+
`"${BOUNDARY_SEPARATOR}". Got ${JSON.stringify(childId)}.`);
|
|
7
|
+
}
|
|
8
|
+
return parent === ROOT_BOUNDARY
|
|
9
|
+
? childId
|
|
10
|
+
: `${parent}${BOUNDARY_SEPARATOR}${childId}`;
|
|
11
|
+
};
|
|
12
|
+
const splitBoundary = (boundaryId) => boundaryId === ROOT_BOUNDARY ? [] : boundaryId.split(BOUNDARY_SEPARATOR);
|
|
13
|
+
export const createBoundaryRegistry = () => ({
|
|
14
|
+
wraps: new Map(),
|
|
15
|
+
boundaryDispatches: new WeakMap(),
|
|
16
|
+
seenThisRender: new Map(),
|
|
17
|
+
lazyTrackingStack: [],
|
|
18
|
+
});
|
|
19
|
+
const captureCallSite = () => {
|
|
20
|
+
const stack = new Error().stack ?? '';
|
|
21
|
+
const lines = stack.split('\n');
|
|
22
|
+
for (const line of lines) {
|
|
23
|
+
const trimmed = line.trim();
|
|
24
|
+
if (trimmed.length === 0 ||
|
|
25
|
+
trimmed.startsWith('Error') ||
|
|
26
|
+
trimmed.includes('captureCallSite') ||
|
|
27
|
+
trimmed.includes('registerBoundaryWrap') ||
|
|
28
|
+
trimmed.includes('at submodel')) {
|
|
29
|
+
continue;
|
|
30
|
+
}
|
|
31
|
+
return trimmed;
|
|
32
|
+
}
|
|
33
|
+
return '(call site unavailable)';
|
|
34
|
+
};
|
|
35
|
+
export const registerBoundaryWrap = (registry, boundaryId, descriptor) => {
|
|
36
|
+
const existingCallSite = registry.seenThisRender.get(boundaryId);
|
|
37
|
+
if (existingCallSite !== undefined) {
|
|
38
|
+
const ownSlotId = boundaryId.includes(BOUNDARY_SEPARATOR)
|
|
39
|
+
? boundaryId.slice(boundaryId.lastIndexOf(BOUNDARY_SEPARATOR) + 1)
|
|
40
|
+
: boundaryId;
|
|
41
|
+
const newCallSite = captureCallSite();
|
|
42
|
+
throw new Error(`Foldkit: duplicate h.submodel slotId "${ownSlotId}" at boundary "${boundaryId}".\n` +
|
|
43
|
+
` First registration: ${existingCallSite}\n` +
|
|
44
|
+
` Second registration: ${newCallSite}\n` +
|
|
45
|
+
`Each h.submodel call inside the same parent boundary must use a unique \`slotId\`. ` +
|
|
46
|
+
`The slotId is DOM-slot identity, not model identity. If the same model is ` +
|
|
47
|
+
`rendered in two locations (desktop + mobile, master + detail), each slot ` +
|
|
48
|
+
`needs its own id (e.g. "desktop-foo", "mobile-foo"). For lists, use a stable ` +
|
|
49
|
+
`per-item identifier.`);
|
|
50
|
+
}
|
|
51
|
+
// NOTE: compute the call site before writing either map. If
|
|
52
|
+
// captureCallSite throws (e.g. hardened runtime without
|
|
53
|
+
// Error.stack), neither map is mutated, so a later registration
|
|
54
|
+
// with the same slotId throws the duplicate error correctly instead
|
|
55
|
+
// of silently overwriting after a half-finished prior write.
|
|
56
|
+
const callSite = captureCallSite();
|
|
57
|
+
registry.wraps.set(boundaryId, descriptor);
|
|
58
|
+
registry.seenThisRender.set(boundaryId, callSite);
|
|
59
|
+
for (const tracked of registry.lazyTrackingStack) {
|
|
60
|
+
tracked.set(boundaryId, callSite);
|
|
61
|
+
}
|
|
62
|
+
};
|
|
63
|
+
/** Starts capturing boundary registrations on a fresh set pushed onto
|
|
64
|
+
* `lazyTrackingStack`. Used by `createLazy`/`createKeyedLazy` around the
|
|
65
|
+
* wrapped view function. Must be paired with {@link endLazyTracking} on
|
|
66
|
+
* the same call stack so an exception inside the view does not leak the
|
|
67
|
+
* tracking frame to a later render. */
|
|
68
|
+
export const beginLazyTracking = (registry) => {
|
|
69
|
+
const tracked = new Map();
|
|
70
|
+
registry.lazyTrackingStack.push(tracked);
|
|
71
|
+
return tracked;
|
|
72
|
+
};
|
|
73
|
+
/** Pops the most recent tracking set. Throws when called on an empty
|
|
74
|
+
* stack to surface unmatched begin/end pairs immediately rather than
|
|
75
|
+
* silently corrupting later renders. */
|
|
76
|
+
export const endLazyTracking = (registry) => {
|
|
77
|
+
if (registry.lazyTrackingStack.length === 0) {
|
|
78
|
+
throw new Error('Foldkit: endLazyTracking called on an empty stack. This means a ' +
|
|
79
|
+
'`beginLazyTracking` was not paired with `endLazyTracking` upstream.');
|
|
80
|
+
}
|
|
81
|
+
registry.lazyTrackingStack.pop();
|
|
82
|
+
};
|
|
83
|
+
/** Replays a set of boundary ids captured during a previous lazy run
|
|
84
|
+
* into `seenThisRender` so the duplicate-slotId guard sees them. Also
|
|
85
|
+
* forwards them into any active tracking sets so an outer lazy
|
|
86
|
+
* wrapping this cache hit captures the ids in its own snapshot.
|
|
87
|
+
*
|
|
88
|
+
* Skips ids already present in `seenThisRender` to preserve the
|
|
89
|
+
* original call site of the live entry (the first registration this
|
|
90
|
+
* render still wins the error message). */
|
|
91
|
+
export const markSeenForLazyHit = (registry, trackedIds) => {
|
|
92
|
+
for (const [boundaryId, callSite] of trackedIds) {
|
|
93
|
+
if (!registry.seenThisRender.has(boundaryId)) {
|
|
94
|
+
registry.seenThisRender.set(boundaryId, callSite);
|
|
95
|
+
}
|
|
96
|
+
for (const outerTracked of registry.lazyTrackingStack) {
|
|
97
|
+
if (!outerTracked.has(boundaryId)) {
|
|
98
|
+
outerTracked.set(boundaryId, callSite);
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
};
|
|
103
|
+
/** Removes a boundary's wrap. Called by `h.submodel`'s destroy hook when
|
|
104
|
+
* the corresponding vnode leaves the DOM.
|
|
105
|
+
*
|
|
106
|
+
* Does not touch `boundaryDispatches`: it is a WeakMap keyed by
|
|
107
|
+
* outerDispatch, so per-outerDispatch inner Maps become unreachable and
|
|
108
|
+
* are GC'd when their outerDispatch is. Cached dispatcher closures that
|
|
109
|
+
* outlive a deregister become inert. `dispatchAcrossBoundary` throws
|
|
110
|
+
* when it cannot find an ancestor wrap, which surfaces a clear error
|
|
111
|
+
* rather than letting events from a destroyed boundary silently
|
|
112
|
+
* misroute. */
|
|
113
|
+
export const deregisterBoundaryWrap = (registry, boundaryId) => {
|
|
114
|
+
registry.wraps.delete(boundaryId);
|
|
115
|
+
};
|
|
116
|
+
/** Applies the wrapping chain for `boundaryId` from innermost to
|
|
117
|
+
* outermost, then dispatches the fully-wrapped message via
|
|
118
|
+
* `outerDispatch`. Called at event-fire time by the dispatcher closure
|
|
119
|
+
* returned from `getOrCreateBoundaryDispatch`.
|
|
120
|
+
*
|
|
121
|
+
* Throws when an ancestor wrap is missing from the registry. DOM events
|
|
122
|
+
* fire synchronously, so a sync handler against a live boundary always
|
|
123
|
+
* finds a complete chain. A missing wrap implies one of: (a) the wrap
|
|
124
|
+
* was deregistered between event scheduling and dispatch (e.g. a slot
|
|
125
|
+
* callback captured at one render is invoked from a deferred context
|
|
126
|
+
* after the Submodel unmounted), or (b) the registry is corrupt.
|
|
127
|
+
* Either way, silently skipping the ancestor and applying only outer
|
|
128
|
+
* wraps would produce a malformed Message that the outermost
|
|
129
|
+
* `Match.tagsExhaustive` would then crash on with no useful trace. */
|
|
130
|
+
const dispatchAcrossBoundary = (registry, outerDispatch, boundaryId, message) => {
|
|
131
|
+
let wrapped = message;
|
|
132
|
+
const parts = splitBoundary(boundaryId);
|
|
133
|
+
for (let depth = parts.length; depth > 0; depth--) {
|
|
134
|
+
const ancestorBoundary = parts.slice(0, depth).join(BOUNDARY_SEPARATOR);
|
|
135
|
+
const descriptor = registry.wraps.get(ancestorBoundary);
|
|
136
|
+
if (descriptor === undefined) {
|
|
137
|
+
throw new Error(`Foldkit: dispatchAcrossBoundary missing wrap for ancestor ` +
|
|
138
|
+
`"${ancestorBoundary}" of boundary "${boundaryId}". This means a ` +
|
|
139
|
+
`Submodel's wrap was deregistered between event scheduling and ` +
|
|
140
|
+
`dispatch. Most likely cause: a slot callback (h.submodel ` +
|
|
141
|
+
`\`viewInputs\` function value) was invoked from a deferred context ` +
|
|
142
|
+
`(setTimeout, Promise.then, stored callback) after the parent ` +
|
|
143
|
+
`Submodel unmounted. Slot callbacks must be invoked synchronously ` +
|
|
144
|
+
`inside the render in which they were created.`);
|
|
145
|
+
}
|
|
146
|
+
wrapped = descriptor.toParentMessage(wrapped);
|
|
147
|
+
}
|
|
148
|
+
outerDispatch(wrapped);
|
|
149
|
+
};
|
|
150
|
+
export const getOrCreateBoundaryDispatch = (registry, outerDispatch, boundaryId) => {
|
|
151
|
+
if (boundaryId === ROOT_BOUNDARY) {
|
|
152
|
+
return outerDispatch;
|
|
153
|
+
}
|
|
154
|
+
let perOuterDispatch = registry.boundaryDispatches.get(outerDispatch);
|
|
155
|
+
if (perOuterDispatch === undefined) {
|
|
156
|
+
perOuterDispatch = new Map();
|
|
157
|
+
registry.boundaryDispatches.set(outerDispatch, perOuterDispatch);
|
|
158
|
+
}
|
|
159
|
+
const existing = perOuterDispatch.get(boundaryId);
|
|
160
|
+
if (existing !== undefined) {
|
|
161
|
+
return existing;
|
|
162
|
+
}
|
|
163
|
+
const dispatch = message => {
|
|
164
|
+
dispatchAcrossBoundary(registry, outerDispatch, boundaryId, message);
|
|
165
|
+
};
|
|
166
|
+
perOuterDispatch.set(boundaryId, dispatch);
|
|
167
|
+
return dispatch;
|
|
168
|
+
};
|
|
169
|
+
/** Called at the start of each top-level render. Clears the
|
|
170
|
+
* per-render duplicate-slotId tracking map so siblings inside the
|
|
171
|
+
* same parent boundary can be re-validated. Does NOT touch `wraps`
|
|
172
|
+
* or `boundaryDispatches`. Those persist across renders and are
|
|
173
|
+
* evicted by vnode destroy hooks instead. */
|
|
174
|
+
export const beginRender = (registry) => {
|
|
175
|
+
registry.seenThisRender.clear();
|
|
176
|
+
};
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import { type DispatchSync } from './runtimeSingleton.js';
|
|
2
|
+
declare const BRAND = "__childAttribute";
|
|
3
|
+
/** An attribute carrying a handler that dispatches through a Submodel
|
|
4
|
+
* boundary's wrapping chain. Published by Submodels (typically Foldkit's
|
|
5
|
+
* `Ui.*` primitives) for a parent to spread into its own element
|
|
6
|
+
* attribute arrays. The parent does not know or care which child
|
|
7
|
+
* produced these; the runtime routes each handler through the
|
|
8
|
+
* originating Submodel's wrap chain at event-fire time.
|
|
9
|
+
*
|
|
10
|
+
* Created via {@link childAttributes}. Element constructors accept
|
|
11
|
+
* `ChildAttribute` alongside `Attribute<Message>` in their attribute
|
|
12
|
+
* arrays. */
|
|
13
|
+
export type ChildAttribute = Readonly<{
|
|
14
|
+
readonly [BRAND]: true;
|
|
15
|
+
readonly attribute: unknown;
|
|
16
|
+
readonly dispatch: DispatchSync;
|
|
17
|
+
}>;
|
|
18
|
+
export declare const isChildAttribute: (value: unknown) => value is ChildAttribute;
|
|
19
|
+
/** Captures the current boundary's dispatcher and wraps each attribute
|
|
20
|
+
* so handlers inside it route through that boundary's wrapping chain at
|
|
21
|
+
* event-fire time, even when the attribute is later spread into a
|
|
22
|
+
* parent's element in a different boundary.
|
|
23
|
+
*
|
|
24
|
+
* Submodels call this when publishing attribute groups to a consumer's
|
|
25
|
+
* `toView` slot callback:
|
|
26
|
+
*
|
|
27
|
+
* ```ts
|
|
28
|
+
* // Inside a SubmodelView running in the child's boundary:
|
|
29
|
+
* return viewInputs.toView({
|
|
30
|
+
* checkbox: childAttributes([
|
|
31
|
+
* h.OnClick(Toggled()),
|
|
32
|
+
* h.Role('checkbox'),
|
|
33
|
+
* ]),
|
|
34
|
+
* ...
|
|
35
|
+
* })
|
|
36
|
+
* ```
|
|
37
|
+
*
|
|
38
|
+
* Without this binding step the consumer's element constructor would
|
|
39
|
+
* process `h.OnClick(Toggled())` using the parent's dispatcher (because
|
|
40
|
+
* the consumer's `toView` runs in the parent's boundary), bypassing the
|
|
41
|
+
* Submodel's `toParentMessage`. */
|
|
42
|
+
export declare const childAttributes: <Attribute>(attributes: ReadonlyArray<Attribute>) => ReadonlyArray<ChildAttribute>;
|
|
43
|
+
export {};
|
|
44
|
+
//# sourceMappingURL=childAttribute.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"childAttribute.d.ts","sourceRoot":"","sources":["../../src/html/childAttribute.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,YAAY,EAAmB,MAAM,uBAAuB,CAAA;AAE1E,QAAA,MAAM,KAAK,qBAAqB,CAAA;AAEhC;;;;;;;;;cASc;AACd,MAAM,MAAM,cAAc,GAAG,QAAQ,CAAC;IACpC,QAAQ,CAAC,CAAC,KAAK,CAAC,EAAE,IAAI,CAAA;IACtB,QAAQ,CAAC,SAAS,EAAE,OAAO,CAAA;IAC3B,QAAQ,CAAC,QAAQ,EAAE,YAAY,CAAA;CAChC,CAAC,CAAA;AAEF,eAAO,MAAM,gBAAgB,GAAI,OAAO,OAAO,KAAG,KAAK,IAAI,cACI,CAAA;AAE/D;;;;;;;;;;;;;;;;;;;;;;oCAsBoC;AACpC,eAAO,MAAM,eAAe,GAAI,SAAS,EACvC,YAAY,aAAa,CAAC,SAAS,CAAC,KACnC,aAAa,CAAC,cAAc,CAO9B,CAAA"}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import { requireDispatch } from './runtimeSingleton.js';
|
|
2
|
+
const BRAND = '__childAttribute';
|
|
3
|
+
export const isChildAttribute = (value) => typeof value === 'object' && value !== null && BRAND in value;
|
|
4
|
+
/** Captures the current boundary's dispatcher and wraps each attribute
|
|
5
|
+
* so handlers inside it route through that boundary's wrapping chain at
|
|
6
|
+
* event-fire time, even when the attribute is later spread into a
|
|
7
|
+
* parent's element in a different boundary.
|
|
8
|
+
*
|
|
9
|
+
* Submodels call this when publishing attribute groups to a consumer's
|
|
10
|
+
* `toView` slot callback:
|
|
11
|
+
*
|
|
12
|
+
* ```ts
|
|
13
|
+
* // Inside a SubmodelView running in the child's boundary:
|
|
14
|
+
* return viewInputs.toView({
|
|
15
|
+
* checkbox: childAttributes([
|
|
16
|
+
* h.OnClick(Toggled()),
|
|
17
|
+
* h.Role('checkbox'),
|
|
18
|
+
* ]),
|
|
19
|
+
* ...
|
|
20
|
+
* })
|
|
21
|
+
* ```
|
|
22
|
+
*
|
|
23
|
+
* Without this binding step the consumer's element constructor would
|
|
24
|
+
* process `h.OnClick(Toggled())` using the parent's dispatcher (because
|
|
25
|
+
* the consumer's `toView` runs in the parent's boundary), bypassing the
|
|
26
|
+
* Submodel's `toParentMessage`. */
|
|
27
|
+
export const childAttributes = (attributes) => {
|
|
28
|
+
const dispatch = requireDispatch();
|
|
29
|
+
return attributes.map(attribute => ({
|
|
30
|
+
[BRAND]: true,
|
|
31
|
+
attribute,
|
|
32
|
+
dispatch,
|
|
33
|
+
}));
|
|
34
|
+
};
|
package/dist/html/index.d.ts
CHANGED
|
@@ -1,9 +1,32 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { Context, Data, Option, Stream } from 'effect';
|
|
2
2
|
import type { File } from '../file/index.js';
|
|
3
3
|
import type { MountAction } from '../mount/index.js';
|
|
4
|
-
import { Dispatch } from '../runtime/index.js';
|
|
5
4
|
import { VNode } from '../vdom.js';
|
|
5
|
+
import { type ChildAttribute } from './childAttribute.js';
|
|
6
|
+
import { type DispatchSync } from './runtimeSingleton.js';
|
|
6
7
|
export { createKeyedLazy, createLazy } from './lazy.js';
|
|
8
|
+
export { beginRender as __beginRender, createBoundaryRegistry as __createBoundaryRegistry, } from './boundary.js';
|
|
9
|
+
export type { BoundaryRegistry } from './boundary.js';
|
|
10
|
+
export { childAttributes } from './childAttribute.js';
|
|
11
|
+
export type { ChildAttribute } from './childAttribute.js';
|
|
12
|
+
export { defineView, submodel } from './submodel.js';
|
|
13
|
+
export type { SubmodelConfig, SubmodelView } from './submodel.js';
|
|
14
|
+
/** Pushes a dispatch and runtime context frame for the duration of a render.
|
|
15
|
+
* The runtime calls this immediately before invoking a user `view` and
|
|
16
|
+
* matches it with {@link __clearRuntime} in a `finally` so an exception
|
|
17
|
+
* inside view code does not leak the frame to the next render. Test
|
|
18
|
+
* scaffolding that builds VNodes outside of a real program (Scene, Canvas
|
|
19
|
+
* view-only tests, Mount tests) uses the same pair. Nested frames are
|
|
20
|
+
* supported via an internal stack. */
|
|
21
|
+
export declare const __setRuntime: (dispatch: DispatchSync, runtimeContext: Context.Context<never>, boundaryRegistry?: import("./boundary.js").BoundaryRegistry) => void;
|
|
22
|
+
/** Pops the current dispatch and runtime context frame. Must be paired with a
|
|
23
|
+
* prior {@link __setRuntime} on the same call stack. */
|
|
24
|
+
export declare const __clearRuntime: () => void;
|
|
25
|
+
/** Returns the current dispatch function. Foldkit's `Canvas.view` reads this
|
|
26
|
+
* to build its synchronous pointer handlers, since it builds VNodes directly
|
|
27
|
+
* rather than going through the html factory. Most application code never
|
|
28
|
+
* needs to call this. */
|
|
29
|
+
export declare const __requireDispatch: () => DispatchSync;
|
|
7
30
|
/**
|
|
8
31
|
* The `id` of the DOM element that hosts the Foldkit DevTools shadow root.
|
|
9
32
|
* Lives here (not in `devTools/`) because the `OnBlur` handler below uses it
|
|
@@ -16,7 +39,7 @@ export declare const DEVTOOLS_HOST_ID = "foldkit-devtools";
|
|
|
16
39
|
* Tag symbol attached to file-aware event handler functions so Scene test
|
|
17
40
|
* helpers can distinguish `OnFileChange` from `OnChange` (both register on
|
|
18
41
|
* the DOM `change` event) and `OnDropFiles` from `OnDrop` (both register on
|
|
19
|
-
* the DOM `drop` event). Internal implementation detail
|
|
42
|
+
* the DOM `drop` event). Internal implementation detail. Consumer code
|
|
20
43
|
* should never need to reference this directly.
|
|
21
44
|
*/
|
|
22
45
|
export declare const FileHandlerSymbol: unique symbol;
|
|
@@ -29,8 +52,10 @@ export type KeyboardModifiers = Readonly<{
|
|
|
29
52
|
altKey: boolean;
|
|
30
53
|
metaKey: boolean;
|
|
31
54
|
}>;
|
|
32
|
-
/** A virtual DOM element
|
|
33
|
-
|
|
55
|
+
/** A virtual DOM element. Constructed synchronously by the element factories
|
|
56
|
+
* returned from {@link html}. The runtime patches a `VNode` (or `null` to
|
|
57
|
+
* render nothing) into the application container. */
|
|
58
|
+
export type Html = VNode | null;
|
|
34
59
|
export type Child = Html | string;
|
|
35
60
|
/** A view's complete output for the runtime: title, body, and optional document
|
|
36
61
|
* metadata. The runtime applies `title` to `document.title`, syncs `canonical`
|
|
@@ -60,7 +85,15 @@ export type FoldkitMountMarker = Readonly<{
|
|
|
60
85
|
name: string;
|
|
61
86
|
args?: Record<string, unknown>;
|
|
62
87
|
}>;
|
|
63
|
-
/** Union of all HTML, SVG, and MathML attributes a virtual DOM element can carry.
|
|
88
|
+
/** Union of all HTML, SVG, and MathML attributes a virtual DOM element can carry.
|
|
89
|
+
*
|
|
90
|
+
* When a Submodel publishes attribute groups to a consumer's `toView`
|
|
91
|
+
* slot, those attributes are wrapped via {@link childAttributes} into
|
|
92
|
+
* {@link ChildAttribute}, a distinct type that carries the Submodel's
|
|
93
|
+
* own dispatcher. Element constructors accept the union
|
|
94
|
+
* `ReadonlyArray<Attribute<Message> | ChildAttribute>`, so consumers
|
|
95
|
+
* can spread published bundles directly into their own attribute
|
|
96
|
+
* arrays. */
|
|
64
97
|
export type Attribute<Message> = Data.TaggedEnum<{
|
|
65
98
|
Key: {
|
|
66
99
|
readonly value: string;
|
|
@@ -798,22 +831,27 @@ declare const Prop: <A>(args: {
|
|
|
798
831
|
readonly f: (event: CustomEvent<any>) => A;
|
|
799
832
|
};
|
|
800
833
|
export { Prop, OnCustomEvent };
|
|
801
|
-
export declare const customElement: <Message>() => (tagName: string) => (attributes?: ReadonlyArray<Attribute<Message
|
|
802
|
-
type ElementFunction<Message> = (attributes: ReadonlyArray<Attribute<Message
|
|
803
|
-
type VoidElementFunction<Message> = (attributes: ReadonlyArray<Attribute<Message
|
|
804
|
-
|
|
805
|
-
|
|
806
|
-
|
|
807
|
-
|
|
808
|
-
|
|
809
|
-
|
|
810
|
-
|
|
811
|
-
keyed: (tagName: TagName) => (key: string, attributes?: readonly ({
|
|
834
|
+
export declare const customElement: <Message>() => (tagName: string) => (attributes?: ReadonlyArray<Attribute<Message> | ChildAttribute>, children?: ReadonlyArray<Child>) => Html;
|
|
835
|
+
type ElementFunction<Message> = (attributes: ReadonlyArray<Attribute<Message> | ChildAttribute>, children: ReadonlyArray<Child>) => Html;
|
|
836
|
+
type VoidElementFunction<Message> = (attributes: ReadonlyArray<Attribute<Message> | ChildAttribute>) => Html;
|
|
837
|
+
declare const buildHtmlFactory: <Message>() => {
|
|
838
|
+
empty: null;
|
|
839
|
+
keyed: (tagName: TagName) => (key: string, attributes?: readonly (Readonly<{
|
|
840
|
+
readonly attribute: unknown;
|
|
841
|
+
readonly dispatch: DispatchSync;
|
|
842
|
+
readonly __childAttribute: true;
|
|
843
|
+
}> | {
|
|
812
844
|
readonly _tag: "Type";
|
|
813
845
|
readonly value: string;
|
|
814
846
|
} | {
|
|
815
847
|
readonly _tag: "Start";
|
|
816
848
|
readonly value: number;
|
|
849
|
+
} | {
|
|
850
|
+
readonly _tag: "OnFileChange";
|
|
851
|
+
readonly f: (files: ReadonlyArray<File>) => Message;
|
|
852
|
+
} | {
|
|
853
|
+
readonly _tag: "OnDropFiles";
|
|
854
|
+
readonly f: (files: ReadonlyArray<File>) => Message;
|
|
817
855
|
} | {
|
|
818
856
|
readonly _tag: "Key";
|
|
819
857
|
readonly value: string;
|
|
@@ -953,9 +991,6 @@ export declare const html: <Message = never>() => {
|
|
|
953
991
|
} | {
|
|
954
992
|
readonly _tag: "OnChange";
|
|
955
993
|
readonly f: (value: string) => Message;
|
|
956
|
-
} | {
|
|
957
|
-
readonly _tag: "OnFileChange";
|
|
958
|
-
readonly f: (files: ReadonlyArray<File>) => Message;
|
|
959
994
|
} | {
|
|
960
995
|
readonly _tag: "OnSubmit";
|
|
961
996
|
readonly message: Message;
|
|
@@ -1009,9 +1044,6 @@ export declare const html: <Message = never>() => {
|
|
|
1009
1044
|
} | {
|
|
1010
1045
|
readonly _tag: "OnDrop";
|
|
1011
1046
|
readonly message: Message;
|
|
1012
|
-
} | {
|
|
1013
|
-
readonly _tag: "OnDropFiles";
|
|
1014
|
-
readonly f: (files: ReadonlyArray<File>) => Message;
|
|
1015
1047
|
} | {
|
|
1016
1048
|
readonly _tag: "OnTouchStart";
|
|
1017
1049
|
readonly message: Message;
|
|
@@ -1558,6 +1590,9 @@ export declare const html: <Message = never>() => {
|
|
|
1558
1590
|
f: (element: Element) => Stream.Stream<Message, any, never>;
|
|
1559
1591
|
}>;
|
|
1560
1592
|
})[], children?: ReadonlyArray<Child>) => Html;
|
|
1593
|
+
submodel: <View extends ((...args: ReadonlyArray<any>) => VNode | null) & {
|
|
1594
|
+
readonly __submodelMessage: unknown;
|
|
1595
|
+
}>(config: import("./submodel.js").SubmodelConfig<View>) => VNode | null;
|
|
1561
1596
|
Key: (value: string) => {
|
|
1562
1597
|
readonly _tag: "Key";
|
|
1563
1598
|
readonly value: string;
|
|
@@ -2779,4 +2814,16 @@ export declare const html: <Message = never>() => {
|
|
|
2779
2814
|
munderover: ElementFunction<Message>;
|
|
2780
2815
|
semantics: ElementFunction<Message>;
|
|
2781
2816
|
};
|
|
2817
|
+
/**
|
|
2818
|
+
* Returns all HTML, SVG, and MathML element constructors, attribute
|
|
2819
|
+
* constructors, a `keyed` helper for keyed elements, and `empty` for
|
|
2820
|
+
* rendering nothing.
|
|
2821
|
+
*
|
|
2822
|
+
* The returned object is a process-wide singleton. The `Message` type
|
|
2823
|
+
* parameter is erased at runtime, and the element and attribute constructors
|
|
2824
|
+
* carry no per-program state (dispatch is read from the runtime singleton at
|
|
2825
|
+
* call time), so calling `html()` repeatedly from inside view functions does
|
|
2826
|
+
* not allocate a fresh object.
|
|
2827
|
+
*/
|
|
2828
|
+
export declare const html: <Message = never>() => ReturnType<typeof buildHtmlFactory<Message>>;
|
|
2782
2829
|
//# sourceMappingURL=index.d.ts.map
|