@nxgt/material 3.101.0 → 3.104.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 (207) hide show
  1. package/CHANGELOG.md +82 -0
  2. package/README.md +37 -5
  3. package/dist/{alert-dialog-DYzxchiS.js → alert-dialog-CK_47jfm.js} +1 -1
  4. package/dist/{async-slice-drJyPvuM.js → async-slice-1ZNMiwyJ.js} +1 -1
  5. package/dist/{bubble-input-CQwVSoU3.js → bubble-input-BxI1WmNs.js} +17 -5
  6. package/dist/{button-GeIsUekU.js → button-YfEMZbRO.js} +2 -2
  7. package/dist/{calculator-BS4PAm6l.js → calculator-BmYZId4c.js} +261 -460
  8. package/dist/calculator-field.js +7 -7
  9. package/dist/{calculator-segment-CEdwE24M.js → calculator-segment-DJ08DJ-n.js} +1 -1
  10. package/dist/calculator.js +1 -1
  11. package/dist/charts.js +819 -764
  12. package/dist/{chip-BdEtFQ85.js → chip-DPj6e-3v.js} +2 -2
  13. package/dist/{code-editor-BByXZOGy.js → code-editor-CZg3nLZO.js} +178 -177
  14. package/dist/code-editor.js +5 -5
  15. package/dist/{code-language-items-CSZX5zxD.js → code-language-items-Nq1iOGId.js} +14 -5
  16. package/dist/components/ui/actions/action-card/action-card-tile.css +47 -0
  17. package/dist/components/ui/display/chip/chip-soft.css +27 -2
  18. package/dist/components/ui/display/code/code-moonlight.css +10 -10
  19. package/dist/components/ui/primitives/collapsible/collapsible.css +9 -0
  20. package/dist/{components-DQ4MljCr.js → components-B2wrH_W0.js} +19302 -18583
  21. package/dist/components.js +38 -37
  22. package/dist/{conversion-variant-DTQqAyDt.js → conversion-variant-C-LPx5ek.js} +5 -5
  23. package/dist/{currency-field-Dnju7ss2.js → currency-field-DnsRIA80.js} +24 -23
  24. package/dist/{dialog-5_2__tu8.js → dialog-BKBsDGFc.js} +3 -3
  25. package/dist/dnd.js +1 -1
  26. package/dist/{dropdown-menu-FdGC5kIP.js → dropdown-menu-QMDbRidH.js} +1 -1
  27. package/dist/editor.js +9 -9
  28. package/dist/{empty-state-BoepPG5v.js → empty-state-BLIJ6znY.js} +1 -1
  29. package/dist/{field-blur-DkiZOVNV.js → field-blur-DMJwPLsg.js} +9 -9
  30. package/dist/field-blur-context-3rKussBQ.js +29 -0
  31. package/dist/{financial-variant-BhqJp5C-.js → financial-variant-Ws0Jp01H.js} +5 -5
  32. package/dist/{hooks-DjcbJZiO.js → hooks-C3vkQmzh.js} +106 -61
  33. package/dist/hooks.js +3 -3
  34. package/dist/{hover-card-CmHJeBeY.js → hover-card-Df649U6I.js} +1 -1
  35. package/dist/i18n.js +3 -3
  36. package/dist/{icon-badge-LGUPQh_c.js → icon-badge-Cma1qOOJ.js} +1 -1
  37. package/dist/{icon-button-BSVpO1jP.js → icon-button-CpKxV264.js} +1 -1
  38. package/dist/key-layout-D2goCDkD.js +31 -0
  39. package/dist/keypad.js +551 -0
  40. package/dist/label-DR-zZyGQ.js +47 -0
  41. package/dist/lib/components/ui/actions/index.d.ts +1 -0
  42. package/dist/lib/components/ui/actions/product-tile/index.d.ts +1 -0
  43. package/dist/lib/components/ui/actions/product-tile/product-tile-link.d.ts +16 -0
  44. package/dist/lib/components/ui/actions/product-tile/product-tile.d.ts +41 -0
  45. package/dist/lib/components/ui/collections/data-table/data-table-density.d.ts +1 -1
  46. package/dist/lib/components/ui/collections/data-table/partials/data-table-scroll-region.d.ts +4 -1
  47. package/dist/lib/components/ui/collections/data-table/partials/layouts/data-table-list-bar.d.ts +6 -3
  48. package/dist/lib/components/ui/collections/data-table/partials/layouts/list-bar-in-row.d.ts +2 -1
  49. package/dist/lib/components/ui/collections/data-table/types.d.ts +11 -8
  50. package/dist/lib/components/ui/collections/data-table/virtual-option.d.ts +9 -3
  51. package/dist/lib/components/ui/collections/filter/use-filter-field-config.d.ts +2 -0
  52. package/dist/lib/components/ui/collections/server-table/partials/server-table-passed-through.d.ts +1 -0
  53. package/dist/lib/components/ui/collections/server-table/types.d.ts +1 -1
  54. package/dist/lib/components/ui/display/chip/chip.variants.d.ts +5 -4
  55. package/dist/lib/components/ui/display/code/code-block-parts.d.ts +1 -1
  56. package/dist/lib/components/ui/display/code/code-block.d.ts +4 -1
  57. package/dist/lib/components/ui/display/code/languages.d.ts +2 -0
  58. package/dist/lib/components/ui/display/code/moonlight-tokens.d.ts +10 -10
  59. package/dist/lib/components/ui/feedback/confirm-dialog/confirm-dialog-props.d.ts +73 -0
  60. package/dist/lib/components/ui/feedback/confirm-dialog/confirm-dialog-rules.d.ts +12 -0
  61. package/dist/lib/components/ui/feedback/confirm-dialog/confirm-dialog.d.ts +5 -61
  62. package/dist/lib/components/ui/feedback/confirm-dialog/confirm-footer.d.ts +12 -0
  63. package/dist/lib/components/ui/feedback/confirm-dialog/confirm-phrase.d.ts +26 -0
  64. package/dist/lib/components/ui/feedback/confirm-dialog/use-confirm-action.d.ts +1 -1
  65. package/dist/lib/components/ui/fields/contacts/placeholders.d.ts +1 -1
  66. package/dist/lib/components/ui/fields/index.d.ts +1 -0
  67. package/dist/lib/components/ui/fields/quantity-field/types.d.ts +1 -1
  68. package/dist/lib/components/ui/fields/quantity-stepper/index.d.ts +2 -0
  69. package/dist/lib/components/ui/fields/quantity-stepper/quantity-stepper-model.d.ts +9 -0
  70. package/dist/lib/components/ui/fields/quantity-stepper/quantity-stepper-value.d.ts +15 -0
  71. package/dist/lib/components/ui/fields/quantity-stepper/quantity-stepper.d.ts +9 -0
  72. package/dist/lib/components/ui/fields/quantity-stepper/quantity-stepper.types.d.ts +35 -0
  73. package/dist/lib/components/ui/fields/quantity-stepper/use-quantity-stepper.d.ts +28 -0
  74. package/dist/lib/components/ui/layout/index.d.ts +1 -0
  75. package/dist/lib/components/ui/layout/pane-layout/pane-layout.d.ts +8 -3
  76. package/dist/lib/components/ui/layout/pane-layout/partials/pane-layout-classes.d.ts +2 -2
  77. package/dist/lib/components/ui/layout/pane-layout/partials/pane-layout-context.d.ts +9 -0
  78. package/dist/lib/components/ui/layout/pane-layout/partials/use-pane-layout-state.d.ts +7 -2
  79. package/dist/lib/components/ui/layout/panel-card/index.d.ts +1 -0
  80. package/dist/lib/components/ui/layout/panel-card/panel-card.d.ts +23 -0
  81. package/dist/lib/components/ui/primitives/collapsible/collapsible.d.ts +9 -1
  82. package/dist/lib/components/ui/primitives/tabs/partials/tabs-list.d.ts +6 -1
  83. package/dist/lib/components/ui/primitives/tabs/tabs-classes.d.ts +1 -0
  84. package/dist/lib/components/ui/selection/chip-group-field/chip-group-field.d.ts +8 -0
  85. package/dist/lib/components/ui/selection/chip-group-field/chip-group-field.types.d.ts +6 -0
  86. package/dist/lib/components/ui/selection/chip-group-field/partials/chip-group-reasons.d.ts +10 -0
  87. package/dist/lib/components/ui/selection/chip-group-field/partials/use-chip-rail.d.ts +12 -0
  88. package/dist/lib/components/ui/selection/choice-group/choice-group-root.d.ts +5 -2
  89. package/dist/lib/components/ui/selection/index.d.ts +1 -0
  90. package/dist/lib/components/ui/selection/status-menu/index.d.ts +3 -0
  91. package/dist/lib/components/ui/selection/status-menu/partials/status-confirm.d.ts +12 -0
  92. package/dist/lib/components/ui/selection/status-menu/partials/status-icon.d.ts +6 -0
  93. package/dist/lib/components/ui/selection/status-menu/partials/status-items.d.ts +18 -0
  94. package/dist/lib/components/ui/selection/status-menu/partials/status-menu-list.d.ts +14 -0
  95. package/dist/lib/components/ui/selection/status-menu/partials/status-sheet-row.d.ts +11 -0
  96. package/dist/lib/components/ui/selection/status-menu/partials/status-sheet.d.ts +21 -0
  97. package/dist/lib/components/ui/selection/status-menu/partials/status-trigger.d.ts +18 -0
  98. package/dist/lib/components/ui/selection/status-menu/status-menu-data.d.ts +12 -0
  99. package/dist/lib/components/ui/selection/status-menu/status-menu-form-field.d.ts +20 -0
  100. package/dist/lib/components/ui/selection/status-menu/status-menu.d.ts +13 -0
  101. package/dist/lib/components/ui/selection/status-menu/types.d.ts +76 -0
  102. package/dist/lib/components/ui/selection/status-menu/use-status-change.d.ts +18 -0
  103. package/dist/lib/components/ui/selection/status-menu/use-status-menu.d.ts +30 -0
  104. package/dist/lib/components/ui/widgets/calculator/partials/calculator-keypad.d.ts +1 -5
  105. package/dist/lib/components/ui/widgets/calculator/variants/key-layout.d.ts +3 -49
  106. package/dist/lib/components/ui/widgets/keypad/cash-model.d.ts +16 -0
  107. package/dist/lib/components/ui/widgets/keypad/index.d.ts +5 -0
  108. package/dist/lib/components/ui/widgets/keypad/key-layout.d.ts +56 -0
  109. package/dist/lib/components/ui/widgets/keypad/keypad-binding.d.ts +32 -0
  110. package/dist/lib/components/ui/widgets/keypad/keypad-cash.d.ts +28 -0
  111. package/dist/lib/components/ui/widgets/keypad/keypad-display.d.ts +11 -0
  112. package/dist/lib/components/ui/widgets/keypad/keypad-entry.d.ts +39 -0
  113. package/dist/lib/components/ui/widgets/keypad/keypad-grid.d.ts +27 -0
  114. package/dist/lib/components/ui/widgets/{calculator/partials/calculator-key.d.ts → keypad/keypad-key.d.ts} +6 -3
  115. package/dist/lib/components/ui/widgets/keypad/keypad-layout.d.ts +19 -0
  116. package/dist/lib/components/ui/widgets/{calculator/partials → keypad}/keypad-navigation.d.ts +1 -1
  117. package/dist/lib/components/ui/widgets/keypad/keypad.d.ts +9 -0
  118. package/dist/lib/components/ui/widgets/keypad/keypad.types.d.ts +91 -0
  119. package/dist/lib/components/ui/widgets/keypad/use-keypad-cash.d.ts +14 -0
  120. package/dist/lib/components/ui/widgets/keypad/use-keypad-keyboard.d.ts +7 -0
  121. package/dist/lib/components/ui/widgets/keypad/use-keypad-number.d.ts +10 -0
  122. package/dist/lib/components/ui/widgets/keypad/use-keypad-quantity.d.ts +16 -0
  123. package/dist/lib/components/ui/widgets/keypad/use-keypad-value.d.ts +17 -0
  124. package/dist/lib/components/ui/widgets/keypad/use-keypad.d.ts +23 -0
  125. package/dist/lib/components/ui/widgets/native-charts/core/label-placement.d.ts +25 -0
  126. package/dist/lib/components/ui/widgets/native-charts/core/reference-geometry.d.ts +3 -2
  127. package/dist/lib/hooks/index.d.ts +1 -0
  128. package/dist/lib/hooks/use-barcode-scanner.d.ts +39 -0
  129. package/dist/lib/i18n/resources/en/en.d.ts +28 -0
  130. package/dist/lib/i18n/resources/en/material.json.d.ts +30 -2
  131. package/dist/lib/i18n/resources/fr/fr.d.ts +28 -0
  132. package/dist/lib/i18n/resources/fr/material.json.d.ts +30 -2
  133. package/dist/lib/i18n/resources/resources.d.ts +56 -0
  134. package/dist/lib/i18n/translator.d.ts +1 -1
  135. package/dist/lib/keypad/index.d.ts +20 -0
  136. package/dist/lib/print/output/csv.d.ts +37 -0
  137. package/dist/lib/print/output/index.d.ts +1 -0
  138. package/dist/lib.js +1 -1
  139. package/dist/main.js +54 -53
  140. package/dist/map.js +9 -9
  141. package/dist/material.css +1 -1
  142. package/dist/pdf-reader.js +1 -1
  143. package/dist/{percent-field-DGlU_xii.js → percent-field-sAq7BaxN.js} +15 -14
  144. package/dist/{picker-surface-CGhqNR8a.js → picker-surface--6E-nvpU.js} +4 -4
  145. package/dist/{popover-ZxL7ktKk.js → popover-bEB8I_-w.js} +1 -1
  146. package/dist/{pos-types-BQ0QpYMp.js → pos-types-Cpdc4E33.js} +1 -1
  147. package/dist/{pos-variant-CKy8h_5i.js → pos-variant-ClMGu59I.js} +25 -25
  148. package/dist/print.js +146 -127
  149. package/dist/{programmer-variant-CbHstE28.js → programmer-variant-ChzgyA7x.js} +30 -30
  150. package/dist/{public-D-tdOz4b.js → public-BY8N5NDT.js} +9 -9
  151. package/dist/{rich-code-block-CTPj1LuD.js → rich-code-block-D2GiWuqD.js} +18 -18
  152. package/dist/{scientific-variant-B8U9h3II.js → scientific-variant-31_93gcZ.js} +8 -8
  153. package/dist/{sortable-provider-CSoWE7Ce.js → sortable-provider-DGiVn72t.js} +2 -2
  154. package/dist/{spinner-ffuwBXHl.js → spinner-CEVomQ5K.js} +1 -1
  155. package/dist/standard-layout-DTr9yy8Z.js +48 -0
  156. package/dist/{tabs-JgRq6ZJx.js → tabs-B8MXBbPW.js} +14 -14
  157. package/dist/{text-field-DURkIP-v.js → text-field-DN88qD0Q.js} +16 -15
  158. package/dist/theme-picker.js +13 -13
  159. package/dist/{theme-toggle-n_Zg7JAA.js → theme-toggle-C7pnu1Xh.js} +1 -1
  160. package/dist/{toolbar-items-IANZdcw4.js → toolbar-items-BDfoh8QB.js} +4 -4
  161. package/dist/{translate-material-CMHUH5Ha.js → translate-material-s_lxIV43.js} +1 -1
  162. package/dist/{translator-9zA-Um3W.js → translator-Cgql9srO.js} +56 -4
  163. package/dist/use-calculator-keyboard-DysnFK8m.js +222 -0
  164. package/dist/{use-chat-composer-BoIN7RCA.js → use-chat-composer-xCcp9fVc.js} +2250 -2195
  165. package/dist/{use-heading-spy-Ciw9GBHL.js → use-heading-spy-FIZlf9qj.js} +235 -154
  166. package/dist/{use-material-translation-CLNaMhUf.js → use-material-translation-xNzbSVgS.js} +1 -1
  167. package/dist/{use-return-focus-DWhbTGVe.js → use-return-focus-CW9KkDkp.js} +1 -1
  168. package/docs/README.md +2 -1
  169. package/docs/components/README.md +2 -0
  170. package/docs/components/buttons-and-actions.md +81 -2
  171. package/docs/components/data-display.md +6 -3
  172. package/docs/components/data-table-filter-and-lists.md +19 -6
  173. package/docs/components/feedback-and-status.md +20 -0
  174. package/docs/components/form-fields.md +60 -7
  175. package/docs/components/navigation-and-layout.md +48 -2
  176. package/docs/components/primitives.md +44 -2
  177. package/docs/components/rich-widgets.md +28 -0
  178. package/docs/components/selection-and-choice.md +176 -1
  179. package/docs/guides/calculator.md +1 -1
  180. package/docs/guides/cards-and-tiles.md +31 -24
  181. package/docs/guides/csp.md +4 -3
  182. package/docs/guides/data-grid.md +5 -4
  183. package/docs/guides/field-look-refined.md +2 -2
  184. package/docs/guides/forms.md +1 -0
  185. package/docs/guides/helpers.md +49 -0
  186. package/docs/guides/keypad.md +233 -0
  187. package/docs/guides/printing.md +51 -1
  188. package/docs/previews/buttons-actions-producttile.webp +0 -0
  189. package/docs/previews/data-display-codeblock.webp +0 -0
  190. package/docs/previews/data-display-codegroup.webp +0 -0
  191. package/docs/previews/data-display-jsonviewer.webp +0 -0
  192. package/docs/previews/form-fields-quantitystepper.webp +0 -0
  193. package/docs/previews/navigation-layout-panelcard.webp +0 -0
  194. package/docs/previews/rich-widgets-keypad.webp +0 -0
  195. package/docs/previews/selection-choice-statusmenu.webp +0 -0
  196. package/docs/roadmap.md +21 -0
  197. package/docs/troubleshooting.md +68 -4
  198. package/lib/components/ui/actions/action-card/action-card-tile.css +47 -0
  199. package/lib/components/ui/display/chip/chip-soft.css +27 -2
  200. package/lib/components/ui/display/code/code-moonlight.css +10 -10
  201. package/lib/components/ui/primitives/collapsible/collapsible.css +9 -0
  202. package/lib/components/ui/widgets/calculator/calculator-keys.css +3 -0
  203. package/lib/components/ui/widgets/calculator/calculator.css +118 -0
  204. package/package.json +7 -2
  205. package/dist/field-blur-context-BLGgf_3z.js +0 -73
  206. package/dist/key-layout-cR79xfGE.js +0 -38
  207. package/dist/standard-layout-BuSRr3TY.js +0 -40
