@ixfx/components 0.5.20 → 0.6.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/bundle/index.d.ts +535 -263
- package/bundle/index.d.ts.map +1 -1
- package/bundle/index.js +7971 -6596
- package/bundle/index.js.map +1 -1
- package/dist/ac-text.d.ts +12 -7
- package/dist/ac-text.d.ts.map +1 -1
- package/dist/ac-text.js +3 -4
- package/dist/ac-text.js.map +1 -1
- package/dist/ac-token-DVbmHmky.d.ts +107 -0
- package/dist/ac-token-DVbmHmky.d.ts.map +1 -0
- package/dist/ac-token.d.ts +2 -0
- package/dist/ac-token.js +646 -0
- package/dist/ac-token.js.map +1 -0
- package/dist/{button-pcDaCemT.js → button-Bn0BuLpO.js} +3 -4
- package/dist/{button-pcDaCemT.js.map → button-Bn0BuLpO.js.map} +1 -1
- package/dist/button.d.ts +1 -2
- package/dist/button.d.ts.map +1 -1
- package/dist/button.js +1 -1
- package/dist/checkbox.d.ts +0 -1
- package/dist/checkbox.d.ts.map +1 -1
- package/dist/checkbox.js +1 -1
- package/dist/checkbox.js.map +1 -1
- package/dist/{colour-picker-D43Q96r0.js → colour-picker-0stHB90J.js} +11 -14
- package/dist/{colour-picker-D43Q96r0.js.map → colour-picker-0stHB90J.js.map} +1 -1
- package/dist/colour-picker.d.ts +1 -1
- package/dist/colour-picker.js +1 -1
- package/dist/crumbs.d.ts +4 -2
- package/dist/crumbs.d.ts.map +1 -1
- package/dist/crumbs.js +1152 -1
- package/dist/crumbs.js.map +1 -0
- package/dist/data-controller-DOlmqNKb.js +171 -0
- package/dist/data-controller-DOlmqNKb.js.map +1 -0
- package/dist/data-display.d.ts +1 -2
- package/dist/data-display.d.ts.map +1 -1
- package/dist/data-display.js +24 -22
- package/dist/data-display.js.map +1 -1
- package/dist/data-grid-BeAkORz2.d.ts +215 -0
- package/dist/data-grid-BeAkORz2.d.ts.map +1 -0
- package/dist/data-grid.d.ts +2 -0
- package/dist/data-grid.js +1225 -0
- package/dist/data-grid.js.map +1 -0
- package/dist/data-provider-BAn_-oR1.d.ts +61 -0
- package/dist/data-provider-BAn_-oR1.d.ts.map +1 -0
- package/dist/{decorate-DdjvVHS-.js → decorate-VRK8rslU.js} +2 -2
- package/dist/{decorate-DdjvVHS-.js.map → decorate-VRK8rslU.js.map} +1 -1
- package/dist/{defaults-BkWCPJFL.js → defaults-BCiDhZbF.js} +20 -3
- package/dist/defaults-BCiDhZbF.js.map +1 -0
- package/dist/drag-ghost-DtSDvjri.js +85 -0
- package/dist/drag-ghost-DtSDvjri.js.map +1 -0
- package/dist/editable-label.d.ts +1 -2
- package/dist/editable-label.d.ts.map +1 -1
- package/dist/editable-label.js +1 -1
- package/dist/editable-label.js.map +1 -1
- package/dist/{incr-search-CeERfijK.js → element-search-Y8SRfPGM.js} +7 -135
- package/dist/element-search-Y8SRfPGM.js.map +1 -0
- package/dist/form-CsXJX15p.js +64 -0
- package/dist/form-CsXJX15p.js.map +1 -0
- package/dist/form.d.ts +15 -0
- package/dist/form.d.ts.map +1 -0
- package/dist/form.js +2 -0
- package/dist/grouped-item-lister-CNLMgdIr.d.ts +121 -0
- package/dist/grouped-item-lister-CNLMgdIr.d.ts.map +1 -0
- package/dist/grouped-item-lister.d.ts +2 -0
- package/dist/grouped-item-lister.js +177 -0
- package/dist/grouped-item-lister.js.map +1 -0
- package/dist/{hex-editor-B-UI4OZu.js → hex-editor-Bk6rxhfg.js} +6 -8
- package/dist/{hex-editor-B-UI4OZu.js.map → hex-editor-Bk6rxhfg.js.map} +1 -1
- package/dist/{hex-editor-CMIxtNgT.d.ts → hex-editor-Caq8vNQk.d.ts} +2 -3
- package/dist/hex-editor-Caq8vNQk.d.ts.map +1 -0
- package/dist/hex.d.ts +1 -1
- package/dist/hex.js +1 -1
- package/dist/highlight-B-eQrhhb.js.map +1 -1
- package/dist/{icon-Bd5BiU4b.d.ts → icon-BUwP1CZ1.d.ts} +3 -4
- package/dist/icon-BUwP1CZ1.d.ts.map +1 -0
- package/dist/{icon-CK14NUcE.js → icons-Bm2ByQ3s.js} +10 -5
- package/dist/icons-Bm2ByQ3s.js.map +1 -0
- package/dist/icons.d.ts +2 -2
- package/dist/icons.js +2 -8
- package/dist/incr-search-vCzuao-2.js +137 -0
- package/dist/incr-search-vCzuao-2.js.map +1 -0
- package/dist/incr-search.d.ts +1 -1
- package/dist/incr-search.js +2 -1
- package/dist/{index-DrKRD8_a.d.ts → index-BOUaDIW-.d.ts} +4 -4
- package/dist/index-BOUaDIW-.d.ts.map +1 -0
- package/dist/{index-CkMIKEWp.d.ts → index-BUB5SICW.d.ts} +3 -4
- package/dist/index-BUB5SICW.d.ts.map +1 -0
- package/dist/{index-tX6fKF8m.d.ts → index-BeuCXtiO.d.ts} +3 -3
- package/dist/index-BeuCXtiO.d.ts.map +1 -0
- package/dist/{index-BslNaMLo.d.ts → index-Cu5i8zZY.d.ts} +3 -3
- package/dist/index-Cu5i8zZY.d.ts.map +1 -0
- package/dist/{index-D87kRcEs.d.ts → index-RqMh1i-O.d.ts} +2 -1
- package/dist/index-RqMh1i-O.d.ts.map +1 -0
- package/dist/{index-Cdmrn0SZ.d.ts → index-ovq_GTdl.d.ts} +11 -11
- package/dist/index-ovq_GTdl.d.ts.map +1 -0
- package/dist/index.d.ts +93 -606
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1351 -3714
- package/dist/index.js.map +1 -1
- package/dist/{labelled-input-base-ORb1rGq6.d.ts → labelled-input-base-Dp_9KP0G.d.ts} +2 -3
- package/dist/labelled-input-base-Dp_9KP0G.d.ts.map +1 -0
- package/dist/{labelled-input-base-9K_w3oLj.js → labelled-input-base-hoKGwyKT.js} +2 -2
- package/dist/{labelled-input-base-9K_w3oLj.js.map → labelled-input-base-hoKGwyKT.js.map} +1 -1
- package/dist/labelled-radial-input.d.ts +4 -5
- package/dist/labelled-radial-input.d.ts.map +1 -1
- package/dist/labelled-radial-input.js +2 -3
- package/dist/labelled-radial-input.js.map +1 -1
- package/dist/labelled-range-input.d.ts +1 -1
- package/dist/labelled-range-input.js +2 -2
- package/dist/labelled-range-input.js.map +1 -1
- package/dist/led.d.ts +1 -2
- package/dist/led.d.ts.map +1 -1
- package/dist/led.js +1 -1
- package/dist/led.js.map +1 -1
- package/dist/menu-DIfU70AA.js +1609 -0
- package/dist/menu-DIfU70AA.js.map +1 -0
- package/dist/{menu-item-AtoP6bD4.d.ts → menu-item-BG5w7fi4.d.ts} +4 -4
- package/dist/menu-item-BG5w7fi4.d.ts.map +1 -0
- package/dist/menu.d.ts +2 -2
- package/dist/menu.js +1 -2
- package/dist/miller.d.ts +7 -5
- package/dist/miller.d.ts.map +1 -1
- package/dist/miller.js +23 -25
- package/dist/miller.js.map +1 -1
- package/dist/narrowed-text.d.ts +1 -2
- package/dist/narrowed-text.d.ts.map +1 -1
- package/dist/narrowed-text.js +14 -13
- package/dist/narrowed-text.js.map +1 -1
- package/dist/notification-pill-DyZydXoZ.d.ts +68 -0
- package/dist/notification-pill-DyZydXoZ.d.ts.map +1 -0
- package/dist/notifier.d.ts +2 -0
- package/dist/notifier.js +146 -0
- package/dist/notifier.js.map +1 -0
- package/dist/panel.d.ts +1 -1
- package/dist/panel.d.ts.map +1 -1
- package/dist/panel.js +1 -2
- package/dist/panel.js.map +1 -1
- package/dist/plots.d.ts +1 -1
- package/dist/plots.js +1 -1
- package/dist/polar-pad.d.ts +1 -2
- package/dist/polar-pad.d.ts.map +1 -1
- package/dist/polar-pad.js +2 -2
- package/dist/polar-pad.js.map +1 -1
- package/dist/{radial-input-Dhu5ZGP5.d.ts → radial-input-DXMN55Nz.d.ts} +2 -3
- package/dist/radial-input-DXMN55Nz.d.ts.map +1 -0
- package/dist/{radial-input-C4f-2Bya.js → radial-input-Dk8Wydp5.js} +26 -16
- package/dist/radial-input-Dk8Wydp5.js.map +1 -0
- package/dist/radial-input.d.ts +1 -1
- package/dist/radial-input.js +1 -1
- package/dist/range-input.d.ts +2 -3
- package/dist/range-input.d.ts.map +1 -1
- package/dist/range-input.js +2 -2
- package/dist/range-input.js.map +1 -1
- package/dist/range.d.ts +2 -3
- package/dist/range.d.ts.map +1 -1
- package/dist/range.js +2 -2
- package/dist/range.js.map +1 -1
- package/dist/scroll-fade-CAs1EabA.js +70 -0
- package/dist/scroll-fade-CAs1EabA.js.map +1 -0
- package/dist/select-horiz.d.ts +50 -0
- package/dist/select-horiz.d.ts.map +1 -0
- package/dist/select-horiz.js +263 -0
- package/dist/select-horiz.js.map +1 -0
- package/dist/{slider-input-SW7e2Ac2.js → slider-input-CT4gcF-o.js} +30 -27
- package/dist/{slider-input-SW7e2Ac2.js.map → slider-input-CT4gcF-o.js.map} +1 -1
- package/dist/{slider-input-BEaztT-g.d.ts → slider-input-XppH3vcy.d.ts} +2 -3
- package/dist/slider-input-XppH3vcy.d.ts.map +1 -0
- package/dist/slider-input.d.ts +1 -1
- package/dist/slider-input.js +1 -1
- package/dist/snackbar.d.ts +58 -0
- package/dist/snackbar.d.ts.map +1 -0
- package/dist/snackbar.js +265 -0
- package/dist/snackbar.js.map +1 -0
- package/dist/snap-container.d.ts +1 -2
- package/dist/snap-container.d.ts.map +1 -1
- package/dist/snap-container.js +6 -5
- package/dist/snap-container.js.map +1 -1
- package/dist/split-layout.d.ts +1 -2
- package/dist/split-layout.d.ts.map +1 -1
- package/dist/split-layout.js +5 -3
- package/dist/split-layout.js.map +1 -1
- package/dist/swipe.d.ts +1 -2
- package/dist/swipe.d.ts.map +1 -1
- package/dist/swipe.js +4 -3
- package/dist/swipe.js.map +1 -1
- package/dist/{tab-list-B8v9KntS.d.ts → tab-list-Beuh2nom.d.ts} +4 -4
- package/dist/tab-list-Beuh2nom.d.ts.map +1 -0
- package/dist/tabs.d.ts +1 -1
- package/dist/tabs.js +533 -1
- package/dist/tabs.js.map +1 -0
- package/dist/{tickled-controller-JDOR9B8V.d.ts → tickled-controller-BtevrRLV.d.ts} +1 -2
- package/dist/tickled-controller-BtevrRLV.d.ts.map +1 -0
- package/dist/{tickled-styles-Bgo_Lpw-.js → tickled-controller-DkAU-0qL.js} +2 -88
- package/dist/tickled-controller-DkAU-0qL.js.map +1 -0
- package/dist/tickled-styles-BrAHEj1q.js +89 -0
- package/dist/tickled-styles-BrAHEj1q.js.map +1 -0
- package/dist/{timeline-CdSI003L.js → timeline-B2fgDL4U.js} +3 -3
- package/dist/{timeline-CdSI003L.js.map → timeline-B2fgDL4U.js.map} +1 -1
- package/dist/timeline.d.ts +1 -1
- package/dist/timeline.js +1 -1
- package/dist/{tooltip-BMTSUPBU.d.ts → tooltip-BlvBUQxx.d.ts} +2 -3
- package/dist/tooltip-BlvBUQxx.d.ts.map +1 -0
- package/dist/transitory-label.d.ts +30 -0
- package/dist/transitory-label.d.ts.map +1 -0
- package/dist/transitory-label.js +249 -0
- package/dist/transitory-label.js.map +1 -0
- package/dist/{tree-CqPhQRHo.js → tree-BO6BXI2b.js} +9 -10
- package/dist/{tree-CqPhQRHo.js.map → tree-BO6BXI2b.js.map} +1 -1
- package/dist/{tree-component-CDLO1ITF.d.ts → tree-component-BvV4muxx.d.ts} +8 -124
- package/dist/tree-component-BvV4muxx.d.ts.map +1 -0
- package/dist/tree.d.ts +9 -4
- package/dist/tree.d.ts.map +1 -1
- package/dist/tree.js +1 -1
- package/dist/types-Bc23SI94.d.ts +72 -0
- package/dist/types-Bc23SI94.d.ts.map +1 -0
- package/dist/types-DlVNJez_.d.ts +41 -0
- package/dist/types-DlVNJez_.d.ts.map +1 -0
- package/dist/vertical-list.d.ts +122 -0
- package/dist/vertical-list.d.ts.map +1 -0
- package/dist/vertical-list.js +737 -0
- package/dist/vertical-list.js.map +1 -0
- package/dist/{wheel-nudge-Dhzi5nHc.js → wheel-nudge-BlSCe_hD.js} +2 -2
- package/dist/wheel-nudge-BlSCe_hD.js.map +1 -0
- package/dist/{wheel-nudge-C-ra_1os.d.ts → wheel-nudge-DGrNzWuE.d.ts} +3 -4
- package/dist/wheel-nudge-DGrNzWuE.d.ts.map +1 -0
- package/dist/{xy-axis-CtDDQzGZ.d.ts → xy-axis-5KhVTNoX.d.ts} +8 -6
- package/dist/xy-axis-5KhVTNoX.d.ts.map +1 -0
- package/dist/{xy-axis-BpA2eJq6.js → xy-axis-B6yMjckW.js} +8 -112
- package/dist/xy-axis-B6yMjckW.js.map +1 -0
- package/dist/xy-pad.d.ts +1 -2
- package/dist/xy-pad.d.ts.map +1 -1
- package/dist/xy-pad.js +2 -2
- package/dist/xy-pad.js.map +1 -1
- package/docs-user/README.md +3 -2
- package/docs-user/data-grid.md +248 -0
- package/docs-user/index.json +217 -0
- package/docs-user/llms.txt +57 -0
- package/docs-user/rating.md +102 -0
- package/llms.txt +57 -0
- package/package.json +21 -11
- package/dist/crumb-navigation-Pif-kupA.js +0 -1221
- package/dist/crumb-navigation-Pif-kupA.js.map +0 -1
- package/dist/defaults-BkWCPJFL.js.map +0 -1
- package/dist/hex-editor-CMIxtNgT.d.ts.map +0 -1
- package/dist/icon-Bd5BiU4b.d.ts.map +0 -1
- package/dist/icon-CK14NUcE.js.map +0 -1
- package/dist/icons.js.map +0 -1
- package/dist/incr-search-CeERfijK.js.map +0 -1
- package/dist/index-BslNaMLo.d.ts.map +0 -1
- package/dist/index-Cdmrn0SZ.d.ts.map +0 -1
- package/dist/index-CkMIKEWp.d.ts.map +0 -1
- package/dist/index-D87kRcEs.d.ts.map +0 -1
- package/dist/index-DrKRD8_a.d.ts.map +0 -1
- package/dist/index-tX6fKF8m.d.ts.map +0 -1
- package/dist/interaction-_Y2qO3QI.js +0 -1
- package/dist/labelled-input-base-ORb1rGq6.d.ts.map +0 -1
- package/dist/menu-BiFarLUA.js +0 -826
- package/dist/menu-BiFarLUA.js.map +0 -1
- package/dist/menu-item-AtoP6bD4.d.ts.map +0 -1
- package/dist/menu-item-yHSPV8nS.js +0 -783
- package/dist/menu-item-yHSPV8nS.js.map +0 -1
- package/dist/radial-input-C4f-2Bya.js.map +0 -1
- package/dist/radial-input-Dhu5ZGP5.d.ts.map +0 -1
- package/dist/registry-CkW7q09Q.js +0 -21
- package/dist/registry-CkW7q09Q.js.map +0 -1
- package/dist/selecthorizontal.d.ts +0 -16
- package/dist/selecthorizontal.d.ts.map +0 -1
- package/dist/selecthorizontal.js +0 -43
- package/dist/selecthorizontal.js.map +0 -1
- package/dist/slider-input-BEaztT-g.d.ts.map +0 -1
- package/dist/tab-list-B8v9KntS.d.ts.map +0 -1
- package/dist/tab-list-CR0v53KJ.js +0 -615
- package/dist/tab-list-CR0v53KJ.js.map +0 -1
- package/dist/tickled-controller-JDOR9B8V.d.ts.map +0 -1
- package/dist/tickled-styles-Bgo_Lpw-.js.map +0 -1
- package/dist/tooltip-BMTSUPBU.d.ts.map +0 -1
- package/dist/tree-component-CDLO1ITF.d.ts.map +0 -1
- package/dist/types-DSfbtHs3.d.ts +0 -8
- package/dist/types-DSfbtHs3.d.ts.map +0 -1
- package/dist/wheel-nudge-C-ra_1os.d.ts.map +0 -1
- package/dist/wheel-nudge-Dhzi5nHc.js.map +0 -1
- package/dist/xy-axis-BpA2eJq6.js.map +0 -1
- package/dist/xy-axis-CtDDQzGZ.d.ts.map +0 -1
- package/docs-user/selecthorizontal.md +0 -32
- /package/bundle/{chunk-D7D4PA-g.js → rolldown-runtime-D7D4PA-g.js} +0 -0
- /package/dist/{chunk-D7D4PA-g.js → rolldown-runtime-D7D4PA-g.js} +0 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"crumbs.js","names":["#getTickledItems","#onTickled","#getHostContainer","#onMenuKeyNav","#currentOpenTrigger","#menuOpenedByKeyboard","#canFocusSuggestions","#shiftFocusToNarrowedText","#handleOpenCaretMenu","#activateTickled","#shiftFocusToPath","#isWheelScrolling","#wheelScrollTimeout","#findPath","#scrollTickledIntoView","#pendingNode","#hasChildOptions","#propagateInputModeToMenu","#setSelected","#modelUnsubscribe","#runLayoutUpdate","#onHostClick","#onWheel","#previousSelectionKey","#scrollToValue","#pendingController","#updateTrailingWidth","#scrollSegmentIntoView","#abortPending","#invokeLoadChildren","#onChildClick","#currentLeadingSiblings","#findNodePath","#getSiblingMenuItems","#onLabelClick","#onSegmentMenuCommand","#onUpClick","#onFocus","#onBlur","#onKeyDown","#onMenuTriggerClose","#renderChildOptions","#getChildOptionsWidth","#onNarrowedTextChange","#onNarrowedTextBlur","#onNarrowedTextShiftTab","customElement"],"sources":["../src/crumbs/crumb-navigation.ts"],"sourcesContent":["/* eslint-disable ts/no-unsafe-declaration-merging */\nimport type { PropertyValues } from 'lit';\nimport type {\n TreeActivateEvent,\n TreeComponent,\n TreeComponentEventMap,\n TreeExpandEvent,\n TreeItemClickEvent,\n TreeSelectDetail,\n TreeSelectEvent,\n TreeTickleDetail,\n TreeTickleEvent,\n} from '../common/tree-component.js';\nimport type { TreeDataModel } from '../common/tree-data-model.js';\nimport type {\n TreeExclusivity,\n TreeFilterPredicate,\n TreeSelectionFilter,\n} from '../common/types.js';\nimport type { MenuTrigger } from '../menu/menu-trigger.js';\nimport type { LoadChildrenCallback, TreeNode } from '../tree/types.js';\nimport { css, html, LitElement, nothing } from 'lit';\nimport { property, state } from 'lit/decorators.js';\nimport { collectDataResult } from '../common/data-provider.js';\n\nimport { TickledController, tickledItemStyles, tickledStyles } from '../interaction/index.js';\nimport { themeFallbacks } from '../styles/fallbacks.js';\nimport { scrollFadeStyles } from '../styles/scroll-fade.js';\nimport { safeCustomElement as customElement } from '../util/custom-elements.js';\nimport '../menu/menu-trigger.js';\nimport '../menu/menu-container.js';\nimport '../menu/menu-item.js';\n\nimport '../narrowed-text/index.js';\n\n/** @deprecated Use TreeSelectDetail from src/common/tree-component.ts */\nexport type CrumbNavigationChangeDetail = {\n readonly selected: TreeNode;\n readonly previous: TreeNode | undefined;\n};\n\nexport type CrumbNavigationChangeEvent = CustomEvent<CrumbNavigationChangeDetail>;\n\nexport type CrumbNavigationItemClickDetail = { node: TreeNode; depth: number };\nexport type CrumbNavigationItemClickEvent = CustomEvent<CrumbNavigationItemClickDetail>;\n\nexport type CrumbNavigationExpandDetail = { node: TreeNode; depth: number };\nexport type CrumbNavigationExpandEvent = CustomEvent<CrumbNavigationExpandDetail>;\n\n/**\n * Breadcrumb navigation with lazy-loading support.\n *\n * Uses the same `TreeNode` / `TreeItem` data model as `ixfx-tree-list`,\n * so the two components can be swapped with minimal code changes.\n *\n * Events\n * - `navigate`: fired when user clicks a breadcrumb label. detail: `{ node: TreeNode }`\n * - `change`: fired when selected node changes. detail: `{ selected: TreeNode, previous: TreeNode | undefined }`\n * - `expand`: fired when user clicks a caret whose node has no children yet.\n * detail: `{ node: TreeNode, depth: number, signal: AbortSignal }`\n * Populate `node.children` then call `requestUpdate()` on the element.\n *\n * CSS variables\n * --crumb-item-bg: var(--item-bg, transparent); // item background\n * --crumb-item-bg-tickled: var(--item-bg-tickled); // item background on hover\n * --crumb-item-text-tickled: var(--item-text-tickled); // text color on hover\n * --crumb-item-border: var(--item-border); // item border\n * --crumb-item-border-tickled: var(--item-border-tickled); // border color on hover\n * --crumb-item-padding: var(--item-padding, var(--space-xs)); // item padding\n * --crumb-item-border-radius: var(--item-border-radius); // item border radius\n * --crumb-item-gap: var(--item-gap, var(--space-xs)); // gap between items\n * --crumb-separator: var(--surface-muted-text); // separator/caret color\n * --crumb-truncate-min-width: 5ch; // minimum width for truncatable segments\n */\n@customElement(`ixfx-crumb-navigation`)\nexport class CrumbNavigationElement extends LitElement implements TreeComponent {\n @property({ type: Object })\n root: TreeNode | undefined;\n\n @property({ attribute: false })\n model: TreeDataModel | undefined;\n\n @property({ type: Object })\n selectedNode: TreeNode | undefined;\n\n @state()\n private _selectedNodes = new Set<TreeNode>();\n\n get selectedNodes(): ReadonlySet<TreeNode> {\n return this._selectedNodes;\n }\n\n /** Callback to lazily load children for a node. When set, replaces event-based lazy loading. */\n @property({ attribute: false })\n loadChildren: LoadChildrenCallback | undefined;\n\n @property({ attribute: false })\n filterPredicate: TreeFilterPredicate | undefined;\n\n @property({ reflect: true, attribute: `exclusivity` })\n exclusivity: TreeExclusivity = `none`;\n\n @property({ reflect: true, attribute: `selection-filter` })\n selectionFilter: TreeSelectionFilter = `leaf`;\n\n @state()\n private _openIdx = -1;\n\n @state()\n private _isFocused = false;\n\n @state()\n private _menuOpen = false;\n\n @state()\n private _focusOnNarrowedText = false;\n\n @property({ reflect: true, attribute: `input-mode` })\n inputMode: string = ``;\n\n @property({ type: Boolean, reflect: true, attribute: `no-truncate` })\n noTruncate = false;\n\n @property({ type: Boolean, reflect: true, attribute: `show-suggestions` })\n showSuggestions = false;\n\n @property({ type: Boolean, reflect: true, attribute: `leading-caret` })\n leadingCaret = false;\n\n @property({ type: Boolean, reflect: true, attribute: `caret-embedded` })\n caretEmbedded = true;\n\n @property({ type: Boolean, reflect: true, attribute: `hide-root` })\n hideRoot = false;\n\n @property({ type: Boolean, reflect: true, attribute: `pad-ending` })\n padEnding = false;\n\n @property({ type: Boolean, reflect: true, attribute: `with-up` })\n withUp = false;\n\n #pendingNode: TreeNode | undefined;\n #pendingController: AbortController | undefined;\n #modelUnsubscribe: (() => void) | undefined;\n\n #previousSelectionKey = ``;\n #menuOpenedByKeyboard = false;\n #currentOpenTrigger: MenuTrigger | null = null;\n\n private tickled = new TickledController<number>(this, {\n getItems: () => this.#getTickledItems(),\n onTickle: (index) => {\n if (index !== undefined) {\n this.#onTickled(index);\n }\n },\n });\n\n #getTickledItems() {\n const r = this.root;\n const sel = this.selectedNode;\n if (!r || !sel)\n return [];\n\n const pathNodes = this.#findPath(r, sel) ?? [r];\n const items: Array<{ id: number; enabled: boolean }> = [];\n\n if (this.caretEmbedded) {\n pathNodes.forEach((_node, i) => {\n items.push({ id: i, enabled: true });\n });\n if (this.#canFocusSuggestions()) {\n items.push({ id: pathNodes.length, enabled: true });\n }\n } else {\n let segmentId = 0;\n pathNodes.forEach((node, i) => {\n const isLast = i === pathNodes.length - 1;\n const hasChildren = node.item.isLeaf !== true && (node.children === undefined || node.children.length > 0);\n const showLeadingCaret = this.leadingCaret && (i > 0 || this.hideRoot) && hasChildren;\n const showTrailingCaret = (!this.leadingCaret && hasChildren) || (this.leadingCaret && isLast && hasChildren);\n\n if (showLeadingCaret) {\n items.push({ id: segmentId++, enabled: true });\n }\n items.push({ id: segmentId++, enabled: true });\n if (showTrailingCaret) {\n items.push({ id: segmentId++, enabled: true });\n }\n });\n }\n\n return items;\n }\n\n #onTickled(index: number) {\n if (this.tickled.inputMode === `keyboard`) {\n this.#scrollTickledIntoView(index);\n }\n }\n\n #scrollTickledIntoView(index: number): void {\n const r = this.root;\n const sel = this.selectedNode;\n if (!r || !sel)\n return;\n\n const pathNodes = this.#findPath(r, sel) ?? [r];\n let el: HTMLElement | null = null;\n\n if (this.caretEmbedded && this.#canFocusSuggestions() && index === pathNodes.length) {\n el = this.shadowRoot?.querySelector<HTMLElement>(`ixfx-narrowed-text`) ?? null;\n } else {\n el = this.shadowRoot?.querySelectorAll<HTMLElement>(`.crumb-segment`)[index] ?? null;\n }\n\n el?.scrollIntoView({ inline: `nearest`, block: `nearest`, behavior: `smooth` });\n }\n\n #hasChildOptions(): boolean {\n const s = this.selectedNode;\n if (s === undefined)\n return false;\n\n const isPending = this.#pendingNode === s;\n const children = s.children ?? [];\n\n return children.length > 0 || isPending;\n }\n\n /** True when the suggestions (narrowed-text) sub-part is renderable and focusable. */\n #canFocusSuggestions(): boolean {\n return this.showSuggestions && this.#hasChildOptions();\n }\n\n #onFocus = (): void => {\n this._isFocused = true;\n };\n\n #onBlur = (): void => {\n this._isFocused = false;\n };\n\n #getHostContainer(): HTMLElement | null {\n return this.shadowRoot?.querySelector<HTMLElement>(`.host-container`) ?? null;\n }\n\n #onHostClick = (): void => {\n this.#getHostContainer()?.focus();\n };\n\n #handleOpenCaretMenu() {\n const currentTickled = this.tickled.tickledId;\n if (currentTickled === undefined)\n return;\n\n const r = this.root;\n const sel = this.selectedNode;\n if (!r || !sel)\n return;\n\n const pathNodes = this.#findPath(r, sel) ?? [r];\n\n // Virtual \"beyond last\" item (embedded mode only, when suggestions are available)\n if (this.caretEmbedded && this.#canFocusSuggestions() && currentTickled === pathNodes.length) {\n this.#shiftFocusToNarrowedText();\n return;\n }\n\n const segments = this.shadowRoot?.querySelectorAll<HTMLElement>(`.crumb-segment`);\n const trigger = segments?.[currentTickled]?.querySelector<MenuTrigger>(`.caret ixfx-menu-trigger`);\n if (trigger) {\n this.#menuOpenedByKeyboard = true;\n this.#currentOpenTrigger = trigger;\n document.addEventListener(`keydown`, this.#onMenuKeyNav, { capture: true });\n trigger.openMenu();\n this.#propagateInputModeToMenu();\n }\n }\n\n #propagateInputModeToMenu(): void {\n const inputMode = this.tickled.inputMode;\n requestAnimationFrame(() => {\n const container = this.#currentOpenTrigger?.querySelector(`ixfx-menu-container`);\n if (container) {\n container.setAttribute(`data-input-mode`, inputMode);\n }\n });\n }\n\n #onMenuTriggerClose = (): void => {\n document.removeEventListener(`keydown`, this.#onMenuKeyNav, { capture: true });\n this.#currentOpenTrigger = null;\n this.#menuOpenedByKeyboard = false;\n requestAnimationFrame(() => {\n this.#getHostContainer()?.focus();\n });\n };\n\n #onMenuKeyNav = (e: KeyboardEvent): void => {\n // Only handle ArrowLeft/ArrowRight - close menu and navigate to previous/next breadcrumb segment\n // ArrowDown/ArrowUp should pass through to let the menu handle them\n const container = this.#currentOpenTrigger?.querySelector(`ixfx-menu-container`);\n if (!container || !this.#currentOpenTrigger?.isOpen)\n return;\n\n switch (e.key) {\n case `ArrowLeft`:\n case `ArrowRight`: {\n e.preventDefault();\n e.stopPropagation();\n this.#currentOpenTrigger.closeMenu();\n const r = this.root;\n const sel = this.selectedNode;\n if (!r || !sel)\n break;\n const totalItems = this.#getTickledItems().length;\n const currentTickled = this.tickled.tickledId ?? -1;\n if (e.key === `ArrowLeft`) {\n if (currentTickled > 0) {\n this.tickled.handleKeyboardNavigation(`previous`);\n }\n } else {\n if (currentTickled < totalItems - 1) {\n this.tickled.handleKeyboardNavigation(`next`);\n }\n }\n break;\n }\n }\n };\n\n #onKeyDown = (e: KeyboardEvent): void => {\n const r = this.root;\n const sel = this.selectedNode;\n if (!r || !sel)\n return;\n\n const totalItems = this.#getTickledItems().length;\n const currentTickled = this.tickled.tickledId ?? -1;\n\n switch (e.key) {\n case `ArrowRight`: {\n e.preventDefault();\n if (currentTickled < totalItems - 1) {\n this.tickled.handleKeyboardNavigation(`next`);\n } else if (currentTickled === totalItems - 1 && this.#canFocusSuggestions()) {\n this.#shiftFocusToNarrowedText();\n }\n break;\n }\n case `ArrowLeft`: {\n e.preventDefault();\n if (currentTickled > 0) {\n this.tickled.handleKeyboardNavigation(`previous`);\n }\n break;\n }\n case `ArrowDown`:\n case `ArrowUp`: {\n if (this.tickled.tickledId !== undefined) {\n e.preventDefault();\n if (this.#currentOpenTrigger?.isOpen) {\n // Menu is already open - dispatch ArrowDown to the popover element for it to handle\n const container = this.#currentOpenTrigger.querySelector(`ixfx-menu-container`);\n const popover = container?.shadowRoot?.querySelector(`.popover`);\n if (popover) {\n popover.dispatchEvent(new KeyboardEvent(`keydown`, { key: e.key, bubbles: true }));\n }\n } else {\n this.#handleOpenCaretMenu();\n }\n }\n break;\n }\n case `Enter`:\n case ` `: {\n e.preventDefault();\n this.#activateTickled();\n break;\n }\n case `Escape`: {\n e.preventDefault();\n this._menuOpen = false;\n this.tickled.clearTickled();\n this.blur();\n break;\n }\n case `Tab`: {\n if (e.shiftKey) {\n // Let default Shift+Tab move focus backward, out of the component.\n break;\n }\n if (currentTickled === totalItems - 1 && this.#canFocusSuggestions()) {\n e.preventDefault();\n this.#shiftFocusToNarrowedText();\n }\n break;\n }\n }\n };\n\n /** Activates the currently tickled item, as if it had been clicked. */\n #activateTickled() {\n const currentTickled = this.tickled.tickledId;\n if (currentTickled === undefined)\n return;\n\n const r = this.root;\n const sel = this.selectedNode;\n if (!r || !sel)\n return;\n\n const pathNodes = this.#findPath(r, sel) ?? [r];\n\n // Virtual \"beyond last\" item (embedded mode only, when suggestions are available)\n if (this.caretEmbedded && this.#canFocusSuggestions() && currentTickled === pathNodes.length) {\n this.#shiftFocusToNarrowedText();\n return;\n }\n\n const segment = this.shadowRoot?.querySelector<HTMLElement>(`.crumb-segment[data-segment-id=\"${currentTickled}\"]`);\n segment?.click();\n }\n\n #shiftFocusToNarrowedText() {\n const narrowedText = this.shadowRoot?.querySelector(`ixfx-narrowed-text`);\n if (narrowedText) {\n this._menuOpen = false;\n this._focusOnNarrowedText = true;\n narrowedText.focus();\n }\n }\n\n #shiftFocusToPath() {\n this._focusOnNarrowedText = false;\n const hostContainer = this.#getHostContainer();\n if (hostContainer) {\n hostContainer.focus();\n }\n }\n\n #onNarrowedTextBlur = (): void => {\n this._focusOnNarrowedText = false;\n this.#shiftFocusToPath();\n };\n\n #onNarrowedTextShiftTab = (): void => {\n this._focusOnNarrowedText = false;\n this.#shiftFocusToPath();\n };\n\n // --- TreeComponent methods ---\n\n select(node: TreeNode): void {\n this.#setSelected(node);\n }\n\n deselect(_node: TreeNode): void {\n // Crumb navigation is single-selection; deselect navigates to parent or root\n }\n\n clearSelection(): void {\n if (this.root)\n this.#setSelected(this.root);\n }\n\n /** Not implemented on crumb-navigation. */\n selectAll(): void {\n // no-op\n }\n\n /** Not implemented on crumb-navigation. */\n deselectAll(): void {\n // no-op\n }\n\n getNodes(): ReadonlyArray<{ node: TreeNode; depth: number }> {\n if (!this.root)\n return [];\n const result: Array<{ node: TreeNode; depth: number }> = [];\n const visit = (node: TreeNode, depth: number) => {\n result.push({ node, depth });\n if (node.children) {\n for (const child of node.children) visit(child, depth + 1);\n }\n };\n for (const child of this.root.children ?? []) visit(child, 0);\n return result;\n }\n\n // --- Lifecycle ---\n\n override updated(changedProps: PropertyValues): void {\n if (changedProps.has(`model`)) {\n this.#modelUnsubscribe?.();\n this.#modelUnsubscribe = undefined;\n const model = this.model;\n if (model) {\n this.root = model.root;\n this.#modelUnsubscribe = model._subscribe((event) => {\n if (event.type === `root`) {\n this.root = event.root;\n this.requestUpdate();\n }\n });\n }\n }\n this.#runLayoutUpdate(changedProps);\n }\n\n override connectedCallback() {\n super.connectedCallback();\n this.addEventListener(`click`, this.#onHostClick);\n this.addEventListener(`wheel`, this.#onWheel, { passive: false });\n }\n\n override disconnectedCallback() {\n super.disconnectedCallback();\n this.removeEventListener(`click`, this.#onHostClick);\n this.removeEventListener(`wheel`, this.#onWheel);\n this.#modelUnsubscribe?.();\n this.#modelUnsubscribe = undefined;\n document.removeEventListener(`keydown`, this.#onMenuKeyNav, { capture: true });\n this.#currentOpenTrigger = null;\n }\n\n override firstUpdated() {\n const hostContainer = this.#getHostContainer();\n if (hostContainer) {\n hostContainer.scrollLeft = hostContainer.scrollWidth - hostContainer.clientWidth;\n }\n }\n\n #isWheelScrolling = false;\n\n #onWheel = (e: Event) => {\n const wheelEvent = e as WheelEvent;\n if (wheelEvent.deltaX !== 0 || wheelEvent.deltaY !== 0) {\n e.preventDefault();\n if (!this.#isWheelScrolling) {\n this.#isWheelScrolling = true;\n this.tickled.clearTickled();\n }\n const hostContainer = this.#getHostContainer();\n if (hostContainer) {\n hostContainer.scrollLeft += wheelEvent.deltaX + wheelEvent.deltaY;\n }\n clearTimeout(this.#wheelScrollTimeout);\n this.#wheelScrollTimeout = setTimeout(() => {\n this.#isWheelScrolling = false;\n }, 150);\n }\n };\n\n #wheelScrollTimeout: ReturnType<typeof setTimeout> | undefined;\n\n #runLayoutUpdate(_changedProperties: PropertyValues): void {\n if (!this.shadowRoot)\n return;\n\n const hsiElement: HTMLElement | null = this.shadowRoot.querySelector(`.horiz-select-items`);\n if (!hsiElement)\n return;\n\n const ulElement: HTMLElement | null = hsiElement.querySelector(`ul`);\n if (!ulElement)\n return;\n\n const menuTrigger: HTMLElement | null = this.shadowRoot.querySelector(`ixfx-menu-trigger`);\n if (!menuTrigger)\n return;\n\n if (ulElement.getBoundingClientRect().width > hsiElement.getBoundingClientRect().width) {\n menuTrigger.style.display = `inline-flex`;\n } else {\n menuTrigger.style.display = `none`;\n }\n\n for (const li of ulElement.querySelectorAll(`li`)) {\n const key = li.getAttribute(`data-key`) ?? ``;\n if (key === this.#previousSelectionKey) {\n this.#scrollToValue(li);\n break;\n }\n }\n }\n\n #scrollToValue(li: HTMLLIElement) {\n let l = li.offsetLeft;\n\n const ul = li.parentElement;\n if (!ul)\n return;\n l -= ul.offsetLeft;\n\n const horizSelectItems = ul.parentElement;\n if (!horizSelectItems)\n return;\n horizSelectItems.scroll({ left: l, top: 0, behavior: `smooth` });\n\n const horizSelect = horizSelectItems.parentElement;\n if (!horizSelect)\n return;\n horizSelect.style.minWidth = `${li.getBoundingClientRect().width}px`;\n }\n\n #abortPending() {\n if (this.#pendingController) {\n this.#pendingController.abort();\n this.#pendingController = undefined;\n this.#pendingNode = undefined;\n }\n }\n\n #findPath(node: TreeNode, target: TreeNode, acc: TreeNode[] = []): TreeNode[] | undefined {\n const path = [...acc, node];\n if (node === target)\n return path;\n if (!node.children)\n return undefined;\n for (const child of node.children) {\n const result = this.#findPath(child, target, path);\n if (result)\n return result;\n }\n return undefined;\n }\n\n #scrollSegmentIntoView(depth: number) {\n if (!this.shadowRoot)\n return;\n const segments = this.shadowRoot.querySelectorAll(`.crumb-segment`);\n const segment = segments[depth];\n segment?.scrollIntoView({ block: `nearest`, inline: `start` });\n }\n\n #updateTrailingWidth(): void {\n if (!this.padEnding || !this.shadowRoot)\n return;\n const hostContainer = this.shadowRoot.querySelector<HTMLElement>(`.host-container`);\n const trailing = this.shadowRoot.querySelector<HTMLElement>(`.trailing`);\n if (!hostContainer || !trailing)\n return;\n const segments = this.shadowRoot.querySelectorAll(`.crumb-segment`);\n const lastSegment = segments[segments.length - 1];\n if (!lastSegment)\n return;\n const containerWidth = hostContainer.getBoundingClientRect().width;\n const itemWidth = lastSegment.getBoundingClientRect().width;\n if (itemWidth < containerWidth) {\n trailing.style.width = `${containerWidth - itemWidth - 5}px`;\n requestAnimationFrame(() => {\n if (hostContainer.scrollWidth <= hostContainer.clientWidth) {\n hostContainer.style.setProperty(`--scroll-fade-x-start`, `0px`, `important`);\n } else {\n hostContainer.style.removeProperty(`--scroll-fade-x-start`);\n }\n });\n } else {\n trailing.style.width = ``;\n }\n }\n\n #setSelected(node: TreeNode) {\n const previous = this.selectedNode;\n if (previous) {\n this.#previousSelectionKey = previous.item?.key ?? ``;\n } else {\n this.#previousSelectionKey = ``;\n }\n const previousSet: ReadonlySet<TreeNode> = previous ? new Set([previous]) : new Set();\n this.selectedNode = node;\n this._selectedNodes = new Set([node]);\n\n if (this.root) {\n const path = this.#findPath(this.root, node);\n if (path) {\n const depth = this.hideRoot && path.length > 1 ? path.length - 2 : path.length - 1;\n requestAnimationFrame(() => {\n this.#updateTrailingWidth();\n const hostContainer = this.#getHostContainer();\n if (hostContainer) {\n hostContainer.scrollLeft = 0;\n }\n this.#scrollSegmentIntoView(depth);\n });\n }\n }\n\n this.dispatchEvent(new CustomEvent<TreeSelectDetail>(`select`, {\n detail: { selected: new Set([node]), previous: previousSet },\n bubbles: true,\n composed: true,\n }));\n }\n\n #onLabelClick(node: TreeNode, depth: number) {\n this._openIdx = -1;\n this.#setSelected(node);\n this.#scrollSegmentIntoView(depth);\n this.dispatchEvent(new CustomEvent<CrumbNavigationItemClickDetail>(`item-click`, {\n detail: { node, depth },\n bubbles: true,\n composed: true,\n }));\n }\n\n #onCaretClick(node: TreeNode, depth: number, e: MouseEvent) {\n e.preventDefault();\n e.stopPropagation();\n\n if (this._openIdx === depth) {\n this._openIdx = -1;\n return;\n }\n this._openIdx = depth;\n\n if (node.children === undefined && this.#pendingNode !== node) {\n this.#abortPending();\n this.#pendingNode = node;\n const controller = new AbortController();\n this.#pendingController = controller;\n\n if (this.loadChildren) {\n this.#invokeLoadChildren(node, depth, controller).catch(() => {});\n }\n }\n\n this.requestUpdate();\n }\n\n async #invokeLoadChildren(node: TreeNode, depth: number, controller: AbortController): Promise<void> {\n try {\n const children = [...await collectDataResult(\n this.loadChildren!({ node, depth }, controller.signal),\n controller.signal,\n )];\n if (controller.signal.aborted)\n return;\n node.children = children;\n this.#pendingNode = undefined;\n this.#pendingController = undefined;\n this.dispatchEvent(new CustomEvent<CrumbNavigationExpandDetail>(`expand`, {\n detail: { node, depth },\n bubbles: true,\n composed: true,\n }));\n this.requestUpdate();\n } catch {\n if (controller.signal.aborted)\n return;\n node.children = [];\n this.#pendingNode = undefined;\n this.#pendingController = undefined;\n this.requestUpdate();\n }\n }\n\n #onSegmentMenuCommand(e: CustomEvent, node: TreeNode, depth: number) {\n const key = e.detail.command;\n if (this.leadingCaret) {\n const child = node.children?.find(c => c.item.key === key);\n if (child) {\n this.#onChildClick(child, depth + 1);\n return;\n }\n if (this.#currentLeadingSiblings) {\n const sibling = this.#currentLeadingSiblings.find(c => c.item.key === key);\n if (sibling) {\n this.#onChildClick(sibling, depth);\n }\n this.#currentLeadingSiblings = undefined;\n return;\n }\n }\n const child = node.children?.find(c => c.item.key === key);\n if (child) {\n this.#onChildClick(child, depth + 1);\n }\n }\n\n #currentLeadingSiblings: TreeNode[] | undefined = undefined;\n\n #getSiblingMenuItems(pathNodes: TreeNode[], index: number): unknown {\n if (index === 0) {\n if (!this.hideRoot || !this.root)\n return [];\n const siblings = [...(this.root.children ?? [])].sort((a, b) => (a.item.label ?? ``).localeCompare(b.item.label ?? ``));\n this.#currentLeadingSiblings = siblings;\n return siblings.map(sibling => html`\n <ixfx-menu-item\n label=\"${sibling.item.label}\"\n command=\"${sibling.item.key}\"\n icon-name=\"${sibling.item.icon ?? nothing}\"\n @click=${() => {\n this.#onChildClick(sibling, index);\n }}\n ></ixfx-menu-item>\n `);\n }\n const parent = pathNodes[index - 1];\n const siblings = [...(parent.children ?? [])].sort((a, b) => (a.item.label ?? ``).localeCompare(b.item.label ?? ``));\n this.#currentLeadingSiblings = siblings;\n return siblings.map(sibling => html`\n <ixfx-menu-item\n label=\"${sibling.item.label}\"\n command=\"${sibling.item.key}\"\n icon-name=\"${sibling.item.icon ?? nothing}\"\n @click=${() => {\n this.#onChildClick(sibling, index);\n }}\n ></ixfx-menu-item>\n `);\n }\n\n #onChildClick(node: TreeNode, depth: number) {\n this._openIdx = -1;\n this.#setSelected(node);\n this.dispatchEvent(new CustomEvent<CrumbNavigationItemClickDetail>(`item-click`, {\n detail: { node, depth },\n bubbles: true,\n composed: true,\n }));\n }\n\n #onUpClick(): void {\n const r = this.root;\n const sel = this.selectedNode;\n if (!r || !sel)\n return;\n\n const path = this.#findPath(r, sel);\n if (!path || path.length <= 1)\n return;\n\n const parent = path[path.length - 2];\n this.#setSelected(parent);\n }\n\n /** Navigate to a node by key path. Returns false if any key is not found in already-loaded children. */\n navigateTo(keys: readonly string[]): boolean {\n if (!this.root?.children)\n return false;\n let current: TreeNode | undefined = this.root;\n for (const key of keys) {\n const found: TreeNode | undefined = current?.children?.find(n => n.item.key === key);\n if (!found)\n return false;\n current = found;\n }\n if (current && current !== this.root) {\n this.#setSelected(current);\n }\n return true;\n }\n\n /** Navigate to the first node matching the predicate. Returns false if not found. */\n navigateToNode(predicate: (node: TreeNode) => boolean): boolean {\n if (!this.root)\n return false;\n const keyPath = this.#findNodePath(this.root.children ?? [], predicate);\n if (!keyPath)\n return false;\n return this.navigateTo(keyPath);\n }\n\n #findNodePath(\n nodes: TreeNode[],\n predicate: (node: TreeNode) => boolean,\n prefix: string[] = [],\n ): string[] | undefined {\n for (const node of nodes) {\n const path = [...prefix, node.item.key];\n if (predicate(node))\n return path;\n if (node.children?.length) {\n const result = this.#findNodePath(node.children, predicate, path);\n if (result)\n return result;\n }\n }\n return undefined;\n }\n\n #onMenuCommand(e: CustomEvent) {\n const node = this.selectedNode;\n if (!node?.children)\n return;\n\n const key = e.detail.command;\n const child = node.children.find(c => c.item.key === key);\n if (child) {\n const depth = this.root ? (this.#findPath(this.root, node)?.length ?? 1) : 1;\n this.#onChildClick(child, depth);\n }\n }\n\n render() {\n const r = this.root;\n const sel = this.selectedNode;\n\n if (!r || !sel) {\n return html``;\n }\n\n this.inputMode = this.tickled.inputMode;\n\n let pathNodes = this.#findPath(r, sel) ?? [r];\n if (this.hideRoot && pathNodes.length > 1) {\n pathNodes = pathNodes.slice(1);\n }\n const _hasChildOptions = this.#hasChildOptions();\n\n const isAtRoot = (() => {\n const fullPath = this.#findPath(r, sel) ?? [r];\n return fullPath.length <= 1;\n })();\n\n const parts: Array<ReturnType<typeof html>> = [];\n let segmentId = 0;\n\n pathNodes.forEach((node, i) => {\n const isLast = i === pathNodes.length - 1;\n const isPending = this.#pendingNode === node;\n const isOpen = this._openIdx === i;\n const hasChildren = node.item.isLeaf !== true && (node.children === undefined || node.children.length > 0);\n const isTickled = this.tickled.isTickled(i);\n\n const showLeadingCaret = this.leadingCaret && (i > 0 || this.hideRoot) && hasChildren;\n const showTrailingCaret = (!this.leadingCaret && hasChildren) || (this.leadingCaret && isLast && hasChildren);\n\n const siblingMenuItems = showLeadingCaret ? this.#getSiblingMenuItems(pathNodes, i) : [];\n const childMenuItems = (node.children ?? []).map(c => html`\n <ixfx-menu-item\n label=\"${c.item.label}\"\n command=\"${c.item.key}\"\n icon-name=\"${c.item.icon ?? nothing}\"\n ></ixfx-menu-item>\n `);\n\n if (this.caretEmbedded) {\n const canTruncate = !this.noTruncate && !isLast && !isTickled;\n\n parts.push(html`\n <div class=\"item crumb-segment ${isTickled ? `tickled` : ``} ${canTruncate ? `truncatable` : ``} ${this.leadingCaret ? `leading-caret` : ``} ${isLast ? `last-label` : ``}\" data-segment-id=\"${i}\" data-path-index=\"${i}\"\n @click=${(e: MouseEvent) => {\n if ((e.target as HTMLElement).closest(`.caret`))\n return; this.#onLabelClick(node, i);\n }}\n >\n ${showLeadingCaret\n ? html`\n <span class=\"caret ${isOpen ? `open` : ``} ${isPending ? `pending` : ``}\">\n ${isPending\n ? html`<span class=\"loading-spinner\"></span>`\n : html`\n <ixfx-menu-trigger mode=\"trigger\" label=\"›\" .tabStop=${false} @menu-command=${(e: CustomEvent) => this.#onSegmentMenuCommand(e, node, i)}>\n <ixfx-menu-container slot=\"menu\">\n ${siblingMenuItems}\n </ixfx-menu-container>\n </ixfx-menu-trigger>\n `\n }\n </span>\n `\n : nothing\n }\n <span class=\"label\">${node.item.label}</span>\n ${showTrailingCaret\n ? html`\n <span class=\"caret ${isOpen ? `open` : ``} ${isPending ? `pending` : ``}\">\n ${isPending\n ? html`<span class=\"loading-spinner\"></span>`\n : html`\n <ixfx-menu-trigger mode=\"trigger\" label=\"›\" .tabStop=${false} placement=\"right-start\" @menu-command=${(e: CustomEvent) => this.#onSegmentMenuCommand(e, node, i)}>\n <ixfx-menu-container slot=\"menu\">\n ${childMenuItems}\n </ixfx-menu-container>\n </ixfx-menu-trigger>\n `\n }\n </span>\n `\n : nothing\n }\n </div>\n `);\n } else {\n const leadingCaretTickled = showLeadingCaret ? this.tickled.isTickled(segmentId) : false;\n if (showLeadingCaret) {\n parts.push(html`\n <div class=\"item crumb-segment ${leadingCaretTickled ? `tickled` : ``}\" data-segment-id=\"${segmentId}\" data-path-index=\"${i}\"\n @click=${(e: MouseEvent) => {\n const trigger = (e.target as HTMLElement).closest(`.crumb-segment`)?.querySelector(`ixfx-menu-trigger`);\n if (trigger)\n trigger.openMenu();\n }}\n >\n <span class=\"caret ${isOpen ? `open` : ``} ${isPending ? `pending` : ``}\">\n ${isPending\n ? html`<span class=\"loading-spinner\"></span>`\n : html`\n <ixfx-menu-trigger mode=\"trigger\" label=\"›\" .tabStop=${false} placement=\"right-start\" @menu-command=${(e: CustomEvent) => this.#onSegmentMenuCommand(e, node, i)}>\n <ixfx-menu-container slot=\"menu\">\n ${siblingMenuItems}\n </ixfx-menu-container>\n </ixfx-menu-trigger>\n `\n }\n </span>\n </div>\n `);\n segmentId++;\n }\n const labelTickled = this.tickled.isTickled(segmentId);\n const canTruncate = !this.noTruncate && !isLast && !labelTickled;\n parts.push(html`\n <div class=\"item crumb-segment ${labelTickled ? `tickled` : ``} ${canTruncate ? `truncatable` : ``} ${isLast ? `last-label` : ``}\" data-segment-id=\"${segmentId}\" data-path-index=\"${i}\"\n @click=${(e: MouseEvent) => {\n if ((e.target as HTMLElement).closest(`.caret`))\n return; this.#onLabelClick(node, i);\n }}\n >\n <span class=\"label\">${node.item.label}</span>\n </div>\n `);\n segmentId++;\n if (showTrailingCaret) {\n const trailingCaretTickled = this.tickled.isTickled(segmentId);\n parts.push(html`\n <div class=\"item crumb-segment ${trailingCaretTickled ? `tickled` : ``}\" data-segment-id=\"${segmentId}\" data-path-index=\"${i}\"\n @click=${(e: MouseEvent) => {\n const trigger = (e.target as HTMLElement).closest(`.crumb-segment`)?.querySelector(`ixfx-menu-trigger`);\n if (trigger)\n trigger.openMenu();\n }}\n >\n <span class=\"caret ${isOpen ? `open` : ``} ${isPending ? `pending` : ``}\">\n ${isPending\n ? html`<span class=\"loading-spinner\"></span>`\n : html`\n <ixfx-menu-trigger mode=\"trigger\" label=\"›\" .tabStop=${false} @menu-command=${(e: CustomEvent) => this.#onSegmentMenuCommand(e, node, i)}>\n <ixfx-menu-container slot=\"menu\">\n ${childMenuItems}\n </ixfx-menu-container>\n </ixfx-menu-trigger>\n `\n }\n </span>\n </div>\n `);\n segmentId++;\n }\n }\n });\n\n return html`\n <div class=\"crumb-wrapper\">\n ${this.withUp\n ? html`\n <button\n class=\"up-button\"\n ?disabled=${isAtRoot}\n aria-label=\"Go up one level\"\n @click=${this.#onUpClick}\n >\n <ixfx-icon name=\"folder-up\"></ixfx-icon>\n </button>\n `\n : nothing}\n <div\n class=\"host-container scroll-fade-x\"\n tabindex=\"0\"\n @focus=${this.#onFocus}\n @blur=${this.#onBlur}\n @keydown=${this.#onKeyDown}\n @click=${this.#onHostClick}\n @menu-trigger-close=${this.#onMenuTriggerClose}\n @mouseout=${(e: MouseEvent) => this.tickled.handlePointerLeave(e as PointerEvent)}\n >\n <div class=\"parts\"\n @mouseover=${(e: MouseEvent) => {\n if (this.#isWheelScrolling)\n return;\n const target = e.target;\n if (!(target instanceof HTMLElement))\n return;\n const segment = target.closest(`.crumb-segment`) as HTMLElement | null;\n if (!segment)\n return;\n const segmentId = parseInt(segment.dataset.segmentId ?? ``, 10);\n if (Number.isNaN(segmentId))\n return;\n const pathIndex = parseInt(segment.dataset.pathIndex ?? ``, 10);\n const node = pathNodes[pathIndex];\n if (!node)\n return;\n this.tickled.handlePointerEnter(segmentId);\n this.dispatchEvent(new CustomEvent<TreeTickleDetail>(`tickle`, { detail: { node, depth: pathIndex }, bubbles: true, composed: true }));\n }}\n >${parts}${this.padEnding ? html`<div class=\"trailing\"></div>` : nothing}</div>\n ${this.showSuggestions ? this.#renderChildOptions() : nothing}\n </div>\n </div>\n `;\n }\n\n #renderChildOptions() {\n const s = this.selectedNode;\n if (s === undefined) {\n return nothing;\n }\n\n const isPending = this.#pendingNode === s;\n const children = s.children ?? [];\n\n if (children.length === 0 && !isPending) {\n return nothing;\n }\n\n if (isPending) {\n return html`\n <div class=\"horiz-select\">\n <div class=\"horiz-select-items\">\n <span class=\"loading-spinner\"></span>\n </div>\n </div>\n `;\n }\n\n return html`\n <ixfx-narrowed-text\n class=\"horiz-select\"\n selection-mode=\"single\"\n orientation=\"horizontal\"\n nowrap\n width=${this.#getChildOptionsWidth()}\n @change=${this.#onNarrowedTextChange}\n @narrowed-text-blur=${this.#onNarrowedTextBlur}\n @narrowed-text-shift-tab=${this.#onNarrowedTextShiftTab}\n >\n ${children.map(c => html`\n <span data-value=\"${c.item.key}\" data-label=\"${c.item.label}\"></span>\n `)}\n </ixfx-narrowed-text>\n `;\n }\n\n #onNarrowedTextChange(e: CustomEvent) {\n e.stopPropagation();\n const detail = e.detail as { item: { value: string } };\n const node = this.selectedNode;\n if (!node?.children)\n return;\n\n const child = node.children.find(c => c.item.key === detail.item.value);\n if (child) {\n const depth = this.root ? (this.#findPath(this.root, node)?.length ?? 1) : 1;\n this.#onChildClick(child, depth);\n }\n }\n\n #getChildOptionsWidth(): string {\n return `var(--child-options-width, 50ch)`;\n }\n\n static styles = [themeFallbacks, tickledStyles, tickledItemStyles, scrollFadeStyles(`x`), css`\n :host {\n --crumb-item-bg: var(--item-bg, transparent);\n --crumb-item-bg-tickled: var(--item-bg-tickled);\n --crumb-item-text-tickled: var(--item-text-tickled);\n --crumb-item-border: var(--item-border);\n --crumb-item-border-tickled: var(--item-border-tickled);\n --crumb-item-padding: var(--space-s, 2px);\n --crumb-item-border-radius: var(--item-border-radius);\n --crumb-item-gap: var(--item-gap, var(--space-xs));\n --crumb-separator: var(--surface-muted-text);\n --crumb-truncate-min-width: 10ch;\n display: flex;\n width: 100%;\n }\n\n /* Outline goes on :host, not .host-container: .host-container carries the\n * scroll-fade mask-image, and CSS masks clip everything painted outside\n * the masked box - including an outline, which paints outside the border edge. */\n :host(:focus-within) {\n outline: 2px solid var(--accent);\n outline-offset: 2px;\n }\n\n .crumb-wrapper {\n display: flex;\n align-items: center;\n gap: var(--crumb-item-gap);\n width: 100%;\n }\n\n .up-button {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n flex-shrink: 0;\n background: var(--crumb-item-bg);\n border: var(--crumb-item-border);\n border-radius: var(--crumb-item-border-radius);\n padding: var(--crumb-item-padding);\n cursor: pointer;\n color: inherit;\n }\n\n .up-button:disabled {\n opacity: 0.5;\n cursor: not-allowed;\n }\n\n .up-button:hover:not(:disabled) {\n background: var(--crumb-item-bg-tickled);\n border-color: var(--crumb-item-border-tickled);\n }\n\n .up-button ixfx-icon {\n width: 1em;\n height: 1em;\n pointer-events: none;\n }\n\n /* Edge fade (shows/hides based on scroll position) comes from the\n * shared .scroll-fade-x class - see ../styles/scroll-fade.ts */\n .host-container {\n display: flex;\n flex: 1;\n min-width: 0;\n outline: none;\n overflow: scroll;\n scroll-snap-type: x mandatory;\n scrollbar-width: none;\n overscroll-behavior: none;\n }\n\n .host-container::-webkit-scrollbar {\n display: none;\n }\n\n .parts {\n display: flex;\n gap: var(--space-s);\n }\n\n .trailing {\n flex-shrink: 0;\n }\n\n .crumb-segment {\n display: flex;\n align-items: center;\n flex-shrink: 0;\n background: var(--crumb-item-bg);\n border: var(--crumb-item-border);\n border-radius: var(--crumb-item-border-radius);\n padding:0;\n }\n\n .crumb-segment.leading-caret {\n flex-direction: row;\n }\n\n .crumb-segment.tickled {\n background: var(--crumb-item-bg-tickled);\n border-color: var(--crumb-item-border-tickled);\n color: var(--crumb-item-text-tickled);\n flex-shrink: 0;\n min-width: auto;\n }\n\n .crumb-segment.truncatable {\n flex-shrink: 1;\n min-width: min(var(--crumb-truncate-min-width), auto);\n overflow: hidden;\n }\n\n .crumb-segment.truncatable .label {\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n min-width: 0;\n }\n\n .label {\n padding: var(--crumb-item-padding);\n cursor: pointer;\n white-space: nowrap;\n color: inherit;\n }\n\n .crumb-segment.last-label .label {\n color: var(--crumb-last-label-color, inherit);\n font-style: var(--crumb-last-label-font-style, inherit);\n font-weight: var(--crumb-last-label-font-weight, inherit);\n text-decoration: var(--crumb-last-label-text-decoration, inherit);\n text-underline-offset: var(--crumb-last-label-text-underline-offset, auto);\n }\n\n .crumb-segment.tickled .label {\n color: var(--crumb-item-text-tickled);\n overflow: visible;\n text-overflow: clip;\n }\n\n .crumb-segment ixfx-menu-trigger {\n --ixfx-button-padding: var(--space-s, 2px);\n }\n\n .caret {\n position: relative;\n cursor: pointer;\n color: var(--crumb-separator);\n display: inline-flex;\n align-items: center;\n justify-content: center;\n transition: all 0.2s ease-in-out;\n }\n\n .caret.open {\n background: color-mix(in srgb, var(--surface-5) 40%, transparent);\n }\n\n .caret.pending {\n display: inline-flex;\n }\n\n .caret > ixfx-menu-trigger {\n display: inline-flex;\n margin: 0;\n --_trigger-hover-bg: transparent;\n --_trigger-hover-opacity: 0.6;\n }\n\n .caret > ixfx-menu-trigger::part(base) {\n background: none;\n border: none;\n color: inherit;\n cursor: pointer;\n font-size: inherit;\n line-height: 1;\n }\n\n .caret > ixfx-menu-trigger::part(base):hover {\n background: none;\n opacity: 0.6;\n }\n\n .separator {\n margin-left: var(--crumb-item-gap);\n margin-right: var(--crumb-item-gap);\n color: var(--crumb-separator);\n }\n\n .separator-trigger {\n display: inline-flex;\n margin-left: var(--crumb-item-gap);\n margin-right: var(--crumb-item-gap);\n --_trigger-hover-bg: transparent;\n --_trigger-hover-opacity: 0.6;\n }\n\n .separator-trigger::part(base) {\n background: none;\n border: none;\n color: var(--crumb-separator);\n padding: 0;\n cursor: pointer;\n font-size: inherit;\n line-height: 1;\n }\n\n .separator-trigger::part(base):hover {\n background: none;\n opacity: 0.6;\n }\n\n .separator-trigger.tickled::part(base) {\n }\n\n ixfx-menu-trigger {\n display: none;\n }\n\n .horiz-select > ixfx-menu-trigger {\n display: inline-flex;\n }\n\n .horiz-select {\n display: flex;\n min-width: 5ch;\n }\n\n .loading-spinner {\n display: inline-block;\n width: 12px;\n height: 12px;\n border: 2px solid var(--surface-5);\n border-top-color: var(--accent);\n border-radius: 50%;\n animation: crumb-spin 0.7s linear infinite;\n }\n\n @keyframes crumb-spin {\n to { transform: rotate(360deg); }\n }\n\n ::slotted(*), option {\n user-select: none;\n scroll-snap-align: start;\n }\n `];\n}\n\ndeclare global {\n interface HTMLElementTagNameMap {\n \"ixfx-crumb-navigation\": CrumbNavigationElement;\n }\n}\n\nexport interface CrumbNavigationElementEventMap extends TreeComponentEventMap {\n 'item-click': TreeItemClickEvent;\n 'expand': TreeExpandEvent;\n 'select': TreeSelectEvent;\n 'tickle': TreeTickleEvent;\n 'activate': TreeActivateEvent;\n}\n\nexport interface CrumbNavigationElement {\n addEventListener: (<K extends keyof CrumbNavigationElementEventMap>(\n type: K,\n listener: (this: CrumbNavigationElement, event: CrumbNavigationElementEventMap[K]) => void,\n options?: boolean | AddEventListenerOptions,\n ) => void) & ((\n type: string,\n listener: EventListenerOrEventListenerObject,\n options?: boolean | AddEventListenerOptions,\n ) => void);\n}\n"],"mappings":"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"}
|
|
@@ -0,0 +1,171 @@
|
|
|
1
|
+
//#region src/common/data-controller.ts
|
|
2
|
+
function isAsyncIterable(v) {
|
|
3
|
+
return typeof v === `object` && v !== null && Symbol.asyncIterator in v;
|
|
4
|
+
}
|
|
5
|
+
/**
|
|
6
|
+
* Lit ReactiveController that manages one active data provider request at a time.
|
|
7
|
+
*
|
|
8
|
+
* Handles all three provider return modes (sync, async one-shot, streaming),
|
|
9
|
+
* tracks progress, and cancels in-flight requests when a new one starts.
|
|
10
|
+
* Calls host.requestUpdate() on every state change so the component re-renders
|
|
11
|
+
* automatically.
|
|
12
|
+
*
|
|
13
|
+
* @typeParam TQuery - The query/scope type passed to the provider.
|
|
14
|
+
* @typeParam TItem - The item type produced by the provider.
|
|
15
|
+
*
|
|
16
|
+
* @example
|
|
17
|
+
* ```ts
|
|
18
|
+
* class MyList extends LitElement {
|
|
19
|
+
* #data = new DataController<string, MyItem>(this, myProvider);
|
|
20
|
+
*
|
|
21
|
+
* protected override render() {
|
|
22
|
+
* return html`
|
|
23
|
+
* ${this.#data.loading ? html`<span>Loading…</span>` : nothing}
|
|
24
|
+
* ${this.#data.items.map(item => html`<div>${item.label}</div>`)}
|
|
25
|
+
* `;
|
|
26
|
+
* }
|
|
27
|
+
* }
|
|
28
|
+
* ```
|
|
29
|
+
*/
|
|
30
|
+
var DataController = class {
|
|
31
|
+
#host;
|
|
32
|
+
#opts;
|
|
33
|
+
#provider;
|
|
34
|
+
#abort;
|
|
35
|
+
#items = [];
|
|
36
|
+
#loading = false;
|
|
37
|
+
#loaded = 0;
|
|
38
|
+
#total;
|
|
39
|
+
#error;
|
|
40
|
+
constructor(host, provider, options) {
|
|
41
|
+
this.#host = host;
|
|
42
|
+
this.#provider = provider;
|
|
43
|
+
this.#opts = {
|
|
44
|
+
clearOnRequest: options?.clearOnRequest ?? true,
|
|
45
|
+
onError: options?.onError
|
|
46
|
+
};
|
|
47
|
+
host.addController(this);
|
|
48
|
+
}
|
|
49
|
+
hostConnected() {}
|
|
50
|
+
hostDisconnected() {
|
|
51
|
+
this.cancel();
|
|
52
|
+
}
|
|
53
|
+
get provider() {
|
|
54
|
+
return this.#provider;
|
|
55
|
+
}
|
|
56
|
+
set provider(value) {
|
|
57
|
+
this.#provider = value;
|
|
58
|
+
}
|
|
59
|
+
/** The currently accumulated items. */
|
|
60
|
+
get items() {
|
|
61
|
+
return this.#items;
|
|
62
|
+
}
|
|
63
|
+
/** True while a provider call is pending or a stream is still open. */
|
|
64
|
+
get loading() {
|
|
65
|
+
return this.#loading;
|
|
66
|
+
}
|
|
67
|
+
/** Number of items accumulated so far in the current request. */
|
|
68
|
+
get loaded() {
|
|
69
|
+
return this.#loaded;
|
|
70
|
+
}
|
|
71
|
+
/**
|
|
72
|
+
* Provider's latest estimate of the total number of items expected.
|
|
73
|
+
* Undefined when the provider has not reported a total.
|
|
74
|
+
*/
|
|
75
|
+
get total() {
|
|
76
|
+
return this.#total;
|
|
77
|
+
}
|
|
78
|
+
/**
|
|
79
|
+
* Progress as a 0–1 value, or undefined when total is unknown.
|
|
80
|
+
* Derived from loaded / total.
|
|
81
|
+
*/
|
|
82
|
+
get progress() {
|
|
83
|
+
if (this.#total === void 0 || this.#total === 0) return void 0;
|
|
84
|
+
return Math.min(this.#loaded / this.#total, 1);
|
|
85
|
+
}
|
|
86
|
+
/** The last error thrown by the provider, or undefined if the last request succeeded. */
|
|
87
|
+
get error() {
|
|
88
|
+
return this.#error;
|
|
89
|
+
}
|
|
90
|
+
/**
|
|
91
|
+
* Cancel any in-flight request and start a new one.
|
|
92
|
+
* Clears items immediately unless clearOnRequest was set to false.
|
|
93
|
+
*/
|
|
94
|
+
request(query) {
|
|
95
|
+
this.cancel();
|
|
96
|
+
if (!this.#provider) return;
|
|
97
|
+
if (this.#opts.clearOnRequest) {
|
|
98
|
+
this.#items = [];
|
|
99
|
+
this.#loaded = 0;
|
|
100
|
+
}
|
|
101
|
+
this.#total = void 0;
|
|
102
|
+
this.#error = void 0;
|
|
103
|
+
this.#loading = true;
|
|
104
|
+
this.#host.requestUpdate();
|
|
105
|
+
this.#abort = new AbortController();
|
|
106
|
+
const { signal } = this.#abort;
|
|
107
|
+
this.#consume(this.#provider(query, signal), signal);
|
|
108
|
+
}
|
|
109
|
+
/** Abort any in-flight request without issuing a new one. */
|
|
110
|
+
cancel() {
|
|
111
|
+
this.#abort?.abort();
|
|
112
|
+
this.#abort = void 0;
|
|
113
|
+
if (this.#loading) {
|
|
114
|
+
this.#loading = false;
|
|
115
|
+
this.#host.requestUpdate();
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
#consume(result, signal) {
|
|
119
|
+
if (Array.isArray(result)) {
|
|
120
|
+
this.#applyBatch({ items: result }, signal);
|
|
121
|
+
this.#loading = false;
|
|
122
|
+
this.#host.requestUpdate();
|
|
123
|
+
} else if (isAsyncIterable(result)) this.#consumeStream(result, signal);
|
|
124
|
+
else result.then((items) => {
|
|
125
|
+
if (signal.aborted) return;
|
|
126
|
+
this.#applyBatch({ items }, signal);
|
|
127
|
+
this.#loading = false;
|
|
128
|
+
this.#host.requestUpdate();
|
|
129
|
+
}, (err) => {
|
|
130
|
+
if (signal.aborted) return;
|
|
131
|
+
this.#handleError(err);
|
|
132
|
+
});
|
|
133
|
+
}
|
|
134
|
+
async #consumeStream(stream, signal) {
|
|
135
|
+
try {
|
|
136
|
+
for await (const batch of stream) {
|
|
137
|
+
if (signal.aborted) return;
|
|
138
|
+
this.#applyBatch(batch, signal);
|
|
139
|
+
this.#host.requestUpdate();
|
|
140
|
+
}
|
|
141
|
+
} catch (err) {
|
|
142
|
+
if (signal.aborted) return;
|
|
143
|
+
this.#handleError(err);
|
|
144
|
+
return;
|
|
145
|
+
}
|
|
146
|
+
if (!signal.aborted) {
|
|
147
|
+
this.#loading = false;
|
|
148
|
+
this.#host.requestUpdate();
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
#applyBatch(batch, _signal) {
|
|
152
|
+
if (batch.replace) {
|
|
153
|
+
this.#items = [...batch.items];
|
|
154
|
+
this.#loaded = batch.items.length;
|
|
155
|
+
} else {
|
|
156
|
+
this.#items = [...this.#items, ...batch.items];
|
|
157
|
+
this.#loaded = this.#items.length;
|
|
158
|
+
}
|
|
159
|
+
if (batch.total !== void 0) this.#total = batch.total;
|
|
160
|
+
}
|
|
161
|
+
#handleError(err) {
|
|
162
|
+
this.#error = err;
|
|
163
|
+
this.#loading = false;
|
|
164
|
+
this.#opts.onError?.(err);
|
|
165
|
+
this.#host.requestUpdate();
|
|
166
|
+
}
|
|
167
|
+
};
|
|
168
|
+
//#endregion
|
|
169
|
+
export { DataController as t };
|
|
170
|
+
|
|
171
|
+
//# sourceMappingURL=data-controller-DOlmqNKb.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"data-controller-DOlmqNKb.js","names":["#host","#opts","#provider","#items","#loading","#loaded","#total","#error","#abort","#consume","#applyBatch","#consumeStream","#handleError"],"sources":["../src/common/data-controller.ts"],"sourcesContent":["import type { ReactiveController, ReactiveControllerHost } from 'lit';\nimport type { DataBatch, DataProviderResult, IDataProvider } from './data-provider.js';\n\nexport type DataControllerOptions = {\n /**\n * Clear accumulated items immediately when request() is called.\n * When false, stale items remain visible while the new request is in-flight\n * (useful for re-query-on-keystroke patterns — avoids a blank flash).\n * Default: true.\n */\n clearOnRequest?: boolean;\n /**\n * Called when the provider throws or rejects. Useful for logging without\n * coupling the error to render logic.\n */\n onError?: (err: unknown) => void;\n};\n\nfunction isAsyncIterable<T>(v: unknown): v is AsyncIterable<T> {\n return typeof v === `object` && v !== null && Symbol.asyncIterator in v;\n}\n\n/**\n * Lit ReactiveController that manages one active data provider request at a time.\n *\n * Handles all three provider return modes (sync, async one-shot, streaming),\n * tracks progress, and cancels in-flight requests when a new one starts.\n * Calls host.requestUpdate() on every state change so the component re-renders\n * automatically.\n *\n * @typeParam TQuery - The query/scope type passed to the provider.\n * @typeParam TItem - The item type produced by the provider.\n *\n * @example\n * ```ts\n * class MyList extends LitElement {\n * #data = new DataController<string, MyItem>(this, myProvider);\n *\n * protected override render() {\n * return html`\n * ${this.#data.loading ? html`<span>Loading…</span>` : nothing}\n * ${this.#data.items.map(item => html`<div>${item.label}</div>`)}\n * `;\n * }\n * }\n * ```\n */\nexport class DataController<TQuery, TItem> implements ReactiveController {\n readonly #host: ReactiveControllerHost;\n readonly #opts: Required<Omit<DataControllerOptions, `onError`>> & Pick<DataControllerOptions, `onError`>;\n\n #provider: IDataProvider<TQuery, TItem> | undefined;\n #abort: AbortController | undefined;\n\n #items: readonly TItem[] = [];\n #loading = false;\n #loaded = 0;\n #total: number | undefined;\n #error: unknown;\n\n constructor(\n host: ReactiveControllerHost,\n provider?: IDataProvider<TQuery, TItem>,\n options?: DataControllerOptions,\n ) {\n this.#host = host;\n this.#provider = provider;\n this.#opts = {\n clearOnRequest: options?.clearOnRequest ?? true,\n onError: options?.onError,\n };\n host.addController(this);\n }\n\n // ---- ReactiveController lifecycle ----\n\n hostConnected(): void {}\n\n hostDisconnected(): void {\n this.cancel();\n }\n\n // ---- Configuration ----\n\n get provider(): IDataProvider<TQuery, TItem> | undefined {\n return this.#provider;\n }\n\n set provider(value: IDataProvider<TQuery, TItem> | undefined) {\n this.#provider = value;\n }\n\n // ---- Reactive state (read-only) ----\n\n /** The currently accumulated items. */\n get items(): readonly TItem[] {\n return this.#items;\n }\n\n /** True while a provider call is pending or a stream is still open. */\n get loading(): boolean {\n return this.#loading;\n }\n\n /** Number of items accumulated so far in the current request. */\n get loaded(): number {\n return this.#loaded;\n }\n\n /**\n * Provider's latest estimate of the total number of items expected.\n * Undefined when the provider has not reported a total.\n */\n get total(): number | undefined {\n return this.#total;\n }\n\n /**\n * Progress as a 0–1 value, or undefined when total is unknown.\n * Derived from loaded / total.\n */\n get progress(): number | undefined {\n if (this.#total === undefined || this.#total === 0)\n return undefined;\n return Math.min(this.#loaded / this.#total, 1);\n }\n\n /** The last error thrown by the provider, or undefined if the last request succeeded. */\n get error(): unknown {\n return this.#error;\n }\n\n // ---- Control ----\n\n /**\n * Cancel any in-flight request and start a new one.\n * Clears items immediately unless clearOnRequest was set to false.\n */\n request(query: TQuery): void {\n this.cancel();\n\n if (!this.#provider)\n return;\n\n if (this.#opts.clearOnRequest) {\n this.#items = [];\n this.#loaded = 0;\n }\n this.#total = undefined;\n this.#error = undefined;\n this.#loading = true;\n this.#host.requestUpdate();\n\n this.#abort = new AbortController();\n const { signal } = this.#abort;\n\n this.#consume(this.#provider(query, signal), signal);\n }\n\n /** Abort any in-flight request without issuing a new one. */\n cancel(): void {\n this.#abort?.abort();\n this.#abort = undefined;\n if (this.#loading) {\n this.#loading = false;\n this.#host.requestUpdate();\n }\n }\n\n // ---- Internal ----\n\n #consume(result: DataProviderResult<TItem>, signal: AbortSignal): void {\n if (Array.isArray(result)) {\n this.#applyBatch({ items: result }, signal);\n this.#loading = false;\n this.#host.requestUpdate();\n } else if (isAsyncIterable<DataBatch<TItem>>(result)) {\n this.#consumeStream(result, signal);\n } else {\n // Promise (async one-shot)\n (result as Promise<readonly TItem[]>).then(\n (items) => {\n if (signal.aborted)\n return;\n this.#applyBatch({ items }, signal);\n this.#loading = false;\n this.#host.requestUpdate();\n },\n (err: unknown) => {\n if (signal.aborted)\n return;\n this.#handleError(err);\n },\n );\n }\n }\n\n async #consumeStream(stream: AsyncIterable<DataBatch<TItem>>, signal: AbortSignal): Promise<void> {\n try {\n for await (const batch of stream) {\n if (signal.aborted)\n return;\n this.#applyBatch(batch, signal);\n this.#host.requestUpdate();\n }\n } catch (err) {\n if (signal.aborted)\n return;\n this.#handleError(err);\n return;\n }\n if (!signal.aborted) {\n this.#loading = false;\n this.#host.requestUpdate();\n }\n }\n\n #applyBatch(batch: { items: readonly TItem[]; replace?: boolean; total?: number }, _signal: AbortSignal): void {\n if (batch.replace) {\n this.#items = [...batch.items];\n this.#loaded = batch.items.length;\n } else {\n this.#items = [...this.#items, ...batch.items];\n this.#loaded = this.#items.length;\n }\n if (batch.total !== undefined) {\n this.#total = batch.total;\n }\n }\n\n #handleError(err: unknown): void {\n this.#error = err;\n this.#loading = false;\n this.#opts.onError?.(err);\n this.#host.requestUpdate();\n }\n}\n"],"mappings":"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"}
|
package/dist/data-display.d.ts
CHANGED
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
import { LitElement } from "lit";
|
|
2
|
-
|
|
3
2
|
//#region src/data-display/data-display.d.ts
|
|
4
3
|
type RendererStyle = `led` | `plot` | `plot-xy` | `plot-heat` | `plot-histogram` | `time-elapsed` | `hide`;
|
|
5
4
|
type ConfigEntry = readonly [path: string, style: RendererStyle, options?: Record<string, unknown>];
|
|
@@ -25,7 +24,7 @@ declare global {
|
|
|
25
24
|
interface HTMLElementTagNameMap {
|
|
26
25
|
'ixfx-data-display': DataDisplayComponent;
|
|
27
26
|
}
|
|
28
|
-
}
|
|
27
|
+
}
|
|
29
28
|
//#endregion
|
|
30
29
|
export { ConfigEntry, DataDisplayComponent, FormattingOptions, RendererStyle };
|
|
31
30
|
//# sourceMappingURL=data-display.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"data-display.d.ts","names":[],"sources":["../src/data-display/data-display.ts"],"mappings":"
|
|
1
|
+
{"version":3,"file":"data-display.d.ts","names":[],"sources":["../src/data-display/data-display.ts"],"mappings":";;KAOY;KASA,wBACV,cACA,OAAO,eACP,UAAU;KAGA;WACD;WACA;;cAWE,6BAA6B;;SACxB,sBAAM;EAqCtB;EAEA,eAAe;EACf,YAAY;;EAYH;EAKT,UAAU,QAAQ;EAalB,YAAY,YAAY,UAAS;EAqBjC,YAAY,GAAG;EAQf,WAAW,OAAO;EAMlB,YAAY,cAAc,QAAQ,QAAQ,uBAAuB;;QA6V3D;YACI;IACR,qBAAqB"}
|
package/dist/data-display.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { t as themeFallbacks } from "./fallbacks-DEE1nCTt.js";
|
|
2
|
-
import { n as safeCustomElement, t as __decorate } from "./decorate-
|
|
2
|
+
import { n as safeCustomElement, t as __decorate } from "./decorate-VRK8rslU.js";
|
|
3
3
|
import { LitElement, css } from "lit";
|
|
4
4
|
import { property } from "lit/decorators.js";
|
|
5
5
|
import { rangeStream, round } from "@ixfx/numbers";
|
|
@@ -121,15 +121,16 @@ let DataDisplayComponent = class DataDisplayComponent extends LitElement {
|
|
|
121
121
|
}
|
|
122
122
|
continue;
|
|
123
123
|
}
|
|
124
|
-
if (typeof value === `object` && value !== null && !Array.isArray(value))
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
124
|
+
if (typeof value === `object` && value !== null && !Array.isArray(value)) {
|
|
125
|
+
if (this.#hasDescendantConfig(fullPath)) this.#walk(value, fullPath, activePaths);
|
|
126
|
+
else if (this.automap) {
|
|
127
|
+
const row = this.#ensureRow(fullPath, key);
|
|
128
|
+
this.#renderNestedDisplay(row, value, true);
|
|
129
|
+
} else {
|
|
130
|
+
const row = this.#ensureRow(fullPath, key);
|
|
131
|
+
this.#renderNestedDisplay(row, value);
|
|
132
|
+
}
|
|
128
133
|
} else {
|
|
129
|
-
const row = this.#ensureRow(fullPath, key);
|
|
130
|
-
this.#renderNestedDisplay(row, value);
|
|
131
|
-
}
|
|
132
|
-
else {
|
|
133
134
|
const autoStyle = this.#determineAutoStyle(value);
|
|
134
135
|
if (autoStyle !== void 0) {
|
|
135
136
|
const row = this.#ensureRow(fullPath, key);
|
|
@@ -210,13 +211,15 @@ let DataDisplayComponent = class DataDisplayComponent extends LitElement {
|
|
|
210
211
|
case `plot`:
|
|
211
212
|
if (typeof value === `number`) {
|
|
212
213
|
if (changed) el.add(value);
|
|
213
|
-
} else if (typeof value === `object` && value !== null && changed)
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
214
|
+
} else if (typeof value === `object` && value !== null && changed) {
|
|
215
|
+
if (Array.isArray(value)) {
|
|
216
|
+
const record = {};
|
|
217
|
+
value.forEach((v, i) => {
|
|
218
|
+
if (typeof v === `number`) record[String(i)] = v;
|
|
219
|
+
});
|
|
220
|
+
if (Object.keys(record).length > 0) el.addData(record);
|
|
221
|
+
} else el.addData(value);
|
|
222
|
+
}
|
|
220
223
|
this.#applyPlotOptions(el, style, options);
|
|
221
224
|
break;
|
|
222
225
|
case `plot-xy`:
|
|
@@ -228,9 +231,7 @@ let DataDisplayComponent = class DataDisplayComponent extends LitElement {
|
|
|
228
231
|
if (typeof value === `number` && changed) el.add(value);
|
|
229
232
|
this.#applyPlotOptions(el, style, options);
|
|
230
233
|
break;
|
|
231
|
-
case `time-elapsed`:
|
|
232
|
-
el.textContent = this.#formatTimeElapsed(value);
|
|
233
|
-
break;
|
|
234
|
+
case `time-elapsed`: el.textContent = this.#formatTimeElapsed(value);
|
|
234
235
|
}
|
|
235
236
|
this.#previousValues.set(path, value);
|
|
236
237
|
}
|
|
@@ -276,9 +277,10 @@ let DataDisplayComponent = class DataDisplayComponent extends LitElement {
|
|
|
276
277
|
#formatTimeElapsed(value) {
|
|
277
278
|
let timestamp;
|
|
278
279
|
if (value instanceof Date) timestamp = value.getTime();
|
|
279
|
-
else if (typeof value === `number`)
|
|
280
|
-
|
|
281
|
-
|
|
280
|
+
else if (typeof value === `number`) {
|
|
281
|
+
if (value > 0xe8d4a51000) timestamp = value;
|
|
282
|
+
else timestamp = Date.now();
|
|
283
|
+
} else if (typeof value === `string`) timestamp = new Date(value).getTime();
|
|
282
284
|
else return String(value);
|
|
283
285
|
if (Number.isNaN(timestamp)) return String(value);
|
|
284
286
|
const elapsed = Date.now() - timestamp;
|
package/dist/data-display.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"data-display.js","names":["#config","#previousValues","#rangeStreams","#currentData","#renderAll","#walk","#cleanupPaths","#ensureRow","#updateRenderer","#hasDescendantConfig","#renderNestedDisplay","#determineAutoStyle","#renderText","#rendererTag","#getOrCreateRendererElement","#applyValue","#applyLed","#applyPlotOptions","#applyPlotXy","#formatTimeElapsed","customElement"],"sources":["../src/data-display/data-display.ts"],"sourcesContent":["import { rangeStream, round } from \"@ixfx/numbers\";\n\nimport { css, LitElement } from 'lit';\nimport { property } from 'lit/decorators.js';\nimport { themeFallbacks } from '../styles/fallbacks.js';\nimport { safeCustomElement as customElement } from '../util/custom-elements.js';\n\nexport type RendererStyle\n = | `led`\n | `plot`\n | `plot-xy`\n | `plot-heat`\n | `plot-histogram`\n | `time-elapsed`\n | `hide`;\n\nexport type ConfigEntry = readonly [\n path: string,\n style: RendererStyle,\n options?: Record<string, unknown>,\n];\n\nexport type FormattingOptions = {\n readonly precision?: number;\n readonly roundNumbers?: number;\n};\n\ntype ConfigRecord = {\n readonly style: RendererStyle;\n readonly options?: Record<string, unknown>;\n};\n\ntype RangeStream = ReturnType<typeof rangeStream>;\n\n@customElement(`ixfx-data-display`)\nexport class DataDisplayComponent extends LitElement {\n static override styles = [themeFallbacks, css`\n :host {\n display: block;\n width: fit-content;\n }\n section {\n background: var(--surface-3);\n color: var(--surface-2-text);\n border: var(--border);\n padding: var(--space-m);\n font-family: var(--font-mono);\n display: grid;\n grid-template-columns: auto auto;\n column-gap: var(--space-s);\n }\n .row {\n display: contents;\n }\n .row > label {\n font-weight: bold;\n text-align: end;\n justify-self: end;\n padding: 2px 0;\n }\n .row > :not(label) {\n padding: 2px 0;\n }\n .row > ixfx-led {\n align-self: center;\n }\n .value {\n font-variant-numeric: tabular-nums;\n white-space: pre;\n }\n `];\n\n @property({ type: Boolean })\n automap = false;\n\n previousValue: Record<string, unknown> | undefined;\n _container: HTMLElement;\n\n #config = new Map<string, ConfigRecord>();\n #previousValues = new Map<string, unknown>();\n #rangeStreams = new Map<string, RangeStream>();\n #currentData: Record<string, unknown> | undefined;\n\n constructor() {\n super();\n this._container = document.createElement(`section`);\n }\n\n override connectedCallback() {\n super.connectedCallback();\n this.renderRoot.append(this._container);\n }\n\n configure(config: ConfigEntry[]) {\n this.#config.clear();\n for (const [path, style, options] of config) {\n this.#config.set(path, { style, options });\n }\n this._container.innerHTML = ``;\n this.#previousValues.clear();\n this.#rangeStreams.clear();\n if (this.#currentData !== undefined) {\n this.#renderAll(this.#currentData);\n }\n }\n\n formatValue(v: unknown, options: FormattingOptions = {}): string {\n if (v === null)\n return `(null)`;\n if (v === undefined)\n return `(undefined)`;\n if (typeof v === `boolean`)\n return v ? `true` : `false`;\n if (typeof v === `string`)\n return `\"${v}\"`;\n if (typeof v === `number`) {\n let vAsNumber = v;\n if (options.roundNumbers !== undefined)\n vAsNumber = round(options.roundNumbers, v);\n if (options.precision !== undefined)\n return vAsNumber.toFixed(options.precision);\n const formatted = vAsNumber.toFixed(2);\n return vAsNumber >= 0 ? ` ${formatted}` : formatted;\n }\n return JSON.stringify(v);\n }\n\n displayData(o: Record<string, unknown> | unknown[]) {\n if (o === null) {\n this.innerHTML = ``;\n return;\n }\n this.#renderAll(o as Record<string, unknown>);\n }\n\n updateData(value: Record<string, unknown>) {\n this.#currentData = value;\n this.#renderAll(value);\n this.previousValue = value;\n }\n\n getOrCreate(path: string, init?: (parent: HTMLElement) => void): HTMLElement {\n const element = this.renderRoot.querySelector(`#${path}`) as HTMLElement | null;\n if (element !== null)\n return element;\n\n const elementCreated = document.createElement(`div`);\n elementCreated.id = path;\n if (init)\n init(elementCreated);\n this._container.append(elementCreated);\n return elementCreated;\n }\n\n #renderAll(data: Record<string, unknown>) {\n const activePaths = new Set<string>();\n this.#walk(data, ``, activePaths);\n this.#cleanupPaths(activePaths);\n }\n\n #walk(\n data: Record<string, unknown>,\n basePath: string,\n activePaths: Set<string>,\n ) {\n for (const [key, value] of Object.entries(data)) {\n const fullPath = basePath ? `${basePath}.${key}` : key;\n activePaths.add(fullPath);\n\n const config = this.#config.get(fullPath);\n\n if (config !== undefined) {\n if (config.style !== `hide`) {\n const row = this.#ensureRow(fullPath, key);\n this.#updateRenderer(row, fullPath, config.style, value, config.options);\n }\n continue;\n }\n\n if (typeof value === `object` && value !== null && !Array.isArray(value)) {\n if (this.#hasDescendantConfig(fullPath)) {\n this.#walk(value as Record<string, unknown>, fullPath, activePaths);\n } else if (this.automap) {\n const row = this.#ensureRow(fullPath, key);\n this.#renderNestedDisplay(row, value as Record<string, unknown>, true);\n } else {\n const row = this.#ensureRow(fullPath, key);\n this.#renderNestedDisplay(row, value as Record<string, unknown>);\n }\n } else {\n const autoStyle = this.#determineAutoStyle(value);\n if (autoStyle !== undefined) {\n const row = this.#ensureRow(fullPath, key);\n this.#updateRenderer(row, fullPath, autoStyle, value, undefined);\n } else {\n const row = this.#ensureRow(fullPath, key);\n this.#renderText(row, this.formatValue(value));\n }\n }\n }\n }\n\n #hasDescendantConfig(path: string): boolean {\n const prefix = path ? `${path}.` : ``;\n for (const configPath of this.#config.keys()) {\n if (configPath.startsWith(prefix))\n return true;\n }\n return false;\n }\n\n #determineAutoStyle(value: unknown): RendererStyle | undefined {\n if (!this.automap)\n return undefined;\n if (typeof value === `boolean`)\n return `led`;\n if (typeof value === `number`)\n return `plot`;\n return undefined;\n }\n\n #ensureRow(path: string, label: string): HTMLElement {\n const id = `path-${path}`;\n let row = this.renderRoot.querySelector(`#${CSS.escape(id)}`) as HTMLElement | null;\n if (row !== null)\n return row;\n\n row = document.createElement(`div`);\n row.id = id;\n row.classList.add(`row`);\n\n const labelEl = document.createElement(`label`);\n labelEl.textContent = label;\n row.append(labelEl);\n\n this._container.append(row);\n return row;\n }\n\n #updateRenderer(\n row: HTMLElement,\n path: string,\n style: RendererStyle,\n value: unknown,\n options?: Record<string, unknown>,\n ) {\n const tag = this.#rendererTag(style, value);\n if (tag === null)\n return;\n\n const el = this.#getOrCreateRendererElement(row, tag);\n if (el === null)\n return;\n\n this.#applyValue(el, tag, style, path, value, options);\n }\n\n #rendererTag(style: RendererStyle, value: unknown): string | null {\n switch (style) {\n case `hide`:\n return null;\n case `led`:\n return `ixfx-led`;\n case `plot`:\n if (typeof value === `number`)\n return `ixfx-plot-single-axis`;\n if (typeof value === `object` && value !== null)\n return `ixfx-plot-multi-axis`;\n return `span`;\n case `plot-xy`:\n return `ixfx-plot-xy-axis`;\n case `plot-heat`:\n case `plot-histogram`:\n return `ixfx-plot-histogram`;\n case `time-elapsed`:\n return `span`;\n }\n }\n\n #getOrCreateRendererElement(row: HTMLElement, tag: string): HTMLElement | null {\n const existing = row.querySelector(`:scope > [data-renderer]`) as HTMLElement | null;\n if (existing !== null) {\n if (existing.tagName.toLowerCase() === tag)\n return existing;\n existing.remove();\n }\n const el = document.createElement(tag);\n el.dataset.renderer = ``;\n if (tag.startsWith(`ixfx-plot`)) {\n (el as HTMLElement).style.height = `1.4em`;\n if (tag === `ixfx-plot-xy-axis`) {\n (el as HTMLElement).style.width = `1.4em`;\n } else {\n (el as HTMLElement).style.width = `5em`;\n }\n }\n row.append(el);\n return el;\n }\n\n #applyValue(\n el: HTMLElement,\n _tag: string,\n style: RendererStyle,\n path: string,\n value: unknown,\n options?: Record<string, unknown>,\n ) {\n const prev = this.#previousValues.get(path);\n const changed = prev !== value;\n\n switch (style) {\n case `led`:\n this.#applyLed(el, path, value, options);\n break;\n\n case `plot`:\n if (typeof value === `number`) {\n if (changed) {\n (el as any).add(value);\n }\n } else if (typeof value === `object` && value !== null && changed) {\n if (Array.isArray(value)) {\n const record: Record<string, number> = {};\n value.forEach((v: unknown, i: number) => {\n if (typeof v === `number`)\n record[String(i)] = v;\n });\n if (Object.keys(record).length > 0) {\n (el as any).addData(record);\n }\n } else {\n (el as any).addData(value as Record<string, number>);\n }\n }\n this.#applyPlotOptions(el, style, options);\n break;\n\n case `plot-xy`:\n if (changed) {\n this.#applyPlotXy(el, value);\n }\n this.#applyPlotOptions(el, style, options);\n break;\n // @ts-expect-error fallthrough allowed\n case `plot-heat`:\n el.style.setProperty(`--plot-histogram-bar-length`, `1`);\n // falls through\n case `plot-histogram`:\n if (typeof value === `number` && changed) {\n (el as any).add(value);\n }\n this.#applyPlotOptions(el, style, options);\n break;\n\n case `time-elapsed`:\n el.textContent = this.#formatTimeElapsed(value);\n break;\n }\n\n this.#previousValues.set(path, value);\n }\n\n #applyLed(el: HTMLElement, path: string, value: unknown, options?: Record<string, unknown>) {\n const led = el as any;\n\n if (typeof value === `boolean`) {\n led.lit = value;\n led.value = value ? 1 : 0;\n } else if (typeof value === `number`) {\n let rs = this.#rangeStreams.get(path);\n if (rs === undefined) {\n rs = rangeStream();\n this.#rangeStreams.set(path, rs);\n }\n const range = rs.seen(value);\n const normalized = range.max !== range.min\n ? (value - range.min) / (range.max - range.min)\n : 0.5;\n led.value = normalized;\n led.lit = normalized > 0.3;\n }\n\n if (options?.color !== undefined)\n led.color = options.color;\n }\n\n #applyPlotXy(el: HTMLElement, value: unknown) {\n const xy = el as any;\n\n if (Array.isArray(value) && value.length >= 2) {\n xy.add(value[0], value[1]);\n } else if (typeof value === `object` && value !== null) {\n const obj = value as Record<string, number>;\n if (`x` in obj && `y` in obj) {\n xy.add(obj.x, obj.y);\n } else {\n const entries = Object.entries(obj).filter(([_, v]) => typeof v === `number`);\n if (entries.length >= 2) {\n xy.add(entries[0][1], entries[1][1]);\n }\n }\n }\n }\n\n #applyPlotOptions(el: HTMLElement, _style: RendererStyle, options?: Record<string, unknown>) {\n if (options === undefined)\n return;\n\n const target = el as any;\n\n if (typeof options.capacity === `number`)\n target.capacity = options.capacity;\n if (typeof options.resolution === `number`)\n target.resolution = options.resolution;\n if (typeof options.drawStyle === `string`)\n target.drawStyle = options.drawStyle;\n if (typeof options.orientation === `string`)\n target.orientation = options.orientation;\n if (typeof options.layout === `string`)\n target.layout = options.layout;\n }\n\n #formatTimeElapsed(value: unknown): string {\n let timestamp: number;\n\n if (value instanceof Date) {\n timestamp = value.getTime();\n } else if (typeof value === `number`) {\n if (value > 1e12) {\n timestamp = value;\n } else {\n timestamp = Date.now();\n }\n } else if (typeof value === `string`) {\n timestamp = new Date(value).getTime();\n } else {\n return String(value);\n }\n\n if (Number.isNaN(timestamp))\n return String(value);\n\n const elapsed = Date.now() - timestamp;\n const abs = Math.abs(elapsed);\n\n if (abs < 1000)\n return `${abs}ms`;\n if (abs < 60000)\n return `${(abs / 1000).toFixed(1)}s`;\n if (abs < 3600000)\n return `${(abs / 60000).toFixed(1)}mins`;\n if (abs < 86400000)\n return `${(abs / 3600000).toFixed(1)}h`;\n return `${(abs / 86400000).toFixed(1)}d`;\n }\n\n #renderText(row: HTMLElement, text: string) {\n let valueEl = row.querySelector(`:scope > .value`) as HTMLElement | null;\n if (valueEl === null) {\n valueEl = document.createElement(`span`);\n valueEl.classList.add(`value`);\n row.append(valueEl);\n }\n valueEl.textContent = text;\n }\n\n #renderNestedDisplay(row: HTMLElement, data: Record<string, unknown>, automapChild = false) {\n let child = row.querySelector(`:scope > ixfx-data-display`) as DataDisplayComponent | null;\n if (child === null) {\n child = document.createElement(`ixfx-data-display`) as DataDisplayComponent;\n row.append(child);\n }\n child.automap = automapChild;\n child.updateData(data);\n }\n\n #cleanupPaths(activePaths: Set<string>) {\n const rows = this._container.querySelectorAll<HTMLElement>(`[id^=\"path-\"]`);\n for (const row of rows) {\n const path = row.id.slice(5);\n if (!activePaths.has(path)) {\n row.remove();\n this.#rangeStreams.delete(path);\n this.#previousValues.delete(path);\n }\n }\n }\n}\n\ndeclare global {\n interface HTMLElementTagNameMap {\n 'ixfx-data-display': DataDisplayComponent;\n }\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"data-display.js","names":["#config","#previousValues","#rangeStreams","#currentData","#renderAll","#walk","#cleanupPaths","#ensureRow","#updateRenderer","#hasDescendantConfig","#renderNestedDisplay","#determineAutoStyle","#renderText","#rendererTag","#getOrCreateRendererElement","#applyValue","#applyLed","#applyPlotOptions","#applyPlotXy","#formatTimeElapsed","customElement"],"sources":["../src/data-display/data-display.ts"],"sourcesContent":["import { rangeStream, round } from \"@ixfx/numbers\";\n\nimport { css, LitElement } from 'lit';\nimport { property } from 'lit/decorators.js';\nimport { themeFallbacks } from '../styles/fallbacks.js';\nimport { safeCustomElement as customElement } from '../util/custom-elements.js';\n\nexport type RendererStyle\n = | `led`\n | `plot`\n | `plot-xy`\n | `plot-heat`\n | `plot-histogram`\n | `time-elapsed`\n | `hide`;\n\nexport type ConfigEntry = readonly [\n path: string,\n style: RendererStyle,\n options?: Record<string, unknown>,\n];\n\nexport type FormattingOptions = {\n readonly precision?: number;\n readonly roundNumbers?: number;\n};\n\ntype ConfigRecord = {\n readonly style: RendererStyle;\n readonly options?: Record<string, unknown>;\n};\n\ntype RangeStream = ReturnType<typeof rangeStream>;\n\n@customElement(`ixfx-data-display`)\nexport class DataDisplayComponent extends LitElement {\n static override styles = [themeFallbacks, css`\n :host {\n display: block;\n width: fit-content;\n }\n section {\n background: var(--surface-3);\n color: var(--surface-2-text);\n border: var(--border);\n padding: var(--space-m);\n font-family: var(--font-mono);\n display: grid;\n grid-template-columns: auto auto;\n column-gap: var(--space-s);\n }\n .row {\n display: contents;\n }\n .row > label {\n font-weight: bold;\n text-align: end;\n justify-self: end;\n padding: 2px 0;\n }\n .row > :not(label) {\n padding: 2px 0;\n }\n .row > ixfx-led {\n align-self: center;\n }\n .value {\n font-variant-numeric: tabular-nums;\n white-space: pre;\n }\n `];\n\n @property({ type: Boolean })\n automap = false;\n\n previousValue: Record<string, unknown> | undefined;\n _container: HTMLElement;\n\n #config = new Map<string, ConfigRecord>();\n #previousValues = new Map<string, unknown>();\n #rangeStreams = new Map<string, RangeStream>();\n #currentData: Record<string, unknown> | undefined;\n\n constructor() {\n super();\n this._container = document.createElement(`section`);\n }\n\n override connectedCallback() {\n super.connectedCallback();\n this.renderRoot.append(this._container);\n }\n\n configure(config: ConfigEntry[]) {\n this.#config.clear();\n for (const [path, style, options] of config) {\n this.#config.set(path, { style, options });\n }\n this._container.innerHTML = ``;\n this.#previousValues.clear();\n this.#rangeStreams.clear();\n if (this.#currentData !== undefined) {\n this.#renderAll(this.#currentData);\n }\n }\n\n formatValue(v: unknown, options: FormattingOptions = {}): string {\n if (v === null)\n return `(null)`;\n if (v === undefined)\n return `(undefined)`;\n if (typeof v === `boolean`)\n return v ? `true` : `false`;\n if (typeof v === `string`)\n return `\"${v}\"`;\n if (typeof v === `number`) {\n let vAsNumber = v;\n if (options.roundNumbers !== undefined)\n vAsNumber = round(options.roundNumbers, v);\n if (options.precision !== undefined)\n return vAsNumber.toFixed(options.precision);\n const formatted = vAsNumber.toFixed(2);\n return vAsNumber >= 0 ? ` ${formatted}` : formatted;\n }\n return JSON.stringify(v);\n }\n\n displayData(o: Record<string, unknown> | unknown[]) {\n if (o === null) {\n this.innerHTML = ``;\n return;\n }\n this.#renderAll(o as Record<string, unknown>);\n }\n\n updateData(value: Record<string, unknown>) {\n this.#currentData = value;\n this.#renderAll(value);\n this.previousValue = value;\n }\n\n getOrCreate(path: string, init?: (parent: HTMLElement) => void): HTMLElement {\n const element = this.renderRoot.querySelector(`#${path}`) as HTMLElement | null;\n if (element !== null)\n return element;\n\n const elementCreated = document.createElement(`div`);\n elementCreated.id = path;\n if (init)\n init(elementCreated);\n this._container.append(elementCreated);\n return elementCreated;\n }\n\n #renderAll(data: Record<string, unknown>) {\n const activePaths = new Set<string>();\n this.#walk(data, ``, activePaths);\n this.#cleanupPaths(activePaths);\n }\n\n #walk(\n data: Record<string, unknown>,\n basePath: string,\n activePaths: Set<string>,\n ) {\n for (const [key, value] of Object.entries(data)) {\n const fullPath = basePath ? `${basePath}.${key}` : key;\n activePaths.add(fullPath);\n\n const config = this.#config.get(fullPath);\n\n if (config !== undefined) {\n if (config.style !== `hide`) {\n const row = this.#ensureRow(fullPath, key);\n this.#updateRenderer(row, fullPath, config.style, value, config.options);\n }\n continue;\n }\n\n if (typeof value === `object` && value !== null && !Array.isArray(value)) {\n if (this.#hasDescendantConfig(fullPath)) {\n this.#walk(value as Record<string, unknown>, fullPath, activePaths);\n } else if (this.automap) {\n const row = this.#ensureRow(fullPath, key);\n this.#renderNestedDisplay(row, value as Record<string, unknown>, true);\n } else {\n const row = this.#ensureRow(fullPath, key);\n this.#renderNestedDisplay(row, value as Record<string, unknown>);\n }\n } else {\n const autoStyle = this.#determineAutoStyle(value);\n if (autoStyle !== undefined) {\n const row = this.#ensureRow(fullPath, key);\n this.#updateRenderer(row, fullPath, autoStyle, value, undefined);\n } else {\n const row = this.#ensureRow(fullPath, key);\n this.#renderText(row, this.formatValue(value));\n }\n }\n }\n }\n\n #hasDescendantConfig(path: string): boolean {\n const prefix = path ? `${path}.` : ``;\n for (const configPath of this.#config.keys()) {\n if (configPath.startsWith(prefix))\n return true;\n }\n return false;\n }\n\n #determineAutoStyle(value: unknown): RendererStyle | undefined {\n if (!this.automap)\n return undefined;\n if (typeof value === `boolean`)\n return `led`;\n if (typeof value === `number`)\n return `plot`;\n return undefined;\n }\n\n #ensureRow(path: string, label: string): HTMLElement {\n const id = `path-${path}`;\n let row = this.renderRoot.querySelector(`#${CSS.escape(id)}`) as HTMLElement | null;\n if (row !== null)\n return row;\n\n row = document.createElement(`div`);\n row.id = id;\n row.classList.add(`row`);\n\n const labelEl = document.createElement(`label`);\n labelEl.textContent = label;\n row.append(labelEl);\n\n this._container.append(row);\n return row;\n }\n\n #updateRenderer(\n row: HTMLElement,\n path: string,\n style: RendererStyle,\n value: unknown,\n options?: Record<string, unknown>,\n ) {\n const tag = this.#rendererTag(style, value);\n if (tag === null)\n return;\n\n const el = this.#getOrCreateRendererElement(row, tag);\n if (el === null)\n return;\n\n this.#applyValue(el, tag, style, path, value, options);\n }\n\n #rendererTag(style: RendererStyle, value: unknown): string | null {\n switch (style) {\n case `hide`:\n return null;\n case `led`:\n return `ixfx-led`;\n case `plot`:\n if (typeof value === `number`)\n return `ixfx-plot-single-axis`;\n if (typeof value === `object` && value !== null)\n return `ixfx-plot-multi-axis`;\n return `span`;\n case `plot-xy`:\n return `ixfx-plot-xy-axis`;\n case `plot-heat`:\n case `plot-histogram`:\n return `ixfx-plot-histogram`;\n case `time-elapsed`:\n return `span`;\n }\n }\n\n #getOrCreateRendererElement(row: HTMLElement, tag: string): HTMLElement | null {\n const existing = row.querySelector(`:scope > [data-renderer]`) as HTMLElement | null;\n if (existing !== null) {\n if (existing.tagName.toLowerCase() === tag)\n return existing;\n existing.remove();\n }\n const el = document.createElement(tag);\n el.dataset.renderer = ``;\n if (tag.startsWith(`ixfx-plot`)) {\n (el as HTMLElement).style.height = `1.4em`;\n if (tag === `ixfx-plot-xy-axis`) {\n (el as HTMLElement).style.width = `1.4em`;\n } else {\n (el as HTMLElement).style.width = `5em`;\n }\n }\n row.append(el);\n return el;\n }\n\n #applyValue(\n el: HTMLElement,\n _tag: string,\n style: RendererStyle,\n path: string,\n value: unknown,\n options?: Record<string, unknown>,\n ) {\n const prev = this.#previousValues.get(path);\n const changed = prev !== value;\n\n switch (style) {\n case `led`:\n this.#applyLed(el, path, value, options);\n break;\n\n case `plot`:\n if (typeof value === `number`) {\n if (changed) {\n (el as any).add(value);\n }\n } else if (typeof value === `object` && value !== null && changed) {\n if (Array.isArray(value)) {\n const record: Record<string, number> = {};\n value.forEach((v: unknown, i: number) => {\n if (typeof v === `number`)\n record[String(i)] = v;\n });\n if (Object.keys(record).length > 0) {\n (el as any).addData(record);\n }\n } else {\n (el as any).addData(value as Record<string, number>);\n }\n }\n this.#applyPlotOptions(el, style, options);\n break;\n\n case `plot-xy`:\n if (changed) {\n this.#applyPlotXy(el, value);\n }\n this.#applyPlotOptions(el, style, options);\n break;\n // @ts-expect-error fallthrough allowed\n case `plot-heat`:\n el.style.setProperty(`--plot-histogram-bar-length`, `1`);\n // falls through\n case `plot-histogram`:\n if (typeof value === `number` && changed) {\n (el as any).add(value);\n }\n this.#applyPlotOptions(el, style, options);\n break;\n\n case `time-elapsed`:\n el.textContent = this.#formatTimeElapsed(value);\n break;\n }\n\n this.#previousValues.set(path, value);\n }\n\n #applyLed(el: HTMLElement, path: string, value: unknown, options?: Record<string, unknown>) {\n const led = el as any;\n\n if (typeof value === `boolean`) {\n led.lit = value;\n led.value = value ? 1 : 0;\n } else if (typeof value === `number`) {\n let rs = this.#rangeStreams.get(path);\n if (rs === undefined) {\n rs = rangeStream();\n this.#rangeStreams.set(path, rs);\n }\n const range = rs.seen(value);\n const normalized = range.max !== range.min\n ? (value - range.min) / (range.max - range.min)\n : 0.5;\n led.value = normalized;\n led.lit = normalized > 0.3;\n }\n\n if (options?.color !== undefined)\n led.color = options.color;\n }\n\n #applyPlotXy(el: HTMLElement, value: unknown) {\n const xy = el as any;\n\n if (Array.isArray(value) && value.length >= 2) {\n xy.add(value[0], value[1]);\n } else if (typeof value === `object` && value !== null) {\n const obj = value as Record<string, number>;\n if (`x` in obj && `y` in obj) {\n xy.add(obj.x, obj.y);\n } else {\n const entries = Object.entries(obj).filter(([_, v]) => typeof v === `number`);\n if (entries.length >= 2) {\n xy.add(entries[0][1], entries[1][1]);\n }\n }\n }\n }\n\n #applyPlotOptions(el: HTMLElement, _style: RendererStyle, options?: Record<string, unknown>) {\n if (options === undefined)\n return;\n\n const target = el as any;\n\n if (typeof options.capacity === `number`)\n target.capacity = options.capacity;\n if (typeof options.resolution === `number`)\n target.resolution = options.resolution;\n if (typeof options.drawStyle === `string`)\n target.drawStyle = options.drawStyle;\n if (typeof options.orientation === `string`)\n target.orientation = options.orientation;\n if (typeof options.layout === `string`)\n target.layout = options.layout;\n }\n\n #formatTimeElapsed(value: unknown): string {\n let timestamp: number;\n\n if (value instanceof Date) {\n timestamp = value.getTime();\n } else if (typeof value === `number`) {\n if (value > 1e12) {\n timestamp = value;\n } else {\n timestamp = Date.now();\n }\n } else if (typeof value === `string`) {\n timestamp = new Date(value).getTime();\n } else {\n return String(value);\n }\n\n if (Number.isNaN(timestamp))\n return String(value);\n\n const elapsed = Date.now() - timestamp;\n const abs = Math.abs(elapsed);\n\n if (abs < 1000)\n return `${abs}ms`;\n if (abs < 60000)\n return `${(abs / 1000).toFixed(1)}s`;\n if (abs < 3600000)\n return `${(abs / 60000).toFixed(1)}mins`;\n if (abs < 86400000)\n return `${(abs / 3600000).toFixed(1)}h`;\n return `${(abs / 86400000).toFixed(1)}d`;\n }\n\n #renderText(row: HTMLElement, text: string) {\n let valueEl = row.querySelector(`:scope > .value`) as HTMLElement | null;\n if (valueEl === null) {\n valueEl = document.createElement(`span`);\n valueEl.classList.add(`value`);\n row.append(valueEl);\n }\n valueEl.textContent = text;\n }\n\n #renderNestedDisplay(row: HTMLElement, data: Record<string, unknown>, automapChild = false) {\n let child = row.querySelector(`:scope > ixfx-data-display`) as DataDisplayComponent | null;\n if (child === null) {\n child = document.createElement(`ixfx-data-display`) as DataDisplayComponent;\n row.append(child);\n }\n child.automap = automapChild;\n child.updateData(data);\n }\n\n #cleanupPaths(activePaths: Set<string>) {\n const rows = this._container.querySelectorAll<HTMLElement>(`[id^=\"path-\"]`);\n for (const row of rows) {\n const path = row.id.slice(5);\n if (!activePaths.has(path)) {\n row.remove();\n this.#rangeStreams.delete(path);\n this.#previousValues.delete(path);\n }\n }\n }\n}\n\ndeclare global {\n interface HTMLElementTagNameMap {\n 'ixfx-data-display': DataDisplayComponent;\n }\n}\n"],"mappings":"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"}
|