@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 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 `effect` as peer dependencies, so install those alongside it.
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
 
@@ -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,40YA8rBzB,CAAA"}
1
+ {"version":3,"file":"overlay-styles.d.ts","sourceRoot":"","sources":["../src/overlay-styles.ts"],"names":[],"mappings":"AAAA,eAAO,MAAM,aAAa,o+cAoyBzB,CAAA"}
@@ -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
- /* Scrubber */
612
- .dt-scrubber-row {
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<{
@@ -1 +1 @@
1
- {"version":3,"file":"overlay.d.ts","sourceRoot":"","sources":["../src/overlay.ts"],"names":[],"mappings":"AACA,OAAO,EAEL,OAAO,EACP,MAAM,EAGN,OAAO,EAGP,MAAM,EAKN,MAAM,IAAI,CAAC,EAGX,eAAe,EAEhB,MAAM,QAAQ,CAAA;AACf,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;;oFA2D/B,CAAC;;;;;;;;;;;;;;;;;AAoPvC,cAAM,YAAa,SAAQ,iBAE1B;CAAG;;AAEJ,cAAM,iBAAkB,SAAQ,sBAGC;CAAG;AAEpC,eAAO,MAAM,UAAU;;iBAGsB,CAAA;AAE7C,eAAO,MAAM,YAAY;;iBAGwB,CAAA;AAuBjD,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;AAitDD,eAAO,MAAM,aAAa,GACxB,OAAO,aAAa,EACpB,UAAU,gBAAgB,EAC1B,MAAM,YAAY,EAClB,aAAa,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,6DAwEhC,CAAA"}
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, Equal, Function, HashSet, Match as M, Number as Number_, Option, Order, Predicate, Queue, Record, Schema as S, Stream, String as String_, SubscriptionRef, pipe, } from '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: S.Unknown,
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, innerMessage => GotInspectorTabsMessage({ message: innerMessage })),
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, innerMessage => GotSubmodelFilterMessage({ message: innerMessage }));
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, innerMessage => GotScrubberSliderMessage({ message: innerMessage }));
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 = unwrapIfFiltered(rawMessage, maybeSubmodelFilter);
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 = isFiltered
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
- // PANEL
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
- h.div([h.Class('flex flex-1 min-h-0 dt-content')], [
1163
- h.div([h.Class('flex flex-col min-h-0 dt-message-pane')], [
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
- ...flags,
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.122.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.122.0",
32
- "foldkit": "0.122.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 -b tsconfig.build.json --noEmit"
60
+ "typecheck": "tsc -p tsconfig.json --noEmit"
59
61
  }
60
62
  }