@allxsmith/bestax-bulma 5.60.0 → 5.62.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 (98) hide show
  1. package/dist/bestax.css +1 -1
  2. package/dist/bestax.css.map +1 -1
  3. package/dist/esm/components/Carousel.js +3 -43
  4. package/dist/esm/components/Carousel.js.map +1 -1
  5. package/dist/esm/components/Command.js +3 -3
  6. package/dist/esm/components/Navbar.js +3 -1
  7. package/dist/esm/components/Navbar.js.map +1 -1
  8. package/dist/esm/components/Popover.js +7 -27
  9. package/dist/esm/components/Popover.js.map +1 -1
  10. package/dist/esm/components/Sidebar.js +17 -58
  11. package/dist/esm/components/Sidebar.js.map +1 -1
  12. package/dist/esm/components/TreeView.js +14 -10
  13. package/dist/esm/components/TreeView.js.map +1 -1
  14. package/dist/esm/form/ColorPicker.js +4 -4
  15. package/dist/esm/form/ColorPicker.js.map +1 -1
  16. package/dist/esm/form/Combobox.js +11 -16
  17. package/dist/esm/form/Combobox.js.map +1 -1
  18. package/dist/esm/form/Field.js.map +1 -1
  19. package/dist/esm/form/TreeSelect.js +395 -0
  20. package/dist/esm/form/TreeSelect.js.map +1 -0
  21. package/dist/esm/form/_pickerInternals/PickerPopover.js +5 -1
  22. package/dist/esm/form/_pickerInternals/PickerPopover.js.map +1 -1
  23. package/dist/esm/form/_selectInternals/DialogSelect.js +208 -0
  24. package/dist/esm/form/_selectInternals/DialogSelect.js.map +1 -0
  25. package/dist/esm/form/_selectInternals/ValueTags.js +28 -0
  26. package/dist/esm/form/_selectInternals/ValueTags.js.map +1 -0
  27. package/dist/esm/helpers/overlayStack.js +33 -1
  28. package/dist/esm/helpers/overlayStack.js.map +1 -1
  29. package/dist/esm/helpers/treeData.js +97 -0
  30. package/dist/esm/helpers/treeData.js.map +1 -0
  31. package/dist/esm/helpers/useBulmaViewport.js +82 -0
  32. package/dist/esm/helpers/useBulmaViewport.js.map +1 -0
  33. package/dist/esm/helpers/useComboboxEngine.js +2 -2
  34. package/dist/esm/helpers/useComboboxEngine.js.map +1 -1
  35. package/dist/esm/helpers/useControlled.js +30 -0
  36. package/dist/esm/helpers/useControlled.js.map +1 -0
  37. package/dist/esm/helpers/useInertSiblings.js +7 -3
  38. package/dist/esm/helpers/useInertSiblings.js.map +1 -1
  39. package/dist/esm/helpers/useOutsidePress.js +53 -0
  40. package/dist/esm/helpers/useOutsidePress.js.map +1 -0
  41. package/dist/esm/helpers/useOverlayFocus.js +74 -0
  42. package/dist/esm/helpers/useOverlayFocus.js.map +1 -0
  43. package/dist/esm/helpers/useTreeView.js +15 -13
  44. package/dist/esm/helpers/useTreeView.js.map +1 -1
  45. package/dist/esm/layout/AppFrame.js +438 -0
  46. package/dist/esm/layout/AppFrame.js.map +1 -0
  47. package/dist/extras.css +1 -1
  48. package/dist/extras.css.map +1 -1
  49. package/dist/index.cjs +1767 -518
  50. package/dist/index.cjs.map +1 -1
  51. package/dist/index.esm.js +2 -0
  52. package/dist/index.esm.js.map +1 -1
  53. package/dist/types/components/Navbar.d.ts +4 -3
  54. package/dist/types/form/Field.d.ts +1 -1
  55. package/dist/types/form/TreeSelect.d.ts +308 -0
  56. package/dist/types/form/_pickerInternals/PickerPopover.d.ts +8 -0
  57. package/dist/types/form/_selectInternals/DialogSelect.d.ts +86 -0
  58. package/dist/types/form/_selectInternals/ValueTags.d.ts +40 -0
  59. package/dist/types/helpers/overlayStack.d.ts +17 -0
  60. package/dist/types/helpers/treeData.d.ts +48 -0
  61. package/dist/types/helpers/useBulmaViewport.d.ts +34 -0
  62. package/dist/types/helpers/useControlled.d.ts +14 -0
  63. package/dist/types/helpers/useInertSiblings.d.ts +4 -1
  64. package/dist/types/helpers/useOutsidePress.d.ts +24 -0
  65. package/dist/types/helpers/useOverlayFocus.d.ts +44 -0
  66. package/dist/types/helpers/useTreeView.d.ts +30 -0
  67. package/dist/types/index.d.ts +2 -0
  68. package/dist/types/layout/AppFrame.d.ts +306 -0
  69. package/dist/types-cjs/components/Navbar.d.ts +4 -3
  70. package/dist/types-cjs/form/Field.d.ts +1 -1
  71. package/dist/types-cjs/form/TreeSelect.d.ts +308 -0
  72. package/dist/types-cjs/form/_pickerInternals/PickerPopover.d.ts +8 -0
  73. package/dist/types-cjs/form/_selectInternals/DialogSelect.d.ts +86 -0
  74. package/dist/types-cjs/form/_selectInternals/ValueTags.d.ts +40 -0
  75. package/dist/types-cjs/helpers/overlayStack.d.ts +17 -0
  76. package/dist/types-cjs/helpers/treeData.d.ts +48 -0
  77. package/dist/types-cjs/helpers/useBulmaViewport.d.ts +34 -0
  78. package/dist/types-cjs/helpers/useControlled.d.ts +14 -0
  79. package/dist/types-cjs/helpers/useInertSiblings.d.ts +4 -1
  80. package/dist/types-cjs/helpers/useOutsidePress.d.ts +24 -0
  81. package/dist/types-cjs/helpers/useOverlayFocus.d.ts +44 -0
  82. package/dist/types-cjs/helpers/useTreeView.d.ts +30 -0
  83. package/dist/types-cjs/index.d.ts +2 -0
  84. package/dist/types-cjs/layout/AppFrame.d.ts +306 -0
  85. package/dist/versions/bestax-no-dark-mode.css +1 -1
  86. package/dist/versions/bestax-no-dark-mode.css.map +1 -1
  87. package/dist/versions/bestax-no-helpers-prefixed.css +1 -1
  88. package/dist/versions/bestax-no-helpers-prefixed.css.map +1 -1
  89. package/dist/versions/bestax-no-helpers.css +1 -1
  90. package/dist/versions/bestax-no-helpers.css.map +1 -1
  91. package/dist/versions/bestax-prefixed.css +1 -1
  92. package/dist/versions/bestax-prefixed.css.map +1 -1
  93. package/package.json +1 -1
  94. package/src/scss/form/_index.scss +1 -0
  95. package/src/scss/form/_picker-popover.scss +6 -0
  96. package/src/scss/form/_treeselect.scss +146 -0
  97. package/src/scss/layout/_appframe.scss +306 -0
  98. package/src/scss/layout/_index.scss +1 -0
