haze-ui 1.12.1 → 1.13.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 (137) hide show
  1. package/README.md +99 -31
  2. package/dist/components/Checkbox/Checkbox.js +13 -20
  3. package/dist/components/Checkbox/CheckboxCore.js +23 -0
  4. package/dist/components/ColorPicker/ColorPicker.js +13 -42
  5. package/dist/components/ColorPicker/ColorPickerCore.js +38 -0
  6. package/dist/components/Combobox/Combobox.js +45 -34
  7. package/dist/components/Command/Command.js +72 -37
  8. package/dist/components/ContextMenu/ContextMenu.js +19 -17
  9. package/dist/components/ContextMenu/ContextMenuContent.js +24 -12
  10. package/dist/components/ContextMenu/ContextMenuItem.js +2 -0
  11. package/dist/components/DateRangePicker/DateRangePicker.js +17 -35
  12. package/dist/components/DateRangePicker/DateRangePickerCore.js +33 -0
  13. package/dist/components/Datepicker/Calendar.js +58 -44
  14. package/dist/components/Datepicker/Datepicker.js +15 -39
  15. package/dist/components/Datepicker/DatepickerCore.js +50 -0
  16. package/dist/components/DropdownMenu/DropdownMenu.js +20 -20
  17. package/dist/components/DropdownMenu/DropdownMenuContent.js +38 -45
  18. package/dist/components/DropdownMenu/DropdownMenuTrigger.js +9 -7
  19. package/dist/components/InlineEdit/InlineEdit.js +1 -0
  20. package/dist/components/Input/Input.js +11 -22
  21. package/dist/components/Input/InputCore.js +26 -0
  22. package/dist/components/Menu/Menu.js +38 -26
  23. package/dist/components/Menu/MenuItem.js +1 -0
  24. package/dist/components/ModelPicker/ModelPicker.js +1 -0
  25. package/dist/components/NumberInput/NumberInput.js +16 -53
  26. package/dist/components/NumberInput/NumberInputCore.js +56 -0
  27. package/dist/components/OTPInput/OTPInput.js +11 -45
  28. package/dist/components/OTPInput/OTPInputCore.js +44 -0
  29. package/dist/components/PasswordInput/PasswordInput.js +14 -29
  30. package/dist/components/PasswordInput/PasswordInputCore.js +31 -0
  31. package/dist/components/Popover/Popover.js +32 -75
  32. package/dist/components/Progress/Progress.js +2 -0
  33. package/dist/components/Radio/RadioGroup.js +12 -21
  34. package/dist/components/Radio/RadioGroupCore.js +24 -0
  35. package/dist/components/Rating/Rating.js +14 -46
  36. package/dist/components/Rating/RatingCore.js +48 -0
  37. package/dist/components/Segmented/Segmented.js +12 -37
  38. package/dist/components/Segmented/SegmentedCore.js +39 -0
  39. package/dist/components/Select/Select.js +12 -23
  40. package/dist/components/Select/SelectCore.js +27 -0
  41. package/dist/components/Slider/Slider.js +10 -15
  42. package/dist/components/Slider/SliderCore.js +19 -0
  43. package/dist/components/Switch/Switch.js +11 -38
  44. package/dist/components/Switch/SwitchCore.js +42 -0
  45. package/dist/components/TagInput/TagInput.js +18 -72
  46. package/dist/components/TagInput/TagInputCore.js +68 -0
  47. package/dist/components/Textarea/Textarea.js +11 -22
  48. package/dist/components/Textarea/TextareaCore.js +26 -0
  49. package/dist/components/TimePicker/TimePicker.js +10 -15
  50. package/dist/components/TimePicker/TimePickerCore.js +18 -0
  51. package/dist/components/Tooltip/Tooltip.js +50 -24
  52. package/dist/components/Tree/TreeItem.js +44 -41
  53. package/dist/components/Upload/Upload.js +1 -0
  54. package/dist/css/checkbox.css +1 -1
  55. package/dist/css/color-picker.css +1 -1
  56. package/dist/css/combobox.css +2 -1
  57. package/dist/css/command.css +1 -1
  58. package/dist/css/context-menu.css +1 -0
  59. package/dist/css/date-range-picker.css +1 -1
  60. package/dist/css/datepicker.css +3 -2
  61. package/dist/css/dropdown-menu.css +2 -1
  62. package/dist/css/input.css +1 -1
  63. package/dist/css/menu.css +2 -1
  64. package/dist/css/number-input.css +1 -1
  65. package/dist/css/otp-input.css +1 -1
  66. package/dist/css/password-input.css +1 -1
  67. package/dist/css/popover.css +2 -1
  68. package/dist/css/radio.css +1 -1
  69. package/dist/css/rating.css +1 -1
  70. package/dist/css/segmented.css +1 -1
  71. package/dist/css/select.css +1 -1
  72. package/dist/css/slider.css +1 -1
  73. package/dist/css/switch.css +1 -1
  74. package/dist/css/tag-input.css +1 -1
  75. package/dist/css/textarea.css +1 -1
  76. package/dist/css/time-picker.css +1 -1
  77. package/dist/css/tooltip.css +2 -1
  78. package/dist/form/FormItem.js +41 -33
  79. package/dist/haze-ui.css +31 -24
  80. package/dist/index.js +138 -122
  81. package/dist/types/components/Checkbox/CheckboxCore.d.ts +12 -0
  82. package/dist/types/components/Checkbox/index.d.ts +2 -0
  83. package/dist/types/components/ColorPicker/ColorPickerCore.d.ts +8 -0
  84. package/dist/types/components/ColorPicker/index.d.ts +2 -0
  85. package/dist/types/components/ContextMenu/ContextMenuContent.d.ts +1 -1
  86. package/dist/types/components/ContextMenu/ContextMenuContext.d.ts +5 -1
  87. package/dist/types/components/DateRangePicker/DateRangePickerCore.d.ts +11 -0
  88. package/dist/types/components/DateRangePicker/index.d.ts +2 -0
  89. package/dist/types/components/Datepicker/DatepickerCore.d.ts +12 -0
  90. package/dist/types/components/Datepicker/index.d.ts +2 -0
  91. package/dist/types/components/DropdownMenu/DropdownMenuContent.d.ts +1 -1
  92. package/dist/types/components/DropdownMenu/DropdownMenuContext.d.ts +3 -0
  93. package/dist/types/components/DropdownMenu/DropdownMenuTrigger.d.ts +1 -1
  94. package/dist/types/components/Input/InputCore.d.ts +13 -0
  95. package/dist/types/components/Input/index.d.ts +2 -0
  96. package/dist/types/components/NumberInput/NumberInputCore.d.ts +15 -0
  97. package/dist/types/components/NumberInput/index.d.ts +2 -0
  98. package/dist/types/components/OTPInput/OTPInputCore.d.ts +8 -0
  99. package/dist/types/components/OTPInput/index.d.ts +2 -0
  100. package/dist/types/components/PasswordInput/PasswordInputCore.d.ts +9 -0
  101. package/dist/types/components/PasswordInput/index.d.ts +2 -0
  102. package/dist/types/components/Radio/RadioContext.d.ts +1 -2
  103. package/dist/types/components/Radio/RadioGroupCore.d.ts +10 -0
  104. package/dist/types/components/Radio/index.d.ts +2 -0
  105. package/dist/types/components/Rating/RatingCore.d.ts +9 -0
  106. package/dist/types/components/Rating/index.d.ts +2 -0
  107. package/dist/types/components/Segmented/Segmented.d.ts +1 -6
  108. package/dist/types/components/Segmented/SegmentedCore.d.ts +15 -0
  109. package/dist/types/components/Segmented/index.d.ts +2 -0
  110. package/dist/types/components/Select/SelectCore.d.ts +13 -0
  111. package/dist/types/components/Select/index.d.ts +2 -0
  112. package/dist/types/components/Slider/SliderCore.d.ts +11 -0
  113. package/dist/types/components/Slider/index.d.ts +2 -0
  114. package/dist/types/components/Switch/Switch.d.ts +1 -1
  115. package/dist/types/components/Switch/SwitchCore.d.ts +12 -0
  116. package/dist/types/components/Switch/index.d.ts +2 -0
  117. package/dist/types/components/TagInput/TagInputCore.d.ts +20 -0
  118. package/dist/types/components/TagInput/index.d.ts +2 -0
  119. package/dist/types/components/Textarea/TextareaCore.d.ts +12 -0
  120. package/dist/types/components/Textarea/index.d.ts +2 -0
  121. package/dist/types/components/TimePicker/TimePickerCore.d.ts +9 -0
  122. package/dist/types/components/TimePicker/index.d.ts +2 -0
  123. package/dist/types/components/Tooltip/Tooltip.d.ts +5 -1
  124. package/dist/types/form/FormItem.d.ts +86 -19
  125. package/dist/types/form/index.d.ts +2 -3
  126. package/dist/types/index.d.ts +36 -36
  127. package/dist/types/utils/floating.d.ts +99 -0
  128. package/dist/types/utils/menuKeyboard.d.ts +43 -0
  129. package/dist/utils/floating.js +181 -0
  130. package/dist/utils/menuKeyboard.js +88 -0
  131. package/package.json +45 -19
  132. package/dist/components/DropdownMenu/useMenuKeyboard.js +0 -52
  133. package/dist/form/useFormControl.js +0 -54
  134. package/dist/types/components/DropdownMenu/useMenuKeyboard.d.ts +0 -19
  135. package/dist/types/form/useFormControl.d.ts +0 -35
  136. package/dist/types/hooks/index.d.ts +0 -1
  137. package/dist/types/utils/index.d.ts +0 -1
