@ixfx/components 0.18.0 → 0.18.1

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.
Files changed (69) hide show
  1. package/bundle/index.d.ts +209 -4
  2. package/bundle/index.js +359 -319
  3. package/dist/ac-text.js +1 -1
  4. package/dist/ac-token.js +2 -2
  5. package/dist/{checked-select-DsQ-o9lI.js → checked-select-CC-qSO1P.js} +2 -2
  6. package/dist/checked-select.js +1 -1
  7. package/dist/{crumb-navigation-09YFje6W.js → crumb-navigation-C78edQGt.js} +3 -3
  8. package/dist/crumbs.js +1 -1
  9. package/dist/{data-grid-BQWmVYg0.d.ts → data-grid-BYMZZbNc.d.ts} +25 -2
  10. package/dist/{data-grid-BGmJbMCb.js → data-grid-CJrbLzLr.js} +79 -18
  11. package/dist/data-grid.d.ts +1 -1
  12. package/dist/data-grid.js +1 -1
  13. package/dist/{detail-list-CfjoIl2N.d.ts → detail-list-CBgnKkEm.d.ts} +29 -3
  14. package/dist/{detail-list-CrHASoAx.js → detail-list-Dk9oSvAZ.js} +74 -10
  15. package/dist/detail-list.d.ts +2 -2
  16. package/dist/detail-list.js +1 -1
  17. package/dist/{flat-list-C2z81bK6.d.ts → flat-list-D5glF_vD.d.ts} +1 -1
  18. package/dist/flat-list.d.ts +1 -1
  19. package/dist/flat-list.js +3 -3
  20. package/dist/{grid-list-DYU_z2K9.js → grid-list-0wC2xGBS.js} +103 -14
  21. package/dist/{grid-list-Crv-hFJL.d.ts → grid-list-B3T_2N0N.d.ts} +26 -2
  22. package/dist/grid-list.d.ts +1 -1
  23. package/dist/grid-list.js +1 -1
  24. package/dist/{incr-search-C5114RxZ.js → incr-search-Bk4acsCM.js} +14 -6
  25. package/dist/incr-search.d.ts +1 -1
  26. package/dist/incr-search.js +1 -1
  27. package/dist/{index-BymYKGY-.d.ts → index-BIv_Hu7C.d.ts} +2 -2
  28. package/dist/{index-Db5VGFR1.d.ts → index-BuvySJEc.d.ts} +4 -0
  29. package/dist/{index-BE0hk8xS.d.ts → index-fhZCKSY6.d.ts} +2 -2
  30. package/dist/index.d.ts +63 -17
  31. package/dist/index.js +200 -37
  32. package/dist/interaction-DNuFnTm0.js +3 -0
  33. package/dist/item-tags-Dz-jQq-4.d.ts +65 -0
  34. package/dist/{list-native-drag-controller-Brk30s5d.js → list-native-drag-controller-B_INa6_G.js} +106 -1
  35. package/dist/{menu-B6NFqEtm.js → menu-CgT60B3-.js} +2 -2
  36. package/dist/{menu-item-D0zy1yax.js → menu-item-CbywH4Xo.js} +2 -2
  37. package/dist/menu.js +2 -2
  38. package/dist/{miller-B0qbnWwe.js → miller-Dyv4UM7k.js} +3 -3
  39. package/dist/miller.d.ts +1 -1
  40. package/dist/miller.js +1 -1
  41. package/dist/narrowed-text.js +3 -3
  42. package/dist/{node-graph-D9iovxQp.js → node-graph-yrbOLbYo.js} +1 -1
  43. package/dist/node-graph.js +1 -1
  44. package/dist/select-horiz.js +2 -2
  45. package/dist/sunburst-tree.d.ts +1 -1
  46. package/dist/sunburst-tree.js +1 -1
  47. package/dist/{sunbursttree-list-C-FuZB5z.js → sunbursttree-list-CJdznPzN.js} +2 -2
  48. package/dist/{sunbursttree-list-XF7gBKod.d.ts → sunbursttree-list-CmydFG66.d.ts} +1 -1
  49. package/dist/{tickled-controller-BVhGKzjZ.js → tickled-controller-BsFFr_1N.js} +1 -1
  50. package/dist/{tickled-controller-DSPoG551.d.ts → tickled-controller-Dz0UqwlQ.d.ts} +5 -0
  51. package/dist/{tree-1CSNgw72.js → tree-C3rgEEmm.js} +4 -4
  52. package/dist/tree.d.ts +1 -1
  53. package/dist/tree.js +1 -1
  54. package/dist/{vertical-list-BNCRA_zy.js → vertical-list-By-yuhkw.js} +60 -6
  55. package/dist/{vertical-list-Dyc5azxv.d.ts → vertical-list-C4z3La0C.d.ts} +20 -2
  56. package/dist/vertical-list.d.ts +1 -1
  57. package/dist/vertical-list.js +1 -1
  58. package/docs-user/README.md +1 -0
  59. package/docs-user/button.md +31 -1
  60. package/docs-user/data-grid.md +3 -0
  61. package/docs-user/detail-list.md +3 -0
  62. package/docs-user/grid-list.md +3 -0
  63. package/docs-user/index.json +6 -2
  64. package/docs-user/llms.txt +1 -0
  65. package/docs-user/multicol-list.md +3 -0
  66. package/docs-user/user-item-tags.md +68 -0
  67. package/llms.txt +1 -0
  68. package/package.json +1 -1
  69. package/dist/interaction-BEcBIY0d.js +0 -3
@@ -1,8 +1,8 @@
1
1
  import { t as __exportAll } from "./rolldown-runtime-D3KUYPsf.js";
2
2
  import { t as tickledItemStyles } from "./tickled-styles-pnieYweS.js";
3
3
  import { n as safeCustomElement, t as __decorate } from "./decorate-Dxs8sFX8.js";
4
- import { n as MenuTrigger, r as MenuContainer, t as MenuItem } from "./menu-item-D0zy1yax.js";
5
- import "./interaction-BEcBIY0d.js";
4
+ import { n as MenuTrigger, r as MenuContainer, t as MenuItem } from "./menu-item-CbywH4Xo.js";
5
+ import "./interaction-DNuFnTm0.js";
6
6
  import { t as themeFallbacks } from "./fallbacks-BPjjBoED.js";
7
7
  import "./icon-DvTQuylG.js";
8
8
  import { LitElement, css, html, nothing } from "lit";
@@ -1,10 +1,10 @@
1
- import { t as TickledController } from "./tickled-controller-BVhGKzjZ.js";
1
+ import { t as TickledController } from "./tickled-controller-BsFFr_1N.js";
2
2
  import { n as tickledStyles, t as tickledItemStyles } from "./tickled-styles-pnieYweS.js";
3
3
  import { t as themeFallbacks } from "./fallbacks-BPjjBoED.js";
4
4
  import { t as popupSurfaceStyles } from "./popup-D8IxN1Eq.js";
5
5
  import { n as safeCustomElement, t as __decorate } from "./decorate-Dxs8sFX8.js";
6
6
  import "./icon-DvTQuylG.js";
7
- import "./interaction-BEcBIY0d.js";
7
+ import "./interaction-DNuFnTm0.js";
8
8
  import { t as scrollFadeStyles } from "./scroll-fade-DH8OXSqL.js";
9
9
  import { LitElement, css, html } from "lit";
10
10
  import { property, query, state } from "lit/decorators.js";
