@foldkit/devtools 0.137.0 → 0.139.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
@@ -7,33 +7,44 @@ The overlay displays every Message flowing through your app and lets you inspect
7
7
  ## Installation
8
8
 
9
9
  ```bash
10
- pnpm add @foldkit/devtools
10
+ pnpm add --save-dev @foldkit/devtools
11
11
  # or
12
- npm install @foldkit/devtools
12
+ npm install --save-dev @foldkit/devtools
13
13
  # or
14
- yarn add @foldkit/devtools
14
+ yarn add --dev @foldkit/devtools
15
15
  ```
16
16
 
17
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
 
21
- The overlay is opt-in. Pass its `overlay` factory as `devTools.overlay` when you create the application:
21
+ With `@foldkit/vite-plugin`, installing this package as a development dependency is enough to mount the overlay during development. The plugin leaves it out of production builds:
22
22
 
23
23
  ```typescript
24
24
  import { Runtime } from 'foldkit'
25
25
 
26
- import { overlay } from '@foldkit/devtools'
27
-
28
26
  const application = Runtime.makeApplication({
29
27
  // ...
30
- devTools: { Message, overlay },
28
+ devTools: {
29
+ Message,
30
+ },
31
31
  })
32
32
 
33
33
  Runtime.run(application)
34
34
  ```
35
35
 
