@foldkit/devtools 0.122.0 → 0.123.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 +1 -1
- package/dist/overlay-styles.d.ts +1 -1
- package/dist/overlay-styles.d.ts.map +1 -1
- package/dist/overlay-styles.js +104 -2
- package/dist/overlay.d.ts +5 -0
- package/dist/overlay.d.ts.map +1 -1
- package/dist/overlay.js +189 -32
- package/package.json +6 -4
package/README.md
CHANGED
|
@@ -14,7 +14,7 @@ npm install @foldkit/devtools
|
|
|
14
14
|
yarn add @foldkit/devtools
|
|
15
15
|
```
|
|
16
16
|
|
|
17
|
-
`@foldkit/devtools` lists `foldkit`, `@foldkit/ui`, and
|
|
17
|
+
`@foldkit/devtools` lists `foldkit`, `@foldkit/ui`, `effect`, and `@effect/platform-browser` as peer dependencies, so install those alongside it.
|
|
18
18
|
|
|
19
19
|
## Usage
|
|
20
20
|
|
package/dist/overlay-styles.d.ts
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
export declare const overlayStyles = ":host {\n position: relative;\n z-index: 2147483647;\n\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-3 {\n gap: 12px;\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.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-scroll-pill {\n display: flex;\n align-items: center;\n justify-content: center;\n gap: 6px;\n flex-shrink: 0;\n padding: 4px 12px;\n background-color: var(--dt-surface-selected);\n border: none;\n border-bottom: 1px solid var(--dt-border);\n color: var(--dt-accent);\n font-family:\n ui-monospace, SFMono-Regular, 'SF Mono', Menlo, Consolas, monospace;\n font-size: 13px;\n cursor: pointer;\n}\n.dt-scroll-pill-icon {\n width: 12px;\n height: 12px;\n}\n.dt-scroll-pill-text {\n margin-top: 1px;\n}\n.dt-scroll-pill:hover {\n background-color: var(--dt-tree-hover);\n}\n.dt-scroll-pill:focus-visible {\n outline: 1px solid var(--dt-accent);\n outline-offset: -1px;\n}\n.dt-filter-wrapper {\n position: relative;\n flex-shrink: 0;\n border-bottom: 1px solid var(--dt-border);\n}\n.dt-filter-button {\n width: 100%;\n display: flex;\n align-items: center;\n justify-content: space-between;\n padding: 6px 12px;\n background: transparent;\n border: none;\n color: var(--dt-text-muted);\n font-family:\n ui-monospace, SFMono-Regular, 'SF Mono', Menlo, Consolas, monospace;\n font-size: 13px;\n cursor: pointer;\n text-align: left;\n}\n.dt-filter-button:hover {\n color: var(--dt-text);\n background-color: var(--dt-tree-hover);\n}\n.dt-filter-button:focus-visible {\n outline: 1px solid var(--dt-accent);\n outline-offset: -1px;\n}\n.dt-filter-button[data-open] {\n color: var(--dt-text);\n background-color: var(--dt-surface-selected);\n}\n.dt-filter-button[data-open]:hover {\n background-color: var(--dt-tree-hover);\n}\n.dt-filter-button[data-open] .json-arrow {\n transform: rotate(180deg);\n}\n.dt-filter-items {\n position: absolute;\n width: var(--button-width);\n background-color: var(--dt-bg);\n border-top: 1px solid var(--dt-border);\n border-bottom: 1px solid var(--dt-border);\n z-index: 100000;\n max-height: 200px;\n overflow-y: auto;\n outline: none;\n}\n.dt-filter-item {\n padding: 6px 12px;\n color: var(--dt-text-muted);\n cursor: pointer;\n font-family:\n ui-monospace, SFMono-Regular, 'SF Mono', Menlo, Consolas, monospace;\n font-size: 13px;\n border-bottom: 1px solid var(--dt-border);\n}\n.dt-filter-item:last-child {\n border-bottom: none;\n}\n.dt-filter-item[data-active] {\n background-color: var(--dt-tree-hover);\n color: var(--dt-text);\n}\n.dt-filter-item[data-selected] {\n color: var(--dt-accent);\n}\n.dt-filter-check {\n width: 12px;\n height: 12px;\n visibility: hidden;\n}\n.dt-filter-item[data-selected] .dt-filter-check {\n visibility: visible;\n color: var(--dt-accent);\n}\n.dt-filter-backdrop {\n position: fixed;\n inset: 0;\n pointer-events: none;\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/* Scrubber */\n.dt-scrubber-row {\n background-color: var(--dt-bg);\n}\n.dt-scrubber-control {\n position: relative;\n height: 16px;\n width: 100%;\n padding: 0 7px;\n display: flex;\n align-items: center;\n}\n.dt-scrubber-track {\n width: 100%;\n height: 4px;\n background-color: var(--dt-border);\n border-radius: 9999px;\n cursor: pointer;\n}\n.dt-scrubber-track[data-disabled] {\n cursor: not-allowed;\n}\n.dt-scrubber-fill {\n height: 100%;\n background-color: var(--dt-accent);\n border-radius: 9999px;\n}\n.dt-scrubber-thumb {\n width: 14px;\n height: 14px;\n border-radius: 9999px;\n background-color: var(--dt-accent);\n border: 2px solid var(--dt-bg);\n cursor: grab;\n outline: none;\n top: 50%;\n margin-top: -7px;\n box-shadow: 0 1px 3px rgba(0, 0, 0, 0.4);\n}\n.dt-scrubber-thumb:focus-visible {\n outline: 2px solid var(--dt-text);\n outline-offset: 2px;\n}\n.dt-scrubber-thumb[data-dragging] {\n cursor: grabbing;\n}\n.dt-scrubber-position {\n width: 72px;\n padding-left: 12px;\n border-left: 1px solid var(--dt-border);\n align-self: stretch;\n margin-top: -8px;\n margin-bottom: -8px;\n display: flex;\n align-items: center;\n justify-content: center;\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 .dt-badge.dt-pos-br,\n .dt-badge.dt-pos-bl {\n bottom: 44px;\n }\n}\n";
|
|
1
|
+
export declare const overlayStyles = ":host {\n position: relative;\n z-index: 2147483647;\n\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-3 {\n gap: 12px;\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.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-scroll-pill {\n display: flex;\n align-items: center;\n justify-content: center;\n gap: 6px;\n flex-shrink: 0;\n padding: 4px 12px;\n background-color: var(--dt-surface-selected);\n border: none;\n border-bottom: 1px solid var(--dt-border);\n color: var(--dt-accent);\n font-family:\n ui-monospace, SFMono-Regular, 'SF Mono', Menlo, Consolas, monospace;\n font-size: 13px;\n cursor: pointer;\n}\n.dt-scroll-pill-icon {\n width: 12px;\n height: 12px;\n}\n.dt-scroll-pill-text {\n margin-top: 1px;\n}\n.dt-scroll-pill:hover {\n background-color: var(--dt-tree-hover);\n}\n.dt-scroll-pill:focus-visible {\n outline: 1px solid var(--dt-accent);\n outline-offset: -1px;\n}\n.dt-filter-wrapper {\n position: relative;\n flex-shrink: 0;\n border-bottom: 1px solid var(--dt-border);\n}\n.dt-filter-button {\n width: 100%;\n display: flex;\n align-items: center;\n justify-content: space-between;\n padding: 6px 12px;\n background: transparent;\n border: none;\n color: var(--dt-text-muted);\n font-family:\n ui-monospace, SFMono-Regular, 'SF Mono', Menlo, Consolas, monospace;\n font-size: 13px;\n cursor: pointer;\n text-align: left;\n}\n.dt-filter-button:hover {\n color: var(--dt-text);\n background-color: var(--dt-tree-hover);\n}\n.dt-filter-button:focus-visible {\n outline: 1px solid var(--dt-accent);\n outline-offset: -1px;\n}\n.dt-filter-button[data-open] {\n color: var(--dt-text);\n background-color: var(--dt-surface-selected);\n}\n.dt-filter-button[data-open]:hover {\n background-color: var(--dt-tree-hover);\n}\n.dt-filter-button[data-open] .json-arrow {\n transform: rotate(180deg);\n}\n.dt-filter-items {\n position: absolute;\n width: var(--button-width);\n background-color: var(--dt-bg);\n border-top: 1px solid var(--dt-border);\n border-bottom: 1px solid var(--dt-border);\n z-index: 100000;\n max-height: 200px;\n overflow-y: auto;\n outline: none;\n}\n.dt-filter-item {\n padding: 6px 12px;\n color: var(--dt-text-muted);\n cursor: pointer;\n font-family:\n ui-monospace, SFMono-Regular, 'SF Mono', Menlo, Consolas, monospace;\n font-size: 13px;\n border-bottom: 1px solid var(--dt-border);\n}\n.dt-filter-item:last-child {\n border-bottom: none;\n}\n.dt-filter-item[data-active] {\n background-color: var(--dt-tree-hover);\n color: var(--dt-text);\n}\n.dt-filter-item[data-selected] {\n color: var(--dt-accent);\n}\n.dt-filter-check {\n width: 12px;\n height: 12px;\n visibility: hidden;\n}\n.dt-filter-item[data-selected] .dt-filter-check {\n visibility: visible;\n color: var(--dt-accent);\n}\n.dt-filter-backdrop {\n position: fixed;\n inset: 0;\n pointer-events: none;\n}\n.dt-settings-button {\n display: flex;\n align-items: center;\n justify-content: center;\n align-self: stretch;\n margin: -8px 0 -8px -12px;\n padding: 0 12px;\n background: transparent;\n border: none;\n border-right: 1px solid var(--dt-border);\n color: var(--dt-text-muted);\n cursor: pointer;\n flex-shrink: 0;\n}\n.dt-settings-button:hover {\n color: var(--dt-text);\n background-color: var(--dt-tree-hover);\n}\n.dt-settings-button:focus-visible {\n outline: 1px solid var(--dt-accent);\n outline-offset: -1px;\n}\n.dt-settings-button-active {\n color: var(--dt-accent);\n background-color: var(--dt-surface-selected);\n}\n.dt-settings-button-active:hover {\n background-color: var(--dt-tree-hover);\n}\n.dt-settings-icon {\n width: 14px;\n height: 14px;\n}\n.dt-settings-section-title {\n padding: 10px 12px 4px;\n color: var(--dt-text-muted);\n font-size: 10px;\n letter-spacing: 0.08em;\n text-transform: uppercase;\n}\n.dt-settings-row {\n display: flex;\n align-items: center;\n gap: 20px;\n padding: 8px 12px;\n}\n.dt-settings-row-text {\n display: flex;\n flex-direction: column;\n gap: 2px;\n min-width: 0;\n}\n.dt-settings-row-label {\n color: var(--dt-text);\n font-size: 13px;\n cursor: pointer;\n}\n.dt-settings-row-description {\n color: var(--dt-text-muted);\n font-size: 10px;\n}\n.dt-switch {\n position: relative;\n width: 36px;\n height: 20px;\n border-radius: 9999px;\n background-color: var(--dt-border);\n cursor: pointer;\n flex-shrink: 0;\n transition:\n background-color 100ms ease,\n filter 100ms ease;\n}\n.dt-switch:hover {\n filter: brightness(1.2);\n}\n.dt-switch:focus-visible {\n outline: 1px solid var(--dt-accent);\n outline-offset: 2px;\n}\n.dt-switch[data-checked] {\n background-color: var(--dt-accent);\n}\n.dt-switch-thumb {\n position: absolute;\n top: 2px;\n left: 2px;\n width: 16px;\n height: 16px;\n border-radius: 9999px;\n background-color: var(--dt-text-muted);\n transition:\n transform 100ms ease,\n background-color 100ms ease;\n}\n.dt-switch[data-checked] .dt-switch-thumb {\n transform: translateX(16px);\n background-color: var(--dt-bg);\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/* Footer */\n.dt-footer {\n background-color: var(--dt-bg);\n height: 33px;\n}\n\n/* Scrubber */\n.dt-scrubber-control {\n position: relative;\n height: 16px;\n width: 100%;\n padding: 0 7px;\n display: flex;\n align-items: center;\n}\n.dt-scrubber-track {\n width: 100%;\n height: 4px;\n background-color: var(--dt-border);\n border-radius: 9999px;\n cursor: pointer;\n}\n.dt-scrubber-track[data-disabled] {\n cursor: not-allowed;\n}\n.dt-scrubber-fill {\n height: 100%;\n background-color: var(--dt-accent);\n border-radius: 9999px;\n}\n.dt-scrubber-thumb {\n width: 14px;\n height: 14px;\n border-radius: 9999px;\n background-color: var(--dt-accent);\n border: 2px solid var(--dt-bg);\n cursor: grab;\n outline: none;\n top: 50%;\n margin-top: -7px;\n box-shadow: 0 1px 3px rgba(0, 0, 0, 0.4);\n}\n.dt-scrubber-thumb:focus-visible {\n outline: 2px solid var(--dt-text);\n outline-offset: 2px;\n}\n.dt-scrubber-thumb[data-dragging] {\n cursor: grabbing;\n}\n.dt-scrubber-position {\n width: 72px;\n padding-left: 12px;\n border-left: 1px solid var(--dt-border);\n align-self: stretch;\n margin-top: -8px;\n margin-bottom: -8px;\n display: flex;\n align-items: center;\n justify-content: center;\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 .dt-badge.dt-pos-br,\n .dt-badge.dt-pos-bl {\n bottom: 44px;\n }\n}\n";
|
|
2
2
|
//# sourceMappingURL=overlay-styles.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"overlay-styles.d.ts","sourceRoot":"","sources":["../src/overlay-styles.ts"],"names":[],"mappings":"AAAA,eAAO,MAAM,aAAa,
|
|
1
|
+
{"version":3,"file":"overlay-styles.d.ts","sourceRoot":"","sources":["../src/overlay-styles.ts"],"names":[],"mappings":"AAAA,eAAO,MAAM,aAAa,o+cAoyBzB,CAAA"}
|
package/dist/overlay-styles.js
CHANGED
|
@@ -346,6 +346,105 @@ ul {
|
|
|
346
346
|
inset: 0;
|
|
347
347
|
pointer-events: none;
|
|
348
348
|
}
|
|
349
|
+
.dt-settings-button {
|
|
350
|
+
display: flex;
|
|
351
|
+
align-items: center;
|
|
352
|
+
justify-content: center;
|
|
353
|
+
align-self: stretch;
|
|
354
|
+
margin: -8px 0 -8px -12px;
|
|
355
|
+
padding: 0 12px;
|
|
356
|
+
background: transparent;
|
|
357
|
+
border: none;
|
|
358
|
+
border-right: 1px solid var(--dt-border);
|
|
359
|
+
color: var(--dt-text-muted);
|
|
360
|
+
cursor: pointer;
|
|
361
|
+
flex-shrink: 0;
|
|
362
|
+
}
|
|
363
|
+
.dt-settings-button:hover {
|
|
364
|
+
color: var(--dt-text);
|
|
365
|
+
background-color: var(--dt-tree-hover);
|
|
366
|
+
}
|
|
367
|
+
.dt-settings-button:focus-visible {
|
|
368
|
+
outline: 1px solid var(--dt-accent);
|
|
369
|
+
outline-offset: -1px;
|
|
370
|
+
}
|
|
371
|
+
.dt-settings-button-active {
|
|
372
|
+
color: var(--dt-accent);
|
|
373
|
+
background-color: var(--dt-surface-selected);
|
|
374
|
+
}
|
|
375
|
+
.dt-settings-button-active:hover {
|
|
376
|
+
background-color: var(--dt-tree-hover);
|
|
377
|
+
}
|
|
378
|
+
.dt-settings-icon {
|
|
379
|
+
width: 14px;
|
|
380
|
+
height: 14px;
|
|
381
|
+
}
|
|
382
|
+
.dt-settings-section-title {
|
|
383
|
+
padding: 10px 12px 4px;
|
|
384
|
+
color: var(--dt-text-muted);
|
|
385
|
+
font-size: 10px;
|
|
386
|
+
letter-spacing: 0.08em;
|
|
387
|
+
text-transform: uppercase;
|
|
388
|
+
}
|
|
389
|
+
.dt-settings-row {
|
|
390
|
+
display: flex;
|
|
391
|
+
align-items: center;
|
|
392
|
+
gap: 20px;
|
|
393
|
+
padding: 8px 12px;
|
|
394
|
+
}
|
|
395
|
+
.dt-settings-row-text {
|
|
396
|
+
display: flex;
|
|
397
|
+
flex-direction: column;
|
|
398
|
+
gap: 2px;
|
|
399
|
+
min-width: 0;
|
|
400
|
+
}
|
|
401
|
+
.dt-settings-row-label {
|
|
402
|
+
color: var(--dt-text);
|
|
403
|
+
font-size: 13px;
|
|
404
|
+
cursor: pointer;
|
|
405
|
+
}
|
|
406
|
+
.dt-settings-row-description {
|
|
407
|
+
color: var(--dt-text-muted);
|
|
408
|
+
font-size: 10px;
|
|
409
|
+
}
|
|
410
|
+
.dt-switch {
|
|
411
|
+
position: relative;
|
|
412
|
+
width: 36px;
|
|
413
|
+
height: 20px;
|
|
414
|
+
border-radius: 9999px;
|
|
415
|
+
background-color: var(--dt-border);
|
|
416
|
+
cursor: pointer;
|
|
417
|
+
flex-shrink: 0;
|
|
418
|
+
transition:
|
|
419
|
+
background-color 100ms ease,
|
|
420
|
+
filter 100ms ease;
|
|
421
|
+
}
|
|
422
|
+
.dt-switch:hover {
|
|
423
|
+
filter: brightness(1.2);
|
|
424
|
+
}
|
|
425
|
+
.dt-switch:focus-visible {
|
|
426
|
+
outline: 1px solid var(--dt-accent);
|
|
427
|
+
outline-offset: 2px;
|
|
428
|
+
}
|
|
429
|
+
.dt-switch[data-checked] {
|
|
430
|
+
background-color: var(--dt-accent);
|
|
431
|
+
}
|
|
432
|
+
.dt-switch-thumb {
|
|
433
|
+
position: absolute;
|
|
434
|
+
top: 2px;
|
|
435
|
+
left: 2px;
|
|
436
|
+
width: 16px;
|
|
437
|
+
height: 16px;
|
|
438
|
+
border-radius: 9999px;
|
|
439
|
+
background-color: var(--dt-text-muted);
|
|
440
|
+
transition:
|
|
441
|
+
transform 100ms ease,
|
|
442
|
+
background-color 100ms ease;
|
|
443
|
+
}
|
|
444
|
+
.dt-switch[data-checked] .dt-switch-thumb {
|
|
445
|
+
transform: translateX(16px);
|
|
446
|
+
background-color: var(--dt-bg);
|
|
447
|
+
}
|
|
349
448
|
.dt-tab-button {
|
|
350
449
|
position: relative;
|
|
351
450
|
background: transparent;
|
|
@@ -608,10 +707,13 @@ ul {
|
|
|
608
707
|
cursor: not-allowed;
|
|
609
708
|
}
|
|
610
709
|
|
|
611
|
-
/*
|
|
612
|
-
.dt-
|
|
710
|
+
/* Footer */
|
|
711
|
+
.dt-footer {
|
|
613
712
|
background-color: var(--dt-bg);
|
|
713
|
+
height: 33px;
|
|
614
714
|
}
|
|
715
|
+
|
|
716
|
+
/* Scrubber */
|
|
615
717
|
.dt-scrubber-control {
|
|
616
718
|
position: relative;
|
|
617
719
|
height: 16px;
|
package/dist/overlay.d.ts
CHANGED
|
@@ -31,6 +31,11 @@ export declare const LockScroll: Command.CommandDefinitionNoArgs<"LockScroll", E
|
|
|
31
31
|
export declare const UnlockScroll: Command.CommandDefinitionNoArgs<"UnlockScroll", Effect.Effect<{
|
|
32
32
|
readonly _tag: "UnlockedScroll";
|
|
33
33
|
}, never, never>>;
|
|
34
|
+
export declare const PersistFlatten: Command.CommandDefinitionWithArgs<"PersistFlatten", {
|
|
35
|
+
isFlattened: S.Boolean;
|
|
36
|
+
}, Effect.Effect<{
|
|
37
|
+
readonly _tag: "CompletedPersistFlatten";
|
|
38
|
+
}, never, never>>;
|
|
34
39
|
export declare const JumpToAndInspect: Command.CommandDefinitionWithArgs<"JumpToAndInspect", {
|
|
35
40
|
index: S.Number;
|
|
36
41
|
}, Effect.Effect<{
|
package/dist/overlay.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"overlay.d.ts","sourceRoot":"","sources":["../src/overlay.ts"],"names":[],"mappings":"AACA,OAAO,EAEL,OAAO,EACP,MAAM,
|
|
1
|
+
{"version":3,"file":"overlay.d.ts","sourceRoot":"","sources":["../src/overlay.ts"],"names":[],"mappings":"AACA,OAAO,EAEL,OAAO,EACP,MAAM,EAEN,OAAO,EAGP,MAAM,EAKN,MAAM,IAAI,CAAC,EAGX,eAAe,EAEhB,MAAM,QAAQ,CAAA;AAEf,OAAO,KAAK,OAAO,MAAM,iBAAiB,CAAA;AAC1C,OAAO,EACL,KAAK,aAAa,EAElB,KAAK,aAAa,EAGlB,KAAK,WAAW,EAChB,KAAK,UAAU,EAKhB,MAAM,uBAAuB,CAAA;AAW9B,OAAO,KAAK,EAAE,YAAY,EAAE,gBAAgB,EAAE,MAAM,iBAAiB,CAAA;;oFAyDnC,CAAC;;;;;;;;;;;;;;;;;AAyQnC,cAAM,YAAa,SAAQ,iBAE1B;CAAG;;AAEJ,cAAM,iBAAkB,SAAQ,sBAGC;CAAG;AAEpC,eAAO,MAAM,UAAU;;iBAGsB,CAAA;AAE7C,eAAO,MAAM,YAAY;;iBAGwB,CAAA;AAajD,eAAO,MAAM,cAAc;;;;iBAc1B,CAAA;AAuBD,eAAO,MAAM,gBAAgB;;;;;;;;wBAU5B,CAAA;AAED,eAAO,MAAM,YAAY;;;;;;;;wBAIqB,CAAA;AAE9C,eAAO,MAAM,aAAa;;;;;;wBASzB,CAAA;AAED,eAAO,MAAM,MAAM;;wBASlB,CAAA;AAED,eAAO,MAAM,KAAK;;wBASjB,CAAA;AAED,eAAO,MAAM,WAAW;;6BAYvB,CAAA;AAy6DD,eAAO,MAAM,aAAa,GACxB,OAAO,aAAa,EACpB,UAAU,gBAAgB,EAC1B,MAAM,YAAY,EAClB,aAAa,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,6DAgFhC,CAAA"}
|
package/dist/overlay.js
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { clsx } from 'clsx';
|
|
2
|
-
import { Array as Array_, Context, Effect,
|
|
2
|
+
import { Array as Array_, Context, Effect, Function, HashSet, Match as M, Number as Number_, Option, Order, Predicate, Queue, Record, Schema as S, Stream, String as String_, SubscriptionRef, pipe, } from 'effect';
|
|
3
|
+
import { KeyValueStore } from 'effect/unstable/persistence';
|
|
3
4
|
import * as Command from 'foldkit/command';
|
|
4
5
|
import { DEVTOOLS_HOST_ID, GOT_MESSAGE_PATTERN, INIT_INDEX, extractSubmodelInfo, isTagged, latestEntryIndex, toInspectableValue, } from 'foldkit/devtools-host';
|
|
5
6
|
import { lockScroll, unlockScroll } from 'foldkit/dom';
|
|
@@ -8,8 +9,10 @@ import { m } from 'foldkit/message';
|
|
|
8
9
|
import { makeElement } from 'foldkit/runtime';
|
|
9
10
|
import { evo } from 'foldkit/struct';
|
|
10
11
|
import * as Subscription from 'foldkit/subscription';
|
|
12
|
+
import { BrowserKeyValueStore } from '@effect/platform-browser';
|
|
11
13
|
import * as Listbox from '@foldkit/ui/listbox';
|
|
12
14
|
import * as Slider from '@foldkit/ui/slider';
|
|
15
|
+
import * as Switch from '@foldkit/ui/switch';
|
|
13
16
|
import * as Tabs from '@foldkit/ui/tabs';
|
|
14
17
|
import * as OptionExt from './internal/optionExtensions.js';
|
|
15
18
|
import { overlayStyles } from './overlay-styles.js';
|
|
@@ -35,6 +38,7 @@ const DisplayEntry = S.Struct({
|
|
|
35
38
|
});
|
|
36
39
|
const INSPECTOR_TABS_ID = 'dt-inspector';
|
|
37
40
|
const SUBMODEL_FILTER_ID = 'dt-submodel-filter';
|
|
41
|
+
const FLATTEN_SWITCH_ID = 'dt-flatten-switch';
|
|
38
42
|
const SCRUBBER_SLIDER_ID = 'dt-scrubber';
|
|
39
43
|
const InspectorTabsModel = S.Struct({
|
|
40
44
|
id: S.String,
|
|
@@ -61,9 +65,11 @@ const InspectorTabs = Tabs.create();
|
|
|
61
65
|
* which makes reference equality the correct comparison.
|
|
62
66
|
*/
|
|
63
67
|
const UnknownByReference = S.Unknown.pipe(S.overrideToEquivalence(() => (a, b) => a === b));
|
|
68
|
+
const Screen = S.Literals(['Messages', 'Settings']);
|
|
64
69
|
const Model = S.Struct({
|
|
65
70
|
isOpen: S.Boolean,
|
|
66
71
|
isMobile: S.Boolean,
|
|
72
|
+
screen: Screen,
|
|
67
73
|
entries: S.Array(DisplayEntry),
|
|
68
74
|
initCommands: S.Array(DisplayCommand),
|
|
69
75
|
initMountStarts: S.Array(DisplayMount),
|
|
@@ -77,6 +83,7 @@ const Model = S.Struct({
|
|
|
77
83
|
maybeInspectedMessage: S.Option(UnknownByReference),
|
|
78
84
|
submodelTags: S.Array(S.String),
|
|
79
85
|
maybeSubmodelFilter: S.Option(S.String),
|
|
86
|
+
flattenSwitch: Switch.Model,
|
|
80
87
|
submodelFilterListbox: Listbox.Model,
|
|
81
88
|
expandedPaths: S.HashSet(S.String),
|
|
82
89
|
changedPaths: S.HashSet(S.String),
|
|
@@ -95,6 +102,7 @@ const Model = S.Struct({
|
|
|
95
102
|
});
|
|
96
103
|
const Flags = S.Struct({
|
|
97
104
|
isMobile: S.Boolean,
|
|
105
|
+
isFlattened: S.Boolean,
|
|
98
106
|
entries: S.Array(DisplayEntry),
|
|
99
107
|
initCommands: S.Array(DisplayCommand),
|
|
100
108
|
initMountStarts: S.Array(DisplayMount),
|
|
@@ -104,6 +112,11 @@ const Flags = S.Struct({
|
|
|
104
112
|
});
|
|
105
113
|
// MESSAGE
|
|
106
114
|
const ClickedToggle = m('ClickedToggle');
|
|
115
|
+
const ClickedSettingsToggle = m('ClickedSettingsToggle');
|
|
116
|
+
const GotFlattenSwitchMessage = m('GotFlattenSwitchMessage', {
|
|
117
|
+
message: Switch.Message,
|
|
118
|
+
});
|
|
119
|
+
const CompletedPersistFlatten = m('CompletedPersistFlatten');
|
|
107
120
|
const ClickedRow = m('ClickedRow', { index: S.Number });
|
|
108
121
|
const ClickedResume = m('ClickedResume');
|
|
109
122
|
const ClickedClear = m('ClickedClear');
|
|
@@ -127,7 +140,7 @@ const ReceivedInspectedState = m('ReceivedInspectedState', {
|
|
|
127
140
|
const ToggledTreeNode = m('ToggledTreeNode', { path: S.String });
|
|
128
141
|
const TickedScrubFrame = m('TickedScrubFrame');
|
|
129
142
|
const GotInspectorTabsMessage = m('GotInspectorTabsMessage', {
|
|
130
|
-
message:
|
|
143
|
+
message: Tabs.Message,
|
|
131
144
|
});
|
|
132
145
|
const ReceivedStoreUpdate = m('ReceivedStoreUpdate', {
|
|
133
146
|
entries: S.Array(DisplayEntry),
|
|
@@ -146,6 +159,9 @@ const GotScrubberSliderMessage = m('GotScrubberSliderMessage', {
|
|
|
146
159
|
});
|
|
147
160
|
const Message = S.Union([
|
|
148
161
|
ClickedToggle,
|
|
162
|
+
ClickedSettingsToggle,
|
|
163
|
+
GotFlattenSwitchMessage,
|
|
164
|
+
CompletedPersistFlatten,
|
|
149
165
|
ClickedRow,
|
|
150
166
|
ClickedResume,
|
|
151
167
|
ClickedClear,
|
|
@@ -173,6 +189,8 @@ const MOBILE_BREAKPOINT_QUERY = `(max-width: ${MOBILE_BREAKPOINT}px)`;
|
|
|
173
189
|
const TREE_INDENT_PX = 12;
|
|
174
190
|
const MAX_PREVIEW_KEYS = 3;
|
|
175
191
|
const ALL_MESSAGES_VALUE = '';
|
|
192
|
+
const FLATTEN_STORAGE_KEY = 'foldkit-devtools-flatten';
|
|
193
|
+
const BooleanJsonString = S.fromJsonString(S.Boolean);
|
|
176
194
|
const NO_COMMANDS = [];
|
|
177
195
|
const NO_MOUNTS = [];
|
|
178
196
|
const formatTimeDelta = (deltaMs) => M.value(deltaMs).pipe(M.when(0, () => '0ms'), M.when(Number_.isLessThan(MILLIS_PER_SECOND), ms => `+${Math.round(ms)}ms`), M.orElse(ms => `+${(ms / MILLIS_PER_SECOND).toFixed(1)}s`));
|
|
@@ -233,6 +251,17 @@ class ShadowRootService extends Context.Service()('foldkit/DevToolsShadowRoot')
|
|
|
233
251
|
}
|
|
234
252
|
export const LockScroll = Command.define('LockScroll', LockedScroll)(lockScroll.pipe(Effect.as(LockedScroll())));
|
|
235
253
|
export const UnlockScroll = Command.define('UnlockScroll', UnlockedScroll)(unlockScroll.pipe(Effect.as(UnlockedScroll())));
|
|
254
|
+
const readPersistedFlatten = Effect.gen(function* () {
|
|
255
|
+
const store = yield* KeyValueStore.KeyValueStore;
|
|
256
|
+
const json = yield* Effect.fromOption(Option.fromNullishOr(yield* store.get(FLATTEN_STORAGE_KEY)));
|
|
257
|
+
return yield* S.decodeEffect(BooleanJsonString)(json);
|
|
258
|
+
}).pipe(Effect.catch(() => Effect.succeed(false)), Effect.provide(BrowserKeyValueStore.layerLocalStorage));
|
|
259
|
+
export const PersistFlatten = Command.define('PersistFlatten', { isFlattened: S.Boolean }, CompletedPersistFlatten)(({ isFlattened }) => Effect.gen(function* () {
|
|
260
|
+
const store = yield* KeyValueStore.KeyValueStore;
|
|
261
|
+
const json = yield* S.encodeEffect(BooleanJsonString)(isFlattened);
|
|
262
|
+
yield* store.set(FLATTEN_STORAGE_KEY, json);
|
|
263
|
+
return CompletedPersistFlatten();
|
|
264
|
+
}).pipe(Effect.catch(() => Effect.succeed(CompletedPersistFlatten())), Effect.provide(BrowserKeyValueStore.layerLocalStorage)));
|
|
236
265
|
const buildInspectionFromModel = (index, model) => Effect.gen(function* () {
|
|
237
266
|
const store = yield* StoreService;
|
|
238
267
|
const maybeMessage = yield* store.getMessageAtIndex(index);
|
|
@@ -296,6 +325,31 @@ const makeUpdate = (store, shadow, mode) => {
|
|
|
296
325
|
OptionExt.when(model.isMobile, toggleScrollLock(nextIsOpen)).pipe(Option.toArray),
|
|
297
326
|
];
|
|
298
327
|
},
|
|
328
|
+
ClickedSettingsToggle: () => [
|
|
329
|
+
evo(model, {
|
|
330
|
+
screen: currentScreen => M.value(currentScreen).pipe(M.withReturnType(), M.when('Messages', () => 'Settings'), M.when('Settings', () => 'Messages'), M.exhaustive),
|
|
331
|
+
}),
|
|
332
|
+
[],
|
|
333
|
+
],
|
|
334
|
+
GotFlattenSwitchMessage: ({ message: switchMessage }) => {
|
|
335
|
+
const [nextFlattenSwitch, switchCommands, maybeOutMessage] = Switch.update(model.flattenSwitch, switchMessage);
|
|
336
|
+
const mappedCommands = Command.mapMessages(switchCommands, message => GotFlattenSwitchMessage({ message }));
|
|
337
|
+
return Option.match(maybeOutMessage, {
|
|
338
|
+
onNone: () => [
|
|
339
|
+
evo(model, { flattenSwitch: () => nextFlattenSwitch }),
|
|
340
|
+
mappedCommands,
|
|
341
|
+
],
|
|
342
|
+
onSome: M.type().pipe(M.withReturnType(), M.tagsExhaustive({
|
|
343
|
+
ToggledChecked: ({ isChecked }) => [
|
|
344
|
+
evo(model, { flattenSwitch: () => nextFlattenSwitch }),
|
|
345
|
+
[
|
|
346
|
+
...mappedCommands,
|
|
347
|
+
PersistFlatten({ isFlattened: isChecked }),
|
|
348
|
+
],
|
|
349
|
+
],
|
|
350
|
+
})),
|
|
351
|
+
});
|
|
352
|
+
},
|
|
299
353
|
CrossedMobileBreakpoint: ({ isMobile }) => [
|
|
300
354
|
evo(model, { isMobile: () => isMobile }),
|
|
301
355
|
OptionExt.when(model.isOpen, toggleScrollLock(isMobile)).pipe(Option.toArray),
|
|
@@ -367,14 +421,12 @@ const makeUpdate = (store, shadow, mode) => {
|
|
|
367
421
|
[],
|
|
368
422
|
],
|
|
369
423
|
GotInspectorTabsMessage: ({ message: tabsMessage }) => {
|
|
370
|
-
const [nextTabsModel, tabsCommands] = InspectorTabs.update(model.inspectorTabs,
|
|
371
|
-
/* eslint-disable-next-line @typescript-eslint/consistent-type-assertions */
|
|
372
|
-
tabsMessage);
|
|
424
|
+
const [nextTabsModel, tabsCommands] = InspectorTabs.update(model.inspectorTabs, tabsMessage);
|
|
373
425
|
return [
|
|
374
426
|
evo(model, {
|
|
375
427
|
inspectorTabs: () => nextTabsModel,
|
|
376
428
|
}),
|
|
377
|
-
Command.mapMessages(tabsCommands,
|
|
429
|
+
Command.mapMessages(tabsCommands, message => GotInspectorTabsMessage({ message })),
|
|
378
430
|
];
|
|
379
431
|
},
|
|
380
432
|
ToggledTreeNode: ({ path }) => [
|
|
@@ -426,7 +478,7 @@ const makeUpdate = (store, shadow, mode) => {
|
|
|
426
478
|
},
|
|
427
479
|
GotSubmodelFilterMessage: ({ message: listboxMessage }) => {
|
|
428
480
|
const [nextListboxModel, listboxCommands, maybeOutMessage] = SubmodelFilterListbox.update(model.submodelFilterListbox, listboxMessage);
|
|
429
|
-
const mappedCommands = Command.mapMessages(listboxCommands,
|
|
481
|
+
const mappedCommands = Command.mapMessages(listboxCommands, message => GotSubmodelFilterMessage({ message }));
|
|
430
482
|
return Option.match(maybeOutMessage, {
|
|
431
483
|
onNone: () => [
|
|
432
484
|
evo(model, { submodelFilterListbox: () => nextListboxModel }),
|
|
@@ -445,7 +497,7 @@ const makeUpdate = (store, shadow, mode) => {
|
|
|
445
497
|
},
|
|
446
498
|
GotScrubberSliderMessage: ({ message: sliderMessage }) => {
|
|
447
499
|
const [nextSlider, sliderCommands, maybeOutMessage] = Slider.update(model.scrubberSlider, sliderMessage);
|
|
448
|
-
const mappedSliderCommands = Command.mapMessages(sliderCommands,
|
|
500
|
+
const mappedSliderCommands = Command.mapMessages(sliderCommands, message => GotScrubberSliderMessage({ message }));
|
|
449
501
|
// NOTE: the thumb tracks every pointermove (cheap, model-only via
|
|
450
502
|
// `nextSlider`), but the heavy jump-plus-inspect is coalesced to one
|
|
451
503
|
// navigation per animation frame. Each `ChangedValue` overwrites the
|
|
@@ -473,7 +525,7 @@ const makeUpdate = (store, shadow, mode) => {
|
|
|
473
525
|
[jumpToAndInspect(hostIndex)],
|
|
474
526
|
],
|
|
475
527
|
}),
|
|
476
|
-
}), M.tag('CompletedResume', 'CompletedClear', 'LockedScroll', 'UnlockedScroll', 'ScrolledToTop', () => [model, []]), M.exhaustive);
|
|
528
|
+
}), M.tag('CompletedResume', 'CompletedClear', 'CompletedPersistFlatten', 'LockedScroll', 'UnlockedScroll', 'ScrolledToTop', () => [model, []]), M.exhaustive);
|
|
477
529
|
};
|
|
478
530
|
// SUBSCRIPTION
|
|
479
531
|
const makeOverlaySubscriptions = (store, shadow) => {
|
|
@@ -689,6 +741,17 @@ const makeView = (position, mode, shadow, maybeBanner) => {
|
|
|
689
741
|
h.Class('flex-1 flex items-center justify-center text-dt-muted text-2xs font-mono min-w-0'),
|
|
690
742
|
], ['init: no Message']);
|
|
691
743
|
const modelTabContent = (inspectedModel, expandedPaths, changedPaths, affectedPaths) => treeView(inspectedModel, 'root', expandedPaths, changedPaths, affectedPaths, Option.none(), true);
|
|
744
|
+
const unwrapToLeaf = (message) => {
|
|
745
|
+
if (isTagged(message) &&
|
|
746
|
+
GOT_MESSAGE_PATTERN.test(message._tag) &&
|
|
747
|
+
Predicate.hasProperty(message, 'message') &&
|
|
748
|
+
Predicate.isNotUndefined(message.message)) {
|
|
749
|
+
return unwrapToLeaf(message.message);
|
|
750
|
+
}
|
|
751
|
+
else {
|
|
752
|
+
return message;
|
|
753
|
+
}
|
|
754
|
+
};
|
|
692
755
|
const unwrapIfFiltered = (message, maybeSubmodelFilter) => {
|
|
693
756
|
if (Option.isNone(maybeSubmodelFilter)) {
|
|
694
757
|
return message;
|
|
@@ -712,10 +775,12 @@ const makeView = (position, mode, shadow, maybeBanner) => {
|
|
|
712
775
|
}
|
|
713
776
|
return current;
|
|
714
777
|
};
|
|
715
|
-
const messageTabContent = (maybeInspectedMessage, maybeSubmodelFilter, expandedPaths, timestamp) => Option.match(maybeInspectedMessage, {
|
|
778
|
+
const messageTabContent = (maybeInspectedMessage, maybeSubmodelFilter, isFlattened, expandedPaths, timestamp) => Option.match(maybeInspectedMessage, {
|
|
716
779
|
onNone: noMessageView,
|
|
717
780
|
onSome: rawMessage => {
|
|
718
|
-
const message =
|
|
781
|
+
const message = isFlattened
|
|
782
|
+
? unwrapToLeaf(rawMessage)
|
|
783
|
+
: unwrapIfFiltered(rawMessage, maybeSubmodelFilter);
|
|
719
784
|
return h.div([h.Class('flex flex-col flex-1 min-h-0 min-w-0')], [
|
|
720
785
|
h.div([
|
|
721
786
|
h.Class('px-2 py-1 border-b text-2xs text-dt-muted font-mono shrink-0'),
|
|
@@ -846,6 +911,7 @@ const makeView = (position, mode, shadow, maybeBanner) => {
|
|
|
846
911
|
])), M.when('Message', () => lazyTabContent('Message', messageTabContent, [
|
|
847
912
|
model.maybeInspectedMessage,
|
|
848
913
|
model.maybeSubmodelFilter,
|
|
914
|
+
model.flattenSwitch.isChecked,
|
|
849
915
|
model.expandedPaths,
|
|
850
916
|
inspectedTimestamp(model),
|
|
851
917
|
])), M.when('Commands', () => lazyTabContent('Commands', commandsTabContent, [
|
|
@@ -1000,6 +1066,31 @@ const makeView = (position, mode, shadow, maybeBanner) => {
|
|
|
1000
1066
|
toParentMessage: message => GotSubmodelFilterMessage({ message }),
|
|
1001
1067
|
});
|
|
1002
1068
|
};
|
|
1069
|
+
// SETTINGS
|
|
1070
|
+
const flattenSwitchView = (model) => h.submodel({
|
|
1071
|
+
slotId: 'flatten-switch',
|
|
1072
|
+
model: model.flattenSwitch,
|
|
1073
|
+
view: Switch.view,
|
|
1074
|
+
viewInputs: {
|
|
1075
|
+
toView: attributes => h.div([h.Class('dt-settings-row')], [
|
|
1076
|
+
h.div([...attributes.button, h.Class('dt-switch')], [h.span([h.Class('dt-switch-thumb')], [])]),
|
|
1077
|
+
h.div([h.Class('dt-settings-row-text')], [
|
|
1078
|
+
h.label([...attributes.label, h.Class('dt-settings-row-label')], ['Flatten to leaf Message']),
|
|
1079
|
+
h.span([
|
|
1080
|
+
...attributes.description,
|
|
1081
|
+
h.Class('dt-settings-row-description'),
|
|
1082
|
+
], ['Label each row with its innermost Message']),
|
|
1083
|
+
]),
|
|
1084
|
+
]),
|
|
1085
|
+
},
|
|
1086
|
+
toParentMessage: message => GotFlattenSwitchMessage({ message }),
|
|
1087
|
+
});
|
|
1088
|
+
const settingsScreenView = (model) => h.keyed('div')('Settings', [h.Class('flex flex-col flex-1 min-h-0 overflow-y-auto overscroll-none')], [
|
|
1089
|
+
h.div([h.Class('flex flex-col')], [
|
|
1090
|
+
h.span([h.Class('dt-settings-section-title')], ['Message List']),
|
|
1091
|
+
flattenSwitchView(model),
|
|
1092
|
+
]),
|
|
1093
|
+
]);
|
|
1003
1094
|
const headerView = (model) => {
|
|
1004
1095
|
const { status, maybeAction } = M.value(mode).pipe(M.withReturnType(), M.when('TimeTravel', () => model.isPaused
|
|
1005
1096
|
? {
|
|
@@ -1064,13 +1155,25 @@ const makeView = (position, mode, shadow, maybeBanner) => {
|
|
|
1064
1155
|
h.Class('text-2xs text-dt-muted font-mono shrink-0 text-right min-w-5'),
|
|
1065
1156
|
], [formatTimeDelta(timeDelta)]),
|
|
1066
1157
|
]);
|
|
1067
|
-
const messageListBody = (entries, startIndex, selectedIndex, isPaused, pausedAtIndex, maybeFilterTag) => {
|
|
1158
|
+
const messageListBody = (entries, startIndex, selectedIndex, isPaused, pausedAtIndex, maybeFilterTag, isFlattened) => {
|
|
1068
1159
|
const baseTimestamp = pipe(entries, Array_.head, Option.match({
|
|
1069
1160
|
onNone: () => 0,
|
|
1070
1161
|
onSome: ({ timestamp }) => timestamp,
|
|
1071
1162
|
}));
|
|
1072
1163
|
const isInitSelected = selectedIndex === INIT_INDEX;
|
|
1073
1164
|
const isFiltered = Option.isSome(maybeFilterTag);
|
|
1165
|
+
const leafOrTag = (entry) => Option.getOrElse(entry.maybeLeafTag, () => entry.tag);
|
|
1166
|
+
const displayTagFor = (entry) => {
|
|
1167
|
+
if (isFlattened) {
|
|
1168
|
+
return leafOrTag(entry);
|
|
1169
|
+
}
|
|
1170
|
+
else {
|
|
1171
|
+
return Option.match(maybeFilterTag, {
|
|
1172
|
+
onNone: () => entry.tag,
|
|
1173
|
+
onSome: filterTag => pipe(entry.submodelPath, Array_.findFirstIndex(pathTag => pathTag === filterTag), Option.flatMap(filterIndex => Array_.get(entry.submodelPath, Number_.increment(filterIndex))), Option.orElse(() => entry.maybeLeafTag), Option.getOrElse(() => entry.tag)),
|
|
1174
|
+
});
|
|
1175
|
+
}
|
|
1176
|
+
};
|
|
1074
1177
|
const indexedEntries = pipe(entries, Array_.map((entry, arrayIndex) => ({
|
|
1075
1178
|
entry,
|
|
1076
1179
|
absoluteIndex: startIndex + arrayIndex,
|
|
@@ -1080,9 +1183,7 @@ const makeView = (position, mode, shadow, maybeBanner) => {
|
|
|
1080
1183
|
const messageRows = pipe(indexedEntries, Array_.map(({ entry, absoluteIndex }) => {
|
|
1081
1184
|
const isSelected = selectedIndex === absoluteIndex;
|
|
1082
1185
|
const isPausedHere = isPaused && pausedAtIndex === absoluteIndex;
|
|
1083
|
-
const displayTag =
|
|
1084
|
-
? pipe(entry.submodelPath, Array_.findFirstIndex(Equal.equals(maybeFilterTag.value)), Option.flatMap(filterIndex => Array_.get(entry.submodelPath, Number_.increment(filterIndex))), Option.orElse(() => entry.maybeLeafTag), Option.getOrElse(() => entry.tag))
|
|
1085
|
-
: entry.tag;
|
|
1186
|
+
const displayTag = displayTagFor(entry);
|
|
1086
1187
|
return lazyMessageRow(String(absoluteIndex), messageRowView, [
|
|
1087
1188
|
displayTag,
|
|
1088
1189
|
absoluteIndex,
|
|
@@ -1112,6 +1213,7 @@ const makeView = (position, mode, shadow, maybeBanner) => {
|
|
|
1112
1213
|
model.isPaused,
|
|
1113
1214
|
model.pausedAtIndex,
|
|
1114
1215
|
model.maybeSubmodelFilter,
|
|
1216
|
+
model.flattenSwitch.isChecked,
|
|
1115
1217
|
]);
|
|
1116
1218
|
};
|
|
1117
1219
|
// SCRUBBER
|
|
@@ -1128,9 +1230,7 @@ const makeView = (position, mode, shadow, maybeBanner) => {
|
|
|
1128
1230
|
ariaLabel: 'Session scrubber',
|
|
1129
1231
|
getTrackRoot: () => shadow,
|
|
1130
1232
|
formatValue: value => value === 0 ? 'init' : `Message ${String(value)}`,
|
|
1131
|
-
toView: attributes => h.div([
|
|
1132
|
-
h.Class('dt-scrubber-row flex items-center gap-3 px-3 py-2 border-t shrink-0'),
|
|
1133
|
-
], [
|
|
1233
|
+
toView: attributes => h.div([h.Class('flex items-center gap-3 flex-1 min-w-0')], [
|
|
1134
1234
|
h.div([
|
|
1135
1235
|
...attributes.root,
|
|
1136
1236
|
h.Class('dt-scrubber-control flex-1 flex items-center'),
|
|
@@ -1150,8 +1250,67 @@ const makeView = (position, mode, shadow, maybeBanner) => {
|
|
|
1150
1250
|
},
|
|
1151
1251
|
toParentMessage: message => GotScrubberSliderMessage({ message }),
|
|
1152
1252
|
});
|
|
1153
|
-
//
|
|
1253
|
+
// FOOTER
|
|
1154
1254
|
const isScrubberVisible = mode === 'TimeTravel';
|
|
1255
|
+
const GEAR_OUTER = 'M9.594 3.94c.09-.542.56-.94 1.11-.94h2.593c.55 0 1.02.398 1.11.94l.213 1.281c.063.374.313.686.645.87.074.04.147.083.22.127.325.196.72.257 1.075.124l1.217-.456a1.125 1.125 0 0 1 1.37.49l1.296 2.247a1.125 1.125 0 0 1-.26 1.431l-1.003.827c-.293.241-.438.613-.43.992a7.723 7.723 0 0 1 0 .255c-.008.378.137.75.43.991l1.004.827c.424.35.534.955.26 1.43l-1.298 2.247a1.125 1.125 0 0 1-1.369.491l-1.217-.456c-.355-.133-.75-.072-1.076.124a6.47 6.47 0 0 1-.22.128c-.331.183-.581.495-.644.869l-.213 1.281c-.09.543-.56.94-1.11.94h-2.594c-.55 0-1.019-.398-1.11-.94l-.213-1.281c-.062-.374-.312-.686-.644-.87a6.52 6.52 0 0 1-.22-.127c-.325-.196-.72-.257-1.076-.124l-1.217.456a1.125 1.125 0 0 1-1.369-.49l-1.297-2.247a1.125 1.125 0 0 1 .26-1.431l1.004-.827c.292-.24.437-.613.43-.991a6.932 6.932 0 0 1 0-.255c.007-.38-.138-.751-.43-.992l-1.004-.827a1.125 1.125 0 0 1-.26-1.43l1.297-2.247a1.125 1.125 0 0 1 1.37-.491l1.216.456c.356.133.751.072 1.076-.124.072-.044.146-.086.22-.128.332-.183.582-.495.644-.869l.214-1.28Z';
|
|
1256
|
+
const GEAR_INNER = 'M15 12a3 3 0 1 1-6 0 3 3 0 0 1 6 0Z';
|
|
1257
|
+
const X_MARK = 'M6 18L18 6M6 6l12 12';
|
|
1258
|
+
const gearIconView = h.svg([
|
|
1259
|
+
h.Key('gear-icon'),
|
|
1260
|
+
h.AriaHidden(true),
|
|
1261
|
+
h.Class('dt-settings-icon shrink-0'),
|
|
1262
|
+
h.Xmlns('http://www.w3.org/2000/svg'),
|
|
1263
|
+
h.Fill('none'),
|
|
1264
|
+
h.ViewBox('0 0 24 24'),
|
|
1265
|
+
h.StrokeWidth('1.5'),
|
|
1266
|
+
h.Stroke('currentColor'),
|
|
1267
|
+
], [
|
|
1268
|
+
h.path([h.D(GEAR_OUTER), h.StrokeLinecap('round'), h.StrokeLinejoin('round')], []),
|
|
1269
|
+
h.path([h.D(GEAR_INNER), h.StrokeLinecap('round'), h.StrokeLinejoin('round')], []),
|
|
1270
|
+
]);
|
|
1271
|
+
const closeSettingsIconView = h.svg([
|
|
1272
|
+
h.Key('close-icon'),
|
|
1273
|
+
h.AriaHidden(true),
|
|
1274
|
+
h.Class('dt-settings-icon shrink-0'),
|
|
1275
|
+
h.Xmlns('http://www.w3.org/2000/svg'),
|
|
1276
|
+
h.Fill('none'),
|
|
1277
|
+
h.ViewBox('0 0 24 24'),
|
|
1278
|
+
h.StrokeWidth('2'),
|
|
1279
|
+
h.Stroke('currentColor'),
|
|
1280
|
+
], [
|
|
1281
|
+
h.path([h.D(X_MARK), h.StrokeLinecap('round'), h.StrokeLinejoin('round')], []),
|
|
1282
|
+
]);
|
|
1283
|
+
const settingsToggleView = (screen) => {
|
|
1284
|
+
const isSettingsOpen = screen === 'Settings';
|
|
1285
|
+
return h.button([
|
|
1286
|
+
h.Class(clsx('dt-settings-button', {
|
|
1287
|
+
'dt-settings-button-active': isSettingsOpen,
|
|
1288
|
+
})),
|
|
1289
|
+
h.AriaLabel(isSettingsOpen ? 'Close settings' : 'Settings'),
|
|
1290
|
+
h.AriaPressed(String(isSettingsOpen)),
|
|
1291
|
+
h.OnClick(ClickedSettingsToggle()),
|
|
1292
|
+
], [isSettingsOpen ? closeSettingsIconView : gearIconView]);
|
|
1293
|
+
};
|
|
1294
|
+
const footerView = (model) => h.div([
|
|
1295
|
+
h.Class('dt-footer flex items-center gap-3 px-3 py-2 border-t shrink-0'),
|
|
1296
|
+
], [
|
|
1297
|
+
settingsToggleView(model.screen),
|
|
1298
|
+
...OptionExt.when(isScrubberVisible, scrubberView(model)).pipe(Option.toArray),
|
|
1299
|
+
]);
|
|
1300
|
+
// PANEL
|
|
1301
|
+
const messagesScreenView = (model) => {
|
|
1302
|
+
const maybeSubmodelFilterView = OptionExt.when(Array_.isReadonlyArrayNonEmpty(model.submodelTags), submodelFilterView(model));
|
|
1303
|
+
const maybeScrollToTopPillView = OptionExt.when(!model.isFollowingTop, scrollToTopPillView());
|
|
1304
|
+
return h.keyed('div')('Messages', [h.Class('flex flex-1 min-h-0 dt-content')], [
|
|
1305
|
+
h.div([h.Class('flex flex-col min-h-0 dt-message-pane')], [
|
|
1306
|
+
...Option.toArray(maybeSubmodelFilterView),
|
|
1307
|
+
...Option.toArray(maybeScrollToTopPillView),
|
|
1308
|
+
messageListView(model),
|
|
1309
|
+
]),
|
|
1310
|
+
inspectorPaneView(model),
|
|
1311
|
+
]);
|
|
1312
|
+
};
|
|
1313
|
+
const contentView = (model) => M.value(model.screen).pipe(M.withReturnType(), M.when('Messages', () => messagesScreenView(model)), M.when('Settings', () => settingsScreenView(model)), M.exhaustive);
|
|
1155
1314
|
const panelView = (model) => h.keyed('div')('dt-panel', [
|
|
1156
1315
|
h.Class(clsx('fixed dt-panel dt-panel-wide bg-dt-bg border rounded-lg flex flex-col overflow-hidden font-mono text-dt', PANEL_POSITION_CLASS[position])),
|
|
1157
1316
|
], [
|
|
@@ -1159,18 +1318,8 @@ const makeView = (position, mode, shadow, maybeBanner) => {
|
|
|
1159
1318
|
h.Class('px-3 py-2 border-b text-sm text-dt-muted font-mono shrink-0 leading-snug'),
|
|
1160
1319
|
], [banner])).pipe(Option.toArray),
|
|
1161
1320
|
headerView(model),
|
|
1162
|
-
|
|
1163
|
-
|
|
1164
|
-
...Array_.match(model.submodelTags, {
|
|
1165
|
-
onEmpty: () => [],
|
|
1166
|
-
onNonEmpty: () => [submodelFilterView(model)],
|
|
1167
|
-
}),
|
|
1168
|
-
...OptionExt.when(!model.isFollowingTop, scrollToTopPillView()).pipe(Option.toArray),
|
|
1169
|
-
messageListView(model),
|
|
1170
|
-
]),
|
|
1171
|
-
inspectorPaneView(model),
|
|
1172
|
-
]),
|
|
1173
|
-
...OptionExt.when(isScrubberVisible, scrubberView(model)).pipe(Option.toArray),
|
|
1321
|
+
contentView(model),
|
|
1322
|
+
footerView(model),
|
|
1174
1323
|
]);
|
|
1175
1324
|
const interactionBlocker = () => h.div([h.Class('dt-interaction-blocker')], []);
|
|
1176
1325
|
return (model) => h.div([], [
|
|
@@ -1211,12 +1360,15 @@ export const createOverlay = (store, position, mode, maybeBanner) => Effect.gen(
|
|
|
1211
1360
|
container.id = '__foldkit_devtools_overlay__';
|
|
1212
1361
|
const flags = Effect.gen(function* () {
|
|
1213
1362
|
const storeState = yield* SubscriptionRef.get(store.stateRef);
|
|
1363
|
+
const isFlattened = yield* readPersistedFlatten;
|
|
1214
1364
|
return {
|
|
1215
1365
|
isMobile: window.matchMedia(MOBILE_BREAKPOINT_QUERY).matches,
|
|
1366
|
+
isFlattened,
|
|
1216
1367
|
...toDisplayState(storeState),
|
|
1217
1368
|
};
|
|
1218
1369
|
});
|
|
1219
1370
|
const init = (flags) => {
|
|
1371
|
+
const { isFlattened, ...displayFlags } = flags;
|
|
1220
1372
|
const sliderMax = flags.entries.length;
|
|
1221
1373
|
const initialSliderValue = flags.isPaused
|
|
1222
1374
|
? hostIndexToSliderValue(flags.pausedAtIndex, flags.startIndex)
|
|
@@ -1224,7 +1376,12 @@ export const createOverlay = (store, position, mode, maybeBanner) => Effect.gen(
|
|
|
1224
1376
|
return [
|
|
1225
1377
|
{
|
|
1226
1378
|
isOpen: false,
|
|
1227
|
-
|
|
1379
|
+
screen: 'Messages',
|
|
1380
|
+
...displayFlags,
|
|
1381
|
+
flattenSwitch: Switch.init({
|
|
1382
|
+
id: FLATTEN_SWITCH_ID,
|
|
1383
|
+
isChecked: isFlattened,
|
|
1384
|
+
}),
|
|
1228
1385
|
selectedIndex: INIT_INDEX,
|
|
1229
1386
|
isFollowingLatest: true,
|
|
1230
1387
|
isFollowingTop: true,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@foldkit/devtools",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.123.0",
|
|
4
4
|
"description": "In-browser DevTools overlay for Foldkit applications",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/index.js",
|
|
@@ -17,6 +17,7 @@
|
|
|
17
17
|
"dist"
|
|
18
18
|
],
|
|
19
19
|
"peerDependencies": {
|
|
20
|
+
"@effect/platform-browser": "4.0.0-beta.88",
|
|
20
21
|
"@foldkit/ui": "^0",
|
|
21
22
|
"effect": "4.0.0-beta.88",
|
|
22
23
|
"foldkit": "^0"
|
|
@@ -25,11 +26,12 @@
|
|
|
25
26
|
"clsx": "^2.1.1"
|
|
26
27
|
},
|
|
27
28
|
"devDependencies": {
|
|
29
|
+
"@effect/platform-browser": "4.0.0-beta.88",
|
|
28
30
|
"effect": "4.0.0-beta.88",
|
|
29
31
|
"rimraf": "^6.1.3",
|
|
30
32
|
"typescript": "^6.0.3",
|
|
31
|
-
"@foldkit/ui": "0.
|
|
32
|
-
"foldkit": "0.
|
|
33
|
+
"@foldkit/ui": "0.123.0",
|
|
34
|
+
"foldkit": "0.123.0"
|
|
33
35
|
},
|
|
34
36
|
"keywords": [
|
|
35
37
|
"foldkit",
|
|
@@ -55,6 +57,6 @@
|
|
|
55
57
|
"build": "pnpm run clean && tsc -b tsconfig.build.json",
|
|
56
58
|
"watch": "tsc -b tsconfig.build.json --watch",
|
|
57
59
|
"lint": "pnpm --filter @foldkit/oxlint-plugin build && oxlint src",
|
|
58
|
-
"typecheck": "tsc -
|
|
60
|
+
"typecheck": "tsc -p tsconfig.json --noEmit"
|
|
59
61
|
}
|
|
60
62
|
}
|