package/dist/menu.js CHANGED
@@ -1,3 +1,3 @@
1
- import { n as MenuTrigger, r as MenuContainer, t as MenuItem } from "./menu-item-D0zy1yax.js";
2
- import { a as menuFromTreeToElements, c as MenuSubTrigger, d as MenuBar, i as menuFromTree, l as MenuCommandController, n as MenuRadioGroup, o as MenuHeader, r as MenuRadioItem, s as MenuSeparator, u as MenuCheckItem } from "./menu-B6NFqEtm.js";
1
+ import { n as MenuTrigger, r as MenuContainer, t as MenuItem } from "./menu-item-CbywH4Xo.js";
2
+ import { a as menuFromTreeToElements, c as MenuSubTrigger, d as MenuBar, i as menuFromTree, l as MenuCommandController, n as MenuRadioGroup, o as MenuHeader, r as MenuRadioItem, s as MenuSeparator, u as MenuCheckItem } from "./menu-CgT60B3-.js";
3
3
  export { MenuBar, MenuCheckItem, MenuCommandController, MenuContainer, MenuHeader, MenuItem, MenuRadioGroup, MenuRadioItem, MenuSeparator, MenuSubTrigger, MenuTrigger, menuFromTree, menuFromTreeToElements };
@@ -1,14 +1,14 @@
1
1
  import { t as collectDataResult } from "./data-provider-C6ZNAcaT.js";
2
- import { i as ListSearchController, n as listSearchStyles, o as registerListSearchCommands, r as LIST_SEARCH_MODES, t as createTreeListSearchAdapter } from "./incr-search-C5114RxZ.js";
2
+ import { i as ListSearchController, n as listSearchStyles, o as registerListSearchCommands, r as LIST_SEARCH_MODES, t as createTreeListSearchAdapter } from "./incr-search-Bk4acsCM.js";
3
3
  import { i as sameKeySet, r as isPartialKey, t as PARTIAL_DESCRIPTION } from "./partial-keys-D4l_ede_.js";
4
- import { t as TickledController } from "./tickled-controller-BVhGKzjZ.js";
4
+ import { t as TickledController } from "./tickled-controller-BsFFr_1N.js";
5
5
  import { n as tickledStyles, t as tickledItemStyles } from "./tickled-styles-pnieYweS.js";
6
6
  import { a as capKeys, d as partitionKeys, l as keysToArray, n as EMPTY_KEYS } from "./pending-Afl4LT64.js";
7
7
  import { t as themeFallbacks } from "./fallbacks-BPjjBoED.js";
8
8
  import { n as safeCustomElement, t as __decorate } from "./decorate-Dxs8sFX8.js";
9
9
  import { n as appearanceColor, t as appearanceAbsent } from "./item-appearance-FRO3TRFI.js";
10
10
  import { a as restoreElementScroll, i as onUserScrollIntent, o as scrollToOffset, r as captureElementScroll, t as ViewStateController } from "./view-state-controller-DiPAPiA7.js";
11
- import "./interaction-BEcBIY0d.js";
11
+ import "./interaction-DNuFnTm0.js";
12
12
  import { LitElement, css, html, nothing } from "lit";
13
13
  import { property, state } from "lit/decorators.js";
14
14
  import { createCommandRegistry } from "@clinth/ui-commands";
package/dist/miller.d.ts CHANGED
@@ -1,4 +1,4 @@
1
1
  import { A as TreeTickleDetail, O as TreeSelectDetail, b as TreeItemClickDetail, i as TreeCollapseEvent, j as TreeTickleEvent, k as TreeSelectEvent, n as TreeActivateEvent, r as TreeCollapseDetail, t as TreeActivateDetail, v as TreeExpandDetail, x as TreeItemClickEvent, y as TreeExpandEvent } from "./tree-component-BE7OEIiH.js";
2
2
  import { a as TreeItem, o as TreeNode } from "./types-6hpXRKt7.js";
3
- import { _ as MillerRebaseEvent, a as MillerBaseElementEventMap, c as MillerHeaderClickEvent, d as MillerItemDblClickDetail, f as MillerItemDblClickEvent, g as MillerRebaseDetail, h as MillerItemState, i as MillerBaseElement, l as MillerHeaderRightClickDetail, m as MillerItemRightClickEvent, n as MillerTreeControllerOptions, o as MillerListViewState, p as MillerItemRightClickDetail, r as MillerListElement, s as MillerHeaderClickDetail, t as MillerTreeController, u as MillerHeaderRightClickEvent, v as MillerSelectionMode } from "./index-BE0hk8xS.js";
3
+ import { _ as MillerRebaseEvent, a as MillerBaseElementEventMap, c as MillerHeaderClickEvent, d as MillerItemDblClickDetail, f as MillerItemDblClickEvent, g as MillerRebaseDetail, h as MillerItemState, i as MillerBaseElement, l as MillerHeaderRightClickDetail, m as MillerItemRightClickEvent, n as MillerTreeControllerOptions, o as MillerListViewState, p as MillerItemRightClickDetail, r as MillerListElement, s as MillerHeaderClickDetail, t as MillerTreeController, u as MillerHeaderRightClickEvent, v as MillerSelectionMode } from "./index-fhZCKSY6.js";
4
4
  export { type TreeActivateDetail as MillerActivateDetail, type TreeActivateEvent as MillerActivateEvent, MillerBaseElement, MillerBaseElementEventMap, type TreeCollapseDetail as MillerCollapseDetail, type TreeCollapseEvent as MillerCollapseEvent, type TreeExpandDetail as MillerExpandDetail, type TreeExpandEvent as MillerExpandEvent, MillerHeaderClickDetail, MillerHeaderClickEvent, MillerHeaderRightClickDetail, MillerHeaderRightClickEvent, type TreeItem as MillerItem, type TreeItemClickDetail as MillerItemClickDetail, type TreeItemClickEvent as MillerItemClickEvent, MillerItemDblClickDetail, MillerItemDblClickEvent, MillerItemRightClickDetail, MillerItemRightClickEvent, MillerItemState, MillerListElement, type MillerListViewState, type TreeNode as MillerNode, MillerRebaseDetail, MillerRebaseEvent, type TreeSelectDetail as MillerSelectDetail, type TreeSelectEvent as MillerSelectEvent, MillerSelectionMode, type TreeTickleDetail as MillerTickleDetail, type TreeTickleEvent as MillerTickleEvent, MillerTreeController, MillerTreeControllerOptions };
package/dist/miller.js CHANGED
@@ -1 +1 @@
1
- export { r as MillerBaseElement, n as MillerListElement, t as MillerTreeController } from "./miller-B0qbnWwe.js";
1
+ export { r as MillerBaseElement, n as MillerListElement, t as MillerTreeController } from "./miller-Dyv4UM7k.js";
@@ -1,8 +1,8 @@
1
1
  import { n as buildHighlightTargets, r as clearHighlights, t as applyHighlights } from "./highlight-noLHFSKZ.js";
2
- import { t as TickledController } from "./tickled-controller-BVhGKzjZ.js";
2
+ import { t as TickledController } from "./tickled-controller-BsFFr_1N.js";
3
3
  import { n as tickledStyles, t as tickledItemStyles } from "./tickled-styles-pnieYweS.js";
4
- import { m as createIncrSearch } from "./incr-search-C5114RxZ.js";
5
- import "./interaction-BEcBIY0d.js";
4
+ import { m as createIncrSearch } from "./incr-search-Bk4acsCM.js";
5
+ import "./interaction-DNuFnTm0.js";
6
6
  import { t as themeFallbacks } from "./fallbacks-BPjjBoED.js";