package/README.md CHANGED
@@ -51,41 +51,45 @@ always come from `haze-ui/css/tokens.css`.
51
51
 
52
52
  ## react-f0rm Integration
53
53
 
54
- The form layer (`FormItem`, `useFormControl`; peer dependency
55
- `react-f0rm`) is exported from the main barrel and glues react-f0rm
56
- form state to haze-ui's control-prop system, so any control-prop
57
- component (`Input`, `Select`, `Switch`, `Textarea`, `TagInput`, ...)
58
- binds to a form field with zero adapters.
54
+ react-f0rm owns form field state, and its headless `useField` hook is
55
+ the single binding layer the same channel its built-in
56
+ `Field`/`Checkbox`/`Select` components use. haze-ui contributes the
57
+ views: controlled cores (`InputCore`, `SelectCore`, `SwitchCore`,
58
+ `TextareaCore`, `TagInputCore`, ...) take the plain `{value, onChange}`
59
+ pair with zero adapters, and `FormItem` wraps the hook's state in label,
60
+ error and aria wiring. The sugar components (`Input`, `Select`, ...)
61
+ keep their `Control<T> | T` API for standalone use outside forms.
59
62
 
60
- ### useFormControl(form, name): field → Control
63
+ ### useField: field → {value, onChange}
61
64
 