@@ -19,6 +19,7 @@ export * from './percent-field/index.js';
19
19
  export * from './phone-field/index.js';
20
20
  export * from './postal-address/index.js';
21
21
  export * from './quantity-field/index.js';
22
+ export * from './quantity-stepper/index.js';
22
23
  export * from './rating-field/index.js';
23
24
  export * from './repeatable-group/index.js';
24
25
  export * from './search-field/index.js';
@@ -31,7 +31,7 @@ export type QuantityFieldProps = {
31
31
  max?: number;
32
32
  step?: number;
33
33
  hideSteppers?: boolean;
34
- /** The units offered. */
34
+ /** The units offered. Without `units` and `allowCustomUnit` the unit chip is not drawn: a plain count. */
35
35
  units?: QuantityUnit[];
36
36
  /** The unit is typed; `units` become suggestions. Without it the unit is picked from `units`. */
37
37
  allowCustomUnit?: boolean;
@@ -0,0 +1,2 @@
1
+ export { QuantityStepper } from './quantity-stepper.js';
2
+ export type { QuantityStepperProps, QuantityStepperSize, } from './quantity-stepper.types.js';
@@ -0,0 +1,9 @@
1
+ export type StepperLimits = {
2
+ min: number;
3
+ max?: number;
4
+ step: number;
5
+ };
6
+ /** The value a key asks for, or `null` when the key is not the stepper's. */
7
+ export declare function valueForKey(key: string, value: number, { min, max, step }: StepperLimits): number | null;
8
+ /** What was typed, clamped; `null` (keep the old value) when it is not a number. */
9
+ export declare function valueForText(text: string, { min, max }: StepperLimits): number | null;
@@ -0,0 +1,15 @@
1
+ import { StepperLimits } from './quantity-stepper-model.js';
2
+ type Props = {
3
+ value: number;
4
+ limits: StepperLimits;
5
+ name: string;
6
+ editable?: boolean;
7
+ disabled?: boolean;
8
+ onValue: (value: number) => void;
9
+ };
10
+ /**
11
+ * The value: a spinbutton (arrow keys, Page and Home/End). A `<span>` to read,
12
+ * or a text input with `editable`, whose text is committed on Enter or blur.
13
+ */
14
+ export declare function QuantityStepperValue({ value, limits, name, editable, disabled, onValue, }: Props): import("react").JSX.Element;
15
+ export {};
@@ -0,0 +1,9 @@
1
+ import { QuantityStepperProps } from './quantity-stepper.types.js';
2
+ /**
3
+ * An inline −/value/+ control for a cart or ticket line: no label, no field
4
+ * box. A named `group` holding a minus button, the value (a `spinbutton`, with
5
+ * the arrow keys; typed with `editable`) and a plus button, each button 44px
6
+ * under a coarse pointer. With `onRemove`, the minus button becomes a remove
7
+ * (trash) button at `min`. Fits a `ListTile`'s `content` or `trailing`.
8
+ */
9
+ export declare function QuantityStepper({ 'aria-label': ariaLabel, value: controlled, defaultValue, onValueChange, min, max, step, size, editable, onRemove, disabled, className, ...props }: QuantityStepperProps): import("react").JSX.Element;
@@ -0,0 +1,35 @@
1
+ import { ComponentProps } from 'react';
2
+ export type QuantityStepperSize = 'sm' | 'md';
3
+ export type QuantityStepperProps = Omit<ComponentProps<'div'>, 'children' | 'defaultValue' | 'onChange' | 'role' | 'aria-label'> & {
4
+ /**
5
+ * What the control counts, as a sentence: "Quantity of Orange juice". It
6
+ * names the group and the value, and the buttons are named after it
7
+ * ("Decrease Quantity of Orange juice"). Required: a stepper in a list
8
+ * row has no visible label.
9
+ */
10
+ 'aria-label': string;
11
+ /** The controlled value. */
12
+ value?: number;
13
+ /** The first value when uncontrolled; `min` (or 0) when unset. */
14
+ defaultValue?: number;
15
+ /** Called with the new value, always within `min` and `max`. */
16
+ onValueChange?: (value: number) => void;
17
+ /** The lowest value. Default 0. */
18
+ min?: number;
19
+ /** The highest value. Default none. */
20
+ max?: number;
21
+ /** What a button press adds or removes. Default 1. */
22
+ step?: number;
23
+ /** `sm` 32px buttons, `md` 36px buttons (default). Both are 44px under a coarse pointer. */
24
+ size?: QuantityStepperSize;
25
+ /** The value can be typed: it is a text input (committed on Enter or blur, Escape cancels). Default false. */
26
+ editable?: boolean;
27
+ /**
28
+ * Turns the minus button into a remove (trash) button while the value is
29
+ * at `min`: it calls `onRemove` instead of stepping. Without it the minus
30
+ * button is disabled at `min`.
31
+ */
32
+ onRemove?: () => void;
33
+ /** Disables every control. */
34
+ disabled?: boolean;
35
+ };
@@ -0,0 +1,28 @@
1
+ type Options = {
2
+ label: string;
3
+ value?: number;
4
+ defaultValue?: number;
5
+ onValueChange?: (value: number) => void;
6
+ min: number;
7
+ max?: number;
8
+ step: number;
9
+ onRemove?: () => void;
10
+ };
11
+ /** The stepper's value (controlled or not), its limits, its button names and what each button does. */
12
+ export declare function useQuantityStepper({ label, value: controlled, defaultValue, onValueChange, min, max, step, onRemove, }: Options): {
13
+ value: number;
14
+ set: (next: number) => void;
15
+ limits: {
16
+ min: number;
17
+ max: number | undefined;
18
+ step: number;
19
+ };
20
+ atMin: boolean;
21
+ atMax: boolean;
22
+ removing: boolean;
23
+ decreaseLabel: string;
24
+ increaseLabel: string;
25
+ decrease: () => void;
26
+ increase: () => void;
27
+ };
28
+ export {};
@@ -17,6 +17,7 @@ export * from './navigation-rail/index.js';
17
17
  export * from './navigation-toolbar/index.js';
18
18
  export * from './pager/index.js';
19
19
  export * from './pane-layout/index.js';
20
+ export * from './panel-card/index.js';
20
21
  export * from './record-page/index.js';
21
22
  export * from './resizable/index.js';
22
23
  export * from './responsive-grid/index.js';
@@ -1,17 +1,22 @@
1
1
  import { ComponentProps } from 'react';
2
2
  import { PaneLayoutContent } from './partials/pane-layout-content.js';
3
- import { PaneLayoutBreakpoint, PaneLayoutPaneWidth, PaneLayoutPhone, PaneSide } from './partials/pane-layout-context.js';
3
+ import { PaneLayoutBreakpoint, PaneLayoutDefaultOpen, PaneLayoutPaneWidth, PaneLayoutPhone, PaneSide } from './partials/pane-layout-context.js';
4
4
  import { PaneLayoutPane } from './partials/pane-layout-pane.js';
5
5
  import { PaneLayoutTrigger } from './partials/pane-layout-trigger.js';
6
6
  export { PaneLayoutContent, type PaneLayoutContentProps, } from './partials/pane-layout-content.js';
7
- export type { PaneLayoutBreakpoint, PaneLayoutPaneWidth, PaneLayoutPhone, } from './partials/pane-layout-context.js';
7
+ export type { PaneLayoutBreakpoint, PaneLayoutDefaultOpen, PaneLayoutPaneWidth, PaneLayoutPhone, } from './partials/pane-layout-context.js';
8
8
  export { usePaneLayout } from './partials/pane-layout-context.js';
9
9
  export { PaneLayoutPane, type PaneLayoutPaneProps, } from './partials/pane-layout-pane.js';
10
10
  export { PaneLayoutTrigger, type PaneLayoutTriggerProps, } from './partials/pane-layout-trigger.js';
11
11
  export interface PaneLayoutProps extends ComponentProps<'div'> {
12
12
  open?: boolean;
13
13
  onOpenChange?: (open: boolean) => void;
14
- defaultOpen?: boolean;
14
+ /**
15
+ * Whether the pane starts open: a boolean for every viewport, `'desktop'`
16
+ * (open wide, shut on a phone) or `{ desktop, phone }`. The phone value
17
+ * applies from the first client render, with no sheet flash.
18
+ */
19
+ defaultOpen?: PaneLayoutDefaultOpen;
15
20
  paneSide?: PaneSide;
16
21
  /**
17
22
  * How the pane shows below 768px: `sheet` (side sheet), `bottom` (bottom
@@ -1,7 +1,7 @@
1
1
  import { PaneLayoutBreakpoint, PaneLayoutPaneWidth, PaneLayoutPhone, PaneSide } from './pane-layout-context.js';
2
2
  /** The flex direction of the row that holds the pane and the content. */
3
- export declare function paneRowClass(phone: PaneLayoutPhone | undefined, breakpoint: PaneLayoutBreakpoint, paneSide: PaneSide): string;
3
+ export declare function paneRowClass(phone: PaneLayoutPhone | undefined, breakpoint: PaneLayoutBreakpoint): string;
4
4
  /** The inline pane's size, and when it gives way to a sheet or a stack. */
5
- export declare function inlinePaneClass(phone: PaneLayoutPhone | undefined, breakpoint: PaneLayoutBreakpoint, paneWidth: PaneLayoutPaneWidth): string;
5
+ export declare function inlinePaneClass(phone: PaneLayoutPhone | undefined, breakpoint: PaneLayoutBreakpoint, paneWidth: PaneLayoutPaneWidth, paneSide: PaneSide): string;
6
6
  /** The edge the pane shares with the content. */
7
7
  export declare function paneBorderClass(phone: PaneLayoutPhone | undefined, breakpoint: PaneLayoutBreakpoint, paneSide: PaneSide): "border-t md:border-t-0 md:border-r" | "border-t md:border-t-0 md:border-l" | "border-t @3xl:border-t-0 @3xl:border-r" | "border-t @3xl:border-t-0 @3xl:border-l" | "border-l" | "border-r";
@@ -10,6 +10,15 @@ export type PaneLayoutPhone = 'sheet' | 'bottom' | 'stack';
10
10
  export type PaneLayoutBreakpoint = 'viewport' | 'container';
11
11
  /** Width of the inline pane: `sm` 16rem, `md` 20rem (default), `lg` 24rem. */
12
12
  export type PaneLayoutPaneWidth = 'sm' | 'md' | 'lg';
13
+ /**
14
+ * Whether the pane starts open. A boolean applies to every viewport; `'desktop'`
15
+ * is open on a wide screen and shut on a phone; an object sets each side
16
+ * (a missing key is shut).
17
+ */
18
+ export type PaneLayoutDefaultOpen = boolean | 'desktop' | {
19
+ desktop?: boolean;
20
+ phone?: boolean;
21
+ };
13
22
  export interface PaneLayoutContextProps {
14
23
  open: boolean;
15
24
  setOpen: (open: boolean | ((prevOpen: boolean) => boolean)) => void;
@@ -1,10 +1,15 @@
1
1
  import { RefObject } from 'react';
2
- import { PaneLayoutBreakpoint, PaneLayoutContextProps, PaneLayoutPaneWidth, PaneLayoutPhone, PaneSide } from './pane-layout-context.js';
2
+ import { PaneLayoutBreakpoint, PaneLayoutContextProps, PaneLayoutDefaultOpen, PaneLayoutPaneWidth, PaneLayoutPhone, PaneSide } from './pane-layout-context.js';
3
3
  export declare const PHONE_MAX = 768;
4
+ /** The default open state for a wide screen and for a phone. */
5
+ export declare function resolveDefaultOpen(d: PaneLayoutDefaultOpen): {
6
+ desktop: boolean;
7
+ phone: boolean;
8
+ };
4
9
  interface Options {
5
10
  open?: boolean;
6
11
  onOpenChange?: (open: boolean) => void;
7
- defaultOpen: boolean;
12
+ defaultOpen: PaneLayoutDefaultOpen;
8
13
  paneSide: PaneSide;
9
14
  phone?: PaneLayoutPhone;
10
15
  breakpoint: PaneLayoutBreakpoint;
@@ -0,0 +1 @@
1
+ export * from './panel-card.js';
@@ -0,0 +1,23 @@
1
+ import { ComponentProps, ReactNode } from 'react';
2
+ export type PanelCardHeadingLevel = 2 | 3 | 4 | 5 | 6;
3
+ export type PanelCardProps = Omit<ComponentProps<'div'>, 'title'> & {
4
+ /** The panel's name: its heading, and the accessible name of the card. */
5
+ title: ReactNode;
6
+ /** One line under the title. */
7
+ description?: ReactNode;
8
+ /**
9
+ * The heading level of the title, `2` by default: a panel sits under the
10
+ * page's `h1`. Use `3` inside a section that already has an `h2`.
11
+ */
12
+ headingLevel?: PanelCardHeadingLevel;
13
+ /** A header slot at the end of the title row (a button, a `RowMenu`). */
14
+ actions?: ReactNode;
15
+ };
16
+ /**
17
+ * A titled card for the side of a page (an `ActivityContent` aside) or its
18
+ * sections: a heading, an optional description and header actions over the
19
+ * content. The card is a named region, labelled by its heading. The title is
20
+ * set in the card-title step (`title-sm` emphasized), one step below an
21
+ * `ActivityContent` page title, whatever its heading level.
22
+ */
23
+ export declare function PanelCard({ title, description, headingLevel, actions, className, children, ...props }: PanelCardProps): import("react").JSX.Element;
@@ -9,8 +9,16 @@ type CollapsibleTriggerProps = ComponentProps<typeof CollapsiblePrimitive.Collap
9
9
  * look and brings its own icon.
10
10
  */
11
11
  variant?: 'tonal' | 'text';
12
+ /**
13
+ * With `variant="text"`, drops the inline padding so the label starts at
14
+ * the section's left edge, and takes the font of its parent, so the
15
+ * trigger can sit inside a heading (`Typography as="h3"`) and line up
16
+ * with the headings around it. The chevron, its rotation, the hover and
17
+ * the focus ring stay. Ignored on the other variants.
18
+ */
19
+ flush?: boolean;
12
20
  };
13
- declare function CollapsibleTrigger({ className, children, variant, asChild, ...props }: CollapsibleTriggerProps): import("react").JSX.Element;
21
+ declare function CollapsibleTrigger({ className, children, variant, flush, asChild, ...props }: CollapsibleTriggerProps): import("react").JSX.Element;
14
22
  /**
15
23
  * Springs open to its height and folds away (collapsible.css); reduced
16
24
  * motion shows and hides it at once.
@@ -8,7 +8,12 @@ import { TabsScrollButtonsMode } from '../tabs-overflow-classes.js';
8
8
  * `scrollButtons="none"` the buttons are left out and the list stays a plain
9
9
  * touch-scrollable row with a soft fade on each side that hides tabs.
10
10
  */
11
- export declare function TabsList({ scrollButtons, className, children, ref, ...props }: ComponentProps<typeof TabsPrimitive.List> & {
11
+ export declare function TabsList({ scrollButtons, fullWidth, className, children, ref, ...props }: ComponentProps<typeof TabsPrimitive.List> & {
12
12
  /** `auto` (default): scroll buttons while tabs are hidden; `none`: no buttons. */
13
13
  scrollButtons?: TabsScrollButtonsMode;
14
+ /**
15
+ * `segmented` only: the list fills its container and its tabs share the
16
+ * width in equal parts. Ignored by `underline`, which already stretches.
17
+ */
18
+ fullWidth?: boolean;
14
19
  }): import("react").JSX.Element;
@@ -18,6 +18,7 @@ export type TabsLook = 'underline' | 'segmented';
18
18
  export declare function tabsLook(variant: TabsVariant | undefined): TabsLook;
19
19
  export declare const TABS_ROOT: Record<TabsLook, string>;
20
20
  export declare const TABS_LIST: Record<TabsLook, string>;
21
+ export declare const TABS_LIST_FULL = "w-full [&>[role=tab]]:flex-1 [&>[role=tab]]:basis-0";
21
22
  export declare const TABS_TRIGGER: Record<TabsLook, string>;
22
23
  export declare const TABS_INDICATOR: Record<TabsLook, string>;
23
24
  /** The label beside a trigger's icon. */
@@ -16,6 +16,14 @@ type ChipGroupFieldBase = ChoiceGroupBase & ChoiceSelection & {
16
16
  * the accessible description.
17
17
  */
18
18
  showDisabledReason?: boolean;
19
+ /**
20
+ * `'wrap'` (default) lets the chips flow onto several lines. `'scroll'`
21
+ * keeps them on one line that scrolls sideways (touch, trackpad, the
22
+ * wheel; a focused chip scrolls into view), with a fade at each
23
+ * edge that hides more chips. The page never scrolls sideways. Ignored
24
+ * with `columns` or `groups`, which lay the chips out in a grid.
25
+ */
26
+ overflow?: 'wrap' | 'scroll';
19
27
  };
20
28
  export type ChipGroupFieldProps = ChipGroupFieldBase & {
21
29
  /** The chips, in one flow. Give `options` or `groups`. */
@@ -1,3 +1,4 @@
1
+ import { Tone } from '../../tones.js';
1
2
  import { ChoiceOption } from '../choice-group/choice-group.types.js';
2
3
  export type ChipGroupOption = ChoiceOption & {
3
4
  label: string;
@@ -5,6 +6,11 @@ export type ChipGroupOption = ChoiceOption & {
5
6
  description?: string;
6
7
  /** Shown after the label and added to its accessible name. */
7
8
  count?: number;
9
+ /**
10
+ * The chip's tone, as `Badge`'s: unselected a soft tint with the tone's text,
11
+ * selected the filled tone (the check still marks the choice). Neutral without one.
12
+ */
13
+ tone?: Tone;
8
14
  };
9
15
  /** A titled run of options, such as "Morning" or "Afternoon". */
10
16
  export type ChipGroupSection = {
@@ -0,0 +1,10 @@
1
+ type Reason = {
2
+ id: string;
3
+ text: string;
4
+ label: string;
5
+ };
6
+ /** The disabled options' reasons, printed below the whole chip row ("Label: reason"). */
7
+ export declare function ChipGroupReasons({ reasons }: {
8
+ reasons: Reason[];
9
+ }): import("react").JSX.Element | null;
10
+ export {};
@@ -0,0 +1,12 @@
1
+ import { RefObject } from 'react';
2
+ /**
3
+ * The single scrolling line of `ChipGroupField overflow="scroll"`: the ref and
4
+ * attributes of the chips' box, and its classes. `data-fade` says which edge
5
+ * hides more chips (`start`, `end` or `both`), read off the scroll offset.
6
+ * With `enabled` false nothing is attached and the chips wrap.
7
+ */
8
+ export declare function useChipRail(enabled: boolean): {
9
+ ref: RefObject<HTMLDivElement | null> | undefined;
10
+ props: Record<string, string | undefined> | undefined;
11
+ className: string | undefined;
12
+ };
@@ -1,4 +1,4 @@
1
- import { ComponentProps, ReactNode } from 'react';
1
+ import { ComponentProps, ReactNode, Ref } from 'react';
2
2
  import { useChoiceGroup } from './use-choice-group.js';
3
3
  export type ChoiceGroupRootProps = {
4
4
  /** What the root reads of the group: not its items, so any element type fits. */
@@ -11,10 +11,13 @@ export type ChoiceGroupRootProps = {
11
11
  inlineReasons?: boolean;
12
12
  /** Printed after the items, outside their flow: the visible reasons the items point to. */
13
13
  reasonsBelow?: ReactNode;
14
+ /** Ref and extra attributes of the box that holds the items (a scrolling rail reads its edges). */
15
+ contentRef?: Ref<HTMLDivElement>;
16
+ contentProps?: ComponentProps<'div'> & Record<`data-${string}`, string | undefined>;
14
17
  children: ReactNode;
15
18
  } & Omit<ComponentProps<'div'>, 'children' | 'role' | 'id' | 'onKeyDown'>;
16
19
  /**
17
20
  * A choice group's root: label, items, help or "not valid" hint, the hidden
18
21
  * reasons items point to, and a polite live region for the count.
19
22
  */
20
- export declare function ChoiceGroupRoot({ group, name, slot, className, contentClassName, inlineReasons, reasonsBelow, children, ref: _ref, ...props }: ChoiceGroupRootProps): import("react").JSX.Element;
23
+ export declare function ChoiceGroupRoot({ group, name, slot, className, contentClassName, inlineReasons, reasonsBelow, contentRef, contentProps, children, ref: _ref, ...props }: ChoiceGroupRootProps): import("react").JSX.Element;
@@ -13,6 +13,7 @@ export * from './radio-group/index.js';
13
13
  export * from './select/index.js';
14
14
  export * from './select-field/index.js';
15
15
  export * from './sortable-list/index.js';
16
+ export * from './status-menu/index.js';
16
17
  export * from './switcher/index.js';
17
18
  export * from './transfer-list/index.js';
18
19
  export * from './tree-select-field/index.js';
@@ -0,0 +1,3 @@
1
+ export { StatusMenu } from './status-menu.js';
2
+ export { StatusMenuFormField, type StatusMenuFormFieldProps, } from './status-menu-form-field.js';
3
+ export type { StatusChoice, StatusConfirm, StatusMenuProps } from './types.js';
@@ -0,0 +1,12 @@
1
+ import { StatusChoice } from '../types.js';
2
+ /**
3
+ * The confirmation a status asks for before it is picked, through the
4
+ * library's `ConfirmDialog` (busy buttons, the failure kept in the dialog,
5
+ * focus back to the chip on close).
6
+ */
7
+ export declare function StatusConfirm({ choice, onConfirm, onCancel, onCloseAutoFocus, }: {
8
+ choice: StatusChoice | null;
9
+ onConfirm: (value: string) => Promise<void>;
10
+ onCancel: () => void;
11
+ onCloseAutoFocus: (event: Event) => void;
12
+ }): import("react").JSX.Element;
@@ -0,0 +1,6 @@
1
+ import { StatusChoice } from '../types.js';
2
+ /** A status's decorative icon in its tone's text colour; the words carry the meaning. */
3
+ export declare function StatusIcon({ choice, className, }: {
4
+ choice: Pick<StatusChoice, 'icon' | 'tone'>;
5
+ className?: string;
6
+ }): import("react").JSX.Element | null;
@@ -0,0 +1,18 @@
1
+ import { StatusEntry } from '@nxgt/material-core/status-menu';
2
+ import { StatusChoice } from '../types.js';
3
+ /**
4
+ * One status row: its icon, label and a second line (the reason when
5
+ * blocked, else the description). The held one is checked and inert; a
6
+ * blocked one is greyed and says why.
7
+ */
8
+ export declare function StatusItem({ entry, choice, reason, }: {
9
+ entry: StatusEntry;
10
+ choice: StatusChoice;
11
+ reason?: string;
12
+ }): import("react").JSX.Element;
13
+ /** A status row's content, in the menu and in the phone sheet: icon, label, and the reason or description. */
14
+ export declare function StatusItemBody({ entry, choice, reason, }: {
15
+ entry: StatusEntry;
16
+ choice: StatusChoice;
17
+ reason?: string;
18
+ }): import("react").JSX.Element;
@@ -0,0 +1,14 @@
1
+ import { StatusEntry } from '@nxgt/material-core/status-menu';
2
+ import { StatusChoice } from '../types.js';
3
+ /** The open menu: the lock reason first when locked, then one radio row per status. */
4
+ export declare function StatusMenuList({ value, lockedReason, rows, onPick, className, }: {
5
+ value: string;
6
+ lockedReason?: string;
7
+ rows: {
8
+ entry: StatusEntry;
9
+ choice: StatusChoice;
10
+ reason?: string;
11
+ }[];
12
+ onPick: (next: string) => void;
13
+ className?: string;
14
+ }): import("react").JSX.Element;
@@ -0,0 +1,11 @@
1
+ import { StatusEntry } from '@nxgt/material-core/status-menu';
2
+ import { StatusChoice } from '../types.js';
3
+ /**
4
+ * One 44px radio row of the phone sheet. The held status is checked and
5
+ * inert; a blocked one is greyed, disabled and says why in its own text.
6
+ */
7
+ export declare function StatusSheetRow({ entry, choice, reason, }: {
8
+ entry: StatusEntry;
9
+ choice: StatusChoice;
10
+ reason?: string;
11
+ }): import("react").JSX.Element;
@@ -0,0 +1,21 @@
1
+ import { StatusEntry } from '@nxgt/material-core/status-menu';
2
+ import { StatusChoice } from '../types.js';
3
+ /**
4
+ * The phone's choices: a bottom sheet named by the record's label, a close
5
+ * button, and a radiogroup of 44px rows. A blocked row says why in its own
6
+ * text (touch has no tooltip); the held one is checked and inert. Picking a
7
+ * row closes the sheet, and focus returns to the chip.
8
+ */
9
+ export declare function StatusSheet({ label, value, lockedReason, rows, onPick, onClose, className, }: {
10
+ label: string;
11
+ value: string;
12
+ lockedReason?: string;
13
+ rows: {
14
+ entry: StatusEntry;
15
+ choice: StatusChoice;
16
+ reason?: string;
17
+ }[];
18
+ onPick: (next: string) => void;
19
+ onClose: () => void;
20
+ className?: string;
21
+ }): import("react").JSX.Element;
@@ -0,0 +1,18 @@
1
+ import { ComponentProps } from 'react';
2
+ import { StatusChoice, StatusMenuProps } from '../types.js';
3
+ /**
4
+ * The chip: a soft Badge pill (tone container, tone icon, words, chevron) as a
5
+ * button. It forwards its props and ref, so it works as the child of a
6
+ * `DropdownMenuTrigger asChild` and a `Tooltip`.
7
+ */
8
+ export declare function StatusTrigger({ choice, size, busy, locked, className, ...props }: {
9
+ choice: Pick<StatusChoice, 'label' | 'icon' | 'tone'>;
10
+ size?: StatusMenuProps['size'];
11
+ busy?: boolean;
12
+ locked?: boolean;
13
+ } & Omit<ComponentProps<'button'>, 'children'>): import("react").JSX.Element;
14
+ /** Read-only: the status as a plain label, no button and no chevron. */
15
+ export declare function StatusReadOnly({ choice, size, className, ...props }: {
16
+ choice: Pick<StatusChoice, 'label' | 'icon' | 'tone'>;
17
+ size?: StatusMenuProps['size'];
18
+ } & ComponentProps<'span'>): import("react").JSX.Element;
@@ -0,0 +1,12 @@
1
+ import { StatusChoice } from './types.js';
2
+ export type TicketStatus = 'todo' | 'progress' | 'waiting' | 'done' | 'cancelled';
3
+ /** Generic statuses: a ticket, an order or a task has a set like this. */
4
+ export declare const TICKET_STATUSES: StatusChoice<TicketStatus>[];
5
+ /** What a task in Done may become: a reopen to In progress only. */
6
+ export declare const TICKET_TRANSITIONS: {
7
+ todo: ("progress" | "waiting" | "cancelled")[];
8
+ progress: ("done" | "waiting" | "cancelled" | "todo")[];
9
+ waiting: ("progress" | "cancelled")[];
10
+ done: "progress"[];
11
+ cancelled: "todo"[];
12
+ };
@@ -0,0 +1,20 @@
1
+ import { UseControllerProps } from 'react-hook-form';
2
+ import { StatusMenuProps } from './types.js';
3
+ export type StatusMenuFormFieldProps<T extends Record<string, any>, V extends string = string> = Pick<UseControllerProps<T>, 'control' | 'name' | 'rules'> & Omit<StatusMenuProps<V>, 'value' | 'onSelect'> & {
4
+ /**
5
+ * Runs first; the form takes the new status once it resolves (a promise
6
+ * keeps the pending state and the old status). A rejection keeps the old
7
+ * value and goes to `onError`.
8
+ */
9
+ onSelect?: StatusMenuProps<V>['onSelect'];
10
+ /** Nothing can be picked, as `locked` (React Hook Form's `disabled` sets it too). */
11
+ disabled?: boolean;
12
+ /** Shown under the chip while there is no error. */
13
+ helperText?: string;
14
+ };
15
+ /**
16
+ * `StatusMenu` bound to React Hook Form: the form holds the status (a
17
+ * `choices` value), a pick calls `field.onChange`, the error message is written
18
+ * under the chip and linked to it, and a refused submit focuses the chip.
19
+ */
20
+ export declare function StatusMenuFormField<T extends Record<string, any>, V extends string = string>({ control, name, rules, onSelect, disabled, helperText, locked, triggerProps, ...props }: StatusMenuFormFieldProps<T, V>): import("react").JSX.Element;
@@ -0,0 +1,13 @@
1
+ import { StatusMenuProps } from './types.js';
2
+ /**
3
+ * A record's status as a chip (a soft Badge pill: tone container, tone icon,
4
+ * words, chevron) that opens a menu of the other statuses. The held one is
5
+ * checked and inert; the ones `transitions` do not reach are greyed with their
6
+ * reason; `locked` shows its reason (tooltip and first menu line) and picks
7
+ * nothing; `busy` (or an `onSelect` that returns a promise, until it settles) keeps the old
8
+ * status with a spinner and announces a failure through `onError`; a choice with
9
+ * `confirm` asks first; `readOnly` is a plain
10
+ * label. Under 768px (`presentation="auto"`) the statuses open in a bottom sheet of 44px rows,
11
+ * each blocked reason written in its row.
12
+ */
13
+ export declare function StatusMenu<V extends string = string>(props: StatusMenuProps<V>): import("react").JSX.Element;
@@ -0,0 +1,76 @@
1
+ import { ComponentProps, ReactNode } from 'react';
2
+ import { IconName } from '../../primitives/icon/icon.js';
3
+ import { Tone } from '../../tones.js';
4
+ /** One status a record can hold. */
5
+ export type StatusChoice<V extends string = string> = {
6
+ value: V;
7
+ /** The status in words: what the chip and the menu say. */
8
+ label: string;
9
+ /** Its colour (neutral without one). */
10
+ tone?: Tone;
11
+ /** A decorative icon: a Font Awesome name or a node. The words name the status. */
12
+ icon?: ReactNode | IconName;
13
+ /** A second line under its label in the menu. */
14
+ description?: string;
15
+ /** Cannot be picked. */
16
+ disabled?: boolean;
17
+ /** Why it cannot be picked, shown under its label. */
18
+ disabledReason?: string;
19
+ /** Picking it first asks for a confirmation (a `ConfirmDialog`); `onSelect` runs on confirm. */
20
+ confirm?: StatusConfirm;
21
+ };
22
+ /** The confirmation a status asks for before it is picked. */
23
+ export type StatusConfirm = {
24
+ title: string;
25
+ description?: ReactNode;
26
+ /** The confirm button's words (default "Confirm"). */
27
+ confirmLabel?: string;
28
+ /** A red confirm button, for a move that cannot be undone. */
29
+ destructive?: boolean;
30
+ };
31
+ export type StatusMenuProps<V extends string = string> = {
32
+ /** What the status belongs to ("Ticket 42"): the button is named "Status of Ticket 42: Open". */
33
+ label: string;
34
+ /** The held status: the `value` of one of `choices`. */
35
+ value: V;
36
+ choices: readonly StatusChoice<V>[];
37
+ /**
38
+ * A different status was picked (never the held one, never when locked or
39
+ * busy). Return a promise to show the pending state until it settles.
40
+ */
41
+ onSelect: (next: V, prev: V) => void | Promise<void>;
42
+ /** An `onSelect` that rejects (or a confirmed one): the failure is announced and reported here. */
43
+ onError?: (error: unknown) => void;
44
+ /**
45
+ * The statuses reachable from each status. A status with no key allows every
46
+ * move.
47
+ */
48
+ transitions?: Partial<Record<V, readonly V[]>>;
49
+ /** A status the transitions do not reach: greyed with its reason (default) or `'hidden'`. */
50
+ unavailable?: 'disabled' | 'hidden';
51
+ /** Nothing can be picked: a tooltip and the first line of the menu say `reason`. */
52
+ locked?: boolean;
53
+ reason?: string;
54
+ /**
55
+ * A change is being saved: a spinner replaces the chevron, the old status
56
+ * stays. An `onSelect` that returns a promise sets it by itself until the
57
+ * promise settles; this prop is for a save the parent runs.
58
+ */
59
+ busy?: boolean;
60
+ /** A plain label: no button, no menu. */
61
+ readOnly?: boolean;
62
+ size?: 'sm' | 'md';
63
+ /**
64
+ * How the statuses open: `'menu'` (a dropdown), `'sheet'` (a bottom sheet of
65
+ * 44px rows, with each blocked reason written in its row) or `'auto'` (the
66
+ * default): a sheet under 768px, a menu above.
67
+ */
68
+ presentation?: 'auto' | 'menu' | 'sheet';
69
+ /** Controlled state, as `DropdownMenu`'s. */
70
+ open?: boolean;
71
+ onOpenChange?: (open: boolean) => void;
72
+ /** Props for the trigger button (`data-*`, `id`, `aria-describedby`…). */
73
+ triggerProps?: Omit<ComponentProps<'button'>, 'children' | 'type'>;
74
+ /** On the menu. */
75
+ className?: string;
76
+ };