foldkit 0.52.0 → 0.53.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.
@@ -1,3 +1,3 @@
1
- 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-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-tab-button {\n position: relative;\n background: transparent;\n border: none;\n border-right: 1px solid var(--dt-border);\n outline: none;\n flex: 1;\n}\n.dt-tab-button:last-child {\n border-right: none;\n}\n.dt-tab-active {\n background-color: var(--dt-surface-selected);\n}\n.dt-tab-button:not(.dt-tab-active):hover {\n color: var(--dt-text);\n background-color: rgba(49, 50, 68, 0.3);\n}\n.font-sans {\n font-family:\n system-ui,\n -apple-system,\n BlinkMacSystemFont,\n 'Segoe UI',\n Roboto,\n sans-serif;\n}\n.font-mono {\n font-family:\n ui-monospace, SFMono-Regular, 'SF Mono', Menlo, Consolas, monospace;\n}\n.font-medium {\n font-weight: 500;\n}\n.font-semibold {\n font-weight: 600;\n}\n.text-xs {\n font-size: 12px;\n}\n.text-2xs {\n font-size: 10px;\n}\n.text-sm {\n font-size: 11px;\n}\n.text-base {\n font-size: 13px;\n}\n.text-md {\n font-size: 15px;\n}\n.text-lg {\n font-size: 20px;\n}\n.text-xl {\n font-size: 26px;\n}\n.italic {\n font-style: italic;\n}\n.text-right {\n text-align: right;\n}\n.tracking-wide {\n letter-spacing: 0.025em;\n}\n.tracking-wider {\n letter-spacing: 0.05em;\n}\n.leading-none {\n line-height: 1;\n}\n.leading-snug {\n line-height: 1.35;\n}\n.bg-dt-bg {\n background-color: var(--dt-bg);\n}\n.bg-dt-live {\n background-color: var(--dt-live);\n}\n.bg-transparent {\n background-color: transparent;\n}\n.text-dt {\n color: var(--dt-text);\n}\n.text-dt-bg {\n color: var(--dt-bg);\n}\n.text-dt-muted {\n color: var(--dt-text-muted);\n}\n.text-dt-accent {\n color: var(--dt-accent);\n}\n.text-dt-live {\n color: var(--dt-live);\n}\n.text-dt-paused {\n color: var(--dt-paused);\n}\n.cursor-pointer {\n cursor: pointer;\n}\n.outline-none {\n outline: none;\n}\n.transition-colors {\n transition-property: color, background-color, border-color;\n transition-duration: 100ms;\n transition-timing-function: ease;\n}\n\n/* Panel */\n.dt-panel {\n width: 360px;\n height: 480px;\n box-shadow: 0 8px 32px rgba(0, 0, 0, 0.5);\n z-index: 99998;\n}\n/* Panel positions */\n.dt-panel-br {\n bottom: 16px;\n right: 28px;\n}\n.dt-panel-bl {\n bottom: 16px;\n left: 28px;\n}\n.dt-panel-tr {\n top: 16px;\n right: 28px;\n}\n.dt-panel-tl {\n top: 16px;\n left: 28px;\n}\n.dt-panel-wide {\n width: 720px;\n}\n.dt-message-pane {\n width: 320px;\n flex-shrink: 0;\n}\n.dt-badge {\n z-index: 99999;\n box-shadow: -2px 0 8px rgba(0, 0, 0, 0.3);\n transition: background-color 150ms ease;\n border: 1px solid var(--dt-border);\n}\n.dt-badge-accent:hover {\n background-color: #252538;\n}\n.dt-badge-paused {\n background-color: var(--dt-paused);\n color: var(--dt-bg);\n border: none;\n}\n.dt-badge-paused:hover {\n background-color: #e0a070;\n}\n.dt-badge.dt-pos-br,\n.dt-badge.dt-pos-tr {\n border-right: none;\n}\n.dt-badge.dt-pos-bl,\n.dt-badge.dt-pos-tl {\n border-left: none;\n}\n\n/* JSON tree */\n.tree-row {\n position: relative;\n white-space: nowrap;\n line-height: 18px;\n padding-right: 8px;\n}\n.tree-row-expandable:hover {\n background-color: var(--dt-tree-hover);\n}\n.inspector-tree {\n font-family:\n ui-monospace, SFMono-Regular, 'SF Mono', Menlo, Consolas, monospace;\n}\n.json-key {\n color: var(--dt-json-key);\n}\n.json-string {\n color: var(--dt-json-string);\n}\n.json-number {\n color: var(--dt-json-number);\n}\n.json-boolean {\n color: var(--dt-json-boolean);\n}\n.json-null {\n color: var(--dt-json-null);\n}\n.json-tag {\n color: var(--dt-json-tag);\n margin-right: 4px;\n}\n.json-preview {\n color: var(--dt-json-preview);\n}\n.json-arrow {\n color: var(--dt-json-arrow);\n width: 10px;\n height: 10px;\n user-select: none;\n}\n\n/* Diff */\n.diff-changed {\n background-color: rgba(116, 199, 236, 0.06);\n}\n.diff-dot {\n position: absolute;\n left: 3px;\n width: 5px;\n height: 5px;\n border-radius: 9999px;\n background-color: var(--dt-diff-changed);\n}\n.diff-dot-inline {\n width: 5px;\n height: 5px;\n border-radius: 9999px;\n background-color: var(--dt-diff-changed);\n flex-shrink: 0;\n}\n.dot-column {\n width: 5px;\n flex-shrink: 0;\n display: flex;\n align-items: center;\n justify-content: center;\n}\n.pause-column {\n width: 8px;\n flex-shrink: 0;\n display: flex;\n align-items: center;\n justify-content: center;\n}\n.dt-pause-icon {\n width: 8px;\n height: 8px;\n color: var(--dt-paused);\n}\n\n/* Interaction blocker \u2014 covers the app while time-travelling */\n.dt-interaction-blocker {\n position: fixed;\n inset: 0;\n z-index: 99997;\n cursor: not-allowed;\n}\n\n/* Mobile */\n@media (max-width: 767px) {\n .dt-panel {\n top: 0;\n left: 0;\n right: 0;\n bottom: 0;\n width: 100%;\n height: 100%;\n border-radius: 0;\n border: none;\n }\n .dt-panel-wide {\n width: 100%;\n }\n .dt-content {\n flex-direction: column;\n }\n .dt-message-pane {\n width: 100%;\n max-height: 40%;\n border-bottom: 1px solid var(--dt-border);\n }\n .message-list > :last-child {\n border-bottom: none;\n }\n .dt-inspector-pane {\n border-left: none;\n }\n}\n";
1
+ 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-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-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] .json-arrow {\n transform: rotate(180deg);\n}\n.dt-filter-items {\n position: absolute;\n top: 100%;\n left: 0;\n right: 0;\n background-color: var(--dt-bg);\n border-top: none;\n border-bottom: 1px solid var(--dt-border);\n z-index: 10;\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}\n.dt-tab-button {\n position: relative;\n background: transparent;\n border: none;\n border-right: 1px solid var(--dt-border);\n outline: none;\n flex: 1;\n}\n.dt-tab-button:last-child {\n border-right: none;\n}\n.dt-tab-active {\n background-color: var(--dt-surface-selected);\n}\n.dt-tab-button:not(.dt-tab-active):hover {\n color: var(--dt-text);\n background-color: rgba(49, 50, 68, 0.3);\n}\n.font-sans {\n font-family:\n system-ui,\n -apple-system,\n BlinkMacSystemFont,\n 'Segoe UI',\n Roboto,\n sans-serif;\n}\n.font-mono {\n font-family:\n ui-monospace, SFMono-Regular, 'SF Mono', Menlo, Consolas, monospace;\n}\n.font-medium {\n font-weight: 500;\n}\n.font-semibold {\n font-weight: 600;\n}\n.text-xs {\n font-size: 12px;\n}\n.text-2xs {\n font-size: 10px;\n}\n.text-sm {\n font-size: 11px;\n}\n.text-base {\n font-size: 13px;\n}\n.text-md {\n font-size: 15px;\n}\n.text-lg {\n font-size: 20px;\n}\n.text-xl {\n font-size: 26px;\n}\n.italic {\n font-style: italic;\n}\n.text-right {\n text-align: right;\n}\n.tracking-wide {\n letter-spacing: 0.025em;\n}\n.tracking-wider {\n letter-spacing: 0.05em;\n}\n.leading-none {\n line-height: 1;\n}\n.leading-snug {\n line-height: 1.35;\n}\n.bg-dt-bg {\n background-color: var(--dt-bg);\n}\n.bg-dt-live {\n background-color: var(--dt-live);\n}\n.bg-transparent {\n background-color: transparent;\n}\n.text-dt {\n color: var(--dt-text);\n}\n.text-dt-bg {\n color: var(--dt-bg);\n}\n.text-dt-muted {\n color: var(--dt-text-muted);\n}\n.text-dt-accent {\n color: var(--dt-accent);\n}\n.text-dt-live {\n color: var(--dt-live);\n}\n.text-dt-paused {\n color: var(--dt-paused);\n}\n.cursor-pointer {\n cursor: pointer;\n}\n.outline-none {\n outline: none;\n}\n.transition-colors {\n transition-property: color, background-color, border-color;\n transition-duration: 100ms;\n transition-timing-function: ease;\n}\n\n/* Panel */\n.dt-panel {\n width: 360px;\n height: 480px;\n box-shadow: 0 8px 32px rgba(0, 0, 0, 0.5);\n z-index: 99998;\n}\n/* Panel positions */\n.dt-panel-br {\n bottom: 16px;\n right: 28px;\n}\n.dt-panel-bl {\n bottom: 16px;\n left: 28px;\n}\n.dt-panel-tr {\n top: 16px;\n right: 28px;\n}\n.dt-panel-tl {\n top: 16px;\n left: 28px;\n}\n.dt-panel-wide {\n width: 720px;\n}\n.dt-message-pane {\n width: 320px;\n flex-shrink: 0;\n}\n.dt-badge {\n z-index: 99999;\n box-shadow: -2px 0 8px rgba(0, 0, 0, 0.3);\n transition: background-color 150ms ease;\n border: 1px solid var(--dt-border);\n}\n.dt-badge-accent:hover {\n background-color: #252538;\n}\n.dt-badge-paused {\n background-color: var(--dt-paused);\n color: var(--dt-bg);\n border: none;\n}\n.dt-badge-paused:hover {\n background-color: #e0a070;\n}\n.dt-badge.dt-pos-br,\n.dt-badge.dt-pos-tr {\n border-right: none;\n}\n.dt-badge.dt-pos-bl,\n.dt-badge.dt-pos-tl {\n border-left: none;\n}\n\n/* JSON tree */\n.tree-row {\n position: relative;\n white-space: nowrap;\n line-height: 18px;\n padding-right: 8px;\n}\n.tree-row-expandable:hover {\n background-color: var(--dt-tree-hover);\n}\n.inspector-tree {\n font-family:\n ui-monospace, SFMono-Regular, 'SF Mono', Menlo, Consolas, monospace;\n}\n.json-key {\n color: var(--dt-json-key);\n}\n.json-string {\n color: var(--dt-json-string);\n}\n.json-number {\n color: var(--dt-json-number);\n}\n.json-boolean {\n color: var(--dt-json-boolean);\n}\n.json-null {\n color: var(--dt-json-null);\n}\n.json-tag {\n color: var(--dt-json-tag);\n margin-right: 4px;\n}\n.json-preview {\n color: var(--dt-json-preview);\n}\n.json-arrow {\n color: var(--dt-json-arrow);\n width: 10px;\n height: 10px;\n user-select: none;\n}\n\n/* Diff */\n.diff-changed {\n background-color: rgba(116, 199, 236, 0.06);\n}\n.diff-dot {\n position: absolute;\n left: 3px;\n width: 5px;\n height: 5px;\n border-radius: 9999px;\n background-color: var(--dt-diff-changed);\n}\n.diff-dot-inline {\n width: 5px;\n height: 5px;\n border-radius: 9999px;\n background-color: var(--dt-diff-changed);\n flex-shrink: 0;\n}\n.dot-column {\n width: 5px;\n flex-shrink: 0;\n display: flex;\n align-items: center;\n justify-content: center;\n}\n.pause-column {\n width: 8px;\n flex-shrink: 0;\n display: flex;\n align-items: center;\n justify-content: center;\n}\n.dt-pause-icon {\n width: 8px;\n height: 8px;\n color: var(--dt-paused);\n}\n\n/* Interaction blocker \u2014 covers the app while time-travelling */\n.dt-interaction-blocker {\n position: fixed;\n inset: 0;\n z-index: 99997;\n cursor: not-allowed;\n}\n\n/* Mobile */\n@media (max-width: 767px) {\n .dt-panel {\n top: 0;\n left: 0;\n right: 0;\n bottom: 0;\n width: 100%;\n height: 100%;\n border-radius: 0;\n border: none;\n }\n .dt-panel-wide {\n width: 100%;\n }\n .dt-content {\n flex-direction: column;\n }\n .dt-message-pane {\n width: 100%;\n max-height: 40%;\n border-bottom: 1px solid var(--dt-border);\n }\n .message-list > :last-child {\n border-bottom: none;\n }\n .dt-inspector-pane {\n border-left: none;\n }\n}\n";
2
2
  export { overlayStyles };
3
3
  //# sourceMappingURL=overlay-styles.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"overlay-styles.d.ts","sourceRoot":"","sources":["../../src/devtools/overlay-styles.ts"],"names":[],"mappings":"AAAA,QAAA,MAAM,aAAa,m7QA6gBlB,CAAA;AAED,OAAO,EAAE,aAAa,EAAE,CAAA"}
1
+ {"version":3,"file":"overlay-styles.d.ts","sourceRoot":"","sources":["../../src/devtools/overlay-styles.ts"],"names":[],"mappings":"AAAA,QAAA,MAAM,aAAa,kvUA6lBlB,CAAA;AAED,OAAO,EAAE,aAAa,EAAE,CAAA"}
@@ -231,6 +231,86 @@ ul {
231
231
  .dt-resume-button:hover {
232
232
  opacity: 0.7;
233
233
  }
234
+ .dt-filter-wrapper {
235
+ position: relative;
236
+ flex-shrink: 0;
237
+ border-bottom: 1px solid var(--dt-border);
238
+ }
239
+ .dt-filter-button {
240
+ width: 100%;
241
+ display: flex;
242
+ align-items: center;
243
+ justify-content: space-between;
244
+ padding: 6px 12px;
245
+ background: transparent;
246
+ border: none;
247
+ color: var(--dt-text-muted);
248
+ font-family:
249
+ ui-monospace, SFMono-Regular, 'SF Mono', Menlo, Consolas, monospace;
250
+ font-size: 13px;
251
+ cursor: pointer;
252
+ text-align: left;
253
+ }
254
+ .dt-filter-button:hover {
255
+ color: var(--dt-text);
256
+ background-color: var(--dt-tree-hover);
257
+ }
258
+ .dt-filter-button:focus-visible {
259
+ outline: 1px solid var(--dt-accent);
260
+ outline-offset: -1px;
261
+ }
262
+ .dt-filter-button[data-open] {
263
+ color: var(--dt-text);
264
+ background-color: var(--dt-surface-selected);
265
+ }
266
+ .dt-filter-button[data-open] .json-arrow {
267
+ transform: rotate(180deg);
268
+ }
269
+ .dt-filter-items {
270
+ position: absolute;
271
+ top: 100%;
272
+ left: 0;
273
+ right: 0;
274
+ background-color: var(--dt-bg);
275
+ border-top: none;
276
+ border-bottom: 1px solid var(--dt-border);
277
+ z-index: 10;
278
+ max-height: 200px;
279
+ overflow-y: auto;
280
+ outline: none;
281
+ }
282
+ .dt-filter-item {
283
+ padding: 6px 12px;
284
+ color: var(--dt-text-muted);
285
+ cursor: pointer;
286
+ font-family:
287
+ ui-monospace, SFMono-Regular, 'SF Mono', Menlo, Consolas, monospace;
288
+ font-size: 13px;
289
+ border-bottom: 1px solid var(--dt-border);
290
+ }
291
+ .dt-filter-item:last-child {
292
+ border-bottom: none;
293
+ }
294
+ .dt-filter-item[data-active] {
295
+ background-color: var(--dt-tree-hover);
296
+ color: var(--dt-text);
297
+ }
298
+ .dt-filter-item[data-selected] {
299
+ color: var(--dt-accent);
300
+ }
301
+ .dt-filter-check {
302
+ width: 12px;
303
+ height: 12px;
304
+ visibility: hidden;
305
+ }
306
+ .dt-filter-item[data-selected] .dt-filter-check {
307
+ visibility: visible;
308
+ color: var(--dt-accent);
309
+ }
310
+ .dt-filter-backdrop {
311
+ position: fixed;
312
+ inset: 0;
313
+ }
234
314
  .dt-tab-button {
235
315
  position: relative;
236
316
  background: transparent;
@@ -1 +1 @@
1
- {"version":3,"file":"overlay.d.ts","sourceRoot":"","sources":["../../src/devtools/overlay.ts"],"names":[],"mappings":"AACA,OAAO,EAEL,MAAM,EACN,OAAO,EAGP,MAAM,EAQP,MAAM,QAAQ,CAAA;AAEf,OAAO,KAAK,OAAO,MAAM,YAAY,CAAA;AAKrC,OAAO,KAAK,EAAE,YAAY,EAAE,gBAAgB,EAAE,MAAM,oBAAoB,CAAA;AAMxE,OAAO,EAAE,KAAK,aAAa,EAA+B,MAAM,SAAS,CAAA;AA0KzE,eAAO,MAAM,MAAM;;EAA0C,CAAA;AAC7D,eAAO,MAAM,YAAY;;;;;;EAGxB,CAAA;AACD,eAAO,MAAM,aAAa;;;;;;EAGzB,CAAA;AACD,eAAO,MAAM,MAAM;;EAA4C,CAAA;AAC/D,eAAO,MAAM,KAAK;;EAA0C,CAAA;AAC5D,eAAO,MAAM,UAAU;;EAA6C,CAAA;AACpE,eAAO,MAAM,YAAY;;EAAiD,CAAA;AAC1E,eAAO,MAAM,WAAW;;EAA+C,CAAA;AAkmCvE,eAAO,MAAM,aAAa,GACxB,OAAO,aAAa,EACpB,UAAU,gBAAgB,EAC1B,MAAM,YAAY,EAClB,aAAa,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,sCA4ChC,CAAA"}
1
+ {"version":3,"file":"overlay.d.ts","sourceRoot":"","sources":["../../src/devtools/overlay.ts"],"names":[],"mappings":"AACA,OAAO,EAEL,MAAM,EAGN,OAAO,EAGP,MAAM,EASP,MAAM,QAAQ,CAAA;AAEf,OAAO,KAAK,OAAO,MAAM,YAAY,CAAA;AAKrC,OAAO,KAAK,EAAE,YAAY,EAAE,gBAAgB,EAAE,MAAM,oBAAoB,CAAA;AAOxE,OAAO,EACL,KAAK,aAAa,EAInB,MAAM,SAAS,CAAA;AAmNhB,eAAO,MAAM,MAAM;;EAA0C,CAAA;AAC7D,eAAO,MAAM,YAAY;;;;;;EAGxB,CAAA;AACD,eAAO,MAAM,aAAa;;;;;;EAGzB,CAAA;AACD,eAAO,MAAM,MAAM;;EAA4C,CAAA;AAC/D,eAAO,MAAM,KAAK;;EAA0C,CAAA;AAC5D,eAAO,MAAM,UAAU;;EAA6C,CAAA;AACpE,eAAO,MAAM,YAAY;;EAAiD,CAAA;AAC1E,eAAO,MAAM,WAAW;;EAA+C,CAAA;AA2xCvE,eAAO,MAAM,aAAa,GACxB,OAAO,aAAa,EACpB,UAAU,gBAAgB,EAC1B,MAAM,YAAY,EAClB,aAAa,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,sCAkDhC,CAAA"}
@@ -1,5 +1,5 @@
1
1
  import { clsx } from 'clsx';
2
- import { Array as Array_, Effect, HashSet, Match as M, Number as Number_, Option, Predicate, Record, Schema as S, Stream, String as String_, SubscriptionRef, pipe, } from 'effect';
2
+ import { Array as Array_, Effect, Equal, Function, HashSet, Match as M, Number as Number_, Option, Order, Predicate, Record, Schema as S, Stream, String as String_, SubscriptionRef, pipe, } from 'effect';
3
3
  import * as Command from '../command';
4
4
  import { OptionExt } from '../effectExtensions';
5
5
  import { createKeyedLazy, html } from '../html';
@@ -8,17 +8,20 @@ import { makeProgram } from '../runtime/runtime';
8
8
  import { makeSubscriptions } from '../runtime/subscription';
9
9
  import { evo } from '../struct';
10
10
  import { lockScroll, unlockScroll } from '../task/scrollLock';
11
+ import * as Listbox from '../ui/listbox/public';
11
12
  import * as Tabs from '../ui/tabs';
12
13
  import { overlayStyles } from './overlay-styles';
13
- import { INIT_INDEX } from './store';
14
+ import { INIT_INDEX, } from './store';
14
15
  // MODEL
15
16
  const DisplayEntry = S.Struct({
16
17
  tag: S.String,
18
+ maybeInnerTag: S.OptionFromSelf(S.String),
17
19
  commandNames: S.Array(S.String),
18
20
  timestamp: S.Number,
19
21
  isModelChanged: S.Boolean,
20
22
  });
21
23
  const INSPECTOR_TABS_ID = 'dt-inspector';
24
+ const SUBMODEL_FILTER_ID = 'dt-submodel-filter';
22
25
  const InspectorTabsModel = S.Struct({
23
26
  id: S.String,
24
27
  activeIndex: S.Number,
@@ -37,6 +40,9 @@ const Model = S.Struct({
37
40
  isFollowingLatest: S.Boolean,
38
41
  maybeInspectedModel: S.OptionFromSelf(S.Unknown),
39
42
  maybeInspectedMessage: S.OptionFromSelf(S.Unknown),
43
+ submodelTags: S.Array(S.String),
44
+ maybeSubmodelFilter: S.OptionFromSelf(S.String),
45
+ submodelFilterListbox: Listbox.Model,
40
46
  expandedPaths: S.HashSetFromSelf(S.String),
41
47
  changedPaths: S.HashSetFromSelf(S.String),
42
48
  affectedPaths: S.HashSetFromSelf(S.String),
@@ -82,20 +88,35 @@ const ReceivedStoreUpdate = m('ReceivedStoreUpdate', {
82
88
  isPaused: S.Boolean,
83
89
  pausedAtIndex: S.Number,
84
90
  });
85
- const Message = S.Union(ClickedToggle, ClickedRow, ClickedResume, ClickedClear, ClickedFollowLatest, CompletedJump, CompletedResume, CompletedClear, LockedScroll, UnlockedScroll, ScrolledToTop, CrossedMobileBreakpoint, ReceivedInspectedState, ToggledTreeNode, GotInspectorTabsMessage, ReceivedStoreUpdate);
91
+ const GotSubmodelFilterMessage = m('GotSubmodelFilterMessage', {
92
+ message: Listbox.Message,
93
+ });
94
+ const SelectedSubmodelFilter = m('SelectedSubmodelFilter', {
95
+ tag: S.String,
96
+ });
97
+ const Message = S.Union(ClickedToggle, ClickedRow, ClickedResume, ClickedClear, ClickedFollowLatest, CompletedJump, CompletedResume, CompletedClear, LockedScroll, UnlockedScroll, ScrolledToTop, CrossedMobileBreakpoint, ReceivedInspectedState, ToggledTreeNode, GotInspectorTabsMessage, ReceivedStoreUpdate, GotSubmodelFilterMessage, SelectedSubmodelFilter);
86
98
  // HELPERS
87
99
  const MILLIS_PER_SECOND = 1000;
88
100
  const MOBILE_BREAKPOINT = 767;
89
101
  const MOBILE_BREAKPOINT_QUERY = `(max-width: ${MOBILE_BREAKPOINT}px)`;
90
102
  const TREE_INDENT_PX = 12;
91
103
  const MAX_PREVIEW_KEYS = 3;
104
+ const ALL_MESSAGES_VALUE = '';
92
105
  const formatTimeDelta = (deltaMs) => M.value(deltaMs).pipe(M.when(0, () => '0ms'), M.when(Number_.lessThan(MILLIS_PER_SECOND), ms => `+${Math.round(ms)}ms`), M.orElse(ms => `+${(ms / MILLIS_PER_SECOND).toFixed(1)}s`));
93
106
  const MESSAGE_LIST_SELECTOR = '.message-list';
94
- const toDisplayEntries = ({ entries }) => Array_.map(entries, ({ tag, commandNames, timestamp, isModelChanged }) => ({
95
- tag,
96
- commandNames,
97
- timestamp,
98
- isModelChanged,
107
+ const computeSubmodelTags = (entries) => pipe(entries, Array_.filterMap(entry => entry.maybeInnerTag.pipe(Option.as(entry.tag))), Array_.dedupe, Array_.sort(Order.string));
108
+ const GOT_MESSAGE_PATTERN = /^Got.+Message$/;
109
+ const extractInnerTag = (entry) => pipe(entry.tag, String_.search(GOT_MESSAGE_PATTERN), Option.flatMap(() => {
110
+ // eslint-disable-next-line @typescript-eslint/consistent-type-assertions
111
+ const inner = entry.message?.['message'];
112
+ return pipe(inner, Option.liftPredicate(isTagged), Option.map(({ _tag }) => _tag));
113
+ }));
114
+ const toDisplayEntries = ({ entries }) => Array_.map(entries, entry => ({
115
+ tag: entry.tag,
116
+ maybeInnerTag: extractInnerTag(entry),
117
+ commandNames: entry.commandNames,
118
+ timestamp: entry.timestamp,
119
+ isModelChanged: entry.isModelChanged,
99
120
  }));
100
121
  const toDisplayState = (state) => ({
101
122
  entries: toDisplayEntries(state),
@@ -104,7 +125,7 @@ const toDisplayState = (state) => ({
104
125
  isPaused: state.isPaused,
105
126
  pausedAtIndex: state.pausedAtIndex,
106
127
  });
107
- const isExpandable = (value) => Predicate.isNotNull(value) && typeof value === 'object';
128
+ const isExpandable = (value) => Predicate.isObject(value);
108
129
  const Tagged = S.Struct({ _tag: S.String });
109
130
  const isTagged = S.is(Tagged);
110
131
  const objectPreview = (value) => pipe(value, Record.keys, Array_.filter(key => key !== '_tag'), Array_.match({
@@ -196,6 +217,7 @@ const makeUpdate = (store, shadow, mode) => {
196
217
  evo(model, {
197
218
  selectedIndex: () => INIT_INDEX,
198
219
  isFollowingLatest: () => true,
220
+ maybeSubmodelFilter: () => Option.none(),
199
221
  expandedPaths: () => HashSet.empty(),
200
222
  changedPaths: () => HashSet.empty(),
201
223
  affectedPaths: () => HashSet.empty(),
@@ -250,6 +272,8 @@ const makeUpdate = (store, shadow, mode) => {
250
272
  onEmpty: () => INIT_INDEX,
251
273
  onNonEmpty: () => startIndex + entries.length - 1,
252
274
  });
275
+ const nextSubmodelTags = computeSubmodelTags(entries);
276
+ const isFilterStale = Option.exists(model.maybeSubmodelFilter, filterTag => !Array_.contains(nextSubmodelTags, filterTag));
253
277
  return [
254
278
  evo(model, {
255
279
  entries: () => entries,
@@ -257,11 +281,37 @@ const makeUpdate = (store, shadow, mode) => {
257
281
  startIndex: () => startIndex,
258
282
  isPaused: () => isPaused,
259
283
  pausedAtIndex: () => pausedAtIndex,
284
+ submodelTags: () => nextSubmodelTags,
285
+ maybeSubmodelFilter: current => isFilterStale ? Option.none() : current,
286
+ submodelFilterListbox: current => isFilterStale
287
+ ? evo(current, {
288
+ maybeSelectedItem: () => Option.some(ALL_MESSAGES_VALUE),
289
+ })
290
+ : current,
260
291
  selectedIndex: current => shouldFollowLatest ? latestIndex : current,
261
292
  }),
262
293
  shouldFollowLatest ? [scrollToTop, inspectLatest] : [],
263
294
  ];
264
295
  },
296
+ GotSubmodelFilterMessage: ({ message: listboxMessage }) => {
297
+ const [nextListboxModel, listboxCommands] = Listbox.update(model.submodelFilterListbox, listboxMessage);
298
+ return [
299
+ evo(model, {
300
+ submodelFilterListbox: () => nextListboxModel,
301
+ }),
302
+ listboxCommands.map(Command.mapEffect(Effect.map(innerMessage => GotSubmodelFilterMessage({ message: innerMessage })))),
303
+ ];
304
+ },
305
+ SelectedSubmodelFilter: ({ tag }) => {
306
+ const [nextListbox, listboxCommands] = Listbox.selectItem(model.submodelFilterListbox, tag);
307
+ return [
308
+ evo(model, {
309
+ maybeSubmodelFilter: () => Option.liftPredicate(tag, String_.isNonEmpty),
310
+ submodelFilterListbox: () => nextListbox,
311
+ }),
312
+ listboxCommands.map(Command.mapEffect(Effect.map(innerMessage => GotSubmodelFilterMessage({ message: innerMessage })))),
313
+ ];
314
+ },
265
315
  }), M.tag('CompletedJump', 'CompletedResume', 'CompletedClear', 'LockedScroll', 'UnlockedScroll', 'ScrolledToTop', () => [model, []]), M.exhaustive);
266
316
  };
267
317
  // SUBSCRIPTION
@@ -467,16 +517,27 @@ const makeView = (position, mode, maybeBanner) => {
467
517
  Class('flex-1 flex items-center justify-center text-dt-muted text-2xs font-mono min-w-0'),
468
518
  ], ['init — no Message']);
469
519
  const modelTabContent = (model, inspectedModel) => treeView(inspectedModel, 'root', model.expandedPaths, model.changedPaths, model.affectedPaths, Option.none(), true);
520
+ const unwrapIfFiltered = (message, model) => {
521
+ if (Option.isNone(model.maybeSubmodelFilter)) {
522
+ return message;
523
+ }
524
+ // eslint-disable-next-line @typescript-eslint/consistent-type-assertions
525
+ const inner = message?.['message'];
526
+ return isTagged(inner) ? inner : message;
527
+ };
470
528
  const messageTabContent = (model) => Option.match(model.maybeInspectedMessage, {
471
529
  onNone: () => noMessageView,
472
- onSome: message => div([Class('flex flex-col flex-1 min-h-0 min-w-0')], [
473
- div([
474
- Class('px-2 py-1 border-b text-2xs text-dt-muted font-mono shrink-0'),
475
- ], [inspectedTimestamp(model)]),
476
- div([Class('flex flex-col flex-1 min-h-0 min-w-0 pt-1 pl-1')], [
477
- treeView(message, 'root', model.expandedPaths, HashSet.empty(), HashSet.empty(), Option.none(), false),
478
- ]),
479
- ]),
530
+ onSome: rawMessage => {
531
+ const message = unwrapIfFiltered(rawMessage, model);
532
+ return div([Class('flex flex-col flex-1 min-h-0 min-w-0')], [
533
+ div([
534
+ Class('px-2 py-1 border-b text-2xs text-dt-muted font-mono shrink-0'),
535
+ ], [inspectedTimestamp(model)]),
536
+ div([Class('flex flex-col flex-1 min-h-0 min-w-0 pt-1 pl-1')], [
537
+ treeView(message, 'root', model.expandedPaths, HashSet.empty(), HashSet.empty(), Option.none(), false),
538
+ ]),
539
+ ]);
540
+ },
480
541
  });
481
542
  const selectedCommandNames = (model) => {
482
543
  const selectedIndex = M.value(mode).pipe(M.when('TimeTravel', () => model.isPaused ? model.pausedAtIndex : INIT_INDEX), M.when('Inspect', () => model.selectedIndex), M.exhaustive);
@@ -552,30 +613,80 @@ const makeView = (position, mode, maybeBanner) => {
552
613
  const actionButtonClass = 'dt-resume-button bg-transparent border-none text-dt-live cursor-pointer text-base font-mono font-medium';
553
614
  const statusClass = 'text-base font-mono';
554
615
  const clearHistoryButton = button([Class(headerButtonClass), OnClick(ClickedClear())], ['Clear history']);
616
+ const submodelLabel = (tag) => pipe(tag, String_.replace(/^Got/, ''), String_.replace(/Message$/, ''));
617
+ const CHECK_ICON = 'M4.5 12.75l6 6 9-13.5';
618
+ const checkIconView = svg([
619
+ AriaHidden(true),
620
+ Class('dt-filter-check shrink-0'),
621
+ Xmlns('http://www.w3.org/2000/svg'),
622
+ Fill('none'),
623
+ ViewBox('0 0 24 24'),
624
+ StrokeWidth('2'),
625
+ Stroke('currentColor'),
626
+ ], [
627
+ path([D(CHECK_ICON), StrokeLinecap('round'), StrokeLinejoin('round')], []),
628
+ ]);
629
+ const filterItemLabel = (item) => String_.isNonEmpty(item) ? submodelLabel(item) : 'All Messages';
630
+ const submodelFilterView = (model) => {
631
+ const buttonLabel = Option.match(model.maybeSubmodelFilter, {
632
+ onNone: () => 'All Messages',
633
+ onSome: submodelLabel,
634
+ });
635
+ return Listbox.view({
636
+ model: model.submodelFilterListbox,
637
+ toParentMessage: message => GotSubmodelFilterMessage({ message }),
638
+ onSelectedItem: tag => SelectedSubmodelFilter({ tag }),
639
+ items: [ALL_MESSAGES_VALUE, ...model.submodelTags],
640
+ itemToConfig: item => ({
641
+ className: 'dt-filter-item',
642
+ content: div([Class('flex items-center gap-2')], [checkIconView, span([], [filterItemLabel(item)])]),
643
+ }),
644
+ buttonContent: span([Class('flex flex-1 items-center justify-between')], [
645
+ span([], [buttonLabel]),
646
+ svg([
647
+ AriaHidden(true),
648
+ Class('json-arrow shrink-0'),
649
+ Xmlns('http://www.w3.org/2000/svg'),
650
+ Fill('none'),
651
+ ViewBox('0 0 24 24'),
652
+ StrokeWidth('2'),
653
+ Stroke('currentColor'),
654
+ ], [
655
+ path([
656
+ D(CHEVRON_DOWN),
657
+ StrokeLinecap('round'),
658
+ StrokeLinejoin('round'),
659
+ ], []),
660
+ ]),
661
+ ]),
662
+ buttonClassName: 'dt-filter-button',
663
+ itemsClassName: 'dt-filter-items',
664
+ className: 'dt-filter-wrapper',
665
+ backdropClassName: 'dt-filter-backdrop',
666
+ });
667
+ };
555
668
  const headerView = (model) => {
556
- const { status, action } = M.value(mode).pipe(M.withReturnType(), M.when('TimeTravel', () => model.isPaused
669
+ const { status, maybeAction } = M.value(mode).pipe(M.withReturnType(), M.when('TimeTravel', () => model.isPaused
557
670
  ? {
558
671
  status: span([Class(`${statusClass} text-dt-paused`)], [
559
672
  model.pausedAtIndex === INIT_INDEX
560
673
  ? 'Paused (init)'
561
674
  : `Paused (${model.pausedAtIndex + 1})`,
562
675
  ]),
563
- action: button([Class(actionButtonClass), OnClick(ClickedResume())], ['Resume →']),
676
+ maybeAction: Option.some(button([Class(actionButtonClass), OnClick(ClickedResume())], ['Resume →'])),
564
677
  }
565
678
  : {
566
679
  status: span([Class(`${statusClass} text-dt-live font-medium`)], ['Live']),
567
- action: div([], []),
680
+ maybeAction: Option.none(),
568
681
  }), M.when('Inspect', () => ({
569
682
  status: span([Class(`${statusClass} text-dt-accent`)], [
570
683
  model.selectedIndex === INIT_INDEX
571
684
  ? 'Inspecting (init)'
572
685
  : `Inspecting (${model.selectedIndex + 1})`,
573
686
  ]),
574
- action: model.isFollowingLatest
575
- ? div([], [])
576
- : button([Class(actionButtonClass), OnClick(ClickedFollowLatest())], ['Follow Latest →']),
687
+ maybeAction: OptionExt.when(!model.isFollowingLatest, button([Class(actionButtonClass), OnClick(ClickedFollowLatest())], ['Follow Latest →'])),
577
688
  })), M.exhaustive);
578
- return header([Class(headerClass)], [status, action, clearHistoryButton]);
689
+ return header([Class(headerClass)], [status, ...Option.toArray(maybeAction), clearHistoryButton]);
579
690
  };
580
691
  const initRowView = (isSelected, isPausedHere) => keyed('li')('init', [
581
692
  Class(clsx(ROW_BASE, { selected: isSelected })),
@@ -623,12 +734,21 @@ const makeView = (position, mode, maybeBanner) => {
623
734
  : model.startIndex + model.entries.length - 1;
624
735
  const selectedIndex = M.value(mode).pipe(M.when('TimeTravel', () => model.isPaused ? model.pausedAtIndex : lastIndex), M.when('Inspect', () => model.selectedIndex), M.exhaustive);
625
736
  const isInitSelected = selectedIndex === INIT_INDEX;
626
- const messageRows = pipe(model.entries, Array_.map((entry, arrayIndex) => {
627
- const absoluteIndex = model.startIndex + arrayIndex;
737
+ const isFiltered = Option.isSome(model.maybeSubmodelFilter);
738
+ const indexedEntries = pipe(model.entries, Array_.map((entry, arrayIndex) => ({
739
+ entry,
740
+ absoluteIndex: model.startIndex + arrayIndex,
741
+ })), isFiltered
742
+ ? Array_.filter(({ entry }) => Option.exists(model.maybeSubmodelFilter, Equal.equals(entry.tag)))
743
+ : Function.identity);
744
+ const messageRows = pipe(indexedEntries, Array_.map(({ entry, absoluteIndex }) => {
628
745
  const isSelected = selectedIndex === absoluteIndex;
629
746
  const isPausedHere = model.isPaused && model.pausedAtIndex === absoluteIndex;
747
+ const displayTag = isFiltered
748
+ ? Option.getOrElse(entry.maybeInnerTag, () => entry.tag)
749
+ : entry.tag;
630
750
  return lazyMessageRow(String(absoluteIndex), messageRowView, [
631
- entry.tag,
751
+ displayTag,
632
752
  absoluteIndex,
633
753
  isSelected,
634
754
  isPausedHere,
@@ -636,10 +756,12 @@ const makeView = (position, mode, maybeBanner) => {
636
756
  entry.isModelChanged,
637
757
  ]);
638
758
  }), Array_.reverse);
639
- return ul([Class('message-list flex-1 overflow-y-auto min-h-0 overscroll-none')], [
640
- ...messageRows,
641
- initRowView(isInitSelected, model.isPaused && model.pausedAtIndex === INIT_INDEX),
642
- ]);
759
+ return ul([Class('message-list flex-1 overflow-y-auto min-h-0 overscroll-none')], isFiltered
760
+ ? messageRows
761
+ : [
762
+ ...messageRows,
763
+ initRowView(isInitSelected, model.isPaused && model.pausedAtIndex === INIT_INDEX),
764
+ ]);
643
765
  };
644
766
  // PANEL
645
767
  const panelView = (model) => keyed('div')('dt-panel', [
@@ -650,7 +772,13 @@ const makeView = (position, mode, maybeBanner) => {
650
772
  ], [banner])).pipe(Option.toArray),
651
773
  headerView(model),
652
774
  div([Class('flex flex-1 min-h-0 dt-content')], [
653
- div([Class('flex flex-col min-h-0 dt-message-pane')], [messageListView(model)]),
775
+ div([Class('flex flex-col min-h-0 dt-message-pane')], [
776
+ ...Array_.match(model.submodelTags, {
777
+ onEmpty: () => [],
778
+ onNonEmpty: () => [submodelFilterView(model)],
779
+ }),
780
+ messageListView(model),
781
+ ]),
654
782
  inspectorPaneView(model),
655
783
  ]),
656
784
  ]);
@@ -694,6 +822,12 @@ export const createOverlay = (store, position, mode, maybeBanner) => Effect.gen(
694
822
  ...flags,
695
823
  selectedIndex: INIT_INDEX,
696
824
  isFollowingLatest: true,
825
+ submodelTags: computeSubmodelTags(flags.entries),
826
+ maybeSubmodelFilter: Option.none(),
827
+ submodelFilterListbox: Listbox.init({
828
+ id: SUBMODEL_FILTER_ID,
829
+ selectedItem: ALL_MESSAGES_VALUE,
830
+ }),
697
831
  maybeInspectedModel: Option.none(),
698
832
  maybeInspectedMessage: Option.none(),
699
833
  expandedPaths: HashSet.empty(),
@@ -34,17 +34,17 @@ export declare const update: (model: {
34
34
  readonly isOpen: boolean;
35
35
  readonly isAnimated: boolean;
36
36
  readonly isModal: boolean;
37
- readonly nullable: boolean;
38
- readonly immediate: boolean;
39
- readonly selectInputOnFocus: boolean;
40
37
  readonly transitionState: "Idle" | "EnterStart" | "EnterAnimating" | "LeaveStart" | "LeaveAnimating";
41
38
  readonly maybeActiveItemIndex: import("effect/Option").Option<number>;
42
39
  readonly activationTrigger: "Pointer" | "Keyboard";
43
- readonly inputValue: string;
44
40
  readonly maybeLastPointerPosition: import("effect/Option").Option<{
45
41
  readonly screenX: number;
46
42
  readonly screenY: number;
47
43
  }>;
44
+ readonly nullable: boolean;
45
+ readonly immediate: boolean;
46
+ readonly selectInputOnFocus: boolean;
47
+ readonly inputValue: string;
48
48
  } & {
49
49
  readonly selectedItems: readonly string[];
50
50
  }, message: import("./shared").Message) => readonly [{
@@ -52,68 +52,68 @@ export declare const update: (model: {
52
52
  readonly isOpen: boolean;
53
53
  readonly isAnimated: boolean;
54
54
  readonly isModal: boolean;
55
- readonly nullable: boolean;
56
- readonly immediate: boolean;
57
- readonly selectInputOnFocus: boolean;
58
55
  readonly transitionState: "Idle" | "EnterStart" | "EnterAnimating" | "LeaveStart" | "LeaveAnimating";
59
56
  readonly maybeActiveItemIndex: import("effect/Option").Option<number>;
60
57
  readonly activationTrigger: "Pointer" | "Keyboard";
61
- readonly inputValue: string;
62
58
  readonly maybeLastPointerPosition: import("effect/Option").Option<{
63
59
  readonly screenX: number;
64
60
  readonly screenY: number;
65
61
  }>;
62
+ readonly nullable: boolean;
63
+ readonly immediate: boolean;
64
+ readonly selectInputOnFocus: boolean;
65
+ readonly inputValue: string;
66
66
  } & {
67
67
  readonly selectedItems: readonly string[];
68
68
  }, readonly Readonly<{
69
69
  name: string;
70
70
  effect: import("effect/Effect").Effect<{
71
- readonly _tag: "Opened";
72
- readonly maybeActiveItemIndex: import("effect/Option").Option<number>;
73
- } | {
74
71
  readonly _tag: "Closed";
75
72
  } | {
76
73
  readonly _tag: "ClosedByTab";
74
+ } | {
75
+ readonly _tag: "DeactivatedItem";
76
+ } | {
77
+ readonly _tag: "CompletedLockScroll";
78
+ } | {
79
+ readonly _tag: "CompletedUnlockScroll";
80
+ } | {
81
+ readonly _tag: "CompletedSetupInert";
82
+ } | {
83
+ readonly _tag: "CompletedTeardownInert";
84
+ } | {
85
+ readonly _tag: "CompletedScrollIntoView";
86
+ } | {
87
+ readonly _tag: "CompletedClickItem";
88
+ } | {
89
+ readonly _tag: "AdvancedTransitionFrame";
90
+ } | {
91
+ readonly _tag: "EndedTransition";
92
+ } | {
93
+ readonly _tag: "Opened";
94
+ readonly maybeActiveItemIndex: import("effect/Option").Option<number>;
77
95
  } | {
78
96
  readonly _tag: "ActivatedItem";
79
- readonly index: number;
80
97
  readonly activationTrigger: "Pointer" | "Keyboard";
98
+ readonly index: number;
81
99
  readonly maybeImmediateSelection: import("effect/Option").Option<{
82
100
  readonly item: string;
83
101
  readonly displayText: string;
84
102
  }>;
85
- } | {
86
- readonly _tag: "DeactivatedItem";
87
103
  } | {
88
104
  readonly _tag: "SelectedItem";
89
105
  readonly item: string;
90
106
  readonly displayText: string;
91
107
  } | {
92
108
  readonly _tag: "MovedPointerOverItem";
93
- readonly index: number;
94
109
  readonly screenX: number;
95
110
  readonly screenY: number;
111
+ readonly index: number;
96
112
  } | {
97
113
  readonly _tag: "RequestedItemClick";
98
114
  readonly index: number;
99
- } | {
100
- readonly _tag: "CompletedLockScroll";
101
- } | {
102
- readonly _tag: "CompletedUnlockScroll";
103
- } | {
104
- readonly _tag: "CompletedSetupInert";
105
- } | {
106
- readonly _tag: "CompletedTeardownInert";
107
115
  } | {
108
116
  readonly _tag: "CompletedFocusInput";
109
- } | {
110
- readonly _tag: "CompletedScrollIntoView";
111
- } | {
112
- readonly _tag: "CompletedClickItem";
113
- } | {
114
- readonly _tag: "AdvancedTransitionFrame";
115
- } | {
116
- readonly _tag: "EndedTransition";
117
117
  } | {
118
118
  readonly _tag: "DetectedInputMovement";
119
119
  } | {
@@ -132,17 +132,17 @@ export declare const view: <Message, Item extends string>(config: Readonly<{
132
132
  readonly isOpen: boolean;
133
133
  readonly isAnimated: boolean;
134
134
  readonly isModal: boolean;
135
- readonly nullable: boolean;
136
- readonly immediate: boolean;
137
- readonly selectInputOnFocus: boolean;
138
135
  readonly transitionState: "Idle" | "EnterStart" | "EnterAnimating" | "LeaveStart" | "LeaveAnimating";
139
136
  readonly maybeActiveItemIndex: import("effect/Option").Option<number>;
140
137
  readonly activationTrigger: "Pointer" | "Keyboard";
141
- readonly inputValue: string;
142
138
  readonly maybeLastPointerPosition: import("effect/Option").Option<{
143
139
  readonly screenX: number;
144
140
  readonly screenY: number;
145
141
  }>;
142
+ readonly nullable: boolean;
143
+ readonly immediate: boolean;
144
+ readonly selectInputOnFocus: boolean;
145
+ readonly inputValue: string;
146
146
  } & {
147
147
  readonly selectedItems: readonly string[];
148
148
  };
@@ -205,52 +205,52 @@ export declare const makeUpdate: <Model extends BaseModel>(handlers: Readonly<{
205
205
  }>) => (model: Model, message: Message) => readonly [Model, readonly Readonly<{
206
206
  name: string;
207
207
  effect: Effect.Effect<{
208
- readonly _tag: "Opened";
209
- readonly maybeActiveItemIndex: Option.Option<number>;
210
- } | {
211
208
  readonly _tag: "Closed";
212
209
  } | {
213
210
  readonly _tag: "ClosedByTab";
211
+ } | {
212
+ readonly _tag: "DeactivatedItem";
213
+ } | {
214
+ readonly _tag: "CompletedLockScroll";
215
+ } | {
216
+ readonly _tag: "CompletedUnlockScroll";
217
+ } | {
218
+ readonly _tag: "CompletedSetupInert";
219
+ } | {
220
+ readonly _tag: "CompletedTeardownInert";
221
+ } | {
222
+ readonly _tag: "CompletedScrollIntoView";
223
+ } | {
224
+ readonly _tag: "CompletedClickItem";
225
+ } | {
226
+ readonly _tag: "AdvancedTransitionFrame";
227
+ } | {
228
+ readonly _tag: "EndedTransition";
229
+ } | {
230
+ readonly _tag: "Opened";
231
+ readonly maybeActiveItemIndex: Option.Option<number>;
214
232
  } | {
215
233
  readonly _tag: "ActivatedItem";
216
- readonly index: number;
217
234
  readonly activationTrigger: "Pointer" | "Keyboard";
235
+ readonly index: number;
218
236
  readonly maybeImmediateSelection: Option.Option<{
219
237
  readonly item: string;
220
238
  readonly displayText: string;
221
239
  }>;
222
- } | {
223
- readonly _tag: "DeactivatedItem";
224
240
  } | {
225
241
  readonly _tag: "SelectedItem";
226
242
  readonly item: string;
227
243
  readonly displayText: string;
228
244
  } | {
229
245
  readonly _tag: "MovedPointerOverItem";
230
- readonly index: number;
231
246
  readonly screenX: number;
232
247
  readonly screenY: number;
248
+ readonly index: number;
233
249
  } | {
234
250
  readonly _tag: "RequestedItemClick";
235
251
  readonly index: number;
236
- } | {
237
- readonly _tag: "CompletedLockScroll";
238
- } | {
239
- readonly _tag: "CompletedUnlockScroll";
240
- } | {
241
- readonly _tag: "CompletedSetupInert";
242
- } | {
243
- readonly _tag: "CompletedTeardownInert";
244
252
  } | {
245
253
  readonly _tag: "CompletedFocusInput";
246
- } | {
247
- readonly _tag: "CompletedScrollIntoView";
248
- } | {
249
- readonly _tag: "CompletedClickItem";
250
- } | {
251
- readonly _tag: "AdvancedTransitionFrame";
252
- } | {
253
- readonly _tag: "EndedTransition";
254
254
  } | {
255
255
  readonly _tag: "DetectedInputMovement";
256
256
  } | {
@@ -36,17 +36,17 @@ export declare const update: (model: {
36
36
  readonly isOpen: boolean;
37
37
  readonly isAnimated: boolean;
38
38
  readonly isModal: boolean;
39
- readonly nullable: boolean;
40
- readonly immediate: boolean;
41
- readonly selectInputOnFocus: boolean;
42
39
  readonly transitionState: "Idle" | "EnterStart" | "EnterAnimating" | "LeaveStart" | "LeaveAnimating";
43
40
  readonly maybeActiveItemIndex: Option.Option<number>;
44
41
  readonly activationTrigger: "Pointer" | "Keyboard";
45
- readonly inputValue: string;
46
42
  readonly maybeLastPointerPosition: Option.Option<{
47
43
  readonly screenX: number;
48
44
  readonly screenY: number;
49
45
  }>;
46
+ readonly nullable: boolean;
47
+ readonly immediate: boolean;
48
+ readonly selectInputOnFocus: boolean;
49
+ readonly inputValue: string;
50
50
  } & {
51
51
  readonly maybeSelectedItem: Option.Option<string>;
52
52
  readonly maybeSelectedDisplayText: Option.Option<string>;
@@ -55,69 +55,69 @@ export declare const update: (model: {
55
55
  readonly isOpen: boolean;
56
56
  readonly isAnimated: boolean;
57
57
  readonly isModal: boolean;
58
- readonly nullable: boolean;
59
- readonly immediate: boolean;
60
- readonly selectInputOnFocus: boolean;
61
58
  readonly transitionState: "Idle" | "EnterStart" | "EnterAnimating" | "LeaveStart" | "LeaveAnimating";
62
59
  readonly maybeActiveItemIndex: Option.Option<number>;
63
60
  readonly activationTrigger: "Pointer" | "Keyboard";
64
- readonly inputValue: string;
65
61
  readonly maybeLastPointerPosition: Option.Option<{
66
62
  readonly screenX: number;
67
63
  readonly screenY: number;
68
64
  }>;
65
+ readonly nullable: boolean;
66
+ readonly immediate: boolean;
67
+ readonly selectInputOnFocus: boolean;
68
+ readonly inputValue: string;
69
69
  } & {
70
70
  readonly maybeSelectedItem: Option.Option<string>;
71
71
  readonly maybeSelectedDisplayText: Option.Option<string>;
72
72
  }, readonly Readonly<{
73
73
  name: string;
74
74
  effect: import("effect/Effect").Effect<{
75
- readonly _tag: "Opened";
76
- readonly maybeActiveItemIndex: Option.Option<number>;
77
- } | {
78
75
  readonly _tag: "Closed";
79
76
  } | {
80
77
  readonly _tag: "ClosedByTab";
78
+ } | {
79
+ readonly _tag: "DeactivatedItem";
80
+ } | {
81
+ readonly _tag: "CompletedLockScroll";
82
+ } | {
83
+ readonly _tag: "CompletedUnlockScroll";
84
+ } | {
85
+ readonly _tag: "CompletedSetupInert";
86
+ } | {
87
+ readonly _tag: "CompletedTeardownInert";
88
+ } | {
89
+ readonly _tag: "CompletedScrollIntoView";
90
+ } | {
91
+ readonly _tag: "CompletedClickItem";
92
+ } | {
93
+ readonly _tag: "AdvancedTransitionFrame";
94
+ } | {
95
+ readonly _tag: "EndedTransition";
96
+ } | {
97
+ readonly _tag: "Opened";
98
+ readonly maybeActiveItemIndex: Option.Option<number>;
81
99
  } | {
82
100
  readonly _tag: "ActivatedItem";
83
- readonly index: number;
84
101
  readonly activationTrigger: "Pointer" | "Keyboard";
102
+ readonly index: number;
85
103
  readonly maybeImmediateSelection: Option.Option<{
86
104
  readonly item: string;
87
105
  readonly displayText: string;
88
106
  }>;
89
- } | {
90
- readonly _tag: "DeactivatedItem";
91
107
  } | {
92
108
  readonly _tag: "SelectedItem";
93
109
  readonly item: string;
94
110
  readonly displayText: string;
95
111
  } | {
96
112
  readonly _tag: "MovedPointerOverItem";
97
- readonly index: number;
98
113
  readonly screenX: number;
99
114
  readonly screenY: number;
115
+ readonly index: number;
100
116
  } | {
101
117
  readonly _tag: "RequestedItemClick";
102
118
  readonly index: number;
103
- } | {
104
- readonly _tag: "CompletedLockScroll";
105
- } | {
106
- readonly _tag: "CompletedUnlockScroll";
107
- } | {
108
- readonly _tag: "CompletedSetupInert";
109
- } | {
110
- readonly _tag: "CompletedTeardownInert";
111
119
  } | {
112
120
  readonly _tag: "CompletedFocusInput";
113
- } | {
114
- readonly _tag: "CompletedScrollIntoView";
115
- } | {
116
- readonly _tag: "CompletedClickItem";
117
- } | {
118
- readonly _tag: "AdvancedTransitionFrame";
119
- } | {
120
- readonly _tag: "EndedTransition";
121
121
  } | {
122
122
  readonly _tag: "DetectedInputMovement";
123
123
  } | {
@@ -136,17 +136,17 @@ export declare const view: <Message, Item extends string>(config: Readonly<{
136
136
  readonly isOpen: boolean;
137
137
  readonly isAnimated: boolean;
138
138
  readonly isModal: boolean;
139
- readonly nullable: boolean;
140
- readonly immediate: boolean;
141
- readonly selectInputOnFocus: boolean;
142
139
  readonly transitionState: "Idle" | "EnterStart" | "EnterAnimating" | "LeaveStart" | "LeaveAnimating";
143
140
  readonly maybeActiveItemIndex: Option.Option<number>;
144
141
  readonly activationTrigger: "Pointer" | "Keyboard";
145
- readonly inputValue: string;
146
142
  readonly maybeLastPointerPosition: Option.Option<{
147
143
  readonly screenX: number;
148
144
  readonly screenY: number;
149
145
  }>;
146
+ readonly nullable: boolean;
147
+ readonly immediate: boolean;
148
+ readonly selectInputOnFocus: boolean;
149
+ readonly inputValue: string;
150
150
  } & {
151
151
  readonly maybeSelectedItem: Option.Option<string>;
152
152
  readonly maybeSelectedDisplayText: Option.Option<string>;
@@ -164,7 +164,7 @@ export declare const SubscriptionDeps: S.Struct<{
164
164
  /** Document-level subscriptions for pointer and keyboard events during drag operations. */
165
165
  export declare const subscriptions: import("../../runtime/subscription").Subscriptions<{
166
166
  readonly id: string;
167
- readonly orientation: "Horizontal" | "Vertical";
167
+ readonly orientation: "Vertical" | "Horizontal";
168
168
  readonly activationThreshold: number;
169
169
  readonly dragState: {
170
170
  readonly _tag: "Idle";
@@ -204,9 +204,9 @@ export declare const subscriptions: import("../../runtime/subscription").Subscri
204
204
  };
205
205
  }, {
206
206
  readonly _tag: "PressedDraggable";
207
- readonly index: number;
208
207
  readonly screenX: number;
209
208
  readonly screenY: number;
209
+ readonly index: number;
210
210
  readonly containerId: string;
211
211
  readonly itemId: string;
212
212
  } | {
@@ -31,73 +31,55 @@ export declare const init: (config: InitConfig) => Model;
31
31
  /** Processes a listbox message and returns the next model and commands. Stays open on selection and toggles item membership (multi-select behavior). */
32
32
  export declare const update: (model: {
33
33
  readonly id: string;
34
- readonly orientation: "Horizontal" | "Vertical";
35
34
  readonly isOpen: boolean;
36
35
  readonly isAnimated: boolean;
37
36
  readonly isModal: boolean;
37
+ readonly orientation: "Vertical" | "Horizontal";
38
38
  readonly transitionState: "Idle" | "EnterStart" | "EnterAnimating" | "LeaveStart" | "LeaveAnimating";
39
39
  readonly maybeActiveItemIndex: Option.Option<number>;
40
40
  readonly activationTrigger: "Pointer" | "Keyboard";
41
+ readonly searchQuery: string;
42
+ readonly searchVersion: number;
41
43
  readonly maybeLastPointerPosition: Option.Option<{
42
44
  readonly screenX: number;
43
45
  readonly screenY: number;
44
46
  }>;
45
- readonly searchQuery: string;
46
- readonly searchVersion: number;
47
47
  readonly maybeLastButtonPointerType: Option.Option<string>;
48
48
  } & {
49
49
  readonly selectedItems: readonly string[];
50
50
  }, message: import("./shared").Message) => readonly [{
51
51
  readonly id: string;
52
- readonly orientation: "Horizontal" | "Vertical";
53
52
  readonly isOpen: boolean;
54
53
  readonly isAnimated: boolean;
55
54
  readonly isModal: boolean;
55
+ readonly orientation: "Vertical" | "Horizontal";
56
56
  readonly transitionState: "Idle" | "EnterStart" | "EnterAnimating" | "LeaveStart" | "LeaveAnimating";
57
57
  readonly maybeActiveItemIndex: Option.Option<number>;
58
58
  readonly activationTrigger: "Pointer" | "Keyboard";
59
+ readonly searchQuery: string;
60
+ readonly searchVersion: number;
59
61
  readonly maybeLastPointerPosition: Option.Option<{
60
62
  readonly screenX: number;
61
63
  readonly screenY: number;
62
64
  }>;
63
- readonly searchQuery: string;
64
- readonly searchVersion: number;
65
65
  readonly maybeLastButtonPointerType: Option.Option<string>;
66
66
  } & {
67
67
  readonly selectedItems: readonly string[];
68
68
  }, readonly Readonly<{
69
69
  name: string;
70
70
  effect: import("effect/Effect").Effect<{
71
+ readonly _tag: "Opened";
72
+ readonly maybeActiveItemIndex: Option.Option<number>;
73
+ } | {
71
74
  readonly _tag: "Closed";
72
75
  } | {
73
76
  readonly _tag: "ClosedByTab";
74
- } | {
75
- readonly _tag: "DeactivatedItem";
76
- } | {
77
- readonly _tag: "CompletedLockScroll";
78
- } | {
79
- readonly _tag: "CompletedUnlockScroll";
80
- } | {
81
- readonly _tag: "CompletedSetupInert";
82
- } | {
83
- readonly _tag: "CompletedTeardownInert";
84
- } | {
85
- readonly _tag: "CompletedScrollIntoView";
86
- } | {
87
- readonly _tag: "CompletedClickItem";
88
- } | {
89
- readonly _tag: "AdvancedTransitionFrame";
90
- } | {
91
- readonly _tag: "EndedTransition";
92
- } | {
93
- readonly _tag: "CompletedFocusButton";
94
- } | {
95
- readonly _tag: "Opened";
96
- readonly maybeActiveItemIndex: Option.Option<number>;
97
77
  } | {
98
78
  readonly _tag: "ActivatedItem";
99
- readonly index: number;
100
79
  readonly activationTrigger: "Pointer" | "Keyboard";
80
+ readonly index: number;
81
+ } | {
82
+ readonly _tag: "DeactivatedItem";
101
83
  } | {
102
84
  readonly _tag: "SelectedItem";
103
85
  readonly item: string;
@@ -113,15 +95,33 @@ export declare const update: (model: {
113
95
  readonly version: number;
114
96
  } | {
115
97
  readonly _tag: "MovedPointerOverItem";
116
- readonly index: number;
117
98
  readonly screenX: number;
118
99
  readonly screenY: number;
100
+ readonly index: number;
101
+ } | {
102
+ readonly _tag: "CompletedLockScroll";
103
+ } | {
104
+ readonly _tag: "CompletedUnlockScroll";
105
+ } | {
106
+ readonly _tag: "CompletedSetupInert";
107
+ } | {
108
+ readonly _tag: "CompletedTeardownInert";
109
+ } | {
110
+ readonly _tag: "CompletedFocusButton";
119
111
  } | {
120
112
  readonly _tag: "CompletedFocusItems";
113
+ } | {
114
+ readonly _tag: "CompletedScrollIntoView";
115
+ } | {
116
+ readonly _tag: "CompletedClickItem";
121
117
  } | {
122
118
  readonly _tag: "IgnoredMouseClick";
123
119
  } | {
124
120
  readonly _tag: "SuppressedSpaceScroll";
121
+ } | {
122
+ readonly _tag: "AdvancedTransitionFrame";
123
+ } | {
124
+ readonly _tag: "EndedTransition";
125
125
  } | {
126
126
  readonly _tag: "DetectedButtonMovement";
127
127
  } | {
@@ -136,19 +136,19 @@ export type ViewConfig<Message, Item> = BaseViewConfig<Message, Item, Model>;
136
136
  export declare const view: <Message, Item>(config: Readonly<{
137
137
  model: {
138
138
  readonly id: string;
139
- readonly orientation: "Horizontal" | "Vertical";
140
139
  readonly isOpen: boolean;
141
140
  readonly isAnimated: boolean;
142
141
  readonly isModal: boolean;
142
+ readonly orientation: "Vertical" | "Horizontal";
143
143
  readonly transitionState: "Idle" | "EnterStart" | "EnterAnimating" | "LeaveStart" | "LeaveAnimating";
144
144
  readonly maybeActiveItemIndex: Option.Option<number>;
145
145
  readonly activationTrigger: "Pointer" | "Keyboard";
146
+ readonly searchQuery: string;
147
+ readonly searchVersion: number;
146
148
  readonly maybeLastPointerPosition: Option.Option<{
147
149
  readonly screenX: number;
148
150
  readonly screenY: number;
149
151
  }>;
150
- readonly searchQuery: string;
151
- readonly searchVersion: number;
152
152
  readonly maybeLastButtonPointerType: Option.Option<string>;
153
153
  } & {
154
154
  readonly selectedItems: readonly string[];
@@ -218,36 +218,18 @@ export declare const DetectMovementOrTransitionEnd: Command.CommandDefinition<"D
218
218
  export declare const makeUpdate: <Model extends BaseModel>(handleSelectedItem: (model: Model, item: string, context: SelectedItemContext) => [Model, ReadonlyArray<Command.Command<Message>>]) => (model: Model, message: Message) => readonly [Model, readonly Readonly<{
219
219
  name: string;
220
220
  effect: Effect.Effect<{
221
+ readonly _tag: "Opened";
222
+ readonly maybeActiveItemIndex: Option.Option<number>;
223
+ } | {
221
224
  readonly _tag: "Closed";
222
225
  } | {
223
226
  readonly _tag: "ClosedByTab";
224
- } | {
225
- readonly _tag: "DeactivatedItem";
226
- } | {
227
- readonly _tag: "CompletedLockScroll";
228
- } | {
229
- readonly _tag: "CompletedUnlockScroll";
230
- } | {
231
- readonly _tag: "CompletedSetupInert";
232
- } | {
233
- readonly _tag: "CompletedTeardownInert";
234
- } | {
235
- readonly _tag: "CompletedScrollIntoView";
236
- } | {
237
- readonly _tag: "CompletedClickItem";
238
- } | {
239
- readonly _tag: "AdvancedTransitionFrame";
240
- } | {
241
- readonly _tag: "EndedTransition";
242
- } | {
243
- readonly _tag: "CompletedFocusButton";
244
- } | {
245
- readonly _tag: "Opened";
246
- readonly maybeActiveItemIndex: Option.Option<number>;
247
227
  } | {
248
228
  readonly _tag: "ActivatedItem";
249
- readonly index: number;
250
229
  readonly activationTrigger: "Pointer" | "Keyboard";
230
+ readonly index: number;
231
+ } | {
232
+ readonly _tag: "DeactivatedItem";
251
233
  } | {
252
234
  readonly _tag: "SelectedItem";
253
235
  readonly item: string;
@@ -263,15 +245,33 @@ export declare const makeUpdate: <Model extends BaseModel>(handleSelectedItem: (
263
245
  readonly version: number;
264
246
  } | {
265
247
  readonly _tag: "MovedPointerOverItem";
266
- readonly index: number;
267
248
  readonly screenX: number;
268
249
  readonly screenY: number;
250
+ readonly index: number;
251
+ } | {
252
+ readonly _tag: "CompletedLockScroll";
253
+ } | {
254
+ readonly _tag: "CompletedUnlockScroll";
255
+ } | {
256
+ readonly _tag: "CompletedSetupInert";
257
+ } | {
258
+ readonly _tag: "CompletedTeardownInert";
259
+ } | {
260
+ readonly _tag: "CompletedFocusButton";
269
261
  } | {
270
262
  readonly _tag: "CompletedFocusItems";
263
+ } | {
264
+ readonly _tag: "CompletedScrollIntoView";
265
+ } | {
266
+ readonly _tag: "CompletedClickItem";
271
267
  } | {
272
268
  readonly _tag: "IgnoredMouseClick";
273
269
  } | {
274
270
  readonly _tag: "SuppressedSpaceScroll";
271
+ } | {
272
+ readonly _tag: "AdvancedTransitionFrame";
273
+ } | {
274
+ readonly _tag: "EndedTransition";
275
275
  } | {
276
276
  readonly _tag: "DetectedButtonMovement";
277
277
  } | {
@@ -32,73 +32,55 @@ export declare const init: (config: InitConfig) => Model;
32
32
  /** Processes a listbox message and returns the next model and commands. Closes the listbox on selection (single-select behavior). */
33
33
  export declare const update: (model: {
34
34
  readonly id: string;
35
- readonly orientation: "Horizontal" | "Vertical";
36
35
  readonly isOpen: boolean;
37
36
  readonly isAnimated: boolean;
38
37
  readonly isModal: boolean;
38
+ readonly orientation: "Vertical" | "Horizontal";
39
39
  readonly transitionState: "Idle" | "EnterStart" | "EnterAnimating" | "LeaveStart" | "LeaveAnimating";
40
40
  readonly maybeActiveItemIndex: Option.Option<number>;
41
41
  readonly activationTrigger: "Pointer" | "Keyboard";
42
+ readonly searchQuery: string;
43
+ readonly searchVersion: number;
42
44
  readonly maybeLastPointerPosition: Option.Option<{
43
45
  readonly screenX: number;
44
46
  readonly screenY: number;
45
47
  }>;
46
- readonly searchQuery: string;
47
- readonly searchVersion: number;
48
48
  readonly maybeLastButtonPointerType: Option.Option<string>;
49
49
  } & {
50
50
  readonly maybeSelectedItem: Option.Option<string>;
51
51
  }, message: Message) => readonly [{
52
52
  readonly id: string;
53
- readonly orientation: "Horizontal" | "Vertical";
54
53
  readonly isOpen: boolean;
55
54
  readonly isAnimated: boolean;
56
55
  readonly isModal: boolean;
56
+ readonly orientation: "Vertical" | "Horizontal";
57
57
  readonly transitionState: "Idle" | "EnterStart" | "EnterAnimating" | "LeaveStart" | "LeaveAnimating";
58
58
  readonly maybeActiveItemIndex: Option.Option<number>;
59
59
  readonly activationTrigger: "Pointer" | "Keyboard";
60
+ readonly searchQuery: string;
61
+ readonly searchVersion: number;
60
62
  readonly maybeLastPointerPosition: Option.Option<{
61
63
  readonly screenX: number;
62
64
  readonly screenY: number;
63
65
  }>;
64
- readonly searchQuery: string;
65
- readonly searchVersion: number;
66
66
  readonly maybeLastButtonPointerType: Option.Option<string>;
67
67
  } & {
68
68
  readonly maybeSelectedItem: Option.Option<string>;
69
69
  }, readonly Readonly<{
70
70
  name: string;
71
71
  effect: import("effect/Effect").Effect<{
72
+ readonly _tag: "Opened";
73
+ readonly maybeActiveItemIndex: Option.Option<number>;
74
+ } | {
72
75
  readonly _tag: "Closed";
73
76
  } | {
74
77
  readonly _tag: "ClosedByTab";
75
- } | {
76
- readonly _tag: "DeactivatedItem";
77
- } | {
78
- readonly _tag: "CompletedLockScroll";
79
- } | {
80
- readonly _tag: "CompletedUnlockScroll";
81
- } | {
82
- readonly _tag: "CompletedSetupInert";
83
- } | {
84
- readonly _tag: "CompletedTeardownInert";
85
- } | {
86
- readonly _tag: "CompletedScrollIntoView";
87
- } | {
88
- readonly _tag: "CompletedClickItem";
89
- } | {
90
- readonly _tag: "AdvancedTransitionFrame";
91
- } | {
92
- readonly _tag: "EndedTransition";
93
- } | {
94
- readonly _tag: "CompletedFocusButton";
95
- } | {
96
- readonly _tag: "Opened";
97
- readonly maybeActiveItemIndex: Option.Option<number>;
98
78
  } | {
99
79
  readonly _tag: "ActivatedItem";
100
- readonly index: number;
101
80
  readonly activationTrigger: "Pointer" | "Keyboard";
81
+ readonly index: number;
82
+ } | {
83
+ readonly _tag: "DeactivatedItem";
102
84
  } | {
103
85
  readonly _tag: "SelectedItem";
104
86
  readonly item: string;
@@ -114,15 +96,33 @@ export declare const update: (model: {
114
96
  readonly version: number;
115
97
  } | {
116
98
  readonly _tag: "MovedPointerOverItem";
117
- readonly index: number;
118
99
  readonly screenX: number;
119
100
  readonly screenY: number;
101
+ readonly index: number;
102
+ } | {
103
+ readonly _tag: "CompletedLockScroll";
104
+ } | {
105
+ readonly _tag: "CompletedUnlockScroll";
106
+ } | {
107
+ readonly _tag: "CompletedSetupInert";
108
+ } | {
109
+ readonly _tag: "CompletedTeardownInert";
110
+ } | {
111
+ readonly _tag: "CompletedFocusButton";
120
112
  } | {
121
113
  readonly _tag: "CompletedFocusItems";
114
+ } | {
115
+ readonly _tag: "CompletedScrollIntoView";
116
+ } | {
117
+ readonly _tag: "CompletedClickItem";
122
118
  } | {
123
119
  readonly _tag: "IgnoredMouseClick";
124
120
  } | {
125
121
  readonly _tag: "SuppressedSpaceScroll";
122
+ } | {
123
+ readonly _tag: "AdvancedTransitionFrame";
124
+ } | {
125
+ readonly _tag: "EndedTransition";
126
126
  } | {
127
127
  readonly _tag: "DetectedButtonMovement";
128
128
  } | {
@@ -140,19 +140,19 @@ export type ViewConfig<Message, Item> = BaseViewConfig<Message, Item, Model>;
140
140
  export declare const view: <Message, Item>(config: Readonly<{
141
141
  model: {
142
142
  readonly id: string;
143
- readonly orientation: "Horizontal" | "Vertical";
144
143
  readonly isOpen: boolean;
145
144
  readonly isAnimated: boolean;
146
145
  readonly isModal: boolean;
146
+ readonly orientation: "Vertical" | "Horizontal";
147
147
  readonly transitionState: "Idle" | "EnterStart" | "EnterAnimating" | "LeaveStart" | "LeaveAnimating";
148
148
  readonly maybeActiveItemIndex: Option.Option<number>;
149
149
  readonly activationTrigger: "Pointer" | "Keyboard";
150
+ readonly searchQuery: string;
151
+ readonly searchVersion: number;
150
152
  readonly maybeLastPointerPosition: Option.Option<{
151
153
  readonly screenX: number;
152
154
  readonly screenY: number;
153
155
  }>;
154
- readonly searchQuery: string;
155
- readonly searchVersion: number;
156
156
  readonly maybeLastButtonPointerType: Option.Option<string>;
157
157
  } & {
158
158
  readonly maybeSelectedItem: Option.Option<string>;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "foldkit",
3
- "version": "0.52.0",
3
+ "version": "0.53.0",
4
4
  "description": "A frontend framework for TypeScript, built on Effect, using The Elm Architecture",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",