7
7
  import { n as safeCustomElement, t as __decorate } from "./decorate-Dxs8sFX8.js";
8
8
  import { LitElement, css, html, nothing } from "lit";
@@ -2,7 +2,7 @@ import { n as safeCustomElement, t as __decorate } from "./decorate-Dxs8sFX8.js"
2
2
  import { t as themeFallbacks } from "./fallbacks-BPjjBoED.js";
3
3
  import { t as handleStyles } from "./handle-BVUWv97X.js";
4
4
  import "./icon-DvTQuylG.js";
5
- import "./menu-item-D0zy1yax.js";
5
+ import "./menu-item-CbywH4Xo.js";
6
6
  import { t as ViewStateController } from "./view-state-controller-DiPAPiA7.js";
7
7
  import { LitElement, css, html, nothing, svg } from "lit";
8
8
  import { property, state } from "lit/decorators.js";
@@ -1 +1 @@
1
- export { Y as DEFAULT_FORCE_OPTIONS, T as DRAG_THRESHOLD_PX, dt as EASY_CONNECT_MARGIN, tt as EDGE_CORNER_RADIUS, z as GraphNodeElement, K as GraphPortElement, D as MARQUEE_THRESHOLD_PX, q as MAX_BLINK_HZ, u as MAX_FLOW_SPEED, O as MarqueeController, B as NODE_SHAPES, E as NodeDragController, t as NodeGraphElement, m as PanZoomController, U as RESIZE_HANDLES, r as WireDragController, bt as addWire, J as blinkPeriodSeconds, g as boundsOf, ht as canConnect, _ as clampZoom, c as collapsedOffset, k as combineSelection, xt as connectContext, St as cycleBlockedNodes, nt as defaultSide, Ct as edgeId, rt as edgeMidpoint, it as edgePath, at as edgeShape, wt as ensurePort, ot as extendFromSide, o as findProximityConnection, F as findSnapTarget, gt as findValidWire, v as fitBounds, y as fitRects, b as flowToScreen, X as forceMovement, Z as forcePin, Q as forcePositions, $ as forceState, et as forceStep, Tt as fromEdges, Et as hasWire, Dt as inDegreeOf, ft as inEasyConnectZone, Ot as incomingEdge, kt as incomingEdges, h as isEditableTarget, V as isNodeShape, W as isResizeHandle, A as marqueeStyle, l as measureNode, w as nodeGraphStyles, j as nodesInRect, _t as normaliseConnection, At as outDegreeOf, x as panBy, jt as parsePortId, pt as pickStartPort, st as polylineMidpoint, ct as polylinePath, lt as polylineShape, Mt as portId, I as proximityFactor, M as rectFromPoints, s as rectGap, N as rectsIntersect, Nt as removeNode, mt as removeNodes, Pt as removeWire, n as renderWires, G as resizeRect, vt as resolveConnection, d as sanitizeFlowSpeed, S as screenToFlow, i as selectionAfterEdgeClick, a as selectionAfterNodePress, L as settled, H as shapeSpec, R as smoothStep, ut as stepPoints, Ft as toEdges, It as toNodeGraph, yt as typesCompatible, P as wantsMarquee, f as withEntry, p as withWireFlow, C as zoomAt } from "./node-graph-D9iovxQp.js";
1
+ export { Y as DEFAULT_FORCE_OPTIONS, T as DRAG_THRESHOLD_PX, dt as EASY_CONNECT_MARGIN, tt as EDGE_CORNER_RADIUS, z as GraphNodeElement, K as GraphPortElement, D as MARQUEE_THRESHOLD_PX, q as MAX_BLINK_HZ, u as MAX_FLOW_SPEED, O as MarqueeController, B as NODE_SHAPES, E as NodeDragController, t as NodeGraphElement, m as PanZoomController, U as RESIZE_HANDLES, r as WireDragController, bt as addWire, J as blinkPeriodSeconds, g as boundsOf, ht as canConnect, _ as clampZoom, c as collapsedOffset, k as combineSelection, xt as connectContext, St as cycleBlockedNodes, nt as defaultSide, Ct as edgeId, rt as edgeMidpoint, it as edgePath, at as edgeShape, wt as ensurePort, ot as extendFromSide, o as findProximityConnection, F as findSnapTarget, gt as findValidWire, v as fitBounds, y as fitRects, b as flowToScreen, X as forceMovement, Z as forcePin, Q as forcePositions, $ as forceState, et as forceStep, Tt as fromEdges, Et as hasWire, Dt as inDegreeOf, ft as inEasyConnectZone, Ot as incomingEdge, kt as incomingEdges, h as isEditableTarget, V as isNodeShape, W as isResizeHandle, A as marqueeStyle, l as measureNode, w as nodeGraphStyles, j as nodesInRect, _t as normaliseConnection, At as outDegreeOf, x as panBy, jt as parsePortId, pt as pickStartPort, st as polylineMidpoint, ct as polylinePath, lt as polylineShape, Mt as portId, I as proximityFactor, M as rectFromPoints, s as rectGap, N as rectsIntersect, Nt as removeNode, mt as removeNodes, Pt as removeWire, n as renderWires, G as resizeRect, vt as resolveConnection, d as sanitizeFlowSpeed, S as screenToFlow, i as selectionAfterEdgeClick, a as selectionAfterNodePress, L as settled, H as shapeSpec, R as smoothStep, ut as stepPoints, Ft as toEdges, It as toNodeGraph, yt as typesCompatible, P as wantsMarquee, f as withEntry, p as withWireFlow, C as zoomAt } from "./node-graph-yrbOLbYo.js";
@@ -1,6 +1,6 @@
1
- import { t as TickledController } from "./tickled-controller-BVhGKzjZ.js";
1
+ import { t as TickledController } from "./tickled-controller-BsFFr_1N.js";
2
2
  import { n as tickledStyles, t as tickledItemStyles } from "./tickled-styles-pnieYweS.js";
3
- import "./interaction-BEcBIY0d.js";
3
+ import "./interaction-DNuFnTm0.js";
4
4
  import { t as WheelNudgeMixin } from "./wheel-nudge-DgJzrL28.js";
5
5
  import { t as themeFallbacks } from "./fallbacks-BPjjBoED.js";
6
6
  import { t as scrollFadeStyles } from "./scroll-fade-DH8OXSqL.js";
@@ -1,2 +1,2 @@
1
- import { a as SunburstViewState, i as SunburstZoomEvent, n as SunburstTreeListElementEventMap, r as SunburstZoomDetail, t as SunburstTreeListElement } from "./sunbursttree-list-XF7gBKod.js";
1
+ import { a as SunburstViewState, i as SunburstZoomEvent, n as SunburstTreeListElementEventMap, r as SunburstZoomDetail, t as SunburstTreeListElement } from "./sunbursttree-list-CmydFG66.js";
2
2
  export { SunburstTreeListElement, SunburstTreeListElementEventMap, type SunburstViewState, SunburstZoomDetail, SunburstZoomEvent };
@@ -1 +1 @@
1
- export { t as SunburstTreeListElement } from "./sunbursttree-list-C-FuZB5z.js";
1
+ export { t as SunburstTreeListElement } from "./sunbursttree-list-CJdznPzN.js";
@@ -1,7 +1,7 @@
1
1
  import { t as collectDataResult } from "./data-provider-C6ZNAcaT.js";