62
65
  ```jsx
63
- import { useForm, setValue } from 'react-f0rm';
64
- import { Input, useFormControl } from 'haze-ui';
66
+ import { useForm, useField } from 'react-f0rm';
67
+ import { InputCore } from 'haze-ui';
65
68
 
66
69
  function NameField({ form }) {
67
- const name = useFormControl(form, 'name');
68
- return <Input value={name} />; // two-way bound, no onChange wiring
70
+ const { value, onChange } = useField({ form, name: 'name' });
71
+ return <InputCore value={value} onChange={onChange} />; // two-way bound
69
72
  }
70
73
  ```
71
74
 
72
- The handle is a real `Control`: reads subscribe to the field (sibling
73
- fields stay isolated), and writes go through react-f0rm's user-change
74
- channel (`changeValueByPath`, 0.7) a control write fires exactly the
75
- validation a user typing into the field would fire: the field's effective
76
- `mode` (a `FormItem`/`useField` per-field override included) and the
77
- form's `reValidateMode`. With the default `mode: 'onSubmit'` +
78
- `reValidateMode: 'onChange'`, typing through a bridged control after a
79
- failed submit re-validates per keystroke and clears the error as soon as
80
- the value is valid no blur, no resubmit. Functional updates evaluate
81
- against the live form value. `reset(form, newValues)` re-seeds every
82
- bridged control with no remounting.
75
+ The hook subscribes to the field (sibling fields stay isolated), and
76
+ `onChange` writes through react-f0rm's user-change channel — a write
77
+ fires exactly the validation a user typing into the field would fire:
78
+ the field's effective `mode` (a `FormItem`/`useField` per-field override
79
+ included) and the form's `reValidateMode`. With the default
80
+ `mode: 'onSubmit'` + `reValidateMode: 'onChange'`, typing through a bound
81
+ core after a failed submit re-validates per keystroke and clears the
82
+ error as soon as the value is valid no blur, no resubmit. `onChange`
83
+ accepts plain values only (controlled cores emit the next value, never
84
+ functional updaters; read the previous value from `value` on the next
85
+ render). `reset(form, newValues)` re-seeds every binding with no
86
+ remounting.
83
87
 
84
88
  ### FormItem: label, errors and aria wiring
85
89
 
