foldkit 0.101.0 → 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 +2 -1
- 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 +137 -110
- 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 +1 -1
- package/dist/runtime/runtime.d.ts.map +1 -1
- package/dist/runtime/runtime.js +115 -61
- 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/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 +6 -6
- package/dist/ui/dragAndDrop/index.d.ts.map +1 -1
- package/dist/ui/dragAndDrop/index.js +7 -7
- 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 +72 -34
- package/dist/ui/slider/index.d.ts.map +1 -1
- package/dist/ui/slider/index.js +40 -49
- 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 +18 -41
- package/dist/ui/virtualList/index.d.ts.map +1 -1
- package/dist/ui/virtualList/index.js +17 -37
- 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/render/render.js
CHANGED
|
@@ -8,6 +8,10 @@ export type EnvelopedMessage<Message> = Readonly<{
|
|
|
8
8
|
* class. The runtime calls this on each `Queue.takeAll` batch so user input
|
|
9
9
|
* (view dispatch, navigation, subscription events, managed-resource events,
|
|
10
10
|
* external dispatchers) lands ahead of chain-derived work (Command results)
|
|
11
|
-
* whenever both share a frame.
|
|
11
|
+
* whenever both share a frame.
|
|
12
|
+
*
|
|
13
|
+
* Single-pass partition: walks the batch once and pushes each unwrapped
|
|
14
|
+
* message into either `highs` or `normals`, then concatenates. Avoids the
|
|
15
|
+
* four allocations of the previous filter/filter/appendAll/map chain. */
|
|
12
16
|
export declare const orderByPriority: <Message>(batch: ReadonlyArray<EnvelopedMessage<Message>>) => ReadonlyArray<Message>;
|
|
13
17
|
//# sourceMappingURL=messagePriority.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"messagePriority.d.ts","sourceRoot":"","sources":["../../src/runtime/messagePriority.ts"],"names":[],"mappings":"AAEA,MAAM,MAAM,QAAQ,GAAG,MAAM,GAAG,QAAQ,CAAA;AAExC,MAAM,MAAM,gBAAgB,CAAC,OAAO,IAAI,QAAQ,CAAC;IAC/C,QAAQ,EAAE,QAAQ,CAAA;IAClB,OAAO,EAAE,OAAO,CAAA;CACjB,CAAC,CAAA;AAEF
|
|
1
|
+
{"version":3,"file":"messagePriority.d.ts","sourceRoot":"","sources":["../../src/runtime/messagePriority.ts"],"names":[],"mappings":"AAEA,MAAM,MAAM,QAAQ,GAAG,MAAM,GAAG,QAAQ,CAAA;AAExC,MAAM,MAAM,gBAAgB,CAAC,OAAO,IAAI,QAAQ,CAAC;IAC/C,QAAQ,EAAE,QAAQ,CAAA;IAClB,OAAO,EAAE,OAAO,CAAA;CACjB,CAAC,CAAA;AAEF;;;;;;;;;0EAS0E;AAC1E,eAAO,MAAM,eAAe,GAAI,OAAO,EACrC,OAAO,aAAa,CAAC,gBAAgB,CAAC,OAAO,CAAC,CAAC,KAC9C,aAAa,CAAC,OAAO,CAoBvB,CAAA"}
|
|
@@ -4,9 +4,30 @@ import { Array } from 'effect';
|
|
|
4
4
|
* class. The runtime calls this on each `Queue.takeAll` batch so user input
|
|
5
5
|
* (view dispatch, navigation, subscription events, managed-resource events,
|
|
6
6
|
* external dispatchers) lands ahead of chain-derived work (Command results)
|
|
7
|
-
* whenever both share a frame.
|
|
7
|
+
* whenever both share a frame.
|
|
8
|
+
*
|
|
9
|
+
* Single-pass partition: walks the batch once and pushes each unwrapped
|
|
10
|
+
* message into either `highs` or `normals`, then concatenates. Avoids the
|
|
11
|
+
* four allocations of the previous filter/filter/appendAll/map chain. */
|
|
8
12
|
export const orderByPriority = (batch) => {
|
|
9
|
-
const highs =
|
|
10
|
-
const normals =
|
|
11
|
-
|
|
13
|
+
const highs = [];
|
|
14
|
+
const normals = [];
|
|
15
|
+
for (const envelope of batch) {
|
|
16
|
+
if (envelope.priority === 'High') {
|
|
17
|
+
highs.push(envelope.message);
|
|
18
|
+
}
|
|
19
|
+
else {
|
|
20
|
+
normals.push(envelope.message);
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
if (Array.isReadonlyArrayEmpty(normals)) {
|
|
24
|
+
return highs;
|
|
25
|
+
}
|
|
26
|
+
if (Array.isReadonlyArrayEmpty(highs)) {
|
|
27
|
+
return normals;
|
|
28
|
+
}
|
|
29
|
+
for (const message of normals) {
|
|
30
|
+
highs.push(message);
|
|
31
|
+
}
|
|
32
|
+
return highs;
|
|
12
33
|
};
|
|
@@ -94,7 +94,7 @@ export type CrashContext<Model, Message> = Readonly<{
|
|
|
94
94
|
model: Model;
|
|
95
95
|
message: Message;
|
|
96
96
|
}>;
|
|
97
|
-
/** Configuration for crash handling
|
|
97
|
+
/** Configuration for crash handling, with custom crash UI and/or crash reporting. */
|
|
98
98
|
export type CrashConfig<Model, Message> = Readonly<{
|
|
99
99
|
view?: (context: CrashContext<Model, Message>) => Document;
|
|
100
100
|
report?: (context: CrashContext<Model, Message>) => void;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"runtime.d.ts","sourceRoot":"","sources":["../../src/runtime/runtime.ts"],"names":[],"mappings":"AACA,OAAO,EAGL,OAAO,EAEP,MAAM,EAGN,KAAK,EAEL,MAAM,EAON,MAAM,EAIP,MAAM,QAAQ,CAAA;AAGf,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,qBAAqB,CAAA;AASlD,OAAO,
|
|
1
|
+
{"version":3,"file":"runtime.d.ts","sourceRoot":"","sources":["../../src/runtime/runtime.ts"],"names":[],"mappings":"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"}
|
package/dist/runtime/runtime.js
CHANGED
|
@@ -4,6 +4,7 @@ import { h } from 'snabbdom';
|
|
|
4
4
|
import { createOverlay } from '../devTools/overlay.js';
|
|
5
5
|
import { createDevToolsStore, } from '../devTools/store.js';
|
|
6
6
|
import { startWebSocketBridge } from '../devTools/webSocketBridge.js';
|
|
7
|
+
import { __beginRender as beginHtmlRender, __clearRuntime as clearHtmlRuntime, __createBoundaryRegistry as createHtmlBoundaryRegistry, __setRuntime as setHtmlRuntime, } from '../html/index.js';
|
|
7
8
|
import { MountTracker } from '../mount/index.js';
|
|
8
9
|
import { fromString as urlFromString } from '../url/index.js';
|
|
9
10
|
import { patch, toVNode } from '../vdom.js';
|
|
@@ -66,12 +67,6 @@ const makeRuntime = ({ Model, flags: resolveFlags, init, update, view, subscript
|
|
|
66
67
|
// current burst exceeds FRAME_BUDGET_MS so the browser gets a frame.
|
|
67
68
|
// setTimeout(0) is clamped to 4ms+; MessageChannel delivers in ~0.5ms.
|
|
68
69
|
const FRAME_BUDGET_MS = 5;
|
|
69
|
-
const yieldToBrowser = Effect.callback(resume => {
|
|
70
|
-
const channel = new MessageChannel();
|
|
71
|
-
channel.port2.onmessage = () => resume(Effect.void);
|
|
72
|
-
channel.port1.postMessage(null);
|
|
73
|
-
return Effect.sync(() => channel.port2.close());
|
|
74
|
-
});
|
|
75
70
|
// NOTE: render coalescing relies on this firing once per frame. Multiple
|
|
76
71
|
// Messages dispatched between frames all flag the renderLoop dirty; the
|
|
77
72
|
// next rAF tick reads the latest model and renders once. Without this,
|
|
@@ -87,7 +82,39 @@ const makeRuntime = ({ Model, flags: resolveFlags, init, update, view, subscript
|
|
|
87
82
|
return yield* Effect.die(new Error('[foldkit] Runtime container must have an `id` for HMR model preservation. ' +
|
|
88
83
|
'Set `container.id = "app"` (or any unique string) before passing it to makeProgram.'));
|
|
89
84
|
}
|
|
85
|
+
// NOTE: one persistent MessageChannel for the runtime lifetime,
|
|
86
|
+
// shared by every burst-budget yield. The queue-drain fiber is the
|
|
87
|
+
// sole consumer, so a single `pendingYieldResume` slot is sufficient.
|
|
88
|
+
const yieldChannel = yield* Effect.acquireRelease(Effect.sync(() => new MessageChannel()), channel => Effect.sync(() => {
|
|
89
|
+
channel.port1.close();
|
|
90
|
+
channel.port2.close();
|
|
91
|
+
}));
|
|
92
|
+
let pendingYieldResume = null;
|
|
93
|
+
yieldChannel.port2.onmessage = () => {
|
|
94
|
+
const resume = pendingYieldResume;
|
|
95
|
+
pendingYieldResume = null;
|
|
96
|
+
if (resume !== null) {
|
|
97
|
+
resume(Effect.void);
|
|
98
|
+
}
|
|
99
|
+
};
|
|
100
|
+
const yieldToBrowser = Effect.callback(resume => {
|
|
101
|
+
pendingYieldResume = resume;
|
|
102
|
+
yieldChannel.port1.postMessage(null);
|
|
103
|
+
return Effect.sync(() => {
|
|
104
|
+
if (pendingYieldResume === resume) {
|
|
105
|
+
pendingYieldResume = null;
|
|
106
|
+
}
|
|
107
|
+
});
|
|
108
|
+
});
|
|
90
109
|
const maybeResourceLayer = Option.fromNullishOr(resources);
|
|
110
|
+
// NOTE: One boundary registry per runtime instance, shared
|
|
111
|
+
// across renders so Submodel wrap descriptors registered by
|
|
112
|
+
// h.submodel persist between renders. The render function calls
|
|
113
|
+
// `beginHtmlRender` at the start of each pass; wraps for
|
|
114
|
+
// unmounted Submodels (e.g. an entry removed from a list) are
|
|
115
|
+
// dropped from the registry via snabbdom destroy hooks attached
|
|
116
|
+
// by `h.submodel` to each child vnode.
|
|
117
|
+
const boundaryRegistry = createHtmlBoundaryRegistry();
|
|
91
118
|
const managedResourceEntries = managedResources
|
|
92
119
|
? /* eslint-disable-next-line @typescript-eslint/consistent-type-assertions */
|
|
93
120
|
Record.toEntries(managedResources)
|
|
@@ -181,8 +208,19 @@ const makeRuntime = ({ Model, flags: resolveFlags, init, update, view, subscript
|
|
|
181
208
|
}
|
|
182
209
|
const modelRef = yield* Ref.make(initModel);
|
|
183
210
|
const maybeCurrentVNodeRef = yield* Ref.make(Option.none());
|
|
184
|
-
|
|
185
|
-
|
|
211
|
+
// NOTE: queue-drain-fiber-local state. Kept as plain closure
|
|
212
|
+
// variables instead of `Ref`s because nothing else reads or writes
|
|
213
|
+
// them concurrently, and JS's single-threaded model already orders
|
|
214
|
+
// writes against subsequent reads. `currentMessage` is read by the
|
|
215
|
+
// crash handler, which runs inside the same `forever` fiber via
|
|
216
|
+
// `Effect.catchCause`.
|
|
217
|
+
let currentMessage = Option.none();
|
|
218
|
+
let burstStartedAt = 0;
|
|
219
|
+
// NOTE: the DevTools store is installed at most once during boot and
|
|
220
|
+
// never replaced. Caching it in a closure variable avoids a
|
|
221
|
+
// `Ref.get` on every message and on every render-loop tick (the
|
|
222
|
+
// store powers `isPausedEffect`).
|
|
223
|
+
let maybeDevToolsStore = Option.none();
|
|
186
224
|
const dispatchSync = (message) => {
|
|
187
225
|
/* eslint-disable-next-line @typescript-eslint/consistent-type-assertions */
|
|
188
226
|
enqueueHighUnsafe(message);
|
|
@@ -193,13 +231,10 @@ const makeRuntime = ({ Model, flags: resolveFlags, init, update, view, subscript
|
|
|
193
231
|
const dispatch = { dispatchAsync, dispatchSync };
|
|
194
232
|
const isRenderPendingRef = yield* SubscriptionRef.make(false);
|
|
195
233
|
const lastDirtyMessageRef = yield* Ref.make(Option.none());
|
|
196
|
-
const isPausedEffect = Effect.
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
onSome: ({ stateRef }) => SubscriptionRef.get(stateRef).pipe(Effect.map(({ isPaused }) => isPaused)),
|
|
201
|
-
});
|
|
202
|
-
});
|
|
234
|
+
const isPausedEffect = Effect.suspend(() => Option.match(maybeDevToolsStore, {
|
|
235
|
+
onNone: () => Effect.succeed(false),
|
|
236
|
+
onSome: ({ stateRef }) => SubscriptionRef.get(stateRef).pipe(Effect.map(({ isPaused }) => isPaused)),
|
|
237
|
+
}));
|
|
203
238
|
const mountStartBuffer = [];
|
|
204
239
|
const mountEndBuffer = [];
|
|
205
240
|
const mountTracker = {
|
|
@@ -228,32 +263,30 @@ const makeRuntime = ({ Model, flags: resolveFlags, init, update, view, subscript
|
|
|
228
263
|
PubSub.publishUnsafe(modelPubSub, nextModel);
|
|
229
264
|
yield* schedulePreserveModel(nextModel);
|
|
230
265
|
}
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
266
|
+
if (!Array.isReadonlyArrayEmpty(commands)) {
|
|
267
|
+
yield* Effect.forEach(
|
|
268
|
+
/* eslint-disable-next-line @typescript-eslint/consistent-type-assertions */
|
|
269
|
+
commands, command => Effect.forkDetach(command.effect.pipe(Effect.withSpan(command.name, {
|
|
270
|
+
attributes: command.args ?? {},
|
|
271
|
+
}), provideAllResources, Effect.flatMap(enqueueNormal))));
|
|
272
|
+
}
|
|
237
273
|
/* eslint-disable-next-line @typescript-eslint/consistent-type-assertions */
|
|
238
274
|
const messageTag = message._tag;
|
|
239
275
|
const isModelChanged = currentModel !== nextModel;
|
|
240
276
|
const isExcludedFromHistory = excludeFromHistoryTags.has(messageTag);
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
return Effect.void;
|
|
255
|
-
},
|
|
256
|
-
});
|
|
277
|
+
if (Option.isSome(maybeDevToolsStore)) {
|
|
278
|
+
const store = maybeDevToolsStore.value;
|
|
279
|
+
if (!isExcludedFromHistory) {
|
|
280
|
+
yield* store.recordMessage(
|
|
281
|
+
/* eslint-disable-next-line @typescript-eslint/consistent-type-assertions */
|
|
282
|
+
message, currentModel, nextModel, Array.map(
|
|
283
|
+
/* eslint-disable-next-line @typescript-eslint/consistent-type-assertions */
|
|
284
|
+
commands, toCommandRecord), isModelChanged);
|
|
285
|
+
}
|
|
286
|
+
else if (isModelChanged) {
|
|
287
|
+
yield* store.updateLatestModel(nextModel);
|
|
288
|
+
}
|
|
289
|
+
}
|
|
257
290
|
});
|
|
258
291
|
// NOTE: `dispatchService` defaults to the live dispatch but is
|
|
259
292
|
// overridable so the DevTools jumpTo render path can pass
|
|
@@ -264,9 +297,18 @@ const makeRuntime = ({ Model, flags: resolveFlags, init, update, view, subscript
|
|
|
264
297
|
// This prevents mount-derived Messages from polluting history when
|
|
265
298
|
// the user is just inspecting past state.
|
|
266
299
|
const render = (model, message, dispatchService = dispatch) => Effect.gen(function* () {
|
|
300
|
+
const runtimeContext = yield* Effect.context();
|
|
267
301
|
const viewStart = performance.now();
|
|
268
|
-
|
|
269
|
-
|
|
302
|
+
beginHtmlRender(boundaryRegistry);
|
|
303
|
+
setHtmlRuntime(dispatchService.dispatchSync, runtimeContext, boundaryRegistry);
|
|
304
|
+
let nextDocument;
|
|
305
|
+
try {
|
|
306
|
+
nextDocument = view(model);
|
|
307
|
+
}
|
|
308
|
+
finally {
|
|
309
|
+
clearHtmlRuntime();
|
|
310
|
+
}
|
|
311
|
+
const nextVNode = nextDocument.body;
|
|
270
312
|
const viewDuration = performance.now() - viewStart;
|
|
271
313
|
Option.match(resolvedSlowView, {
|
|
272
314
|
onNone: Function.constVoid,
|
|
@@ -282,7 +324,7 @@ const makeRuntime = ({ Model, flags: resolveFlags, init, update, view, subscript
|
|
|
282
324
|
},
|
|
283
325
|
});
|
|
284
326
|
const maybeCurrentVNode = yield* Ref.get(maybeCurrentVNodeRef);
|
|
285
|
-
const patchedVNode = yield* Effect.sync(() => patchVNode(maybeCurrentVNode,
|
|
327
|
+
const patchedVNode = yield* Effect.sync(() => patchVNode(maybeCurrentVNode, nextVNode, container));
|
|
286
328
|
yield* Ref.set(maybeCurrentVNodeRef, Option.some(patchedVNode));
|
|
287
329
|
yield* Effect.sync(() => applyDocumentMetadata(nextDocument, patchedVNode.elm));
|
|
288
330
|
}).pipe(Effect.provideService(Dispatch, dispatchService), Effect.provideService(MountTracker, mountTracker));
|
|
@@ -296,7 +338,7 @@ const makeRuntime = ({ Model, flags: resolveFlags, init, update, view, subscript
|
|
|
296
338
|
const { position, mode, maybeBanner } = resolvedDevTools.value;
|
|
297
339
|
// NOTE: when excludeFromHistory is active, the runtime drops
|
|
298
340
|
// excluded Messages from the recorded history. Replay walks the
|
|
299
|
-
// recorded entries forward from the nearest keyframe
|
|
341
|
+
// recorded entries forward from the nearest keyframe. With
|
|
300
342
|
// exclusion, the dropped Messages aren't in that walk, so any
|
|
301
343
|
// cumulative state they would have produced is missing from the
|
|
302
344
|
// replayed model. Setting keyframeInterval to 1 stores a full
|
|
@@ -337,7 +379,7 @@ const makeRuntime = ({ Model, flags: resolveFlags, init, update, view, subscript
|
|
|
337
379
|
maxEntries: devToolsMaxEntries,
|
|
338
380
|
}),
|
|
339
381
|
});
|
|
340
|
-
|
|
382
|
+
maybeDevToolsStore = Option.some(devToolsStore);
|
|
341
383
|
// The init render runs below; capture the events it produces. We
|
|
342
384
|
// record init AFTER that render so the buffer reflects the mounts
|
|
343
385
|
// that fired on the first paint.
|
|
@@ -355,8 +397,7 @@ const makeRuntime = ({ Model, flags: resolveFlags, init, update, view, subscript
|
|
|
355
397
|
}
|
|
356
398
|
yield* render(initModel, Option.none());
|
|
357
399
|
const initMountEvents = drainMountEvents();
|
|
358
|
-
|
|
359
|
-
yield* Option.match(maybeStoreForInit, {
|
|
400
|
+
yield* Option.match(maybeDevToolsStore, {
|
|
360
401
|
onNone: () => Effect.void,
|
|
361
402
|
onSome: store => store.recordInit(initModel, Array.map(initCommands, toCommandRecord), initMountEvents.starts),
|
|
362
403
|
});
|
|
@@ -375,8 +416,7 @@ const makeRuntime = ({ Model, flags: resolveFlags, init, update, view, subscript
|
|
|
375
416
|
const maybeMessage = yield* Ref.get(lastDirtyMessageRef);
|
|
376
417
|
yield* render(model, maybeMessage);
|
|
377
418
|
const mountEvents = drainMountEvents();
|
|
378
|
-
|
|
379
|
-
yield* Option.match(maybeStore, {
|
|
419
|
+
yield* Option.match(maybeDevToolsStore, {
|
|
380
420
|
onNone: () => Effect.void,
|
|
381
421
|
onSome: store => store.attachRenderedMounts(mountEvents.starts, mountEvents.ends),
|
|
382
422
|
});
|
|
@@ -439,16 +479,14 @@ const makeRuntime = ({ Model, flags: resolveFlags, init, update, view, subscript
|
|
|
439
479
|
concurrency: 'unbounded',
|
|
440
480
|
discard: true,
|
|
441
481
|
});
|
|
442
|
-
const burstStartedAtRef = yield* Ref.make(0);
|
|
443
482
|
const processWithBudget = (message) => Effect.gen(function* () {
|
|
444
|
-
|
|
483
|
+
currentMessage = Option.some(message);
|
|
445
484
|
yield* processMessage(message);
|
|
446
|
-
const burstStartedAt = yield* Ref.get(burstStartedAtRef);
|
|
447
485
|
if (performance.now() - burstStartedAt < FRAME_BUDGET_MS) {
|
|
448
486
|
return;
|
|
449
487
|
}
|
|
450
488
|
yield* yieldToBrowser;
|
|
451
|
-
|
|
489
|
+
burstStartedAt = performance.now();
|
|
452
490
|
});
|
|
453
491
|
const processBatch = (batch) => Effect.forEach(orderByPriority(batch), processWithBudget, {
|
|
454
492
|
discard: true,
|
|
@@ -488,7 +526,7 @@ const makeRuntime = ({ Model, flags: resolveFlags, init, update, view, subscript
|
|
|
488
526
|
const first = yield* Option.match(maybeFirst, {
|
|
489
527
|
onNone: () => Effect.gen(function* () {
|
|
490
528
|
const message = yield* Queue.take(messageQueue);
|
|
491
|
-
|
|
529
|
+
burstStartedAt = performance.now();
|
|
492
530
|
return message;
|
|
493
531
|
}),
|
|
494
532
|
onSome: Effect.succeed,
|
|
@@ -502,7 +540,7 @@ const makeRuntime = ({ Model, flags: resolveFlags, init, update, view, subscript
|
|
|
502
540
|
? squashed
|
|
503
541
|
: new Error(String(squashed));
|
|
504
542
|
const model = Effect.runSync(Ref.get(modelRef));
|
|
505
|
-
const message =
|
|
543
|
+
const message = Option.getOrThrow(currentMessage);
|
|
506
544
|
renderCrashView({ error: appError, model, message }, crash, container, maybeCurrentVNodeRef);
|
|
507
545
|
})));
|
|
508
546
|
}));
|
|
@@ -556,22 +594,38 @@ const renderCrashView = (context, crash, container, maybeCurrentVNodeRef) => {
|
|
|
556
594
|
console.error('[foldkit] crash.report failed:', reportError);
|
|
557
595
|
}
|
|
558
596
|
}
|
|
597
|
+
const crashContext = Context.make(Dispatch, noOpDispatch).pipe(Context.add(MountTracker, {
|
|
598
|
+
started: () => { },
|
|
599
|
+
ended: () => { },
|
|
600
|
+
}));
|
|
559
601
|
try {
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
|
|
602
|
+
setHtmlRuntime(noOpDispatch.dispatchSync, crashContext);
|
|
603
|
+
let crashDocument;
|
|
604
|
+
try {
|
|
605
|
+
crashDocument = crash?.view
|
|
606
|
+
? crash.view(context)
|
|
607
|
+
: defaultCrashView(context);
|
|
608
|
+
}
|
|
609
|
+
finally {
|
|
610
|
+
clearHtmlRuntime();
|
|
611
|
+
}
|
|
563
612
|
const maybeCurrentVNode = Effect.runSync(Ref.get(maybeCurrentVNodeRef));
|
|
564
|
-
const
|
|
565
|
-
const patchedVNode = patchVNode(maybeCurrentVNode, vnode, container);
|
|
613
|
+
const patchedVNode = patchVNode(maybeCurrentVNode, crashDocument.body, container);
|
|
566
614
|
applyDocumentMetadata(crashDocument, patchedVNode.elm);
|
|
567
615
|
}
|
|
568
616
|
catch (viewError) {
|
|
569
617
|
console.error('[foldkit] crash.view failed:', viewError);
|
|
570
|
-
const maybeCurrentVNode = Effect.runSync(Ref.get(maybeCurrentVNodeRef));
|
|
571
618
|
const fallbackViewError = viewError instanceof Error ? viewError : new Error(String(viewError));
|
|
572
|
-
|
|
573
|
-
|
|
574
|
-
|
|
619
|
+
setHtmlRuntime(noOpDispatch.dispatchSync, crashContext);
|
|
620
|
+
let fallbackDocument;
|
|
621
|
+
try {
|
|
622
|
+
fallbackDocument = defaultCrashView(context, fallbackViewError);
|
|
623
|
+
}
|
|
624
|
+
finally {
|
|
625
|
+
clearHtmlRuntime();
|
|
626
|
+
}
|
|
627
|
+
const maybeCurrentVNode = Effect.runSync(Ref.get(maybeCurrentVNodeRef));
|
|
628
|
+
const patchedVNode = patchVNode(maybeCurrentVNode, fallbackDocument.body, container);
|
|
575
629
|
applyDocumentMetadata(fallbackDocument, patchedVNode.elm);
|
|
576
630
|
}
|
|
577
631
|
};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"public.d.ts","sourceRoot":"","sources":["../../src/submodel/public.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,qBAAqB,CAAA;AAChD,YAAY,EACV,cAAc,IAAI,MAAM,EACxB,YAAY,IAAI,IAAI,GACrB,MAAM,qBAAqB,CAAA;AAC5B,YAAY,EAAE,OAAO,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAA"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { defineView } from '../html/submodel.js';
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
/** Data-first / data-last signature for a `reflect*` setter built with
|
|
2
|
+
* `Function.dual`.
|
|
3
|
+
*
|
|
4
|
+
* A `reflect*` helper conforms a Submodel to a value that originated
|
|
5
|
+
* outside it (a URL, a server push, restored storage, a sibling field),
|
|
6
|
+
* without emitting an OutMessage. It is the inbound complement to
|
|
7
|
+
* OutMessage's outbound direction: the world is the source of truth, so
|
|
8
|
+
* the Submodel mirrors it silently and never announces the change back.
|
|
9
|
+
*
|
|
10
|
+
* Being dual, it reads two ways. Data-first sets the field and returns the
|
|
11
|
+
* model; data-last returns `(model) => model`, which slots point-free into
|
|
12
|
+
* an `evo` callback:
|
|
13
|
+
*
|
|
14
|
+
* ```ts
|
|
15
|
+
* // data-first
|
|
16
|
+
* const next = ColorListbox.reflectSelectedItem(model.colors, fromUrl)
|
|
17
|
+
* // data-last, point-free in evo
|
|
18
|
+
* evo(model, { colors: ColorListbox.reflectSelectedItem(fromUrl) })
|
|
19
|
+
* ```
|
|
20
|
+
*/
|
|
21
|
+
export type Reflect<Model, Value> = {
|
|
22
|
+
(model: Model, value: Value): Model;
|
|
23
|
+
(value: Value): (model: Model) => Model;
|
|
24
|
+
};
|
|
25
|
+
/** Two-argument variant of {@link Reflect}, for setters that resolve a
|
|
26
|
+
* value against a companion argument (e.g. `Tabs.reflectSelectedTab(value,
|
|
27
|
+
* options)`, which finds the value's index in `options`). */
|
|
28
|
+
export type Reflect2<Model, A, B> = {
|
|
29
|
+
(model: Model, a: A, b: B): Model;
|
|
30
|
+
(a: A, b: B): (model: Model) => Model;
|
|
31
|
+
};
|
|
32
|
+
//# sourceMappingURL=submodel.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"submodel.d.ts","sourceRoot":"","sources":["../../src/submodel/submodel.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;GAmBG;AACH,MAAM,MAAM,OAAO,CAAC,KAAK,EAAE,KAAK,IAAI;IAClC,CAAC,KAAK,EAAE,KAAK,EAAE,KAAK,EAAE,KAAK,GAAG,KAAK,CAAA;IACnC,CAAC,KAAK,EAAE,KAAK,GAAG,CAAC,KAAK,EAAE,KAAK,KAAK,KAAK,CAAA;CACxC,CAAA;AAED;;8DAE8D;AAC9D,MAAM,MAAM,QAAQ,CAAC,KAAK,EAAE,CAAC,EAAE,CAAC,IAAI;IAClC,CAAC,KAAK,EAAE,KAAK,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,GAAG,KAAK,CAAA;IACjC,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,GAAG,CAAC,KAAK,EAAE,KAAK,KAAK,KAAK,CAAA;CACtC,CAAA"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -19,21 +19,20 @@ export type Model = typeof Model.Type;
|
|
|
19
19
|
export declare const ClickedToggle: import("../../schema/index.js").CallableTaggedStruct<"ClickedToggle", {}>;
|
|
20
20
|
export declare const ClickedSubmit: import("../../schema/index.js").CallableTaggedStruct<"ClickedSubmit", {}>;
|
|
21
21
|
export declare const GotDialogMessage: import("../../schema/index.js").CallableTaggedStruct<"GotDialogMessage", {
|
|
22
|
-
message: S.Union<[import("../../schema/index.js").CallableTaggedStruct<"
|
|
22
|
+
message: S.Union<[import("../../schema/index.js").CallableTaggedStruct<"RequestedOpen", {}>, import("../../schema/index.js").CallableTaggedStruct<"RequestedClose", {}>, import("../../schema/index.js").CallableTaggedStruct<"CompletedShowDialog", {}>, import("../../schema/index.js").CallableTaggedStruct<"CompletedCloseDialog", {}>, import("../../schema/index.js").CallableTaggedStruct<"GotAnimationMessage", {
|
|
23
23
|
message: S.Union<[import("../../schema/index.js").CallableTaggedStruct<"Showed", {}>, import("../../schema/index.js").CallableTaggedStruct<"Hid", {}>, import("../../schema/index.js").CallableTaggedStruct<"AdvancedAnimationFrame", {}>, import("../../schema/index.js").CallableTaggedStruct<"EndedAnimation", {}>]>;
|
|
24
24
|
}>]>;
|
|
25
25
|
}>;
|
|
26
26
|
export declare const Message: S.Union<readonly [import("../../schema/index.js").CallableTaggedStruct<"ClickedToggle", {}>, import("../../schema/index.js").CallableTaggedStruct<"ClickedSubmit", {}>, import("../../schema/index.js").CallableTaggedStruct<"GotDialogMessage", {
|
|
27
|
-
message: S.Union<[import("../../schema/index.js").CallableTaggedStruct<"
|
|
27
|
+
message: S.Union<[import("../../schema/index.js").CallableTaggedStruct<"RequestedOpen", {}>, import("../../schema/index.js").CallableTaggedStruct<"RequestedClose", {}>, import("../../schema/index.js").CallableTaggedStruct<"CompletedShowDialog", {}>, import("../../schema/index.js").CallableTaggedStruct<"CompletedCloseDialog", {}>, import("../../schema/index.js").CallableTaggedStruct<"GotAnimationMessage", {
|
|
28
28
|
message: S.Union<[import("../../schema/index.js").CallableTaggedStruct<"Showed", {}>, import("../../schema/index.js").CallableTaggedStruct<"Hid", {}>, import("../../schema/index.js").CallableTaggedStruct<"AdvancedAnimationFrame", {}>, import("../../schema/index.js").CallableTaggedStruct<"EndedAnimation", {}>]>;
|
|
29
29
|
}>]>;
|
|
30
30
|
}>]>;
|
|
31
31
|
export type Message = typeof Message.Type;
|
|
32
32
|
export declare const initialModel: Model;
|
|
33
33
|
export declare const update: (model: Model, message: Message) => readonly [Model, ReadonlyArray<Command.Command<Message>>];
|
|
34
|
-
/** Plain view
|
|
34
|
+
/** Plain view, no dialog wrapper. */
|
|
35
35
|
export declare const view: (model: Model) => Html;
|
|
36
|
-
/** View with submit button inside a dialog's
|
|
36
|
+
/** View with submit button inside a dialog's panel. */
|
|
37
37
|
export declare const viewWithDialog: (model: Model) => Html;
|
|
38
|
-
export declare const viewWithLazyDialog: (model: Model) => Html;
|
|
39
38
|
//# sourceMappingURL=disabledButton.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"disabledButton.d.ts","sourceRoot":"","sources":["../../../src/test/apps/disabledButton.ts"],"names":[],"mappings":"AAAA,OAAO,
|
|
1
|
+
{"version":3,"file":"disabledButton.d.ts","sourceRoot":"","sources":["../../../src/test/apps/disabledButton.ts"],"names":[],"mappings":"AAAA,OAAO,EAAc,MAAM,IAAI,CAAC,EAAE,MAAM,QAAQ,CAAA;AAEhD,OAAO,KAAK,OAAO,MAAM,wBAAwB,CAAA;AACjD,OAAO,EAAE,KAAK,IAAI,EAAQ,MAAM,qBAAqB,CAAA;AAMrD,eAAO,MAAM,KAAK;;;;;;;;;;;;;EAGhB,CAAA;AACF,MAAM,MAAM,KAAK,GAAG,OAAO,KAAK,CAAC,IAAI,CAAA;AAIrC,eAAO,MAAM,aAAa,2EAAqB,CAAA;AAC/C,eAAO,MAAM,aAAa,2EAAqB,CAAA;AAC/C,eAAO,MAAM,gBAAgB;;;;EAE3B,CAAA;AAEF,eAAO,MAAM,OAAO;;;;IAA4D,CAAA;AAChF,MAAM,MAAM,OAAO,GAAG,OAAO,OAAO,CAAC,IAAI,CAAA;AAIzC,eAAO,MAAM,YAAY,EAAE,KAG1B,CAAA;AAID,eAAO,MAAM,MAAM,GACjB,OAAO,KAAK,EACZ,SAAS,OAAO,KACf,SAAS,CAAC,KAAK,EAAE,aAAa,CAAC,OAAO,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC,CAqBxD,CAAA;AAgBH,qCAAqC;AACrC,eAAO,MAAM,IAAI,GAAI,OAAO,KAAK,KAAG,IAUnC,CAAA;AAED,uDAAuD;AACvD,eAAO,MAAM,cAAc,GAAI,OAAO,KAAK,KAAG,IA2B7C,CAAA"}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { Match as M, Schema as S } from 'effect';
|
|
2
2
|
import * as Command from '../../command/index.js';
|
|
3
3
|
import { html } from '../../html/index.js';
|
|
4
4
|
import { m } from '../../message/index.js';
|
|
@@ -28,7 +28,7 @@ export const update = (model, message) => M.value(message).pipe(M.withReturnType
|
|
|
28
28
|
const [nextDialog, commands] = Dialog.update(model.dialog, dialogMessage);
|
|
29
29
|
return [
|
|
30
30
|
{ ...model, dialog: nextDialog },
|
|
31
|
-
|
|
31
|
+
Command.mapMessages(commands, dialogMessage => GotDialogMessage({ message: dialogMessage })),
|
|
32
32
|
];
|
|
33
33
|
},
|
|
34
34
|
}));
|
|
@@ -40,7 +40,7 @@ const submitButton = (isEnabled) => {
|
|
|
40
40
|
...(isEnabled ? [h.OnClick(ClickedSubmit())] : [h.Disabled(true)]),
|
|
41
41
|
], ['Submit']);
|
|
42
42
|
};
|
|
43
|
-
/** Plain view
|
|
43
|
+
/** Plain view, no dialog wrapper. */
|
|
44
44
|
export const view = (model) => {
|
|
45
45
|
const h = html();
|
|
46
46
|
return h.div([], [
|
|
@@ -48,24 +48,24 @@ export const view = (model) => {
|
|
|
48
48
|
submitButton(model.isEnabled),
|
|
49
49
|
]);
|
|
50
50
|
};
|
|
51
|
-
/** View with submit button inside a dialog's
|
|
51
|
+
/** View with submit button inside a dialog's panel. */
|
|
52
52
|
export const viewWithDialog = (model) => {
|
|
53
53
|
const h = html();
|
|
54
54
|
return h.div([], [
|
|
55
55
|
h.button([h.OnClick(ClickedToggle())], ['Toggle']),
|
|
56
|
-
|
|
56
|
+
h.submodel({
|
|
57
|
+
slotId: model.dialog.id,
|
|
57
58
|
model: model.dialog,
|
|
58
|
-
|
|
59
|
-
|
|
59
|
+
view: Dialog.view,
|
|
60
|
+
viewInputs: {
|
|
61
|
+
toView: ({ dialog, backdrop, panel, isVisible }) => h.dialog([...dialog], isVisible
|
|
62
|
+
? [
|
|
63
|
+
h.div([...backdrop], []),
|
|
64
|
+
h.div([...panel], [submitButton(model.isEnabled)]),
|
|
65
|
+
]
|
|
66
|
+
: []),
|
|
67
|
+
},
|
|
68
|
+
toParentMessage: message => GotDialogMessage({ message }),
|
|
60
69
|
}),
|
|
61
70
|
]);
|
|
62
71
|
};
|
|
63
|
-
/** View using Dialog.lazy with panelContent passed dynamically. */
|
|
64
|
-
const lazyDialogView = Dialog.lazy({});
|
|
65
|
-
export const viewWithLazyDialog = (model) => {
|
|
66
|
-
const h = html();
|
|
67
|
-
return h.div([], [
|
|
68
|
-
h.button([h.OnClick(ClickedToggle())], ['Toggle']),
|
|
69
|
-
lazyDialogView(model.dialog, (dialogMessage) => GotDialogMessage({ message: dialogMessage }), submitButton(model.isEnabled)),
|
|
70
|
-
]);
|
|
71
|
-
};
|