36
- Without the overlay, a `devTools` config on its own still records Message history and serves the WebSocket bridge that the [DevTools MCP server](https://foldkit.dev/ai/mcp) connects to. Installing `@foldkit/devtools` and passing `overlay` is what mounts the visual panel in the browser.
36
+ The `devTools` configuration is optional unless you need settings such as `Message`, `position`, or `excludeFromHistory`. Recording and the WebSocket bridge that the [DevTools MCP server](https://foldkit.dev/ai/mcp) connects to live in Foldkit's core runtime.
37
+
38
+ To include the overlay in production, move `@foldkit/devtools` to regular `dependencies` and set `show: 'Always'`. The dependency section is the build-time opt-in, and `show` controls whether the runtime mounts it:
39
+
40
+ ```typescript
41
+ const application = Runtime.makeApplication({
42
+ // ...
43
+ devTools: {
44
+ show: 'Always',
45
+ },
46
+ })
47
+ ```
37
48
 
38
49
  See the [DevTools documentation](https://foldkit.dev/core/devtools) for the full configuration surface.
39
50
 
@@ -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.contents {\n display: contents;\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";
1
+ export declare const overlayStyles = ":host {\n /* The host spans the viewport so it has real bounds to snapshot: it carries a\n `view-transition-name` (set in `overlay.ts`, see the note there) to stay\n out of an application's View Transitions, and a name on a zero-size element\n captures nothing. The box itself is inert; the panels inside opt back into\n hit-testing through `.fixed`. */\n position: fixed;\n inset: 0;\n pointer-events: none;\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/* The host is `pointer-events: none` so its viewport-spanning box cannot\n swallow clicks meant for the application, and everything the shadow root\n renders opts back in here. The boundary is the shadow root's children rather\n than any one panel class: content arrives by routes a class list does not\n cover, including the portal root `@foldkit/ui` prepends for anchored\n dropdowns, and a surface that misses the opt-in is silently unclickable.\n These wrappers are zero-height, so granting them hit-testing costs nothing;\n descendants that must stay transparent, like the listbox backdrop, set\n `pointer-events: none` on themselves. */\n:host > * {\n pointer-events: auto;\n}\n\n.fixed {\n position: fixed;\n}\n.flex {\n display: flex;\n}\n.contents {\n display: contents;\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,0gdAuyBzB,CAAA"}
1
+ {"version":3,"file":"overlay-styles.d.ts","sourceRoot":"","sources":["../src/overlay-styles.ts"],"names":[],"mappings":"AAAA,eAAO,MAAM,aAAa,wlfA2zBzB,CAAA"}
@@ -1,5 +1,12 @@
1
1
  export const overlayStyles = `:host {
2
- position: relative;
2
+ /* The host spans the viewport so it has real bounds to snapshot: it carries a
3
+ \`view-transition-name\` (set in \`overlay.ts\`, see the note there) to stay
4
+ out of an application's View Transitions, and a name on a zero-size element
5
+ captures nothing. The box itself is inert; the panels inside opt back into
6
+ hit-testing through \`.fixed\`. */
7
+ position: fixed;
8
+ inset: 0;
9
+ pointer-events: none;
3
10
  z-index: 2147483647;
4
11
 
5
12
  --dt-bg: #1e1e2e;
@@ -37,6 +44,19 @@ ul {
37
44
  list-style: none;
38
45
  }
39
46
 
47
+ /* The host is \`pointer-events: none\` so its viewport-spanning box cannot
48
+ swallow clicks meant for the application, and everything the shadow root
49
+ renders opts back in here. The boundary is the shadow root's children rather
50
+ than any one panel class: content arrives by routes a class list does not
51
+ cover, including the portal root \`@foldkit/ui\` prepends for anchored
52
+ dropdowns, and a surface that misses the opt-in is silently unclickable.
53
+ These wrappers are zero-height, so granting them hit-testing costs nothing;
54
+ descendants that must stay transparent, like the listbox backdrop, set
55
+ \`pointer-events: none\` on themselves. */
56
+ :host > * {
57
+ pointer-events: auto;
58
+ }
59
+
40
60
  .fixed {
41
61
  position: fixed;
42
62
  }
@@ -1 +1 @@
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;AAU9B,OAAO,KAAK,EAAE,YAAY,EAAE,gBAAgB,EAAE,MAAM,iBAAiB,CAAA;;oFAsDR,CAAC;;;;;;;;;;;;;;;;;AAkQ9D,cAAM,YAAa,SAAQ,iBAE1B;CAAG;;AAEJ,cAAM,iBAAkB,SAAQ,sBAGC;CAAG;AAEpC,eAAO,MAAM,UAAU;;iBAGrB,CAAA;AAEF,eAAO,MAAM,YAAY;;iBAGvB,CAAA;AAgCF,eAAO,MAAM,oBAAoB;;;;;iBAgB/B,CAAA;AAuBF,eAAO,MAAM,gBAAgB;;;;;;;;wBAS3B,CAAA;AAEF,eAAO,MAAM,YAAY;;;;;;;;wBAIvB,CAAA;AAEF,eAAO,MAAM,aAAa;;;;;;wBAOxB,CAAA;AAEF,eAAO,MAAM,MAAM;;wBAOjB,CAAA;AAEF,eAAO,MAAM,KAAK;;wBAOhB,CAAA;AAEF,eAAO,MAAM,WAAW;;6BAUtB,CAAA;AAu9DF,eAAO,MAAM,aAAa,GACxB,OAAO,aAAa,EACpB,UAAU,gBAAgB,EAC1B,MAAM,YAAY,EAClB,aAAa,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,6DAkFhC,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;AAU9B,OAAO,KAAK,EAAE,YAAY,EAAE,gBAAgB,EAAE,MAAM,iBAAiB,CAAA;;oFAsDR,CAAC;;;;;;;;;;;;;;;;;AAkQ9D,cAAM,YAAa,SAAQ,iBAE1B;CAAG;;AAEJ,cAAM,iBAAkB,SAAQ,sBAGC;CAAG;AAEpC,eAAO,MAAM,UAAU;;iBAGrB,CAAA;AAEF,eAAO,MAAM,YAAY;;iBAGvB,CAAA;AAgCF,eAAO,MAAM,oBAAoB;;;;;iBAgB/B,CAAA;AAuBF,eAAO,MAAM,gBAAgB;;;;;;;;wBAS3B,CAAA;AAEF,eAAO,MAAM,YAAY;;;;;;;;wBAIvB,CAAA;AAEF,eAAO,MAAM,aAAa;;;;;;wBAOxB,CAAA;AAEF,eAAO,MAAM,MAAM;;wBAOjB,CAAA;AAEF,eAAO,MAAM,KAAK;;wBAOhB,CAAA;AAEF,eAAO,MAAM,WAAW;;6BAUtB,CAAA;AAsgEF,eAAO,MAAM,aAAa,GACxB,OAAO,aAAa,EACpB,UAAU,gBAAgB,EAC1B,MAAM,YAAY,EAClB,aAAa,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,6DAmFhC,CAAA"}
package/dist/overlay.js CHANGED
@@ -646,12 +646,12 @@ const buildOverlayView = (position, mode, shadow, maybeBanner, h) => {
646
646
  h.StrokeLinecap('round'),
647
647
  h.StrokeLinejoin('round'),
648
648
  h.D(isExpanded ? CHEVRON_DOWN : CHEVRON_RIGHT),
649
- ], []),
649
+ ]),
650
650
  ])), "@foldkit/devtools/overlay.js#arrowView");
651
651
  const tagLabelView = (tag) => __foldkitBrandViewResult((h.span([h.Class('json-tag')], [tag])), "@foldkit/devtools/overlay.js#tagLabelView");
652
652
  const previewView = (preview) => __foldkitBrandViewResult((h.span([h.Class('json-preview')], [preview])), "@foldkit/devtools/overlay.js#previewView");
653
- const diffDotView = h.span([h.Class('diff-dot')], []);
654
- const inlineDiffDotView = h.span([h.Class('diff-dot-inline')], []);
653
+ const diffDotView = h.span([h.Class('diff-dot')]);
654
+ const inlineDiffDotView = h.span([h.Class('diff-dot-inline')]);
655
655
  const ArrowSegment = ts('ArrowSegment', { isExpanded: S.Boolean });
656
656
  const DiffDotSegment = ts('DiffDotSegment');
657
657
  const KeyLabelSegment = ts('KeyLabelSegment', { key: S.String });
@@ -1049,7 +1049,7 @@ const buildOverlayView = (position, mode, shadow, maybeBanner, h) => {
1049
1049
  h.StrokeLinecap('round'),
1050
1050
  h.StrokeLinejoin('round'),
1051
1051
  h.D('M6 18L18 6M6 6l12 12'),
1052
- ], []),
1052
+ ]),
1053
1053
  ])
1054
1054
  : h.div([
1055
1055
  h.Class(clsx('flex flex-col items-center gap-0.5 font-semibold tracking-wider leading-none', model.isPaused ? 'text-dt-bg' : 'text-dt-muted')),
@@ -1070,7 +1070,11 @@ const buildOverlayView = (position, mode, shadow, maybeBanner, h) => {
1070
1070
  h.StrokeWidth('2'),
1071
1071
  h.Stroke('currentColor'),
1072
1072
  ], [
1073
- h.path([h.D(CHECK_ICON), h.StrokeLinecap('round'), h.StrokeLinejoin('round')], []),
1073
+ h.path([
1074
+ h.D(CHECK_ICON),
1075
+ h.StrokeLinecap('round'),
1076
+ h.StrokeLinejoin('round'),
1077
+ ]),
1074
1078
  ]);
1075
1079
  const filterItemLabel = (item) => __foldkitBrandViewResult((String_.isNonEmpty(item) ? submodelLabel(item) : 'All Messages'), "@foldkit/devtools/overlay.js#filterItemLabel");
1076
1080
  const ARROW_UP = 'M4.5 10.5L12 3m0 0l7.5 7.5M12 3v18';
@@ -1083,7 +1087,11 @@ const buildOverlayView = (position, mode, shadow, maybeBanner, h) => {
1083
1087
  h.StrokeWidth('2'),
1084
1088
  h.Stroke('currentColor'),
1085
1089
  ], [
1086
- h.path([h.D(ARROW_UP), h.StrokeLinecap('round'), h.StrokeLinejoin('round')], []),
1090
+ h.path([
1091
+ h.D(ARROW_UP),
1092
+ h.StrokeLinecap('round'),
1093
+ h.StrokeLinejoin('round'),
1094
+ ]),
1087
1095
  ]);
1088
1096
  const scrollToTopPillView = () => __foldkitBrandViewResult((h.button([h.Class('dt-scroll-pill'), h.OnClick(ClickedScrollToTopPill())], [
1089
1097
  arrowUpIconView,
@@ -1120,7 +1128,7 @@ const buildOverlayView = (position, mode, shadow, maybeBanner, h) => {
1120
1128
  h.D(CHEVRON_DOWN),
1121
1129
  h.StrokeLinecap('round'),
1122
1130
  h.StrokeLinejoin('round'),
1123
- ], []),
1131
+ ]),
1124
1132
  ]),
1125
1133
  ]),
1126
1134
  buttonClassName: 'dt-filter-button',
@@ -1137,7 +1145,7 @@ const buildOverlayView = (position, mode, shadow, maybeBanner, h) => {
1137
1145
  isChecked: model.isFlattened,
1138
1146
  onToggle: isFlattened => __foldkitBrandViewResult((ToggledFlatten({ isFlattened })), "@foldkit/devtools/overlay.js#onToggle"),
1139
1147
  toView: attributes => __foldkitBrandViewResult((h.div([h.Class('dt-settings-row')], [
1140
- h.div([...attributes.button, h.Class('dt-switch')], [h.span([h.Class('dt-switch-thumb')], [])]),
1148
+ h.div([...attributes.button, h.Class('dt-switch')], [h.span([h.Class('dt-switch-thumb')])]),
1141
1149
  h.div([h.Class('dt-settings-row-text')], [
1142
1150
  h.label([...attributes.label, h.Class('dt-settings-row-label')], ['Flatten to leaf Message']),
1143
1151
  h.span([
@@ -1186,8 +1194,8 @@ const buildOverlayView = (position, mode, shadow, maybeBanner, h) => {
1186
1194
  h.OnClick(ClickedRow({ index: INIT_INDEX })),
1187
1195
  ], [
1188
1196
  ...OptionExt.when(mode === 'TimeTravel', h.span([h.Class('pause-column')], isPausedHere ? [pauseIconView] : [])).pipe(Option.toArray),
1189
- h.span([h.Class('dot-column')], []),
1190
- h.span([h.Class(indexClass)], []),
1197
+ h.span([h.Class('dot-column')]),
1198
+ h.span([h.Class(indexClass)]),
1191
1199
  h.span([h.Class('text-base text-dt-muted font-mono')], ['init']),
1192
1200
  ])), "@foldkit/devtools/overlay.js#initRowView");
1193
1201
  const pauseIconView = h.svg([
@@ -1203,7 +1211,7 @@ const buildOverlayView = (position, mode, shadow, maybeBanner, h) => {
1203
1211
  h.StrokeLinecap('round'),
1204
1212
  h.StrokeLinejoin('round'),
1205
1213
  h.D('M5.75 3v18M18.25 3v18'),
1206
- ], []),
1214
+ ]),
1207
1215
  ]);
1208
1216
  const messageRowView = (tag, absoluteIndex, isSelected, isPausedHere, timeDelta, isModelChanged) => __foldkitBrandViewResult((h.keyed('li')(String(absoluteIndex), [
1209
1217
  h.Class(clsx(ROW_BASE, { selected: isSelected })),
@@ -1301,8 +1309,11 @@ const buildOverlayView = (position, mode, shadow, maybeBanner, h) => {
1301
1309
  h.div([
1302
1310
  ...attributes.filledTrack,
1303
1311
  h.Class('dt-scrubber-fill'),
1304
- ], []),
1305
- h.div([...attributes.thumb, h.Class('dt-scrubber-thumb')], []),
1312
+ ]),
1313
+ h.div([
1314
+ ...attributes.thumb,
1315
+ h.Class('dt-scrubber-thumb'),
1316
+ ]),
1306
1317
  ]),
1307
1318
  ]),
1308
1319
  h.span([
@@ -1326,8 +1337,16 @@ const buildOverlayView = (position, mode, shadow, maybeBanner, h) => {
1326
1337
  h.StrokeWidth('1.5'),
1327
1338
  h.Stroke('currentColor'),
1328
1339
  ], [
1329
- h.path([h.D(GEAR_OUTER), h.StrokeLinecap('round'), h.StrokeLinejoin('round')], []),
1330
- h.path([h.D(GEAR_INNER), h.StrokeLinecap('round'), h.StrokeLinejoin('round')], []),
1340
+ h.path([
1341
+ h.D(GEAR_OUTER),
1342
+ h.StrokeLinecap('round'),
1343
+ h.StrokeLinejoin('round'),
1344
+ ]),
1345
+ h.path([
1346
+ h.D(GEAR_INNER),
1347
+ h.StrokeLinecap('round'),
1348
+ h.StrokeLinejoin('round'),
1349
+ ]),
1331
1350
  ]);
1332
1351
  const closeSettingsIconView = h.svg([
1333
1352
  h.AriaHidden(true),
@@ -1338,7 +1357,11 @@ const buildOverlayView = (position, mode, shadow, maybeBanner, h) => {
1338
1357
  h.StrokeWidth('2'),
1339
1358
  h.Stroke('currentColor'),
1340
1359
  ], [
1341
- h.path([h.D(X_MARK), h.StrokeLinecap('round'), h.StrokeLinejoin('round')], []),
1360
+ h.path([
1361
+ h.D(X_MARK),
1362
+ h.StrokeLinecap('round'),
1363
+ h.StrokeLinejoin('round'),
1364
+ ]),
1342
1365
  ]);
1343
1366
  const settingsToggleView = (screen) => {
1344
1367
  const isSettingsOpen = screen === 'Settings';
@@ -1381,7 +1404,7 @@ const buildOverlayView = (position, mode, shadow, maybeBanner, h) => {
1381
1404
  contentView(model),
1382
1405
  footerView(model),
1383
1406
  ])), "@foldkit/devtools/overlay.js#panelView");
1384
- const interactionBlocker = () => __foldkitBrandViewResult((h.div([h.Class('dt-interaction-blocker')], [])), "@foldkit/devtools/overlay.js#interactionBlocker");
1407
+ const interactionBlocker = () => __foldkitBrandViewResult((h.div([h.Class('dt-interaction-blocker')])), "@foldkit/devtools/overlay.js#interactionBlocker");
1385
1408
  return __foldkitBrandViewResult(((model) => __foldkitBrandViewResult((h.div([], [
1386
1409
  ...OptionExt.when(model.isPaused && mode === 'TimeTravel', interactionBlocker()).pipe(Option.toArray),
1387
1410
  ...OptionExt.when(model.isOpen, panelView(model)).pipe(Option.toArray),
@@ -1389,11 +1412,55 @@ const buildOverlayView = (position, mode, shadow, maybeBanner, h) => {
1389
1412
  ])), "@foldkit/devtools/overlay.js#anonymous~91")), "@foldkit/devtools/overlay.js#buildOverlayView");
1390
1413
  };
1391
1414
  // CREATE
1415
+ const VIEW_TRANSITION_NAME = 'foldkit-devtools';
1416
+ const VIEW_TRANSITION_STYLE_ID = 'foldkit-devtools-view-transition';
1417
+ /**
1418
+ * Holds the overlay still through an application's View Transitions.
1419
+ *
1420
+ * The host's `view-transition-name` lifts the overlay out of the page's root
1421
+ * snapshot, which is what stops it cross-fading with the page. The browser then
1422
+ * gives it its own pair of snapshots and cross-fades those against each other
1423
+ * instead. The overlay is identical on both sides of any application render, so
1424
+ * rather than rely on that cross-fade being lossless, the outgoing snapshot is
1425
+ * hidden and the incoming one held opaque.
1426
+ *
1427
+ * Only the two snapshots are pinned. The host spans the viewport, so its old
1428
+ * and new geometry are identical and the group's animation is already a no-op;
1429
+ * there is nothing to gain by overriding it.
1430
+ *
1431
+ * These pseudo-elements live on the top-level document, which the overlay's own
1432
+ * shadow styles cannot reach, so the rule goes in `document.head`.
1433
+ */
1434
+ const installViewTransitionStyle = () => {
1435
+ if (document.getElementById(VIEW_TRANSITION_STYLE_ID) !== null) {
1436
+ return;
1437
+ }
1438
+ const style = document.createElement('style');
1439
+ style.id = VIEW_TRANSITION_STYLE_ID;
1440
+ // NOTE: the UA composites these snapshots with `plus-lighter`, which is
1441
+ // right for a cross-fade and wrong for a snapshot held opaque: it adds to
1442
+ // the backdrop and washes the overlay out.
1443
+ style.textContent = `
1444
+ ::view-transition-old(${VIEW_TRANSITION_NAME}) {
1445
+ animation: none;
1446
+ opacity: 0;
1447
+ mix-blend-mode: normal;
1448
+ }
1449
+
1450
+ ::view-transition-new(${VIEW_TRANSITION_NAME}) {
1451
+ animation: none;
1452
+ opacity: 1;
1453
+ mix-blend-mode: normal;
1454
+ }
1455
+ `;
1456
+ document.head.appendChild(style);
1457
+ };
1392
1458
  const createShadowContainer = () => {
1393
1459
  const existingHost = document.getElementById(DEVTOOLS_HOST_ID);
1394
1460
  if (existingHost) {
1395
1461
  existingHost.remove();
1396
1462
  }
1463
+ installViewTransitionStyle();
1397
1464
  const host = document.createElement('div');
1398
1465
  host.id = DEVTOOLS_HOST_ID;
1399
1466
  host.addEventListener('pointerdown', event => {
@@ -1404,6 +1471,15 @@ const createShadowContainer = () => {
1404
1471
  event.preventDefault();
1405
1472
  }
1406
1473
  }, { capture: true });
1474
+ // NOTE: the name is set here, not on `:host` alongside every other host
1475
+ // property. A `view-transition-name` reaching the host through a shadow
1476
+ // `:host` rule computes (`getComputedStyle` reports it) but Chromium does
1477
+ // not then capture the element as its own snapshot, so the overlay stays in
1478
+ // the page's root snapshot and cross-fades with it. Authored from the light
1479
+ // DOM it captures. Observed in Chromium 149 and not checked elsewhere;
1480
+ // moving this into the stylesheet reintroduces the fade with no other
1481
+ // symptom.
1482
+ host.style.viewTransitionName = VIEW_TRANSITION_NAME;
1407
1483
  document.body.appendChild(host);
1408
1484
  const shadow = host.attachShadow({ mode: 'open' });
1409
1485
  const styleElement = document.createElement('style');
@@ -1416,6 +1492,7 @@ const createShadowContainer = () => {
1416
1492
  export const createOverlay = (store, position, mode, maybeBanner) => __foldkitBrandViewResult((Effect.gen(function* () {
1417
1493
  const { container, shadow } = yield* Effect.acquireRelease(Effect.sync(() => __foldkitBrandViewResult((createShadowContainer()), "@foldkit/devtools/overlay.js#anonymous~94")), createdShadowContainer => __foldkitBrandViewResult((Effect.sync(() => {
1418
1494
  createdShadowContainer.shadow.host.remove();
1495
+ document.getElementById(VIEW_TRANSITION_STYLE_ID)?.remove();
1419
1496
  })), "@foldkit/devtools/overlay.js#anonymous~95"));
1420
1497
  container.id = '__foldkit_devtools_overlay__';
1421
1498
  const flags = Effect.gen(function* () {
package/dist/vite.d.ts ADDED
@@ -0,0 +1,4 @@
1
+ import type { DevToolsOverlay } from 'foldkit/devtools-host';
2
+ /** The in-browser DevTools overlay factory consumed by the Foldkit Vite plugin. */
3
+ export declare const overlay: DevToolsOverlay;
4
+ //# sourceMappingURL=vite.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"vite.d.ts","sourceRoot":"","sources":["../src/vite.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,uBAAuB,CAAA;AAI5D,mFAAmF;AACnF,eAAO,MAAM,OAAO,EAAE,eAA+B,CAAA"}
package/dist/vite.js ADDED
@@ -0,0 +1,3 @@
1
+ import { createOverlay } from './overlay.js';
2
+ /** The in-browser DevTools overlay factory consumed by the Foldkit Vite plugin. */
3
+ export const overlay = createOverlay;
package/package.json CHANGED
@@ -1,15 +1,12 @@
1
1
  {
2
2
  "name": "@foldkit/devtools",
3
- "version": "0.137.0",
3
+ "version": "0.139.0",
4
4
  "description": "In-browser DevTools overlay for Foldkit applications",
5
5
  "type": "module",
6
- "main": "./dist/index.js",
7
- "module": "./dist/index.js",
8
- "types": "./dist/index.d.ts",
9
6
  "exports": {
10
- ".": {
11
- "types": "./dist/index.d.ts",
12
- "import": "./dist/index.js"
7
+ "./vite": {
8
+ "types": "./dist/vite.d.ts",
9
+ "import": "./dist/vite.js"
13
10
  }
14
11
  },
15
12
  "sideEffects": false,
@@ -17,23 +14,23 @@
17
14
  "dist"
18
15
  ],
19
16
  "peerDependencies": {
20
- "@effect/platform-browser": "4.0.0-beta.102",
17
+ "@effect/platform-browser": "4.0.0-beta.103",
21
18
  "@foldkit/ui": "^0",
22
- "effect": "4.0.0-beta.102",
19
+ "effect": "4.0.0-beta.103",
23
20
  "foldkit": "^0"
24
21
  },
25
22
  "dependencies": {
26
23
  "clsx": "^2.1.1"
27
24
  },
28
25
  "devDependencies": {
29
- "@effect/platform-browser": "4.0.0-beta.102",
30
- "effect": "4.0.0-beta.102",
26
+ "@effect/platform-browser": "4.0.0-beta.103",
27
+ "effect": "4.0.0-beta.103",
31
28
  "rimraf": "^6.1.3",
32
29
  "typescript": "^6.0.3",
33
30
  "vitest": "^4.1.9",
34
- "@foldkit/ui": "0.137.0",
35
- "@foldkit/vite-plugin": "0.11.3",
36
- "foldkit": "0.137.0"
31
+ "@foldkit/ui": "0.139.0",
32
+ "@foldkit/vite-plugin": "0.12.0",
33
+ "foldkit": "0.139.0"
37
34
  },
38
35
  "keywords": [
39
36
  "foldkit",
package/dist/index.d.ts DELETED
@@ -1,16 +0,0 @@
1
- import type { DevToolsOverlay } from 'foldkit/runtime';
2
- /**
3
- * The in-browser DevTools overlay factory. Pass it as `DevToolsConfig.overlay`
4
- * to mount the panel:
5
- *
6
- * ```ts
7
- * import { overlay } from '@foldkit/devtools'
8
- *
9
- * Runtime.makeApplication({
10
- * // ...
11
- * devTools: { Message, overlay },
12
- * })
13
- * ```
14
- */
15
- export declare const overlay: DevToolsOverlay;
16
- //# sourceMappingURL=index.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,iBAAiB,CAAA;AAItD;;;;;;;;;;;;GAYG;AACH,eAAO,MAAM,OAAO,EAAE,eAA+B,CAAA"}
package/dist/index.js DELETED
@@ -1,15 +0,0 @@
1
- import { createOverlay } from './overlay.js';
2
- /**
3
- * The in-browser DevTools overlay factory. Pass it as `DevToolsConfig.overlay`
4
- * to mount the panel:
5
- *
6
- * ```ts
7
- * import { overlay } from '@foldkit/devtools'
8
- *
9
- * Runtime.makeApplication({
10
- * // ...
11
- * devTools: { Message, overlay },
12
- * })
13
- * ```
14
- */
15
- export const overlay = createOverlay;