2
2
  import { a as resolveKeyPath } from "./tree-DUc-iQcg.js";
3
- import { i as ListSearchController, n as listSearchStyles, o as registerListSearchCommands, r as LIST_SEARCH_MODES, t as createTreeListSearchAdapter } from "./incr-search-C5114RxZ.js";
4
- import { t as TickledController } from "./tickled-controller-BVhGKzjZ.js";
3
+ import { i as ListSearchController, n as listSearchStyles, o as registerListSearchCommands, r as LIST_SEARCH_MODES, t as createTreeListSearchAdapter } from "./incr-search-Bk4acsCM.js";
4
+ import { t as TickledController } from "./tickled-controller-BsFFr_1N.js";
5
5
  import { a as capKeys, l as keysToArray, n as EMPTY_KEYS } from "./pending-Afl4LT64.js";
6
6
  import { t as themeFallbacks } from "./fallbacks-BPjjBoED.js";
7
7
  import { t as ViewStateController } from "./view-state-controller-DiPAPiA7.js";
@@ -2,7 +2,7 @@ import { C as TreeItemDblClickEvent, E as TreeSearchHost, M as TreeDataModel, a
2
2
  import { a as TreeItem, n as TreeExclusivity, o as TreeNode, r as TreeFilterPredicate, s as TreeSelectionFilter, t as LoadChildrenCallback } from "./types-6hpXRKt7.js";
3
3
  import { a as ViewStateBase, t as GetViewStateOptions } from "./types-16GC5k1z.js";
4
4
  import "./index-Cdcek1Oj.js";
5
- import { S as ListSearchController } from "./index-Db5VGFR1.js";
5
+ import { S as ListSearchController } from "./index-BuvySJEc.js";
6
6
  import { LitElement, PropertyValues } from "lit";
7
7
  import { CommandRegistry } from "@clinth/ui-commands";
8
8
  /**
@@ -185,7 +185,7 @@ var TickledController = class TickledController {
185
185
  const modeChanged = this._inputMode !== `keyboard`;
186
186
  this._inputMode = `keyboard`;
187
187
  TickledController.ignoreHoverUntilPointerMoves();
188
- const enabledItems = this.config.getItems().filter((item) => item.enabled !== false);
188
+ const enabledItems = this.config.getItems().filter((item) => item.enabled !== false && item.focusable !== false);
189
189
  if (enabledItems.length === 0) return;
190
190
  let newId;
191
191
  if (direction === `first`) newId = enabledItems[0].id;
@@ -11,6 +11,11 @@ type TickledItem<T = unknown> = {
11
11
  * Whether the item is currently enabled/interactive
12
12
  */
13
13
  readonly enabled?: boolean;
14
+ /**
15
+ * `false`: hover may still tickle the item, but keyboard cursor movement
16
+ * skips it. Independent of `enabled` (which blocks both).
17
+ */
18
+ readonly focusable?: boolean;
14
19
  };