@@ -0,0 +1,308 @@
1
+ import React from 'react';
2
+ import type { BulmaClassesProps } from '../helpers/useBulmaClasses.js';
3
+ import type { FormFieldProps } from './fieldProps.js';
4
+ import type { PickerPosition } from './_pickerInternals/pickerTypes.js';
5
+ /**
6
+ * One node in a TreeSelect's `data`: Combobox's item fields plus
7
+ * TreeView.Item's, with `children` for the nodes under it.
8
+ */
9
+ export interface TreeItemData {
10
+ /** **Required.** What the value holds and `name` posts. Unique in the whole tree. */
11
+ value: string;
12
+ /** What the row, the field and the tags show, and what search matches. The `value` when it's left out. */
13
+ label?: string;
14
+ /** Reachable, but never picked, checked, opened or closed. */
15
+ disabled?: boolean;
16
+ /** A picture before the label: an `Icon` name, or a node. Hidden from assistive tech. */
17
+ icon?: React.ReactNode;
18
+ /** The nodes under this one. */
19
+ children?: TreeItemData[];
20
+ /** Shows the node as a parent before its children are known, for a branch that loads when it opens. */
21
+ hasChildren?: boolean;
22
+ /** Its children are on their way: an open branch ends in a row that says so, and the live region says it too. */
23
+ isLoading?: boolean;
24
+ /** Its children didn't load: an open branch ends in this message, with a Retry button when there's an `onRetry`. */
25
+ loadError?: React.ReactNode;
26
+ /** Called by the Retry button on a failed load's row. Set `isLoading` while the retry runs. */
27
+ onRetry?: () => void;
28
+ }
29
+ /** What a checked branch puts in the value a check makes. */
30
+ export type TreeSelectCheckedStrategy = 'child' | 'parent' | 'all';
31
+ /** The visible and accessible strings, in your app's language. */
32
+ export interface TreeSelectLabels {
33
+ /**
34
+ * Names the panel and the tree in it.
35
+ * @defaultValue the field's label
36
+ */
37
+ choose?: string;
38
+ /**
39
+ * Names the search box.
40
+ * @defaultValue 'Search'
41
+ */
42
+ search?: string;
43
+ /**
44
+ * Names the clear button.
45
+ * @defaultValue 'Clear'
46
+ */
47
+ clear?: string;
48
+ /**
49
+ * What a loading branch's row says, as on TreeView.
50
+ * @defaultValue 'Loading…'
51
+ */
52
+ loading?: string;
53
+ /**
54
+ * The Retry button's text on a failed load's row, as on TreeView.
55
+ * @defaultValue 'Retry'
56
+ */
57
+ retry?: string;
58
+ /**
59
+ * What the live region says when an open branch starts loading, built
60
+ * from its name, as on TreeView.
61
+ * @defaultValue name => `Loading ${name}`
62
+ */
63
+ loadingAnnouncement?: (name: string) => string;
64
+ /**
65
+ * What the live region says when that load finishes, as on TreeView.
66
+ * @defaultValue name => `${name} loaded`
67
+ */
68
+ loadedAnnouncement?: (name: string) => string;
69
+ }
70
+ /**
71
+ * What every TreeSelect takes. The helper props and the other attributes
72
+ * land on the root `<div>`, as Combobox's do, and the `ref` on the field.
73
+ */
74
+ interface TreeSelectBaseProps extends Omit<React.HTMLAttributes<HTMLDivElement>, 'color' | 'onChange' | 'defaultValue' | 'children'>, Omit<BulmaClassesProps, 'color'>, FormFieldProps {
75
+ /** **Required.** The tree, as nodes nested through `children`. */
76
+ data: TreeItemData[];
77
+ /**
78
+ * The field's label, which names the field through `htmlFor`, and the
79
+ * panel and the tree in it through `aria-labelledby`. Dropped inside an
80
+ * outer `Field`, whose label names them instead.
81
+ */
82
+ label?: React.ReactNode;
83
+ /** The field's `id`, which the label then points at. The panel's is this one with `-panel` after it. */
84
+ id?: string;
85
+ /** Names the field, and the panel and the tree, in place of a `label`. */
86
+ 'aria-label'?: string;
87
+ /** The ids of what names the field, and the panel and the tree, in place of a `label`. */
88
+ 'aria-labelledby'?: string;
89
+ /** The ids of what describes the field, ahead of the tags. */
90
+ 'aria-describedby'?: string;
91
+ /** The open branches' values when you hold the state, as TreeView's `expanded`. */
92
+ expanded?: string[];
93
+ /** The branches open to begin with, when TreeSelect holds its own state. */
94
+ defaultExpanded?: string[];
95
+ /**
96
+ * Called with the new list whenever a branch opens or closes, opening the
97
+ * panel on the picked item's branch included. Fetch a lazy branch's
98
+ * children from here. The branches a search opens aren't in it.
99
+ */
100
+ onExpandedChange?: (expanded: string[]) => void;
101
+ /** Whether the panel is open, controlled: opening and closing then only call `onOpenChange`. */
102
+ open?: boolean;
103
+ /** The panel is open to begin with. */
104
+ defaultOpen?: boolean;
105
+ /** Called with the new state when the panel opens or closes. */
106
+ onOpenChange?: (open: boolean) => void;
107
+ /**
108
+ * Puts a search box at the top of the panel. It matches labels, keeps a
109
+ * match's ancestors and the nodes under it, and opens every branch with a
110
+ * match. A printable key on the field opens the panel with it in the box,
111
+ * and the search empties when the panel closes.
112
+ */
113
+ searchable?: boolean;
114
+ /** The search text when you hold the state. */
115
+ query?: string;
116
+ /** The search text to begin with. */
117
+ defaultQuery?: string;
118
+ /** Called with the search text as it changes. */
119
+ onQueryChange?: (query: string) => void;
120
+ /**
121
+ * Whether a node matches the search, in place of the locale-aware match on
122
+ * its label. It's handed the search text trimmed, the node, and its path
123
+ * from the top node down, the node last, as Cascader's `filter` is. A
124
+ * match's ancestors stay either way. The search runs again when the search
125
+ * text or `data` changes, not when only this does, so one written inline
126
+ * costs nothing.
127
+ */
128
+ filter?: (query: string, item: TreeItemData, path: TreeItemData[]) => boolean;
129
+ /** What the panel shows when the search matches nothing, such as "No folders match". Announced once. */
130
+ empty?: React.ReactNode;
131
+ /** Renders a row's content in place of its label. The field and the tags still show the label. */
132
+ itemTemplate?: (item: TreeItemData) => React.ReactNode;
133
+ /** What the field shows while nothing is picked. */
134
+ placeholder?: string;
135
+ /** A form field name. A hidden input posts the value, or one per value in the checkbox modes. */
136
+ name?: string;
137
+ /** The id of the form the hidden inputs belong to, when it isn't an ancestor. */
138
+ form?: string;
139
+ /**
140
+ * A value is needed: the field is `aria-required`, and the form won't
141
+ * submit while nothing is picked. The browser's message points at the
142
+ * field, which shows focus, and the next key goes to it.
143
+ */
144
+ required?: boolean;
145
+ /** The field can't be used: it can't be focused or opened, its tags lose their buttons, and its hidden inputs don't post. */
146
+ disabled?: boolean;
147
+ /**
148
+ * Shows a clear button at the field's inline end while something it can
149
+ * take off is picked. It leaves checked disabled items, which no control
150
+ * unchecks.
151
+ */
152
+ clearable?: boolean;
153
+ /** Bulma color modifier for the field. */
154
+ color?: 'primary' | 'link' | 'info' | 'success' | 'warning' | 'danger';
155
+ /** The field's size, which the tree in the panel follows. */
156
+ size?: 'small' | 'medium' | 'large';
157
+ /** Rounds the field's corners (Bulma's `is-rounded`). */
158
+ isRounded?: boolean;
159
+ /**
160
+ * Where the panel opens, relative to the field, as on the pickers.
161
+ * @defaultValue 'bottom-left'
162
+ */
163
+ position?: PickerPosition;
164
+ /** Renders the panel through a portal, into a `ConfigProvider`'s `portalContainer`, `document.body` by default. */
165
+ appendToBody?: boolean;
166
+ /** The visible and accessible strings, in your app's language. */
167
+ labels?: TreeSelectLabels;
168
+ }
169
+ /** Props for a TreeSelect that picks one item. */
170
+ export interface TreeSelectSingleProps extends TreeSelectBaseProps {
171
+ /**
172
+ * `'single'`: one item, picked with Enter, Space or a click on its row.
173
+ * `'checkbox'`: any number, with a box on every item. A check reaches every
174
+ * enabled item under it, and a parent with some of them checked is mixed.
175
+ * `'checkbox-independent'`: any number, each box checking its own item, so
176
+ * a parent means the parent alone (Mantine's and Ant Design's
177
+ * `checkStrictly`). The checkbox modes show the value as tags.
178
+ */
179
+ selectionMode?: 'single';
180
+ /**
181
+ * The value when you hold the state: in `'single'` the picked item's
182
+ * value, or `null` for none, and in the checkbox modes the checked values.
183
+ * In `'checkbox'` a parent's value checks its whole branch, so the list any
184
+ * `checkedStrategy` gives checks the same boxes.
185
+ */
186
+ value?: string | null;
187
+ /** The value to begin with, when TreeSelect holds its own state: a value or `null`, or a list in the checkbox modes. */
188
+ defaultValue?: string | null;
189
+ /**
190
+ * Called with the new value: in `'single'` the picked item's value, or
191
+ * `null` when it's cleared, and in the checkbox modes the new list, after a
192
+ * check, an uncheck, a tag's button or the clear button, each shaped by
193
+ * `checkedStrategy`. A reset of the field's form calls it too, with
194
+ * `defaultValue` as it was given, or with `null` or `[]` when you hold
195
+ * the value, for you to set.
196
+ */
197
+ onChange?: (value: string | null) => void;
198
+ /**
199
+ * A parent's row picks the parent. `false` makes the row, Enter and Space
200
+ * open it instead, so only leaves are picked.
201
+ * @defaultValue true
202
+ */
203
+ parentsSelectable?: boolean;
204
+ /**
205
+ * Closes the panel after a pick and puts focus back on the field.
206
+ * @defaultValue true
207
+ */
208
+ closeOnSelect?: boolean;
209
+ /** @internal Read with the checkbox modes only. */
210
+ checkedStrategy?: never;
211
+ /** @internal Read with the checkbox modes only. */
212
+ ariaCloseLabel?: never;
213
+ }
214
+ /** Props for a TreeSelect with a box on every item. */
215
+ export interface TreeSelectCheckboxProps extends TreeSelectBaseProps {
216
+ /**
217
+ * `'checkbox'`: a check reaches every enabled item under it, and a parent
218
+ * with some of them checked is mixed. `'checkbox-independent'`: each box
219
+ * checks its own item, so a parent means the parent alone.
220
+ */
221
+ selectionMode: 'checkbox' | 'checkbox-independent';
222
+ /**
223
+ * The checked values when you hold the state. In `'checkbox'`, a parent's
224
+ * value checks its whole branch, so the list any `checkedStrategy` gives
225
+ * checks the same boxes.
226
+ */
227
+ value?: string[];
228
+ /** The values checked to begin with, when TreeSelect holds its own state. */
229
+ defaultValue?: string[];
230
+ /**
231
+ * Called with the new list after a check, an uncheck, a tag's button or
232
+ * the clear button, shaped by `checkedStrategy`, and after a reset of the
233
+ * field's form, with `defaultValue` as given, or `[]` when you hold the
234
+ * value.
235
+ */
236
+ onChange?: (value: string[]) => void;
237
+ /**
238
+ * What a checked branch puts in the value, in `'checkbox'`: `'child'` its
239
+ * leaves, `'parent'` its topmost checked item, `'all'` every checked item,
240
+ * parents included. A checked disabled item is in all three, since only
241
+ * its own value checks it. It shapes the value a check, an uncheck, a
242
+ * tag's button or the clear button makes, which `onChange` reports, and
243
+ * not `defaultValue`, a value you pass or the one a form reset puts back.
244
+ * The tags and the hidden
245
+ * inputs show the value as it's held, so a value you pass shows as you
246
+ * pass it, and a branch that loads later changes nothing the form posts.
247
+ * `'checkbox-independent'` always reports exactly the checked items.
248
+ * @defaultValue 'child'
249
+ */
250
+ checkedStrategy?: TreeSelectCheckedStrategy;
251
+ /** Names each tag's button, in place of "Remove" and the item's label, as on Combobox. */
252
+ ariaCloseLabel?: string;
253
+ /** @internal Read with `'single'` only. */
254
+ parentsSelectable?: never;
255
+ /** @internal Read with `'single'` only: the panel stays open while boxes are checked. */
256
+ closeOnSelect?: never;
257
+ }
258
+ /**
259
+ * Props for the TreeSelect component. The helper props and the other
260
+ * attributes land on the `div.tree-select` around the field, and the `ref`
261
+ * on the field. It renders the `Field` and the label itself, unless an outer
262
+ * `Field` already does.
263
+ *
264
+ * @extraProp {React.Ref<HTMLInputElement>} [ref] - Ref forwarded to the field, the read-only `<input role="combobox">`.
265
+ */
266
+ export type TreeSelectProps = TreeSelectSingleProps | TreeSelectCheckboxProps;
267
+ /**
268
+ * The `TreeSelect` component is a form field whose options are a tree, such as categories, places or teams: it opens a panel holding a real `TreeView`, picks one item or checks a branch at a time, and searches labels.
269
+ *
270
+ * The field is a read-only `role="combobox"` that opens a dialog, wired as
271
+ * DateInput's is, so focus moves into the tree for real and the tree keeps
272
+ * TreeView's keys, type-ahead and spoken output. The tree is given as `data`,
273
+ * so the field and the tags can name what's picked while the panel is shut,
274
+ * and on the server.
275
+ *
276
+ * `selectionMode` picks the kind. `'single'` picks one item and closes. With
277
+ * `'checkbox'`, a check reaches every enabled item under it, closed or hidden
278
+ * by a search, and `checkedStrategy` decides what the value holds: the
279
+ * leaves, the topmost checked items or every one. With
280
+ * `'checkbox-independent'`, each box is its own item's, so a parent means
281
+ * itself alone (Mantine's and Ant Design's `checkStrictly`). The value shows
282
+ * as tags under the field.
283
+ *
284
+ * A value no node has is kept and shown as it is, with a warning in
285
+ * development, so a value under a branch that hasn't loaded survives until
286
+ * it does.
287
+ *
288
+ * @function
289
+ * @param {TreeSelectProps} props - Props for the TreeSelect component.
290
+ * @param {React.Ref<HTMLInputElement>} ref - Forwarded ref to the field.
291
+ * @returns {JSX.Element} The field, its tags and its panel, in a `Field` with the label unless one is around it.
292
+ * @see {@link https://www.w3.org/WAI/ARIA/apg/patterns/combobox/ | APG Combobox Pattern}
293
+ *
294
+ * @example
295
+ * <TreeSelect
296
+ * label="Save to"
297
+ * data={[
298
+ * { value: 'docs', label: 'Documents', children: [{ value: 'invoices', label: 'Invoices' }] },
299
+ * { value: 'photos', label: 'Photos' },
300
+ * ]}
301
+ * searchable
302
+ * />
303
+ *
304
+ * @example
305
+ * <TreeSelect label="Regions" selectionMode="checkbox" checkedStrategy="parent" data={regions} />
306
+ */
307
+ export declare const TreeSelect: React.ForwardRefExoticComponent<TreeSelectProps & React.RefAttributes<HTMLInputElement>>;
308
+ export default TreeSelect;
@@ -35,6 +35,14 @@ export interface PickerPopoverProps {
35
35
  * `LocaleProvider`'s: the picker's own, from `usePickerLocaleScope`.
36
36
  */
37
37
  localeScope?: PortalLocale;
38
+ /**
39
+ * At least as wide as the anchor: in place through its partial's
40
+ * `has-anchor-width` rule, which needs the anchor to be the element it's
41
+ * placed against, and portaled through the anchor's width set inline.
42
+ */
43
+ matchWidth?: boolean;
44
+ /** Placed again after each render, for content that changes size while it's open. */
45
+ followContent?: boolean;
38
46
  }
