foldkit 0.33.4 → 0.33.6
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
CHANGED
|
@@ -64,7 +64,7 @@ const ClickedIncrement = m('ClickedIncrement')
|
|
|
64
64
|
const ClickedReset = m('ClickedReset')
|
|
65
65
|
|
|
66
66
|
const Message = S.Union(ClickedDecrement, ClickedIncrement, ClickedReset)
|
|
67
|
-
|
|
67
|
+
type Message = typeof Message.Type
|
|
68
68
|
|
|
69
69
|
// UPDATE
|
|
70
70
|
|
|
@@ -142,6 +142,7 @@ Foldkit is a complete system, not a collection of libraries you stitch together.
|
|
|
142
142
|
- **UI Components** — Dialog, menu, tabs, listbox, disclosure — fully accessible primitives that are easy to style and customize.
|
|
143
143
|
- **Field Validation** — Per-field validation state modeled as a discriminated union. Define rules as data, apply them in update, and the Model tracks the result.
|
|
144
144
|
- **Virtual DOM** — Declarative Views powered by [Snabbdom](https://github.com/snabbdom/snabbdom). Fast, keyed diffing. Views are plain functions of your Model.
|
|
145
|
+
- **DevTools** — Built-in overlay for inspecting Messages and Model state. Time-travel mode lets you jump to any point in your app's history.
|
|
145
146
|
- **HMR** — Vite plugin with state-preserving hot module replacement. Change your view, keep your state.
|
|
146
147
|
|
|
147
148
|
## Correctness You (And Your LLM) Can See
|
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
declare const overlayStyles = ":host {\n --dt-bg: #1e1e2e;\n --dt-surface-selected: #282839;\n --dt-border: #
|
|
1
|
+
declare const overlayStyles = ":host {\n --dt-bg: #1e1e2e;\n --dt-surface-selected: #282839;\n --dt-border: #45475a;\n --dt-text: #cdd6f4;\n --dt-text-muted: #9399b2;\n --dt-accent: #cba6f7;\n --dt-live: #a6e3a1;\n --dt-paused: #fab387;\n --dt-json-string: #a6e3a1;\n --dt-json-number: #89b4fa;\n --dt-json-boolean: #fab387;\n --dt-json-null: #9399b2;\n --dt-json-key: #89dceb;\n --dt-json-tag: #cba6f7;\n --dt-json-preview: #9399b2;\n --dt-json-arrow: #9399b2;\n --dt-tree-hover: #313244;\n --dt-diff-changed: #74c7ec;\n}\n\n*,\n*::before,\n*::after {\n box-sizing: border-box;\n margin: 0;\n padding: 0;\n}\nbutton {\n font: inherit;\n color: inherit;\n}\nul {\n list-style: none;\n}\n\n.fixed {\n position: fixed;\n}\n.flex {\n display: flex;\n}\n.flex-col {\n flex-direction: column;\n}\n.flex-1 {\n flex: 1 1 0%;\n}\n.items-center {\n align-items: center;\n}\n.justify-center {\n justify-content: center;\n}\n.justify-between {\n justify-content: space-between;\n}\n.shrink-0 {\n flex-shrink: 0;\n}\n.inline-block {\n display: inline-block;\n}\n.gap-0\\.5 {\n gap: 2px;\n}\n.gap-1\\.5 {\n gap: 6px;\n}\n.gap-2 {\n gap: 8px;\n}\n.gap-px {\n gap: 1px;\n}\n.px-1 {\n padding-left: 4px;\n padding-right: 4px;\n}\n.px-2 {\n padding-left: 8px;\n padding-right: 8px;\n}\n.px-2\\.5 {\n padding-left: 10px;\n padding-right: 10px;\n}\n.p-3 {\n padding: 12px;\n}\n.px-3 {\n padding-left: 12px;\n padding-right: 12px;\n}\n.py-0\\.5 {\n padding-top: 2px;\n padding-bottom: 2px;\n}\n.pt-1 {\n padding-top: 4px;\n}\n.pl-1 {\n padding-left: 4px;\n}\n.py-1 {\n padding-top: 4px;\n padding-bottom: 4px;\n}\n.py-1\\.5 {\n padding-top: 6px;\n padding-bottom: 6px;\n}\n.py-2 {\n padding-top: 8px;\n padding-bottom: 8px;\n}\n.py-px {\n padding-top: 1px;\n padding-bottom: 1px;\n}\n.w-1\\.5 {\n width: 6px;\n}\n.h-1\\.5 {\n height: 6px;\n}\n.w-3 {\n width: 12px;\n}\n.w-5 {\n width: 20px;\n}\n.h-5 {\n height: 20px;\n}\n.w-14 {\n width: 56px;\n}\n.h-14 {\n height: 56px;\n}\n.min-w-0 {\n min-width: 0;\n}\n.min-w-5 {\n min-width: 20px;\n}\n.min-h-0 {\n min-height: 0;\n}\n/* Badge positions \u2014 flush against side edge */\n.dt-pos-br {\n bottom: 16px;\n right: 0;\n border-radius: 6px 0 0 6px;\n}\n.dt-pos-bl {\n bottom: 16px;\n left: 0;\n border-radius: 0 6px 6px 0;\n}\n.dt-pos-tr {\n top: 16px;\n right: 0;\n border-radius: 6px 0 0 6px;\n}\n.dt-pos-tl {\n top: 16px;\n left: 0;\n border-radius: 0 6px 6px 0;\n}\n.overflow-hidden {\n overflow: hidden;\n}\n.overflow-auto {\n overflow: auto;\n}\n.overflow-y-auto {\n overflow-y: auto;\n}\n.overscroll-none {\n overscroll-behavior: none;\n}\n\n.truncate {\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n}\n.rounded {\n border-radius: 4px;\n}\n.rounded-lg {\n border-radius: 8px;\n}\n.rounded-full {\n border-radius: 9999px;\n}\n.border {\n border-width: 1px;\n border-style: solid;\n border-color: var(--dt-border);\n}\n.border-b {\n border-bottom: 1px solid var(--dt-border);\n}\n.border-t {\n border-top: 1px solid var(--dt-border);\n}\n.border-r {\n border-right: 1px solid var(--dt-border);\n}\n.border-l {\n border-left: 1px solid var(--dt-border);\n}\n.border-none {\n border: none;\n}\n.border-l-3 {\n border-left: 3px solid transparent;\n}\n.border-dt-live {\n border-color: var(--dt-live);\n}\n.selected {\n background-color: var(--dt-surface-selected);\n}\n.dt-row:hover:not(.selected) {\n background-color: var(--dt-tree-hover);\n}\n.dt-header-button:hover {\n color: var(--dt-text);\n}\n.dt-resume-button:hover {\n opacity: 0.7;\n}\n.dt-tab-button {\n position: relative;\n background: transparent;\n border: none;\n border-right: 1px solid var(--dt-border);\n outline: none;\n flex: 1;\n}\n.dt-tab-button:last-child {\n border-right: none;\n}\n.dt-tab-active {\n background-color: var(--dt-surface-selected);\n}\n.dt-tab-button:not(.dt-tab-active):hover {\n color: var(--dt-text);\n background-color: rgba(49, 50, 68, 0.3);\n}\n.font-sans {\n font-family:\n system-ui,\n -apple-system,\n BlinkMacSystemFont,\n 'Segoe UI',\n Roboto,\n sans-serif;\n}\n.font-mono {\n font-family:\n ui-monospace, SFMono-Regular, 'SF Mono', Menlo, Consolas, monospace;\n}\n.font-medium {\n font-weight: 500;\n}\n.font-semibold {\n font-weight: 600;\n}\n.text-xs {\n font-size: 12px;\n}\n.text-2xs {\n font-size: 10px;\n}\n.text-sm {\n font-size: 11px;\n}\n.text-base {\n font-size: 13px;\n}\n.text-md {\n font-size: 15px;\n}\n.text-lg {\n font-size: 20px;\n}\n.text-xl {\n font-size: 26px;\n}\n.italic {\n font-style: italic;\n}\n.text-right {\n text-align: right;\n}\n.tracking-wide {\n letter-spacing: 0.025em;\n}\n.tracking-wider {\n letter-spacing: 0.05em;\n}\n.leading-none {\n line-height: 1;\n}\n.leading-snug {\n line-height: 1.35;\n}\n.bg-dt-bg {\n background-color: var(--dt-bg);\n}\n.bg-dt-live {\n background-color: var(--dt-live);\n}\n.bg-transparent {\n background-color: transparent;\n}\n.text-dt {\n color: var(--dt-text);\n}\n.text-dt-bg {\n color: var(--dt-bg);\n}\n.text-dt-muted {\n color: var(--dt-text-muted);\n}\n.text-dt-accent {\n color: var(--dt-accent);\n}\n.text-dt-live {\n color: var(--dt-live);\n}\n.text-dt-paused {\n color: var(--dt-paused);\n}\n.cursor-pointer {\n cursor: pointer;\n}\n.outline-none {\n outline: none;\n}\n.transition-colors {\n transition-property: color, background-color, border-color;\n transition-duration: 100ms;\n transition-timing-function: ease;\n}\n\n/* Panel */\n.dt-panel {\n width: 360px;\n height: 480px;\n box-shadow: 0 8px 32px rgba(0, 0, 0, 0.5);\n z-index: 99998;\n}\n/* Panel positions */\n.dt-panel-br {\n bottom: 16px;\n right: 28px;\n}\n.dt-panel-bl {\n bottom: 16px;\n left: 28px;\n}\n.dt-panel-tr {\n top: 16px;\n right: 28px;\n}\n.dt-panel-tl {\n top: 16px;\n left: 28px;\n}\n.dt-panel-wide {\n width: 720px;\n}\n.dt-message-pane {\n width: 320px;\n flex-shrink: 0;\n}\n.dt-badge {\n z-index: 99999;\n box-shadow: -2px 0 8px rgba(0, 0, 0, 0.3);\n transition: background-color 150ms ease;\n border: 1px solid var(--dt-border);\n}\n.dt-badge-accent:hover {\n background-color: #252538;\n}\n.dt-badge-paused {\n background-color: var(--dt-paused);\n color: var(--dt-bg);\n border: none;\n}\n.dt-badge-paused:hover {\n background-color: #e0a070;\n}\n.dt-badge.dt-pos-br,\n.dt-badge.dt-pos-tr {\n border-right: none;\n}\n.dt-badge.dt-pos-bl,\n.dt-badge.dt-pos-tl {\n border-left: none;\n}\n\n/* JSON tree */\n.tree-row {\n position: relative;\n white-space: nowrap;\n line-height: 18px;\n padding-right: 8px;\n}\n.tree-row-expandable:hover {\n background-color: var(--dt-tree-hover);\n}\n.inspector-tree {\n font-family:\n ui-monospace, SFMono-Regular, 'SF Mono', Menlo, Consolas, monospace;\n}\n.json-key {\n color: var(--dt-json-key);\n}\n.json-string {\n color: var(--dt-json-string);\n}\n.json-number {\n color: var(--dt-json-number);\n}\n.json-boolean {\n color: var(--dt-json-boolean);\n}\n.json-null {\n color: var(--dt-json-null);\n}\n.json-tag {\n color: var(--dt-json-tag);\n margin-right: 4px;\n}\n.json-preview {\n color: var(--dt-json-preview);\n}\n.json-arrow {\n color: var(--dt-json-arrow);\n width: 10px;\n height: 10px;\n user-select: none;\n}\n\n/* Diff */\n.diff-changed {\n background-color: rgba(116, 199, 236, 0.06);\n}\n.diff-dot {\n position: absolute;\n left: 3px;\n width: 5px;\n height: 5px;\n border-radius: 9999px;\n background-color: var(--dt-diff-changed);\n}\n.diff-dot-inline {\n width: 5px;\n height: 5px;\n border-radius: 9999px;\n background-color: var(--dt-diff-changed);\n flex-shrink: 0;\n}\n.dot-column {\n width: 5px;\n flex-shrink: 0;\n display: flex;\n align-items: center;\n justify-content: center;\n}\n.pause-column {\n width: 8px;\n flex-shrink: 0;\n display: flex;\n align-items: center;\n justify-content: center;\n}\n.dt-pause-icon {\n width: 8px;\n height: 8px;\n color: var(--dt-paused);\n}\n\n/* Interaction blocker \u2014 covers the app while time-travelling */\n.dt-interaction-blocker {\n position: fixed;\n inset: 0;\n z-index: 99997;\n cursor: not-allowed;\n}\n\n/* Mobile */\n@media (max-width: 767px) {\n .dt-panel {\n top: 0;\n left: 0;\n right: 0;\n bottom: 0;\n width: 100%;\n height: 100%;\n border-radius: 0;\n border: none;\n }\n .dt-panel-wide {\n width: 100%;\n }\n .dt-content {\n flex-direction: column;\n }\n .dt-message-pane {\n width: 100%;\n max-height: 40%;\n border-bottom: 1px solid var(--dt-border);\n }\n .message-list > :last-child {\n border-bottom: none;\n }\n .dt-inspector-pane {\n border-left: none;\n }\n}\n";
|
|
2
2
|
export { overlayStyles };
|
|
3
3
|
//# sourceMappingURL=overlay-styles.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"overlay-styles.d.ts","sourceRoot":"","sources":["../../src/devtools/overlay-styles.ts"],"names":[],"mappings":"AAAA,QAAA,MAAM,aAAa,
|
|
1
|
+
{"version":3,"file":"overlay-styles.d.ts","sourceRoot":"","sources":["../../src/devtools/overlay-styles.ts"],"names":[],"mappings":"AAAA,QAAA,MAAM,aAAa,k/QAghBlB,CAAA;AAED,OAAO,EAAE,aAAa,EAAE,CAAA"}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
const overlayStyles = `:host {
|
|
2
2
|
--dt-bg: #1e1e2e;
|
|
3
3
|
--dt-surface-selected: #282839;
|
|
4
|
-
--dt-border: #
|
|
4
|
+
--dt-border: #45475a;
|
|
5
5
|
--dt-text: #cdd6f4;
|
|
6
6
|
--dt-text-muted: #9399b2;
|
|
7
7
|
--dt-accent: #cba6f7;
|
|
@@ -178,6 +178,9 @@ ul {
|
|
|
178
178
|
.overflow-y-auto {
|
|
179
179
|
overflow-y: auto;
|
|
180
180
|
}
|
|
181
|
+
.overscroll-none {
|
|
182
|
+
overscroll-behavior: none;
|
|
183
|
+
}
|
|
181
184
|
|
|
182
185
|
.truncate {
|
|
183
186
|
overflow: hidden;
|
|
@@ -239,6 +242,9 @@ ul {
|
|
|
239
242
|
outline: none;
|
|
240
243
|
flex: 1;
|
|
241
244
|
}
|
|
245
|
+
.dt-tab-button:last-child {
|
|
246
|
+
border-right: none;
|
|
247
|
+
}
|
|
242
248
|
.dt-tab-active {
|
|
243
249
|
background-color: var(--dt-surface-selected);
|
|
244
250
|
}
|
|
@@ -316,6 +322,9 @@ ul {
|
|
|
316
322
|
.text-dt {
|
|
317
323
|
color: var(--dt-text);
|
|
318
324
|
}
|
|
325
|
+
.text-dt-bg {
|
|
326
|
+
color: var(--dt-bg);
|
|
327
|
+
}
|
|
319
328
|
.text-dt-muted {
|
|
320
329
|
color: var(--dt-text-muted);
|
|
321
330
|
}
|
|
@@ -383,6 +392,7 @@ ul {
|
|
|
383
392
|
.dt-badge-paused {
|
|
384
393
|
background-color: var(--dt-paused);
|
|
385
394
|
color: var(--dt-bg);
|
|
395
|
+
border: none;
|
|
386
396
|
}
|
|
387
397
|
.dt-badge-paused:hover {
|
|
388
398
|
background-color: #e0a070;
|
|
@@ -509,6 +519,9 @@ ul {
|
|
|
509
519
|
max-height: 40%;
|
|
510
520
|
border-bottom: 1px solid var(--dt-border);
|
|
511
521
|
}
|
|
522
|
+
.message-list > :last-child {
|
|
523
|
+
border-bottom: none;
|
|
524
|
+
}
|
|
512
525
|
.dt-inspector-pane {
|
|
513
526
|
border-left: none;
|
|
514
527
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"overlay.d.ts","sourceRoot":"","sources":["../../src/devtools/overlay.ts"],"names":[],"mappings":"AACA,OAAO,EAEL,MAAM,EAIN,MAAM,EAQP,MAAM,QAAQ,CAAA;AAOf,OAAO,KAAK,EAAE,YAAY,EAAE,gBAAgB,EAAE,MAAM,oBAAoB,CAAA;AAMxE,OAAO,EAAE,KAAK,aAAa,EAA+B,MAAM,SAAS,CAAA;
|
|
1
|
+
{"version":3,"file":"overlay.d.ts","sourceRoot":"","sources":["../../src/devtools/overlay.ts"],"names":[],"mappings":"AACA,OAAO,EAEL,MAAM,EAIN,MAAM,EAQP,MAAM,QAAQ,CAAA;AAOf,OAAO,KAAK,EAAE,YAAY,EAAE,gBAAgB,EAAE,MAAM,oBAAoB,CAAA;AAMxE,OAAO,EAAE,KAAK,aAAa,EAA+B,MAAM,SAAS,CAAA;AA4wCzE,eAAO,MAAM,aAAa,GACxB,OAAO,aAAa,EACpB,UAAU,gBAAgB,EAC1B,MAAM,YAAY,EAClB,aAAa,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,sCA4ChC,CAAA"}
|
package/dist/devtools/overlay.js
CHANGED
|
@@ -438,7 +438,9 @@ const makeView = (position, mode, maybeBanner) => {
|
|
|
438
438
|
const treeView = (value, rootPath, expandedPaths, changedPaths, affectedPaths, maybeRootLabel, indentRootChildren) => {
|
|
439
439
|
const nodes = [];
|
|
440
440
|
flattenTree(value, rootPath, expandedPaths, changedPaths, affectedPaths, 0, maybeRootLabel, nodes, indentRootChildren);
|
|
441
|
-
return div([
|
|
441
|
+
return div([
|
|
442
|
+
Class('inspector-tree flex-1 overflow-auto min-h-0 min-w-0 overscroll-none'),
|
|
443
|
+
], nodes.map(flatNodeView));
|
|
442
444
|
};
|
|
443
445
|
const inspectedTimestamp = (model) => {
|
|
444
446
|
const lastIndex = Array_.isEmptyReadonlyArray(model.entries)
|
|
@@ -481,7 +483,9 @@ const makeView = (position, mode, maybeBanner) => {
|
|
|
481
483
|
]),
|
|
482
484
|
});
|
|
483
485
|
const inspectorTabContent = (model, tab, inspectedModel) => M.value(tab).pipe(M.when('Model', () => modelTabContent(model, inspectedModel)), M.when('Message', () => messageTabContent(model)), M.exhaustive);
|
|
484
|
-
const inspectorPaneView = (model) => div([
|
|
486
|
+
const inspectorPaneView = (model) => div([
|
|
487
|
+
Class('flex flex-col border-l min-w-0 min-h-0 flex-1 dt-inspector-pane'),
|
|
488
|
+
], [
|
|
485
489
|
Tabs.view({
|
|
486
490
|
model: model.inspectorTabs,
|
|
487
491
|
toMessage: tabsMessage => GotInspectorTabsMessage({ message: tabsMessage }),
|
|
@@ -522,7 +526,7 @@ const makeView = (position, mode, maybeBanner) => {
|
|
|
522
526
|
], []),
|
|
523
527
|
])
|
|
524
528
|
: div([
|
|
525
|
-
Class('flex flex-col items-center gap-0.5
|
|
529
|
+
Class(clsx('flex flex-col items-center gap-0.5 font-semibold tracking-wider leading-none', model.isPaused ? 'text-dt-bg' : 'text-dt-muted')),
|
|
526
530
|
], [span([], ['D']), span([], ['E']), span([], ['V'])]),
|
|
527
531
|
]);
|
|
528
532
|
const headerClass = 'flex items-center justify-between px-3 py-1.5 border-b shrink-0';
|
|
@@ -606,7 +610,7 @@ const makeView = (position, mode, maybeBanner) => {
|
|
|
606
610
|
const isPausedHere = model.isPaused && model.pausedAtIndex === absoluteIndex;
|
|
607
611
|
return messageRowView(entry.tag, absoluteIndex, isSelected, isPausedHere, entry.timestamp - baseTimestamp, entry.isModelChanged);
|
|
608
612
|
}), Array_.reverse);
|
|
609
|
-
return ul([Class('message-list flex-1 overflow-y-auto min-h-0')], [
|
|
613
|
+
return ul([Class('message-list flex-1 overflow-y-auto min-h-0 overscroll-none')], [
|
|
610
614
|
...messageRows,
|
|
611
615
|
initRowView(isInitSelected, model.isPaused && model.pausedAtIndex === INIT_INDEX),
|
|
612
616
|
]);
|