@viax.io/uxm 4.39.0 → 4.40.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 (122) hide show
  1. package/CHANGELOG.md +12 -0
  2. package/LICENSE.md +21 -0
  3. package/README.md +33 -44
  4. package/dist/hooks/index.cjs.map +1 -1
  5. package/dist/hooks/index.d.ts +1 -1
  6. package/dist/hooks/index.js.map +1 -1
  7. package/dist/index.cjs.map +1 -1
  8. package/dist/index.d.ts +3 -3
  9. package/dist/index.js.map +1 -1
  10. package/dist/previews/index.cjs.map +1 -1
  11. package/dist/previews/index.d.ts +2 -2
  12. package/dist/previews/index.js.map +1 -1
  13. package/dist/studio/index.cjs.map +1 -1
  14. package/dist/studio/index.d.ts +2 -2
  15. package/dist/studio/index.js.map +1 -1
  16. package/dist/studio/lib/registry/buttons.cjs +2 -2
  17. package/dist/studio/lib/registry/buttons.cjs.map +1 -1
  18. package/dist/studio/lib/registry/buttons.js +2 -2
  19. package/dist/studio/lib/registry/buttons.js.map +1 -1
  20. package/dist/studio/lib/registry/composite/sidebar-nav-trigger.cjs +1 -1
  21. package/dist/studio/lib/registry/composite/sidebar-nav-trigger.cjs.map +1 -1
  22. package/dist/studio/lib/registry/composite/sidebar-nav-trigger.js +1 -1
  23. package/dist/studio/lib/registry/composite/sidebar-nav-trigger.js.map +1 -1
  24. package/dist/studio/lib/registry/diagram.cjs +1 -1
  25. package/dist/studio/lib/registry/diagram.cjs.map +1 -1
  26. package/dist/studio/lib/registry/diagram.js +1 -1
  27. package/dist/studio/lib/registry/diagram.js.map +1 -1
  28. package/dist/studio/lib/registry/display.cjs +2 -2
  29. package/dist/studio/lib/registry/display.cjs.map +1 -1
  30. package/dist/studio/lib/registry/display.js +2 -2
  31. package/dist/studio/lib/registry/display.js.map +1 -1
  32. package/dist/studio/lib/registry/feedback.cjs +3 -3
  33. package/dist/studio/lib/registry/feedback.cjs.map +1 -1
  34. package/dist/studio/lib/registry/feedback.js +3 -3
  35. package/dist/studio/lib/registry/feedback.js.map +1 -1
  36. package/dist/studio/lib/registry/inputs/color-input.cjs +1 -1
  37. package/dist/studio/lib/registry/inputs/color-input.cjs.map +1 -1
  38. package/dist/studio/lib/registry/inputs/color-input.js +1 -1
  39. package/dist/studio/lib/registry/inputs/color-input.js.map +1 -1
  40. package/dist/studio/lib/registry/inputs/currency-input.cjs +1 -1
  41. package/dist/studio/lib/registry/inputs/currency-input.cjs.map +1 -1
  42. package/dist/studio/lib/registry/inputs/currency-input.js +1 -1
  43. package/dist/studio/lib/registry/inputs/currency-input.js.map +1 -1
  44. package/dist/studio/lib/registry/inputs/editable-cell.cjs +1 -1
  45. package/dist/studio/lib/registry/inputs/editable-cell.cjs.map +1 -1
  46. package/dist/studio/lib/registry/inputs/editable-cell.js +1 -1
  47. package/dist/studio/lib/registry/inputs/editable-cell.js.map +1 -1
  48. package/dist/studio/lib/registry/inputs/file-upload.cjs +1 -1
  49. package/dist/studio/lib/registry/inputs/file-upload.cjs.map +1 -1
  50. package/dist/studio/lib/registry/inputs/file-upload.js +1 -1
  51. package/dist/studio/lib/registry/inputs/file-upload.js.map +1 -1
  52. package/dist/studio/lib/registry/inputs/input-text.cjs +1 -1
  53. package/dist/studio/lib/registry/inputs/input-text.cjs.map +1 -1
  54. package/dist/studio/lib/registry/inputs/input-text.js +1 -1
  55. package/dist/studio/lib/registry/inputs/input-text.js.map +1 -1
  56. package/dist/studio/lib/registry/inputs/listbox.cjs +1 -1
  57. package/dist/studio/lib/registry/inputs/listbox.cjs.map +1 -1
  58. package/dist/studio/lib/registry/inputs/listbox.js +1 -1
  59. package/dist/studio/lib/registry/inputs/listbox.js.map +1 -1
  60. package/dist/studio/lib/registry/inputs/menu.cjs +1 -1
  61. package/dist/studio/lib/registry/inputs/menu.cjs.map +1 -1
  62. package/dist/studio/lib/registry/inputs/menu.js +1 -1
  63. package/dist/studio/lib/registry/inputs/menu.js.map +1 -1
  64. package/dist/studio/lib/registry/inputs/number-input.cjs +1 -1
  65. package/dist/studio/lib/registry/inputs/number-input.cjs.map +1 -1
  66. package/dist/studio/lib/registry/inputs/number-input.js +1 -1
  67. package/dist/studio/lib/registry/inputs/number-input.js.map +1 -1
  68. package/dist/studio/lib/registry/inputs/password-input.cjs +1 -1
  69. package/dist/studio/lib/registry/inputs/password-input.cjs.map +1 -1
  70. package/dist/studio/lib/registry/inputs/password-input.js +1 -1
  71. package/dist/studio/lib/registry/inputs/password-input.js.map +1 -1
  72. package/dist/studio/lib/registry/inputs/phone-input.cjs +1 -1
  73. package/dist/studio/lib/registry/inputs/phone-input.cjs.map +1 -1
  74. package/dist/studio/lib/registry/inputs/phone-input.js +1 -1
  75. package/dist/studio/lib/registry/inputs/phone-input.js.map +1 -1
  76. package/dist/studio/lib/registry/inputs/slider.cjs +1 -1
  77. package/dist/studio/lib/registry/inputs/slider.cjs.map +1 -1
  78. package/dist/studio/lib/registry/inputs/slider.js +1 -1
  79. package/dist/studio/lib/registry/inputs/slider.js.map +1 -1
  80. package/dist/studio/lib/registry/inputs/time-input.cjs +1 -1
  81. package/dist/studio/lib/registry/inputs/time-input.cjs.map +1 -1
  82. package/dist/studio/lib/registry/inputs/time-input.js +1 -1
  83. package/dist/studio/lib/registry/inputs/time-input.js.map +1 -1
  84. package/dist/studio/lib/types.cjs.map +1 -1
  85. package/dist/studio/persistence/generate-css.cjs.map +1 -1
  86. package/dist/studio/persistence/generate-css.js.map +1 -1
  87. package/dist/ui/editable-cell/editable-cell-date.cjs +226 -0
  88. package/dist/ui/editable-cell/editable-cell-date.cjs.map +1 -0
  89. package/dist/ui/editable-cell/editable-cell-date.d.ts +4 -0
  90. package/dist/ui/editable-cell/editable-cell-date.d.ts.map +1 -0
  91. package/dist/ui/editable-cell/editable-cell-date.js +202 -0
  92. package/dist/ui/editable-cell/editable-cell-date.js.map +1 -0
  93. package/dist/ui/editable-cell/editable-cell-select.cjs +297 -0
  94. package/dist/ui/editable-cell/editable-cell-select.cjs.map +1 -0
  95. package/dist/ui/editable-cell/editable-cell-select.d.ts +4 -0
  96. package/dist/ui/editable-cell/editable-cell-select.d.ts.map +1 -0
  97. package/dist/ui/editable-cell/editable-cell-select.js +273 -0
  98. package/dist/ui/editable-cell/editable-cell-select.js.map +1 -0
  99. package/dist/ui/editable-cell/editable-cell-text.cjs +175 -0
  100. package/dist/ui/editable-cell/editable-cell-text.cjs.map +1 -0
  101. package/dist/ui/editable-cell/editable-cell-text.d.ts +4 -0
  102. package/dist/ui/editable-cell/editable-cell-text.d.ts.map +1 -0
  103. package/dist/ui/editable-cell/editable-cell-text.js +151 -0
  104. package/dist/ui/editable-cell/editable-cell-text.js.map +1 -0
  105. package/dist/ui/editable-cell/editable-cell.cjs +27 -705
  106. package/dist/ui/editable-cell/editable-cell.cjs.map +1 -1
  107. package/dist/ui/editable-cell/editable-cell.d.ts +1 -1
  108. package/dist/ui/editable-cell/editable-cell.d.ts.map +1 -1
  109. package/dist/ui/editable-cell/editable-cell.js +28 -706
  110. package/dist/ui/editable-cell/editable-cell.js.map +1 -1
  111. package/dist/ui/editable-cell/use-editable-cell.cjs +284 -0
  112. package/dist/ui/editable-cell/use-editable-cell.cjs.map +1 -0
  113. package/dist/ui/editable-cell/use-editable-cell.d.ts +51 -0
  114. package/dist/ui/editable-cell/use-editable-cell.d.ts.map +1 -0
  115. package/dist/ui/editable-cell/use-editable-cell.js +260 -0
  116. package/dist/ui/editable-cell/use-editable-cell.js.map +1 -0
  117. package/dist/ui/page-shell/page-shell.cjs.map +1 -1
  118. package/dist/ui/page-shell/page-shell.d.ts +1 -1
  119. package/dist/ui/page-shell/page-shell.d.ts.map +1 -1
  120. package/dist/ui/page-shell/page-shell.js.map +1 -1
  121. package/dist/ui/styles.css +1 -1
  122. package/package.json +5 -5
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../../../src/studio/lib/registry/inputs/input-text.ts"],"sourcesContent":["import type { ComponentDef } from '../../types';\n\nexport const inputTextDef: ComponentDef = {\n id: 'input-text',\n name: 'Text Input',\n category: 'Inputs',\n description: 'Standard text input field with label. State knobs cover default / hover / focus / disabled / error — error replaces the previous standalone `Input with Error` atom (one tone surface, one shape surface).',\n styleProperties: [\n // Default\n { key: 'backgroundColor', label: 'Background', control: 'color', defaultValue: 'var(--color-card)', section: 'fieldColors', showWhen: { state: 'default' } },\n { key: 'borderColor', label: 'Border', control: 'color', defaultValue: 'var(--color-border)', section: 'fieldColors', showWhen: { state: 'default' } },\n { key: 'color', label: 'Text', control: 'color', defaultValue: 'var(--color-text)', section: 'fieldColors', showWhen: { state: 'default' } },\n // Hover\n { key: 'hoverBg', label: 'Background', control: 'color', defaultValue: 'var(--color-card)', section: 'fieldColors', showWhen: { state: 'hover' } },\n { key: 'hoverBorder', label: 'Border', control: 'color', defaultValue: 'var(--color-accent)', section: 'fieldColors', showWhen: { state: 'hover' } },\n // Focus\n { key: 'focusBorder', label: 'Border', control: 'color', defaultValue: 'var(--color-accent)', section: 'fieldColors', showWhen: { state: 'focus' } },\n { key: 'focusRing', label: 'Ring', control: 'color', defaultValue: 'var(--color-accent)', section: 'focusState', showWhen: { state: 'focus' } },\n // Disabled\n { key: 'disabledBg', label: 'Background', control: 'color', defaultValue: 'var(--color-surface-alt)', section: 'fieldColors', showWhen: { state: 'disabled' } },\n { key: 'disabledBorder', label: 'Border', control: 'color', defaultValue: 'var(--color-border)', section: 'fieldColors', showWhen: { state: 'disabled' } },\n { key: 'disabledColor', label: 'Text', control: 'color', defaultValue: 'var(--color-text-muted)', section: 'fieldColors', showWhen: { state: 'disabled' } },\n { key: 'disabledOpacity', label: 'Opacity', control: 'slider', defaultValue: 0.6, min: 0.1, max: 1, step: 0.05, section: 'disabledState', showWhen: { state: 'disabled' } },\n // Error\n { key: 'errorBg', label: 'Background', control: 'color', defaultValue: 'var(--color-card)', section: 'fieldColors', showWhen: { state: 'error' } },\n { key: 'errorBorder', label: 'Border', control: 'color', defaultValue: 'var(--color-danger-text)', section: 'fieldColors', showWhen: { state: 'error' } },\n { key: 'errorColor', label: 'Label + Message', control: 'color', defaultValue: 'var(--color-danger-text)', section: 'errorState', showWhen: { state: 'error' } },\n { key: 'errorMessageSize', label: 'Message Size', control: 'number', defaultValue: 12, min: 10, max: 16, step: 1, unit: 'px', section: 'errorState', showWhen: { state: 'error' } },\n // Shared\n { key: 'borderRadius', label: 'Border Radius', control: 'slider', defaultValue: 8, min: 0, max: 16, step: 1, unit: 'px' },\n { key: 'paddingX', label: 'Padding X', control: 'number', defaultValue: 12, min: 4, max: 24, step: 2, unit: 'px' },\n { key: 'paddingY', label: 'Padding Y', control: 'number', defaultValue: 10, min: 4, max: 20, step: 2, unit: 'px' },\n { key: 'fontSize', label: 'Font Size', control: 'number', defaultValue: 14, min: 10, max: 20, step: 1, unit: 'px' },\n // Label theming AND label position live on FormField. This atom\n // is just the input element — no label rendered, no labelPosition\n // variant. Wrap with `<FormField>` when you want a label.\n // Previously had `labelColor` knob + shared `labelPositionVariant`\n // here; both only affected the workbench preview's hand-rolled\n // label and have been removed as part of the consolidation pass.\n ],\n layoutVariants: [\n {\n key: 'state',\n label: 'State',\n options: [\n { value: 'default', label: 'Default' },\n { value: 'hover', label: 'Hover' },\n { value: 'focus', label: 'Focus' },\n { value: 'disabled', label: 'Disabled' },\n { value: 'error', label: 'Error' },\n ],\n defaultValue: 'default',\n },\n ],\n events: [\n { name: 'onChange', description: 'Fires after the user commits a change (blur or Enter).', payload: '{ value: string }' },\n { name: 'onInput', description: 'Fires on every keystroke. High-frequency — use for live validation, not for save.', payload: '{ value: string }' },\n { name: 'onFocus', description: 'Fires when the field receives focus (click or Tab).', payload: 'FocusEvent' },\n { name: 'onBlur', description: 'Fires when the field loses focus.', payload: 'FocusEvent' },\n ],\n api: {\n importPath: '@viax/uxm/ui',\n importNames: 'TextInput',\n props: [\n { name: 'value', type: 'string', description: 'Current value (controlled).' },\n { name: 'onChange', type: '(e: ChangeEvent<HTMLInputElement>) => void', description: 'Change handler. Read `e.target.value`.' },\n { name: 'placeholder', type: 'string', description: 'Placeholder shown when empty.' },\n { name: 'type', type: '\"text\" | \"email\" | \"tel\" | \"url\" | \"password\" | \"search\"', defaultValue: '\"text\"', description: 'Native input type — affects keyboard and validation hints on mobile.' },\n { name: 'disabled', type: 'boolean', defaultValue: 'false', description: 'Disables the input.' },\n { name: 'clearable', type: 'boolean', defaultValue: 'true', description: 'Show a clear (✕) button at the trailing edge when the field has content. On by default; the ✕ self-clears and fires `onChange` with \"\", so no wiring is needed for controlled fields. Pass `false` to opt out.' },\n { name: 'onClear', type: '() => void', description: 'Optional override for the clear action. By default the field clears itself (and notifies via `onChange`); pass `onClear` only for custom reset logic beyond emptying the value.' },\n { name: '...rest', type: 'InputHTMLAttributes<HTMLInputElement>', description: 'All other native input attributes (aria-label, name, autoComplete, etc.) pass through.' },\n ],\n },\n};\n"],"mappings":"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","names":[]}
1
+ {"version":3,"sources":["../../../../../src/studio/lib/registry/inputs/input-text.ts"],"sourcesContent":["import type { ComponentDef } from '../../types';\n\nexport const inputTextDef: ComponentDef = {\n id: 'input-text',\n name: 'Text Input',\n category: 'Inputs',\n description: 'Standard text input field with label. State knobs cover default / hover / focus / disabled / error — error replaces the previous standalone `Input with Error` atom (one tone surface, one shape surface).',\n styleProperties: [\n // Default\n { key: 'backgroundColor', label: 'Background', control: 'color', defaultValue: 'var(--color-card)', section: 'fieldColors', showWhen: { state: 'default' } },\n { key: 'borderColor', label: 'Border', control: 'color', defaultValue: 'var(--color-border)', section: 'fieldColors', showWhen: { state: 'default' } },\n { key: 'color', label: 'Text', control: 'color', defaultValue: 'var(--color-text)', section: 'fieldColors', showWhen: { state: 'default' } },\n // Hover\n { key: 'hoverBg', label: 'Background', control: 'color', defaultValue: 'var(--color-card)', section: 'fieldColors', showWhen: { state: 'hover' } },\n { key: 'hoverBorder', label: 'Border', control: 'color', defaultValue: 'var(--color-accent)', section: 'fieldColors', showWhen: { state: 'hover' } },\n // Focus\n { key: 'focusBorder', label: 'Border', control: 'color', defaultValue: 'var(--color-accent)', section: 'fieldColors', showWhen: { state: 'focus' } },\n { key: 'focusRing', label: 'Ring', control: 'color', defaultValue: 'var(--color-accent)', section: 'focusState', showWhen: { state: 'focus' } },\n // Disabled\n { key: 'disabledBg', label: 'Background', control: 'color', defaultValue: 'var(--color-surface-alt)', section: 'fieldColors', showWhen: { state: 'disabled' } },\n { key: 'disabledBorder', label: 'Border', control: 'color', defaultValue: 'var(--color-border)', section: 'fieldColors', showWhen: { state: 'disabled' } },\n { key: 'disabledColor', label: 'Text', control: 'color', defaultValue: 'var(--color-text-muted)', section: 'fieldColors', showWhen: { state: 'disabled' } },\n { key: 'disabledOpacity', label: 'Opacity', control: 'slider', defaultValue: 0.6, min: 0.1, max: 1, step: 0.05, section: 'disabledState', showWhen: { state: 'disabled' } },\n // Error\n { key: 'errorBg', label: 'Background', control: 'color', defaultValue: 'var(--color-card)', section: 'fieldColors', showWhen: { state: 'error' } },\n { key: 'errorBorder', label: 'Border', control: 'color', defaultValue: 'var(--color-danger-text)', section: 'fieldColors', showWhen: { state: 'error' } },\n { key: 'errorColor', label: 'Label + Message', control: 'color', defaultValue: 'var(--color-danger-text)', section: 'errorState', showWhen: { state: 'error' } },\n { key: 'errorMessageSize', label: 'Message Size', control: 'number', defaultValue: 12, min: 10, max: 16, step: 1, unit: 'px', section: 'errorState', showWhen: { state: 'error' } },\n // Shared\n { key: 'borderRadius', label: 'Border Radius', control: 'slider', defaultValue: 8, min: 0, max: 16, step: 1, unit: 'px' },\n { key: 'paddingX', label: 'Padding X', control: 'number', defaultValue: 12, min: 4, max: 24, step: 2, unit: 'px' },\n { key: 'paddingY', label: 'Padding Y', control: 'number', defaultValue: 10, min: 4, max: 20, step: 2, unit: 'px' },\n { key: 'fontSize', label: 'Font Size', control: 'number', defaultValue: 14, min: 10, max: 20, step: 1, unit: 'px' },\n // Label theming AND label position live on FormField. This atom\n // is just the input element — no label rendered, no labelPosition\n // variant. Wrap with `<FormField>` when you want a label.\n // Previously had `labelColor` knob + shared `labelPositionVariant`\n // here; both only affected the workbench preview's hand-rolled\n // label and have been removed as part of the consolidation pass.\n ],\n layoutVariants: [\n {\n key: 'state',\n label: 'State',\n options: [\n { value: 'default', label: 'Default' },\n { value: 'hover', label: 'Hover' },\n { value: 'focus', label: 'Focus' },\n { value: 'disabled', label: 'Disabled' },\n { value: 'error', label: 'Error' },\n ],\n defaultValue: 'default',\n },\n ],\n events: [\n { name: 'onChange', description: 'Fires after the user commits a change (blur or Enter).', payload: '{ value: string }' },\n { name: 'onInput', description: 'Fires on every keystroke. High-frequency — use for live validation, not for save.', payload: '{ value: string }' },\n { name: 'onFocus', description: 'Fires when the field receives focus (click or Tab).', payload: 'FocusEvent' },\n { name: 'onBlur', description: 'Fires when the field loses focus.', payload: 'FocusEvent' },\n ],\n api: {\n importPath: '@viax.io/uxm/ui',\n importNames: 'TextInput',\n props: [\n { name: 'value', type: 'string', description: 'Current value (controlled).' },\n { name: 'onChange', type: '(e: ChangeEvent<HTMLInputElement>) => void', description: 'Change handler. Read `e.target.value`.' },\n { name: 'placeholder', type: 'string', description: 'Placeholder shown when empty.' },\n { name: 'type', type: '\"text\" | \"email\" | \"tel\" | \"url\" | \"password\" | \"search\"', defaultValue: '\"text\"', description: 'Native input type — affects keyboard and validation hints on mobile.' },\n { name: 'disabled', type: 'boolean', defaultValue: 'false', description: 'Disables the input.' },\n { name: 'clearable', type: 'boolean', defaultValue: 'true', description: 'Show a clear (✕) button at the trailing edge when the field has content. On by default; the ✕ self-clears and fires `onChange` with \"\", so no wiring is needed for controlled fields. Pass `false` to opt out.' },\n { name: 'onClear', type: '() => void', description: 'Optional override for the clear action. By default the field clears itself (and notifies via `onChange`); pass `onClear` only for custom reset logic beyond emptying the value.' },\n { name: '...rest', type: 'InputHTMLAttributes<HTMLInputElement>', description: 'All other native input attributes (aria-label, name, autoComplete, etc.) pass through.' },\n ],\n },\n};\n"],"mappings":"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","names":[]}
@@ -189,7 +189,7 @@ const listboxDef = {
189
189
  { name: "onOpenChange", description: "Fires when the panel opens or closes.", payload: "boolean" }
190
190
  ],
191
191
  api: {
192
- importPath: "@viax/uxm/ui",
192
+ importPath: "@viax.io/uxm/ui",
193
193
  importNames: ["Listbox", "MultiListbox"],
194
194
  props: [
195
195
  { name: "items", type: "T[]", required: true, description: "Source data \u2014 the listbox is generic over T and has no knowledge of what's inside." },
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../../../src/studio/lib/registry/inputs/listbox.ts"],"sourcesContent":["import type { ComponentDef } from '../../types';\n\nexport const listboxDef: ComponentDef = {\n id: 'listbox',\n name: 'Listbox (Dropdown Panel)',\n category: 'Inputs',\n description: \"Shared dropdown panel used by every select / picker in the app (SearchDropdown, PhoneInput country, CurrencyInput, PillSelect, native Select replacement, ColorPicker). The atom is generic over item shape — consumers pass items + a renderItem and own the trigger entirely. This entry themes the PANEL only: chrome, search input, option rows + states, group headers, empty state, footer. Trigger / field theming lives on each consuming component's own registry entry.\",\n styleProperties: [\n // Panel chrome — the floating card.\n { key: 'panelBg', label: 'Background', control: 'color', defaultValue: 'var(--color-card)', section: 'panel' },\n { key: 'panelBorder', label: 'Border', control: 'color', defaultValue: 'var(--color-border)', section: 'panel' },\n { key: 'panelRadius', label: 'Radius', control: 'slider', defaultValue: 8, min: 0, max: 16, step: 1, unit: 'px', section: 'panel' },\n // Drop shadow — decomposed into Color / Blur / Offset Y (colour picker\n // + sliders) instead of a raw box-shadow text field. Same pattern as\n // the Calendar / Menu atoms; the box-shadow is composed from these\n // three vars in listbox.scss.\n { key: 'shadowColor', label: 'Color', control: 'color', defaultValue: 'rgba(0, 0, 0, 0.10)', section: 'shadow' },\n { key: 'shadowBlur', label: 'Blur', control: 'slider', defaultValue: 20, min: 0, max: 48, step: 1, unit: 'px', section: 'shadow' },\n { key: 'shadowOffsetY', label: 'Offset Y', control: 'slider', defaultValue: 6, min: 0, max: 24, step: 1, unit: 'px', section: 'shadow' },\n { key: 'panelMaxHeight', label: 'Max Height', control: 'number', defaultValue: 320, min: 120, max: 600, step: 20, unit: 'px', section: 'panel' },\n\n // Search input — only meaningful when the consumer enables search.\n { key: 'searchBorder', label: 'Divider', control: 'color', defaultValue: 'var(--color-border)', section: 'search', showWhen: { withSearch: 'yes' } },\n { key: 'searchIconColor', label: 'Icon', control: 'color', defaultValue: 'var(--color-text-subtle)', section: 'search', showWhen: { withSearch: 'yes' } },\n { key: 'searchColor', label: 'Text', control: 'color', defaultValue: 'var(--color-text)', section: 'search', showWhen: { withSearch: 'yes' } },\n { key: 'searchPlaceholderColor', label: 'Placeholder', control: 'color', defaultValue: 'var(--color-text-subtle)', section: 'search', showWhen: { withSearch: 'yes' } },\n { key: 'searchFontSize', label: 'Font Size', control: 'number', defaultValue: 12, min: 10, max: 18, step: 1, unit: 'px', section: 'search', showWhen: { withSearch: 'yes' } },\n\n // Option row — sizing knobs apply across all states. The shared\n // (always-visible) section keeps padding / font / radius next to\n // the state-specific colours so they're easy to find.\n { key: 'optionPaddingX', label: 'Padding X', control: 'number', defaultValue: 10, min: 4, max: 20, step: 1, unit: 'px', section: 'option' },\n { key: 'optionPaddingY', label: 'Padding Y', control: 'number', defaultValue: 6, min: 2, max: 14, step: 1, unit: 'px', section: 'option' },\n { key: 'optionFontSize', label: 'Font Size', control: 'number', defaultValue: 13, min: 10, max: 18, step: 1, unit: 'px', section: 'option' },\n { key: 'optionRadius', label: 'Radius', control: 'slider', defaultValue: 4, min: 0, max: 12, step: 1, unit: 'px', section: 'option' },\n\n // Per-state colour knobs — scoped by `state` variant so only the\n // knobs relevant to the currently-displayed showcase state are\n // visible. Matches the search-dropdown / select-dropdown / input-text\n // convention. State labels in showWhen match the variant `value`\n // strings (\"default\" / \"active\" / \"selected\" / \"selected-active\" /\n // \"disabled\"). Default state has no row background of its own — the\n // panel bg shows through — so only the text colour is exposed there.\n // Default state — bg + text. Bg defaults to transparent so the\n // panel chrome shows through (the common case); tune it if you\n // want every row to have its own surface (e.g. striped rows).\n { key: 'optionDefaultBg', label: 'Background', control: 'color', defaultValue: 'transparent', section: 'optionState', showWhen: { state: 'default' } },\n { key: 'optionColor', label: 'Text', control: 'color', defaultValue: 'var(--color-text)', section: 'optionState', showWhen: { state: 'default' } },\n\n // \"Hover\" state covers both mouse hover and keyboard arrow-key\n // highlight — they paint the same modifier class (`--active`)\n // because the atom keeps them visually equivalent. Registry key\n // names stay `optionActive*` to match the CSS class + var\n // namespace; the workbench label is \"Hover\" because that's the\n // term designers use.\n { key: 'optionActiveBg', label: 'Background', control: 'color', defaultValue: 'var(--color-surface-alt)', section: 'optionState', showWhen: { state: 'hover' } },\n { key: 'optionActiveColor', label: 'Text', control: 'color', defaultValue: 'var(--color-text)', section: 'optionState', showWhen: { state: 'hover' } },\n\n { key: 'optionSelectedBg', label: 'Background', control: 'color', defaultValue: 'var(--color-accent-subtle)', section: 'optionState', showWhen: { state: 'selected' } },\n { key: 'optionSelectedColor', label: 'Text', control: 'color', defaultValue: 'var(--color-accent-bold)', section: 'optionState', showWhen: { state: 'selected' } },\n\n { key: 'optionDisabledOpacity', label: 'Opacity', control: 'slider', defaultValue: 0.4, min: 0.1, max: 1, step: 0.05, section: 'optionState', showWhen: { state: 'disabled' } },\n\n // Group headers — only meaningful when the consumer groups items.\n { key: 'groupHeaderFontSize', label: 'Font Size', control: 'number', defaultValue: 10, min: 9, max: 14, step: 1, unit: 'px', section: 'groupHeader', showWhen: { withGroups: 'yes' } },\n { key: 'groupHeaderColor', label: 'Color', control: 'color', defaultValue: 'var(--color-text-subtle)', section: 'groupHeader', showWhen: { withGroups: 'yes' } },\n\n // Empty-state line (e.g. \"No matches\").\n { key: 'emptyColor', label: 'Color', control: 'color', defaultValue: 'var(--color-text-muted)', section: 'empty' },\n\n // Footer divider — only shown when a consumer passes a footer slot\n // (ColorPicker's custom-hex panel).\n { key: 'footerBorder', label: 'Divider', control: 'color', defaultValue: 'var(--color-border)', section: 'footer', showWhen: { withFooter: 'yes' } },\n\n // No \"Selection Indicator\" knobs — the atom decides the pattern\n // (single-select → right-edge ✓ on selected, multi-select → left\n // checkboxes on every row). The right-edge ✓ inherits the row's\n // `--selected` text colour (tune via Selected → Text). The\n // checkbox marker reads `--uxm-checkbox-*` (tune via the Checkbox\n // atom). No new tuning surface here.\n ],\n layoutVariants: [\n {\n // Which state's classes to apply to the static showcase row at\n // the top of the preview. The interactive instance below is\n // always live — hover / keyboard / selection exercise the real\n // CSS rules independently. This picker is purely for VISUAL\n // confirmation of the per-state knobs (active bg, selected\n // bg/color, disabled opacity) — without it you'd have to hover\n // / click the interactive instance to verify each state.\n key: 'state',\n label: 'Row State',\n options: [\n { value: 'default', label: 'Default' },\n { value: 'hover', label: 'Hover' },\n { value: 'selected', label: 'Selected' },\n { value: 'disabled', label: 'Disabled' },\n ],\n defaultValue: 'default',\n },\n {\n key: 'withSearch',\n label: 'Search Input',\n options: [\n { value: 'yes', label: 'On' },\n { value: 'no', label: 'Off' },\n ],\n defaultValue: 'yes',\n },\n {\n key: 'withGroups',\n label: 'Group Headers',\n options: [\n { value: 'no', label: 'Off' },\n { value: 'yes', label: 'On' },\n ],\n defaultValue: 'no',\n },\n {\n key: 'withFooter',\n label: 'Footer Slot',\n options: [\n { value: 'no', label: 'Off' },\n { value: 'yes', label: 'On' },\n ],\n defaultValue: 'no',\n },\n {\n // Wrap a long list into up to two balanced columns to roughly halve\n // the panel height. Drives `--uxm-listbox-list-columns` on the list\n // in the preview; a real consumer sets the `columns` prop. The count\n // is a max (each column keeps a min width, so a narrow panel falls\n // back to one) — try it with Group Headers on to see headers span.\n // One vs two — deeper columns get unusable in a dropdown.\n key: 'columns',\n label: 'Columns',\n options: [\n { value: '1', label: 'One' },\n { value: '2', label: 'Two' },\n ],\n defaultValue: '1',\n },\n {\n // Which atom the interactive preview mounts. The indicator\n // pattern is decided by the atom, not by the workbench:\n // - `Listbox` (single) → right-edge ✓ on the selected row\n // - `MultiListbox` (multi) → left-edge checkbox on every row\n // The static showcase above respects this too — single mode\n // shows the right-✓ when `state=selected`; multi mode shows\n // checkboxes on the row regardless of state.\n key: 'mode',\n label: 'Selection',\n options: [\n { value: 'single', label: 'Single' },\n { value: 'multi', label: 'Multi' },\n ],\n defaultValue: 'single',\n },\n // Multi-only — the Checkboxes variant shows the with/without\n // indicator design choice for multi-select panels. `excludeSelected`\n // (hide picked items from the list) is intentionally NOT exposed\n // — it's a consumer-level decision baked into atoms like\n // PillSelect, not a panel-design choice designers should tune.\n // `showWhen: { mode: \"multi\" }` keeps it out of single mode.\n {\n key: 'showCheckbox',\n label: 'Checkboxes',\n options: [\n { value: 'on', label: 'On' },\n { value: 'off', label: 'Off' },\n ],\n defaultValue: 'on',\n showWhen: { mode: 'multi' },\n },\n ],\n events: [\n { name: 'onChange', description: 'Fires when the user picks an option (click or Enter). Multi-select toggles items in/out of the array.', payload: 'T (single) | T[] (multi)' },\n { name: 'onOpenChange', description: 'Fires when the panel opens or closes.', payload: 'boolean' },\n ],\n api: {\n importPath: '@viax/uxm/ui',\n importNames: ['Listbox', 'MultiListbox'],\n props: [\n { name: 'items', type: 'T[]', required: true, description: \"Source data — the listbox is generic over T and has no knowledge of what's inside.\" },\n { name: 'getKey', type: '(item: T) => string', required: true, description: 'Stable React key per item.' },\n { name: 'getLabel', type: '(item: T) => string', required: true, description: 'Plain text used for default substring filter and a11y.' },\n { name: 'value', type: 'T | null // Listbox\\nT[] // MultiListbox', required: true, description: 'Current selection.' },\n { name: 'onChange', type: '(item: T | null) => void // Listbox — null when consumer clears\\n(items: T[]) => void // MultiListbox — empty array when cleared', required: true, description: 'Selection callback. Listbox passes null when the consumer wires up a clear affordance (e.g. ✕ in their renderTrigger). MultiListbox passes an empty array when all selections are cleared.' },\n { name: 'renderTrigger', type: '(state: { open, selected, triggerProps }) => ReactNode', required: true, description: \"Render the consumer's trigger. Spread `triggerProps` on a button — that wires ref + click + ARIA in one go.\" },\n { name: 'renderItem', type: '(item: T, state: { active, selected }) => ReactNode', required: true, description: 'Render each row body — the atom owns layout + states; consumer owns visuals (icon, flag, swatch, etc.).' },\n { name: 'searchable', type: 'boolean | \"auto\"', defaultValue: 'true', description: 'Show a search input above the list. `\"auto\"` reveals it only once the option count exceeds the shared threshold (6) — the one place that rule lives, so every Listbox-backed picker shares it.' },\n { name: 'filterItems', type: '(items: T[], query: string) => T[]', description: 'Override the default case-insensitive substring filter on `getLabel`.' },\n { name: 'groupBy', type: '(item: T) => string', description: 'Group items under section headers in declared order.' },\n { name: 'columns', type: '1 | 2', defaultValue: '1', description: 'Wrap a long list into up to two balanced columns to roughly halve the panel height. Rows keep source order down column one then continue in column two, so arrow-key nav still reads naturally. A max, not a fixed count — each column keeps a min width (--uxm-listbox-list-column-min-width), so a narrow panel falls back to one column instead of cramping; widen the panel (wider anchor or matchAnchorWidth={false} + minPanelWidth) to reveal the second. Works with groupBy — headers span full width above each group.' },\n { name: 'footer', type: 'ReactNode', description: \"Slot below the list (e.g. ColorPicker's custom hex panel).\" },\n { name: 'isItemDisabled', type: '(item: T) => boolean', description: 'Mark individual items inert (not selectable, skipped by keyboard nav).' },\n { name: 'placement', type: '\"bottom-start\" | \"bottom-end\" | \"top-start\" | \"top-end\"', defaultValue: '\"bottom-start\"', description: 'Preferred placement; flips on overflow.' },\n { name: 'matchAnchorWidth', type: 'boolean', defaultValue: 'true', description: \"Match the positioning anchor's width (the trigger by default, or `anchorRef` if provided).\" },\n { name: 'anchorRef', type: 'RefObject<HTMLElement | null>', description: \"Override what the popover positions / sizes against. Defaults to the trigger element. Use when the trigger is a small affordance inside a larger field (e.g. PhoneInput's country button inside the phone field).\" },\n { name: 'showCheckmark', type: 'boolean', defaultValue: 'true', description: 'Listbox only — show the right-edge ✓ on the selected row. Set to `false` when row content already has trailing meta (dial codes, currency codes) that would compete for the right edge.' },\n { name: 'portal', type: 'boolean', defaultValue: 'true', description: 'Mount the panel into document.body — escapes clipping parents.' },\n { name: 'excludeSelected', type: 'boolean', defaultValue: 'true', description: 'MultiListbox only — hide items already in `value` from the panel.' },\n ],\n },\n};\n"],"mappings":"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","names":[]}
1
+ {"version":3,"sources":["../../../../../src/studio/lib/registry/inputs/listbox.ts"],"sourcesContent":["import type { ComponentDef } from '../../types';\n\nexport const listboxDef: ComponentDef = {\n id: 'listbox',\n name: 'Listbox (Dropdown Panel)',\n category: 'Inputs',\n description: \"Shared dropdown panel used by every select / picker in the app (SearchDropdown, PhoneInput country, CurrencyInput, PillSelect, native Select replacement, ColorPicker). The atom is generic over item shape — consumers pass items + a renderItem and own the trigger entirely. This entry themes the PANEL only: chrome, search input, option rows + states, group headers, empty state, footer. Trigger / field theming lives on each consuming component's own registry entry.\",\n styleProperties: [\n // Panel chrome — the floating card.\n { key: 'panelBg', label: 'Background', control: 'color', defaultValue: 'var(--color-card)', section: 'panel' },\n { key: 'panelBorder', label: 'Border', control: 'color', defaultValue: 'var(--color-border)', section: 'panel' },\n { key: 'panelRadius', label: 'Radius', control: 'slider', defaultValue: 8, min: 0, max: 16, step: 1, unit: 'px', section: 'panel' },\n // Drop shadow — decomposed into Color / Blur / Offset Y (colour picker\n // + sliders) instead of a raw box-shadow text field. Same pattern as\n // the Calendar / Menu atoms; the box-shadow is composed from these\n // three vars in listbox.scss.\n { key: 'shadowColor', label: 'Color', control: 'color', defaultValue: 'rgba(0, 0, 0, 0.10)', section: 'shadow' },\n { key: 'shadowBlur', label: 'Blur', control: 'slider', defaultValue: 20, min: 0, max: 48, step: 1, unit: 'px', section: 'shadow' },\n { key: 'shadowOffsetY', label: 'Offset Y', control: 'slider', defaultValue: 6, min: 0, max: 24, step: 1, unit: 'px', section: 'shadow' },\n { key: 'panelMaxHeight', label: 'Max Height', control: 'number', defaultValue: 320, min: 120, max: 600, step: 20, unit: 'px', section: 'panel' },\n\n // Search input — only meaningful when the consumer enables search.\n { key: 'searchBorder', label: 'Divider', control: 'color', defaultValue: 'var(--color-border)', section: 'search', showWhen: { withSearch: 'yes' } },\n { key: 'searchIconColor', label: 'Icon', control: 'color', defaultValue: 'var(--color-text-subtle)', section: 'search', showWhen: { withSearch: 'yes' } },\n { key: 'searchColor', label: 'Text', control: 'color', defaultValue: 'var(--color-text)', section: 'search', showWhen: { withSearch: 'yes' } },\n { key: 'searchPlaceholderColor', label: 'Placeholder', control: 'color', defaultValue: 'var(--color-text-subtle)', section: 'search', showWhen: { withSearch: 'yes' } },\n { key: 'searchFontSize', label: 'Font Size', control: 'number', defaultValue: 12, min: 10, max: 18, step: 1, unit: 'px', section: 'search', showWhen: { withSearch: 'yes' } },\n\n // Option row — sizing knobs apply across all states. The shared\n // (always-visible) section keeps padding / font / radius next to\n // the state-specific colours so they're easy to find.\n { key: 'optionPaddingX', label: 'Padding X', control: 'number', defaultValue: 10, min: 4, max: 20, step: 1, unit: 'px', section: 'option' },\n { key: 'optionPaddingY', label: 'Padding Y', control: 'number', defaultValue: 6, min: 2, max: 14, step: 1, unit: 'px', section: 'option' },\n { key: 'optionFontSize', label: 'Font Size', control: 'number', defaultValue: 13, min: 10, max: 18, step: 1, unit: 'px', section: 'option' },\n { key: 'optionRadius', label: 'Radius', control: 'slider', defaultValue: 4, min: 0, max: 12, step: 1, unit: 'px', section: 'option' },\n\n // Per-state colour knobs — scoped by `state` variant so only the\n // knobs relevant to the currently-displayed showcase state are\n // visible. Matches the search-dropdown / select-dropdown / input-text\n // convention. State labels in showWhen match the variant `value`\n // strings (\"default\" / \"active\" / \"selected\" / \"selected-active\" /\n // \"disabled\"). Default state has no row background of its own — the\n // panel bg shows through — so only the text colour is exposed there.\n // Default state — bg + text. Bg defaults to transparent so the\n // panel chrome shows through (the common case); tune it if you\n // want every row to have its own surface (e.g. striped rows).\n { key: 'optionDefaultBg', label: 'Background', control: 'color', defaultValue: 'transparent', section: 'optionState', showWhen: { state: 'default' } },\n { key: 'optionColor', label: 'Text', control: 'color', defaultValue: 'var(--color-text)', section: 'optionState', showWhen: { state: 'default' } },\n\n // \"Hover\" state covers both mouse hover and keyboard arrow-key\n // highlight — they paint the same modifier class (`--active`)\n // because the atom keeps them visually equivalent. Registry key\n // names stay `optionActive*` to match the CSS class + var\n // namespace; the workbench label is \"Hover\" because that's the\n // term designers use.\n { key: 'optionActiveBg', label: 'Background', control: 'color', defaultValue: 'var(--color-surface-alt)', section: 'optionState', showWhen: { state: 'hover' } },\n { key: 'optionActiveColor', label: 'Text', control: 'color', defaultValue: 'var(--color-text)', section: 'optionState', showWhen: { state: 'hover' } },\n\n { key: 'optionSelectedBg', label: 'Background', control: 'color', defaultValue: 'var(--color-accent-subtle)', section: 'optionState', showWhen: { state: 'selected' } },\n { key: 'optionSelectedColor', label: 'Text', control: 'color', defaultValue: 'var(--color-accent-bold)', section: 'optionState', showWhen: { state: 'selected' } },\n\n { key: 'optionDisabledOpacity', label: 'Opacity', control: 'slider', defaultValue: 0.4, min: 0.1, max: 1, step: 0.05, section: 'optionState', showWhen: { state: 'disabled' } },\n\n // Group headers — only meaningful when the consumer groups items.\n { key: 'groupHeaderFontSize', label: 'Font Size', control: 'number', defaultValue: 10, min: 9, max: 14, step: 1, unit: 'px', section: 'groupHeader', showWhen: { withGroups: 'yes' } },\n { key: 'groupHeaderColor', label: 'Color', control: 'color', defaultValue: 'var(--color-text-subtle)', section: 'groupHeader', showWhen: { withGroups: 'yes' } },\n\n // Empty-state line (e.g. \"No matches\").\n { key: 'emptyColor', label: 'Color', control: 'color', defaultValue: 'var(--color-text-muted)', section: 'empty' },\n\n // Footer divider — only shown when a consumer passes a footer slot\n // (ColorPicker's custom-hex panel).\n { key: 'footerBorder', label: 'Divider', control: 'color', defaultValue: 'var(--color-border)', section: 'footer', showWhen: { withFooter: 'yes' } },\n\n // No \"Selection Indicator\" knobs — the atom decides the pattern\n // (single-select → right-edge ✓ on selected, multi-select → left\n // checkboxes on every row). The right-edge ✓ inherits the row's\n // `--selected` text colour (tune via Selected → Text). The\n // checkbox marker reads `--uxm-checkbox-*` (tune via the Checkbox\n // atom). No new tuning surface here.\n ],\n layoutVariants: [\n {\n // Which state's classes to apply to the static showcase row at\n // the top of the preview. The interactive instance below is\n // always live — hover / keyboard / selection exercise the real\n // CSS rules independently. This picker is purely for VISUAL\n // confirmation of the per-state knobs (active bg, selected\n // bg/color, disabled opacity) — without it you'd have to hover\n // / click the interactive instance to verify each state.\n key: 'state',\n label: 'Row State',\n options: [\n { value: 'default', label: 'Default' },\n { value: 'hover', label: 'Hover' },\n { value: 'selected', label: 'Selected' },\n { value: 'disabled', label: 'Disabled' },\n ],\n defaultValue: 'default',\n },\n {\n key: 'withSearch',\n label: 'Search Input',\n options: [\n { value: 'yes', label: 'On' },\n { value: 'no', label: 'Off' },\n ],\n defaultValue: 'yes',\n },\n {\n key: 'withGroups',\n label: 'Group Headers',\n options: [\n { value: 'no', label: 'Off' },\n { value: 'yes', label: 'On' },\n ],\n defaultValue: 'no',\n },\n {\n key: 'withFooter',\n label: 'Footer Slot',\n options: [\n { value: 'no', label: 'Off' },\n { value: 'yes', label: 'On' },\n ],\n defaultValue: 'no',\n },\n {\n // Wrap a long list into up to two balanced columns to roughly halve\n // the panel height. Drives `--uxm-listbox-list-columns` on the list\n // in the preview; a real consumer sets the `columns` prop. The count\n // is a max (each column keeps a min width, so a narrow panel falls\n // back to one) — try it with Group Headers on to see headers span.\n // One vs two — deeper columns get unusable in a dropdown.\n key: 'columns',\n label: 'Columns',\n options: [\n { value: '1', label: 'One' },\n { value: '2', label: 'Two' },\n ],\n defaultValue: '1',\n },\n {\n // Which atom the interactive preview mounts. The indicator\n // pattern is decided by the atom, not by the workbench:\n // - `Listbox` (single) → right-edge ✓ on the selected row\n // - `MultiListbox` (multi) → left-edge checkbox on every row\n // The static showcase above respects this too — single mode\n // shows the right-✓ when `state=selected`; multi mode shows\n // checkboxes on the row regardless of state.\n key: 'mode',\n label: 'Selection',\n options: [\n { value: 'single', label: 'Single' },\n { value: 'multi', label: 'Multi' },\n ],\n defaultValue: 'single',\n },\n // Multi-only — the Checkboxes variant shows the with/without\n // indicator design choice for multi-select panels. `excludeSelected`\n // (hide picked items from the list) is intentionally NOT exposed\n // — it's a consumer-level decision baked into atoms like\n // PillSelect, not a panel-design choice designers should tune.\n // `showWhen: { mode: \"multi\" }` keeps it out of single mode.\n {\n key: 'showCheckbox',\n label: 'Checkboxes',\n options: [\n { value: 'on', label: 'On' },\n { value: 'off', label: 'Off' },\n ],\n defaultValue: 'on',\n showWhen: { mode: 'multi' },\n },\n ],\n events: [\n { name: 'onChange', description: 'Fires when the user picks an option (click or Enter). Multi-select toggles items in/out of the array.', payload: 'T (single) | T[] (multi)' },\n { name: 'onOpenChange', description: 'Fires when the panel opens or closes.', payload: 'boolean' },\n ],\n api: {\n importPath: '@viax.io/uxm/ui',\n importNames: ['Listbox', 'MultiListbox'],\n props: [\n { name: 'items', type: 'T[]', required: true, description: \"Source data — the listbox is generic over T and has no knowledge of what's inside.\" },\n { name: 'getKey', type: '(item: T) => string', required: true, description: 'Stable React key per item.' },\n { name: 'getLabel', type: '(item: T) => string', required: true, description: 'Plain text used for default substring filter and a11y.' },\n { name: 'value', type: 'T | null // Listbox\\nT[] // MultiListbox', required: true, description: 'Current selection.' },\n { name: 'onChange', type: '(item: T | null) => void // Listbox — null when consumer clears\\n(items: T[]) => void // MultiListbox — empty array when cleared', required: true, description: 'Selection callback. Listbox passes null when the consumer wires up a clear affordance (e.g. ✕ in their renderTrigger). MultiListbox passes an empty array when all selections are cleared.' },\n { name: 'renderTrigger', type: '(state: { open, selected, triggerProps }) => ReactNode', required: true, description: \"Render the consumer's trigger. Spread `triggerProps` on a button — that wires ref + click + ARIA in one go.\" },\n { name: 'renderItem', type: '(item: T, state: { active, selected }) => ReactNode', required: true, description: 'Render each row body — the atom owns layout + states; consumer owns visuals (icon, flag, swatch, etc.).' },\n { name: 'searchable', type: 'boolean | \"auto\"', defaultValue: 'true', description: 'Show a search input above the list. `\"auto\"` reveals it only once the option count exceeds the shared threshold (6) — the one place that rule lives, so every Listbox-backed picker shares it.' },\n { name: 'filterItems', type: '(items: T[], query: string) => T[]', description: 'Override the default case-insensitive substring filter on `getLabel`.' },\n { name: 'groupBy', type: '(item: T) => string', description: 'Group items under section headers in declared order.' },\n { name: 'columns', type: '1 | 2', defaultValue: '1', description: 'Wrap a long list into up to two balanced columns to roughly halve the panel height. Rows keep source order down column one then continue in column two, so arrow-key nav still reads naturally. A max, not a fixed count — each column keeps a min width (--uxm-listbox-list-column-min-width), so a narrow panel falls back to one column instead of cramping; widen the panel (wider anchor or matchAnchorWidth={false} + minPanelWidth) to reveal the second. Works with groupBy — headers span full width above each group.' },\n { name: 'footer', type: 'ReactNode', description: \"Slot below the list (e.g. ColorPicker's custom hex panel).\" },\n { name: 'isItemDisabled', type: '(item: T) => boolean', description: 'Mark individual items inert (not selectable, skipped by keyboard nav).' },\n { name: 'placement', type: '\"bottom-start\" | \"bottom-end\" | \"top-start\" | \"top-end\"', defaultValue: '\"bottom-start\"', description: 'Preferred placement; flips on overflow.' },\n { name: 'matchAnchorWidth', type: 'boolean', defaultValue: 'true', description: \"Match the positioning anchor's width (the trigger by default, or `anchorRef` if provided).\" },\n { name: 'anchorRef', type: 'RefObject<HTMLElement | null>', description: \"Override what the popover positions / sizes against. Defaults to the trigger element. Use when the trigger is a small affordance inside a larger field (e.g. PhoneInput's country button inside the phone field).\" },\n { name: 'showCheckmark', type: 'boolean', defaultValue: 'true', description: 'Listbox only — show the right-edge ✓ on the selected row. Set to `false` when row content already has trailing meta (dial codes, currency codes) that would compete for the right edge.' },\n { name: 'portal', type: 'boolean', defaultValue: 'true', description: 'Mount the panel into document.body — escapes clipping parents.' },\n { name: 'excludeSelected', type: 'boolean', defaultValue: 'true', description: 'MultiListbox only — hide items already in `value` from the panel.' },\n ],\n },\n};\n"],"mappings":"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","names":[]}
@@ -166,7 +166,7 @@ const listboxDef = {
166
166
  { name: "onOpenChange", description: "Fires when the panel opens or closes.", payload: "boolean" }
167
167
  ],
168
168
  api: {
169
- importPath: "@viax/uxm/ui",
169
+ importPath: "@viax.io/uxm/ui",
170
170
  importNames: ["Listbox", "MultiListbox"],
171
171
  props: [
172
172
  { name: "items", type: "T[]", required: true, description: "Source data \u2014 the listbox is generic over T and has no knowledge of what's inside." },
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../../../src/studio/lib/registry/inputs/listbox.ts"],"sourcesContent":["import type { ComponentDef } from '../../types';\n\nexport const listboxDef: ComponentDef = {\n id: 'listbox',\n name: 'Listbox (Dropdown Panel)',\n category: 'Inputs',\n description: \"Shared dropdown panel used by every select / picker in the app (SearchDropdown, PhoneInput country, CurrencyInput, PillSelect, native Select replacement, ColorPicker). The atom is generic over item shape — consumers pass items + a renderItem and own the trigger entirely. This entry themes the PANEL only: chrome, search input, option rows + states, group headers, empty state, footer. Trigger / field theming lives on each consuming component's own registry entry.\",\n styleProperties: [\n // Panel chrome — the floating card.\n { key: 'panelBg', label: 'Background', control: 'color', defaultValue: 'var(--color-card)', section: 'panel' },\n { key: 'panelBorder', label: 'Border', control: 'color', defaultValue: 'var(--color-border)', section: 'panel' },\n { key: 'panelRadius', label: 'Radius', control: 'slider', defaultValue: 8, min: 0, max: 16, step: 1, unit: 'px', section: 'panel' },\n // Drop shadow — decomposed into Color / Blur / Offset Y (colour picker\n // + sliders) instead of a raw box-shadow text field. Same pattern as\n // the Calendar / Menu atoms; the box-shadow is composed from these\n // three vars in listbox.scss.\n { key: 'shadowColor', label: 'Color', control: 'color', defaultValue: 'rgba(0, 0, 0, 0.10)', section: 'shadow' },\n { key: 'shadowBlur', label: 'Blur', control: 'slider', defaultValue: 20, min: 0, max: 48, step: 1, unit: 'px', section: 'shadow' },\n { key: 'shadowOffsetY', label: 'Offset Y', control: 'slider', defaultValue: 6, min: 0, max: 24, step: 1, unit: 'px', section: 'shadow' },\n { key: 'panelMaxHeight', label: 'Max Height', control: 'number', defaultValue: 320, min: 120, max: 600, step: 20, unit: 'px', section: 'panel' },\n\n // Search input — only meaningful when the consumer enables search.\n { key: 'searchBorder', label: 'Divider', control: 'color', defaultValue: 'var(--color-border)', section: 'search', showWhen: { withSearch: 'yes' } },\n { key: 'searchIconColor', label: 'Icon', control: 'color', defaultValue: 'var(--color-text-subtle)', section: 'search', showWhen: { withSearch: 'yes' } },\n { key: 'searchColor', label: 'Text', control: 'color', defaultValue: 'var(--color-text)', section: 'search', showWhen: { withSearch: 'yes' } },\n { key: 'searchPlaceholderColor', label: 'Placeholder', control: 'color', defaultValue: 'var(--color-text-subtle)', section: 'search', showWhen: { withSearch: 'yes' } },\n { key: 'searchFontSize', label: 'Font Size', control: 'number', defaultValue: 12, min: 10, max: 18, step: 1, unit: 'px', section: 'search', showWhen: { withSearch: 'yes' } },\n\n // Option row — sizing knobs apply across all states. The shared\n // (always-visible) section keeps padding / font / radius next to\n // the state-specific colours so they're easy to find.\n { key: 'optionPaddingX', label: 'Padding X', control: 'number', defaultValue: 10, min: 4, max: 20, step: 1, unit: 'px', section: 'option' },\n { key: 'optionPaddingY', label: 'Padding Y', control: 'number', defaultValue: 6, min: 2, max: 14, step: 1, unit: 'px', section: 'option' },\n { key: 'optionFontSize', label: 'Font Size', control: 'number', defaultValue: 13, min: 10, max: 18, step: 1, unit: 'px', section: 'option' },\n { key: 'optionRadius', label: 'Radius', control: 'slider', defaultValue: 4, min: 0, max: 12, step: 1, unit: 'px', section: 'option' },\n\n // Per-state colour knobs — scoped by `state` variant so only the\n // knobs relevant to the currently-displayed showcase state are\n // visible. Matches the search-dropdown / select-dropdown / input-text\n // convention. State labels in showWhen match the variant `value`\n // strings (\"default\" / \"active\" / \"selected\" / \"selected-active\" /\n // \"disabled\"). Default state has no row background of its own — the\n // panel bg shows through — so only the text colour is exposed there.\n // Default state — bg + text. Bg defaults to transparent so the\n // panel chrome shows through (the common case); tune it if you\n // want every row to have its own surface (e.g. striped rows).\n { key: 'optionDefaultBg', label: 'Background', control: 'color', defaultValue: 'transparent', section: 'optionState', showWhen: { state: 'default' } },\n { key: 'optionColor', label: 'Text', control: 'color', defaultValue: 'var(--color-text)', section: 'optionState', showWhen: { state: 'default' } },\n\n // \"Hover\" state covers both mouse hover and keyboard arrow-key\n // highlight — they paint the same modifier class (`--active`)\n // because the atom keeps them visually equivalent. Registry key\n // names stay `optionActive*` to match the CSS class + var\n // namespace; the workbench label is \"Hover\" because that's the\n // term designers use.\n { key: 'optionActiveBg', label: 'Background', control: 'color', defaultValue: 'var(--color-surface-alt)', section: 'optionState', showWhen: { state: 'hover' } },\n { key: 'optionActiveColor', label: 'Text', control: 'color', defaultValue: 'var(--color-text)', section: 'optionState', showWhen: { state: 'hover' } },\n\n { key: 'optionSelectedBg', label: 'Background', control: 'color', defaultValue: 'var(--color-accent-subtle)', section: 'optionState', showWhen: { state: 'selected' } },\n { key: 'optionSelectedColor', label: 'Text', control: 'color', defaultValue: 'var(--color-accent-bold)', section: 'optionState', showWhen: { state: 'selected' } },\n\n { key: 'optionDisabledOpacity', label: 'Opacity', control: 'slider', defaultValue: 0.4, min: 0.1, max: 1, step: 0.05, section: 'optionState', showWhen: { state: 'disabled' } },\n\n // Group headers — only meaningful when the consumer groups items.\n { key: 'groupHeaderFontSize', label: 'Font Size', control: 'number', defaultValue: 10, min: 9, max: 14, step: 1, unit: 'px', section: 'groupHeader', showWhen: { withGroups: 'yes' } },\n { key: 'groupHeaderColor', label: 'Color', control: 'color', defaultValue: 'var(--color-text-subtle)', section: 'groupHeader', showWhen: { withGroups: 'yes' } },\n\n // Empty-state line (e.g. \"No matches\").\n { key: 'emptyColor', label: 'Color', control: 'color', defaultValue: 'var(--color-text-muted)', section: 'empty' },\n\n // Footer divider — only shown when a consumer passes a footer slot\n // (ColorPicker's custom-hex panel).\n { key: 'footerBorder', label: 'Divider', control: 'color', defaultValue: 'var(--color-border)', section: 'footer', showWhen: { withFooter: 'yes' } },\n\n // No \"Selection Indicator\" knobs — the atom decides the pattern\n // (single-select → right-edge ✓ on selected, multi-select → left\n // checkboxes on every row). The right-edge ✓ inherits the row's\n // `--selected` text colour (tune via Selected → Text). The\n // checkbox marker reads `--uxm-checkbox-*` (tune via the Checkbox\n // atom). No new tuning surface here.\n ],\n layoutVariants: [\n {\n // Which state's classes to apply to the static showcase row at\n // the top of the preview. The interactive instance below is\n // always live — hover / keyboard / selection exercise the real\n // CSS rules independently. This picker is purely for VISUAL\n // confirmation of the per-state knobs (active bg, selected\n // bg/color, disabled opacity) — without it you'd have to hover\n // / click the interactive instance to verify each state.\n key: 'state',\n label: 'Row State',\n options: [\n { value: 'default', label: 'Default' },\n { value: 'hover', label: 'Hover' },\n { value: 'selected', label: 'Selected' },\n { value: 'disabled', label: 'Disabled' },\n ],\n defaultValue: 'default',\n },\n {\n key: 'withSearch',\n label: 'Search Input',\n options: [\n { value: 'yes', label: 'On' },\n { value: 'no', label: 'Off' },\n ],\n defaultValue: 'yes',\n },\n {\n key: 'withGroups',\n label: 'Group Headers',\n options: [\n { value: 'no', label: 'Off' },\n { value: 'yes', label: 'On' },\n ],\n defaultValue: 'no',\n },\n {\n key: 'withFooter',\n label: 'Footer Slot',\n options: [\n { value: 'no', label: 'Off' },\n { value: 'yes', label: 'On' },\n ],\n defaultValue: 'no',\n },\n {\n // Wrap a long list into up to two balanced columns to roughly halve\n // the panel height. Drives `--uxm-listbox-list-columns` on the list\n // in the preview; a real consumer sets the `columns` prop. The count\n // is a max (each column keeps a min width, so a narrow panel falls\n // back to one) — try it with Group Headers on to see headers span.\n // One vs two — deeper columns get unusable in a dropdown.\n key: 'columns',\n label: 'Columns',\n options: [\n { value: '1', label: 'One' },\n { value: '2', label: 'Two' },\n ],\n defaultValue: '1',\n },\n {\n // Which atom the interactive preview mounts. The indicator\n // pattern is decided by the atom, not by the workbench:\n // - `Listbox` (single) → right-edge ✓ on the selected row\n // - `MultiListbox` (multi) → left-edge checkbox on every row\n // The static showcase above respects this too — single mode\n // shows the right-✓ when `state=selected`; multi mode shows\n // checkboxes on the row regardless of state.\n key: 'mode',\n label: 'Selection',\n options: [\n { value: 'single', label: 'Single' },\n { value: 'multi', label: 'Multi' },\n ],\n defaultValue: 'single',\n },\n // Multi-only — the Checkboxes variant shows the with/without\n // indicator design choice for multi-select panels. `excludeSelected`\n // (hide picked items from the list) is intentionally NOT exposed\n // — it's a consumer-level decision baked into atoms like\n // PillSelect, not a panel-design choice designers should tune.\n // `showWhen: { mode: \"multi\" }` keeps it out of single mode.\n {\n key: 'showCheckbox',\n label: 'Checkboxes',\n options: [\n { value: 'on', label: 'On' },\n { value: 'off', label: 'Off' },\n ],\n defaultValue: 'on',\n showWhen: { mode: 'multi' },\n },\n ],\n events: [\n { name: 'onChange', description: 'Fires when the user picks an option (click or Enter). Multi-select toggles items in/out of the array.', payload: 'T (single) | T[] (multi)' },\n { name: 'onOpenChange', description: 'Fires when the panel opens or closes.', payload: 'boolean' },\n ],\n api: {\n importPath: '@viax/uxm/ui',\n importNames: ['Listbox', 'MultiListbox'],\n props: [\n { name: 'items', type: 'T[]', required: true, description: \"Source data — the listbox is generic over T and has no knowledge of what's inside.\" },\n { name: 'getKey', type: '(item: T) => string', required: true, description: 'Stable React key per item.' },\n { name: 'getLabel', type: '(item: T) => string', required: true, description: 'Plain text used for default substring filter and a11y.' },\n { name: 'value', type: 'T | null // Listbox\\nT[] // MultiListbox', required: true, description: 'Current selection.' },\n { name: 'onChange', type: '(item: T | null) => void // Listbox — null when consumer clears\\n(items: T[]) => void // MultiListbox — empty array when cleared', required: true, description: 'Selection callback. Listbox passes null when the consumer wires up a clear affordance (e.g. ✕ in their renderTrigger). MultiListbox passes an empty array when all selections are cleared.' },\n { name: 'renderTrigger', type: '(state: { open, selected, triggerProps }) => ReactNode', required: true, description: \"Render the consumer's trigger. Spread `triggerProps` on a button — that wires ref + click + ARIA in one go.\" },\n { name: 'renderItem', type: '(item: T, state: { active, selected }) => ReactNode', required: true, description: 'Render each row body — the atom owns layout + states; consumer owns visuals (icon, flag, swatch, etc.).' },\n { name: 'searchable', type: 'boolean | \"auto\"', defaultValue: 'true', description: 'Show a search input above the list. `\"auto\"` reveals it only once the option count exceeds the shared threshold (6) — the one place that rule lives, so every Listbox-backed picker shares it.' },\n { name: 'filterItems', type: '(items: T[], query: string) => T[]', description: 'Override the default case-insensitive substring filter on `getLabel`.' },\n { name: 'groupBy', type: '(item: T) => string', description: 'Group items under section headers in declared order.' },\n { name: 'columns', type: '1 | 2', defaultValue: '1', description: 'Wrap a long list into up to two balanced columns to roughly halve the panel height. Rows keep source order down column one then continue in column two, so arrow-key nav still reads naturally. A max, not a fixed count — each column keeps a min width (--uxm-listbox-list-column-min-width), so a narrow panel falls back to one column instead of cramping; widen the panel (wider anchor or matchAnchorWidth={false} + minPanelWidth) to reveal the second. Works with groupBy — headers span full width above each group.' },\n { name: 'footer', type: 'ReactNode', description: \"Slot below the list (e.g. ColorPicker's custom hex panel).\" },\n { name: 'isItemDisabled', type: '(item: T) => boolean', description: 'Mark individual items inert (not selectable, skipped by keyboard nav).' },\n { name: 'placement', type: '\"bottom-start\" | \"bottom-end\" | \"top-start\" | \"top-end\"', defaultValue: '\"bottom-start\"', description: 'Preferred placement; flips on overflow.' },\n { name: 'matchAnchorWidth', type: 'boolean', defaultValue: 'true', description: \"Match the positioning anchor's width (the trigger by default, or `anchorRef` if provided).\" },\n { name: 'anchorRef', type: 'RefObject<HTMLElement | null>', description: \"Override what the popover positions / sizes against. Defaults to the trigger element. Use when the trigger is a small affordance inside a larger field (e.g. PhoneInput's country button inside the phone field).\" },\n { name: 'showCheckmark', type: 'boolean', defaultValue: 'true', description: 'Listbox only — show the right-edge ✓ on the selected row. Set to `false` when row content already has trailing meta (dial codes, currency codes) that would compete for the right edge.' },\n { name: 'portal', type: 'boolean', defaultValue: 'true', description: 'Mount the panel into document.body — escapes clipping parents.' },\n { name: 'excludeSelected', type: 'boolean', defaultValue: 'true', description: 'MultiListbox only — hide items already in `value` from the panel.' },\n ],\n },\n};\n"],"mappings":"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","names":[]}
1
+ {"version":3,"sources":["../../../../../src/studio/lib/registry/inputs/listbox.ts"],"sourcesContent":["import type { ComponentDef } from '../../types';\n\nexport const listboxDef: ComponentDef = {\n id: 'listbox',\n name: 'Listbox (Dropdown Panel)',\n category: 'Inputs',\n description: \"Shared dropdown panel used by every select / picker in the app (SearchDropdown, PhoneInput country, CurrencyInput, PillSelect, native Select replacement, ColorPicker). The atom is generic over item shape — consumers pass items + a renderItem and own the trigger entirely. This entry themes the PANEL only: chrome, search input, option rows + states, group headers, empty state, footer. Trigger / field theming lives on each consuming component's own registry entry.\",\n styleProperties: [\n // Panel chrome — the floating card.\n { key: 'panelBg', label: 'Background', control: 'color', defaultValue: 'var(--color-card)', section: 'panel' },\n { key: 'panelBorder', label: 'Border', control: 'color', defaultValue: 'var(--color-border)', section: 'panel' },\n { key: 'panelRadius', label: 'Radius', control: 'slider', defaultValue: 8, min: 0, max: 16, step: 1, unit: 'px', section: 'panel' },\n // Drop shadow — decomposed into Color / Blur / Offset Y (colour picker\n // + sliders) instead of a raw box-shadow text field. Same pattern as\n // the Calendar / Menu atoms; the box-shadow is composed from these\n // three vars in listbox.scss.\n { key: 'shadowColor', label: 'Color', control: 'color', defaultValue: 'rgba(0, 0, 0, 0.10)', section: 'shadow' },\n { key: 'shadowBlur', label: 'Blur', control: 'slider', defaultValue: 20, min: 0, max: 48, step: 1, unit: 'px', section: 'shadow' },\n { key: 'shadowOffsetY', label: 'Offset Y', control: 'slider', defaultValue: 6, min: 0, max: 24, step: 1, unit: 'px', section: 'shadow' },\n { key: 'panelMaxHeight', label: 'Max Height', control: 'number', defaultValue: 320, min: 120, max: 600, step: 20, unit: 'px', section: 'panel' },\n\n // Search input — only meaningful when the consumer enables search.\n { key: 'searchBorder', label: 'Divider', control: 'color', defaultValue: 'var(--color-border)', section: 'search', showWhen: { withSearch: 'yes' } },\n { key: 'searchIconColor', label: 'Icon', control: 'color', defaultValue: 'var(--color-text-subtle)', section: 'search', showWhen: { withSearch: 'yes' } },\n { key: 'searchColor', label: 'Text', control: 'color', defaultValue: 'var(--color-text)', section: 'search', showWhen: { withSearch: 'yes' } },\n { key: 'searchPlaceholderColor', label: 'Placeholder', control: 'color', defaultValue: 'var(--color-text-subtle)', section: 'search', showWhen: { withSearch: 'yes' } },\n { key: 'searchFontSize', label: 'Font Size', control: 'number', defaultValue: 12, min: 10, max: 18, step: 1, unit: 'px', section: 'search', showWhen: { withSearch: 'yes' } },\n\n // Option row — sizing knobs apply across all states. The shared\n // (always-visible) section keeps padding / font / radius next to\n // the state-specific colours so they're easy to find.\n { key: 'optionPaddingX', label: 'Padding X', control: 'number', defaultValue: 10, min: 4, max: 20, step: 1, unit: 'px', section: 'option' },\n { key: 'optionPaddingY', label: 'Padding Y', control: 'number', defaultValue: 6, min: 2, max: 14, step: 1, unit: 'px', section: 'option' },\n { key: 'optionFontSize', label: 'Font Size', control: 'number', defaultValue: 13, min: 10, max: 18, step: 1, unit: 'px', section: 'option' },\n { key: 'optionRadius', label: 'Radius', control: 'slider', defaultValue: 4, min: 0, max: 12, step: 1, unit: 'px', section: 'option' },\n\n // Per-state colour knobs — scoped by `state` variant so only the\n // knobs relevant to the currently-displayed showcase state are\n // visible. Matches the search-dropdown / select-dropdown / input-text\n // convention. State labels in showWhen match the variant `value`\n // strings (\"default\" / \"active\" / \"selected\" / \"selected-active\" /\n // \"disabled\"). Default state has no row background of its own — the\n // panel bg shows through — so only the text colour is exposed there.\n // Default state — bg + text. Bg defaults to transparent so the\n // panel chrome shows through (the common case); tune it if you\n // want every row to have its own surface (e.g. striped rows).\n { key: 'optionDefaultBg', label: 'Background', control: 'color', defaultValue: 'transparent', section: 'optionState', showWhen: { state: 'default' } },\n { key: 'optionColor', label: 'Text', control: 'color', defaultValue: 'var(--color-text)', section: 'optionState', showWhen: { state: 'default' } },\n\n // \"Hover\" state covers both mouse hover and keyboard arrow-key\n // highlight — they paint the same modifier class (`--active`)\n // because the atom keeps them visually equivalent. Registry key\n // names stay `optionActive*` to match the CSS class + var\n // namespace; the workbench label is \"Hover\" because that's the\n // term designers use.\n { key: 'optionActiveBg', label: 'Background', control: 'color', defaultValue: 'var(--color-surface-alt)', section: 'optionState', showWhen: { state: 'hover' } },\n { key: 'optionActiveColor', label: 'Text', control: 'color', defaultValue: 'var(--color-text)', section: 'optionState', showWhen: { state: 'hover' } },\n\n { key: 'optionSelectedBg', label: 'Background', control: 'color', defaultValue: 'var(--color-accent-subtle)', section: 'optionState', showWhen: { state: 'selected' } },\n { key: 'optionSelectedColor', label: 'Text', control: 'color', defaultValue: 'var(--color-accent-bold)', section: 'optionState', showWhen: { state: 'selected' } },\n\n { key: 'optionDisabledOpacity', label: 'Opacity', control: 'slider', defaultValue: 0.4, min: 0.1, max: 1, step: 0.05, section: 'optionState', showWhen: { state: 'disabled' } },\n\n // Group headers — only meaningful when the consumer groups items.\n { key: 'groupHeaderFontSize', label: 'Font Size', control: 'number', defaultValue: 10, min: 9, max: 14, step: 1, unit: 'px', section: 'groupHeader', showWhen: { withGroups: 'yes' } },\n { key: 'groupHeaderColor', label: 'Color', control: 'color', defaultValue: 'var(--color-text-subtle)', section: 'groupHeader', showWhen: { withGroups: 'yes' } },\n\n // Empty-state line (e.g. \"No matches\").\n { key: 'emptyColor', label: 'Color', control: 'color', defaultValue: 'var(--color-text-muted)', section: 'empty' },\n\n // Footer divider — only shown when a consumer passes a footer slot\n // (ColorPicker's custom-hex panel).\n { key: 'footerBorder', label: 'Divider', control: 'color', defaultValue: 'var(--color-border)', section: 'footer', showWhen: { withFooter: 'yes' } },\n\n // No \"Selection Indicator\" knobs — the atom decides the pattern\n // (single-select → right-edge ✓ on selected, multi-select → left\n // checkboxes on every row). The right-edge ✓ inherits the row's\n // `--selected` text colour (tune via Selected → Text). The\n // checkbox marker reads `--uxm-checkbox-*` (tune via the Checkbox\n // atom). No new tuning surface here.\n ],\n layoutVariants: [\n {\n // Which state's classes to apply to the static showcase row at\n // the top of the preview. The interactive instance below is\n // always live — hover / keyboard / selection exercise the real\n // CSS rules independently. This picker is purely for VISUAL\n // confirmation of the per-state knobs (active bg, selected\n // bg/color, disabled opacity) — without it you'd have to hover\n // / click the interactive instance to verify each state.\n key: 'state',\n label: 'Row State',\n options: [\n { value: 'default', label: 'Default' },\n { value: 'hover', label: 'Hover' },\n { value: 'selected', label: 'Selected' },\n { value: 'disabled', label: 'Disabled' },\n ],\n defaultValue: 'default',\n },\n {\n key: 'withSearch',\n label: 'Search Input',\n options: [\n { value: 'yes', label: 'On' },\n { value: 'no', label: 'Off' },\n ],\n defaultValue: 'yes',\n },\n {\n key: 'withGroups',\n label: 'Group Headers',\n options: [\n { value: 'no', label: 'Off' },\n { value: 'yes', label: 'On' },\n ],\n defaultValue: 'no',\n },\n {\n key: 'withFooter',\n label: 'Footer Slot',\n options: [\n { value: 'no', label: 'Off' },\n { value: 'yes', label: 'On' },\n ],\n defaultValue: 'no',\n },\n {\n // Wrap a long list into up to two balanced columns to roughly halve\n // the panel height. Drives `--uxm-listbox-list-columns` on the list\n // in the preview; a real consumer sets the `columns` prop. The count\n // is a max (each column keeps a min width, so a narrow panel falls\n // back to one) — try it with Group Headers on to see headers span.\n // One vs two — deeper columns get unusable in a dropdown.\n key: 'columns',\n label: 'Columns',\n options: [\n { value: '1', label: 'One' },\n { value: '2', label: 'Two' },\n ],\n defaultValue: '1',\n },\n {\n // Which atom the interactive preview mounts. The indicator\n // pattern is decided by the atom, not by the workbench:\n // - `Listbox` (single) → right-edge ✓ on the selected row\n // - `MultiListbox` (multi) → left-edge checkbox on every row\n // The static showcase above respects this too — single mode\n // shows the right-✓ when `state=selected`; multi mode shows\n // checkboxes on the row regardless of state.\n key: 'mode',\n label: 'Selection',\n options: [\n { value: 'single', label: 'Single' },\n { value: 'multi', label: 'Multi' },\n ],\n defaultValue: 'single',\n },\n // Multi-only — the Checkboxes variant shows the with/without\n // indicator design choice for multi-select panels. `excludeSelected`\n // (hide picked items from the list) is intentionally NOT exposed\n // — it's a consumer-level decision baked into atoms like\n // PillSelect, not a panel-design choice designers should tune.\n // `showWhen: { mode: \"multi\" }` keeps it out of single mode.\n {\n key: 'showCheckbox',\n label: 'Checkboxes',\n options: [\n { value: 'on', label: 'On' },\n { value: 'off', label: 'Off' },\n ],\n defaultValue: 'on',\n showWhen: { mode: 'multi' },\n },\n ],\n events: [\n { name: 'onChange', description: 'Fires when the user picks an option (click or Enter). Multi-select toggles items in/out of the array.', payload: 'T (single) | T[] (multi)' },\n { name: 'onOpenChange', description: 'Fires when the panel opens or closes.', payload: 'boolean' },\n ],\n api: {\n importPath: '@viax.io/uxm/ui',\n importNames: ['Listbox', 'MultiListbox'],\n props: [\n { name: 'items', type: 'T[]', required: true, description: \"Source data — the listbox is generic over T and has no knowledge of what's inside.\" },\n { name: 'getKey', type: '(item: T) => string', required: true, description: 'Stable React key per item.' },\n { name: 'getLabel', type: '(item: T) => string', required: true, description: 'Plain text used for default substring filter and a11y.' },\n { name: 'value', type: 'T | null // Listbox\\nT[] // MultiListbox', required: true, description: 'Current selection.' },\n { name: 'onChange', type: '(item: T | null) => void // Listbox — null when consumer clears\\n(items: T[]) => void // MultiListbox — empty array when cleared', required: true, description: 'Selection callback. Listbox passes null when the consumer wires up a clear affordance (e.g. ✕ in their renderTrigger). MultiListbox passes an empty array when all selections are cleared.' },\n { name: 'renderTrigger', type: '(state: { open, selected, triggerProps }) => ReactNode', required: true, description: \"Render the consumer's trigger. Spread `triggerProps` on a button — that wires ref + click + ARIA in one go.\" },\n { name: 'renderItem', type: '(item: T, state: { active, selected }) => ReactNode', required: true, description: 'Render each row body — the atom owns layout + states; consumer owns visuals (icon, flag, swatch, etc.).' },\n { name: 'searchable', type: 'boolean | \"auto\"', defaultValue: 'true', description: 'Show a search input above the list. `\"auto\"` reveals it only once the option count exceeds the shared threshold (6) — the one place that rule lives, so every Listbox-backed picker shares it.' },\n { name: 'filterItems', type: '(items: T[], query: string) => T[]', description: 'Override the default case-insensitive substring filter on `getLabel`.' },\n { name: 'groupBy', type: '(item: T) => string', description: 'Group items under section headers in declared order.' },\n { name: 'columns', type: '1 | 2', defaultValue: '1', description: 'Wrap a long list into up to two balanced columns to roughly halve the panel height. Rows keep source order down column one then continue in column two, so arrow-key nav still reads naturally. A max, not a fixed count — each column keeps a min width (--uxm-listbox-list-column-min-width), so a narrow panel falls back to one column instead of cramping; widen the panel (wider anchor or matchAnchorWidth={false} + minPanelWidth) to reveal the second. Works with groupBy — headers span full width above each group.' },\n { name: 'footer', type: 'ReactNode', description: \"Slot below the list (e.g. ColorPicker's custom hex panel).\" },\n { name: 'isItemDisabled', type: '(item: T) => boolean', description: 'Mark individual items inert (not selectable, skipped by keyboard nav).' },\n { name: 'placement', type: '\"bottom-start\" | \"bottom-end\" | \"top-start\" | \"top-end\"', defaultValue: '\"bottom-start\"', description: 'Preferred placement; flips on overflow.' },\n { name: 'matchAnchorWidth', type: 'boolean', defaultValue: 'true', description: \"Match the positioning anchor's width (the trigger by default, or `anchorRef` if provided).\" },\n { name: 'anchorRef', type: 'RefObject<HTMLElement | null>', description: \"Override what the popover positions / sizes against. Defaults to the trigger element. Use when the trigger is a small affordance inside a larger field (e.g. PhoneInput's country button inside the phone field).\" },\n { name: 'showCheckmark', type: 'boolean', defaultValue: 'true', description: 'Listbox only — show the right-edge ✓ on the selected row. Set to `false` when row content already has trailing meta (dial codes, currency codes) that would compete for the right edge.' },\n { name: 'portal', type: 'boolean', defaultValue: 'true', description: 'Mount the panel into document.body — escapes clipping parents.' },\n { name: 'excludeSelected', type: 'boolean', defaultValue: 'true', description: 'MultiListbox only — hide items already in `value` from the panel.' },\n ],\n },\n};\n"],"mappings":"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","names":[]}
@@ -187,7 +187,7 @@ const menuDef = {
187
187
  { name: "onOpenChange", description: "Fires when the menu opens or closes.", payload: "boolean" }
188
188
  ],
189
189
  api: {
190
- importPath: "@viax/uxm/ui",
190
+ importPath: "@viax.io/uxm/ui",
191
191
  importNames: "Menu",
192
192
  props: [
193
193
  { name: "items", type: "MenuEntry[]", required: true, description: "Menu entries \u2014 actionable items ({ key, label, subtitle?, icon?, iconColor?, hint?, onSelect?, disabled?, danger?, current? }) and separators ({ separator: true }), in display order. Pass `subtitle` to render a two-line row (label = headline), `iconColor` to tint ONE row's glyph (prefer a `var(--color-*)` reference; raw hex only for entity-identity colours), and `current` to mark the row the user is already on (aria-current + trailing checkmark + heavier label)." },
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../../../src/studio/lib/registry/inputs/menu.ts"],"sourcesContent":["import type { ComponentDef } from '../../types';\n\nexport const menuDef: ComponentDef = {\n id: 'menu',\n name: 'Menu (Action Menu)',\n category: 'Inputs',\n description:\n \"Action / dropdown menu — a list of commands invoked from a consumer-owned trigger (a ⋮ IconButton, a Button, anything). Built on the same headless Popover as Listbox (positioning, portal, outside-click, Escape) but with menu semantics (role=menu / menuitem / separator) and NO selected-value state: pick a row → run its action → dismiss. Reach for Listbox/Select when you need to HOLD a chosen value; reach for Menu for row ⋮ actions, overflow menus, and command lists. Supports leading icons (optionally tinted per row via the item's iconColor), trailing hints (e.g. shortcuts), optional two-line rows (a headline label + a supporting subtitle), separators, disabled rows, destructive (danger) items, and a Current row for context switchers — a workspace / scope / view picker (aria-current + a trailing checkmark + heavier label — it REFLECTS where the user is, it does not hold a value). Panel width follows the trigger when matchAnchorWidth is set (a field-like switcher trigger) and comes from content otherwise (a kebab trigger). The Shape picker swaps the live panel between the atom's two shapes — row actions (every row a command, destructive last, kebab trigger, default bottom-end) and a context switcher (sibling contexts plus one command under a separator, exactly one Current row, field trigger, matchAnchorWidth='min' + bottom-start). Both share every knob and class; only the entries differ. This entry themes the PANEL + rows; the trigger is owned entirely by the consumer's renderTrigger.\",\n styleProperties: [\n // Panel chrome — the floating card.\n { key: 'panelBg', label: 'Background', control: 'color', defaultValue: 'var(--color-card)', section: 'panel' },\n { key: 'panelBorder', label: 'Border', control: 'color', defaultValue: 'var(--color-border)', section: 'panel' },\n { key: 'panelRadius', label: 'Radius', control: 'slider', defaultValue: 8, min: 0, max: 16, step: 1, unit: 'px', section: 'panel' },\n { key: 'panelMaxHeight', label: 'Max Height', control: 'number', defaultValue: 360, min: 120, max: 600, step: 20, unit: 'px', section: 'panel' },\n\n // Drop shadow — decomposed into Color / Blur / Offset Y instead of a\n // raw `box-shadow` text field, so designers tune it with a colour\n // picker + sliders. Same pattern as the Calendar atom; the box-shadow\n // is composed from these three vars in styles.css. Defaults match the\n // floating-panel elevation (0 6px 20px rgba(0,0,0,0.10)).\n { key: 'shadowColor', label: 'Color', control: 'color', defaultValue: 'rgba(0, 0, 0, 0.10)', section: 'shadow' },\n { key: 'shadowBlur', label: 'Blur', control: 'slider', defaultValue: 20, min: 0, max: 48, step: 1, unit: 'px', section: 'shadow' },\n { key: 'shadowOffsetY', label: 'Offset Y', control: 'slider', defaultValue: 6, min: 0, max: 24, step: 1, unit: 'px', section: 'shadow' },\n\n // Item row — sizing knobs apply across all states.\n { key: 'itemPaddingX', label: 'Padding X', control: 'number', defaultValue: 10, min: 4, max: 20, step: 1, unit: 'px', section: 'item' },\n { key: 'itemPaddingY', label: 'Padding Y', control: 'number', defaultValue: 7, min: 2, max: 14, step: 1, unit: 'px', section: 'item' },\n { key: 'itemFontSize', label: 'Font Size', control: 'number', defaultValue: 13, min: 10, max: 18, step: 1, unit: 'px', section: 'item' },\n { key: 'itemRadius', label: 'Radius', control: 'slider', defaultValue: 4, min: 0, max: 12, step: 1, unit: 'px', section: 'item' },\n\n // Per-state colours — scoped by the `state` showcase variant so only\n // the knobs relevant to the displayed row state are visible. Mirrors\n // the listbox / select-dropdown convention. \"Hover\" covers both\n // mouse hover and keyboard arrow-key highlight (same `--active`\n // class). Default row has no surface of its own (panel bg shows\n // through), so only text colour is exposed there.\n { key: 'itemColor', label: 'Text', control: 'color', defaultValue: 'var(--color-text)', section: 'itemState', showWhen: { state: 'default' } },\n\n { key: 'itemActiveBg', label: 'Background', control: 'color', defaultValue: 'var(--color-surface-alt)', section: 'itemState', showWhen: { state: 'hover' } },\n { key: 'itemActiveColor', label: 'Text', control: 'color', defaultValue: 'var(--color-text)', section: 'itemState', showWhen: { state: 'hover' } },\n\n { key: 'itemDisabledOpacity', label: 'Opacity', control: 'slider', defaultValue: 0.4, min: 0.1, max: 1, step: 0.05, section: 'itemState', showWhen: { state: 'disabled' } },\n\n // Destructive rows (Delete etc.) — danger text at rest, danger-tinted\n // surface when highlighted.\n { key: 'itemDangerColor', label: 'Text', control: 'color', defaultValue: 'var(--color-danger-text)', section: 'itemState', showWhen: { state: 'danger' } },\n { key: 'itemDangerActiveBg', label: 'Hover Background', control: 'color', defaultValue: 'var(--color-danger-bg)', section: 'itemState', showWhen: { state: 'danger' } },\n\n // The row the user is currently ON (a switcher's active workspace) —\n // weight + a trailing checkmark, no colour of its own so `itemColor`\n // and the danger tone keep reaching it and the checkmark inherits the\n // row. Background defaults to transparent: a resting tint collided\n // with the hover surface, whose default is the obvious\n // `--color-surface-alt`. The knob stays so a designer can opt in; the\n // CSS rule order keeps hover on top of it either way.\n { key: 'itemCurrentBg', label: 'Background', control: 'color', defaultValue: 'transparent', section: 'itemState', showWhen: { state: 'current' } },\n { key: 'itemCurrentFontWeight', label: 'Font Weight', control: 'select', defaultValue: '600', options: ['400', '500', '600', '700'], section: 'itemState', showWhen: { state: 'current' } },\n\n // Leading icon colour at rest (tracks the row text colour when\n // active / danger — no separate knobs for those states).\n //\n // `--color-text-strong`, not `--color-text-subtle`: subtle measures\n // 1.48:1 on the panel in the light theme (2.85:1 dark), below even the\n // 3:1 non-text floor, and ends up fainter than a disabled row — a live\n // glyph read as switched off. See the note in menu.scss.\n { key: 'itemIconColor', label: 'Color', control: 'color', defaultValue: 'var(--color-text-strong)', section: 'icon', showWhen: { withIcons: 'yes' } },\n\n // Trailing hint (a shortcut echo like ⌘C). Muted is BELOW the AA floor\n // for text at 2.54:1 — a deliberate exception because the hint carries\n // no content the label lacks. The subtitle below refuses the same token\n // for exactly the opposite reason; see menu.scss.\n { key: 'itemHintFontSize', label: 'Font Size', control: 'number', defaultValue: 12, min: 9, max: 16, step: 1, unit: 'px', section: 'hint', showWhen: { withHints: 'yes' } },\n { key: 'itemHintColor', label: 'Color', control: 'color', defaultValue: 'var(--color-text-muted)', section: 'hint', showWhen: { withHints: 'yes' } },\n\n // Two-line rows — a headline (label) plus a supporting subtitle\n // beneath. Only shown when the Subtitles variant is on.\n { key: 'itemSubtitleFontSize', label: 'Font Size', control: 'number', defaultValue: 11, min: 9, max: 16, step: 1, unit: 'px', section: 'subtitle', showWhen: { withSubtitles: 'yes' } },\n // Default is text-STRONG, not text-muted: muted fails WCAG AA on the\n // panel in the light theme (2.54:1) and a subtitle carries real content.\n // See the note in menu.scss.\n { key: 'itemSubtitleColor', label: 'Color', control: 'color', defaultValue: 'var(--color-text-strong)', section: 'subtitle', showWhen: { withSubtitles: 'yes' } },\n { key: 'itemSubtitleGap', label: 'Row Gap', control: 'number', defaultValue: 2, min: 0, max: 8, step: 1, unit: 'px', section: 'subtitle', showWhen: { withSubtitles: 'yes' } },\n\n // Separator divider colour. A separator divides ROWS, so the single-row\n // static showcase has nothing to draw it between — open the live menu to\n // see this one land.\n { key: 'separatorColor', label: 'Color', control: 'color', defaultValue: 'var(--color-border)', section: 'separator', showWhen: { withSeparator: 'yes' } },\n ],\n layoutVariants: [\n {\n // Which state the static showcase rows paint. The interactive\n // instance (a real ⋮ trigger) below is always live — hover /\n // keyboard exercise the real CSS independently. This picker is\n // purely to VISUALLY confirm each per-state knob without having\n // to hover the live menu.\n key: 'state',\n label: 'Row State',\n options: [\n { value: 'default', label: 'Default' },\n { value: 'hover', label: 'Hover' },\n { value: 'disabled', label: 'Disabled' },\n { value: 'danger', label: 'Danger' },\n // `current` is ORTHOGONAL to the others — a row can be current and\n // hovered and disabled at once — so this option is a knob-scoping\n // device, not a claim of exclusivity (the same licence `hover` and\n // `disabled` already take here). The showcase paints the picked state\n // on its single row AT REST and never stacks one state on another:\n // forcing the highlight under `Current` made it contradict its own\n // knobs (`itemCurrentBg` defaults to `transparent`) and read as\n // \"current has a background\". Hover the current row in the LIVE menu\n // to see the two compose.\n { value: 'current', label: 'Current' },\n ],\n defaultValue: 'default',\n },\n {\n // Which of the atom's two shapes the LIVE panel demonstrates. Both are\n // legitimately this atom — they share every knob, every class and the\n // same ARIA; only the entries differ, plus the trigger and placement a\n // consumer would pick. Scopes no knobs on purpose: it changes the\n // example, not the knob set. It exists because collapsing the demo to\n // one shape hid the other, and mixing them into one list made a\n // switcher row stick out among commands — telling two stories at once.\n key: 'shape',\n label: 'Shape',\n options: [\n { value: 'actions', label: 'Row actions' },\n { value: 'switcher', label: 'Switcher' },\n ],\n defaultValue: 'actions',\n },\n {\n key: 'withIcons',\n label: 'Leading Icons',\n options: [\n { value: 'yes', label: 'On' },\n { value: 'no', label: 'Off' },\n ],\n defaultValue: 'yes',\n },\n {\n key: 'withSeparator',\n label: 'Separator',\n options: [\n { value: 'yes', label: 'On' },\n { value: 'no', label: 'Off' },\n ],\n defaultValue: 'yes',\n },\n {\n // Trailing shortcut hints. Off by default: with Subtitles also on, a\n // row concatenates label + subtitle + hint into one accessible name\n // — the anti-pattern the README warns about. Worth being able to SEE\n // (it is also visually tight inside maxWidth 280), not worth\n // shipping as the baseline.\n key: 'withHints',\n label: 'Hints',\n options: [\n { value: 'yes', label: 'On' },\n { value: 'no', label: 'Off' },\n ],\n defaultValue: 'no',\n },\n {\n // Turns each row into a two-line headline + subtitle item. Off by\n // default so the classic single-line menu is the baseline.\n key: 'withSubtitles',\n label: 'Subtitles',\n options: [\n { value: 'yes', label: 'On' },\n { value: 'no', label: 'Off' },\n ],\n defaultValue: 'no',\n },\n ],\n events: [\n { name: 'onSelect', description: \"Fires when an item is invoked (click / Enter / Space). The menu closes afterward. Per-item — wired via each item's `onSelect`.\", payload: 'void' },\n { name: 'onOpenChange', description: 'Fires when the menu opens or closes.', payload: 'boolean' },\n ],\n api: {\n importPath: '@viax/uxm/ui',\n importNames: 'Menu',\n props: [\n { name: 'items', type: 'MenuEntry[]', required: true, description: 'Menu entries — actionable items ({ key, label, subtitle?, icon?, iconColor?, hint?, onSelect?, disabled?, danger?, current? }) and separators ({ separator: true }), in display order. Pass `subtitle` to render a two-line row (label = headline), `iconColor` to tint ONE row\\'s glyph (prefer a `var(--color-*)` reference; raw hex only for entity-identity colours), and `current` to mark the row the user is already on (aria-current + trailing checkmark + heavier label).' },\n { name: 'renderTrigger', type: '(api: { open, triggerProps }) => ReactNode', required: true, description: 'Render the trigger. Spread `triggerProps` on your interactive element (an IconButton ⋮, a Button) — wires ref + click + ARIA in one go.' },\n { name: 'placement', type: '\"bottom-start\" | \"bottom-end\" | \"top-start\" | \"top-end\"', defaultValue: '\"bottom-end\"', description: 'Preferred placement; flips on overflow. Defaults to bottom-end since menus usually align to a trailing ⋮.' },\n { name: 'open', type: 'boolean', description: 'Controlled open state. Pair with onOpenChange. Omit for uncontrolled.' },\n { name: 'onOpenChange', type: '(open: boolean) => void', description: 'Called whenever the menu wants to open/close.' },\n { name: 'minWidth', type: 'number', defaultValue: '160', description: 'Minimum panel width in px.' },\n { name: 'maxWidth', type: 'number', defaultValue: '280', description: 'Maximum panel width in px — long labels truncate beyond it. The default applies only while matchAnchorWidth is off.' },\n { name: 'matchAnchorWidth', type: 'boolean | \"min\"', defaultValue: 'false', description: 'Tie the panel width to the trigger: true makes it equal, \"min\" makes the trigger width a floor the panel can grow past. Use it for a field-like trigger that displays a value (a workspace switcher) — the panel then reads as a continuation of the control, the native <select> convention; \"min\" is the forgiving choice since user-authored labels outgrow a fixed width. Never use it with an icon-only / kebab trigger: you would get a 32px panel, which is why the default is false and placement is bottom-end. Setting it also drops the 160/280 defaults, which would otherwise clamp a wide trigger\\'s panel narrower than the trigger. Restoring bounds is asymmetric: maxWidth is always honoured, but minWidth is ignored under \\'min\\' (Popover makes the measured anchor width the floor) — use true plus an explicit minWidth if you need a floor wider than the trigger.' },\n ],\n },\n};\n"],"mappings":"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","names":[]}
1
+ {"version":3,"sources":["../../../../../src/studio/lib/registry/inputs/menu.ts"],"sourcesContent":["import type { ComponentDef } from '../../types';\n\nexport const menuDef: ComponentDef = {\n id: 'menu',\n name: 'Menu (Action Menu)',\n category: 'Inputs',\n description:\n \"Action / dropdown menu — a list of commands invoked from a consumer-owned trigger (a ⋮ IconButton, a Button, anything). Built on the same headless Popover as Listbox (positioning, portal, outside-click, Escape) but with menu semantics (role=menu / menuitem / separator) and NO selected-value state: pick a row → run its action → dismiss. Reach for Listbox/Select when you need to HOLD a chosen value; reach for Menu for row ⋮ actions, overflow menus, and command lists. Supports leading icons (optionally tinted per row via the item's iconColor), trailing hints (e.g. shortcuts), optional two-line rows (a headline label + a supporting subtitle), separators, disabled rows, destructive (danger) items, and a Current row for context switchers — a workspace / scope / view picker (aria-current + a trailing checkmark + heavier label — it REFLECTS where the user is, it does not hold a value). Panel width follows the trigger when matchAnchorWidth is set (a field-like switcher trigger) and comes from content otherwise (a kebab trigger). The Shape picker swaps the live panel between the atom's two shapes — row actions (every row a command, destructive last, kebab trigger, default bottom-end) and a context switcher (sibling contexts plus one command under a separator, exactly one Current row, field trigger, matchAnchorWidth='min' + bottom-start). Both share every knob and class; only the entries differ. This entry themes the PANEL + rows; the trigger is owned entirely by the consumer's renderTrigger.\",\n styleProperties: [\n // Panel chrome — the floating card.\n { key: 'panelBg', label: 'Background', control: 'color', defaultValue: 'var(--color-card)', section: 'panel' },\n { key: 'panelBorder', label: 'Border', control: 'color', defaultValue: 'var(--color-border)', section: 'panel' },\n { key: 'panelRadius', label: 'Radius', control: 'slider', defaultValue: 8, min: 0, max: 16, step: 1, unit: 'px', section: 'panel' },\n { key: 'panelMaxHeight', label: 'Max Height', control: 'number', defaultValue: 360, min: 120, max: 600, step: 20, unit: 'px', section: 'panel' },\n\n // Drop shadow — decomposed into Color / Blur / Offset Y instead of a\n // raw `box-shadow` text field, so designers tune it with a colour\n // picker + sliders. Same pattern as the Calendar atom; the box-shadow\n // is composed from these three vars in styles.css. Defaults match the\n // floating-panel elevation (0 6px 20px rgba(0,0,0,0.10)).\n { key: 'shadowColor', label: 'Color', control: 'color', defaultValue: 'rgba(0, 0, 0, 0.10)', section: 'shadow' },\n { key: 'shadowBlur', label: 'Blur', control: 'slider', defaultValue: 20, min: 0, max: 48, step: 1, unit: 'px', section: 'shadow' },\n { key: 'shadowOffsetY', label: 'Offset Y', control: 'slider', defaultValue: 6, min: 0, max: 24, step: 1, unit: 'px', section: 'shadow' },\n\n // Item row — sizing knobs apply across all states.\n { key: 'itemPaddingX', label: 'Padding X', control: 'number', defaultValue: 10, min: 4, max: 20, step: 1, unit: 'px', section: 'item' },\n { key: 'itemPaddingY', label: 'Padding Y', control: 'number', defaultValue: 7, min: 2, max: 14, step: 1, unit: 'px', section: 'item' },\n { key: 'itemFontSize', label: 'Font Size', control: 'number', defaultValue: 13, min: 10, max: 18, step: 1, unit: 'px', section: 'item' },\n { key: 'itemRadius', label: 'Radius', control: 'slider', defaultValue: 4, min: 0, max: 12, step: 1, unit: 'px', section: 'item' },\n\n // Per-state colours — scoped by the `state` showcase variant so only\n // the knobs relevant to the displayed row state are visible. Mirrors\n // the listbox / select-dropdown convention. \"Hover\" covers both\n // mouse hover and keyboard arrow-key highlight (same `--active`\n // class). Default row has no surface of its own (panel bg shows\n // through), so only text colour is exposed there.\n { key: 'itemColor', label: 'Text', control: 'color', defaultValue: 'var(--color-text)', section: 'itemState', showWhen: { state: 'default' } },\n\n { key: 'itemActiveBg', label: 'Background', control: 'color', defaultValue: 'var(--color-surface-alt)', section: 'itemState', showWhen: { state: 'hover' } },\n { key: 'itemActiveColor', label: 'Text', control: 'color', defaultValue: 'var(--color-text)', section: 'itemState', showWhen: { state: 'hover' } },\n\n { key: 'itemDisabledOpacity', label: 'Opacity', control: 'slider', defaultValue: 0.4, min: 0.1, max: 1, step: 0.05, section: 'itemState', showWhen: { state: 'disabled' } },\n\n // Destructive rows (Delete etc.) — danger text at rest, danger-tinted\n // surface when highlighted.\n { key: 'itemDangerColor', label: 'Text', control: 'color', defaultValue: 'var(--color-danger-text)', section: 'itemState', showWhen: { state: 'danger' } },\n { key: 'itemDangerActiveBg', label: 'Hover Background', control: 'color', defaultValue: 'var(--color-danger-bg)', section: 'itemState', showWhen: { state: 'danger' } },\n\n // The row the user is currently ON (a switcher's active workspace) —\n // weight + a trailing checkmark, no colour of its own so `itemColor`\n // and the danger tone keep reaching it and the checkmark inherits the\n // row. Background defaults to transparent: a resting tint collided\n // with the hover surface, whose default is the obvious\n // `--color-surface-alt`. The knob stays so a designer can opt in; the\n // CSS rule order keeps hover on top of it either way.\n { key: 'itemCurrentBg', label: 'Background', control: 'color', defaultValue: 'transparent', section: 'itemState', showWhen: { state: 'current' } },\n { key: 'itemCurrentFontWeight', label: 'Font Weight', control: 'select', defaultValue: '600', options: ['400', '500', '600', '700'], section: 'itemState', showWhen: { state: 'current' } },\n\n // Leading icon colour at rest (tracks the row text colour when\n // active / danger — no separate knobs for those states).\n //\n // `--color-text-strong`, not `--color-text-subtle`: subtle measures\n // 1.48:1 on the panel in the light theme (2.85:1 dark), below even the\n // 3:1 non-text floor, and ends up fainter than a disabled row — a live\n // glyph read as switched off. See the note in menu.scss.\n { key: 'itemIconColor', label: 'Color', control: 'color', defaultValue: 'var(--color-text-strong)', section: 'icon', showWhen: { withIcons: 'yes' } },\n\n // Trailing hint (a shortcut echo like ⌘C). Muted is BELOW the AA floor\n // for text at 2.54:1 — a deliberate exception because the hint carries\n // no content the label lacks. The subtitle below refuses the same token\n // for exactly the opposite reason; see menu.scss.\n { key: 'itemHintFontSize', label: 'Font Size', control: 'number', defaultValue: 12, min: 9, max: 16, step: 1, unit: 'px', section: 'hint', showWhen: { withHints: 'yes' } },\n { key: 'itemHintColor', label: 'Color', control: 'color', defaultValue: 'var(--color-text-muted)', section: 'hint', showWhen: { withHints: 'yes' } },\n\n // Two-line rows — a headline (label) plus a supporting subtitle\n // beneath. Only shown when the Subtitles variant is on.\n { key: 'itemSubtitleFontSize', label: 'Font Size', control: 'number', defaultValue: 11, min: 9, max: 16, step: 1, unit: 'px', section: 'subtitle', showWhen: { withSubtitles: 'yes' } },\n // Default is text-STRONG, not text-muted: muted fails WCAG AA on the\n // panel in the light theme (2.54:1) and a subtitle carries real content.\n // See the note in menu.scss.\n { key: 'itemSubtitleColor', label: 'Color', control: 'color', defaultValue: 'var(--color-text-strong)', section: 'subtitle', showWhen: { withSubtitles: 'yes' } },\n { key: 'itemSubtitleGap', label: 'Row Gap', control: 'number', defaultValue: 2, min: 0, max: 8, step: 1, unit: 'px', section: 'subtitle', showWhen: { withSubtitles: 'yes' } },\n\n // Separator divider colour. A separator divides ROWS, so the single-row\n // static showcase has nothing to draw it between — open the live menu to\n // see this one land.\n { key: 'separatorColor', label: 'Color', control: 'color', defaultValue: 'var(--color-border)', section: 'separator', showWhen: { withSeparator: 'yes' } },\n ],\n layoutVariants: [\n {\n // Which state the static showcase rows paint. The interactive\n // instance (a real ⋮ trigger) below is always live — hover /\n // keyboard exercise the real CSS independently. This picker is\n // purely to VISUALLY confirm each per-state knob without having\n // to hover the live menu.\n key: 'state',\n label: 'Row State',\n options: [\n { value: 'default', label: 'Default' },\n { value: 'hover', label: 'Hover' },\n { value: 'disabled', label: 'Disabled' },\n { value: 'danger', label: 'Danger' },\n // `current` is ORTHOGONAL to the others — a row can be current and\n // hovered and disabled at once — so this option is a knob-scoping\n // device, not a claim of exclusivity (the same licence `hover` and\n // `disabled` already take here). The showcase paints the picked state\n // on its single row AT REST and never stacks one state on another:\n // forcing the highlight under `Current` made it contradict its own\n // knobs (`itemCurrentBg` defaults to `transparent`) and read as\n // \"current has a background\". Hover the current row in the LIVE menu\n // to see the two compose.\n { value: 'current', label: 'Current' },\n ],\n defaultValue: 'default',\n },\n {\n // Which of the atom's two shapes the LIVE panel demonstrates. Both are\n // legitimately this atom — they share every knob, every class and the\n // same ARIA; only the entries differ, plus the trigger and placement a\n // consumer would pick. Scopes no knobs on purpose: it changes the\n // example, not the knob set. It exists because collapsing the demo to\n // one shape hid the other, and mixing them into one list made a\n // switcher row stick out among commands — telling two stories at once.\n key: 'shape',\n label: 'Shape',\n options: [\n { value: 'actions', label: 'Row actions' },\n { value: 'switcher', label: 'Switcher' },\n ],\n defaultValue: 'actions',\n },\n {\n key: 'withIcons',\n label: 'Leading Icons',\n options: [\n { value: 'yes', label: 'On' },\n { value: 'no', label: 'Off' },\n ],\n defaultValue: 'yes',\n },\n {\n key: 'withSeparator',\n label: 'Separator',\n options: [\n { value: 'yes', label: 'On' },\n { value: 'no', label: 'Off' },\n ],\n defaultValue: 'yes',\n },\n {\n // Trailing shortcut hints. Off by default: with Subtitles also on, a\n // row concatenates label + subtitle + hint into one accessible name\n // — the anti-pattern the README warns about. Worth being able to SEE\n // (it is also visually tight inside maxWidth 280), not worth\n // shipping as the baseline.\n key: 'withHints',\n label: 'Hints',\n options: [\n { value: 'yes', label: 'On' },\n { value: 'no', label: 'Off' },\n ],\n defaultValue: 'no',\n },\n {\n // Turns each row into a two-line headline + subtitle item. Off by\n // default so the classic single-line menu is the baseline.\n key: 'withSubtitles',\n label: 'Subtitles',\n options: [\n { value: 'yes', label: 'On' },\n { value: 'no', label: 'Off' },\n ],\n defaultValue: 'no',\n },\n ],\n events: [\n { name: 'onSelect', description: \"Fires when an item is invoked (click / Enter / Space). The menu closes afterward. Per-item — wired via each item's `onSelect`.\", payload: 'void' },\n { name: 'onOpenChange', description: 'Fires when the menu opens or closes.', payload: 'boolean' },\n ],\n api: {\n importPath: '@viax.io/uxm/ui',\n importNames: 'Menu',\n props: [\n { name: 'items', type: 'MenuEntry[]', required: true, description: 'Menu entries — actionable items ({ key, label, subtitle?, icon?, iconColor?, hint?, onSelect?, disabled?, danger?, current? }) and separators ({ separator: true }), in display order. Pass `subtitle` to render a two-line row (label = headline), `iconColor` to tint ONE row\\'s glyph (prefer a `var(--color-*)` reference; raw hex only for entity-identity colours), and `current` to mark the row the user is already on (aria-current + trailing checkmark + heavier label).' },\n { name: 'renderTrigger', type: '(api: { open, triggerProps }) => ReactNode', required: true, description: 'Render the trigger. Spread `triggerProps` on your interactive element (an IconButton ⋮, a Button) — wires ref + click + ARIA in one go.' },\n { name: 'placement', type: '\"bottom-start\" | \"bottom-end\" | \"top-start\" | \"top-end\"', defaultValue: '\"bottom-end\"', description: 'Preferred placement; flips on overflow. Defaults to bottom-end since menus usually align to a trailing ⋮.' },\n { name: 'open', type: 'boolean', description: 'Controlled open state. Pair with onOpenChange. Omit for uncontrolled.' },\n { name: 'onOpenChange', type: '(open: boolean) => void', description: 'Called whenever the menu wants to open/close.' },\n { name: 'minWidth', type: 'number', defaultValue: '160', description: 'Minimum panel width in px.' },\n { name: 'maxWidth', type: 'number', defaultValue: '280', description: 'Maximum panel width in px — long labels truncate beyond it. The default applies only while matchAnchorWidth is off.' },\n { name: 'matchAnchorWidth', type: 'boolean | \"min\"', defaultValue: 'false', description: 'Tie the panel width to the trigger: true makes it equal, \"min\" makes the trigger width a floor the panel can grow past. Use it for a field-like trigger that displays a value (a workspace switcher) — the panel then reads as a continuation of the control, the native <select> convention; \"min\" is the forgiving choice since user-authored labels outgrow a fixed width. Never use it with an icon-only / kebab trigger: you would get a 32px panel, which is why the default is false and placement is bottom-end. Setting it also drops the 160/280 defaults, which would otherwise clamp a wide trigger\\'s panel narrower than the trigger. Restoring bounds is asymmetric: maxWidth is always honoured, but minWidth is ignored under \\'min\\' (Popover makes the measured anchor width the floor) — use true plus an explicit minWidth if you need a floor wider than the trigger.' },\n ],\n },\n};\n"],"mappings":";;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAEO,MAAM,UAAwB;AAAA,EACnC,IAAI;AAAA,EACJ,MAAM;AAAA,EACN,UAAU;AAAA,EACV,aACE;AAAA,EACF,iBAAiB;AAAA;AAAA,IAEf,EAAE,KAAK,WAAW,OAAO,cAAc,SAAS,SAAS,cAAc,qBAAqB,SAAS,QAAQ;AAAA,IAC7G,EAAE,KAAK,eAAe,OAAO,UAAU,SAAS,SAAS,cAAc,uBAAuB,SAAS,QAAQ;AAAA,IAC/G,EAAE,KAAK,eAAe,OAAO,UAAU,SAAS,UAAU,cAAc,GAAG,KAAK,GAAG,KAAK,IAAI,MAAM,GAAG,MAAM,MAAM,SAAS,QAAQ;AAAA,IAClI,EAAE,KAAK,kBAAkB,OAAO,cAAc,SAAS,UAAU,cAAc,KAAK,KAAK,KAAK,KAAK,KAAK,MAAM,IAAI,MAAM,MAAM,SAAS,QAAQ;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,IAO/I,EAAE,KAAK,eAAe,OAAO,SAAS,SAAS,SAAS,cAAc,uBAAuB,SAAS,SAAS;AAAA,IAC/G,EAAE,KAAK,cAAc,OAAO,QAAQ,SAAS,UAAU,cAAc,IAAI,KAAK,GAAG,KAAK,IAAI,MAAM,GAAG,MAAM,MAAM,SAAS,SAAS;AAAA,IACjI,EAAE,KAAK,iBAAiB,OAAO,YAAY,SAAS,UAAU,cAAc,GAAG,KAAK,GAAG,KAAK,IAAI,MAAM,GAAG,MAAM,MAAM,SAAS,SAAS;AAAA;AAAA,IAGvI,EAAE,KAAK,gBAAgB,OAAO,aAAa,SAAS,UAAU,cAAc,IAAI,KAAK,GAAG,KAAK,IAAI,MAAM,GAAG,MAAM,MAAM,SAAS,OAAO;AAAA,IACtI,EAAE,KAAK,gBAAgB,OAAO,aAAa,SAAS,UAAU,cAAc,GAAG,KAAK,GAAG,KAAK,IAAI,MAAM,GAAG,MAAM,MAAM,SAAS,OAAO;AAAA,IACrI,EAAE,KAAK,gBAAgB,OAAO,aAAa,SAAS,UAAU,cAAc,IAAI,KAAK,IAAI,KAAK,IAAI,MAAM,GAAG,MAAM,MAAM,SAAS,OAAO;AAAA,IACvI,EAAE,KAAK,cAAc,OAAO,UAAU,SAAS,UAAU,cAAc,GAAG,KAAK,GAAG,KAAK,IAAI,MAAM,GAAG,MAAM,MAAM,SAAS,OAAO;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,IAQhI,EAAE,KAAK,aAAa,OAAO,QAAQ,SAAS,SAAS,cAAc,qBAAqB,SAAS,aAAa,UAAU,EAAE,OAAO,UAAU,EAAE;AAAA,IAE7I,EAAE,KAAK,gBAAgB,OAAO,cAAc,SAAS,SAAS,cAAc,4BAA4B,SAAS,aAAa,UAAU,EAAE,OAAO,QAAQ,EAAE;AAAA,IAC3J,EAAE,KAAK,mBAAmB,OAAO,QAAQ,SAAS,SAAS,cAAc,qBAAqB,SAAS,aAAa,UAAU,EAAE,OAAO,QAAQ,EAAE;AAAA,IAEjJ,EAAE,KAAK,uBAAuB,OAAO,WAAW,SAAS,UAAU,cAAc,KAAK,KAAK,KAAK,KAAK,GAAG,MAAM,MAAM,SAAS,aAAa,UAAU,EAAE,OAAO,WAAW,EAAE;AAAA;AAAA;AAAA,IAI1K,EAAE,KAAK,mBAAmB,OAAO,QAAQ,SAAS,SAAS,cAAc,4BAA4B,SAAS,aAAa,UAAU,EAAE,OAAO,SAAS,EAAE;AAAA,IACzJ,EAAE,KAAK,sBAAsB,OAAO,oBAAoB,SAAS,SAAS,cAAc,0BAA0B,SAAS,aAAa,UAAU,EAAE,OAAO,SAAS,EAAE;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,IAStK,EAAE,KAAK,iBAAiB,OAAO,cAAc,SAAS,SAAS,cAAc,eAAe,SAAS,aAAa,UAAU,EAAE,OAAO,UAAU,EAAE;AAAA,IACjJ,EAAE,KAAK,yBAAyB,OAAO,eAAe,SAAS,UAAU,cAAc,OAAO,SAAS,CAAC,OAAO,OAAO,OAAO,KAAK,GAAG,SAAS,aAAa,UAAU,EAAE,OAAO,UAAU,EAAE;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,IAS1L,EAAE,KAAK,iBAAiB,OAAO,SAAS,SAAS,SAAS,cAAc,4BAA4B,SAAS,QAAQ,UAAU,EAAE,WAAW,MAAM,EAAE;AAAA;AAAA;AAAA;AAAA;AAAA,IAMpJ,EAAE,KAAK,oBAAoB,OAAO,aAAa,SAAS,UAAU,cAAc,IAAI,KAAK,GAAG,KAAK,IAAI,MAAM,GAAG,MAAM,MAAM,SAAS,QAAQ,UAAU,EAAE,WAAW,MAAM,EAAE;AAAA,IAC1K,EAAE,KAAK,iBAAiB,OAAO,SAAS,SAAS,SAAS,cAAc,2BAA2B,SAAS,QAAQ,UAAU,EAAE,WAAW,MAAM,EAAE;AAAA;AAAA;AAAA,IAInJ,EAAE,KAAK,wBAAwB,OAAO,aAAa,SAAS,UAAU,cAAc,IAAI,KAAK,GAAG,KAAK,IAAI,MAAM,GAAG,MAAM,MAAM,SAAS,YAAY,UAAU,EAAE,eAAe,MAAM,EAAE;AAAA;AAAA;AAAA;AAAA,IAItL,EAAE,KAAK,qBAAqB,OAAO,SAAS,SAAS,SAAS,cAAc,4BAA4B,SAAS,YAAY,UAAU,EAAE,eAAe,MAAM,EAAE;AAAA,IAChK,EAAE,KAAK,mBAAmB,OAAO,WAAW,SAAS,UAAU,cAAc,GAAG,KAAK,GAAG,KAAK,GAAG,MAAM,GAAG,MAAM,MAAM,SAAS,YAAY,UAAU,EAAE,eAAe,MAAM,EAAE;AAAA;AAAA;AAAA;AAAA,IAK7K,EAAE,KAAK,kBAAkB,OAAO,SAAS,SAAS,SAAS,cAAc,uBAAuB,SAAS,aAAa,UAAU,EAAE,eAAe,MAAM,EAAE;AAAA,EAC3J;AAAA,EACA,gBAAgB;AAAA,IACd;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,MAME,KAAK;AAAA,MACL,OAAO;AAAA,MACP,SAAS;AAAA,QACP,EAAE,OAAO,WAAW,OAAO,UAAU;AAAA,QACrC,EAAE,OAAO,SAAS,OAAO,QAAQ;AAAA,QACjC,EAAE,OAAO,YAAY,OAAO,WAAW;AAAA,QACvC,EAAE,OAAO,UAAU,OAAO,SAAS;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,QAUnC,EAAE,OAAO,WAAW,OAAO,UAAU;AAAA,MACvC;AAAA,MACA,cAAc;AAAA,IAChB;AAAA,IACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,MAQE,KAAK;AAAA,MACL,OAAO;AAAA,MACP,SAAS;AAAA,QACP,EAAE,OAAO,WAAW,OAAO,cAAc;AAAA,QACzC,EAAE,OAAO,YAAY,OAAO,WAAW;AAAA,MACzC;AAAA,MACA,cAAc;AAAA,IAChB;AAAA,IACA;AAAA,MACE,KAAK;AAAA,MACL,OAAO;AAAA,MACP,SAAS;AAAA,QACP,EAAE,OAAO,OAAO,OAAO,KAAK;AAAA,QAC5B,EAAE,OAAO,MAAM,OAAO,MAAM;AAAA,MAC9B;AAAA,MACA,cAAc;AAAA,IAChB;AAAA,IACA;AAAA,MACE,KAAK;AAAA,MACL,OAAO;AAAA,MACP,SAAS;AAAA,QACP,EAAE,OAAO,OAAO,OAAO,KAAK;AAAA,QAC5B,EAAE,OAAO,MAAM,OAAO,MAAM;AAAA,MAC9B;AAAA,MACA,cAAc;AAAA,IAChB;AAAA,IACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,MAME,KAAK;AAAA,MACL,OAAO;AAAA,MACP,SAAS;AAAA,QACP,EAAE,OAAO,OAAO,OAAO,KAAK;AAAA,QAC5B,EAAE,OAAO,MAAM,OAAO,MAAM;AAAA,MAC9B;AAAA,MACA,cAAc;AAAA,IAChB;AAAA,IACA;AAAA;AAAA;AAAA,MAGE,KAAK;AAAA,MACL,OAAO;AAAA,MACP,SAAS;AAAA,QACP,EAAE,OAAO,OAAO,OAAO,KAAK;AAAA,QAC5B,EAAE,OAAO,MAAM,OAAO,MAAM;AAAA,MAC9B;AAAA,MACA,cAAc;AAAA,IAChB;AAAA,EACF;AAAA,EACA,QAAQ;AAAA,IACN,EAAE,MAAM,YAAY,aAAa,uIAAkI,SAAS,OAAO;AAAA,IACnL,EAAE,MAAM,gBAAgB,aAAa,wCAAwC,SAAS,UAAU;AAAA,EAClG;AAAA,EACA,KAAK;AAAA,IACH,YAAY;AAAA,IACZ,aAAa;AAAA,IACb,OAAO;AAAA,MACL,EAAE,MAAM,SAAS,MAAM,eAAe,UAAU,MAAM,aAAa,0dAAsd;AAAA,MACzhB,EAAE,MAAM,iBAAiB,MAAM,8CAA8C,UAAU,MAAM,aAAa,oJAA0I;AAAA,MACpP,EAAE,MAAM,aAAa,MAAM,2DAA2D,cAAc,gBAAgB,aAAa,iHAA4G;AAAA,MAC7O,EAAE,MAAM,QAAQ,MAAM,WAAW,aAAa,wEAAwE;AAAA,MACtH,EAAE,MAAM,gBAAgB,MAAM,2BAA2B,aAAa,gDAAgD;AAAA,MACtH,EAAE,MAAM,YAAY,MAAM,UAAU,cAAc,OAAO,aAAa,6BAA6B;AAAA,MACnG,EAAE,MAAM,YAAY,MAAM,UAAU,cAAc,OAAO,aAAa,2HAAsH;AAAA,MAC5L,EAAE,MAAM,oBAAoB,MAAM,mBAAmB,cAAc,SAAS,aAAa,q2BAA81B;AAAA,IACz7B;AAAA,EACF;AACF;","names":[]}
@@ -164,7 +164,7 @@ const menuDef = {
164
164
  { name: "onOpenChange", description: "Fires when the menu opens or closes.", payload: "boolean" }
165
165
  ],
166
166
  api: {
167
- importPath: "@viax/uxm/ui",
167
+ importPath: "@viax.io/uxm/ui",
168
168
  importNames: "Menu",
169
169
  props: [
170
170
  { name: "items", type: "MenuEntry[]", required: true, description: "Menu entries \u2014 actionable items ({ key, label, subtitle?, icon?, iconColor?, hint?, onSelect?, disabled?, danger?, current? }) and separators ({ separator: true }), in display order. Pass `subtitle` to render a two-line row (label = headline), `iconColor` to tint ONE row's glyph (prefer a `var(--color-*)` reference; raw hex only for entity-identity colours), and `current` to mark the row the user is already on (aria-current + trailing checkmark + heavier label)." },
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../../../src/studio/lib/registry/inputs/menu.ts"],"sourcesContent":["import type { ComponentDef } from '../../types';\n\nexport const menuDef: ComponentDef = {\n id: 'menu',\n name: 'Menu (Action Menu)',\n category: 'Inputs',\n description:\n \"Action / dropdown menu — a list of commands invoked from a consumer-owned trigger (a ⋮ IconButton, a Button, anything). Built on the same headless Popover as Listbox (positioning, portal, outside-click, Escape) but with menu semantics (role=menu / menuitem / separator) and NO selected-value state: pick a row → run its action → dismiss. Reach for Listbox/Select when you need to HOLD a chosen value; reach for Menu for row ⋮ actions, overflow menus, and command lists. Supports leading icons (optionally tinted per row via the item's iconColor), trailing hints (e.g. shortcuts), optional two-line rows (a headline label + a supporting subtitle), separators, disabled rows, destructive (danger) items, and a Current row for context switchers — a workspace / scope / view picker (aria-current + a trailing checkmark + heavier label — it REFLECTS where the user is, it does not hold a value). Panel width follows the trigger when matchAnchorWidth is set (a field-like switcher trigger) and comes from content otherwise (a kebab trigger). The Shape picker swaps the live panel between the atom's two shapes — row actions (every row a command, destructive last, kebab trigger, default bottom-end) and a context switcher (sibling contexts plus one command under a separator, exactly one Current row, field trigger, matchAnchorWidth='min' + bottom-start). Both share every knob and class; only the entries differ. This entry themes the PANEL + rows; the trigger is owned entirely by the consumer's renderTrigger.\",\n styleProperties: [\n // Panel chrome — the floating card.\n { key: 'panelBg', label: 'Background', control: 'color', defaultValue: 'var(--color-card)', section: 'panel' },\n { key: 'panelBorder', label: 'Border', control: 'color', defaultValue: 'var(--color-border)', section: 'panel' },\n { key: 'panelRadius', label: 'Radius', control: 'slider', defaultValue: 8, min: 0, max: 16, step: 1, unit: 'px', section: 'panel' },\n { key: 'panelMaxHeight', label: 'Max Height', control: 'number', defaultValue: 360, min: 120, max: 600, step: 20, unit: 'px', section: 'panel' },\n\n // Drop shadow — decomposed into Color / Blur / Offset Y instead of a\n // raw `box-shadow` text field, so designers tune it with a colour\n // picker + sliders. Same pattern as the Calendar atom; the box-shadow\n // is composed from these three vars in styles.css. Defaults match the\n // floating-panel elevation (0 6px 20px rgba(0,0,0,0.10)).\n { key: 'shadowColor', label: 'Color', control: 'color', defaultValue: 'rgba(0, 0, 0, 0.10)', section: 'shadow' },\n { key: 'shadowBlur', label: 'Blur', control: 'slider', defaultValue: 20, min: 0, max: 48, step: 1, unit: 'px', section: 'shadow' },\n { key: 'shadowOffsetY', label: 'Offset Y', control: 'slider', defaultValue: 6, min: 0, max: 24, step: 1, unit: 'px', section: 'shadow' },\n\n // Item row — sizing knobs apply across all states.\n { key: 'itemPaddingX', label: 'Padding X', control: 'number', defaultValue: 10, min: 4, max: 20, step: 1, unit: 'px', section: 'item' },\n { key: 'itemPaddingY', label: 'Padding Y', control: 'number', defaultValue: 7, min: 2, max: 14, step: 1, unit: 'px', section: 'item' },\n { key: 'itemFontSize', label: 'Font Size', control: 'number', defaultValue: 13, min: 10, max: 18, step: 1, unit: 'px', section: 'item' },\n { key: 'itemRadius', label: 'Radius', control: 'slider', defaultValue: 4, min: 0, max: 12, step: 1, unit: 'px', section: 'item' },\n\n // Per-state colours — scoped by the `state` showcase variant so only\n // the knobs relevant to the displayed row state are visible. Mirrors\n // the listbox / select-dropdown convention. \"Hover\" covers both\n // mouse hover and keyboard arrow-key highlight (same `--active`\n // class). Default row has no surface of its own (panel bg shows\n // through), so only text colour is exposed there.\n { key: 'itemColor', label: 'Text', control: 'color', defaultValue: 'var(--color-text)', section: 'itemState', showWhen: { state: 'default' } },\n\n { key: 'itemActiveBg', label: 'Background', control: 'color', defaultValue: 'var(--color-surface-alt)', section: 'itemState', showWhen: { state: 'hover' } },\n { key: 'itemActiveColor', label: 'Text', control: 'color', defaultValue: 'var(--color-text)', section: 'itemState', showWhen: { state: 'hover' } },\n\n { key: 'itemDisabledOpacity', label: 'Opacity', control: 'slider', defaultValue: 0.4, min: 0.1, max: 1, step: 0.05, section: 'itemState', showWhen: { state: 'disabled' } },\n\n // Destructive rows (Delete etc.) — danger text at rest, danger-tinted\n // surface when highlighted.\n { key: 'itemDangerColor', label: 'Text', control: 'color', defaultValue: 'var(--color-danger-text)', section: 'itemState', showWhen: { state: 'danger' } },\n { key: 'itemDangerActiveBg', label: 'Hover Background', control: 'color', defaultValue: 'var(--color-danger-bg)', section: 'itemState', showWhen: { state: 'danger' } },\n\n // The row the user is currently ON (a switcher's active workspace) —\n // weight + a trailing checkmark, no colour of its own so `itemColor`\n // and the danger tone keep reaching it and the checkmark inherits the\n // row. Background defaults to transparent: a resting tint collided\n // with the hover surface, whose default is the obvious\n // `--color-surface-alt`. The knob stays so a designer can opt in; the\n // CSS rule order keeps hover on top of it either way.\n { key: 'itemCurrentBg', label: 'Background', control: 'color', defaultValue: 'transparent', section: 'itemState', showWhen: { state: 'current' } },\n { key: 'itemCurrentFontWeight', label: 'Font Weight', control: 'select', defaultValue: '600', options: ['400', '500', '600', '700'], section: 'itemState', showWhen: { state: 'current' } },\n\n // Leading icon colour at rest (tracks the row text colour when\n // active / danger — no separate knobs for those states).\n //\n // `--color-text-strong`, not `--color-text-subtle`: subtle measures\n // 1.48:1 on the panel in the light theme (2.85:1 dark), below even the\n // 3:1 non-text floor, and ends up fainter than a disabled row — a live\n // glyph read as switched off. See the note in menu.scss.\n { key: 'itemIconColor', label: 'Color', control: 'color', defaultValue: 'var(--color-text-strong)', section: 'icon', showWhen: { withIcons: 'yes' } },\n\n // Trailing hint (a shortcut echo like ⌘C). Muted is BELOW the AA floor\n // for text at 2.54:1 — a deliberate exception because the hint carries\n // no content the label lacks. The subtitle below refuses the same token\n // for exactly the opposite reason; see menu.scss.\n { key: 'itemHintFontSize', label: 'Font Size', control: 'number', defaultValue: 12, min: 9, max: 16, step: 1, unit: 'px', section: 'hint', showWhen: { withHints: 'yes' } },\n { key: 'itemHintColor', label: 'Color', control: 'color', defaultValue: 'var(--color-text-muted)', section: 'hint', showWhen: { withHints: 'yes' } },\n\n // Two-line rows — a headline (label) plus a supporting subtitle\n // beneath. Only shown when the Subtitles variant is on.\n { key: 'itemSubtitleFontSize', label: 'Font Size', control: 'number', defaultValue: 11, min: 9, max: 16, step: 1, unit: 'px', section: 'subtitle', showWhen: { withSubtitles: 'yes' } },\n // Default is text-STRONG, not text-muted: muted fails WCAG AA on the\n // panel in the light theme (2.54:1) and a subtitle carries real content.\n // See the note in menu.scss.\n { key: 'itemSubtitleColor', label: 'Color', control: 'color', defaultValue: 'var(--color-text-strong)', section: 'subtitle', showWhen: { withSubtitles: 'yes' } },\n { key: 'itemSubtitleGap', label: 'Row Gap', control: 'number', defaultValue: 2, min: 0, max: 8, step: 1, unit: 'px', section: 'subtitle', showWhen: { withSubtitles: 'yes' } },\n\n // Separator divider colour. A separator divides ROWS, so the single-row\n // static showcase has nothing to draw it between — open the live menu to\n // see this one land.\n { key: 'separatorColor', label: 'Color', control: 'color', defaultValue: 'var(--color-border)', section: 'separator', showWhen: { withSeparator: 'yes' } },\n ],\n layoutVariants: [\n {\n // Which state the static showcase rows paint. The interactive\n // instance (a real ⋮ trigger) below is always live — hover /\n // keyboard exercise the real CSS independently. This picker is\n // purely to VISUALLY confirm each per-state knob without having\n // to hover the live menu.\n key: 'state',\n label: 'Row State',\n options: [\n { value: 'default', label: 'Default' },\n { value: 'hover', label: 'Hover' },\n { value: 'disabled', label: 'Disabled' },\n { value: 'danger', label: 'Danger' },\n // `current` is ORTHOGONAL to the others — a row can be current and\n // hovered and disabled at once — so this option is a knob-scoping\n // device, not a claim of exclusivity (the same licence `hover` and\n // `disabled` already take here). The showcase paints the picked state\n // on its single row AT REST and never stacks one state on another:\n // forcing the highlight under `Current` made it contradict its own\n // knobs (`itemCurrentBg` defaults to `transparent`) and read as\n // \"current has a background\". Hover the current row in the LIVE menu\n // to see the two compose.\n { value: 'current', label: 'Current' },\n ],\n defaultValue: 'default',\n },\n {\n // Which of the atom's two shapes the LIVE panel demonstrates. Both are\n // legitimately this atom — they share every knob, every class and the\n // same ARIA; only the entries differ, plus the trigger and placement a\n // consumer would pick. Scopes no knobs on purpose: it changes the\n // example, not the knob set. It exists because collapsing the demo to\n // one shape hid the other, and mixing them into one list made a\n // switcher row stick out among commands — telling two stories at once.\n key: 'shape',\n label: 'Shape',\n options: [\n { value: 'actions', label: 'Row actions' },\n { value: 'switcher', label: 'Switcher' },\n ],\n defaultValue: 'actions',\n },\n {\n key: 'withIcons',\n label: 'Leading Icons',\n options: [\n { value: 'yes', label: 'On' },\n { value: 'no', label: 'Off' },\n ],\n defaultValue: 'yes',\n },\n {\n key: 'withSeparator',\n label: 'Separator',\n options: [\n { value: 'yes', label: 'On' },\n { value: 'no', label: 'Off' },\n ],\n defaultValue: 'yes',\n },\n {\n // Trailing shortcut hints. Off by default: with Subtitles also on, a\n // row concatenates label + subtitle + hint into one accessible name\n // — the anti-pattern the README warns about. Worth being able to SEE\n // (it is also visually tight inside maxWidth 280), not worth\n // shipping as the baseline.\n key: 'withHints',\n label: 'Hints',\n options: [\n { value: 'yes', label: 'On' },\n { value: 'no', label: 'Off' },\n ],\n defaultValue: 'no',\n },\n {\n // Turns each row into a two-line headline + subtitle item. Off by\n // default so the classic single-line menu is the baseline.\n key: 'withSubtitles',\n label: 'Subtitles',\n options: [\n { value: 'yes', label: 'On' },\n { value: 'no', label: 'Off' },\n ],\n defaultValue: 'no',\n },\n ],\n events: [\n { name: 'onSelect', description: \"Fires when an item is invoked (click / Enter / Space). The menu closes afterward. Per-item — wired via each item's `onSelect`.\", payload: 'void' },\n { name: 'onOpenChange', description: 'Fires when the menu opens or closes.', payload: 'boolean' },\n ],\n api: {\n importPath: '@viax/uxm/ui',\n importNames: 'Menu',\n props: [\n { name: 'items', type: 'MenuEntry[]', required: true, description: 'Menu entries — actionable items ({ key, label, subtitle?, icon?, iconColor?, hint?, onSelect?, disabled?, danger?, current? }) and separators ({ separator: true }), in display order. Pass `subtitle` to render a two-line row (label = headline), `iconColor` to tint ONE row\\'s glyph (prefer a `var(--color-*)` reference; raw hex only for entity-identity colours), and `current` to mark the row the user is already on (aria-current + trailing checkmark + heavier label).' },\n { name: 'renderTrigger', type: '(api: { open, triggerProps }) => ReactNode', required: true, description: 'Render the trigger. Spread `triggerProps` on your interactive element (an IconButton ⋮, a Button) — wires ref + click + ARIA in one go.' },\n { name: 'placement', type: '\"bottom-start\" | \"bottom-end\" | \"top-start\" | \"top-end\"', defaultValue: '\"bottom-end\"', description: 'Preferred placement; flips on overflow. Defaults to bottom-end since menus usually align to a trailing ⋮.' },\n { name: 'open', type: 'boolean', description: 'Controlled open state. Pair with onOpenChange. Omit for uncontrolled.' },\n { name: 'onOpenChange', type: '(open: boolean) => void', description: 'Called whenever the menu wants to open/close.' },\n { name: 'minWidth', type: 'number', defaultValue: '160', description: 'Minimum panel width in px.' },\n { name: 'maxWidth', type: 'number', defaultValue: '280', description: 'Maximum panel width in px — long labels truncate beyond it. The default applies only while matchAnchorWidth is off.' },\n { name: 'matchAnchorWidth', type: 'boolean | \"min\"', defaultValue: 'false', description: 'Tie the panel width to the trigger: true makes it equal, \"min\" makes the trigger width a floor the panel can grow past. Use it for a field-like trigger that displays a value (a workspace switcher) — the panel then reads as a continuation of the control, the native <select> convention; \"min\" is the forgiving choice since user-authored labels outgrow a fixed width. Never use it with an icon-only / kebab trigger: you would get a 32px panel, which is why the default is false and placement is bottom-end. Setting it also drops the 160/280 defaults, which would otherwise clamp a wide trigger\\'s panel narrower than the trigger. Restoring bounds is asymmetric: maxWidth is always honoured, but minWidth is ignored under \\'min\\' (Popover makes the measured anchor width the floor) — use true plus an explicit minWidth if you need a floor wider than the trigger.' },\n ],\n },\n};\n"],"mappings":"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","names":[]}
1
+ {"version":3,"sources":["../../../../../src/studio/lib/registry/inputs/menu.ts"],"sourcesContent":["import type { ComponentDef } from '../../types';\n\nexport const menuDef: ComponentDef = {\n id: 'menu',\n name: 'Menu (Action Menu)',\n category: 'Inputs',\n description:\n \"Action / dropdown menu — a list of commands invoked from a consumer-owned trigger (a ⋮ IconButton, a Button, anything). Built on the same headless Popover as Listbox (positioning, portal, outside-click, Escape) but with menu semantics (role=menu / menuitem / separator) and NO selected-value state: pick a row → run its action → dismiss. Reach for Listbox/Select when you need to HOLD a chosen value; reach for Menu for row ⋮ actions, overflow menus, and command lists. Supports leading icons (optionally tinted per row via the item's iconColor), trailing hints (e.g. shortcuts), optional two-line rows (a headline label + a supporting subtitle), separators, disabled rows, destructive (danger) items, and a Current row for context switchers — a workspace / scope / view picker (aria-current + a trailing checkmark + heavier label — it REFLECTS where the user is, it does not hold a value). Panel width follows the trigger when matchAnchorWidth is set (a field-like switcher trigger) and comes from content otherwise (a kebab trigger). The Shape picker swaps the live panel between the atom's two shapes — row actions (every row a command, destructive last, kebab trigger, default bottom-end) and a context switcher (sibling contexts plus one command under a separator, exactly one Current row, field trigger, matchAnchorWidth='min' + bottom-start). Both share every knob and class; only the entries differ. This entry themes the PANEL + rows; the trigger is owned entirely by the consumer's renderTrigger.\",\n styleProperties: [\n // Panel chrome — the floating card.\n { key: 'panelBg', label: 'Background', control: 'color', defaultValue: 'var(--color-card)', section: 'panel' },\n { key: 'panelBorder', label: 'Border', control: 'color', defaultValue: 'var(--color-border)', section: 'panel' },\n { key: 'panelRadius', label: 'Radius', control: 'slider', defaultValue: 8, min: 0, max: 16, step: 1, unit: 'px', section: 'panel' },\n { key: 'panelMaxHeight', label: 'Max Height', control: 'number', defaultValue: 360, min: 120, max: 600, step: 20, unit: 'px', section: 'panel' },\n\n // Drop shadow — decomposed into Color / Blur / Offset Y instead of a\n // raw `box-shadow` text field, so designers tune it with a colour\n // picker + sliders. Same pattern as the Calendar atom; the box-shadow\n // is composed from these three vars in styles.css. Defaults match the\n // floating-panel elevation (0 6px 20px rgba(0,0,0,0.10)).\n { key: 'shadowColor', label: 'Color', control: 'color', defaultValue: 'rgba(0, 0, 0, 0.10)', section: 'shadow' },\n { key: 'shadowBlur', label: 'Blur', control: 'slider', defaultValue: 20, min: 0, max: 48, step: 1, unit: 'px', section: 'shadow' },\n { key: 'shadowOffsetY', label: 'Offset Y', control: 'slider', defaultValue: 6, min: 0, max: 24, step: 1, unit: 'px', section: 'shadow' },\n\n // Item row — sizing knobs apply across all states.\n { key: 'itemPaddingX', label: 'Padding X', control: 'number', defaultValue: 10, min: 4, max: 20, step: 1, unit: 'px', section: 'item' },\n { key: 'itemPaddingY', label: 'Padding Y', control: 'number', defaultValue: 7, min: 2, max: 14, step: 1, unit: 'px', section: 'item' },\n { key: 'itemFontSize', label: 'Font Size', control: 'number', defaultValue: 13, min: 10, max: 18, step: 1, unit: 'px', section: 'item' },\n { key: 'itemRadius', label: 'Radius', control: 'slider', defaultValue: 4, min: 0, max: 12, step: 1, unit: 'px', section: 'item' },\n\n // Per-state colours — scoped by the `state` showcase variant so only\n // the knobs relevant to the displayed row state are visible. Mirrors\n // the listbox / select-dropdown convention. \"Hover\" covers both\n // mouse hover and keyboard arrow-key highlight (same `--active`\n // class). Default row has no surface of its own (panel bg shows\n // through), so only text colour is exposed there.\n { key: 'itemColor', label: 'Text', control: 'color', defaultValue: 'var(--color-text)', section: 'itemState', showWhen: { state: 'default' } },\n\n { key: 'itemActiveBg', label: 'Background', control: 'color', defaultValue: 'var(--color-surface-alt)', section: 'itemState', showWhen: { state: 'hover' } },\n { key: 'itemActiveColor', label: 'Text', control: 'color', defaultValue: 'var(--color-text)', section: 'itemState', showWhen: { state: 'hover' } },\n\n { key: 'itemDisabledOpacity', label: 'Opacity', control: 'slider', defaultValue: 0.4, min: 0.1, max: 1, step: 0.05, section: 'itemState', showWhen: { state: 'disabled' } },\n\n // Destructive rows (Delete etc.) — danger text at rest, danger-tinted\n // surface when highlighted.\n { key: 'itemDangerColor', label: 'Text', control: 'color', defaultValue: 'var(--color-danger-text)', section: 'itemState', showWhen: { state: 'danger' } },\n { key: 'itemDangerActiveBg', label: 'Hover Background', control: 'color', defaultValue: 'var(--color-danger-bg)', section: 'itemState', showWhen: { state: 'danger' } },\n\n // The row the user is currently ON (a switcher's active workspace) —\n // weight + a trailing checkmark, no colour of its own so `itemColor`\n // and the danger tone keep reaching it and the checkmark inherits the\n // row. Background defaults to transparent: a resting tint collided\n // with the hover surface, whose default is the obvious\n // `--color-surface-alt`. The knob stays so a designer can opt in; the\n // CSS rule order keeps hover on top of it either way.\n { key: 'itemCurrentBg', label: 'Background', control: 'color', defaultValue: 'transparent', section: 'itemState', showWhen: { state: 'current' } },\n { key: 'itemCurrentFontWeight', label: 'Font Weight', control: 'select', defaultValue: '600', options: ['400', '500', '600', '700'], section: 'itemState', showWhen: { state: 'current' } },\n\n // Leading icon colour at rest (tracks the row text colour when\n // active / danger — no separate knobs for those states).\n //\n // `--color-text-strong`, not `--color-text-subtle`: subtle measures\n // 1.48:1 on the panel in the light theme (2.85:1 dark), below even the\n // 3:1 non-text floor, and ends up fainter than a disabled row — a live\n // glyph read as switched off. See the note in menu.scss.\n { key: 'itemIconColor', label: 'Color', control: 'color', defaultValue: 'var(--color-text-strong)', section: 'icon', showWhen: { withIcons: 'yes' } },\n\n // Trailing hint (a shortcut echo like ⌘C). Muted is BELOW the AA floor\n // for text at 2.54:1 — a deliberate exception because the hint carries\n // no content the label lacks. The subtitle below refuses the same token\n // for exactly the opposite reason; see menu.scss.\n { key: 'itemHintFontSize', label: 'Font Size', control: 'number', defaultValue: 12, min: 9, max: 16, step: 1, unit: 'px', section: 'hint', showWhen: { withHints: 'yes' } },\n { key: 'itemHintColor', label: 'Color', control: 'color', defaultValue: 'var(--color-text-muted)', section: 'hint', showWhen: { withHints: 'yes' } },\n\n // Two-line rows — a headline (label) plus a supporting subtitle\n // beneath. Only shown when the Subtitles variant is on.\n { key: 'itemSubtitleFontSize', label: 'Font Size', control: 'number', defaultValue: 11, min: 9, max: 16, step: 1, unit: 'px', section: 'subtitle', showWhen: { withSubtitles: 'yes' } },\n // Default is text-STRONG, not text-muted: muted fails WCAG AA on the\n // panel in the light theme (2.54:1) and a subtitle carries real content.\n // See the note in menu.scss.\n { key: 'itemSubtitleColor', label: 'Color', control: 'color', defaultValue: 'var(--color-text-strong)', section: 'subtitle', showWhen: { withSubtitles: 'yes' } },\n { key: 'itemSubtitleGap', label: 'Row Gap', control: 'number', defaultValue: 2, min: 0, max: 8, step: 1, unit: 'px', section: 'subtitle', showWhen: { withSubtitles: 'yes' } },\n\n // Separator divider colour. A separator divides ROWS, so the single-row\n // static showcase has nothing to draw it between — open the live menu to\n // see this one land.\n { key: 'separatorColor', label: 'Color', control: 'color', defaultValue: 'var(--color-border)', section: 'separator', showWhen: { withSeparator: 'yes' } },\n ],\n layoutVariants: [\n {\n // Which state the static showcase rows paint. The interactive\n // instance (a real ⋮ trigger) below is always live — hover /\n // keyboard exercise the real CSS independently. This picker is\n // purely to VISUALLY confirm each per-state knob without having\n // to hover the live menu.\n key: 'state',\n label: 'Row State',\n options: [\n { value: 'default', label: 'Default' },\n { value: 'hover', label: 'Hover' },\n { value: 'disabled', label: 'Disabled' },\n { value: 'danger', label: 'Danger' },\n // `current` is ORTHOGONAL to the others — a row can be current and\n // hovered and disabled at once — so this option is a knob-scoping\n // device, not a claim of exclusivity (the same licence `hover` and\n // `disabled` already take here). The showcase paints the picked state\n // on its single row AT REST and never stacks one state on another:\n // forcing the highlight under `Current` made it contradict its own\n // knobs (`itemCurrentBg` defaults to `transparent`) and read as\n // \"current has a background\". Hover the current row in the LIVE menu\n // to see the two compose.\n { value: 'current', label: 'Current' },\n ],\n defaultValue: 'default',\n },\n {\n // Which of the atom's two shapes the LIVE panel demonstrates. Both are\n // legitimately this atom — they share every knob, every class and the\n // same ARIA; only the entries differ, plus the trigger and placement a\n // consumer would pick. Scopes no knobs on purpose: it changes the\n // example, not the knob set. It exists because collapsing the demo to\n // one shape hid the other, and mixing them into one list made a\n // switcher row stick out among commands — telling two stories at once.\n key: 'shape',\n label: 'Shape',\n options: [\n { value: 'actions', label: 'Row actions' },\n { value: 'switcher', label: 'Switcher' },\n ],\n defaultValue: 'actions',\n },\n {\n key: 'withIcons',\n label: 'Leading Icons',\n options: [\n { value: 'yes', label: 'On' },\n { value: 'no', label: 'Off' },\n ],\n defaultValue: 'yes',\n },\n {\n key: 'withSeparator',\n label: 'Separator',\n options: [\n { value: 'yes', label: 'On' },\n { value: 'no', label: 'Off' },\n ],\n defaultValue: 'yes',\n },\n {\n // Trailing shortcut hints. Off by default: with Subtitles also on, a\n // row concatenates label + subtitle + hint into one accessible name\n // — the anti-pattern the README warns about. Worth being able to SEE\n // (it is also visually tight inside maxWidth 280), not worth\n // shipping as the baseline.\n key: 'withHints',\n label: 'Hints',\n options: [\n { value: 'yes', label: 'On' },\n { value: 'no', label: 'Off' },\n ],\n defaultValue: 'no',\n },\n {\n // Turns each row into a two-line headline + subtitle item. Off by\n // default so the classic single-line menu is the baseline.\n key: 'withSubtitles',\n label: 'Subtitles',\n options: [\n { value: 'yes', label: 'On' },\n { value: 'no', label: 'Off' },\n ],\n defaultValue: 'no',\n },\n ],\n events: [\n { name: 'onSelect', description: \"Fires when an item is invoked (click / Enter / Space). The menu closes afterward. Per-item — wired via each item's `onSelect`.\", payload: 'void' },\n { name: 'onOpenChange', description: 'Fires when the menu opens or closes.', payload: 'boolean' },\n ],\n api: {\n importPath: '@viax.io/uxm/ui',\n importNames: 'Menu',\n props: [\n { name: 'items', type: 'MenuEntry[]', required: true, description: 'Menu entries — actionable items ({ key, label, subtitle?, icon?, iconColor?, hint?, onSelect?, disabled?, danger?, current? }) and separators ({ separator: true }), in display order. Pass `subtitle` to render a two-line row (label = headline), `iconColor` to tint ONE row\\'s glyph (prefer a `var(--color-*)` reference; raw hex only for entity-identity colours), and `current` to mark the row the user is already on (aria-current + trailing checkmark + heavier label).' },\n { name: 'renderTrigger', type: '(api: { open, triggerProps }) => ReactNode', required: true, description: 'Render the trigger. Spread `triggerProps` on your interactive element (an IconButton ⋮, a Button) — wires ref + click + ARIA in one go.' },\n { name: 'placement', type: '\"bottom-start\" | \"bottom-end\" | \"top-start\" | \"top-end\"', defaultValue: '\"bottom-end\"', description: 'Preferred placement; flips on overflow. Defaults to bottom-end since menus usually align to a trailing ⋮.' },\n { name: 'open', type: 'boolean', description: 'Controlled open state. Pair with onOpenChange. Omit for uncontrolled.' },\n { name: 'onOpenChange', type: '(open: boolean) => void', description: 'Called whenever the menu wants to open/close.' },\n { name: 'minWidth', type: 'number', defaultValue: '160', description: 'Minimum panel width in px.' },\n { name: 'maxWidth', type: 'number', defaultValue: '280', description: 'Maximum panel width in px — long labels truncate beyond it. The default applies only while matchAnchorWidth is off.' },\n { name: 'matchAnchorWidth', type: 'boolean | \"min\"', defaultValue: 'false', description: 'Tie the panel width to the trigger: true makes it equal, \"min\" makes the trigger width a floor the panel can grow past. Use it for a field-like trigger that displays a value (a workspace switcher) — the panel then reads as a continuation of the control, the native <select> convention; \"min\" is the forgiving choice since user-authored labels outgrow a fixed width. Never use it with an icon-only / kebab trigger: you would get a 32px panel, which is why the default is false and placement is bottom-end. Setting it also drops the 160/280 defaults, which would otherwise clamp a wide trigger\\'s panel narrower than the trigger. Restoring bounds is asymmetric: maxWidth is always honoured, but minWidth is ignored under \\'min\\' (Popover makes the measured anchor width the floor) — use true plus an explicit minWidth if you need a floor wider than the trigger.' },\n ],\n },\n};\n"],"mappings":"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","names":[]}
@@ -82,7 +82,7 @@ const numberInputDef = {
82
82
  { name: "onFocus", description: "Fires when the field receives focus.", payload: "FocusEvent" }
83
83
  ],
84
84
  api: {
85
- importPath: "@viax/uxm/ui",
85
+ importPath: "@viax.io/uxm/ui",
86
86
  importNames: "NumberInput",
87
87
  props: [
88
88
  { name: "value", type: "string", description: "Current value as a digit string (controlled)." },