39
47
  export declare const PickerPopover: React.FC<PickerPopoverProps>;
40
48
  export default PickerPopover;
@@ -0,0 +1,86 @@
1
+ import React from 'react';
2
+ import { type BulmaClassesProps } from '../../helpers/useBulmaClasses.js';
3
+ import type { FormFieldProps } from '../fieldProps.js';
4
+ import { type PickerPosition } from '../_pickerInternals/pickerTypes.js';
5
+ /** What names the panel, for what's in it to take as well. */
6
+ export interface PanelName {
7
+ 'aria-label'?: string;
8
+ 'aria-labelledby'?: string;
9
+ }
10
+ /** Props for the field a tree picker opens its panel from. */
11
+ export interface DialogSelectProps extends Omit<React.HTMLAttributes<HTMLDivElement>, 'color' | 'onChange' | 'defaultValue' | 'children'>, Omit<BulmaClassesProps, 'color'>, FormFieldProps {
12
+ /** The component's name, for development warnings. */
13
+ component: string;
14
+ /** The root's own class, before any prefix, such as `tree-select`. */
15
+ rootClass: string;
16
+ /** The panel's own class, beside `picker-popover`, before any prefix. */
17
+ panelClass: string;
18
+ /** What the field shows. */
19
+ text: string;
20
+ /** What `name` posts, a hidden input each. */
21
+ values: string[];
22
+ /** Something is picked: `required` is met, and the clear button shows. */
23
+ hasValue: boolean;
24
+ /** Whether the panel is open. */
25
+ open: boolean;
26
+ /**
27
+ * Asked to open or close the panel: by a click on the field, its keys,
28
+ * Escape, Alt+Up, a press outside and the clear button.
29
+ */
30
+ onOpenChange: (open: boolean) => void;
31
+ /**
32
+ * Called once a reset of the field's form has gone ahead, so the picker
33
+ * can put its value back.
34
+ */
35
+ onFormReset: () => void;
36
+ /**
37
+ * A printable key on the field. Returns whether it used the key, as a
38
+ * search box opening with it does.
39
+ */
40
+ onPrintableKey?: (key: string) => boolean;
41
+ /** Empties the value, from the clear button. */
42
+ onClear: () => void;
43
+ /** Shows the clear button while something is picked. */
44
+ clearable?: boolean;
45
+ /** Names the clear button. */
46
+ clearLabel: string;
47
+ /** Names the panel in place of the field's label. */
48
+ chooseLabel?: string;
49
+ placeholder?: string;
50
+ name?: string;
51
+ form?: string;
52
+ required?: boolean;
53
+ /** Already including a disabled `Fieldset` around it. */
54
+ disabled: boolean;
55
+ color?: 'primary' | 'link' | 'info' | 'success' | 'warning' | 'danger';
56
+ size?: 'small' | 'medium' | 'large';
57
+ isRounded?: boolean;
58
+ position?: PickerPosition;
59
+ appendToBody?: boolean;
60
+ /** Holds the field, which focus goes back to. */
61
+ inputRef: React.RefObject<HTMLInputElement | null>;
62
+ /**
63
+ * Set on the field: the picker's callback that fills `inputRef` and the
64
+ * ref its caller gave.
65
+ */
66
+ fieldRef: React.RefCallback<HTMLInputElement>;
67
+ /** The ids of the tags that describe the field. */
68
+ describedBy?: string;
69
+ /** Shown under the field, inside its Field: the tags. */
70
+ below?: React.ReactNode;
71
+ /** Selects what takes focus as the panel opens. */
72
+ initialFocusSelector?: string;
73
+ /** The panel's content, handed the panel's name. */
74
+ children: (name: PanelName) => React.ReactNode;
75
+ }
76
+ /**
77
+ * A read-only `role="combobox"` field, wired as the date pickers' are, that
78
+ * opens a `PickerPopover` dialog panel: in a `Field` of its own unless one is
79
+ * around it, with a chevron at its inline end, a clear button, the hidden
80
+ * inputs for `name` and what the browser's `required` check reads. A click,
81
+ * Enter, Space, Down or Alt+Down opens the panel, which holds focus, as the
82
+ * date pickers' does: Tab and Shift+Tab wrap inside it. Escape and Alt+Up
83
+ * close it and put focus back on the field, and a press outside closes it
84
+ * where the press put focus.
85
+ */
86
+ export declare function DialogSelect({ component, rootClass, panelClass, text, values, hasValue, open, onOpenChange, onFormReset, onPrintableKey, onClear, clearable, clearLabel, chooseLabel, placeholder, name, form, required, disabled, color, size, isRounded, position, appendToBody, inputRef, fieldRef, describedBy, below, initialFocusSelector, children, label, labelSize, labelProps, horizontal, message, messageColor, fieldClassName, className, id, 'aria-label': ariaLabel, 'aria-labelledby': ariaLabelledBy, 'aria-describedby': ariaDescribedBy, ...props }: DialogSelectProps): React.JSX.Element;
@@ -0,0 +1,40 @@
1
+ /** Props for the tags of a field holding several values. */
2
+ export interface ValueTagsProps {
3
+ /** The values, in the order they show. */
4
+ values: string[];
5
+ /** The id of each tag's label, from `tagIds`, which the field's description lists. */
6
+ ids: string[];
7
+ /** What a value shows. */
8
+ labelFor: (value: string) => string;
9
+ /** The field can't be used, so the tags have no buttons. */
10
+ disabled?: boolean;
11
+ /**
12
+ * Names each button in place of "Remove" and the value's label. The
13
+ * button is then described by its tag's label, so it still says which.
14
+ */
15
+ ariaCloseLabel?: string;
16
+ /** Called with a value when its tag's button is pressed. */
17
+ onRemove: (value: string) => void;
18
+ /** Whether a value's tag has a button. Every tag has one without it. */
19
+ removable?: (value: string) => boolean;
20
+ }
21
+ /**
22
+ * The values of a field holding several, as Bulma tags under it, each with a
23
+ * `Delete` that takes its value off. Nothing while there are none.
24
+ */
25
+ export declare function ValueTags({ values, ids, labelFor, disabled, ariaCloseLabel, onRemove, removable, }: ValueTagsProps): import("react").JSX.Element | null;
26
+ /** The ids `ValueTags` gives its labels, built from one id of the field's. */
27
+ export declare const tagIds: (base: string, values: string[]) => string[];
28
+ /** Props for the hidden inputs that post a field's values. */
29
+ export interface HiddenValuesProps {
30
+ /** The form field name. Nothing renders without one. */
31
+ name?: string;
32
+ /** One hidden input each. */
33
+ values: string[];
34
+ /** The id of the form they post with, for a field outside it. */
35
+ form?: string;
36
+ /** They don't post, as a disabled field's value doesn't. */
37
+ disabled?: boolean;
38
+ }
39
+ /** A hidden input for each value, so a form posts them under `name`. */
40
+ export declare function HiddenValues({ name, values, form, disabled, }: HiddenValuesProps): import("react").JSX.Element | null;
@@ -28,3 +28,20 @@ export declare const isModalOverlayOpen: () => boolean;
28
28
  * above this overlay.