15
20
  /**
16
21
  * Input mode determines which mechanism controls the tickled state
@@ -1,13 +1,13 @@
1
- import { t as TickledController } from "./tickled-controller-BVhGKzjZ.js";
1
+ import { t as TickledController } from "./tickled-controller-BsFFr_1N.js";
2
2
  import { n as tickledStyles, t as tickledItemStyles } from "./tickled-styles-pnieYweS.js";
3
3
  import { t as themeFallbacks } from "./fallbacks-BPjjBoED.js";
4
4
  import { n as safeCustomElement, t as __decorate } from "./decorate-Dxs8sFX8.js";
5
- import { i as ListSearchController, n as listSearchStyles, o as registerListSearchCommands, r as LIST_SEARCH_MODES, t as createTreeListSearchAdapter } from "./incr-search-C5114RxZ.js";
6
- import { i as animateListItemOut, o as prefersReducedMotion, r as animateListItemIn, t as ListNativeDragController } from "./list-native-drag-controller-Brk30s5d.js";
5
+ import { i as ListSearchController, n as listSearchStyles, o as registerListSearchCommands, r as LIST_SEARCH_MODES, t as createTreeListSearchAdapter } from "./incr-search-Bk4acsCM.js";
6
+ import { i as animateListItemOut, o as prefersReducedMotion, r as animateListItemIn, t as ListNativeDragController } from "./list-native-drag-controller-B_INa6_G.js";
7
7
  import { a as capKeys, c as keysAsFlags, f as withoutFlag, i as capFlags, l as keysToArray, n as EMPTY_KEYS, o as flagsFromRecord, s as flagsToRecord, t as EMPTY_FLAGS } from "./pending-Afl4LT64.js";
8
8
  import { i as sameKeySet, r as isPartialKey, t as PARTIAL_DESCRIPTION } from "./partial-keys-D4l_ede_.js";
9
9
  import { n as createScrollHoverGuard } from "./scroll-hover-guard-BGAjtyXT.js";
10
- import "./interaction-BEcBIY0d.js";
10
+ import "./interaction-DNuFnTm0.js";
11
11
  import { t as collectDataResult } from "./data-provider-C6ZNAcaT.js";
12
12
  import { n as anchorFromRow, o as scrollToOffset, t as ViewStateController } from "./view-state-controller-DiPAPiA7.js";
13
13
  import { i as reconcileSelection, r as reconcileExpansion } from "./tree-DUc-iQcg.js";
package/dist/tree.d.ts CHANGED
@@ -1,4 +1,4 @@
1
1
  import { A as TreeTickleDetail, M as TreeDataModel, N as TreeDataModelOptions, O as TreeSelectDetail, T as TreeRevealMode, _ as TreeDropTarget, b as TreeItemClickDetail, c as TreeDragContext, d as TreeDragStartEvent, g as TreeDropPosition, h as TreeDropEvent, i as TreeCollapseEvent, j as TreeTickleEvent, k as TreeSelectEvent, l as TreeDragEndEvent, m as TreeDropDetail, n as TreeActivateEvent, o as TreeComponentEventMap, p as TreeDropContext, r as TreeCollapseDetail, s as TreeDndMode, t as TreeActivateDetail, u as TreeDragOverEvent, v as TreeExpandDetail, w as TreeNavigateOptions, x as TreeItemClickEvent, y as TreeExpandEvent } from "./tree-component-BE7OEIiH.js";
2
2
  import { a as TreeItem, n as TreeExclusivity, o as TreeNode, r as TreeFilterPredicate, s as TreeSelectionFilter, t as LoadChildrenCallback } from "./types-6hpXRKt7.js";
3
- import { a as TreeDropVisibleRow, c as TreeListElement, d as TreeBaseElement, f as TreeBaseElementEventMap, h as TreeConfig, i as TreeDropRowInfo, l as TreeCheckboxState, m as TreeListViewState, n as TreeDropControllerConfig, o as TreeController, p as TreeVirtualize, r as TreeDropResolvedDrag, s as TreeControllerOptions, t as TreeDropController, u as TreeAnimation } from "./index-BymYKGY-.js";
3
+ import { a as TreeDropVisibleRow, c as TreeListElement, d as TreeBaseElement, f as TreeBaseElementEventMap, h as TreeConfig, i as TreeDropRowInfo, l as TreeCheckboxState, m as TreeListViewState, n as TreeDropControllerConfig, o as TreeController, p as TreeVirtualize, r as TreeDropResolvedDrag, s as TreeControllerOptions, t as TreeDropController, u as TreeAnimation } from "./index-BIv_Hu7C.js";
4
4
  export { type LoadChildrenCallback, type TreeActivateDetail, type TreeActivateEvent, TreeAnimation, TreeBaseElement, TreeBaseElementEventMap, type TreeCheckboxState, type TreeCollapseDetail, type TreeCollapseEvent, type TreeComponentEventMap, TreeConfig, TreeController, TreeControllerOptions, TreeDataModel, type TreeDataModelOptions, type TreeDndMode, type TreeDragContext, type TreeDragEndEvent, type TreeDragOverEvent, type TreeDragStartEvent, type TreeDropContext, TreeDropController, TreeDropControllerConfig, type TreeDropDetail, type TreeDropEvent, type TreeDropPosition, TreeDropResolvedDrag, TreeDropRowInfo, type TreeDropTarget, TreeDropVisibleRow, type TreeExclusivity, type TreeExpandDetail, type TreeExpandEvent, type TreeFilterPredicate, type TreeItem, type TreeItemClickDetail, type TreeItemClickEvent, TreeListElement, type TreeListViewState, type TreeNavigateOptions, type TreeNode, type TreeRevealMode, type TreeSelectDetail, type TreeSelectEvent, type TreeSelectionFilter, type TreeTickleDetail, type TreeTickleEvent, TreeVirtualize };
package/dist/tree.js CHANGED
@@ -1 +1 @@
1
- export { r as TreeBaseElement, t as TreeController, a as TreeDataModel, i as TreeDropController, n as TreeListElement } from "./tree-1CSNgw72.js";
1
+ export { r as TreeBaseElement, t as TreeController, a as TreeDataModel, i as TreeDropController, n as TreeListElement } from "./tree-C3rgEEmm.js";
@@ -1,9 +1,9 @@
1
1
  import { n as appearanceColor, t as appearanceAbsent } from "./item-appearance-FRO3TRFI.js";
2
- import { c as createElementListSearchAdapter, d as keysOfElements, i as ListSearchController, n as listSearchStyles, o as registerListSearchCommands, r as LIST_SEARCH_MODES, u as keyForElement } from "./incr-search-C5114RxZ.js";
2
+ import { c as createElementListSearchAdapter, d as keysOfElements, i as ListSearchController, n as listSearchStyles, o as registerListSearchCommands, r as LIST_SEARCH_MODES, u as keyForElement } from "./incr-search-Bk4acsCM.js";
3
+ import { d as ItemTagResolver, g as sameTagKeys, i as animateListItemOut, r as animateListItemIn, t as ListNativeDragController, u as DEFAULT_ITEM_TAG_FLAGS, y as tagsAttribute } from "./list-native-drag-controller-B_INa6_G.js";
3
4
  import { i as ListDragSelectController, n as gestureOf, t as ListSelectionController } from "./list-selection-controller-Dkh3m3hX.js";
4
- import { i as animateListItemOut, r as animateListItemIn, t as ListNativeDragController } from "./list-native-drag-controller-Brk30s5d.js";
5
5
  import { i as sameKeySet, n as applyPartialAttributes, r as isPartialKey } from "./partial-keys-D4l_ede_.js";
6
- import { t as TickledController } from "./tickled-controller-BVhGKzjZ.js";
6
+ import { t as TickledController } from "./tickled-controller-BsFFr_1N.js";
7
7
  import { l as keysToArray } from "./pending-Afl4LT64.js";
8
8
  import { t as themeFallbacks } from "./fallbacks-BPjjBoED.js";
9
9
  import { t as scrollFadeStyles } from "./scroll-fade-DH8OXSqL.js";
@@ -168,7 +168,8 @@ let VerticalListElement = class VerticalListElement extends LitElement {
168
168
  this.tickled = ((self) => new TickledController(self, {
169
169
  getItems: () => self.#selectionOrder().map((el) => ({
170
170
  id: el,
171
- enabled: !el.hasAttribute(`not-checked`)
171
+ enabled: !el.hasAttribute(`not-checked`) && self.#flagsOf(el).selectable,
172
+ focusable: self.#flagsOf(el).focusable
172
173
  })),
173
174
  onTickle: (id) => {
174
175
  if (self.tickled.inputMode === `keyboard`) {
@@ -244,10 +245,13 @@ let VerticalListElement = class VerticalListElement extends LitElement {
244
245
  itemSelector: ITEM_SELECTOR,
245
246
  getLabel: (el) => el.getAttribute(`data-search-label`) ?? el.textContent?.trim() ?? ``,
246
247
  highlightKey: `vertical-list-search`,
248
+ isSearchable: (el) => this.#flagsOf(el).searchable,
247
249
  getAllItems: () => this.#selectionOrder(),
248
250
  observeContainer: false
249
251
  }) });
250
252
  this.#partialKeys = /* @__PURE__ */ new Set();
253
+ this.#tagResolver = new ItemTagResolver();
254
+ this.#taggedEls = /* @__PURE__ */ new Set();
251
255
  this.#onScroll = () => {
