@ds-mo/ui 14.5.0 → 14.7.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.
Files changed (118) hide show
  1. package/dist/.package-ready.json +1 -1
  2. package/dist/agent-patterns.json +6 -6
  3. package/dist/agent.json +80 -26
  4. package/dist/angular/ds-menu.d.ts +7 -1
  5. package/dist/angular/ds-menu.js +5 -2
  6. package/dist/angular/ds-table.d.ts +4 -1
  7. package/dist/angular/ds-table.js +7 -4
  8. package/dist/angular/ds-tooltip.d.ts +1 -1
  9. package/dist/angular/ds-tooltip.js +4 -3
  10. package/dist/components/ds-agent-questionnaire.js +1 -1
  11. package/dist/components/ds-agent-response.js +1 -1
  12. package/dist/components/ds-banner.js +1 -1
  13. package/dist/components/ds-bar-nav.js +1 -1
  14. package/dist/components/ds-bar-title.js +1 -1
  15. package/dist/components/ds-bar-workflow.js +1 -1
  16. package/dist/components/ds-bar-workflow.js.map +1 -1
  17. package/dist/components/ds-button-unfilled.js +1 -1
  18. package/dist/components/ds-card-chart.js +1 -1
  19. package/dist/components/ds-card-overview.js +1 -1
  20. package/dist/components/ds-card-setting.js +1 -1
  21. package/dist/components/ds-code-block.js +1 -1
  22. package/dist/components/ds-conversation-list-item.js +1 -1
  23. package/dist/components/ds-conversation-list-item.js.map +1 -1
  24. package/dist/components/ds-filter-menu.js +1 -1
  25. package/dist/components/ds-filter-menu.js.map +1 -1
  26. package/dist/components/ds-input.js +1 -1
  27. package/dist/components/ds-markdown.js +1 -1
  28. package/dist/components/ds-menu.js +1 -1
  29. package/dist/components/ds-message-actions.js +1 -1
  30. package/dist/components/ds-message-composer.js +1 -1
  31. package/dist/components/ds-message-scroller.js +1 -1
  32. package/dist/components/ds-mobile-header.js +1 -1
  33. package/dist/components/ds-mobile-section-switcher.js +1 -1
  34. package/dist/components/ds-mobile-sheet-nav.js +1 -1
  35. package/dist/components/ds-modal.js +1 -1
  36. package/dist/components/ds-pagination.js +1 -1
  37. package/dist/components/ds-panel-nav.js +1 -1
  38. package/dist/components/ds-panel-tool-header.js +1 -1
  39. package/dist/components/ds-panel-tool-search.js +1 -1
  40. package/dist/components/ds-panel-tools.js +1 -1
  41. package/dist/components/ds-select.js +1 -1
  42. package/dist/components/ds-shell-app.js +1 -1
  43. package/dist/components/ds-shell-tools.js +1 -1
  44. package/dist/components/ds-table.js +1 -1
  45. package/dist/components/ds-table.js.map +1 -1
  46. package/dist/components/ds-toast.js +1 -1
  47. package/dist/components/ds-tooltip.js +1 -1
  48. package/dist/components/{p-w64TmQd-.js → p--VFa9x3k.js} +2 -2
  49. package/dist/components/{p-o1v7Choa.js → p-B5um-ps9.js} +2 -2
  50. package/dist/components/{p-BiIdszv1.js → p-BAebDW3a.js} +2 -2
  51. package/dist/components/p-BKWgofxz.js +2 -0
  52. package/dist/components/p-BKWgofxz.js.map +1 -0
  53. package/dist/components/p-BXPQmp7q.js +2 -0
  54. package/dist/components/p-BXPQmp7q.js.map +1 -0
  55. package/dist/components/{p-CXqVVdW2.js → p-BmqfTAXM.js} +2 -2
  56. package/dist/components/{p-B2hqUkg-.js → p-C-L4InQ0.js} +2 -2
  57. package/dist/components/{p-BGGm1NB1.js → p-C1jsgfeh.js} +2 -2
  58. package/dist/components/{p-nImbYpwo.js → p-CoQSB3tl.js} +2 -2
  59. package/dist/components/{p-BXNLaPbw.js → p-CvwtYbmh.js} +2 -2
  60. package/dist/components/{p-ohWEVGHg.js → p-D5VglrfF.js} +2 -2
  61. package/dist/components/{p-DkPNCBA8.js → p-D5bPuNiF.js} +2 -2
  62. package/dist/components/{p-Ba1l3Yot.js → p-DOC4RaAy.js} +2 -2
  63. package/dist/components/{p-CvpsV-jC.js → p-DQUxg6Si.js} +2 -2
  64. package/dist/components/{p-Dkkid-rh.js → p-bQm3gfr1.js} +2 -2
  65. package/dist/components/{p-CTTDiW33.js → p-c_5SXjwx.js} +2 -2
  66. package/dist/components/p-c_5SXjwx.js.map +1 -0
  67. package/dist/components/p-mLRtp5A4.js +2 -0
  68. package/dist/components/{p-CRLRjtsc.js.map → p-mLRtp5A4.js.map} +1 -1
  69. package/dist/docs/components.json +315 -16
  70. package/dist/lib/utils/index.d.ts +1 -0
  71. package/dist/lib/utils/index.js +8 -0
  72. package/dist/lib/utils/index.js.map +3 -3
  73. package/dist/lib/utils/is-element-truncated.d.ts +6 -0
  74. package/dist/mcp-data/registry/button-unfilled.json +6 -6
  75. package/dist/mcp-data/registry/menu.json +40 -12
  76. package/dist/mcp-data/registry/registry.json +79 -25
  77. package/dist/mcp-data/registry/table.json +110 -15
  78. package/dist/mcp-data/registry/tooltip.json +68 -7
  79. package/dist/react/ds-menu.d.ts +2 -1
  80. package/dist/react/ds-menu.js +2 -1
  81. package/dist/react/ds-table.d.ts +2 -1
  82. package/dist/react/ds-table.js +2 -1
  83. package/dist/styles/table.css +81 -2
  84. package/dist/types/components/ButtonUnfilled/ButtonUnfilled.d.ts +4 -2
  85. package/dist/types/components/Menu/Menu.d.ts +19 -1
  86. package/dist/types/components/Menu/menu-reorder.d.ts +21 -0
  87. package/dist/types/components/Menu/menu-types.d.ts +12 -0
  88. package/dist/types/components/Table/Table.d.ts +50 -1
  89. package/dist/types/components/Table/index.d.ts +1 -1
  90. package/dist/types/components/Table/table-action-menu.d.ts +15 -0
  91. package/dist/types/components/Table/table-cell-model.d.ts +16 -1
  92. package/dist/types/components/Table/table-column-customizer.d.ts +33 -0
  93. package/dist/types/components/Table/table-truncate.d.ts +6 -0
  94. package/dist/types/components/Table/table-types.d.ts +44 -2
  95. package/dist/types/components/Tooltip/Tooltip.d.ts +15 -0
  96. package/dist/types/components.d.ts +74 -6
  97. package/dist/types/utils/index.d.ts +1 -0
  98. package/dist/types/utils/is-element-truncated.d.ts +7 -0
  99. package/package.json +1 -1
  100. package/dist/components/p-CRLRjtsc.js +0 -2
  101. package/dist/components/p-CTTDiW33.js.map +0 -1
  102. package/dist/components/p-Ccq1RmOb.js +0 -2
  103. package/dist/components/p-Ccq1RmOb.js.map +0 -1
  104. package/dist/components/p-CtOK5oZ1.js +0 -2
  105. package/dist/components/p-CtOK5oZ1.js.map +0 -1
  106. /package/dist/components/{p-w64TmQd-.js.map → p--VFa9x3k.js.map} +0 -0
  107. /package/dist/components/{p-o1v7Choa.js.map → p-B5um-ps9.js.map} +0 -0
  108. /package/dist/components/{p-BiIdszv1.js.map → p-BAebDW3a.js.map} +0 -0
  109. /package/dist/components/{p-CXqVVdW2.js.map → p-BmqfTAXM.js.map} +0 -0
  110. /package/dist/components/{p-B2hqUkg-.js.map → p-C-L4InQ0.js.map} +0 -0
  111. /package/dist/components/{p-BGGm1NB1.js.map → p-C1jsgfeh.js.map} +0 -0
  112. /package/dist/components/{p-nImbYpwo.js.map → p-CoQSB3tl.js.map} +0 -0
  113. /package/dist/components/{p-BXNLaPbw.js.map → p-CvwtYbmh.js.map} +0 -0
  114. /package/dist/components/{p-ohWEVGHg.js.map → p-D5VglrfF.js.map} +0 -0
  115. /package/dist/components/{p-DkPNCBA8.js.map → p-D5bPuNiF.js.map} +0 -0
  116. /package/dist/components/{p-Ba1l3Yot.js.map → p-DOC4RaAy.js.map} +0 -0
  117. /package/dist/components/{p-CvpsV-jC.js.map → p-DQUxg6Si.js.map} +0 -0
  118. /package/dist/components/{p-Dkkid-rh.js.map → p-bQm3gfr1.js.map} +0 -0