29
29
  */
30
30
  export declare function useOverlayStack(inStack: boolean, modal?: boolean): (among?: 'modal') => boolean;
31
+ /**
32
+ * Calls `onEscape` for an Escape while `active` and the overlay is the
33
+ * topmost one, as `isTopmost` (from `useOverlayStack`) says, and marks the key
34
+ * used with `preventDefault()`, so nothing under it acts on it too.
35
+ *
36
+ * It listens on `window`, so everything inside the overlay has had the key
37
+ * first, and an Escape something there used, such as a popup closing, is
38
+ * left to it. The listener stays put while `onEscape` changes identity, as an
39
+ * inline one does on every render of the parent: it reads the latest one as
40
+ * the key arrives.
41
+ *
42
+ * @function useOverlayEscape
43
+ * @param active - Whether the overlay is open and closes on Escape.
44
+ * @param isTopmost - The overlay's check from `useOverlayStack`.
45
+ * @param onEscape - What closing it does.
46
+ */
47
+ export declare function useOverlayEscape(active: boolean, isTopmost: () => boolean, onEscape: () => void): void;
@@ -0,0 +1,48 @@
1
+ import type { TreeItemData, TreeSelectCheckedStrategy } from '../form/TreeSelect.js';
2
+ import { type TreeViewItemRecord } from './useTreeView.js';
3
+ /** A node, and the values of the nodes above it, from the top. */
4
+ export interface TreeNodeEntry {
5
+ node: TreeItemData;
6
+ path: string[];
7
+ }
8
+ /**
9
+ * Every node by its value, in the order the tree reads from top to bottom.
10
+ * Values are meant to be unique, and the first node with a value wins.
11
+ */
12
+ export declare function indexTree(data: TreeItemData[]): Map<string, TreeNodeEntry>;
13
+ /** What a node is called: its `label`, or its `value` when that's empty. */
14
+ export declare const nodeLabel: (node: TreeItemData) => string;
15
+ /** The nodes under a node, none when it has no `children`. */
16
+ export declare const childNodes: (node: TreeItemData) => TreeItemData[];
17
+ /** Whether a node is a parent: it has children, or `hasChildren` says it will. */
18
+ export declare const isParentNode: (node: TreeItemData) => boolean;
19
+ /**
20
+ * The records TreeView's check rules read, built from the nodes rather than
21
+ * from the items on the page, so the checked list can be worked out while
22
+ * the tree isn't there.
23
+ */
24
+ export declare function checkRecords(index: Map<string, TreeNodeEntry>): Map<string, TreeViewItemRecord>;
25
+ /**
26
+ * The checked list a `checkedStrategy` reports for the items `listed` checks
27
+ * by TreeView's rules, in the tree's order. `all` is every checked item;
28
+ * `child` the checked items with no enabled item under them; `parent` the
29
+ * checked items whose parent isn't. A disabled item is checked by its own
30
+ * value only, so a checked one is in every list. Values no node has are
31
+ * kept, at the end. Passed back in, each list checks the same items.
32
+ */
33
+ export declare function checkedByStrategy(records: Map<string, TreeViewItemRecord>, listed: string[], strategy: TreeSelectCheckedStrategy): string[];
34
+ /** What a search leaves of a tree. */
35
+ export interface TreeSearch {
36
+ /** The values of the nodes it hides. */
37
+ hidden: Set<string>;
38
+ /** The values of the nodes with a match under them, which open. */
39
+ open: string[];
40
+ /** Whether anything matched. */
41
+ found: boolean;
42
+ }
43
+ /**
44
+ * What a search shows of a tree: the nodes that match, the nodes above them,
45
+ * so the results stay a tree, and the nodes under them, so a matching branch
46
+ * can still be opened.
47
+ */
48
+ export declare function searchTree(data: TreeItemData[], matches: (node: TreeItemData, path: TreeItemData[]) => boolean): TreeSearch;
@@ -0,0 +1,34 @@
1
+ /** `useBulmaViewport`'s answer below the tablet breakpoint. */
2
+ export declare const MOBILE: number;
3
+ /** Where Bulma's `widescreen`, `desktop` and `tablet` sit in `VIEWPORT_QUERIES`. */
4
+ declare const VIEWPORT_INDEX: {
5
+ readonly widescreen: 1;
6
+ readonly desktop: 2;
7
+ readonly tablet: 3;
8
+ };
9
+ /**
10
+ * Which of Bulma's viewports the window is in: the index of the widest
11
+ * `VIEWPORT_QUERIES` entry that matches, `MOBILE` below them all, or `-1`
12
+ * when that isn't known (on the server, before the first layout effect, and
13
+ * whenever `enabled` is off, so a caller that needs no answer subscribes to
14
+ * nothing). It's read in a layout effect, so the first paint after hydration
15
+ * already has it.
16
+ *
17
+ * @function useBulmaViewport
18
+ * @param enabled - Whether the caller needs the viewport at all.
19
+ * @returns The viewport, as described above.
20
+ */
21
+ export declare function useBulmaViewport(enabled: boolean): number;
22
+ /**
23
+ * Whether the window is at or past one of Bulma's breakpoints, at its default
24
+ * width, through the one media query Bulma's mixin for it opens with, so a
25
+ * caller re-renders only when the window crosses that breakpoint. `null`
26
+ * until it's known: on the server, and before the first layout effect. Where
27
+ * `matchMedia` isn't there, it's `true`, the wide layout a server renders.
28
+ *
29
+ * @function useBulmaBreakpoint
30
+ * @param breakpoint - The breakpoint: `tablet`, `desktop` or `widescreen`.
31
+ * @returns Whether the window is at or past it, or `null`.
32
+ */
33
+ export declare function useBulmaBreakpoint(breakpoint: keyof typeof VIEWPORT_INDEX): boolean | null;
34
+ export {};
@@ -0,0 +1,14 @@
1
+ /**
2
+ * A value the caller holds, or one this hook holds when the caller doesn't:
3
+ * the `x` / `defaultX` pair of a component's props. The caller holds it
4
+ * whenever `controlled` isn't `undefined`, so `null` is a held value. The
5
+ * setter changes only the value held here, so a held one changes when the
6
+ * caller passes the new value, and it reports nothing: the component calls
7
+ * its own `onXChange`.
8
+ *
9
+ * @function useControlled
10
+ * @param controlled - The caller's value, or `undefined` to hold one here.
11
+ * @param initial - The value held here to begin with.
12
+ * @returns The current value, and the setter for the one held here.
13
+ */
14
+ export declare function useControlled<T>(controlled: T | undefined, initial: T): readonly [T, (next: T) => void];
@@ -26,5 +26,8 @@ import type { RefObject } from 'react';
26
26
  * @param active - Whether what's beside it is inert.
