foldkit 0.156.0 → 0.157.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 -3
- package/dist/asyncData/asyncData.d.ts +7 -7
- package/dist/asyncData/asyncData.d.ts.map +1 -1
- package/dist/asyncData/asyncData.js +12 -12
- package/dist/calendar/calendarDate.d.ts +15 -15
- package/dist/calendar/calendarDate.d.ts.map +1 -1
- package/dist/calendar/calendarDate.js +14 -14
- package/dist/calendar/comparison.d.ts +2 -2
- package/dist/calendar/comparison.d.ts.map +1 -1
- package/dist/calendar/comparison.js +5 -5
- package/dist/calendar/info.d.ts +2 -2
- package/dist/calendar/info.d.ts.map +1 -1
- package/dist/calendar/info.js +2 -2
- package/dist/calendar/locale.d.ts +7 -7
- package/dist/calendar/locale.d.ts.map +1 -1
- package/dist/calendar/locale.js +23 -23
- package/dist/canvas/shape.d.ts +89 -89
- package/dist/canvas/shape.d.ts.map +1 -1
- package/dist/canvas/shape.js +65 -53
- package/dist/command/index.d.ts +3 -3
- package/dist/customElement/index.d.ts +2 -2
- package/dist/customElement/index.js +2 -2
- package/dist/devTools/protocol.d.ts +278 -278
- package/dist/devTools/protocol.d.ts.map +1 -1
- package/dist/devTools/protocol.js +98 -92
- package/dist/devTools/schemaSummarize.d.ts.map +1 -1
- package/dist/devTools/schemaSummarize.js +24 -24
- package/dist/devTools/serialize.d.ts +1 -1
- package/dist/devTools/serialize.d.ts.map +1 -1
- package/dist/devTools/serialize.js +10 -10
- package/dist/devTools/store.d.ts.map +1 -1
- package/dist/devTools/store.js +52 -28
- package/dist/devTools/submodelPath.d.ts.map +1 -1
- package/dist/devTools/submodelPath.js +3 -3
- package/dist/devTools/summarize.d.ts +6 -6
- package/dist/devTools/summarize.d.ts.map +1 -1
- package/dist/devTools/summarize.js +13 -13
- package/dist/devTools/webSocketBridge.d.ts +3 -3
- package/dist/devTools/webSocketBridge.d.ts.map +1 -1
- package/dist/devTools/webSocketBridge.js +8 -8
- package/dist/dom/dom.d.ts +2 -0
- package/dist/dom/dom.d.ts.map +1 -1
- package/dist/dom/dom.js +47 -13
- package/dist/experimental/machine/machine.d.ts +29 -6
- package/dist/experimental/machine/machine.d.ts.map +1 -1
- package/dist/experimental/machine/machine.js +9 -8
- package/dist/experimental/server/entry.js +2 -2
- package/dist/experimental/server/serialize.js +2 -2
- package/dist/experimental/server/server.js +4 -4
- package/dist/fieldValidation/fieldValidation.d.ts +12 -12
- package/dist/fieldValidation/fieldValidation.d.ts.map +1 -1
- package/dist/fieldValidation/fieldValidation.js +9 -9
- package/dist/fieldValidation/rule.d.ts +2 -2
- package/dist/fieldValidation/rule.d.ts.map +1 -1
- package/dist/fieldValidation/rule.js +6 -6
- package/dist/file/file.d.ts +3 -3
- package/dist/file/file.d.ts.map +1 -1
- package/dist/file/file.js +3 -3
- package/dist/html/boundary.d.ts +93 -36
- package/dist/html/boundary.d.ts.map +1 -1
- package/dist/html/boundary.js +242 -75
- package/dist/html/childAttribute.d.ts +6 -4
- package/dist/html/childAttribute.d.ts.map +1 -1
- package/dist/html/childAttribute.js +7 -1
- package/dist/html/index.d.ts +31 -16
- package/dist/html/index.d.ts.map +1 -1
- package/dist/html/index.js +97 -40
- package/dist/html/lazy.d.ts +6 -6
- package/dist/html/lazy.d.ts.map +1 -1
- package/dist/html/lazy.js +37 -15
- package/dist/html/public.d.ts +1 -1
- package/dist/html/public.d.ts.map +1 -1
- package/dist/html/runtimeSingleton.d.ts +27 -6
- package/dist/html/runtimeSingleton.d.ts.map +1 -1
- package/dist/html/runtimeSingleton.js +46 -29
- package/dist/html/submodel.d.ts.map +1 -1
- package/dist/html/submodel.js +28 -39
- package/dist/http/http.d.ts +1 -1
- package/dist/http/http.js +1 -1
- package/dist/managedResource/managedResource.d.ts +5 -5
- package/dist/managedResource/managedResource.js +3 -3
- package/dist/mount/index.d.ts +92 -39
- package/dist/mount/index.d.ts.map +1 -1
- package/dist/mount/index.js +28 -8
- package/dist/mount/public.d.ts +1 -1
- package/dist/mount/public.d.ts.map +1 -1
- package/dist/mount/public.js +1 -1
- package/dist/navigation/urlRequest.d.ts +9 -9
- package/dist/navigation/urlRequest.d.ts.map +1 -1
- package/dist/navigation/urlRequest.js +2 -2
- package/dist/onUnmountModule.d.ts +19 -0
- package/dist/onUnmountModule.d.ts.map +1 -0
- package/dist/onUnmountModule.js +80 -0
- package/dist/port/port.d.ts +5 -5
- package/dist/port/port.js +5 -5
- package/dist/route/parser.d.ts +2 -2
- package/dist/route/parser.js +2 -2
- package/dist/runtime/hmrProtocol.d.ts +10 -10
- package/dist/runtime/hmrProtocol.d.ts.map +1 -1
- package/dist/runtime/hmrProtocol.js +10 -10
- package/dist/runtime/runtime.d.ts +4 -4
- package/dist/runtime/runtime.d.ts.map +1 -1
- package/dist/runtime/runtime.js +168 -51
- package/dist/schema/index.d.ts +41 -29
- package/dist/schema/index.d.ts.map +1 -1
- package/dist/schema/index.js +9 -9
- package/dist/snabbdom/init.d.ts +1 -1
- package/dist/snabbdom/init.d.ts.map +1 -1
- package/dist/snabbdom/init.js +5 -1
- package/dist/snabbdom/vnode.d.ts +1 -0
- package/dist/snabbdom/vnode.d.ts.map +1 -1
- package/dist/snabbdom/vnode.js +1 -0
- package/dist/subscription/animationFrame.d.ts +3 -3
- package/dist/subscription/animationFrame.d.ts.map +1 -1
- package/dist/subscription/animationFrame.js +2 -2
- package/dist/subscription/fromEvent.d.ts +2 -2
- package/dist/subscription/fromEvent.js +2 -2
- package/dist/subscription/subscription.d.ts +3 -3
- package/dist/subscription/subscription.js +1 -1
- package/dist/test/apps/bubbling.d.ts +6 -6
- package/dist/test/apps/bubbling.d.ts.map +1 -1
- package/dist/test/apps/bubbling.js +6 -6
- package/dist/test/apps/colorPicker.d.ts +7 -7
- package/dist/test/apps/colorPicker.d.ts.map +1 -1
- package/dist/test/apps/colorPicker.js +5 -5
- package/dist/test/apps/contextMenu.d.ts +5 -5
- package/dist/test/apps/contextMenu.d.ts.map +1 -1
- package/dist/test/apps/contextMenu.js +4 -4
- package/dist/test/apps/counter.d.ts +8 -8
- package/dist/test/apps/counter.d.ts.map +1 -1
- package/dist/test/apps/counter.js +8 -8
- package/dist/test/apps/crashOnRender.d.ts +18 -18
- package/dist/test/apps/crashOnRender.d.ts.map +1 -1
- package/dist/test/apps/crashOnRender.js +11 -11
- package/dist/test/apps/drafts.d.ts +9 -9
- package/dist/test/apps/drafts.d.ts.map +1 -1
- package/dist/test/apps/drafts.js +6 -6
- package/dist/test/apps/feedSocket.d.ts +6 -6
- package/dist/test/apps/feedSocket.d.ts.map +1 -1
- package/dist/test/apps/feedSocket.js +8 -8
- package/dist/test/apps/fileUpload.d.ts +2 -2
- package/dist/test/apps/fileUpload.d.ts.map +1 -1
- package/dist/test/apps/fileUpload.js +2 -2
- package/dist/test/apps/focusBoundary.d.ts +3 -3
- package/dist/test/apps/focusBoundary.d.ts.map +1 -1
- package/dist/test/apps/focusBoundary.js +3 -3
- package/dist/test/apps/formChild.d.ts +11 -11
- package/dist/test/apps/formChild.d.ts.map +1 -1
- package/dist/test/apps/formChild.js +13 -12
- package/dist/test/apps/interactions.d.ts +8 -8
- package/dist/test/apps/interactions.d.ts.map +1 -1
- package/dist/test/apps/interactions.js +8 -8
- package/dist/test/apps/keypress.d.ts +6 -6
- package/dist/test/apps/keypress.d.ts.map +1 -1
- package/dist/test/apps/keypress.js +6 -6
- package/dist/test/apps/login.d.ts +11 -11
- package/dist/test/apps/login.d.ts.map +1 -1
- package/dist/test/apps/login.js +15 -15
- package/dist/test/apps/logoutButton.d.ts +3 -3
- package/dist/test/apps/logoutButton.d.ts.map +1 -1
- package/dist/test/apps/logoutButton.js +2 -2
- package/dist/test/apps/mountPanel.d.ts +9 -9
- package/dist/test/apps/mountPanel.d.ts.map +1 -1
- package/dist/test/apps/mountPanel.js +9 -9
- package/dist/test/apps/multiRole.d.ts +3 -3
- package/dist/test/apps/multiRole.d.ts.map +1 -1
- package/dist/test/apps/multiRole.js +2 -2
- package/dist/test/apps/pointer.d.ts +7 -7
- package/dist/test/apps/pointer.d.ts.map +1 -1
- package/dist/test/apps/pointer.js +7 -7
- package/dist/test/apps/resumeUpload.d.ts +8 -8
- package/dist/test/apps/resumeUpload.d.ts.map +1 -1
- package/dist/test/apps/resumeUpload.js +7 -7
- package/dist/test/apps/scorePanel.d.ts +3 -3
- package/dist/test/apps/scorePanel.d.ts.map +1 -1
- package/dist/test/apps/scorePanel.js +2 -2
- package/dist/test/apps/selectiveKeys.d.ts +3 -3
- package/dist/test/apps/selectiveKeys.d.ts.map +1 -1
- package/dist/test/apps/selectiveKeys.js +3 -3
- package/dist/test/apps/uploads.d.ts +18 -18
- package/dist/test/apps/uploads.d.ts.map +1 -1
- package/dist/test/apps/uploads.js +13 -13
- package/dist/test/matchers.d.ts.map +1 -1
- package/dist/test/matchers.js +4 -4
- package/dist/test/query.d.ts.map +1 -1
- package/dist/test/query.js +28 -28
- package/dist/test/scene.d.ts +37 -8
- package/dist/test/scene.d.ts.map +1 -1
- package/dist/test/scene.js +58 -15
- package/dist/test/story.d.ts +35 -8
- package/dist/test/story.d.ts.map +1 -1
- package/dist/test/story.js +44 -22
- package/dist/update/update.d.ts +17 -20
- package/dist/update/update.d.ts.map +1 -1
- package/dist/url/index.d.ts +8 -8
- package/dist/url/index.d.ts.map +1 -1
- package/dist/url/index.js +19 -19
- package/dist/vdom.d.ts +3 -2
- package/dist/vdom.d.ts.map +1 -1
- package/dist/vdom.js +16 -6
- package/package.json +1 -1
package/dist/html/boundary.js
CHANGED
|
@@ -13,8 +13,12 @@ const splitBoundary = (boundaryId) => boundaryId === ROOT_BOUNDARY ? [] : bounda
|
|
|
13
13
|
export const createBoundaryRegistry = () => ({
|
|
14
14
|
wraps: new Map(),
|
|
15
15
|
boundaryDispatches: new WeakMap(),
|
|
16
|
+
mountWraps: new WeakMap(),
|
|
17
|
+
mountWrapOwners: new Map(),
|
|
16
18
|
seenThisRender: new Map(),
|
|
17
19
|
lazyTrackingStack: [],
|
|
20
|
+
boundaryWrapTransactionLog: [],
|
|
21
|
+
activeBoundaryWrapTransaction: undefined,
|
|
18
22
|
dedupeSeen: new Set(),
|
|
19
23
|
});
|
|
20
24
|
const captureCallSite = () => {
|
|
@@ -22,10 +26,14 @@ const captureCallSite = () => {
|
|
|
22
26
|
const lines = stack.split('\n');
|
|
23
27
|
for (const line of lines) {
|
|
24
28
|
const trimmed = line.trim();
|
|
29
|
+
const isLazyInternalFrame = /[/\\]html[/\\]lazy\.[cm]?[jt]s/.test(trimmed);
|
|
25
30
|
if (trimmed.length === 0 ||
|
|
26
31
|
trimmed.startsWith('Error') ||
|
|
27
32
|
trimmed.includes('captureCallSite') ||
|
|
33
|
+
trimmed.includes('assertBoundaryNotSeen') ||
|
|
28
34
|
trimmed.includes('registerBoundaryWrap') ||
|
|
35
|
+
trimmed.includes('restoreBoundaryWrapsForLazyHit') ||
|
|
36
|
+
isLazyInternalFrame ||
|
|
29
37
|
trimmed.includes('at submodel')) {
|
|
30
38
|
continue;
|
|
31
39
|
}
|
|
@@ -33,7 +41,7 @@ const captureCallSite = () => {
|
|
|
33
41
|
}
|
|
34
42
|
return '(call site unavailable)';
|
|
35
43
|
};
|
|
36
|
-
|
|
44
|
+
const assertBoundaryNotSeen = (registry, boundaryId) => {
|
|
37
45
|
const existingCallSite = registry.seenThisRender.get(boundaryId);
|
|
38
46
|
if (existingCallSite !== undefined) {
|
|
39
47
|
const ownSlotId = boundaryId.includes(BOUNDARY_SEPARATOR)
|
|
@@ -49,16 +57,47 @@ export const registerBoundaryWrap = (registry, boundaryId, descriptor) => {
|
|
|
49
57
|
`needs its own id (e.g. "desktop-foo", "mobile-foo"). For lists, use a stable ` +
|
|
50
58
|
`per-item identifier.`);
|
|
51
59
|
}
|
|
60
|
+
};
|
|
61
|
+
export const registerBoundaryWrap = (registry, boundaryId, descriptor, mountOuterDispatch) => {
|
|
62
|
+
assertBoundaryNotSeen(registry, boundaryId);
|
|
52
63
|
// NOTE: compute the call site before writing either map. If
|
|
53
64
|
// captureCallSite throws (e.g. hardened runtime without
|
|
54
65
|
// Error.stack), neither map is mutated, so a later registration
|
|
55
66
|
// with the same slotId throws the duplicate error correctly instead
|
|
56
67
|
// of silently overwriting after a half-finished prior write.
|
|
57
68
|
const callSite = captureCallSite();
|
|
69
|
+
writeBoundaryWrap(registry, boundaryId, descriptor, mountOuterDispatch, callSite);
|
|
70
|
+
};
|
|
71
|
+
const writeBoundaryWrap = (registry, boundaryId, descriptor, mountOuterDispatch, callSite) => {
|
|
72
|
+
const previousDescriptor = registry.wraps.get(boundaryId);
|
|
73
|
+
const existingMountWraps = registry.mountWraps.get(mountOuterDispatch);
|
|
74
|
+
const previousMountDescriptor = existingMountWraps?.get(boundaryId);
|
|
75
|
+
if (registry.activeBoundaryWrapTransaction !== undefined) {
|
|
76
|
+
registry.boundaryWrapTransactionLog.push({
|
|
77
|
+
_tag: 'Registration',
|
|
78
|
+
boundaryId,
|
|
79
|
+
descriptor,
|
|
80
|
+
mountOuterDispatch,
|
|
81
|
+
previousDescriptor,
|
|
82
|
+
previousMountDescriptor,
|
|
83
|
+
});
|
|
84
|
+
}
|
|
58
85
|
registry.wraps.set(boundaryId, descriptor);
|
|
86
|
+
let mountWraps = existingMountWraps;
|
|
87
|
+
if (mountWraps === undefined) {
|
|
88
|
+
mountWraps = new Map();
|
|
89
|
+
registry.mountWraps.set(mountOuterDispatch, mountWraps);
|
|
90
|
+
}
|
|
91
|
+
mountWraps.set(boundaryId, descriptor);
|
|
92
|
+
let mountWrapOwners = registry.mountWrapOwners.get(boundaryId);
|
|
93
|
+
if (mountWrapOwners === undefined) {
|
|
94
|
+
mountWrapOwners = new Set();
|
|
95
|
+
registry.mountWrapOwners.set(boundaryId, mountWrapOwners);
|
|
96
|
+
}
|
|
97
|
+
mountWrapOwners.add(mountOuterDispatch);
|
|
59
98
|
registry.seenThisRender.set(boundaryId, callSite);
|
|
60
99
|
for (const tracked of registry.lazyTrackingStack) {
|
|
61
|
-
tracked.set(boundaryId, callSite);
|
|
100
|
+
tracked.set(boundaryId, { callSite, descriptor, mountOuterDispatch });
|
|
62
101
|
}
|
|
63
102
|
};
|
|
64
103
|
/** Starts capturing boundary registrations on a fresh set pushed onto
|
|
@@ -81,28 +120,37 @@ export const endLazyTracking = (registry) => {
|
|
|
81
120
|
}
|
|
82
121
|
registry.lazyTrackingStack.pop();
|
|
83
122
|
};
|
|
84
|
-
/**
|
|
85
|
-
* into `seenThisRender` so the duplicate-slotId guard sees
|
|
86
|
-
* forwards them into
|
|
87
|
-
* wrapping this cache hit captures the
|
|
123
|
+
/** Restores boundary registrations captured during a previous lazy run and
|
|
124
|
+
* replays their ids into `seenThisRender` so the duplicate-slotId guard sees
|
|
125
|
+
* them. Also forwards them into active tracking maps so an outer lazy
|
|
126
|
+
* wrapping this cache hit captures the registrations in its own snapshot.
|
|
88
127
|
*
|
|
89
|
-
*
|
|
90
|
-
*
|
|
91
|
-
*
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
128
|
+
* A registration that still occupies both lookup tables needs only its seen
|
|
129
|
+
* marker restored. A registration evicted when the cached VNode left the DOM
|
|
130
|
+
* is written back transactionally, so a surrounding Submodel render that
|
|
131
|
+
* later fails can still roll the cache hit back. */
|
|
132
|
+
export const restoreBoundaryWrapsForLazyHit = (registry, trackedBoundaries) => {
|
|
133
|
+
for (const [boundaryId, trackedBoundary] of trackedBoundaries) {
|
|
134
|
+
const { callSite, descriptor, mountOuterDispatch } = trackedBoundary;
|
|
135
|
+
assertBoundaryNotSeen(registry, boundaryId);
|
|
136
|
+
registry.seenThisRender.set(boundaryId, callSite);
|
|
97
137
|
for (const outerTracked of registry.lazyTrackingStack) {
|
|
98
138
|
if (!outerTracked.has(boundaryId)) {
|
|
99
|
-
outerTracked.set(boundaryId,
|
|
139
|
+
outerTracked.set(boundaryId, trackedBoundary);
|
|
100
140
|
}
|
|
101
141
|
}
|
|
142
|
+
if (registry.wraps.get(boundaryId) === descriptor &&
|
|
143
|
+
registry.mountWraps.get(mountOuterDispatch)?.get(boundaryId) ===
|
|
144
|
+
descriptor) {
|
|
145
|
+
continue;
|
|
146
|
+
}
|
|
147
|
+
writeBoundaryWrap(registry, boundaryId, descriptor, mountOuterDispatch, callSite);
|
|
102
148
|
}
|
|
103
149
|
};
|
|
104
|
-
/** Removes a boundary's wrap
|
|
105
|
-
*
|
|
150
|
+
/** Removes a boundary's wrap when it still matches the descriptor owned by the
|
|
151
|
+
* VNode being destroyed. A replacement registered earlier in the same patch
|
|
152
|
+
* is left intact. Called by `h.submodel`'s destroy hook when the corresponding
|
|
153
|
+
* VNode leaves the DOM.
|
|
106
154
|
*
|
|
107
155
|
* Does not touch `boundaryDispatches`: it is a WeakMap keyed by
|
|
108
156
|
* outerDispatch, so per-outerDispatch inner Maps become unreachable and
|
|
@@ -111,8 +159,108 @@ export const markSeenForLazyHit = (registry, trackedIds) => {
|
|
|
111
159
|
* when it cannot find an ancestor wrap, which surfaces a clear error
|
|
112
160
|
* rather than letting events from a destroyed boundary silently
|
|
113
161
|
* misroute. */
|
|
114
|
-
export const deregisterBoundaryWrap = (registry, boundaryId) => {
|
|
115
|
-
registry.wraps.
|
|
162
|
+
export const deregisterBoundaryWrap = (registry, boundaryId, descriptor, mountOuterDispatch) => {
|
|
163
|
+
if (registry.wraps.get(boundaryId) === descriptor) {
|
|
164
|
+
registry.wraps.delete(boundaryId);
|
|
165
|
+
const mountWrapOwners = registry.mountWrapOwners.get(boundaryId);
|
|
166
|
+
if (mountWrapOwners !== undefined) {
|
|
167
|
+
for (const owner of mountWrapOwners) {
|
|
168
|
+
registry.mountWraps.get(owner)?.delete(boundaryId);
|
|
169
|
+
}
|
|
170
|
+
registry.mountWrapOwners.delete(boundaryId);
|
|
171
|
+
}
|
|
172
|
+
return;
|
|
173
|
+
}
|
|
174
|
+
const mountWraps = registry.mountWraps.get(mountOuterDispatch);
|
|
175
|
+
if (mountWraps?.get(boundaryId) === descriptor) {
|
|
176
|
+
mountWraps.delete(boundaryId);
|
|
177
|
+
const mountWrapOwners = registry.mountWrapOwners.get(boundaryId);
|
|
178
|
+
mountWrapOwners?.delete(mountOuterDispatch);
|
|
179
|
+
if (mountWrapOwners?.size === 0) {
|
|
180
|
+
registry.mountWrapOwners.delete(boundaryId);
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
};
|
|
184
|
+
/** Restores the registry entries replaced by one boundary registration that
|
|
185
|
+
* did not produce a VNode. Used when a Submodel view throws or returns
|
|
186
|
+
* `null`, where no destroy hook will run and cleanup must undo only that
|
|
187
|
+
* render owner's write without evicting descriptors retained by the
|
|
188
|
+
* currently rendered tree. */
|
|
189
|
+
const rollbackBoundaryWrapRegistration = (registry, boundaryId, descriptor, mountOuterDispatch, previousDescriptor, previousMountDescriptor) => {
|
|
190
|
+
if (registry.wraps.get(boundaryId) === descriptor) {
|
|
191
|
+
if (previousDescriptor === undefined) {
|
|
192
|
+
registry.wraps.delete(boundaryId);
|
|
193
|
+
}
|
|
194
|
+
else {
|
|
195
|
+
registry.wraps.set(boundaryId, previousDescriptor);
|
|
196
|
+
}
|
|
197
|
+
}
|
|
198
|
+
const mountWraps = registry.mountWraps.get(mountOuterDispatch);
|
|
199
|
+
if (mountWraps?.get(boundaryId) !== descriptor) {
|
|
200
|
+
return;
|
|
201
|
+
}
|
|
202
|
+
if (previousMountDescriptor === undefined) {
|
|
203
|
+
mountWraps.delete(boundaryId);
|
|
204
|
+
const mountWrapOwners = registry.mountWrapOwners.get(boundaryId);
|
|
205
|
+
mountWrapOwners?.delete(mountOuterDispatch);
|
|
206
|
+
if (mountWrapOwners?.size === 0) {
|
|
207
|
+
registry.mountWrapOwners.delete(boundaryId);
|
|
208
|
+
}
|
|
209
|
+
}
|
|
210
|
+
else {
|
|
211
|
+
mountWraps.set(boundaryId, previousMountDescriptor);
|
|
212
|
+
}
|
|
213
|
+
};
|
|
214
|
+
/** Starts a nested boundary-registration transaction for one Submodel view. */
|
|
215
|
+
export const beginBoundaryWrapTransaction = (registry) => {
|
|
216
|
+
const transaction = {
|
|
217
|
+
parent: registry.activeBoundaryWrapTransaction,
|
|
218
|
+
startIndex: registry.boundaryWrapTransactionLog.length,
|
|
219
|
+
};
|
|
220
|
+
registry.activeBoundaryWrapTransaction = transaction;
|
|
221
|
+
return transaction;
|
|
222
|
+
};
|
|
223
|
+
/** Commits a Submodel view's boundary registrations. Nested registrations stay
|
|
224
|
+
* in the parent transaction until that parent also produces a VNode. */
|
|
225
|
+
export const commitBoundaryWrapTransaction = (registry, transaction) => {
|
|
226
|
+
if (registry.activeBoundaryWrapTransaction !== transaction) {
|
|
227
|
+
throw new Error('Foldkit: boundary wrap transactions must commit in order.');
|
|
228
|
+
}
|
|
229
|
+
registry.activeBoundaryWrapTransaction = transaction.parent;
|
|
230
|
+
if (transaction.parent === undefined) {
|
|
231
|
+
registry.boundaryWrapTransactionLog.length = 0;
|
|
232
|
+
}
|
|
233
|
+
};
|
|
234
|
+
/** Registers an internal cache restoration with the active Submodel boundary
|
|
235
|
+
* transaction. Calls outside a Submodel view need no rollback and are ignored. */
|
|
236
|
+
export const registerBoundaryWrapTransactionRollback = (registry, value, restore) => {
|
|
237
|
+
if (registry.activeBoundaryWrapTransaction !== undefined) {
|
|
238
|
+
registry.boundaryWrapTransactionLog.push({
|
|
239
|
+
_tag: 'Rollback',
|
|
240
|
+
rollback: () => {
|
|
241
|
+
restore(value);
|
|
242
|
+
},
|
|
243
|
+
});
|
|
244
|
+
}
|
|
245
|
+
};
|
|
246
|
+
/** Restores every boundary registration performed since a Submodel view began,
|
|
247
|
+
* including registrations from nested Submodels whose VNodes never reached
|
|
248
|
+
* snabbdom. */
|
|
249
|
+
export const rollbackBoundaryWrapTransaction = (registry, transaction) => {
|
|
250
|
+
if (registry.activeBoundaryWrapTransaction !== transaction) {
|
|
251
|
+
throw new Error('Foldkit: boundary wrap transactions must roll back in order.');
|
|
252
|
+
}
|
|
253
|
+
const entries = registry.boundaryWrapTransactionLog.splice(transaction.startIndex);
|
|
254
|
+
entries.reverse();
|
|
255
|
+
for (const entry of entries) {
|
|
256
|
+
if (entry._tag === 'Registration') {
|
|
257
|
+
rollbackBoundaryWrapRegistration(registry, entry.boundaryId, entry.descriptor, entry.mountOuterDispatch, entry.previousDescriptor, entry.previousMountDescriptor);
|
|
258
|
+
}
|
|
259
|
+
else {
|
|
260
|
+
entry.rollback();
|
|
261
|
+
}
|
|
262
|
+
}
|
|
263
|
+
registry.activeBoundaryWrapTransaction = transaction.parent;
|
|
116
264
|
};
|
|
117
265
|
// NOTE: reading `_tag` can itself throw, through a getter or a Proxy trap. This
|
|
118
266
|
// runs while reporting another failure, so an escape here would replace the
|
|
@@ -160,6 +308,55 @@ const liftAcrossBoundary = (descriptor, boundaryId, message) => {
|
|
|
160
308
|
`parent's boundary.`, { cause });
|
|
161
309
|
}
|
|
162
310
|
};
|
|
311
|
+
const missingBoundaryWrapError = (mode, ancestorBoundary, boundaryId) => {
|
|
312
|
+
if (mode === 'Dispatch') {
|
|
313
|
+
return new Error(`Foldkit: dispatchAcrossBoundary missing wrap for ancestor ` +
|
|
314
|
+
`"${ancestorBoundary}" of boundary "${boundaryId}". The Submodel's ` +
|
|
315
|
+
`wrap was absent from the registry at dispatch time. A known cause: ` +
|
|
316
|
+
`a slot callback (an h.submodel \`viewInputs\` function value) was ` +
|
|
317
|
+
`invoked from a deferred context (setTimeout, Promise.then, a ` +
|
|
318
|
+
`stored callback) after the parent Submodel unmounted. Slot ` +
|
|
319
|
+
`callbacks must be invoked synchronously inside the render that ` +
|
|
320
|
+
`created them. It can also mean foldkit was loaded as more than ` +
|
|
321
|
+
`one instance (a bundler split foldkit and @foldkit/ui), so the ` +
|
|
322
|
+
`wrap was registered in one copy and read from another.`);
|
|
323
|
+
}
|
|
324
|
+
else if (mode === 'OnUnmount') {
|
|
325
|
+
return new Error(`Foldkit: resolveBoundaryDispatchThunk missing wrap for ancestor ` +
|
|
326
|
+
`"${ancestorBoundary}" of boundary "${boundaryId}" while resolving an ` +
|
|
327
|
+
`OnUnmount message. The Submodel's wrap was absent from the registry ` +
|
|
328
|
+
`at resolve time, which should not happen during a live render.`);
|
|
329
|
+
}
|
|
330
|
+
else if (mode === 'Scene') {
|
|
331
|
+
return new Error(`Foldkit: boundaryMappers missing wrap for ancestor ` +
|
|
332
|
+
`"${ancestorBoundary}" of boundary "${boundaryId}" while snapshotting ` +
|
|
333
|
+
`an OnMount lift. The Submodel's wrap was absent from the registry ` +
|
|
334
|
+
`during render, which should not happen for a live boundary.`);
|
|
335
|
+
}
|
|
336
|
+
else {
|
|
337
|
+
return new Error(`Foldkit: Mount dispatch missing wrap for ancestor ` +
|
|
338
|
+
`"${ancestorBoundary}" of boundary "${boundaryId}". The ` +
|
|
339
|
+
`Submodel's wrap was absent from the Mount's render owner.`);
|
|
340
|
+
}
|
|
341
|
+
};
|
|
342
|
+
const foldBoundaryChain = (wraps, boundaryId, mode, initial, fold) => {
|
|
343
|
+
let result = initial;
|
|
344
|
+
const parts = splitBoundary(boundaryId);
|
|
345
|
+
for (let depth = parts.length; depth > 0; depth--) {
|
|
346
|
+
const ancestorBoundary = parts.slice(0, depth).join(BOUNDARY_SEPARATOR);
|
|
347
|
+
const descriptor = wraps.get(ancestorBoundary);
|
|
348
|
+
if (descriptor === undefined) {
|
|
349
|
+
throw missingBoundaryWrapError(mode, ancestorBoundary, boundaryId);
|
|
350
|
+
}
|
|
351
|
+
result = fold(result, descriptor, ancestorBoundary);
|
|
352
|
+
}
|
|
353
|
+
return result;
|
|
354
|
+
};
|
|
355
|
+
const liftBoundaryMessage = (message, descriptor, ancestorBoundary) => liftAcrossBoundary(descriptor, ancestorBoundary, message);
|
|
356
|
+
const collectBoundaryMapper = (mappers, descriptor) => {
|
|
357
|
+
mappers.push(descriptor.toParentMessage);
|
|
358
|
+
return mappers;
|
|
359
|
+
};
|
|
163
360
|
/** Applies the wrapping chain for `boundaryId` from innermost to
|
|
164
361
|
* outermost, then dispatches the fully-wrapped message via
|
|
165
362
|
* `outerDispatch`. Called at event-fire time by the dispatcher closure
|
|
@@ -175,25 +372,7 @@ const liftAcrossBoundary = (descriptor, boundaryId, message) => {
|
|
|
175
372
|
* wraps would produce a malformed Message that the outermost
|
|
176
373
|
* `Match.tagsExhaustive` would then crash on with no useful trace. */
|
|
177
374
|
const dispatchAcrossBoundary = (registry, outerDispatch, boundaryId, message) => {
|
|
178
|
-
|
|
179
|
-
const parts = splitBoundary(boundaryId);
|
|
180
|
-
for (let depth = parts.length; depth > 0; depth--) {
|
|
181
|
-
const ancestorBoundary = parts.slice(0, depth).join(BOUNDARY_SEPARATOR);
|
|
182
|
-
const descriptor = registry.wraps.get(ancestorBoundary);
|
|
183
|
-
if (descriptor === undefined) {
|
|
184
|
-
throw new Error(`Foldkit: dispatchAcrossBoundary missing wrap for ancestor ` +
|
|
185
|
-
`"${ancestorBoundary}" of boundary "${boundaryId}". The Submodel's ` +
|
|
186
|
-
`wrap was absent from the registry at dispatch time. A known cause: ` +
|
|
187
|
-
`a slot callback (an h.submodel \`viewInputs\` function value) was ` +
|
|
188
|
-
`invoked from a deferred context (setTimeout, Promise.then, a ` +
|
|
189
|
-
`stored callback) after the parent Submodel unmounted. Slot ` +
|
|
190
|
-
`callbacks must be invoked synchronously inside the render that ` +
|
|
191
|
-
`created them. It can also mean foldkit was loaded as more than ` +
|
|
192
|
-
`one instance (a bundler split foldkit and @foldkit/ui), so the ` +
|
|
193
|
-
`wrap was registered in one copy and read from another.`);
|
|
194
|
-
}
|
|
195
|
-
wrapped = liftAcrossBoundary(descriptor, ancestorBoundary, wrapped);
|
|
196
|
-
}
|
|
375
|
+
const wrapped = foldBoundaryChain(registry.wraps, boundaryId, 'Dispatch', message, liftBoundaryMessage);
|
|
197
376
|
outerDispatch(wrapped);
|
|
198
377
|
};
|
|
199
378
|
/** Resolves a message through `boundaryId`'s wrapping chain immediately,
|
|
@@ -213,20 +392,7 @@ export const resolveBoundaryDispatchThunk = (registry, outerDispatch, boundaryId
|
|
|
213
392
|
if (boundaryId === ROOT_BOUNDARY) {
|
|
214
393
|
return () => outerDispatch(message);
|
|
215
394
|
}
|
|
216
|
-
|
|
217
|
-
const parts = splitBoundary(boundaryId);
|
|
218
|
-
for (let depth = parts.length; depth > 0; depth--) {
|
|
219
|
-
const ancestorBoundary = parts.slice(0, depth).join(BOUNDARY_SEPARATOR);
|
|
220
|
-
const descriptor = registry.wraps.get(ancestorBoundary);
|
|
221
|
-
if (descriptor === undefined) {
|
|
222
|
-
throw new Error(`Foldkit: resolveBoundaryDispatchThunk missing wrap for ancestor ` +
|
|
223
|
-
`"${ancestorBoundary}" of boundary "${boundaryId}" while resolving an ` +
|
|
224
|
-
`OnUnmount message. The Submodel's wrap was absent from the registry ` +
|
|
225
|
-
`at resolve time, which should not happen during a live render.`);
|
|
226
|
-
}
|
|
227
|
-
wrapped = liftAcrossBoundary(descriptor, ancestorBoundary, wrapped);
|
|
228
|
-
}
|
|
229
|
-
const rootMessage = wrapped;
|
|
395
|
+
const rootMessage = foldBoundaryChain(registry.wraps, boundaryId, 'OnUnmount', message, liftBoundaryMessage);
|
|
230
396
|
return () => outerDispatch(rootMessage);
|
|
231
397
|
};
|
|
232
398
|
/** Collects the `toParentMessage` wrapping chain for `boundaryId`, innermost
|
|
@@ -238,20 +404,7 @@ export const resolveBoundaryDispatchThunk = (registry, outerDispatch, boundaryId
|
|
|
238
404
|
* it when the mount is resolved. Throws when an ancestor wrap is missing
|
|
239
405
|
* (boundary alive at call time), matching {@link dispatchAcrossBoundary}. */
|
|
240
406
|
export const boundaryMappers = (registry, boundaryId) => {
|
|
241
|
-
|
|
242
|
-
const mappers = [];
|
|
243
|
-
for (let depth = parts.length; depth > 0; depth--) {
|
|
244
|
-
const ancestorBoundary = parts.slice(0, depth).join(BOUNDARY_SEPARATOR);
|
|
245
|
-
const descriptor = registry.wraps.get(ancestorBoundary);
|
|
246
|
-
if (descriptor === undefined) {
|
|
247
|
-
throw new Error(`Foldkit: boundaryMappers missing wrap for ancestor ` +
|
|
248
|
-
`"${ancestorBoundary}" of boundary "${boundaryId}" while snapshotting ` +
|
|
249
|
-
`an OnMount lift. The Submodel's wrap was absent from the registry ` +
|
|
250
|
-
`during render, which should not happen for a live boundary.`);
|
|
251
|
-
}
|
|
252
|
-
mappers.push(descriptor.toParentMessage);
|
|
253
|
-
}
|
|
254
|
-
return mappers;
|
|
407
|
+
return foldBoundaryChain(registry.wraps, boundaryId, 'Scene', [], collectBoundaryMapper);
|
|
255
408
|
};
|
|
256
409
|
export const getOrCreateBoundaryDispatch = (registry, outerDispatch, boundaryId) => {
|
|
257
410
|
if (boundaryId === ROOT_BOUNDARY) {
|
|
@@ -272,17 +425,31 @@ export const getOrCreateBoundaryDispatch = (registry, outerDispatch, boundaryId)
|
|
|
272
425
|
perOuterDispatch.set(boundaryId, dispatch);
|
|
273
426
|
return dispatch;
|
|
274
427
|
};
|
|
428
|
+
/** Returns a dispatcher for a Mount acquired inside `boundaryId`.
|
|
429
|
+
* The root dispatcher identifies the render owner: live and replay renders
|
|
430
|
+
* therefore consult separate wrap tables. Within that owner, the dispatcher
|
|
431
|
+
* resolves the current wrapping chain at emission time so a surviving Mount
|
|
432
|
+
* follows later live `toParentMessage` closures just like an event handler. */
|
|
433
|
+
export const resolveMountBoundaryDispatch = (registry, mountOuterDispatch, boundaryId) => {
|
|
434
|
+
if (boundaryId === ROOT_BOUNDARY) {
|
|
435
|
+
return mountOuterDispatch;
|
|
436
|
+
}
|
|
437
|
+
const dispatch = message => {
|
|
438
|
+
const mountWraps = registry.mountWraps.get(mountOuterDispatch);
|
|
439
|
+
if (mountWraps === undefined) {
|
|
440
|
+
throw new Error(`Foldkit: Mount dispatch missing wraps for boundary "${boundaryId}". ` +
|
|
441
|
+
`The Mount's render owner has no registered Submodel boundaries.`);
|
|
442
|
+
}
|
|
443
|
+
const wrapped = foldBoundaryChain(mountWraps, boundaryId, 'Mount', message, liftBoundaryMessage);
|
|
444
|
+
mountOuterDispatch(wrapped);
|
|
445
|
+
};
|
|
446
|
+
return dispatch;
|
|
447
|
+
};
|
|
275
448
|
/** Called at the start of each top-level render. Clears the
|
|
276
449
|
* per-render duplicate-slotId tracking map so siblings inside the
|
|
277
|
-
* same parent boundary can be re-validated. Does
|
|
278
|
-
* or
|
|
279
|
-
*
|
|
280
|
-
*
|
|
281
|
-
* Clear `seenThisRender` only here, at the start of a cycle, never
|
|
282
|
-
* between the view and patch phases. The Submodel destroy hook reads
|
|
283
|
-
* it during patch to tell a same-cycle remount (a keyed root whose
|
|
284
|
-
* key changed) from a true unmount; clearing it mid-cycle would
|
|
285
|
-
* resurrect the `dispatchAcrossBoundary missing wrap` crash. */
|
|
450
|
+
* same parent boundary can be re-validated. Does not touch the wrap
|
|
451
|
+
* or dispatcher tables. Those persist across renders and are evicted
|
|
452
|
+
* by VNode destroy hooks instead. */
|
|
286
453
|
export const beginRender = (registry) => {
|
|
287
454
|
registry.seenThisRender.clear();
|
|
288
455
|
registry.dedupeSeen.clear();
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { type DispatchSync } from './runtimeSingleton.js';
|
|
1
|
+
import { type DispatchSync, type MountDispatchResolver } from './runtimeSingleton.js';
|
|
2
2
|
declare const BRAND = "__childAttribute";
|
|
3
3
|
/** An attribute carrying a handler that dispatches through a Submodel
|
|
4
4
|
* boundary's wrapping chain. Published by Submodels (typically Foldkit's
|
|
@@ -10,9 +10,10 @@ declare const BRAND = "__childAttribute";
|
|
|
10
10
|
* `resolveUnmount` snapshots the boundary's wrapping chain at the time the
|
|
11
11
|
* group was published (child boundary alive) so `OnUnmount` can dispatch a
|
|
12
12
|
* root message from a destroy hook that fires after the boundary has been
|
|
13
|
-
* torn down. `boundaryMappers` snapshots the
|
|
14
|
-
*
|
|
15
|
-
*
|
|
13
|
+
* torn down. `boundaryMappers` snapshots the `toParentMessage` lifts
|
|
14
|
+
* (innermost first) for the Scene test harness. Groups containing `OnMount`
|
|
15
|
+
* also carry `resolveMountDispatch`, which binds the Mount to the acquiring
|
|
16
|
+
* render's dispatch owner while following that owner's current live wrappers.
|
|
16
17
|
*
|
|
17
18
|
* Created via {@link childAttributes}. Element constructors accept
|
|
18
19
|
* `ChildAttribute` alongside `Attribute<Message>` in their attribute
|
|
@@ -23,6 +24,7 @@ export type ChildAttribute = Readonly<{
|
|
|
23
24
|
readonly dispatch: DispatchSync;
|
|
24
25
|
readonly resolveUnmount: (message: unknown) => () => void;
|
|
25
26
|
readonly boundaryMappers: ReadonlyArray<(message: unknown) => unknown>;
|
|
27
|
+
readonly resolveMountDispatch?: MountDispatchResolver;
|
|
26
28
|
}>;
|
|
27
29
|
export declare const isChildAttribute: (value: unknown) => value is ChildAttribute;
|
|
28
30
|
/** Captures the current boundary's dispatcher and wraps each attribute
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"childAttribute.d.ts","sourceRoot":"","sources":["../../src/html/childAttribute.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"childAttribute.d.ts","sourceRoot":"","sources":["../../src/html/childAttribute.ts"],"names":[],"mappings":"AAEA,OAAO,EACL,KAAK,YAAY,EACjB,KAAK,qBAAqB,EAK3B,MAAM,uBAAuB,CAAA;AAE9B,QAAA,MAAM,KAAK,qBAAqB,CAAA;AAKhC;;;;;;;;;;;;;;;;;cAiBc;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;IAC/B,QAAQ,CAAC,cAAc,EAAE,CAAC,OAAO,EAAE,OAAO,KAAK,MAAM,IAAI,CAAA;IACzD,QAAQ,CAAC,eAAe,EAAE,aAAa,CAAC,CAAC,OAAO,EAAE,OAAO,KAAK,OAAO,CAAC,CAAA;IACtE,QAAQ,CAAC,oBAAoB,CAAC,EAAE,qBAAqB,CAAA;CACtD,CAAC,CAAA;AAEF,eAAO,MAAM,gBAAgB,UAAW,OAAO,KAAG,KAAK,IAAI,cACI,CAAA;AAE/D;;;;;;;;;;;;;;;;;;;;;;oCAsBoC;AACpC,eAAO,MAAM,eAAe,GAAI,SAAS,cAC3B,aAAa,CAAC,SAAS,CAAC,KACnC,aAAa,CAAC,cAAc,CAe9B,CAAA"}
|
|
@@ -1,5 +1,7 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { Predicate } from 'effect';
|
|
2
|
+
import { requireBoundaryMappers, requireDispatch, requireMountDispatchResolver, requireUnmountResolver, } from './runtimeSingleton.js';
|
|
2
3
|
const BRAND = '__childAttribute';
|
|
4
|
+
const isOnMountAttribute = (attribute) => Predicate.isTagged(attribute, 'OnMount');
|
|
3
5
|
export const isChildAttribute = (value) => typeof value === 'object' && value !== null && BRAND in value;
|
|
4
6
|
/** Captures the current boundary's dispatcher and wraps each attribute
|
|
5
7
|
* so handlers inside it route through that boundary's wrapping chain at
|
|
@@ -28,11 +30,15 @@ export const childAttributes = (attributes) => {
|
|
|
28
30
|
const dispatch = requireDispatch();
|
|
29
31
|
const resolveUnmount = requireUnmountResolver();
|
|
30
32
|
const boundaryMappers = requireBoundaryMappers();
|
|
33
|
+
const resolveMountDispatch = attributes.some(isOnMountAttribute)
|
|
34
|
+
? requireMountDispatchResolver()
|
|
35
|
+
: undefined;
|
|
31
36
|
return attributes.map(attribute => ({
|
|
32
37
|
[BRAND]: true,
|
|
33
38
|
attribute,
|
|
34
39
|
dispatch,
|
|
35
40
|
resolveUnmount,
|
|
36
41
|
boundaryMappers,
|
|
42
|
+
...(resolveMountDispatch !== undefined && { resolveMountDispatch }),
|
|
37
43
|
}));
|
|
38
44
|
};
|
package/dist/html/index.d.ts
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
|
-
import { Data, Option, Schema
|
|
1
|
+
import { Data, Option, Schema } from 'effect';
|
|
2
2
|
import type { File } from '../file/index.js';
|
|
3
3
|
import type { MountAction } from '../mount/index.js';
|
|
4
|
+
import { beginReplayUnmountRender, endReplayUnmountRender, flushReplayUnmountsAfterPatchFailure } from '../onUnmountModule.js';
|
|
4
5
|
import { VNode } from '../vdom.js';
|
|
5
6
|
import { type ChildAttribute } from './childAttribute.js';
|
|
6
7
|
import { clearRuntime, requireDispatch, setRuntime } from './runtimeSingleton.js';
|
|
@@ -61,23 +62,23 @@ export type Html = VNode | null;
|
|
|
61
62
|
export type Child = Html | string;
|
|
62
63
|
/** Whether an event handler leaves the browser's default action in place or
|
|
63
64
|
* prevents it synchronously. */
|
|
64
|
-
export declare const DefaultAction:
|
|
65
|
+
export declare const DefaultAction: Schema.Literals<readonly ["Allow", "Prevent"]>;
|
|
65
66
|
/** Whether an event handler leaves the browser's default action in place or
|
|
66
67
|
* prevents it synchronously. */
|
|
67
68
|
export type DefaultAction = typeof DefaultAction.Type;
|
|
68
69
|
/** Whether an event continues through its DOM propagation path or stops after
|
|
69
70
|
* the handlers on its current element have run. */
|
|
70
|
-
export declare const EventPropagation:
|
|
71
|
+
export declare const EventPropagation: Schema.Literals<readonly ["Bubble", "Stop"]>;
|
|
71
72
|
/** Whether an event continues through its DOM propagation path or stops after
|
|
72
73
|
* the handlers on its current element have run. */
|
|
73
74
|
export type EventPropagation = typeof EventPropagation.Type;
|
|
74
75
|
/** Declarative controls for an `OnClick` handler. Omitted
|
|
75
76
|
* fields keep the browser default, allow the click to bubble, and leave focus
|
|
76
77
|
* unchanged. */
|
|
77
|
-
export declare const ClickOptions:
|
|
78
|
-
readonly defaultAction:
|
|
79
|
-
readonly propagation:
|
|
80
|
-
readonly focusSelector:
|
|
78
|
+
export declare const ClickOptions: Schema.Struct<{
|
|
79
|
+
readonly defaultAction: Schema.optional<Schema.Literals<readonly ["Allow", "Prevent"]>>;
|
|
80
|
+
readonly propagation: Schema.optional<Schema.Literals<readonly ["Bubble", "Stop"]>>;
|
|
81
|
+
readonly focusSelector: Schema.optional<Schema.String>;
|
|
81
82
|
}>;
|
|
82
83
|
/** Declarative controls for an `OnClick` handler. Omitted
|
|
83
84
|
* fields keep the browser default, allow the click to bubble, and leave focus
|
|
@@ -85,7 +86,7 @@ export declare const ClickOptions: S.Struct<{
|
|
|
85
86
|
export type ClickOptions = typeof ClickOptions.Type;
|
|
86
87
|
/** Text direction for the document root, applied to `dir` on the `<html>`
|
|
87
88
|
* element. `Auto` defers to the browser's first-strong-character heuristic. */
|
|
88
|
-
export declare const TextDirection:
|
|
89
|
+
export declare const TextDirection: Schema.Literals<readonly ["Ltr", "Rtl", "Auto"]>;
|
|
89
90
|
/** Text direction for the document root, applied to `dir` on the `<html>`
|
|
90
91
|
* element. `Auto` defers to the browser's first-strong-character heuristic. */
|
|
91
92
|
export type TextDirection = typeof TextDirection.Type;
|
|
@@ -125,13 +126,16 @@ export type Document = Readonly<{
|
|
|
125
126
|
export type TagName = 'a' | 'abbr' | 'address' | 'area' | 'article' | 'aside' | 'audio' | 'b' | 'base' | 'bdi' | 'bdo' | 'blockquote' | 'body' | 'br' | 'button' | 'canvas' | 'caption' | 'cite' | 'code' | 'col' | 'colgroup' | 'data' | 'datalist' | 'dd' | 'del' | 'details' | 'dfn' | 'dialog' | 'div' | 'dl' | 'dt' | 'em' | 'embed' | 'fieldset' | 'figcaption' | 'figure' | 'footer' | 'form' | 'h1' | 'h2' | 'h3' | 'h4' | 'h5' | 'h6' | 'head' | 'header' | 'hgroup' | 'hr' | 'html' | 'i' | 'iframe' | 'img' | 'input' | 'ins' | 'kbd' | 'label' | 'legend' | 'li' | 'link' | 'main' | 'map' | 'mark' | 'menu' | 'meta' | 'meter' | 'nav' | 'noscript' | 'object' | 'ol' | 'optgroup' | 'option' | 'output' | 'p' | 'picture' | 'portal' | 'pre' | 'progress' | 'q' | 'rp' | 'rt' | 'ruby' | 's' | 'samp' | 'script' | 'search' | 'section' | 'select' | 'slot' | 'small' | 'source' | 'span' | 'strong' | 'style' | 'sub' | 'summary' | 'sup' | 'table' | 'tbody' | 'td' | 'template' | 'textarea' | 'tfoot' | 'th' | 'thead' | 'time' | 'title' | 'tr' | 'track' | 'u' | 'ul' | 'var' | 'video' | 'wbr' | 'animate' | 'animateMotion' | 'animateTransform' | 'circle' | 'clipPath' | 'defs' | 'desc' | 'ellipse' | 'feBlend' | 'feColorMatrix' | 'feComponentTransfer' | 'feComposite' | 'feConvolveMatrix' | 'feDiffuseLighting' | 'feDisplacementMap' | 'feDistantLight' | 'feDropShadow' | 'feFlood' | 'feFuncA' | 'feFuncB' | 'feFuncG' | 'feFuncR' | 'feGaussianBlur' | 'feImage' | 'feMerge' | 'feMergeNode' | 'feMorphology' | 'feOffset' | 'fePointLight' | 'feSpecularLighting' | 'feSpotLight' | 'feTile' | 'feTurbulence' | 'filter' | 'foreignObject' | 'g' | 'image' | 'line' | 'linearGradient' | 'marker' | 'mask' | 'metadata' | 'mpath' | 'path' | 'pattern' | 'polygon' | 'polyline' | 'radialGradient' | 'rect' | 'set' | 'stop' | 'svg' | 'switch' | 'symbol' | 'text' | 'textPath' | 'tspan' | 'use' | 'view' | 'annotation' | 'annotation-xml' | 'math' | 'maction' | 'menclose' | 'merror' | 'mfenced' | 'mfrac' | 'mglyph' | 'mi' | 'mlabeledtr' | 'mlongdiv' | 'mmultiscripts' | 'mn' | 'mo' | 'mover' | 'mpadded' | 'mphantom' | 'mprescripts' | 'mroot' | 'mrow' | 'ms' | 'mscarries' | 'mscarry' | 'msgroup' | 'msline' | 'mspace' | 'msqrt' | 'msrow' | 'mstack' | 'mstyle' | 'msub' | 'msubsup' | 'msup' | 'mtable' | 'mtd' | 'mtext' | 'mtr' | 'munder' | 'munderover' | 'semantics';
|
|
126
127
|
/** Opens a replay-render window. The runtime calls this immediately before a
|
|
127
128
|
* DevTools time-travel render and closes it with {@link __endReplayRender}
|
|
128
|
-
* afterward, so
|
|
129
|
-
* tree is patched in
|
|
129
|
+
* afterward, so the `OnUnmount` module can defer live callbacks while the
|
|
130
|
+
* replayed tree is patched in. Without the gate the callback would
|
|
130
131
|
* enqueue a hygiene Message into live history during mere inspection of past
|
|
131
132
|
* state. */
|
|
132
|
-
export declare const __beginReplayRender:
|
|
133
|
+
export declare const __beginReplayRender: typeof beginReplayUnmountRender;
|
|
133
134
|
/** Closes the replay-render window opened by {@link __beginReplayRender}. */
|
|
134
|
-
export declare const __endReplayRender:
|
|
135
|
+
export declare const __endReplayRender: typeof endReplayUnmountRender;
|
|
136
|
+
/** Dispatches the live `OnUnmount` callbacks deferred by a replay patch that
|
|
137
|
+
* failed and forced the runtime to discard the damaged DOM. */
|
|
138
|
+
export declare const __flushReplayUnmountsAfterPatchFailure: typeof flushReplayUnmountsAfterPatchFailure;
|
|
135
139
|
/** Key under which the OnMount attribute stamps a `{ name }` marker on the
|
|
136
140
|
* snabbdom `VNodeData`. Snabbdom passes unknown data fields through without
|
|
137
141
|
* rendering them to the DOM, so the marker is invisible at runtime but
|
|
@@ -142,8 +146,9 @@ export declare const FOLDKIT_MOUNT_KEY: 'foldkitMount';
|
|
|
142
146
|
* introspection can identify pending mounts. When the mount lives inside a
|
|
143
147
|
* Submodel boundary, it also carries that boundary's `toParentMessage` chain
|
|
144
148
|
* (innermost first), snapshotted at render time, so `Scene.Mount.resolve` can
|
|
145
|
-
* replay the lift the result travels through in production.
|
|
146
|
-
*
|
|
149
|
+
* replay the lift the result travels through in production. Production keeps
|
|
150
|
+
* the Mount bound to the dispatcher owned by its acquiring render, then
|
|
151
|
+
* resolves that owner's latest chain when the Mount emits. */
|
|
147
152
|
export type FoldkitMountMarker = Readonly<{
|
|
148
153
|
name: string;
|
|
149
154
|
args?: Record<string, unknown>;
|
|
@@ -1116,6 +1121,16 @@ export { Prop, OnCustomEvent };
|
|
|
1116
1121
|
export declare const customElement: <Message>() => (tagName: string) => (attributes?: ReadonlyArray<Attribute<Message> | ChildAttribute>, children?: ReadonlyArray<Child>) => Html;
|
|
1117
1122
|
type ElementFunction<Message> = (attributes: ReadonlyArray<Attribute<Message> | ChildAttribute>, children?: ReadonlyArray<Child>) => Html;
|
|
1118
1123
|
type VoidElementFunction<Message> = (attributes: ReadonlyArray<Attribute<Message> | ChildAttribute>) => Html;
|
|
1124
|
+
/** An attribute accepted by textarea builders. Textarea content must use
|
|
1125
|
+
* `h.Value`; innerHTML does not keep the live value tracking the Model after
|
|
1126
|
+
* the field is dirty. */
|
|
1127
|
+
export type TextareaAttribute<Message> = Exclude<Attribute<Message>, Readonly<{
|
|
1128
|
+
_tag: 'InnerHTML';
|
|
1129
|
+
}>>;
|
|
1130
|
+
type TextValueElementFunction<Message> = (attributes: ReadonlyArray<TextareaAttribute<Message> | ChildAttribute>) => Html;
|
|
1131
|
+
type KeyedElementFunction<Message> = (key: PropertyKey, attributes?: ReadonlyArray<Attribute<Message> | ChildAttribute>, children?: ReadonlyArray<Child>) => Html;
|
|
1132
|
+
type KeyedTextValueElementFunction<Message> = (key: PropertyKey, attributes?: ReadonlyArray<TextareaAttribute<Message> | ChildAttribute>) => Html;
|
|
1133
|
+
type KeyedFunction<Message> = <Name extends TagName>(tagName: Name) => Name extends 'textarea' ? KeyedTextValueElementFunction<Message> : KeyedElementFunction<Message>;
|
|
1119
1134
|
type HtmlElements<Message> = {
|
|
1120
1135
|
a: ElementFunction<Message>;
|
|
1121
1136
|
abbr: ElementFunction<Message>;
|
|
@@ -1217,7 +1232,7 @@ type HtmlElements<Message> = {
|
|
|
1217
1232
|
tbody: ElementFunction<Message>;
|
|
1218
1233
|
td: ElementFunction<Message>;
|
|
1219
1234
|
template: ElementFunction<Message>;
|
|
1220
|
-
textarea:
|
|
1235
|
+
textarea: TextValueElementFunction<Message>;
|
|
1221
1236
|
tfoot: ElementFunction<Message>;
|
|
1222
1237
|
th: ElementFunction<Message>;
|
|
1223
1238
|
thead: ElementFunction<Message>;
|
|
@@ -2653,7 +2668,7 @@ type MessageUniverse<Message> = Readonly<{
|
|
|
2653
2668
|
*/
|
|
2654
2669
|
export type HtmlBuilder<Message> = MessageUniverse<Message> & HtmlElements<Message> & HtmlAttributes<Message> & Readonly<{
|
|
2655
2670
|
empty: null;
|
|
2656
|
-
keyed:
|
|
2671
|
+
keyed: KeyedFunction<Message>;
|
|
2657
2672
|
submodel: <View extends AnySubmodelView>(config: SubmodelConfig<View, Message>) => Html;
|
|
2658
2673
|
}>;
|
|
2659
2674
|
/** @internal Returns the process-wide builder singleton retyped to a frame's
|