@@ -2015,7 +2015,7 @@
2015
2015
  "accessibility": [
2016
2016
  "Provide an explicit accessible name for every icon-only action.",
2017
2017
  "Set hasMenu when the button triggers a Menu; it implies aria-haspopup of menu. Pass controls with the Menu id and expanded from the same open state given to Menu. Expanded popup triggers hold only the pressed wash while open, without changing their resting foreground; expanded disclosure controls without popup semantics retain the normal resting appearance.",
2018
- "Give an icon-only menu button an accessible name that states the role, such as More options, because no visible label or chevron carries it.",
2018
+ "Give an icon-only menu button an accessible name that states the role, such as More options or Customize table, because no visible label or chevron carries it.",
2019
2019
  "Use haspopup directly for a non-menu popup such as a listbox or dialog; those cases get no chevron.",
2020
2020
  "Use pressed only for a genuine toggle button; it supplies aria-pressed and dsChange intent. Use isActive only for owner-controlled visual emphasis inside a composite whose selection semantics live on the owner.",
2021
2021
  "Treat notification dots as supplemental unread or status information; never use a dot as the sole state, meaning, or accessible name.",
@@ -2035,8 +2035,8 @@
2035
2035
  "Rounded changes only the control radius to the half-radius treatment; it does not change hierarchy, size, variant, or interaction semantics.",
2036
2036
  "Physical press scaling is on by default. Disable it only when an owning composite must keep child or background geometry fixed; hover and pressed interaction washes remain available.",
2037
2037
  "Icon and icon-label loading replace the icon in place. Label-only loading centers the loader while preserving the button's measured width.",
2038
- "hasMenu covers two distinct menu-button shapes and the variant selects between them. With label or icon-label the action has a menu, and a trailing chevron carries the affordance. With icon the button is a menu, meaning the overflow or more-options control, and no chevron is added.",
2039
- "Because the icon-only shape has no chevron, its glyph must convey the menu on its own; use Ellipses. Never pair hasMenu with an icon-only glyph that does not read as a menu.",
2038
+ "hasMenu covers two distinct menu-button shapes and the variant selects between them. With label or icon-label the action has a menu, and a trailing chevron carries the affordance. With icon the button is a menu and no chevron is added.",
2039
+ "Because the icon-only shape has no chevron, its glyph must convey the menu on its own. Use Ellipses for a generic more-options or overflow control. Use a specific icon when the menu has a named purpose, such as Preferences for Customize table.",
2040
2040
  "An open popup is a transient pressed state rather than a selected one. While expanded is true and haspopup or hasMenu identifies a popup, the pressed wash is held for the popup's complete rendered lifecycle and survives hover without promoting foreground or selected fill, including when chrome opts out of selected fills with activeFill set to false. Expanded disclosure buttons without popup semantics remain visually neutral."
2041
2041
  ],