252
256
  if (!this.#viewState.pendingScroll) this.#viewState.notify();
253
257
  if (this.#scrollRaf !== 0) return;
@@ -445,7 +449,7 @@ let VerticalListElement = class VerticalListElement extends LitElement {
445
449
  #nativeDrag;
446
450
  #prepareNativeDrag(originKey) {
447
451
  const originEl = this.#itemForKey(originKey);
448
- if (!originEl || !this._isCheckable(originEl)) return void 0;
452
+ if (!originEl || !this._isCheckable(originEl) || !this.#flagsOf(originEl).draggable) return void 0;
449
453
  if (!this.selection.selected.has(originEl)) this.selection.replace(originEl);
450
454
  const ordered = this.#selectionOrder();
451
455
  const selected = [];
@@ -470,7 +474,7 @@ let VerticalListElement = class VerticalListElement extends LitElement {
470
474
  if (!this.isConnected) return;
471
475
  for (const el of this.querySelectorAll(ITEM_SELECTOR)) {
472
476
  if (this.#wrappedElements.has(el)) continue;
473
- if (el instanceof HTMLElement) el.draggable = this.itemsDraggable && this._isCheckable(el);
477
+ if (el instanceof HTMLElement) el.draggable = this.itemsDraggable && this._isCheckable(el) && this.#flagsOf(el).draggable;
474
478
  }
475
479
  }
476
480
  #startPostDragSuppressTimer() {
@@ -777,6 +781,54 @@ let VerticalListElement = class VerticalListElement extends LitElement {
777
781
  return this.selection.selectedKeys;
778
782
  }
779
783
  #partialKeys;
784
+ #tagResolver;
785
+ #taggedEls;
786
+ /**
787
+ * Tags assigned by key, apart from the item data (like {@link partialKeys}):
788
+ * tag name → keys carrying it. Each tag is mirrored on the row as `data-tags`
789
+ * (`li[data-tags~="foo"]`); `tagBehaviour` can switch off selection, focus,
790
+ * drag or search per tag.
791
+ */
792
+ get tagKeys() {
793
+ return this.#tagResolver.tagKeys;
794
+ }
795
+ set tagKeys(value) {
796
+ if (sameTagKeys(value, this.#tagResolver.tagKeys)) return;
797
+ this.#tagResolver.tagKeys = value;
798
+ this.refreshTags();
799
+ }
800
+ /**
801
+ * Interaction flags per tag name: `selectable`, `focusable`, `draggable`,
802
+ * `searchable` (`false` switches one off; omitted keeps the default). With
803
+ * several tags the most restrictive wins. Rows stay rendered.
804
+ */
805
+ get tagBehaviour() {
806
+ return this.#tagResolver.behaviour;
807
+ }
808
+ set tagBehaviour(value) {
809
+ if (value === this.#tagResolver.behaviour) return;
810
+ this.#tagResolver.behaviour = value;
811
+ this.refreshTags();
812
+ }
813
+ /** Re-apply `data-tags` to the rows and refresh drag state. Called automatically on change and after each update. */
814
+ refreshTags() {
815
+ if (!this.isConnected) return;
816
+ if (this.#tagResolver.tagKeys === void 0 && this.#taggedEls.size === 0) return;
817
+ const next = /* @__PURE__ */ new Set();
818
+ for (const el of /* @__PURE__ */ new Set([...this.#allItems, ...this.querySelectorAll(ITEM_SELECTOR)])) {
819
+ const value = tagsAttribute(this.#tagResolver.tagsFor(keyForElement(el) ?? void 0));
820
+ if (value === void 0) continue;
821
+ if (el.getAttribute(`data-tags`) !== value) el.setAttribute(`data-tags`, value);
822
+ next.add(el);
823
+ }
824
+ for (const el of this.#taggedEls) if (!next.has(el)) el.removeAttribute(`data-tags`);
825
+ this.#taggedEls = next;
826
+ this._syncNativeDraggable();
827
+ }
828
+ #flagsOf(el) {
829
+ if (this.#tagResolver.tagKeys === void 0) return DEFAULT_ITEM_TAG_FLAGS;
830
+ return this.#tagResolver.flagsForItem(keyForElement(el) ?? void 0);
831
+ }
780
832
  /**
781
833
  * Rows shown as *partially* selected (a part of the resource is selected):
782
834
  * `data-partial`, an indeterminate checkbox in `checked` mode, and an
@@ -1108,6 +1160,7 @@ let VerticalListElement = class VerticalListElement extends LitElement {
1108
1160
  this.#rekeySelection(previous, anchorKey, this.querySelectorAll(ITEM_SELECTOR));
1109
1161
  if (this.interactionMode === `checked`) this._syncCheckboxes();
1110
1162
  this._syncItemStates();
1163
+ this.refreshTags();
1111
1164
  this._syncNativeDraggable();
1112
1165
  this.#nativeDrag.refreshDraggable();
1113
1166
  this.#reconcileViewState();
@@ -1479,6 +1532,7 @@ let VerticalListElement = class VerticalListElement extends LitElement {
1479
1532
  });
1480
1533
  }
1481
1534
  _isCheckable(item) {
1535
+ if (!this.#flagsOf(item).selectable) return false;
1482
1536
  if (this.interactionMode !== `checked`) return true;
1483
1537
  return !(this.#customWrappers.get(item) ?? item).hasAttribute(`not-checked`);
1484
1538
  }
@@ -1,9 +1,10 @@
1
- import { H as ListNativeDragStartEvent, P as ListDragDataTransferWriter, R as ListDragPreviewRenderer, z as ListDragPreviewSourceResolver } from "./tree-component-BE7OEIiH.js";
1
+ import { i as ItemTagKeys, n as ItemTagBehaviour } from "./item-tags-Dz-jQq-4.js";
2
2
  import { a as ViewStateBase, t as GetViewStateOptions } from "./types-16GC5k1z.js";
3
+ import { H as ListNativeDragStartEvent, P as ListDragDataTransferWriter, R as ListDragPreviewRenderer, z as ListDragPreviewSourceResolver } from "./tree-component-BE7OEIiH.js";
3
4
  import { h as ListSelectionMode, i as ListInteractionMode, r as ListElementEventMap } from "./list-selection-types-CKTt7Rrw.js";
4
5
  import { n as ListViewportChangeEvent } from "./list-viewport-types-BJ8c6qur.js";
5
6
  import "./index-Cdcek1Oj.js";
6
- import { S as ListSearchController } from "./index-Db5VGFR1.js";
7
+ import { S as ListSearchController } from "./index-BuvySJEc.js";
7
8
  import "./editable-label-CiHCDlhC.js";
8
9
  import { LitElement, PropertyValues } from "lit";
9
10
  import { CommandId, CommandRegistry } from "@clinth/ui-commands";
@@ -263,6 +264,23 @@ declare class VerticalListElement extends LitElement {
263
264
  selectAll(): void;
264
265
  /** The selection as stable `data-key` / `data-value` strings. */
265
266
  get selectedKeys(): ReadonlySet<string>;
267
+ /**
268
+ * Tags assigned by key, apart from the item data (like {@link partialKeys}):
269
+ * tag name → keys carrying it. Each tag is mirrored on the row as `data-tags`
270
+ * (`li[data-tags~="foo"]`); `tagBehaviour` can switch off selection, focus,
271
+ * drag or search per tag.
272
+ */
273
+ get tagKeys(): ItemTagKeys | undefined;
274
+ set tagKeys(value: ItemTagKeys | undefined);
275
+ /**
276
+ * Interaction flags per tag name: `selectable`, `focusable`, `draggable`,
277
+ * `searchable` (`false` switches one off; omitted keeps the default). With
278
+ * several tags the most restrictive wins. Rows stay rendered.
279
+ */
280
+ get tagBehaviour(): ItemTagBehaviour | undefined;
281
+ set tagBehaviour(value: ItemTagBehaviour | undefined);
282
+ /** Re-apply `data-tags` to the rows and refresh drag state. Called automatically on change and after each update. */
283
+ refreshTags(): void;
266
284
  /**
267
285
  * Rows shown as *partially* selected (a part of the resource is selected):
268
286
  * `data-partial`, an indeterminate checkbox in `checked` mode, and an
@@ -1,5 +1,5 @@
1
1
  import { B as ListDragSource, F as ListDragEntry, H as ListNativeDragStartEvent, I as ListDragPreview, L as ListDragPreviewContext, R as ListDragPreviewRenderer, V as ListNativeDragStartDetail } from "./tree-component-BE7OEIiH.js";
2
2
  import { n as ListViewportChangeEvent, t as ListViewportChangeDetail } from "./list-viewport-types-BJ8c6qur.js";
3
3
  import { _ as ListTickleEvent, a as ListItemClickDetail, c as ListSelectDetail, g as ListTickleDetail, h as ListSelectionMode, i as ListInteractionMode, l as ListSelectEvent, n as ListActivateEvent, o as ListItemClickEvent, r as ListElementEventMap, t as ListActivateDetail } from "./list-selection-types-CKTt7Rrw.js";
4
- import { a as VerticalListViewState, c as ListDragLeaveDetail, d as ListDropDetail, f as ListDropEvent, g as ListEditCommitEvent, h as ListEditCommitDetail, i as VerticalListElementEventMap, l as ListDragLeaveEvent, m as ListEditCancelEvent, n as CustomCheckboxOptions, o as ListContextMenuDetail, p as ListEditCancelDetail, r as VerticalListElement, s as ListContextMenuEvent, t as AddItemOptions, u as ListDragOverEvent } from "./vertical-list-Dyc5azxv.js";
4
+ import { a as VerticalListViewState, c as ListDragLeaveDetail, d as ListDropDetail, f as ListDropEvent, g as ListEditCommitEvent, h as ListEditCommitDetail, i as VerticalListElementEventMap, l as ListDragLeaveEvent, m as ListEditCancelEvent, n as CustomCheckboxOptions, o as ListContextMenuDetail, p as ListEditCancelDetail, r as VerticalListElement, s as ListContextMenuEvent, t as AddItemOptions, u as ListDragOverEvent } from "./vertical-list-C4z3La0C.js";
5
5
  export { AddItemOptions, CustomCheckboxOptions, type ListActivateDetail, type ListActivateEvent, type ListContextMenuDetail, type ListContextMenuEvent, type ListDragEntry, type ListDragLeaveDetail, type ListDragLeaveEvent, type ListDragOverEvent, type ListDragPreview, type ListDragPreviewContext, type ListDragPreviewRenderer, type ListDragSource, type ListDropDetail, type ListDropEvent, type ListEditCancelDetail, type ListEditCancelEvent, type ListEditCommitDetail, type ListEditCommitEvent, type ListElementEventMap, type ListInteractionMode, type ListItemClickDetail, type ListItemClickEvent, type ListNativeDragStartDetail, type ListNativeDragStartEvent, type ListSelectDetail, type ListSelectEvent, type ListSelectionMode, type ListTickleDetail, type ListTickleEvent, type ListViewportChangeDetail, type ListViewportChangeEvent, VerticalListElement, VerticalListElementEventMap, type VerticalListViewState };
@@ -1 +1 @@
1
- export { t as VerticalListElement } from "./vertical-list-BNCRA_zy.js";
1
+ export { t as VerticalListElement } from "./vertical-list-By-yuhkw.js";
@@ -77,5 +77,6 @@ This directory contains documentation for each component and some architectural
77
77
  - [infra-view-state.md](infra-view-state.md)
78
78
  - [list-state.md](list-state.md)
79
79
  - [user-catalog.md](user-catalog.md)
80
+ - [user-item-tags.md](user-item-tags.md)
80
81
  - [user-selection-intents.md](user-selection-intents.md)
81
82
  - [user-theming.md](user-theming.md)
@@ -3,7 +3,7 @@
3
3
  Three related button components:
4
4
 
5
5
  - **`ixfx-button`** — a styled, icon-capable replacement for `<button>`
6
- - **`ixfx-split-button`** — a button paired with a dropdown caret; supports a static popup menu, a switcher mode, and programmatic item control
6
+ - **`ixfx-split-button`** — a button paired with a dropdown caret; supports a static popup menu, a switcher mode, a popover (slotted, by `popover-target`, or built just in time), and programmatic item control
7
7
  - **`ixfx-radio-group`** — a group of radio-style selectable items; also supports single toggle mode
8
8
 
9
9
  ---
@@ -246,6 +246,8 @@ Inherits all `ixfx-button` properties, plus:
246
246
  | `default-value` | string | `''` | Command to pre-select in switcher mode |
247
247
  | `items` | `PopupItem[]` | — | Directly set popup items (ignored when `itemsProvider` is set) |
248
248
  | `itemsProvider` | `() => PopupItem[] \| Promise<PopupItem[]>` | — | Called on each caret click; return value replaces all other item sources |
249
+ | `popover-target` | string | `''` | Id of a `popover` element the caret toggles instead of the menu (see [Popover](#popover-instead-of-a-menu)) |
250
+ | `popoverProvider` | `(popover: HTMLElement) => void \| Promise<void>` | — | Builds popover content just before each show |
249
251
  | `registry` | `CommandRegistry` | — | Optional command registry forwarded to `ixfx-menu-trigger` |
250
252
  | `keyboardManager` | `KeyboardManager` | — | Optional keyboard manager forwarded to `ixfx-menu-trigger` |
251
253
 
@@ -254,6 +256,7 @@ Inherits all `ixfx-button` properties, plus:
254
256
  | Slot | Description |
255
257
  |-----------|-------------------------------------------------------------------------------|
256
258
  | default | Primary button label |
259
+ | `popover` | Content of a popover the caret toggles instead of the menu |
257
260
  | `menu` | `<ixfx-menu-container>` + items for the popup (default mode); or `<ixfx-menu-item>` elements as the data source in switcher mode |
258
261
 
259
262
  ### Events
@@ -344,6 +347,33 @@ btn.itemsProvider = async () => {
344
347
 
345
348
  The popup shows a "Loading…" placeholder while the promise resolves. `itemsProvider` takes priority over `items` and declarative slot content.
346
349
 
350
+ #### Popover instead of a menu
351
+
352
+ The caret can toggle a native popover instead of the menu (works in both modes; the primary button is unaffected). Popover mode is on when any of these is present, and takes precedence over menu items:
353
+
354
+ ```html
355
+ <!-- 1. Slotted content: shown in a panel anchored under the caret (`part="popover"`) -->
356
+ <ixfx-split-button>
357
+ Share
358
+ <div slot="popover">Anyone with the link can view</div>
359
+ </ixfx-split-button>
360
+
361
+ <!-- 2. An existing popover element anywhere in the same tree -->
362
+ <ixfx-split-button popover-target="share-pop">Share</ixfx-split-button>
363
+ <div id="share-pop" popover>…</div>
364
+ ```
365
+
366
+ ```js
367
+ // 3. Build the content just in time. Runs each time the popover is about to show
368
+ // (awaited), with the panel — or the `popover-target` element — as the argument.
369
+ btn.popoverProvider = async (popover) => {
370
+ const people = await fetch('/api/people').then(r => r.json());
371
+ popover.replaceChildren(...people.map(p => Object.assign(document.createElement('div'), { textContent: p.name })));
372
+ };
373
+ ```
374
+
375
+ `popoverProvider` can be combined with either form; on its own it fills the built-in panel. The caret gets `aria-haspopup="dialog"` and `aria-expanded`, ArrowDown opens it, and clicking the caret again closes it. A `popover-target` element positions itself (the caret is passed as the popover `source`, so CSS anchor positioning can use it implicitly). Width of the built-in panel: `--ixfx-split-button-popover-max-width`.
376
+
347
377
  #### Change mode at runtime
348
378
 
349
379
  ```js
@@ -652,3 +652,6 @@ state.
652
652
 
653
653
  `demo/data-grid.html` + `demo/data-grid.ts`: 200 rows, `Department` random, `Score` float, `Name`/`Department` editable (`user` mode, slow double-click; `Tab`/`Up`/`Down` navigation; `Enter` from tickled row). Controls: Selection/Interaction/Group by/Editability/`column-menu` + `Edit first row` (manual), a `Stream +5,000 rows` button (`appendRows`), and `selectKeys` / `tickleRow` buttons.
654
654
 
655
+
656
+ **Item tags:** `tags` hook / `tagKeys` → `data-tags` and `part="… tag-<name>"`; `tagBehaviour` switches off `selectable` / `focusable` / `draggable` / `searchable` per tag. See [Item tags](./user-item-tags.md).
657
+
@@ -759,3 +759,6 @@ compare runs against each other rather than against fixed budgets. The data
759
759
  grid has the same tooling (`pnpm bench:data-grid`); shared harness code is in
760
760
  `scripts/bench/`.
761
761
 
762
+
763
+ **Item tags:** `tags` hook / `tagKeys` → `data-tags` and `part="… tag-<name>"`; `tagBehaviour` switches off `selectable` / `focusable` / `draggable` / `searchable` per tag. See [Item tags](./user-item-tags.md).
764
+
@@ -770,6 +770,9 @@ For finer control, style `::part(viewport)` directly (including
770
770
 
771
771
  ## Choosing a list component
772
772
 
773
+
774
+ **Item tags:** `tags` hook / `tagKeys` → `data-tags` and `part="… tag-<name>"`; `tagBehaviour` switches off `selectable` / `focusable` / `draggable` / `searchable` per tag. See [Item tags](./user-item-tags.md).
775
+
773
776
  - **Large lists** — prefer `ixfx-grid-list` with `orientation="column"` over
774
777
  `ixfx-vertical-list`. `vertical-list` renders every child; `grid-list` is
775
778
  windowed.
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@ixfx/components",
3
- "version": "0.18.0",
4
- "generated": "2026-11-10T18:13:23.971Z",
3
+ "version": "0.18.1",
4
+ "generated": "2026-11-10T23:10:32.663Z",
5
5
  "components": [
6
6
  {
7
7
  "name": "ac-text",
@@ -348,6 +348,10 @@
348
348
  "name": "user-catalog.md",
349
349
  "path": "docs-user/user-catalog.md"
350
350
  },
351
+ {
352
+ "name": "user-item-tags.md",
353
+ "path": "docs-user/user-item-tags.md"
354
+ },
351
355
  {
352
356
  "name": "user-selection-intents.md",
353
357
  "path": "docs-user/user-selection-intents.md"
@@ -83,5 +83,6 @@ import '@ixfx/components/data-grid';
83
83
  - [infra-view-state.md](docs-user/infra-view-state.md)
84
84
  - [list-state.md](docs-user/list-state.md)
85
85
  - [user-catalog.md](docs-user/user-catalog.md)
86
+ - [user-item-tags.md](docs-user/user-item-tags.md)
86
87
  - [user-selection-intents.md](docs-user/user-selection-intents.md)
87
88
  - [user-theming.md](docs-user/user-theming.md)
@@ -178,4 +178,7 @@ el.addEventListener(`multicol-select`, (event) => {
178
178
  });
179
179
  ```
180
180
 
181
+
182
+ **Item tags:** `tags` hook / `tagKeys` → `data-tags` and `part="… tag-<name>"`; `tagBehaviour` switches off `selectable` / `focusable` / `draggable` / `searchable` per tag. See [Item tags](./user-item-tags.md).
183
+
181
184
  See `demo/multicol-list.html` for a full in-memory example with counts.
@@ -0,0 +1,68 @@
1
+ # Item tags
2
+
3
+ Tag list items with names that mean something to your app, then style them and
4
+ change how they react to input. The components never interpret a tag: they only
5
+ expose it and apply the generic interaction flags you declare for it.
6
+
7
+ Works the same on `ixfx-grid-list`, `ixfx-detail-list`, `ixfx-data-grid` and
8
+ `ixfx-multicol-list` (and on `ixfx-vertical-list`, which `ixfx-multicol-list` uses for its columns).
9
+
10
+ ## 1. Assigning tags
11
+
12
+ Two forms, which can be combined (tags are merged, de-duplicated):
13
+
14
+ | Form | Where |
15
+ | --- | --- |
16
+ | Hook returning `readonly string[] \| undefined` | `ixfx-grid-list`: `itemAdapter.tags(item, index)`. `ixfx-detail-list` / `ixfx-data-grid`: `list.tags(item, index)`. `ixfx-multicol-list`: `list.tags(item, columnId)` |
17
+ | Key sets: `tagKeys: ReadonlyMap<tag, ReadonlySet<key>>` | all of them (`ixfx-vertical-list` too). For tags kept apart from the item data, like `partialKeys`. Works for light-DOM / element-mode items |
18
+
19
+ ```ts
20
+ grid.itemAdapter = { key, render, tags: row => row.willBeRemoved ? [`leaving`] : undefined };
21
+ grid.tagKeys = new Map([[`arriving`, new Set([`k1`, `k2`])]]);
22
+ ```
23
+
24
+ Tags are re-read on every render, so `updateItem` / `updateItems` (grid-list) and
25
+ assigning `items` / `rows` pick up changes without rebuilding the adapter. If a hook reads
26
+ state outside the items, call `refreshTags()` (detail-list, data-grid, multicol-list).
27
+ Empty names and names containing whitespace are ignored.
28
+
29
+ ## 2. Styling
30
+
31
+ Each tag is exposed on the item:
32
+
33
+ - `data-tags` (space separated): `[data-tags~="leaving"]`. Always present.
34
+ - a `part` token `tag-<name>` on shadow-DOM items: `::part(item tag-leaving)`.
35
+
36
+ The prefix keeps a caller tag called `selected` from colliding with the built-in state.
37
+
38
+ Which element carries what:
39
+
40
+ | Component | Item element (background, `part="item …"`) | Content |
41
+ | --- | --- | --- |
42
+ | `ixfx-grid-list` | `.cell` — `part="item"` | `part="content"` inside it |
43
+ | `ixfx-data-grid` | `.row` — `part="item"` | the `.cell` children (`part="cell"`-style cells) |
44
+ | `ixfx-detail-list` | the light-DOM `<li>` (`data-tags` only — it is not in a shadow tree, so no `part`) | the `<li>`'s children |
45
+ | `ixfx-multicol-list` / `ixfx-vertical-list` | the light-DOM `<li>` (`data-tags` only) | the `<li>`'s children |
46
+
47
+ ```css
48
+ ixfx-grid-list::part(item tag-leaving) { opacity: 0.5; text-decoration: line-through; }
49
+ ixfx-detail-list li[data-tags~="arriving"] { background: color-mix(in srgb, green 15%, transparent); }
50
+ ```
51
+
52
+ ## 3. Behaviour
53
+
54
+ ```ts
55
+ list.tagBehaviour = {
56
+ leaving: { selectable: false, focusable: false, draggable: false, searchable: false },
57
+ };
58
+ ```
59
+
60
+ - Flags left out keep the default. A tag with no declaration only styles.
61
+ - Several tags: the most restrictive wins (any `false` beats `true`).
62
+ - `selectable: false` — no selection or tickle, no `list-select-intent`; range, marquee and select-all skip the item.
63
+ - `focusable: false` — keyboard cursor movement skips the item (hover can still tickle it).
64
+ - `draggable: false` — no drag starts from the item.
65
+ - `searchable: false` — left out of incremental search.
66
+ - The item is always still rendered and still counts for layout and scroll position.
67
+
68
+ `ixfx-grid-list`'s `disabled` adapter hook is unchanged and combines with these flags.
package/llms.txt CHANGED
@@ -83,5 +83,6 @@ import '@ixfx/components/data-grid';
83
83
  - [infra-view-state.md](docs-user/infra-view-state.md)
84
84
  - [list-state.md](docs-user/list-state.md)
85
85
  - [user-catalog.md](docs-user/user-catalog.md)
86
+ - [user-item-tags.md](docs-user/user-item-tags.md)
86
87
  - [user-selection-intents.md](docs-user/user-selection-intents.md)
87
88
  - [user-theming.md](docs-user/user-theming.md)
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@ixfx/components",
3
3
  "type": "module",
4
- "version": "0.18.0",
4
+ "version": "0.18.1",
5
5
  "packageManager": "pnpm@10.0.0",
6
6
  "description": "Web components for ixfx — Lit-based UI toolkit",
7
7
  "author": "Clint Heyer",
@@ -1,3 +0,0 @@
1
- import "./list-native-drag-controller-Brk30s5d.js";
2
- import "./tickled-controller-BVhGKzjZ.js";
3
- import "./tickled-styles-pnieYweS.js";