86
90
  ```jsx
87
91
  import { Form, useForm } from 'react-f0rm';
88
- import { FormItem, Input } from 'haze-ui';
92
+ import { FormItem, InputCore } from 'haze-ui';
89
93
 
90
94
  function ProfileForm() {
91
95
  const form = useForm({ initialValues: { email: '' } });
@@ -97,8 +101,8 @@ function ProfileForm() {
97
101
  label="Email"
98
102
  validate={(v) => (v.includes('@') ? undefined : 'must be an email')}
99
103
  >
100
- {({ id, errorId, invalid, control }) => (
101
- <Input id={id} value={control} aria-invalid={invalid} aria-describedby={errorId} />
104
+ {({ id, errorId, invalid, value, onChange }) => (
105
+ <InputCore id={id} value={value} onChange={onChange} aria-invalid={invalid} aria-describedby={errorId} />
102
106
  )}
103
107
  </FormItem>
104
108
  </Form>
@@ -110,6 +114,46 @@ function ProfileForm() {
110
114
  surfaces the first error in a `role="alert"` element — no manual
111
115
  `FieldError` wiring.
112
116
 
117
+ #### `as`: declarative binding (react-f0rm Field-style)
118
+
119
+ Skip the render-prop: pass any component as `as` and `FormItem` wires the
120
+ id, aria attributes, `onBlur` and `onChange` itself — the same props shape
121
+ as react-f0rm's `Field`, not Radix's `asChild`. `as` and the children
122
+ render-prop are mutually exclusive.
123
+
124
+ ```jsx
125
+ // text field: nothing else to wire
126
+ <FormItem form={form} name="email" label="Email" as={InputCore} />
127
+
128
+ // checkbox-style control: value lives in `checked`
129
+ <FormItem
130
+ form={form}
131
+ name="subscribed"
132
+ label="Subscribe"
133
+ as={CheckboxCore}
134
+ valueToProps={(checked) => ({ checked: !!checked })}
135
+ />
136
+
137
+ // DOM-element-shaped control: adapt event and value in one line each
138
+ <FormItem
139
+ form={form}
140
+ name="email"
141
+ as={NativeInput}
142
+ eventToValue={(e) => e.target.value}
143
+ renderError={(error, id) => <em id={id}>{error}</em>}
144
+ />
145
+ ```
146
+
147
+ - `eventToValue` defaults to identity — haze cores' `onChange` emits the
148
+ next plain value; pass `(e) => e.target.value` when `as` is a raw DOM
149
+ element component.
150
+ - `asProps` spreads extra props onto the control before the value props,
151
+ so `value`/`valueToProps` win conflicts (Field.tsx precedence).
152
+ - `renderError(error, id)` replaces the built-in error span's content;
153
+ the span itself (`id`, `role="alert"`, styling) stays FormItem's.
154
+ - With a typed form, `validate`'s value argument is the field's actual
155
+ type (`PathValueOf<TValues, P>`), not `any`.
156
+
113
157
  #### `mode`: per-field validation timing (react-f0rm ≥ 0.6)
114
158
 
115
159
  Pass `mode` to validate one field on its own schedule instead of the
@@ -126,10 +170,11 @@ keep the form's mode.
126
170
  mode="onBlur"
127
171
  validate={(v) => (v.includes('@') ? undefined : 'must be an email')}
128
172
  >
129
- {({ id, errorId, invalid, onBlur, control }) => (
130
- <Input
173
+ {({ id, errorId, invalid, onBlur, value, onChange }) => (
174
+ <InputCore
131
175
  id={id}
132
- value={control}
176
+ value={value}
177
+ onChange={onChange}
133
178
  aria-invalid={invalid}
134
179
  aria-describedby={errorId}
135
180
  onBlur={onBlur}
@@ -138,8 +183,8 @@ keep the form's mode.
138
183
  </FormItem>
139
184
  ```
140
185
 
141
- With `mode="onBlur"` (and the binding's `onBlur` passed to the control,
142
- as above) the email field is validated the moment it loses focus — no
186
+ With `mode="onBlur"` (and the binding's `onBlur` passed to the core, as
187
+ above) the email field is validated the moment it loses focus — no
143
188
  submit needed. `mode` accepts `'onSubmit'`, `'onBlur'`, `'onChange'`,
144
189
  `'onTouched'` or `'all'`; only this field's schedule changes, the rest
145
190
  of the form keeps its own `mode`.
@@ -173,8 +218,8 @@ react-f0rm's `useField`:
173
218
  rules={{ required: 'Email is required' }}
174
219
  validate={(v) => (v.includes('@') ? undefined : 'must be an email')}
175
220
  >