2042
2042
  "responsiveBehavior": [
@@ -4605,7 +4605,7 @@
4605
4605
  {
4606
4606
  "name": "menu",
4607
4607
  "title": "Menu",
4608
- "description": "Anchored action menu with flat commands, grouped sections, single-selection choices, supplemental notification dots or trailing tags, switches, and destructive actions.",
4608
+ "description": "Anchored action menu with flat commands, grouped sections, single-selection choices, supplemental notification dots or trailing tags, prefix icons, reorderable rows, switches, and destructive actions.",
4609
4609
  "type": "registry:ui",
4610
4610
  "meta": {
4611
4611
  "library": "@ds-mo/ui",
@@ -4616,10 +4616,10 @@
4616
4616
  "intent": {
4617
4617
  "audience": "general",
4618
4618
  "status": "stable",
4619
- "summary": "Anchored action menu with flat commands, grouped sections, single-selection choices, supplemental notification dots or trailing tags, switches, and destructive actions.",
4619
+ "summary": "Anchored action menu with flat commands, grouped sections, single-selection choices, supplemental notification dots or trailing tags, prefix icons, reorderable rows, switches, and destructive actions.",
4620
4620
  "useWhen": [
4621
4621
  "A trigger reveals a short contextual list of commands or state-changing actions.",
4622
- "Actions need grouping, mutually exclusive selected state, supplemental notification dots or trailing tags, switch rows, or destructive treatment."
4622
+ "Actions need grouping, mutually exclusive selected state, supplemental notification dots or trailing tags, prefix icons, reorderable switch or command rows, or destructive treatment."
4623
4623
  ],
4624
4624
  "avoidWhen": [
4625
4625
  "The user is selecting a value for a form field.",
@@ -4660,17 +4660,21 @@
4660
4660
  "Single-selection menus use menuitemradio semantics and aria-checked on each row, but render no nested radio control; selected interaction fill and primary foreground provide the visual state.",
4661
4661
  "A swatch-picker section changes the popup to a non-modal dialog so its radio group and ordinary preference buttons keep valid nested semantics; Tab moves between its controls, then leaves and closes at the popup boundary.",
4662
4662
  "Use notification dots only as supplemental status and not as the sole indication of important information.",
4663
- "Trailing tags are non-interactive supplemental content; their visible label remains part of the menu item's accessible name."
4663
+ "Trailing tags are non-interactive supplemental content; their visible label remains part of the menu item's accessible name.",
4664
+ "Reorderable rows keep a presentation Drag handle. Pointer drag on the handle and Alt+Arrow Up or Down emit dsReorder without closing. Pointer cancellation abandons the pending move. Hide-locked reorderable rows expose aria-disabled for the unavailable toggle but stay focusable so they can move; fully locked rows stay out of the contiguous reorderable run.",
4665
+ "Announce the new position through a polite live region that is a sibling of the role=menu popup, so the menu retains only permitted descendants."
4664
4666
  ],
4665
4667
  "states": [
4666
4668
  "The host owns open state and responds to selection and close events.",
4667
4669
  "Use either flat items or sections, not both.",
4668
4670
  "After dsSelect from a switch row, replace the items or sections array with updated switchValue data so the controlled indicator reflects the new state.",
4671
+ "After dsReorder, replace items or the affected section with the emitted items array. Menu never mutates order and does not close.",
4669
4672
  "For selectionMode single, keep exactly one item isSelected and replace the items or sections array after dsSelect; Menu never mutates consumer-owned selection data.",
4670
4673
  "Arrays, objects, and element anchors must be assigned as JavaScript properties.",
4671
4674
  "Use a swatch-picker section for a small curated visual preference and apply dsSwatchSelect immediately without closing the popup.",
4672
4675
  "Ordinary rows, section headings, and supporting text consume the Menu size. At xs, both the primary label and supporting text use caption metrics.",
4673
- "A trailing tag resolves one density smaller than its menu row so it nests without changing row height. Do not combine tag, dot, and switch suffixes on one item."
4676
+ "A trailing tag resolves one density smaller than its menu row and uses the inset recipe so it nests without changing row height. Do not combine tag, dot, and switch suffixes on one item.",
4677
+ "Reorderable rows use the Drag prefix and ignore icon. Prefix and drag-handle icons inherit the choice-popup secondary foreground, matching Select. When any row in a section has an icon or is reorderable, the remaining rows get a spacer so labels align."
4674
4678
  ],
4675
4679
  "responsiveBehavior": [
4676
4680
  "Keep the default choice-cell anchor alignment so the first or last interactive row edge aligns with its trigger, matching Select; use popup-frame only for deliberate custom frame geometry.",
@@ -4679,13 +4683,14 @@
4679
4683
  ],
4680
4684
  "frameworkCaveats": {
4681
4685
  "customElements": [
4682
- "Assign items, sections, and HTMLElement anchors as properties after the element is defined."
4686
+ "Assign items, sections, and HTMLElement anchors as properties after the element is defined.",
4687
+ "Handle dsReorder by replacing the items or section items with the emitted items array; Menu never mutates order."
4683
4688
  ],
4684
4689
  "react": [
4685
- "Pass arrays and objects as wrapper props and handle generated onDsSelect and onDsClose event props."
4690
+ "Pass arrays and objects as wrapper props and handle generated onDsSelect, onDsReorder, and onDsClose event props."
4686
4691
  ],
4687
4692
  "angular": [
4688
- "Use property bindings for arrays, objects, and anchors and event bindings for dsSelect and dsClose."
4693
+ "Use property bindings for arrays, objects, and anchors and event bindings for dsSelect, dsReorder, and dsClose."
4689
4694
  ]
4690
4695
  },
4691
4696
  "references": [
@@ -4774,6 +4779,10 @@
4774
4779
  "name": "dsClose",
4775
4780
  "detail": "void"
4776
4781
  },
4782
+ {
4783
+ "name": "dsReorder",
4784
+ "detail": "MenuReorderDetail"
4785
+ },
4777
4786
  {
4778
4787
  "name": "dsSelect",
4779
4788
  "detail": "MenuItemData"
@@ -4792,10 +4801,12 @@
4792
4801
  },
4793
4802
  "dependencies": [
4794
4803
  "@ds-mo/ui",
4795
- "@ds-mo/tokens"
4804
+ "@ds-mo/tokens",
4805
+ "@ds-mo/icons"
4796
4806
  ],
4797
4807
  "registryDependencies": [
4798
4808
  "badge",
4809
+ "icon",
4799
4810
  "swatch-picker",
4800
4811
  "switch",
4801
4812
  "tag",
@@ -8831,7 +8842,7 @@
8831
8842
  "summary": "Semantic, controlled data table with durable visual primitives for cell geometry, grouping, sorting, multi-selection, sticky overflow, incremental loading, and top-level pagination.",
8832
8843
  "useWhen": [
8833
8844
  "A structured dataset needs native row and column relationships, optional one-level grouping, or comparable values across records.",
8834
- "An application needs controlled sorting, loaded-row selection, infinite loading, or pagination while retaining ownership of the data query and transformations.",
8845
+ "An application needs controlled sorting, loaded-row selection, infinite loading, pagination, or an opted-in table-owned column customizer while retaining ownership of the data query, catalog, and persistence.",
8835
8846
  "A product table needs a token-backed recipe whose individual header, group, row, cell, selection, state, and load-more layers remain easy to restyle."
8836
8847
  ],
8837
8848
  "avoidWhen": [
@@ -8847,21 +8858,28 @@
8847
8858
  "component:ds-pagination",
8848
8859
  "component:ds-bar-action",
8849
8860
  "component:ds-button-unfilled",
8861
+ "component:ds-menu",
8862
+ "component:ds-tooltip",
8850
8863
  "component:ds-tag",
8851
8864
  "component:ds-icon"
8852
8865
  ],
8866
+ "patterns": [
8867
+ "pattern:menu-trigger"
8868
+ ],
8853
8869
  "accessibility": [
8854
- "The rendered structure uses a native table, caption, column headers, row groups, and data cells; keep the caption non-empty. The native caption remains visually hidden as the table's accessible name. When caption visibility is enabled, a 48px header bar renders as component chrome outside the horizontal scrollport. It defaults to a presentational caption title that does not duplicate the accessible name. Application-owned labeled controls supplied through the single named header slot replace that fallback and receive the complete content width inside the component-owned 8px inset, so the application can compose its own control groups and alignment without table-defined leading or trailing zones.",
8870
+ "The rendered structure uses a native table, caption, column headers, row groups, and data cells; keep the caption non-empty. The native caption remains visually hidden as the table's accessible name. When caption visibility is enabled, a 48px header bar renders as component chrome outside the horizontal scrollport. It defaults to a presentational caption title that does not duplicate the accessible name. Application-owned labeled controls supplied through the single named header slot replace that fallback and occupy the leading content width inside the component-owned 8px inset. When columnCustomizer is enabled, the table adds a trailing Preferences control named Customize table; otherwise the header slot receives the complete content width.",
8871
+ "The column customizer is the shared Menu of switch rows, not a table-owned dialog. Data columns can be shown, hidden, and reordered. Locked action columns stay visible, inactive, and last. The selection checkbox is not a column and never appears. The last remaining visible data column cannot be hidden, but it stays focusable so it can still be reordered. Escape and outside click restore focus to the trigger. Persistence stays in the application.",
8855
8872
  "Sorting controls remain buttons inside column headers and expose the table's one controlled member-row sort through aria-sort. Grouping never adds a second sort indicator or header control; the application supplies groups in its fixed product order.",
8856
8873
  "Selection controls expose checkbox semantics and explicit row names; select-all affects selectable loaded rows only and preserves selected identities outside the loaded window. When grouping is active with multi-selection, each group section header also exposes a checkbox that selects or clears that group's selectable loaded rows.",
8857
- "Interactive rows are focusable as native rows, activate with Enter or Space, and do not steal activation from their nested selection, action, or primary-text link controls.",
8874
+ "Interactive rows are focusable as native rows, activate with Enter or Space, and do not steal activation from their nested selection, action, overflow-menu, or primary-text link controls.",
8858
8875
  "Scrollable table regions become keyboard focusable and named only when overflow exists.",
8859
8876
  "Incremental loading, newly appended row counts, failures, and end-of-results transitions are announced through a polite status region without replacing visible state. In grouped tables, announcements name the independently loading group.",
8860
8877
  "Static and infinite tables may show an optional result summary footer when displayedCount and totalCount are finite. Pagination mode instead renders a named Pagination control with a compact selected-size total, vertical divider, and page position; range changes are announced independently with complete phrasing. While focus is anywhere inside a paginated table, unmodified Left and Right Arrow request the adjacent page; editable fields, choice controls, sliders, and modified key combinations retain their own keyboard behavior. The footer slot can replace summary copy, while footer-leading and footer-trailing remain available in the same compact-bar anatomy."
8861
8878
  ],
8862
8879
  "states": [
8863
- "Columns, rows, groups, grouping, sorting, selected row IDs, collapsed group IDs, dataMode, pagination, displayedCount, totalCount, and incremental-loading state are controlled inputs. Events communicate intent and never mutate those inputs. The optional header is one full-width composable table-local surface: the component owns its 48px chrome, 8px inset on every side, and sticky placement while the application owns all internal layout, controls, labels, filtering behavior, and action handling. The footer retains its compact-bar composition: application-owned leading status sits left while a controlled result summary or Pagination aligns right, before any trailing action. Content-sized tables remain natural for sparse or fixed-count results. height bounds the complete header, frame, and footer composition. fitViewport reserves the compact-state composition height in the nearest vertical scrollport while growing the visible table into that reservation as surrounding page chrome collapses.",
8880
+ "Columns, rows, groups, grouping, sorting, selected row IDs, collapsed group IDs, hiddenColumnIds, columnOrder, dataMode, pagination, displayedCount, totalCount, and incremental-loading state are controlled inputs. Events communicate intent and never mutate those inputs. The optional header is one composable table-local surface: the component owns its 48px chrome, 8px inset on every side, and sticky placement while the application owns the leading slot's internal layout, controls, labels, filtering behavior, and action handling. Opting into columnCustomizer adds a trailing Customize table Menu trigger and requires caption visibility. The footer retains its compact-bar composition: application-owned leading status sits left while a controlled result summary or Pagination aligns right, before any trailing action. Content-sized tables remain natural for sparse or fixed-count results. height bounds the complete header, frame, and footer composition. fitViewport reserves the compact-state composition height in the nearest vertical scrollport while growing the visible table into that reservation as surrounding page chrome collapses.",
8864
8881
  "Grouping supports one level. The application supplies groups in a fixed product-defined order and supplies ordered member rows independently. Group section headers show an emphasized text-body-medium label followed by a middle dot and plain secondary loaded progress, for example Critical · 50 of 166. The loaded value comes from the supplied member rows and the total comes from totalCount. A localized countLabel total phrase remains available for the complete assistive progress announcement. Groups may declare an optional intent (brand, neutral, negative, warning, caution, positive) that paints an LTR gradient from the faint intent surface at the label edge into faint neutral at the trailing edge, plus a bold intent title color. Neutral groups remain solid faint neutral. Section separators are painted inside that viewport-width surface so translucent border tokens composite with each intent background. Internal sections keep their separators; a collapsed or empty section header yields its separator only when it is the table's final rendered item. A trailing visually neutral icon-only ButtonUnfilled uses the 24px md double-inset action recipe and toggles controlled collapsedGroupIds, showing ChevronUp while expanded and ChevronDown while collapsed. While any group is expanded, a ChevronDownUp action uses the xs sort-control recipe widened to a table-owned 24px lane and collapses every group. It appears at the inline-end edge of the trailing column declared with kind action when one exists; otherwise a button-hugging 24px by 16px medium-elevation surface floats at the visible scrollport's header edge so the action remains reachable while member columns scroll beneath it. With stickyHeader enabled, each contained section uses its one real section row as a native sticky header inside its real row-group boundary. The browser therefore owns pinning, push-off, scrolling, and resize layout in one pass without a duplicated lane, active-section state, transforms, or scroll-time geometry. Shared grid tracks retain exact header and member-cell alignment. The section surface also stays pinned to the visible horizontal scrollport and spans the smaller of the visible viewport or table width.",
8882
+ "When columnCustomizer is false, columns render in catalog order. When it is true, columns remains the catalog: hiddenColumnIds and columnOrder control visibility and data-column sequence, action columns stay last and cannot be hidden, and dsColumnsConfigChange reports the next hidden ids and data-column order without mutating those inputs. The customizer Menu live-applies show/hide and data-column reorder. The table does not persist preferences.",
8865
8883
  "An active member sort toggles only between ascending and descending; activating a different sortable label moves the one sorting state to that key. Applications may still clear the controlled sort state explicitly. Grouping does not introduce another interactive direction.",
8866
8884
  "Compound headers can expose multiple related labels with independent sort keys. Each label owns only its content-width interaction target while the active direction remains in the column's alignment-aware sort lane.",
8867
8885
  "Initial loading defaults to ten row-shaped skeletons and preserves row dividers, column dividers, selection lanes, and sticky boundaries. A selectable table renders a checkbox-sized control skeleton in its selection lane so loading geometry matches the real checkbox instead of a generic icon. Each column may declare representative text, multiline text, image, Tag, icon, icon-and-text, action, or intentionally blank loading geometry; the table applies the matching resolved-cell padding and track anatomy so the placeholder row has the same height and rhythm as its data row. Columns without a declaration use one text line, while action columns infer an icon action placeholder. Empty, initial error, load-more, retry, loading-more, and terminal bands remain fixed to the visible table width while data columns scroll horizontally beneath them. Incremental loading retains existing rows and supports automatic sentinel, manual load-more, retry, and terminal states. When grouping is active, each expanded group owns its load band at the end of its member rows; internal group load bands keep their bottom divider, while a terminal group load band yields it to the table edge or footer. The global bottom-of-table loader is not rendered.",
@@ -8869,7 +8887,7 @@
8869
8887
  "When pagination enables Fit to page on a bounded table, the table proposes the number of complete top-level rows that fit below its column header. Grouped tables count group headers only; member rows never affect capacity. Selecting Fit captures that numeric snapshot. A changed fitIdentity requests one fresh snapshot for a new query shape, while viewport resizing alone does not change the active controlled page size.",
8870
8888
  "Rows opt into complete-row activation with interactive and emit dsRowActivate without owning navigation. Selection paints through the shared selected ::before layer; interactive hover and press paint through the shared ::after layer.",
8871
8889
  "Row selection owns the single sticky start lane. One explicitly sized application column can own the sticky end lane, or the start lane when selection is absent. Each sticky boundary owns one fixed divider and a row-clipped directional shadow that paints into the adjacent scrolling columns only while more inline content remains beyond that edge.",
8872
- "Cells accept scalar content, standard primary-and-secondary or dual-primary text primitives, declarative Tag, icon-only, icon-and-text, 16:9 Image, or ButtonUnfilled Action content, or explicit Empty and Blank absence values. Text objects may declare an optional href (and target) on the primary track only; the table renders a native anchor with the shared brand text-action treatment when the URL is safe, and leaves scalars unlinked. Standard secondary copy defaults to the secondary foreground and may declare a semantic Text color when the application data carries intent; an optional tertiary track uses the same subdued body-small recipe as secondary. Secondary and tertiary may also be a short list of colorable runs, rendered on one line with the table's middle-dot separator. Dual-primary copy keeps both tracks primary unless explicitly colored and does not gain a tertiary track. Body data cells share 8px outer padding; header and group rows keep their own geometry. Text tracks, including Empty, keep 4px inline padding so copy lines up with column-header labels; Tag and icon-only tracks stay on the 8px cell chrome alone. Icon-and-text cells (`kind: 'icon-text'`) place one md prefix icon beside the same copy stack as a text cell. The icon slot takes 2px padding on every side, then a 2px flex gap before the copy; text-track padding stays on the copy. Omit iconLabel when the glyph is decorative. 20px content (body-medium text, md icon, and the row checkbox) sits in a 24px track so it stays optically aligned with 24px Tag and Action content. Single-track text, selection, tag-only, icon-only, icon-and-text, Action, Empty, Blank, and 1-track Image cells resolve a 40px base contract while two-track cells grow to 62px and three-track cells grow to 84px. Tracks stack with a 2px gap. Keep the same track count in every row of a table or group when those rows should share one height. Tag cells use the inset Tag recipe: md double-inset is a 24px control for tag-only and tag-with-text, while text-with-tag uses sm single-inset at 20px so the second-track pill fills the body-small slot. Action cells primarily use an icon-only Ellipses treatment, render a 24px small ButtonUnfilled, default to unbordered, and emit row, column, and action identities through dsCellAction. Image cells declare tracks 1, 2, or 3 so the 16:9 bordered preview fills that body-row content box (cell height minus 8px padding) and the column hugs the resulting width; omit tracks for the 1-track recipe, and keep image tracks aligned with the other cells in the table or group. Image cells fall back to an accessible placeholder when no source is supplied. Empty means the data applies but has no value and renders an em dash with localized assistive text; Blank means the data is not applicable and renders no content. Nullish values remain backward-compatible Empty values. Stable type and variant hooks keep every cell family independently styleable.",
8890
+ "Cells accept scalar content, standard primary-and-secondary or dual-primary text primitives, declarative Tag, icon-only, icon-and-text, 16:9 Image, or ButtonUnfilled Action content, or explicit Empty and Blank absence values. Text objects may declare an optional href (and target) on the primary track only; the table renders a native anchor with the shared brand text-action treatment when the URL is safe, and leaves scalars unlinked. Standard secondary copy defaults to the secondary foreground and may declare a semantic Text color when the application data carries intent; an optional tertiary track uses the same subdued body-small recipe as secondary. Secondary and tertiary may also be a short list of colorable runs, rendered on one line with the table's middle-dot separator. Dual-primary copy keeps both tracks primary unless explicitly colored and does not gain a tertiary track. Body data cells share 8px outer padding; header and group rows keep their own geometry. Text tracks, including Empty, keep 4px inline padding so copy lines up with column-header labels; Tag and icon-only tracks stay on the 8px cell chrome alone. Icon-and-text cells (`kind: 'icon-text'`) place one md prefix icon beside the same copy stack as a text cell. The icon slot takes 2px padding on every side, then a 2px flex gap before the copy; text-track padding stays on the copy. Omit iconLabel when the glyph is decorative. 20px content (body-medium text, md icon, and the row checkbox) sits in a 24px track so it stays optically aligned with 24px Tag and Action content. Single-track text, selection, tag-only, icon-only, icon-and-text, Action, Empty, Blank, and 1-track Image cells resolve a 40px base contract while two-track cells grow to 62px and three-track cells grow to 84px. Tracks stack with a 2px gap. Wrapping primary on a 1-track cell uses that same rhythm: two wrapped lines share the 62px row and three wrapped lines share the 84px row. Wrapping secondary keeps primary on the first track and consumes later tracks: two secondary lines share the 84px row and three secondary lines share a 106px fourth track. Keep the same track count in every row of a table or group when those rows should share one height. Tag cells use the inset Tag recipe: md double-inset is a 24px control for tag-only and tag-with-text, while text-with-tag uses sm single-inset at 20px so the second-track pill fills the body-small slot. Action cells primarily use an icon-only Ellipses treatment, render a 24px small ButtonUnfilled, default to unbordered, and emit row, column, and action identities through dsCellAction. When an action cell declares items, that Ellipses trigger opens the shared ds-menu for commands, dividers, inactive rows, and destructive rows instead of emitting on click; choosing a command emits dsCellAction with that item's actionId. Omit items to keep a single-shot control. Image cells declare tracks 1, 2, or 3 so the 16:9 bordered preview fills that body-row content box (cell height minus 8px padding) and the column hugs the resulting width; omit tracks for the 1-track recipe, and keep image tracks aligned with the other cells in the table or group. Image cells fall back to an accessible placeholder when no source is supplied. Empty means the data applies but has no value and renders an em dash with localized assistive text; Blank means the data is not applicable and renders no content. Nullish values remain backward-compatible Empty values. Stable type and variant hooks keep every cell family independently styleable.",
8873
8891
  "The public @ds-mo/ui/table.css export is the authoritative zero-specificity visual recipe. Override its --ds-table-* properties or target its stable element classes for product-specific styling."
8874
8892
  ],
8875
8893
  "responsiveBehavior": [
@@ -8880,16 +8898,19 @@
8880
8898
  "Explicit column sizes establish the horizontal overflow width; unsized columns share remaining space.",
8881
8899
  "Prefer the named xs through xl column sizes, which resolve through TokoMo's table-column width tokens; numeric pixel sizes remain an escape hatch for exceptional application-owned widths.",
8882
8900
  "Column headers use one 32px geometry. Body rows use a 40px single-track minimum with shared 8px cell padding; additional tracks grow downward. Image previews fill the same content box as their declared track count. The second text track and the third text track share one subdued body-small recipe so line 3 lines up with line 2.",
8883
- "Long content truncates by default and can opt into wrapping at the column or cell level."
8901
+ "Long content truncates to one line by default. Hover (or keyboard-focus a primary link) shows the omitted value in one table-owned tooltip when that track overflows. maxLines 2 or 3 wrap onto the named 2-track and 3-track row heights, then ellipsize with the same tooltip. wrap: true remains unlimited and does not show a truncation tooltip. Wrapping 1-track primary occupies the named 2-track and 3-track row heights instead of a private line-height scale. Wrapping secondary on a 2-track cell occupies the named 3-track row and a 106px fourth track for three lines."
8884
8902
  ],
8885
8903
  "frameworkCaveats": {
8886
8904
  "customElements": [
8887
- "Assign columns, rows, groups, grouping, sort, selectedRowIds, collapsedGroupIds, pagination, displayedCount, and totalCount through JavaScript properties rather than HTML attribute strings.",
8888
- "Replace controlled property values in response to dsSortChange, dsGroupCollapseChange, dsSelectionChange, dsLoadMore, dsGroupLoadMore, and dsPaginationChange; route dsRowActivate in the application owner."
8905
+ "Assign columns, rows, groups, grouping, sort, selectedRowIds, collapsedGroupIds, hiddenColumnIds, columnOrder, pagination, displayedCount, and totalCount through JavaScript properties rather than HTML attribute strings.",
8906
+ "When an action cell supplies items, the table opens one shared ds-menu from the Ellipses trigger; dsCellAction fires for the selected command, not for opening or closing the menu.",
8907
+ "When columnCustomizer is enabled, the Preferences trigger opens the same shared ds-menu of reorderable switch rows; toggling a switch or reordering a row emits dsColumnsConfigChange and does not close the menu.",
8908
+ "Overflowing text tracks present one shared ds-tooltip with the omitted value. Unlimited wrapping tracks and disabled rows never show it. The tooltip is not linked with aria-describedby because the full string remains in the cell.",
8909
+ "Replace controlled property values in response to dsSortChange, dsGroupCollapseChange, dsSelectionChange, dsLoadMore, dsGroupLoadMore, dsPaginationChange, and dsColumnsConfigChange; route dsRowActivate in the application owner. When columnCustomizer is enabled, keep columns as the full catalog and replace hiddenColumnIds and columnOrder from that event."
8889
8910
  ],
8890
8911
  "react": [
8891
8912
  "Pass new array and state-object references when the controlled data or query state changes.",
8892
- "Apply emitted sort, collapse, selection, action, pagination, or global/group loading detail to application state and perform data transformations in the owning layer."
8913
+ "Apply emitted sort, collapse, selection, action, pagination, column-customizer, or global/group loading detail to application state and perform data transformations in the owning layer."
8893
8914
  ],
8894
8915
  "angular": [
8895
8916
  "Bind complex table inputs as properties and update the controlled values from the corresponding output events.",
@@ -8904,6 +8925,10 @@
8904
8925
  {
8905
8926
  "label": "Public visual recipe",
8906
8927
  "path": "src/wc/styles/table.css"
8928
+ },
8929
+ {
8930
+ "label": "Menu trigger composition",
8931
+ "path": "agent/patterns/menu-trigger/pattern.agent.json"
8907
8932
  }
8908
8933
  ]
8909
8934
  },
@@ -8920,6 +8945,14 @@
8920
8945
  "type": "string[]",
8921
8946
  "required": false
8922
8947
  },
8948
+ "columnCustomizer": {
8949
+ "type": "boolean",
8950
+ "required": false
8951
+ },
8952
+ "columnOrder": {
8953
+ "type": "string[]",
8954
+ "required": false
8955
+ },
8923
8956
  "columns": {
8924
8957
  "type": "TableColumn[]",
8925
8958
  "required": false
@@ -9004,6 +9037,10 @@
9004
9037
  "type": "string | number | undefined",
9005
9038
  "required": false
9006
9039
  },
9040
+ "hiddenColumnIds": {
9041
+ "type": "string[]",
9042
+ "required": false
9043
+ },
9007
9044
  "loadIdentity": {
9008
9045
  "type": "string | number",
9009
9046
  "required": false
@@ -9102,6 +9139,10 @@
9102
9139
  "name": "dsCellAction",
9103
9140
  "detail": "TableCellActionDetail"
9104
9141
  },
9142
+ {
9143
+ "name": "dsColumnsConfigChange",
9144
+ "detail": "TableColumnsConfigChangeDetail"
9145
+ },
9105
9146
  {
9106
9147
  "name": "dsGroupCollapseChange",
9107
9148
  "detail": "TableGroupCollapseChangeDetail"
@@ -9149,10 +9190,12 @@
9149
9190
  "empty-state",
9150
9191
  "icon",
9151
9192
  "loader",
9193
+ "menu",
9152
9194
  "pagination",
9153
9195
  "skeleton",
9154
9196
  "tag",
9155
- "text"
9197
+ "text",
9198
+ "tooltip"
9156
9199
  ]
9157
9200
  },
9158
9201
  {
@@ -9695,12 +9738,13 @@
9695
9738
  "component:ds-button-filled",
9696
9739
  "component:ds-button-unfilled",
9697
9740
  "component:ds-panel-nav",
9698
- "component:ds-panel-tools"
9741
+ "component:ds-panel-tools",
9742
+ "component:ds-table"
9699
9743
  ],
9700
9744
  "accessibility": [
9701
9745
  "The slotted trigger must have its own accessible name, usually an aria-label that closely matches the visual tooltip label.",
9702
9746
  "Tooltip content is supplementary and non-essential; touch input intentionally does not open it.",
9703
- "While open, the trigger is linked to the role=tooltip popup with aria-describedby; the relationship is removed when the popup leaves the DOM without disturbing consumer description IDs.",
9747
+ "While open, the trigger is linked to the role=tooltip popup with aria-describedby by default; the relationship is removed when the popup leaves the DOM without disturbing consumer description IDs. Hosts that already expose the full string, such as a truncated table cell, disable that relationship.",
9704
9748
  "Keyboard focus opens the tooltip and Escape dismisses it without moving focus."
9705
9749
  ],
9706
9750
  "states": [
@@ -9708,18 +9752,20 @@
9708
9752
  "An empty or whitespace-only label suppresses the popup while preserving the wrapper.",
9709
9753
  "Only one tooltip remains active globally; warm handoff removes the previous popup before showing the next.",
9710
9754
  "Disconnecting and reinserting the tooltip host rebinds the current slotted trigger.",
9755
+ "A host may present the popup against an external anchor it already owns, without wrapping that trigger or binding hover on it.",
9711
9756
  "The preferred side flips when it cannot fit, then alignment is clamped to viewport padding.",
9712
9757
  "Reduced motion removes enter and exit fades while retaining the final visible or hidden state."
9713
9758
  ],
9714
9759
  "responsiveBehavior": [
9715
9760
  "The portaled popup follows trigger and popup resize, viewport resize, and nested scrolling while open.",
9716
9761
  "Touch users rely on the trigger's accessible and visible context rather than tooltip disclosure.",
9717
- "Keep labels concise and non-wrapping; use inline text or a larger disclosure component for essential explanation."
9762
+ "Keep labels concise and non-wrapping by default; omitted table cell values may wrap at panel-xs."
9718
9763
  ],
9719
9764
  "frameworkCaveats": {
9720
9765
  "customElements": [
9721
9766
  "Place exactly one trigger element as the component's light-DOM child.",
9722
9767
  "Replacing the slotted trigger rebinds pointer and focus behavior automatically.",
9768
+ "A table or similar host can present the popup against an overflowing text node instead of wrapping that node.",
9723
9769
  "sideOffset, alignOffset, and delay accept numbers or TokoMo CSS values."
9724
9770
  ],
9725
9771
  "react": [
@@ -9757,6 +9803,10 @@
9757
9803
  "type": "number | string",
9758
9804
  "required": false
9759
9805
  },
9806
+ "describedBy": {
9807
+ "type": "boolean",
9808
+ "required": false
9809
+ },
9760
9810
  "label": {
9761
9811
  "type": "string",
9762
9812
  "required": true
@@ -9780,6 +9830,10 @@
9780
9830
  "size": {
9781
9831
  "type": "TooltipSize",
9782
9832
  "required": false
9833
+ },
9834
+ "wrapLabel": {
9835
+ "type": "boolean",
9836
+ "required": false
9783
9837
  }
9784
9838
  },
9785
9839
  "events": [],