27
27
  * @param wholePage - Whether that goes for the whole page rather than only
28
28
  * the element's siblings.
29
+ * @param except - Ref to an element beside it to leave reachable too, such
30
+ * as the overlay's own backdrop, which has to take the presses that close
31
+ * it rather than let them through to what's under it.
29
32
  */
30
- export declare function useInertSiblings(ref: RefObject<Element | null>, active: boolean, wholePage: boolean): void;
33
+ export declare function useInertSiblings(ref: RefObject<Element | null>, active: boolean, wholePage: boolean, except?: RefObject<Element | null>): void;
@@ -0,0 +1,24 @@
1
+ import type React from 'react';
2
+ import type { RefObject } from 'react';
3
+ /**
4
+ * Calls `onOutsidePress` for a `pointerdown` outside `ref`'s element while
5
+ * `active`, as a Popover closes on one.
6
+ *
7
+ * A press counts as inside in two ways: on the element's own path in the DOM,
8
+ * and anywhere in a React tree the returned handler is put on, as
9
+ * `onPointerDownCapture`. React's tree includes content portaled out of it,
10
+ * which the DOM path doesn't, and React has seen a press there by the time
11
+ * the document hears it.
12
+ *
13
+ * The listener is on the element's own document, an iframe's when the tree
14
+ * renders into one, and reads the latest `onOutsidePress` as a press
15
+ * arrives, so it stays put while the callback changes identity.
16
+ *
17
+ * @function useOutsidePress
18
+ * @param ref - Ref to the element a press inside of doesn't count.
19
+ * @param active - Whether to listen.
20
+ * @param onOutsidePress - Called with each press outside.
21
+ * @returns The `onPointerDownCapture` handler that marks a press in its tree
22
+ * as inside.
23
+ */
24
+ export declare function useOutsidePress(ref: RefObject<Element | null>, active: boolean, onOutsidePress: (event: PointerEvent) => void): (event: React.PointerEvent) => void;
@@ -0,0 +1,44 @@
1
+ import type { RefObject } from 'react';
2
+ /** Options for `useOverlayFocus`. */
3
+ export interface OverlayFocusOptions {
4
+ /**
5
+ * Whether the overlay is modal. One that isn't, opened while a modal
6
+ * overlay is open under it, leaves focus where it is: that overlay keeps
7
+ * Tab, so a Tab from this one's controls would only go back to it. It's
8
+ * read as the overlay opens, so a change while it's open moves nothing.
9
+ */
10
+ modal: boolean;
11
+ /**
12
+ * A value that remounts the overlay's nodes while it's open when it
13
+ * changes, such as a new portal target. Focus is handed back from the old
14
+ * nodes and moved into the new ones.
15
+ */
16
+ remountKey?: unknown;
17
+ /**
18
+ * Asked as the overlay closes, while it still holds focus: `false` leaves
19
+ * focus where it is, for a close that shouldn't send it back, such as one
20
+ * whose overlay stays on the page as something else.
21
+ */
22
+ restore?: () => boolean;
23
+ }
24
+ /**
25
+ * Moves focus into an overlay as it opens, to the first stop Tab wraps to
26
+ * inside `ref`'s element or the element itself, and hands it back to
27
+ * whatever had it as it closes, as `Modal` does. Focus goes back only while
28
+ * the overlay still holds it, or it's been dropped to `<body>`: closing one
29
+ * under another overlay mustn't pull focus out of the one on top, and focus
30
+ * moved out to the page stays there. The opener is found wherever it sits,
31
+ * inside a shadow root too, in the overlay's own document, an iframe's when
32
+ * it renders into one. It's read in a layout effect as the overlay opens, so
33
+ * before the commit's passive effects, such as one that makes the page
34
+ * inert. Content inside the overlay with a layout effect of its own, or an
35
+ * `autoFocus`, can still move focus first, and then there's no opener to go
36
+ * back to: focus is never handed back into the overlay that's closing.
37
+ *
38
+ * @function useOverlayFocus
39
+ * @param ref - Ref to the overlay's element.
40
+ * @param open - Whether the overlay is open.
41
+ * @param options - Whether it's modal, what remounts it, and whether a
42
+ * close hands focus back.
43
+ */
44
+ export declare function useOverlayFocus(ref: RefObject<HTMLElement | null>, open: boolean, { modal, remountKey, restore }: OverlayFocusOptions): void;