176
- {({ id, errorId, invalid, control }) => (
177
- <Input id={id} value={control} aria-invalid={invalid} aria-describedby={errorId} />
221
+ {({ id, errorId, invalid, value, onChange }) => (
222
+ <InputCore id={id} value={value} onChange={onChange} aria-invalid={invalid} aria-describedby={errorId} />
178
223
  )}
179
224
  </FormItem>
180
225
  ```
@@ -194,3 +239,26 @@ Anyone and everyone is welcome to contribute.
194
239
  ## License
195
240
 
196
241
  [MIT](https://choosealicense.com/licenses/mit/)
242
+
243
+ ## FAQ
244
+
245
+ ### Components render without any styles
246
+
247
+ haze-ui ships styles as separate CSS subpaths — the JS entry does not
248
+ import any stylesheet. Import the full bundle once:
249
+
250
+ ```js
251
+ import 'haze-ui/styles.css';
252
+ ```
253
+
254
+ or import the tokens plus each component's own rules:
255
+
256
+ ```js
257
+ import 'haze-ui/css/tokens.css';
258
+ import 'haze-ui/css/button.css';
259
+ ```
260
+
261
+ ### Is there a CommonJS build?
262
+
263
+ No — haze-ui is ESM-only (`"type": "module"`). Use a bundler or runtime
264
+ with ESM support (Vite, webpack 5, Next.js, Node ≥ 18, …).
@@ -1,24 +1,17 @@
1
-
2
- import { classnames as e } from "../../utils/classnames.js";
3
- /* empty css */
4
- import { jsx as t, jsxs as n } from "react/jsx-runtime";
5
- import { useControl as r } from "react-use-control";
1
+ import e from "./CheckboxCore.js";
2
+ import { jsx as t } from "react/jsx-runtime";
3
+ import { useControl as n } from "react-use-control";
6
4
  //#region src/lib/components/Checkbox/Checkbox.tsx
7
- var i = "haze-Checkbox__base", a = "haze-Checkbox__labelText";
8
- function o({ checked: o, className: s, label: c, onChange: l, ...u }) {
9
- let [d, f] = r(o, !1), p = /* @__PURE__ */ t("input", {
10
- type: "checkbox",
11
- checked: d,
12
- onChange: (e) => {
13
- f(e.target.checked), l?.(e);
14
- },
15
- ...u,
16
- className: e([i, s])
17
- });
18
- return c === void 0 ? p : /* @__PURE__ */ n("label", {
19
- className: e(a),
20
- children: [p, c]
5
+ function r({ checked: r, className: i, label: a, onChange: o, ...s }) {
6
+ let [c, l] = n(r, !1);
7
+ return /* @__PURE__ */ t(e, {
8
+ checked: c,
9
+ onChange: l,
10
+ onNativeChange: o,
11
+ className: i,
12
+ label: a,
13
+ ...s
21
14
  });
22
15
  }
23
16
  //#endregion
24
- export { o as default };
17
+ export { r as default };
@@ -0,0 +1,23 @@
1
+
2
+ import { classnames as e } from "../../utils/classnames.js";
3
+ /* empty css */
4
+ import { jsx as t, jsxs as n } from "react/jsx-runtime";
5
+ //#region src/lib/components/Checkbox/CheckboxCore.tsx
6
+ var r = "haze-CheckboxCore__base", i = "haze-CheckboxCore__labelText";
7
+ function a({ checked: a, onChange: o, onNativeChange: s, className: c, label: l, ...u }) {
8
+ let d = /* @__PURE__ */ t("input", {
9
+ type: "checkbox",
10
+ checked: a,
11
+ onChange: (e) => {
12
+ o(e.target.checked), s?.(e);
13
+ },
14
+ ...u,
15
+ className: e([r, c])
16
+ });
17
+ return l === void 0 ? d : /* @__PURE__ */ n("label", {
18
+ className: e(i),
19
+ children: [d, l]
20
+ });
21
+ }
22
+ //#endregion
23
+ export { a as default };
@@ -1,46 +1,17 @@
1
-
2
- import { classnames as e } from "../../utils/classnames.js";
3
- /* empty css */
4
- import { jsx as t, jsxs as n } from "react/jsx-runtime";
5
- import { useControl as r } from "react-use-control";
1
+ import e from "./ColorPickerCore.js";
2
+ import { jsx as t } from "react/jsx-runtime";
3
+ import { useControl as n } from "react-use-control";
6
4
  //#region src/lib/components/ColorPicker/ColorPicker.tsx
7
- var i = "haze-ColorPicker__container", a = "haze-ColorPicker__previewRow", o = "haze-ColorPicker__colorInput", s = "haze-ColorPicker__textInput", c = "haze-ColorPicker__presetsRow", l = "haze-ColorPicker__presetBtn", u = "haze-ColorPicker__activePreset";
8
- function d({ value: d, presets: f, onChange: p, className: m }) {
9
- let [h, g] = r(d, "#000000"), _ = (e) => {
10
- let t = e.target.value;
11
- g(t), p?.(t);
12
- }, v = (e) => {
13
- let t = e.target.value;
14
- g(t), p?.(t);
15
- }, y = (e) => {
16
- g(e), p?.(e);
17
- };
18
- return /* @__PURE__ */ n("div", {
19
- className: e([i, m]),
20
- children: [/* @__PURE__ */ n("div", {
21
- className: e([a]),
22
- children: [/* @__PURE__ */ t("input", {
23
- type: "color",
24
- value: h,
25
- onChange: v,
26
- className: e([o])
27
- }), /* @__PURE__ */ t("input", {
28
- type: "text",
29
- value: h,
30
- onChange: _,
31
- className: e([s])
32
- })]
33
- }), f && f.length > 0 && /* @__PURE__ */ t("div", {
34
- className: e([c]),
35
- children: f.map((n) => /* @__PURE__ */ t("button", {
36
- type: "button",
37
- style: { background: n },
38
- "aria-label": n,
39
- onClick: () => y(n),
40
- className: e([l, h === n && u])
41
- }, n))
42
- })]
5
+ function r({ value: r, presets: i, onChange: a, className: o }) {
6
+ let [s, c] = n(r, "#000000");
7
+ return /* @__PURE__ */ t(e, {
8
+ value: s,
9
+ onChange: (e) => {
10
+ c(e), a?.(e);
11
+ },
12
+ presets: i,
13
+ className: o
43
14
  });
44
15
  }
45
16
  //#endregion
46
- export { d as default };
17
+ export { r as default };
@@ -0,0 +1,38 @@
1
+
2
+ import { classnames as e } from "../../utils/classnames.js";
3
+ /* empty css */
4
+ import { jsx as t, jsxs as n } from "react/jsx-runtime";
5
+ //#region src/lib/components/ColorPicker/ColorPickerCore.tsx
6
+ var r = "haze-ColorPickerCore__container", i = "haze-ColorPickerCore__previewRow", a = "haze-ColorPickerCore__colorInput", o = "haze-ColorPickerCore__textInput", s = "haze-ColorPickerCore__presetsRow", c = "haze-ColorPickerCore__presetBtn", l = "haze-ColorPickerCore__activePreset";
7
+ function u({ value: u, onChange: d, presets: f, className: p }) {
8
+ return /* @__PURE__ */ n("div", {
9
+ className: e([r, p]),
10
+ children: [/* @__PURE__ */ n("div", {
11
+ className: e([i]),
12
+ children: [/* @__PURE__ */ t("input", {
13
+ type: "color",
14
+ value: u,
15
+ "aria-label": "Pick color",
16
+ onChange: (e) => d(e.target.value),
17
+ className: e([a])
18
+ }), /* @__PURE__ */ t("input", {
19
+ type: "text",
20
+ value: u,
21
+ "aria-label": "Hex color",
22
+ onChange: (e) => d(e.target.value),
23
+ className: e([o])
24
+ })]
25
+ }), f && f.length > 0 && /* @__PURE__ */ t("div", {
26
+ className: e([s]),
27
+ children: f.map((n) => /* @__PURE__ */ t("button", {
28
+ type: "button",
29
+ style: { background: n },
30
+ "aria-label": n,
31
+ onClick: () => d(n),
32
+ className: e([c, u === n && l])
33
+ }, n))
34
+ })]
35
+ });
36
+ }
37
+ //#endregion
38
+ export { u as default };
@@ -1,53 +1,64 @@
1
1
 
2
2
  import { classnames as e } from "../../utils/classnames.js";
3
- import t from "./ComboboxOption.js";
3
+ import { FloatingPanel as t, useFloating as n } from "../../utils/floating.js";
4
+ import r from "./ComboboxOption.js";
4
5
  /* empty css */
5
- import { jsx as n, jsxs as r } from "react/jsx-runtime";
6
- import { useControl as i } from "react-use-control";
7
- import { useEffect as a, useId as o, useRef as s, useState as c } from "react";
6
+ import { jsx as i, jsxs as a } from "react/jsx-runtime";
7
+ import { useControl as o } from "react-use-control";
8
+ import { useEffect as s, useId as c, useRef as l, useState as u } from "react";
8
9
  //#region src/lib/components/Combobox/Combobox.tsx
9
- var l = "haze-Combobox__wrapper", u = "haze-Combobox__input", d = "haze-Combobox__listbox", f = "haze-Combobox__hidden";
10
- function p({ value: p, open: m, options: h, placeholder: g, className: _ }) {
11
- let [v, y] = i(p, ""), [b, x] = c(""), [S, C] = i(m, !1), [w, T] = c(-1), E = o(), D = s(null), O = h.filter((e) => e.label.toLowerCase().includes(b.toLowerCase()));
12
- a(() => {
13
- T(-1);
14
- }, [b]);
15
- let k = (e) => {
16
- y(e);
17
- let t = h.find((t) => t.value === e)?.label ?? e;
18
- x(t), C(!1), D.current?.focus();
10
+ var d = "haze-Combobox__wrapper", f = "haze-Combobox__input", p = "haze-Combobox__listbox";
11
+ function m({ value: m, open: h, options: g, placeholder: _, className: v }) {
12
+ let [y, b] = o(m, ""), [x, S] = u(""), [C, w] = o(h, !1), [T, E] = u(-1), D = c(), O = l(null), k = l(null), A = n({
13
+ open: C,
14
+ setOpen: w,
15
+ triggerRef: O,
16
+ panelRef: k
17
+ }), j = g.filter((e) => e.label.toLowerCase().includes(x.toLowerCase()));
18
+ s(() => {
19
+ E(-1);
20
+ }, [x]);
21
+ let M = (e) => {
22
+ b(e);
23
+ let t = g.find((t) => t.value === e)?.label ?? e;
24
+ S(t), w(!1), O.current?.focus();
19
25
  };
20
- return /* @__PURE__ */ r("div", {
21
- className: e([l, _]),
22
- children: [/* @__PURE__ */ n("input", {
23
- ref: D,
26
+ return /* @__PURE__ */ a("div", {
27
+ className: e([d, v]),
28
+ children: [/* @__PURE__ */ i("input", {
29
+ ref: O,
24
30
  role: "combobox",
25
- "aria-expanded": S,
26
- "aria-controls": E,
31
+ style: A.triggerStyle,
32
+ "aria-expanded": C,
33
+ "aria-controls": D,
27
34
  "aria-autocomplete": "list",
28
- className: u,
29
- value: b,
30
- placeholder: g,
35
+ className: f,
36
+ value: x,
37
+ placeholder: _,
31
38
  onChange: (e) => {
32
- x(e.target.value), C(!0);
39
+ S(e.target.value), w(!0);
33
40
  },
34
- onFocus: () => C(!0),
41
+ onFocus: () => w(!0),
42
+ onClick: () => w(!0),
35
43
  onKeyDown: (e) => {
36
- e.key === "ArrowDown" ? (e.preventDefault(), T((e) => Math.min(e + 1, O.length - 1))) : e.key === "ArrowUp" ? (e.preventDefault(), T((e) => Math.max(e - 1, 0))) : e.key === "Enter" && w >= 0 && O[w] ? (e.preventDefault(), k(O[w].value)) : e.key === "Escape" && C(!1);
44
+ e.key === "ArrowDown" ? (e.preventDefault(), E((e) => Math.min(e + 1, j.length - 1))) : e.key === "ArrowUp" ? (e.preventDefault(), E((e) => Math.max(e - 1, 0))) : e.key === "Enter" && T >= 0 && j[T] ? (e.preventDefault(), M(j[T].value)) : e.key === "Escape" && w(!1);
37
45
  }
38
- }), /* @__PURE__ */ n("div", {
39
- id: E,
46
+ }), /* @__PURE__ */ i(t, {
47
+ ref: k,
48
+ behavior: A,
49
+ placement: "bottom-span",
50
+ id: D,
40
51
  role: "listbox",
41
- className: e([d, !S && f]),
42
- children: O.map((e, r) => /* @__PURE__ */ n(t, {
52
+ visualClass: p,
53
+ children: j.map((e, t) => /* @__PURE__ */ i(r, {
43
54
  value: e.value,
44
- highlighted: r === w,
45
- selected: e.value === v,
46
- onSelect: k,
55
+ highlighted: t === T,
56
+ selected: e.value === y,
57
+ onSelect: M,
47
58
  children: e.label
48
59
  }, e.value))
49
60
  })]
50
61
  });
51
62
  }
52
63
  //#endregion
53
- export { p as default };
64
+ export { m as default };
@@ -1,59 +1,94 @@
1
1
 
2
2
  import { classnames as e } from "../../utils/classnames.js";
3
+ import { getEnabledMenuItems as t, useMenuKeyboard as n, useRovingTabindex as r } from "../../utils/menuKeyboard.js";
3
4
  /* empty css */
4
- import { jsx as t } from "react/jsx-runtime";
5
- import { useControl as n } from "react-use-control";
6
- import { createContext as r, useContext as i, useMemo as a } from "react";
5
+ import { jsx as i } from "react/jsx-runtime";
6
+ import { useControl as a } from "react-use-control";
7
+ import { createContext as o, useContext as s, useId as c, useMemo as l, useRef as u } from "react";
7
8
  //#region src/lib/components/Command/Command.tsx
8
- var o = r(void 0);
9
- function s() {
10
- let e = i(o);
9
+ var d = "[role=\"option\"]", f = o(void 0);
10
+ function p() {
11
+ let e = s(f);
11
12
  if (!e) throw Error("Command sub-components must be used within <Command>");
12
13
  return e;
13
14
  }
14
- var c = "haze-Command__base";
15
- function l({ query: r, children: i, className: s }) {
16
- let [l, u] = n(r, ""), d = a(() => ({
17
- query: l,
18
- setQuery: u
19
- }), [l, u]);
20
- return /* @__PURE__ */ t(o.Provider, {
21
- value: d,
22
- children: t("div", {
15
+ var m = "haze-Command__base";
16
+ function h({ query: t, children: n, className: r }) {
17
+ let [o, s] = a(t, ""), d = u(null), p = u(null), h = c(), g = l(() => ({
18
+ query: o,
19
+ setQuery: s,
20
+ inputRef: d,
21
+ listRef: p,
22
+ listId: h
23
+ }), [
24
+ o,
25
+ s,
26
+ h
27
+ ]);
28
+ return /* @__PURE__ */ i(f.Provider, {
29
+ value: g,
30
+ children: i("div", {
23
31
  role: "combobox",
24
- className: e([c, s]),
25
- children: i
32
+ "aria-expanded": !0,
33
+ "aria-controls": h,
34
+ className: e([m, r]),
35
+ children: n
26
36
  })
27
37
  });
28
38
  }
29
- var u = "haze-Command__inputStyle";
30
- function d({ placeholder: n, className: r }) {
31
- let { query: i, setQuery: a } = s();
32
- return /* @__PURE__ */ t("input", {
39
+ var g = "haze-Command__inputStyle";
40
+ function _({ placeholder: n, className: r }) {
41
+ let { query: a, setQuery: o, inputRef: s, listRef: c } = p();
42
+ return /* @__PURE__ */ i("input", {
43
+ ref: s,
33
44
  type: "text",
34
45
  placeholder: n,
35
- value: i,
36
- onChange: (e) => a(e.target.value),
37
- className: e([u, r])
46
+ value: a,
47
+ onChange: (e) => o(e.target.value),
48
+ onKeyDown: (e) => {
49
+ if (e.key !== "ArrowDown" && e.key !== "ArrowUp") return;
50
+ e.preventDefault();
51
+ let n = t(c.current, d);
52
+ (e.key === "ArrowDown" ? n[0] : n[n.length - 1])?.focus();
53
+ },
54
+ className: e([g, r])
38
55
  });
39
56
  }
40
- var f = "haze-Command__listStyle";
41
- function p({ children: n, className: r }) {
42
- return /* @__PURE__ */ t("div", {
57
+ var v = "haze-Command__listStyle";
58
+ function y({ children: t, className: a }) {
59
+ let { inputRef: o, listRef: s, listId: c } = p();
60
+ r({
61
+ menuRef: s,
62
+ active: !0,
63
+ selector: d
64
+ });
65
+ let l = n({
66
+ menuRef: s,
67
+ selector: d,
68
+ onClose: () => o.current?.focus()
69
+ });
70
+ return /* @__PURE__ */ i("div", {
71
+ ref: s,
43
72
  role: "listbox",
44
- className: e([f, r]),
45
- children: n
73
+ id: c,
74
+ onKeyDown: l,
75
+ className: e([v, a]),
76
+ children: t
46
77
  });
47
78
  }
48
- var m = "haze-Command__itemStyle";
49
- function h({ children: n, className: r, onSelect: i }) {
50
- let { query: a } = s();
51
- return !a || (typeof n == "string" ? n : "").toLowerCase().includes(a.toLowerCase()) ? /* @__PURE__ */ t("div", {
79
+ var b = "haze-Command__itemStyle";
80
+ function x({ children: t, className: n, onSelect: r }) {
81
+ let { query: a } = p();
82
+ return !a || (typeof t == "string" ? t : "").toLowerCase().includes(a.toLowerCase()) ? /* @__PURE__ */ i("div", {
52
83
  role: "option",
53
- onClick: i,
54
- className: e([m, r]),
55
- children: n
84
+ tabIndex: -1,
85
+ onClick: r,
86
+ onKeyDown: (e) => {
87
+ (e.key === "Enter" || e.key === " ") && (e.preventDefault(), r?.());
88
+ },
89
+ className: e([b, n]),
90
+ children: t
56
91
  }) : null;
57
92
  }
58
93
  //#endregion
59
- export { d as CommandInput, h as CommandItem, p as CommandList, l as default };
94
+ export { _ as CommandInput, x as CommandItem, y as CommandList, h as default };
@@ -1,38 +1,40 @@
1
1
 
2
2
  import { classnames as e } from "../../utils/classnames.js";
3
- import { ContextMenuProvider as t } from "./ContextMenuContext.js";
3
+ import { useFloating as t } from "../../utils/floating.js";
4
+ import { ContextMenuProvider as n } from "./ContextMenuContext.js";
4
5
  /* empty css */
5
- import { jsx as n } from "react/jsx-runtime";
6
- import { useControl as r } from "react-use-control";
7
- import { useCallback as i, useEffect as a, useRef as o, useState as s } from "react";
6
+ import { jsx as r } from "react/jsx-runtime";
7
+ import { useControl as i } from "react-use-control";
8
+ import { useCallback as a, useRef as o, useState as s } from "react";
8
9
  //#region src/lib/components/ContextMenu/ContextMenu.tsx
9
10
  var c = "haze-ContextMenu__wrapper";
10
11
  function l({ open: l, onOpenChange: u, children: d, className: f }) {
11
- let [p, m] = r(l, !1), [h, g] = s(0), [_, v] = s(0), y = o(null), b = i((e) => {
12
+ let [p, m] = i(l, !1), [h, g] = s(0), [_, v] = s(0), y = o(null), b = o(null), x = a((e) => {
12
13
  let t = typeof e == "function" ? e(p) : e;
13
14
  m(t), u?.(t);
14
15
  }, [
15
16
  p,
16
17
  m,
17
18
  u
18
- ]), x = i((e, t) => {
19
+ ]), S = a((e, t) => {
19
20
  g(e), v(t);
20
- }, []);
21
- return a(() => {
22
- if (!p) return;
23
- let e = (e) => {
24
- y.current && !y.current.contains(e.target) && b(!1);
25
- };
26
- return document.addEventListener("mousedown", e), () => document.removeEventListener("mousedown", e);
27
- }, [p, b]), /* @__PURE__ */ n(t, {
21
+ }, []), C = t({
22
+ open: p,
23
+ setOpen: x,
24
+ triggerRef: y,
25
+ panelRef: b
26
+ });
27
+ return /* @__PURE__ */ r(n, {
28
28
  value: {
29
29
  open: p,
30
- setOpen: b,
30
+ setOpen: x,
31
31
  x: h,
32
32
  y: _,
33
- setPosition: x
33
+ setPosition: S,
34
+ contentRef: b,
35
+ floating: C
34
36
  },
35
- children: n("div", {
37
+ children: r("div", {
36
38
  ref: y,
37
39
  className: e([c, f]),
38
40
  children: d