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/devTools/store.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { Array, Effect, HashMap, HashSet, Match, Option, Predicate, Record, String
|
|
1
|
+
import { Array, Effect, HashMap, HashSet, Match, Option, Predicate, Record, String, SubscriptionRef, pipe, } from 'effect';
|
|
2
2
|
import { evo } from '../struct/index.js';
|
|
3
3
|
export const INIT_INDEX = -1;
|
|
4
4
|
const DEFAULT_KEYFRAME_INTERVAL = 31;
|
|
@@ -61,7 +61,7 @@ export const computeDiff = (previous, current) => {
|
|
|
61
61
|
walk(previous, current, 'root');
|
|
62
62
|
const affected = new Set(changed);
|
|
63
63
|
const addAncestors = (path) => {
|
|
64
|
-
pipe(path,
|
|
64
|
+
pipe(path, String.lastIndexOf('.'), Option.map(lastDot => path.substring(0, lastDot)), Option.filter(parent => !affected.has(parent)), Option.map(parent => {
|
|
65
65
|
affected.add(parent);
|
|
66
66
|
addAncestors(parent);
|
|
67
67
|
}));
|
|
@@ -140,29 +140,35 @@ export const createDevToolsStore = (bridge, options = {}) => Effect.gen(function
|
|
|
140
140
|
keyframes: HashMap.set(0, model),
|
|
141
141
|
maybeLatestModel: () => Option.some(model),
|
|
142
142
|
}));
|
|
143
|
-
const recordMessage = (message, modelBeforeUpdate, modelAfterUpdate, commands, isModelChanged) =>
|
|
144
|
-
const
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
143
|
+
const recordMessage = (message, modelBeforeUpdate, modelAfterUpdate, commands, isModelChanged) => Effect.gen(function* () {
|
|
144
|
+
const didAutoResume = yield* SubscriptionRef.modify(stateRef, state => {
|
|
145
|
+
const absoluteIndex = nextEntryIndex(state);
|
|
146
|
+
const diff = isModelChanged
|
|
147
|
+
? computeDiff(modelBeforeUpdate, modelAfterUpdate)
|
|
148
|
+
: emptyDiff;
|
|
149
|
+
const hasChangedFields = HashSet.size(diff.changedPaths) > 0;
|
|
150
|
+
const nextState = evo(state, {
|
|
151
|
+
entries: Array.append({
|
|
152
|
+
tag: message._tag,
|
|
153
|
+
message,
|
|
154
|
+
commands,
|
|
155
|
+
mountStarts: [],
|
|
156
|
+
mountEnds: [],
|
|
157
|
+
timestamp: performance.now(),
|
|
158
|
+
isModelChanged: hasChangedFields,
|
|
159
|
+
diff,
|
|
160
|
+
}),
|
|
161
|
+
keyframes: addKeyframeIfNeeded(absoluteIndex + 1, modelAfterUpdate),
|
|
162
|
+
maybeLatestModel: () => Option.some(modelAfterUpdate),
|
|
163
|
+
});
|
|
164
|
+
const recordedState = nextState.entries.length > maxEntries
|
|
165
|
+
? evictOldestSegment(nextState)
|
|
166
|
+
: nextState;
|
|
167
|
+
return [state.isPaused && !recordedState.isPaused, recordedState];
|
|
162
168
|
});
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
169
|
+
if (didAutoResume) {
|
|
170
|
+
yield* bridge.markRenderPending;
|
|
171
|
+
}
|
|
166
172
|
});
|
|
167
173
|
/** Attaches Mount lifecycle events from the most recent render to the
|
|
168
174
|
* history entry that triggered the render. Mount events fire during
|
|
@@ -207,10 +213,28 @@ export const createDevToolsStore = (bridge, options = {}) => Effect.gen(function
|
|
|
207
213
|
const state = yield* SubscriptionRef.get(stateRef);
|
|
208
214
|
const model = resolveModel(state, index);
|
|
209
215
|
yield* bridge.render(model);
|
|
210
|
-
yield* SubscriptionRef.
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
216
|
+
const wasTargetEvicted = yield* SubscriptionRef.modify(stateRef, currentState => {
|
|
217
|
+
const isTargetRetained = index === INIT_INDEX ||
|
|
218
|
+
(index >= currentState.startIndex &&
|
|
219
|
+
index <= latestEntryIndex(currentState));
|
|
220
|
+
return isTargetRetained
|
|
221
|
+
? [
|
|
222
|
+
false,
|
|
223
|
+
evo(currentState, {
|
|
224
|
+
isPaused: () => true,
|
|
225
|
+
pausedAtIndex: () => index,
|
|
226
|
+
}),
|
|
227
|
+
]
|
|
228
|
+
: [
|
|
229
|
+
true,
|
|
230
|
+
evo(currentState, {
|
|
231
|
+
isPaused: () => false,
|
|
232
|
+
}),
|
|
233
|
+
];
|
|
234
|
+
});
|
|
235
|
+
if (wasTargetEvicted) {
|
|
236
|
+
yield* bridge.markRenderPending;
|
|
237
|
+
}
|
|
214
238
|
return model;
|
|
215
239
|
});
|
|
216
240
|
const resume = Effect.gen(function* () {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"submodelPath.d.ts","sourceRoot":"","sources":["../../src/devTools/submodelPath.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,
|
|
1
|
+
{"version":3,"file":"submodelPath.d.ts","sourceRoot":"","sources":["../../src/devTools/submodelPath.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAgB,MAAM,QAAQ,CAAA;AAE7C,eAAO,MAAM,mBAAmB,QAAmB,CAAA;AAGnD,eAAO,MAAM,QAAQ;;CAAoB,CAAA;AAEzC,oEAAoE;AACpE,MAAM,MAAM,YAAY,GAAG,QAAQ,CAAC;IAClC,YAAY,EAAE,aAAa,CAAC,MAAM,CAAC,CAAA;IACnC,YAAY,EAAE,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,CAAA;CACpC,CAAC,CAAA;AAEF;;;;;;;;;;;;;;GAcG;AACH,eAAO,MAAM,mBAAmB,QACzB,MAAM,WACF,OAAO,KACf,YAuBF,CAAA"}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import { Option, Schema
|
|
1
|
+
import { Option, Schema, pipe } from 'effect';
|
|
2
2
|
export const GOT_MESSAGE_PATTERN = /^Got.+Message$/;
|
|
3
|
-
const Tagged =
|
|
4
|
-
export const isTagged =
|
|
3
|
+
const Tagged = Schema.Struct({ _tag: Schema.String });
|
|
4
|
+
export const isTagged = Schema.is(Tagged);
|
|
5
5
|
/**
|
|
6
6
|
* Walk a chain of `Got<Submodel>Message` wrappers in a recorded Message and
|
|
7
7
|
* return the wrapper tags plus the innermost leaf tag.
|
|
@@ -1,13 +1,13 @@
|
|
|
1
|
-
import { Schema
|
|
1
|
+
import { Schema } from 'effect';
|
|
2
2
|
declare const PathResolution: import("../schema/index.js").TaggedUnion<{
|
|
3
3
|
readonly Found: {
|
|
4
|
-
value:
|
|
5
|
-
atPath:
|
|
4
|
+
value: Schema.Unknown;
|
|
5
|
+
atPath: Schema.String;
|
|
6
6
|
};
|
|
7
7
|
readonly NotFound: {
|
|
8
|
-
failedAt:
|
|
9
|
-
reason:
|
|
10
|
-
availableKeys:
|
|
8
|
+
failedAt: Schema.String;
|
|
9
|
+
reason: Schema.String;
|
|
10
|
+
availableKeys: Schema.$Array<Schema.String>;
|
|
11
11
|
};
|
|
12
12
|
}>;
|
|
13
13
|
/**
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"summarize.d.ts","sourceRoot":"","sources":["../../src/devTools/summarize.ts"],"names":[],"mappings":"AAAA,OAAO,EAOL,MAAM,
|
|
1
|
+
{"version":3,"file":"summarize.d.ts","sourceRoot":"","sources":["../../src/devTools/summarize.ts"],"names":[],"mappings":"AAAA,OAAO,EAOL,MAAM,EACP,MAAM,QAAQ,CAAA;AAaf,QAAA,MAAM,cAAc;;QACT,KAAK;QAAkB,MAAM;;;QAEpC,QAAQ;QACR,MAAM;QACN,aAAa;;EAEf,CAAA;AAEF;;;;;GAKG;AACH,MAAM,MAAM,cAAc,GAAG,OAAO,cAAc,CAAC,IAAI,CAAA;AA8BvD;wDACwD;AACxD,eAAO,MAAM,WAAW,SAAU,OAAO,QAAQ,MAAM,KAAG,cAsCzD,CAAA;AAyDD;;;;;;;;;GASG;AACH,eAAO,MAAM,cAAc,UAAW,OAAO,KAAG,OAAgC,CAAA;AAYhF;yCACyC;AACzC,eAAO,MAAM,kBAAkB,aACnB,OAAO,CAAC,cAAc,EAAE;IAAE,IAAI,EAAE,UAAU,CAAA;CAAE,CAAC,KACtD,MAIC,CAAA"}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { Array
|
|
1
|
+
import { Array, Function, Match, Option, Predicate, Record, Schema, } from 'effect';
|
|
2
2
|
import { OptionExt } from '../effectExtensions/index.js';
|
|
3
3
|
import { defineTaggedUnion } from '../schema/index.js';
|
|
4
4
|
const ROOT = 'root';
|
|
@@ -8,18 +8,18 @@ const STRING_TRUNCATE = 200;
|
|
|
8
8
|
const ARRAY_SAMPLE = 2;
|
|
9
9
|
// PATH
|
|
10
10
|
const PathResolution = defineTaggedUnion({
|
|
11
|
-
Found: { value:
|
|
11
|
+
Found: { value: Schema.Unknown, atPath: Schema.String },
|
|
12
12
|
NotFound: {
|
|
13
|
-
failedAt:
|
|
14
|
-
reason:
|
|
15
|
-
availableKeys:
|
|
13
|
+
failedAt: Schema.String,
|
|
14
|
+
reason: Schema.String,
|
|
15
|
+
availableKeys: Schema.Array(Schema.String),
|
|
16
16
|
},
|
|
17
17
|
});
|
|
18
18
|
const isExpandable = Predicate.isObjectOrArray;
|
|
19
|
-
const keysOf = (value) =>
|
|
19
|
+
const keysOf = (value) => Match.value(value).pipe(Match.when(globalThis.Array.isArray, items => Array.makeBy(items.length, index => index.toString())), Match.when(Predicate.isObject, Record.keys), Match.orElse(() => []));
|
|
20
20
|
const segmentsOf = (path) => path === ROOT ? [] : path.split(PATH_SEPARATOR).slice(1);
|
|
21
21
|
const isRootAnchored = (path) => path === ROOT || path.startsWith(`${ROOT}${PATH_SEPARATOR}`);
|
|
22
|
-
const descend = (parent, segment) =>
|
|
22
|
+
const descend = (parent, segment) => Match.value(parent).pipe(Match.when(globalThis.Array.isArray, array => Option.liftPredicate(Number(segment), Number.isInteger).pipe(Option.flatMap(index => Array.get(array, index)))), Match.when(Predicate.isObject, record => Record.get(record, segment)), Match.orElse(() => Option.none()));
|
|
23
23
|
/** Looks up a `root.foo.bar` path in a Model snapshot. On failure, returns the
|
|
24
24
|
* deepest path reached and the keys available there. */
|
|
25
25
|
export const resolvePath = (root, path) => {
|
|
@@ -34,7 +34,7 @@ export const resolvePath = (root, path) => {
|
|
|
34
34
|
value: root,
|
|
35
35
|
atPath: ROOT,
|
|
36
36
|
});
|
|
37
|
-
return
|
|
37
|
+
return Array.reduce(segmentsOf(path), initial, (resolution, segment) => {
|
|
38
38
|
if (resolution._tag === 'NotFound') {
|
|
39
39
|
return resolution;
|
|
40
40
|
}
|
|
@@ -65,10 +65,10 @@ const sampleArray = (items, depth) => {
|
|
|
65
65
|
const sample = items.length <= ARRAY_SAMPLE
|
|
66
66
|
? items
|
|
67
67
|
: [
|
|
68
|
-
...
|
|
69
|
-
...Option.toArray(
|
|
68
|
+
...Array.take(items, ARRAY_SAMPLE - 1),
|
|
69
|
+
...Option.toArray(Array.last(items)),
|
|
70
70
|
];
|
|
71
|
-
return
|
|
71
|
+
return Array.map(sample, item => summarizeAt(item, depth + 1));
|
|
72
72
|
};
|
|
73
73
|
const summarizeArray = (items, depth) => ({
|
|
74
74
|
_summary: 'array',
|
|
@@ -84,7 +84,7 @@ const summarizeRecord = (value, depth) => {
|
|
|
84
84
|
}
|
|
85
85
|
return Record.map(value, child => summarizeAt(child, depth + 1));
|
|
86
86
|
};
|
|
87
|
-
const summarizeAt = (value, depth) =>
|
|
87
|
+
const summarizeAt = (value, depth) => Match.value(value).pipe(Match.when(Predicate.isString, truncateString), Match.when(globalThis.Array.isArray, items => summarizeArray(items, depth)), Match.when(Predicate.isObject, record => summarizeRecord(record, depth)), Match.orElse(Function.identity));
|
|
88
88
|
/**
|
|
89
89
|
* Apply structural summarization rules to a value:
|
|
90
90
|
* - Arrays collapse to `{ _summary, length, sample: [head, last] }` at every depth.
|
|
@@ -97,7 +97,7 @@ const summarizeAt = (value, depth) => M.value(value).pipe(M.when(Predicate.isStr
|
|
|
97
97
|
*/
|
|
98
98
|
export const summarizeValue = (value) => summarizeAt(value, 0);
|
|
99
99
|
// FORMAT
|
|
100
|
-
const formatAvailableKeys = (keys) => OptionExt.when(
|
|
100
|
+
const formatAvailableKeys = (keys) => OptionExt.when(Array.isReadonlyArrayNonEmpty(keys), `Available keys: ${keys.join(', ')}.`);
|
|
101
101
|
/** Formats a `NotFound` result for `ResponseError.reason`, including the keys
|
|
102
102
|
* available where the lookup stopped. */
|
|
103
103
|
export const formatPathNotFound = (notFound) => Option.match(formatAvailableKeys(notFound.availableKeys), {
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { Effect, Option, Schema
|
|
1
|
+
import { Effect, Option, Schema, Scope } from 'effect';
|
|
2
2
|
import { Request, Response } from './protocol.js';
|
|
3
3
|
import { type DevToolsStore } from './store.js';
|
|
4
4
|
type Hot = NonNullable<ImportMeta['hot']>;
|
|
@@ -38,12 +38,12 @@ export declare const EVENT_CHANNEL = "foldkit:devTools:event";
|
|
|
38
38
|
* Production-safe: callers must check `import.meta.hot` is defined before
|
|
39
39
|
* invoking this. The function assumes a live HMR connection.
|
|
40
40
|
*/
|
|
41
|
-
export declare const startWebSocketBridge: (store: DevToolsStore, hot: Hot, dispatch: (message: unknown) => Effect.Effect<void>, maybeMessageSchema: Option.Option<
|
|
41
|
+
export declare const startWebSocketBridge: (store: DevToolsStore, hot: Hot, dispatch: (message: unknown) => Effect.Effect<void>, maybeMessageSchema: Option.Option<Schema.Codec<any, any>>) => Effect.Effect<void, never, Scope.Scope>;
|
|
42
42
|
/**
|
|
43
43
|
* Fulfill one bridge Request against the DevTools store. `startWebSocketBridge`
|
|
44
44
|
* wires this to the HMR request channel; exported so tests can drive request
|
|
45
45
|
* handling without a live HMR connection.
|
|
46
46
|
*/
|
|
47
|
-
export declare const dispatchRequest: (store: DevToolsStore, dispatch: (message: unknown) => Effect.Effect<void>, maybeDispatchSchema: Option.Option<
|
|
47
|
+
export declare const dispatchRequest: (store: DevToolsStore, dispatch: (message: unknown) => Effect.Effect<void>, maybeDispatchSchema: Option.Option<Schema.Codec<any, any>>, maybeJsonSchemaDocument: Option.Option<unknown>, request: Request) => Effect.Effect<Response>;
|
|
48
48
|
export {};
|
|
49
49
|
//# sourceMappingURL=webSocketBridge.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"webSocketBridge.d.ts","sourceRoot":"","sources":["../../src/devTools/webSocketBridge.ts"],"names":[],"mappings":"AAAA,OAAO,EAGL,MAAM,EAIN,MAAM,EAEN,MAAM,
|
|
1
|
+
{"version":3,"file":"webSocketBridge.d.ts","sourceRoot":"","sources":["../../src/devTools/webSocketBridge.ts"],"names":[],"mappings":"AAAA,OAAO,EAGL,MAAM,EAIN,MAAM,EAEN,MAAM,EACN,KAAK,EAGN,MAAM,QAAQ,CAAA;AAcf,OAAO,EAOL,OAAO,EAEP,QAAQ,EAGT,MAAM,eAAe,CAAA;AAatB,OAAO,EACL,KAAK,aAAa,EAKnB,MAAM,YAAY,CAAA;AAQnB,KAAK,GAAG,GAAG,WAAW,CAAC,UAAU,CAAC,KAAK,CAAC,CAAC,CAAA;AAKzC,uEAAuE;AACvE,eAAO,MAAM,aAAa,2BAA2B,CAAA;AAmBrD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAiCG;AACH,eAAO,MAAM,oBAAoB,UACxB,aAAa,OACf,GAAG,YACE,CAAC,OAAO,EAAE,OAAO,KAAK,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,sBAC/B,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,KAAK,CAAC,GAAG,EAAE,GAAG,CAAC,CAAC,KACxD,MAAM,CAAC,MAAM,CAAC,IAAI,EAAE,KAAK,EAAE,KAAK,CAAC,KAAK,CAyHrC,CAAA;AAyIJ;;;;GAIG;AACH,eAAO,MAAM,eAAe,UACnB,aAAa,YACV,CAAC,OAAO,EAAE,OAAO,KAAK,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,uBAC9B,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,KAAK,CAAC,GAAG,EAAE,GAAG,CAAC,CAAC,2BACjC,MAAM,CAAC,MAAM,CAAC,OAAO,CAAC,WACtC,OAAO,KACf,MAAM,CAAC,MAAM,CAAC,QAAQ,CAyUrB,CAAA"}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { Array, Cause, Effect, Exit, HashMap, Match, Option, Order, Schema
|
|
1
|
+
import { Array, Cause, Effect, Exit, HashMap, Match, Option, Order, Schema, SubscriptionRef, pipe, } from 'effect';
|
|
2
2
|
import { OptionExt } from '../effectExtensions/index.js';
|
|
3
3
|
import { collectMatchingEntries, countEntriesByTag, findUnanchoredPattern, formatIndexNotReadable, isIndexReadable, matchesAnyPathPattern, pageMatchingEntries, pathOrder, readSummarizedValueAt, } from './historyQuery.js';
|
|
4
4
|
import { DiffValue, Event, EventFrame, KeyframeInfo, MAX_DISPATCH_BATCH_SIZE, MessageSchemaResult, Request, RequestFrame, Response, ResponseFrame, RuntimeInfo, } from './protocol.js';
|
|
@@ -13,7 +13,7 @@ export const EVENT_CHANNEL = 'foldkit:devTools:event';
|
|
|
13
13
|
const generateConnectionId = () => `${Date.now().toString(36)}-${Math.random().toString(36).slice(2, 10)}`;
|
|
14
14
|
const tryDeriveJsonSchemaDocument = (schema) => {
|
|
15
15
|
try {
|
|
16
|
-
return Option.some(
|
|
16
|
+
return Option.some(Schema.toJsonSchemaDocument(schema));
|
|
17
17
|
}
|
|
18
18
|
catch (error) {
|
|
19
19
|
console.warn('[foldkit:devTools] Failed to derive JSON Schema from Message Schema; foldkit_get_message_schema will return None.', error);
|
|
@@ -57,10 +57,10 @@ const tryDeriveJsonSchemaDocument = (schema) => {
|
|
|
57
57
|
export const startWebSocketBridge = (store, hot, dispatch, maybeMessageSchema) => Effect.gen(function* () {
|
|
58
58
|
const connectionId = generateConnectionId();
|
|
59
59
|
const capturedContext = yield* Effect.context();
|
|
60
|
-
const maybeDispatchSchema = Option.map(maybeMessageSchema,
|
|
60
|
+
const maybeDispatchSchema = Option.map(maybeMessageSchema, Schema.toCodecJson);
|
|
61
61
|
const maybeJsonSchemaDocument = Option.flatMap(maybeMessageSchema, tryDeriveJsonSchemaDocument);
|
|
62
|
-
const encodeEventFrame =
|
|
63
|
-
const encodeResponseFrame =
|
|
62
|
+
const encodeEventFrame = Schema.encodeUnknownSync(EventFrame);
|
|
63
|
+
const encodeResponseFrame = Schema.encodeUnknownSync(ResponseFrame);
|
|
64
64
|
const sendEvent = (event) => {
|
|
65
65
|
hot.send(EVENT_CHANNEL, encodeEventFrame({
|
|
66
66
|
maybeConnectionId: Option.some(connectionId),
|
|
@@ -85,7 +85,7 @@ export const startWebSocketBridge = (store, hot, dispatch, maybeMessageSchema) =
|
|
|
85
85
|
sendResponse(id, response);
|
|
86
86
|
});
|
|
87
87
|
const handleRequestFrame = (frame) => {
|
|
88
|
-
const decoded =
|
|
88
|
+
const decoded = Schema.decodeUnknownExit(RequestFrame)(frame);
|
|
89
89
|
Exit.match(decoded, {
|
|
90
90
|
onFailure: error => {
|
|
91
91
|
console.warn('[foldkit:devTools] malformed request frame', error);
|
|
@@ -334,7 +334,7 @@ export const dispatchRequest = (store, dispatch, maybeDispatchSchema, maybeJsonS
|
|
|
334
334
|
RequestDispatchMessage: ({ message }) => Option.match(maybeDispatchSchema, {
|
|
335
335
|
onNone: () => Effect.succeed(missingMessageSchemaResponse),
|
|
336
336
|
onSome: dispatchSchema => Effect.gen(function* () {
|
|
337
|
-
const decodedMessage = yield*
|
|
337
|
+
const decodedMessage = yield* Schema.decodeUnknownEffect(dispatchSchema)(message);
|
|
338
338
|
const stateBefore = yield* SubscriptionRef.get(store.stateRef);
|
|
339
339
|
const acceptedAtIndex = nextEntryIndex(stateBefore);
|
|
340
340
|
yield* dispatch(decodedMessage);
|
|
@@ -352,7 +352,7 @@ export const dispatchRequest = (store, dispatch, maybeDispatchSchema, maybeJsonS
|
|
|
352
352
|
return Option.match(maybeDispatchSchema, {
|
|
353
353
|
onNone: () => Effect.succeed(missingMessageSchemaResponse),
|
|
354
354
|
onSome: dispatchSchema => Effect.gen(function* () {
|
|
355
|
-
const decodeMessage =
|
|
355
|
+
const decodeMessage = Schema.decodeUnknownEffect(dispatchSchema);
|
|
356
356
|
const decodedMessages = yield* Effect.forEach(messages, (message, position) => Effect.mapError(decodeMessage(message), error => new Error(`Invalid Message at zero-based batch position ${position}: ${formatInvalidMessageReason(error, message)}\n\nNo Messages from the batch were dispatched.`)));
|
|
357
357
|
const stateBefore = yield* SubscriptionRef.get(store.stateRef);
|
|
358
358
|
const firstAcceptedIndex = nextEntryIndex(stateBefore);
|
package/dist/dom/dom.d.ts
CHANGED
|
@@ -60,6 +60,8 @@ export declare const focus: (selector: string, options?: Readonly<{
|
|
|
60
60
|
* Fails with `ElementNotFound` if the selector does not match an `HTMLDialogElement`.
|
|
61
61
|
*
|
|
62
62
|
* Pass `focusSelector` to focus an element inside the dialog when it opens.
|
|
63
|
+
* When it does not match a focusable element, or when none is provided, focus
|
|
64
|
+
* falls back to the first focusable descendant and then to the dialog itself.
|
|
63
65
|
*
|
|
64
66
|
* Records the element that had focus when the dialog opened so `closeDialog`
|
|
65
67
|
* can return focus there, the way `showModal()` would natively.
|
package/dist/dom/dom.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"dom.d.ts","sourceRoot":"","sources":["../../src/dom/dom.ts"],"names":[],"mappings":"AAAA,OAAO,
|
|
1
|
+
{"version":3,"file":"dom.d.ts","sourceRoot":"","sources":["../../src/dom/dom.ts"],"names":[],"mappings":"AAAA,OAAO,EAAS,MAAM,EAA0C,MAAM,QAAQ,CAAA;AAG9E,OAAO,EAAE,eAAe,EAAE,MAAM,YAAY,CAAA;AA4E5C;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA+CG;AACH,eAAO,MAAM,KAAK,aACN,MAAM,YACN,QAAQ,CAAC;IAAE,aAAa,CAAC,EAAE,OAAO,CAAC;IAAC,aAAa,CAAC,EAAE,OAAO,CAAA;CAAE,CAAC,KACvE,MAAM,CAAC,MAAM,CAAC,IAAI,EAAE,eAAe,CAQlC,CAAA;AAEJ;;;;;;;;;;;;;;;;;;;GAmBG;AACH,eAAO,MAAM,UAAU,aACX,MAAM,YACN,QAAQ,CAAC;IAAE,aAAa,CAAC,EAAE,MAAM,CAAA;CAAE,CAAC,KAC7C,MAAM,CAAC,MAAM,CAAC,IAAI,EAAE,eAAe,CAqElC,CAAA;AA4CJ;;;;;;;;;;;;;;;;GAgBG;AACH,eAAO,MAAM,WAAW,aACZ,MAAM,KACf,MAAM,CAAC,MAAM,CAAC,OAAO,EAAE,eAAe,CAQrC,CAAA;AAqBJ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAiCG;AACH,eAAO,MAAM,sBAAsB,OAAQ,MAAM,KAAG,MAAM,CAAC,MAAM,CAAC,OAAO,CAOrE,CAAA;AAEJ;;;;;;;;GAQG;AACH,eAAO,MAAM,YAAY,aACb,MAAM,KACf,MAAM,CAAC,MAAM,CAAC,IAAI,EAAE,eAAe,CAKlC,CAAA;AAEJ;;;;;;;;;;;;;;GAcG;AACH,eAAO,MAAM,cAAc,aACf,MAAM,YACN,QAAQ,CAAC;IAAE,KAAK,CAAC,EAAE,qBAAqB,CAAA;CAAE,CAAC,KACpD,MAAM,CAAC,MAAM,CAAC,IAAI,EAAE,eAAe,CAKlC,CAAA;AAEJ;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,eAAO,MAAM,wBAAwB,aACzB,MAAM,YACN,QAAQ,CAAC;IAAE,KAAK,CAAC,EAAE,qBAAqB,CAAA;CAAE,CAAC,KACpD,MAAM,CAAC,MAAM,CAAC,IAAI,EAAE,eAAe,CAKlC,CAAA;AAcJ;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AACH,eAAO,MAAM,0BAA0B,aAC3B,MAAM,YACN,QAAQ,CAAC;IACjB,KAAK,CAAC,EAAE,qBAAqB,CAAA;IAC7B,IAAI,CAAC,EAAE,OAAO,GAAG,QAAQ,CAAA;CAC1B,CAAC,KACD,MAAM,CAAC,MAAM,CAAC,IAAI,EAAE,eAAe,CAuBlC,CAAA;AAEJ,yEAAyE;AACzE,MAAM,MAAM,cAAc,GAAG,MAAM,GAAG,UAAU,CAAA;AAEhD;;;;;;;;GAQG;AACH,eAAO,MAAM,YAAY,aACb,MAAM,aACL,cAAc,KACxB,MAAM,CAAC,MAAM,CAAC,IAAI,EAAE,eAAe,CA+BlC,CAAA"}
|
package/dist/dom/dom.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { Array, Effect, Equal, Function, Match
|
|
1
|
+
import { Array, Effect, Equal, Function, Match, Number, Option } from 'effect';
|
|
2
2
|
import { afterCommit, afterPaint } from '../render/render.js';
|
|
3
3
|
import { ElementNotFound } from './error.js';
|
|
4
4
|
import { unlockScroll } from './scrollLock.js';
|
|
@@ -14,6 +14,25 @@ const FOCUSABLE_SELECTOR = Array.join([
|
|
|
14
14
|
'textarea:not([disabled]):not([tabindex="-1"])',
|
|
15
15
|
'[tabindex]:not([tabindex="-1"])',
|
|
16
16
|
], ', ');
|
|
17
|
+
const isFocusableElement = (element) => {
|
|
18
|
+
if (!(element instanceof HTMLElement)) {
|
|
19
|
+
return false;
|
|
20
|
+
}
|
|
21
|
+
if (element.matches(':disabled')) {
|
|
22
|
+
return false;
|
|
23
|
+
}
|
|
24
|
+
if (element instanceof HTMLInputElement && element.type === 'hidden') {
|
|
25
|
+
return false;
|
|
26
|
+
}
|
|
27
|
+
if (element.tabIndex < 0 && !element.hasAttribute('tabindex')) {
|
|
28
|
+
return false;
|
|
29
|
+
}
|
|
30
|
+
if (element.closest('[hidden], [inert]') !== null) {
|
|
31
|
+
return false;
|
|
32
|
+
}
|
|
33
|
+
return element.checkVisibility({ visibilityProperty: true });
|
|
34
|
+
};
|
|
35
|
+
const focusableElementsWithin = (root) => Array.filter(Array.fromIterable(root.querySelectorAll(FOCUSABLE_SELECTOR)), isFocusableElement);
|
|
17
36
|
const queryHTMLElement = (selector) => Effect.suspend(() => {
|
|
18
37
|
const element = document.querySelector(selector);
|
|
19
38
|
return element instanceof HTMLElement
|
|
@@ -84,6 +103,8 @@ export const focus = (selector, options) => Effect.gen(function* () {
|
|
|
84
103
|
* Fails with `ElementNotFound` if the selector does not match an `HTMLDialogElement`.
|
|
85
104
|
*
|
|
86
105
|
* Pass `focusSelector` to focus an element inside the dialog when it opens.
|
|
106
|
+
* When it does not match a focusable element, or when none is provided, focus
|
|
107
|
+
* falls back to the first focusable descendant and then to the dialog itself.
|
|
87
108
|
*
|
|
88
109
|
* Records the element that had focus when the dialog opened so `closeDialog`
|
|
89
110
|
* can return focus there, the way `showModal()` would natively.
|
|
@@ -120,30 +141,39 @@ export const showDialog = (selector, options) => Effect.gen(function* () {
|
|
|
120
141
|
if (!isTopmost) {
|
|
121
142
|
return;
|
|
122
143
|
}
|
|
123
|
-
|
|
144
|
+
Match.value(event.key).pipe(Match.when('Escape', () => {
|
|
124
145
|
if (event.defaultPrevented) {
|
|
125
146
|
return;
|
|
126
147
|
}
|
|
127
148
|
event.preventDefault();
|
|
128
149
|
element.dispatchEvent(new Event('cancel', { cancelable: true }));
|
|
129
|
-
}),
|
|
150
|
+
}), Match.when('Tab', () => {
|
|
130
151
|
trapFocusWithinDialog(event, element);
|
|
131
|
-
}),
|
|
152
|
+
}), Match.orElse(Function.constVoid));
|
|
132
153
|
};
|
|
133
154
|
document.addEventListener('keydown', handleKeydown);
|
|
134
155
|
dialogHygieneById.set(id, {
|
|
135
156
|
removeKeydownListener: () => document.removeEventListener('keydown', handleKeydown),
|
|
136
157
|
returnFocus,
|
|
137
158
|
});
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
159
|
+
const focusTarget = findDialogFocusTarget(element, options?.focusSelector);
|
|
160
|
+
focusTarget.focus();
|
|
161
|
+
});
|
|
162
|
+
const findDialogFocusTarget = (dialog, focusSelector) => {
|
|
163
|
+
if (focusSelector !== undefined) {
|
|
164
|
+
const requestedFocusTarget = dialog.querySelector(focusSelector);
|
|
165
|
+
if (requestedFocusTarget !== null &&
|
|
166
|
+
isFocusableElement(requestedFocusTarget)) {
|
|
167
|
+
return requestedFocusTarget;
|
|
142
168
|
}
|
|
143
169
|
}
|
|
144
|
-
|
|
170
|
+
return Option.match(Array.head(focusableElementsWithin(dialog)), {
|
|
171
|
+
onSome: Function.identity,
|
|
172
|
+
onNone: () => dialog,
|
|
173
|
+
});
|
|
174
|
+
};
|
|
145
175
|
const trapFocusWithinDialog = (event, dialog) => {
|
|
146
|
-
const focusable =
|
|
176
|
+
const focusable = focusableElementsWithin(dialog);
|
|
147
177
|
if (Array.isReadonlyArrayNonEmpty(focusable)) {
|
|
148
178
|
const first = Array.headNonEmpty(focusable);
|
|
149
179
|
const last = Array.lastNonEmpty(focusable);
|
|
@@ -156,6 +186,10 @@ const trapFocusWithinDialog = (event, dialog) => {
|
|
|
156
186
|
first.focus();
|
|
157
187
|
}
|
|
158
188
|
}
|
|
189
|
+
else {
|
|
190
|
+
event.preventDefault();
|
|
191
|
+
dialog.focus();
|
|
192
|
+
}
|
|
159
193
|
};
|
|
160
194
|
/**
|
|
161
195
|
* Closes a dialog element using `.close()`.
|
|
@@ -335,7 +369,7 @@ const findScrollParent = (element) => {
|
|
|
335
369
|
*/
|
|
336
370
|
export const scrollIntoViewIfNotVisible = (selector, options) => Effect.gen(function* () {
|
|
337
371
|
const when = options?.when ?? 'Paint';
|
|
338
|
-
yield*
|
|
372
|
+
yield* Match.value(when).pipe(Match.when('Paint', () => afterPaint), Match.when('Commit', () => afterCommit), Match.exhaustive);
|
|
339
373
|
const element = yield* queryHTMLElement(selector);
|
|
340
374
|
Option.match(findScrollParent(element), {
|
|
341
375
|
onNone: () => element.scrollIntoView({ block: options?.block ?? 'center' }),
|
|
@@ -362,12 +396,12 @@ export const scrollIntoViewIfNotVisible = (selector, options) => Effect.gen(func
|
|
|
362
396
|
export const advanceFocus = (selector, direction) => Effect.gen(function* () {
|
|
363
397
|
yield* afterCommit;
|
|
364
398
|
const reference = yield* queryHTMLElement(selector);
|
|
365
|
-
const focusableElements =
|
|
399
|
+
const focusableElements = focusableElementsWithin(document);
|
|
366
400
|
const referenceElementIndex = Array.findFirstIndex(focusableElements, Equal.equals(reference));
|
|
367
401
|
if (Option.isNone(referenceElementIndex)) {
|
|
368
402
|
return yield* Effect.fail(new ElementNotFound({ selector }));
|
|
369
403
|
}
|
|
370
|
-
const offsetReferenceElementIndex =
|
|
404
|
+
const offsetReferenceElementIndex = Match.value(direction).pipe(Match.when('Next', () => Number.increment), Match.when('Previous', () => Number.decrement), Match.exhaustive)(referenceElementIndex.value);
|
|
371
405
|
const nextElement = Array.get(focusableElements, offsetReferenceElementIndex);
|
|
372
406
|
if (Option.isSome(nextElement)) {
|
|
373
407
|
nextElement.value.focus();
|
|
@@ -11,7 +11,6 @@ export type TagOf<Union extends Tagged> = Union['_tag'];
|
|
|
11
11
|
export type Variant<Union extends Tagged, Tag extends TagOf<Union>> = Extract<Union, Readonly<{
|
|
12
12
|
_tag: Tag;
|
|
13
13
|
}>>;
|
|
14
|
-
declare const EdgeGuardValueTypeId: unique symbol;
|
|
15
14
|
/**
|
|
16
15
|
* The single argument an Edge's `build` and `commands` callbacks receive:
|
|
17
16
|
* the source state, the triggering Message, and the guard value produced by
|
|
@@ -41,7 +40,7 @@ export type Edge<State extends Tagged, Message extends Tagged, SourceState exten
|
|
|
41
40
|
target: TagOf<State>;
|
|
42
41
|
build: (input: EdgeInput<SourceState, TriggerMessage, unknown>) => State;
|
|
43
42
|
maybeCommands: Option.Option<(input: EdgeInput<SourceState, TriggerMessage, unknown>) => ReadonlyArray<Command<Message, never, R>>>;
|
|
44
|
-
readonly
|
|
43
|
+
readonly '~foldkit/EdgeGuardValue'?: GuardValue;
|
|
45
44
|
}>;
|
|
46
45
|
/** A guarded Edge that fires only when its guard passes. Construct with {@link when}. */
|
|
47
46
|
export type When<State extends Tagged, Message extends Tagged, SourceState extends State, TriggerMessage extends Message, GuardValue = unknown, R = never> = Readonly<{
|
|
@@ -150,9 +149,14 @@ export type EdgeSummary<State extends Tagged, Message extends Tagged> = Readonly
|
|
|
150
149
|
target: TagOf<State>;
|
|
151
150
|
guard: EdgeGuard;
|
|
152
151
|
}>;
|
|
153
|
-
/**
|
|
152
|
+
/**
|
|
153
|
+
* Why an Edge cannot fire in a walk of the declared Edge set:
|
|
154
|
+
* `UnreachableSource` means no path from the walk roots reaches the Edge's
|
|
155
|
+
* source state, and `ShadowedByOtherwise` means an earlier `otherwise` in the
|
|
156
|
+
* Edge's guard list always fires first.
|
|
157
|
+
*/
|
|
154
158
|
export type DeadTransitionReason = 'UnreachableSource' | 'ShadowedByOtherwise';
|
|
155
|
-
/** An Edge that
|
|
159
|
+
/** An Edge that cannot fire in a walk of the declared Edge set, with the reason. */
|
|
156
160
|
export type DeadTransition<State extends Tagged, Message extends Tagged> = Readonly<{
|
|
157
161
|
edge: EdgeSummary<State, Message>;
|
|
158
162
|
reason: DeadTransitionReason;
|
|
@@ -173,9 +177,28 @@ export type Machine<State extends Tagged, Message extends Tagged, R = never> = R
|
|
|
173
177
|
* inspect Edge metadata. */
|
|
174
178
|
transition: (state: State, message: Message) => Update.Return<State, Message, R>;
|
|
175
179
|
step: (state: State, message: Message) => TransitionResult<State, Message, R>;
|
|
180
|
+
/** The state tags a walk of the declared Edge set visits starting from `tag`. */
|
|
176
181
|
reachableFrom: (tag: TagOf<State>) => ReadonlySet<TagOf<State>>;
|
|
177
|
-
|
|
178
|
-
|
|
182
|
+
/**
|
|
183
|
+
* The state tags a walk of the declared Edge set never visits, starting
|
|
184
|
+
* from the initial state's tag plus `extraRoots`. The walk sees only the
|
|
185
|
+
* declared Edges, so state changes made outside `transition` and `step`
|
|
186
|
+
* are invisible to it, and it always starts at `initial`. Entry points
|
|
187
|
+
* other than `initial`, such as restored persistence, deep links, or SSR
|
|
188
|
+
* hydration, must be passed as `extraRoots`, or the states they enter are
|
|
189
|
+
* reported unreachable even though the running program visits them.
|
|
190
|
+
*/
|
|
191
|
+
unreachableStates: (extraRoots?: ReadonlyArray<TagOf<State>>) => ReadonlyArray<TagOf<State>>;
|
|
192
|
+
/**
|
|
193
|
+
* The Edges that cannot fire in a walk of the declared Edge set starting
|
|
194
|
+
* from the initial state's tag plus `extraRoots`, each with its
|
|
195
|
+
* {@link DeadTransitionReason}. The same assumptions as
|
|
196
|
+
* `unreachableStates` apply: the walk cannot see state changes made
|
|
197
|
+
* outside `transition` and `step`, and entry points other than `initial`
|
|
198
|
+
* must be passed as `extraRoots`, or their outgoing Edges are reported as
|
|
199
|
+
* `UnreachableSource` even though the running program fires them.
|
|
200
|
+
*/
|
|
201
|
+
deadTransitions: (extraRoots?: ReadonlyArray<TagOf<State>>) => ReadonlyArray<DeadTransition<State, Message>>;
|
|
179
202
|
toMermaid: () => string;
|
|
180
203
|
}>;
|
|
181
204
|
/**
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"machine.d.ts","sourceRoot":"","sources":["../../../src/experimental/machine/machine.ts"],"names":[],"mappings":"AAAA,OAAO,
|
|
1
|
+
{"version":3,"file":"machine.d.ts","sourceRoot":"","sources":["../../../src/experimental/machine/machine.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { Array, Match
|
|
1
|
+
import { Array, Match, Option, Predicate, Record, pipe } from 'effect';
|
|
2
2
|
const makeEdge = (target, build, commands) => {
|
|
3
3
|
const narrowGuardValue = (input) => {
|
|
4
4
|
/* eslint-disable-next-line @typescript-eslint/consistent-type-assertions */
|
|
@@ -212,17 +212,18 @@ export const define = (schemas) => (definition) => {
|
|
|
212
212
|
}
|
|
213
213
|
};
|
|
214
214
|
const targetsFrom = (tag) => pipe(edges, Array.filter(edgeSummary => edgeSummary.from === tag), Array.map(edgeSummary => edgeSummary.target));
|
|
215
|
-
const
|
|
215
|
+
const reachableFromRoots = (roots) => {
|
|
216
216
|
const visit = (frontier, visited) => Array.matchLeft(frontier, {
|
|
217
217
|
onEmpty: () => visited,
|
|
218
218
|
onNonEmpty: (head, tail) => visited.has(head)
|
|
219
219
|
? visit(tail, visited)
|
|
220
220
|
: visit([...tail, ...targetsFrom(head)], new Set([...visited, head])),
|
|
221
221
|
});
|
|
222
|
-
return visit(
|
|
222
|
+
return visit(roots, new Set());
|
|
223
223
|
};
|
|
224
|
-
const
|
|
225
|
-
|
|
224
|
+
const reachableFrom = (tag) => reachableFromRoots([tag]);
|
|
225
|
+
const unreachableStates = (extraRoots = []) => {
|
|
226
|
+
const reachable = reachableFromRoots([initialTag, ...extraRoots]);
|
|
226
227
|
return Array.filter(stateTags, stateTag => !reachable.has(stateTag));
|
|
227
228
|
};
|
|
228
229
|
const makeDeadTransition = (edge, reason) => ({ edge, reason });
|
|
@@ -239,13 +240,13 @@ export const define = (schemas) => (definition) => {
|
|
|
239
240
|
})), Array.map(edgeSummary => makeDeadTransition(edgeSummary, 'ShadowedByOtherwise'))),
|
|
240
241
|
});
|
|
241
242
|
}));
|
|
242
|
-
const deadTransitions = () => {
|
|
243
|
-
const reachable =
|
|
243
|
+
const deadTransitions = (extraRoots = []) => {
|
|
244
|
+
const reachable = reachableFromRoots([initialTag, ...extraRoots]);
|
|
244
245
|
const unreachableSourceEdges = pipe(edges, Array.filter(edgeSummary => !reachable.has(edgeSummary.from)), Array.map(edgeSummary => makeDeadTransition(edgeSummary, 'UnreachableSource')));
|
|
245
246
|
return [...unreachableSourceEdges, ...shadowedEdges()];
|
|
246
247
|
};
|
|
247
248
|
const toMermaid = () => {
|
|
248
|
-
const guardLabel = (guard) =>
|
|
249
|
+
const guardLabel = (guard) => Match.value(guard).pipe(Match.tagsExhaustive({
|
|
249
250
|
Unguarded: () => '',
|
|
250
251
|
When: ({ position }) => ` [when ${position + 1}]`,
|
|
251
252
|
Otherwise: () => ' [otherwise]',
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { Match
|
|
1
|
+
import { Match } from 'effect';
|
|
2
2
|
import { injectIntoTemplate, } from './template.js';
|
|
3
3
|
/** Constructs a rendered server entry result with optional HTTP status and
|
|
4
4
|
* headers.
|
|
@@ -26,7 +26,7 @@ export const Responded = (response) => ({
|
|
|
26
26
|
*
|
|
27
27
|
* @experimental Ships from `foldkit/experimental/server`; expect breaking changes while the API settles.
|
|
28
28
|
*/
|
|
29
|
-
export const toResponse = (template, result, options) =>
|
|
29
|
+
export const toResponse = (template, result, options) => Match.value(result).pipe(Match.tagsExhaustive({
|
|
30
30
|
Responded: ({ response }) => response,
|
|
31
31
|
Rendered: rendered => {
|
|
32
32
|
const headers = new Headers(rendered.headers);
|