@boxcustodia/library 2.0.0-alpha.19 → 2.0.0-alpha.20
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.
- package/dist/components/button/button.cjs.js +1 -1
- package/dist/components/button/button.es.js +19 -18
- package/dist/components/button/components/base-button.cjs.js +1 -1
- package/dist/components/button/components/base-button.es.js +20 -20
- package/dist/components/calendar/calendar.cjs.js +1 -1
- package/dist/components/calendar/calendar.es.js +1 -0
- package/dist/components/date-picker/date-input.cjs.js +1 -1
- package/dist/components/date-picker/date-input.es.js +92 -75
- package/dist/components/date-picker/date-picker.cjs.js +1 -1
- package/dist/components/date-picker/date-picker.es.js +104 -95
- package/dist/components/date-picker/date-picker.utils.cjs.js +1 -1
- package/dist/components/date-picker/date-picker.utils.es.js +51 -43
- package/dist/components/date-picker/use-hidden-field-value.cjs.js +1 -0
- package/dist/components/date-picker/use-hidden-field-value.es.js +11 -0
- package/dist/components/menu/menu.es.js +1 -9
- package/dist/components/otp/otp.cjs.js +2 -0
- package/dist/components/otp/otp.es.js +93 -0
- package/dist/components/password/password.cjs.js +1 -1
- package/dist/components/password/password.es.js +2 -2
- package/dist/components/select/select.cjs.js +1 -1
- package/dist/components/select/select.es.js +68 -60
- package/dist/hooks/internal/is-apple-device.cjs.js +1 -0
- package/dist/hooks/internal/is-apple-device.es.js +9 -0
- package/dist/hooks/internal/use-latest-ref.cjs.js +1 -0
- package/dist/hooks/internal/use-latest-ref.es.js +11 -0
- package/dist/hooks/use-array/use-array.cjs.js +1 -1
- package/dist/hooks/use-array/use-array.es.js +54 -42
- package/dist/hooks/use-async/use-async.cjs.js +1 -1
- package/dist/hooks/use-async/use-async.es.js +53 -20
- package/dist/hooks/use-boolean/use-boolean.cjs.js +1 -0
- package/dist/hooks/use-boolean/use-boolean.es.js +25 -0
- package/dist/hooks/use-click-outside/use-click-outside.cjs.js +1 -1
- package/dist/hooks/use-click-outside/use-click-outside.es.js +26 -12
- package/dist/hooks/use-debounce-callback/use-debounced-callback.cjs.js +1 -1
- package/dist/hooks/use-debounce-callback/use-debounced-callback.es.js +27 -10
- package/dist/hooks/use-debounce-value/use-debounced-value.cjs.js +1 -1
- package/dist/hooks/use-debounce-value/use-debounced-value.es.js +7 -9
- package/dist/hooks/use-disclosure/use-disclosure.cjs.js +1 -1
- package/dist/hooks/use-disclosure/use-disclosure.es.js +21 -11
- package/dist/hooks/use-document-title/use-document-title.cjs.js +1 -1
- package/dist/hooks/use-document-title/use-document-title.es.js +14 -12
- package/dist/hooks/use-event-listener/use-event-listener.cjs.js +1 -1
- package/dist/hooks/use-event-listener/use-event-listener.es.js +17 -9
- package/dist/hooks/use-hotkey/use-hotkey.cjs.js +1 -1
- package/dist/hooks/use-hotkey/use-hotkey.es.js +30 -14
- package/dist/hooks/use-hotkey/utils/is-input-field.cjs.js +1 -1
- package/dist/hooks/use-hotkey/utils/is-input-field.es.js +4 -2
- package/dist/hooks/use-hotkey/utils/match-and-run.cjs.js +1 -0
- package/dist/hooks/use-hotkey/utils/match-and-run.es.js +12 -0
- package/dist/hooks/use-hotkey/utils/match-key-modifiers.cjs.js +1 -1
- package/dist/hooks/use-hotkey/utils/match-key-modifiers.es.js +13 -12
- package/dist/hooks/use-hover/use-hover.cjs.js +1 -1
- package/dist/hooks/use-hover/use-hover.es.js +32 -17
- package/dist/hooks/use-is-visible/use-is-visible.cjs.js +1 -1
- package/dist/hooks/use-is-visible/use-is-visible.es.js +31 -27
- package/dist/hooks/use-local-storage/use-local-storage.cjs.js +1 -1
- package/dist/hooks/use-local-storage/use-local-storage.es.js +52 -20
- package/dist/hooks/use-media-query/use-media-query.cjs.js +1 -1
- package/dist/hooks/use-media-query/use-media-query.es.js +21 -11
- package/dist/hooks/use-mutation/use-mutation.cjs.js +1 -1
- package/dist/hooks/use-mutation/use-mutation.es.js +36 -22
- package/dist/hooks/use-object/use-object.cjs.js +1 -1
- package/dist/hooks/use-object/use-object.es.js +26 -22
- package/dist/hooks/use-prevent-page-close/use-prevent-page-close.cjs.js +1 -0
- package/dist/hooks/use-prevent-page-close/use-prevent-page-close.es.js +14 -0
- package/dist/hooks/use-step/use-step.cjs.js +1 -1
- package/dist/hooks/use-step/use-step.es.js +25 -24
- package/dist/index.cjs.js +1 -1
- package/dist/index.es.js +308 -300
- package/dist/src/components/date-picker/date-picker.utils.d.ts +17 -0
- package/dist/src/components/date-picker/use-hidden-field-value.d.ts +12 -0
- package/dist/src/components/index.d.ts +1 -0
- package/dist/src/hooks/index.d.ts +2 -2
- package/dist/src/hooks/internal/index.d.ts +2 -0
- package/dist/src/hooks/internal/is-apple-device.d.ts +12 -0
- package/dist/src/hooks/internal/use-latest-ref.d.ts +12 -0
- package/dist/src/hooks/use-array/use-array.d.ts +24 -11
- package/dist/src/hooks/use-async/use-async.d.ts +16 -13
- package/dist/src/hooks/use-boolean/index.d.ts +1 -0
- package/dist/src/hooks/use-boolean/use-boolean.d.ts +15 -0
- package/dist/src/hooks/use-boolean/use-boolean.test.d.ts +1 -0
- package/dist/src/hooks/use-click-outside/use-click-outside.d.ts +23 -1
- package/dist/src/hooks/use-debounce-callback/use-debounced-callback.d.ts +19 -1
- package/dist/src/hooks/use-debounce-value/use-debounced-value.d.ts +10 -1
- package/dist/src/hooks/use-disclosure/use-disclosure.d.ts +17 -8
- package/dist/src/hooks/use-document-title/use-document-title.d.ts +11 -0
- package/dist/src/hooks/use-event-listener/use-event-listener.d.ts +18 -1
- package/dist/src/hooks/use-hotkey/index.d.ts +2 -1
- package/dist/src/hooks/use-hotkey/use-hotkey.d.ts +62 -5
- package/dist/src/hooks/use-hotkey/utils/index.d.ts +4 -3
- package/dist/src/hooks/use-hotkey/utils/is-input-field.d.ts +12 -2
- package/dist/src/hooks/use-hotkey/utils/is-input-field.test.d.ts +1 -0
- package/dist/src/hooks/use-hotkey/utils/match-and-run.d.ts +36 -0
- package/dist/src/hooks/use-hotkey/utils/match-and-run.test.d.ts +1 -0
- package/dist/src/hooks/use-hotkey/utils/match-key-modifiers.d.ts +20 -6
- package/dist/src/hooks/use-hotkey/utils/match-key-modifiers.test.d.ts +1 -0
- package/dist/src/hooks/use-hover/use-hover.d.ts +8 -4
- package/dist/src/hooks/use-is-visible/use-is-visible.d.ts +28 -4
- package/dist/src/hooks/use-local-storage/use-local-storage.d.ts +13 -2
- package/dist/src/hooks/use-media-query/use-media-query.d.ts +10 -1
- package/dist/src/hooks/use-media-query/use-media-query.test.d.ts +1 -0
- package/dist/src/hooks/use-mutation/use-mutation.d.ts +18 -11
- package/dist/src/hooks/use-object/use-object.d.ts +15 -6
- package/dist/src/hooks/use-prevent-page-close/index.d.ts +1 -0
- package/dist/src/hooks/use-prevent-page-close/use-prevent-page-close.d.ts +10 -0
- package/dist/src/hooks/use-prevent-page-close/use-prevent-page-close.test.d.ts +1 -0
- package/dist/src/hooks/use-step/use-step.d.ts +18 -11
- package/dist/src/utils/form.d.ts +10 -0
- package/package.json +1 -1
- package/src/components/alert-dialog/alert-dialog.test.tsx +13 -9
- package/src/components/auto-complete/auto-complete.test.tsx +4 -14
- package/src/components/avatar/avatar.test.tsx +7 -12
- package/src/components/button/button.test.tsx +10 -15
- package/src/components/button/button.tsx +14 -9
- package/src/components/button/components/base-button.tsx +2 -4
- package/src/components/calendar/calendar.test.tsx +12 -19
- package/src/components/calendar/calendar.tsx +4 -0
- package/src/components/card/card.test.tsx +4 -6
- package/src/components/checkbox/checkbox.test.tsx +12 -8
- package/src/components/checkbox-group/checkbox-group.test.tsx +7 -8
- package/src/components/combobox/combobox.test.tsx +24 -21
- package/src/components/date-picker/date-input-form.test.tsx +77 -0
- package/src/components/date-picker/date-input.stories.tsx +30 -18
- package/src/components/date-picker/date-input.tsx +77 -44
- package/src/components/date-picker/date-picker.stories.tsx +31 -1
- package/src/components/date-picker/date-picker.test.tsx +3 -13
- package/src/components/date-picker/date-picker.tsx +35 -16
- package/src/components/date-picker/date-picker.utils.test.ts +32 -14
- package/src/components/date-picker/date-picker.utils.ts +33 -0
- package/src/components/date-picker/use-date-input-popover.test.ts +3 -1
- package/src/components/date-picker/use-hidden-field-value.ts +23 -0
- package/src/components/dialog/dialog.test.tsx +10 -8
- package/src/components/dropzone/dropzone.test.tsx +11 -13
- package/src/components/empty/empty.test.tsx +4 -3
- package/src/components/field/field.test.tsx +12 -13
- package/src/components/form/form.stories.tsx +16 -1
- package/src/components/index.ts +1 -0
- package/src/components/label/label.test.tsx +3 -3
- package/src/components/menu/menu.tsx +1 -5
- package/src/components/number-input/number-input.test.tsx +6 -2
- package/src/components/password/password.test.tsx +20 -6
- package/src/components/password/password.tsx +2 -2
- package/src/components/popover/popover.test.tsx +4 -4
- package/src/components/progress/progress.test.tsx +7 -8
- package/src/components/radio-group/radio-group.test.tsx +17 -11
- package/src/components/select/select.test.tsx +10 -10
- package/src/components/select/select.tsx +9 -1
- package/src/components/stepper/stepper.stories.tsx +11 -15
- package/src/components/stepper/stepper.test.tsx +6 -4
- package/src/components/switch/switch.test.tsx +3 -3
- package/src/components/table/table.test.tsx +9 -3
- package/src/components/tabs/tabs.test.tsx +6 -2
- package/src/components/tag/tag.test.tsx +1 -3
- package/src/components/textarea/textarea.test.tsx +4 -1
- package/src/components/timeline/timeline.test.tsx +10 -5
- package/src/components/toast/toast.test.tsx +11 -14
- package/src/components/tooltip/tooltip.test.tsx +1 -5
- package/src/components/tree/tree.test.tsx +3 -1
- package/src/hooks/index.ts +2 -2
- package/src/hooks/internal/index.ts +2 -0
- package/src/hooks/internal/is-apple-device.test.ts +41 -0
- package/src/hooks/internal/is-apple-device.ts +33 -0
- package/src/hooks/internal/use-isomorphic-layout-effect.ts +3 -1
- package/src/hooks/internal/use-latest-ref.ts +21 -0
- package/src/hooks/use-array/use-array.stories.tsx +435 -64
- package/src/hooks/use-array/use-array.test.tsx +398 -15
- package/src/hooks/use-array/use-array.ts +105 -66
- package/src/hooks/use-async/use-async.stories.tsx +255 -131
- package/src/hooks/use-async/use-async.test.ts +397 -0
- package/src/hooks/use-async/use-async.ts +117 -39
- package/src/hooks/use-boolean/index.ts +1 -0
- package/src/hooks/use-boolean/use-boolean.stories.tsx +377 -0
- package/src/hooks/use-boolean/use-boolean.test.tsx +177 -0
- package/src/hooks/use-boolean/use-boolean.ts +50 -0
- package/src/hooks/use-click-outside/use-click-outside.stories.tsx +188 -18
- package/src/hooks/use-click-outside/use-click-outside.test.tsx +89 -10
- package/src/hooks/use-click-outside/use-click-outside.ts +62 -16
- package/src/hooks/use-debounce-callback/use-debounced-callback.stories.tsx +141 -41
- package/src/hooks/use-debounce-callback/use-debounced-callback.test.ts +217 -9
- package/src/hooks/use-debounce-callback/use-debounced-callback.ts +71 -11
- package/src/hooks/use-debounce-value/use-debounced-value.stories.tsx +247 -47
- package/src/hooks/use-debounce-value/use-debounced-value.test.ts +105 -10
- package/src/hooks/use-debounce-value/use-debounced-value.ts +19 -10
- package/src/hooks/use-disclosure/use-disclosure.stories.tsx +305 -14
- package/src/hooks/use-disclosure/use-disclosure.test.ts +198 -50
- package/src/hooks/use-disclosure/use-disclosure.ts +49 -29
- package/src/hooks/use-document-title/use-document-title.stories.tsx +54 -0
- package/src/hooks/use-document-title/use-document-title.test.tsx +26 -0
- package/src/hooks/use-document-title/{use-document-title.tsx → use-document-title.ts} +17 -3
- package/src/hooks/use-event-listener/use-event-listener.stories.tsx +105 -9
- package/src/hooks/use-event-listener/use-event-listener.test.tsx +77 -10
- package/src/hooks/use-event-listener/use-event-listener.ts +71 -11
- package/src/hooks/use-focus-trap/use-focus-trap.test.ts +31 -6
- package/src/hooks/use-focus-trap/use-focus-trap.ts +3 -2
- package/src/hooks/use-hotkey/index.ts +9 -1
- package/src/hooks/use-hotkey/use-hotkey.stories.tsx +279 -74
- package/src/hooks/use-hotkey/use-hotkey.test.tsx +286 -34
- package/src/hooks/use-hotkey/use-hotkey.ts +141 -17
- package/src/hooks/use-hotkey/utils/index.ts +8 -3
- package/src/hooks/use-hotkey/utils/is-input-field.test.ts +78 -0
- package/src/hooks/use-hotkey/utils/is-input-field.ts +31 -10
- package/src/hooks/use-hotkey/utils/match-and-run.test.ts +203 -0
- package/src/hooks/use-hotkey/utils/match-and-run.ts +62 -0
- package/src/hooks/use-hotkey/utils/match-key-modifiers.test.ts +65 -0
- package/src/hooks/use-hotkey/utils/match-key-modifiers.ts +39 -12
- package/src/hooks/use-hover/use-hover.stories.tsx +258 -80
- package/src/hooks/use-hover/use-hover.test.tsx +266 -26
- package/src/hooks/use-hover/use-hover.tsx +93 -28
- package/src/hooks/use-is-visible/use-is-visible.stories.tsx +193 -46
- package/src/hooks/use-is-visible/use-is-visible.test.tsx +235 -7
- package/src/hooks/use-is-visible/use-is-visible.ts +114 -0
- package/src/hooks/use-local-storage/use-local-storage.stories.tsx +129 -29
- package/src/hooks/use-local-storage/use-local-storage.test.ts +106 -41
- package/src/hooks/use-local-storage/use-local-storage.ts +100 -31
- package/src/hooks/use-media-query/use-media-query.stories.tsx +86 -26
- package/src/hooks/use-media-query/use-media-query.test.ts +132 -0
- package/src/hooks/use-media-query/use-media-query.ts +39 -14
- package/src/hooks/use-memoized-fn/use-memoized-fn.ts +0 -1
- package/src/hooks/use-mutation/use-mutation.stories.tsx +260 -94
- package/src/hooks/use-mutation/use-mutation.test.ts +359 -0
- package/src/hooks/use-mutation/use-mutation.ts +97 -0
- package/src/hooks/use-object/use-object.stories.tsx +310 -79
- package/src/hooks/use-object/use-object.test.tsx +235 -56
- package/src/hooks/use-object/use-object.ts +59 -0
- package/src/hooks/use-pagination/use-pagination.tsx +0 -1
- package/src/hooks/use-prevent-page-close/index.ts +1 -0
- package/src/hooks/use-prevent-page-close/use-prevent-page-close.stories.tsx +39 -0
- package/src/hooks/use-prevent-page-close/use-prevent-page-close.test.ts +89 -0
- package/src/hooks/use-prevent-page-close/use-prevent-page-close.ts +27 -0
- package/src/hooks/use-range-pagination/use-range-pagination.test.tsx +1 -1
- package/src/hooks/use-range-pagination/use-range-pagination.tsx +1 -1
- package/src/hooks/use-selection/use-selection.ts +0 -1
- package/src/hooks/use-step/use-step.stories.tsx +178 -65
- package/src/hooks/use-step/use-step.test.ts +178 -53
- package/src/hooks/use-step/use-step.ts +57 -49
- package/src/utils/form.test.tsx +13 -8
- package/src/utils/form.tsx +10 -0
- package/src/utils/functions/getFormData.test.ts +1 -1
- package/dist/hooks/use-hotkey/utils/create-hotkey-listener.cjs.js +0 -1
- package/dist/hooks/use-hotkey/utils/create-hotkey-listener.es.js +0 -10
- package/dist/hooks/use-prevent-close-window/use-prevent-close-window.cjs.js +0 -1
- package/dist/hooks/use-prevent-close-window/use-prevent-close-window.es.js +0 -15
- package/dist/hooks/use-toggle/use-toggle.cjs.js +0 -1
- package/dist/hooks/use-toggle/use-toggle.es.js +0 -10
- package/dist/src/hooks/use-hotkey/utils/create-hotkey-listener.d.ts +0 -1
- package/dist/src/hooks/use-prevent-close-window/index.d.ts +0 -1
- package/dist/src/hooks/use-prevent-close-window/use-prevent-close-window.d.ts +0 -13
- package/dist/src/hooks/use-toggle/index.d.ts +0 -1
- package/dist/src/hooks/use-toggle/use-toggle.d.ts +0 -3
- package/src/hooks/use-async/use-async.test.tsx +0 -68
- package/src/hooks/use-hotkey/utils/create-hotkey-listener.ts +0 -25
- package/src/hooks/use-is-visible/use-is-visible.tsx +0 -49
- package/src/hooks/use-mutation/use-mutation.test.tsx +0 -83
- package/src/hooks/use-mutation/use-mutation.tsx +0 -59
- package/src/hooks/use-object/use-object.tsx +0 -46
- package/src/hooks/use-prevent-close-window/index.ts +0 -1
- package/src/hooks/use-prevent-close-window/use-prevent-close-window.stories.tsx +0 -32
- package/src/hooks/use-prevent-close-window/use-prevent-close-window.test.ts +0 -79
- package/src/hooks/use-prevent-close-window/use-prevent-close-window.ts +0 -33
- package/src/hooks/use-toggle/index.ts +0 -1
- package/src/hooks/use-toggle/use-toggle.stories.tsx +0 -25
- package/src/hooks/use-toggle/use-toggle.test.tsx +0 -64
- package/src/hooks/use-toggle/use-toggle.ts +0 -14
- /package/dist/src/{hooks/use-prevent-close-window/use-prevent-close-window.test.d.ts → components/date-picker/date-input-form.test.d.ts} +0 -0
- /package/dist/src/hooks/{use-toggle/use-toggle.test.d.ts → internal/is-apple-device.test.d.ts} +0 -0
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { useEffect, useRef } from "react";
|
|
2
|
+
import { emitNativeInputChange } from "./date-picker.utils";
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Drives a hidden Base UI `FieldControl` input from a derived form value.
|
|
6
|
+
*
|
|
7
|
+
* The input is left uncontrolled and updated imperatively so a native `input`
|
|
8
|
+
* event fires on every change. Base UI re-runs Field validation (and clears the
|
|
9
|
+
* error) only inside the control's `onChange` — never from a React `value` prop
|
|
10
|
+
* — so date changes coming from the calendar or the visible input must emit a
|
|
11
|
+
* real event for the invalid state to clear.
|
|
12
|
+
*
|
|
13
|
+
* Returns the ref to attach to the hidden input.
|
|
14
|
+
*/
|
|
15
|
+
export function useHiddenFieldValue(value: string) {
|
|
16
|
+
const ref = useRef<HTMLInputElement>(null);
|
|
17
|
+
|
|
18
|
+
useEffect(() => {
|
|
19
|
+
emitNativeInputChange(ref.current, value);
|
|
20
|
+
}, [value]);
|
|
21
|
+
|
|
22
|
+
return ref;
|
|
23
|
+
}
|
|
@@ -162,9 +162,9 @@ describe("Dialog component", () => {
|
|
|
162
162
|
<DialogPopup className="custom-popup-class">Content</DialogPopup>
|
|
163
163
|
</DialogRoot>,
|
|
164
164
|
);
|
|
165
|
-
expect(
|
|
166
|
-
|
|
167
|
-
)
|
|
165
|
+
expect(document.querySelector('[data-slot="dialog-popup"]')).toHaveClass(
|
|
166
|
+
"custom-popup-class",
|
|
167
|
+
);
|
|
168
168
|
});
|
|
169
169
|
});
|
|
170
170
|
|
|
@@ -177,7 +177,9 @@ describe("Dialog component", () => {
|
|
|
177
177
|
</DialogPopup>
|
|
178
178
|
</DialogRoot>,
|
|
179
179
|
);
|
|
180
|
-
expect(
|
|
180
|
+
expect(
|
|
181
|
+
screen.getByRole("button", { name: "Cerrar" }),
|
|
182
|
+
).toBeInTheDocument();
|
|
181
183
|
});
|
|
182
184
|
|
|
183
185
|
it("hides close button when hideClose is true", () => {
|
|
@@ -230,9 +232,7 @@ describe("Dialog component", () => {
|
|
|
230
232
|
</DialogRoot>,
|
|
231
233
|
);
|
|
232
234
|
// Close button is wrapped in a Button with the closeButton class
|
|
233
|
-
expect(
|
|
234
|
-
document.querySelector(".custom-close-btn"),
|
|
235
|
-
).toBeInTheDocument();
|
|
235
|
+
expect(document.querySelector(".custom-close-btn")).toBeInTheDocument();
|
|
236
236
|
});
|
|
237
237
|
});
|
|
238
238
|
|
|
@@ -306,7 +306,9 @@ describe("Dialog composite", () => {
|
|
|
306
306
|
setup({ onClose });
|
|
307
307
|
click(screen.getByRole("button", { name: "Open" }));
|
|
308
308
|
await waitFor(() =>
|
|
309
|
-
expect(
|
|
309
|
+
expect(
|
|
310
|
+
screen.getByRole("button", { name: "Cerrar" }),
|
|
311
|
+
).toBeInTheDocument(),
|
|
310
312
|
);
|
|
311
313
|
click(screen.getByRole("button", { name: "Cerrar" }));
|
|
312
314
|
await waitFor(() => expect(onClose).toHaveBeenCalledTimes(1));
|
|
@@ -16,7 +16,9 @@ import {
|
|
|
16
16
|
describe("DropzoneRoot", () => {
|
|
17
17
|
it("renders with data-slot dropzone", () => {
|
|
18
18
|
render(<DropzoneRoot />);
|
|
19
|
-
expect(
|
|
19
|
+
expect(
|
|
20
|
+
document.querySelector('[data-slot="dropzone"]'),
|
|
21
|
+
).toBeInTheDocument();
|
|
20
22
|
});
|
|
21
23
|
|
|
22
24
|
it("applies className to root div", () => {
|
|
@@ -136,15 +138,11 @@ describe("DropzoneItem", () => {
|
|
|
136
138
|
|
|
137
139
|
it("applies className", () => {
|
|
138
140
|
render(
|
|
139
|
-
<DropzoneItem
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
/>,
|
|
141
|
+
<DropzoneItem file={file} onRemove={vi.fn()} className="custom-item" />,
|
|
142
|
+
);
|
|
143
|
+
expect(document.querySelector('[data-slot="dropzone-item"]')).toHaveClass(
|
|
144
|
+
"custom-item",
|
|
144
145
|
);
|
|
145
|
-
expect(
|
|
146
|
-
document.querySelector('[data-slot="dropzone-item"]'),
|
|
147
|
-
).toHaveClass("custom-item");
|
|
148
146
|
});
|
|
149
147
|
});
|
|
150
148
|
|
|
@@ -247,15 +245,15 @@ describe("Dropzone composite", () => {
|
|
|
247
245
|
|
|
248
246
|
it("shows allowed extensions when provided", () => {
|
|
249
247
|
render(<Dropzone allowedExtensions={["image/png", "image/jpeg"]} />);
|
|
250
|
-
expect(
|
|
251
|
-
screen.getByText(/Tipos permitidos/),
|
|
252
|
-
).toBeInTheDocument();
|
|
248
|
+
expect(screen.getByText(/Tipos permitidos/)).toBeInTheDocument();
|
|
253
249
|
});
|
|
254
250
|
|
|
255
251
|
it("does not show rejected section when showRejected is false", () => {
|
|
256
252
|
render(<Dropzone showRejected={false} />);
|
|
257
253
|
// No rejected items in DOM since showRejected=false (default)
|
|
258
|
-
expect(
|
|
254
|
+
expect(
|
|
255
|
+
document.querySelectorAll('[data-slot="dropzone-item"]'),
|
|
256
|
+
).toHaveLength(0);
|
|
259
257
|
});
|
|
260
258
|
|
|
261
259
|
it("applies classNames.trigger to trigger element", () => {
|
|
@@ -168,9 +168,10 @@ describe("Empty composite", () => {
|
|
|
168
168
|
|
|
169
169
|
it("applies iconVariant='icon' to media slot", () => {
|
|
170
170
|
render(<Empty iconVariant="icon" />);
|
|
171
|
-
expect(
|
|
172
|
-
|
|
173
|
-
|
|
171
|
+
expect(document.querySelector('[data-slot="empty-media"]')).toHaveAttribute(
|
|
172
|
+
"data-variant",
|
|
173
|
+
"icon",
|
|
174
|
+
);
|
|
174
175
|
});
|
|
175
176
|
|
|
176
177
|
it("renders children alongside default slots", () => {
|
|
@@ -1,5 +1,4 @@
|
|
|
1
|
-
import { render, screen } from "@testing-library/react";
|
|
2
|
-
import { renderHook } from "@testing-library/react";
|
|
1
|
+
import { render, renderHook, screen } from "@testing-library/react";
|
|
3
2
|
import { describe, expect, it } from "vitest";
|
|
4
3
|
import {
|
|
5
4
|
Field,
|
|
@@ -12,8 +11,8 @@ import {
|
|
|
12
11
|
FieldPrimitive,
|
|
13
12
|
FieldRoot,
|
|
14
13
|
FieldSet,
|
|
15
|
-
FieldValidity,
|
|
16
14
|
FieldsetPrimitive,
|
|
15
|
+
FieldValidity,
|
|
17
16
|
normalizeError,
|
|
18
17
|
useFieldName,
|
|
19
18
|
useIsInsideFieldRoot,
|
|
@@ -56,9 +55,7 @@ describe("useIsInsideFieldRoot", () => {
|
|
|
56
55
|
|
|
57
56
|
it("returns true inside FieldRoot", () => {
|
|
58
57
|
const { result } = renderHook(() => useIsInsideFieldRoot(), {
|
|
59
|
-
wrapper: ({ children }) =>
|
|
60
|
-
<FieldRoot name="test">{children}</FieldRoot>
|
|
61
|
-
),
|
|
58
|
+
wrapper: ({ children }) => <FieldRoot name="test">{children}</FieldRoot>,
|
|
62
59
|
});
|
|
63
60
|
expect(result.current).toBe(true);
|
|
64
61
|
});
|
|
@@ -72,9 +69,7 @@ describe("useFieldName", () => {
|
|
|
72
69
|
|
|
73
70
|
it("returns the name provided to FieldRoot", () => {
|
|
74
71
|
const { result } = renderHook(() => useFieldName(), {
|
|
75
|
-
wrapper: ({ children }) =>
|
|
76
|
-
<FieldRoot name="email">{children}</FieldRoot>
|
|
77
|
-
),
|
|
72
|
+
wrapper: ({ children }) => <FieldRoot name="email">{children}</FieldRoot>,
|
|
78
73
|
});
|
|
79
74
|
expect(result.current).toBe("email");
|
|
80
75
|
});
|
|
@@ -97,9 +92,9 @@ describe("FieldRoot", () => {
|
|
|
97
92
|
|
|
98
93
|
it("does not set data-required when required is absent", () => {
|
|
99
94
|
render(<FieldRoot name="x" />);
|
|
100
|
-
expect(
|
|
101
|
-
|
|
102
|
-
)
|
|
95
|
+
expect(document.querySelector('[data-slot="field"]')).not.toHaveAttribute(
|
|
96
|
+
"data-required",
|
|
97
|
+
);
|
|
103
98
|
});
|
|
104
99
|
|
|
105
100
|
it("forwards className", () => {
|
|
@@ -204,7 +199,11 @@ describe("Field composite", () => {
|
|
|
204
199
|
});
|
|
205
200
|
|
|
206
201
|
it("renders children", () => {
|
|
207
|
-
render(
|
|
202
|
+
render(
|
|
203
|
+
<Field>
|
|
204
|
+
<input placeholder="ctrl" />
|
|
205
|
+
</Field>,
|
|
206
|
+
);
|
|
208
207
|
expect(screen.getByPlaceholderText("ctrl")).toBeInTheDocument();
|
|
209
208
|
});
|
|
210
209
|
|
|
@@ -10,7 +10,7 @@ import {
|
|
|
10
10
|
import { Button } from "../button/button";
|
|
11
11
|
import { Checkbox } from "../checkbox/checkbox";
|
|
12
12
|
import { Combobox } from "../combobox";
|
|
13
|
-
import { DateInput } from "../date-picker";
|
|
13
|
+
import { DateInput, DatePicker } from "../date-picker";
|
|
14
14
|
import { Field, FieldError, FieldLabel, FieldRoot } from "../field/field";
|
|
15
15
|
import { Input } from "../input/input";
|
|
16
16
|
import { NumberInput } from "../number-input";
|
|
@@ -63,6 +63,11 @@ const ROLES = [
|
|
|
63
63
|
* Native HTML constraint validation. Each `FieldRoot` carries a `name` so Form
|
|
64
64
|
* can route server errors automatically. Errors only surface after the first
|
|
65
65
|
* submit attempt — no premature invalid state.
|
|
66
|
+
*
|
|
67
|
+
* Both date controls — typeable `DateInput` and popover `DatePicker` — submit an
|
|
68
|
+
* ISO date string (`yyyy-MM-dd`), or `""` when empty so `required` triggers
|
|
69
|
+
* `valueMissing`. The displayed text stays `dd/MM/yyyy`; value and display are
|
|
70
|
+
* separate layers.
|
|
66
71
|
*/
|
|
67
72
|
export const Default: Story = {
|
|
68
73
|
render: () => {
|
|
@@ -130,11 +135,21 @@ export const Default: Story = {
|
|
|
130
135
|
<Field
|
|
131
136
|
name="startDate"
|
|
132
137
|
label="Start date"
|
|
138
|
+
description="Typeable input — submits yyyy-MM-dd."
|
|
133
139
|
error={{ message: "Start date is required.", match: "valueMissing" }}
|
|
134
140
|
>
|
|
135
141
|
<DateInput required />
|
|
136
142
|
</Field>
|
|
137
143
|
|
|
144
|
+
<Field
|
|
145
|
+
name="endDate"
|
|
146
|
+
label="End date"
|
|
147
|
+
description="Popover picker — submits yyyy-MM-dd."
|
|
148
|
+
error={{ message: "End date is required.", match: "valueMissing" }}
|
|
149
|
+
>
|
|
150
|
+
<DatePicker mode="single" required />
|
|
151
|
+
</Field>
|
|
152
|
+
|
|
138
153
|
<Field
|
|
139
154
|
name="notifications"
|
|
140
155
|
label="Notification channels"
|
package/src/components/index.ts
CHANGED
|
@@ -100,8 +100,8 @@ describe("Label component", () => {
|
|
|
100
100
|
Email
|
|
101
101
|
</Label>,
|
|
102
102
|
);
|
|
103
|
-
expect(
|
|
104
|
-
|
|
105
|
-
)
|
|
103
|
+
expect(screen.getByRole("button", { name: "Más información" })).toHaveClass(
|
|
104
|
+
"tooltip-btn-cls",
|
|
105
|
+
);
|
|
106
106
|
});
|
|
107
107
|
});
|
|
@@ -106,11 +106,7 @@ function renderItem(item: MenuItemType, index: number): React.ReactNode {
|
|
|
106
106
|
case "radio-group": {
|
|
107
107
|
const { type: _, value, onValueChange, items } = item;
|
|
108
108
|
return (
|
|
109
|
-
<MenuRadioGroup
|
|
110
|
-
key={index}
|
|
111
|
-
value={value}
|
|
112
|
-
onValueChange={onValueChange}
|
|
113
|
-
>
|
|
109
|
+
<MenuRadioGroup key={index} value={value} onValueChange={onValueChange}>
|
|
114
110
|
{items.map((subItem, i) => renderItem(subItem, i))}
|
|
115
111
|
</MenuRadioGroup>
|
|
116
112
|
);
|
|
@@ -215,7 +215,9 @@ describe("NumberInput scrub primitives", () => {
|
|
|
215
215
|
render(
|
|
216
216
|
<NumberInputRoot name="amount">
|
|
217
217
|
<NumberInputGroup>
|
|
218
|
-
<NumberInputScrubArea className="scrub-cls">
|
|
218
|
+
<NumberInputScrubArea className="scrub-cls">
|
|
219
|
+
Drag
|
|
220
|
+
</NumberInputScrubArea>
|
|
219
221
|
<NumberInputInput />
|
|
220
222
|
</NumberInputGroup>
|
|
221
223
|
</NumberInputRoot>,
|
|
@@ -251,6 +253,8 @@ describe("NumberInput scrub primitives", () => {
|
|
|
251
253
|
const { container } = render(
|
|
252
254
|
<NumberInputCursorIcon data-testid="cursor-icon" />,
|
|
253
255
|
);
|
|
254
|
-
expect(
|
|
256
|
+
expect(
|
|
257
|
+
container.querySelector("[data-testid='cursor-icon']"),
|
|
258
|
+
).toBeInTheDocument();
|
|
255
259
|
});
|
|
256
260
|
});
|
|
@@ -12,12 +12,17 @@ describe("Password", () => {
|
|
|
12
12
|
|
|
13
13
|
it("renders toggle button with data-slot='password-toggle'", () => {
|
|
14
14
|
render(<Password />);
|
|
15
|
-
expect(
|
|
15
|
+
expect(
|
|
16
|
+
document.querySelector('[data-slot="password-toggle"]'),
|
|
17
|
+
).toBeTruthy();
|
|
16
18
|
});
|
|
17
19
|
|
|
18
20
|
it("defaults to type='password'", () => {
|
|
19
21
|
render(<Password />);
|
|
20
|
-
expect(document.querySelector("input")).toHaveAttribute(
|
|
22
|
+
expect(document.querySelector("input")).toHaveAttribute(
|
|
23
|
+
"type",
|
|
24
|
+
"password",
|
|
25
|
+
);
|
|
21
26
|
});
|
|
22
27
|
});
|
|
23
28
|
|
|
@@ -25,7 +30,9 @@ describe("Password", () => {
|
|
|
25
30
|
it("reveals password on toggle click", async () => {
|
|
26
31
|
render(<Password />);
|
|
27
32
|
await userEvent.click(
|
|
28
|
-
document.querySelector(
|
|
33
|
+
document.querySelector(
|
|
34
|
+
'[data-slot="password-toggle"]',
|
|
35
|
+
) as HTMLButtonElement,
|
|
29
36
|
);
|
|
30
37
|
expect(document.querySelector("input")).toHaveAttribute("type", "text");
|
|
31
38
|
});
|
|
@@ -37,14 +44,19 @@ describe("Password", () => {
|
|
|
37
44
|
) as HTMLButtonElement;
|
|
38
45
|
await userEvent.click(toggle);
|
|
39
46
|
await userEvent.click(toggle);
|
|
40
|
-
expect(document.querySelector("input")).toHaveAttribute(
|
|
47
|
+
expect(document.querySelector("input")).toHaveAttribute(
|
|
48
|
+
"type",
|
|
49
|
+
"password",
|
|
50
|
+
);
|
|
41
51
|
});
|
|
42
52
|
|
|
43
53
|
it("fires onShow when revealing password", async () => {
|
|
44
54
|
const onShow = vi.fn();
|
|
45
55
|
render(<Password onShow={onShow} />);
|
|
46
56
|
await userEvent.click(
|
|
47
|
-
document.querySelector(
|
|
57
|
+
document.querySelector(
|
|
58
|
+
'[data-slot="password-toggle"]',
|
|
59
|
+
) as HTMLButtonElement,
|
|
48
60
|
);
|
|
49
61
|
expect(onShow).toHaveBeenCalledTimes(1);
|
|
50
62
|
});
|
|
@@ -107,7 +119,9 @@ describe("Password", () => {
|
|
|
107
119
|
it("renders custom hideIcon after toggle", async () => {
|
|
108
120
|
render(<Password hideIcon={<span data-testid="hide-icon" />} />);
|
|
109
121
|
await userEvent.click(
|
|
110
|
-
document.querySelector(
|
|
122
|
+
document.querySelector(
|
|
123
|
+
'[data-slot="password-toggle"]',
|
|
124
|
+
) as HTMLButtonElement,
|
|
111
125
|
);
|
|
112
126
|
expect(screen.getByTestId("hide-icon")).toBeTruthy();
|
|
113
127
|
});
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
import { Eye, EyeOff } from "lucide-react";
|
|
4
4
|
import { type ChangeEvent, type ReactNode } from "react";
|
|
5
|
-
import {
|
|
5
|
+
import { useBoolean } from "../../hooks";
|
|
6
6
|
import { cn } from "../../lib";
|
|
7
7
|
import { InputPrimitive, type InputProps } from "../input/input";
|
|
8
8
|
|
|
@@ -32,7 +32,7 @@ export function Password({
|
|
|
32
32
|
classNames,
|
|
33
33
|
...rest
|
|
34
34
|
}: PasswordProps) {
|
|
35
|
-
const [showPassword, toggleShowPassword] =
|
|
35
|
+
const [showPassword, { toggle: toggleShowPassword }] = useBoolean(false);
|
|
36
36
|
|
|
37
37
|
const handleToggle = () => {
|
|
38
38
|
toggleShowPassword();
|
|
@@ -21,7 +21,9 @@ describe("Popover primitives", () => {
|
|
|
21
21
|
<PopoverPopup>Content</PopoverPopup>
|
|
22
22
|
</PopoverRoot>,
|
|
23
23
|
);
|
|
24
|
-
expect(
|
|
24
|
+
expect(
|
|
25
|
+
document.querySelector('[data-slot="popover-trigger"]'),
|
|
26
|
+
).toBeTruthy();
|
|
25
27
|
});
|
|
26
28
|
|
|
27
29
|
it("PopoverPopup renders data-slot='popover-popup' when open", () => {
|
|
@@ -125,9 +127,7 @@ describe("Popover composite", () => {
|
|
|
125
127
|
<span data-testid="content">Content</span>
|
|
126
128
|
</Popover>,
|
|
127
129
|
);
|
|
128
|
-
expect(
|
|
129
|
-
document.querySelector('[data-slot="popover-title"]'),
|
|
130
|
-
).toBeNull();
|
|
130
|
+
expect(document.querySelector('[data-slot="popover-title"]')).toBeNull();
|
|
131
131
|
});
|
|
132
132
|
|
|
133
133
|
it("opens on trigger click", async () => {
|
|
@@ -58,9 +58,7 @@ describe("ProgressLabel", () => {
|
|
|
58
58
|
<ProgressTrack />
|
|
59
59
|
</ProgressRoot>,
|
|
60
60
|
);
|
|
61
|
-
expect(
|
|
62
|
-
document.querySelector('[data-slot="progress-label"]'),
|
|
63
|
-
).toBeTruthy();
|
|
61
|
+
expect(document.querySelector('[data-slot="progress-label"]')).toBeTruthy();
|
|
64
62
|
});
|
|
65
63
|
});
|
|
66
64
|
|
|
@@ -74,9 +72,7 @@ describe("ProgressValue", () => {
|
|
|
74
72
|
<ProgressValue />
|
|
75
73
|
</ProgressRoot>,
|
|
76
74
|
);
|
|
77
|
-
expect(
|
|
78
|
-
document.querySelector('[data-slot="progress-value"]'),
|
|
79
|
-
).toBeTruthy();
|
|
75
|
+
expect(document.querySelector('[data-slot="progress-value"]')).toBeTruthy();
|
|
80
76
|
});
|
|
81
77
|
});
|
|
82
78
|
|
|
@@ -110,7 +106,9 @@ describe("Progress indicator variants", () => {
|
|
|
110
106
|
|
|
111
107
|
describe("Progress className", () => {
|
|
112
108
|
it("applies className to root", () => {
|
|
113
|
-
render(
|
|
109
|
+
render(
|
|
110
|
+
<Progress value={null} className="custom-root" aria-label="Loading" />,
|
|
111
|
+
);
|
|
114
112
|
expect(document.querySelector('[data-slot="progress"]')).toHaveClass(
|
|
115
113
|
"custom-root",
|
|
116
114
|
);
|
|
@@ -120,7 +118,8 @@ describe("Progress className", () => {
|
|
|
120
118
|
describe("Progress primitive exports", () => {
|
|
121
119
|
it("exports ProgressRoot", () => expect(ProgressRoot).toBeDefined());
|
|
122
120
|
it("exports ProgressTrack", () => expect(ProgressTrack).toBeDefined());
|
|
123
|
-
it("exports ProgressIndicator", () =>
|
|
121
|
+
it("exports ProgressIndicator", () =>
|
|
122
|
+
expect(ProgressIndicator).toBeDefined());
|
|
124
123
|
it("exports ProgressLabel", () => expect(ProgressLabel).toBeDefined());
|
|
125
124
|
it("exports ProgressValue", () => expect(ProgressValue).toBeDefined());
|
|
126
125
|
});
|
|
@@ -42,7 +42,9 @@ describe("RadioGroup primitives", () => {
|
|
|
42
42
|
</RadioRoot>
|
|
43
43
|
</RadioGroupRoot>,
|
|
44
44
|
);
|
|
45
|
-
expect(
|
|
45
|
+
expect(
|
|
46
|
+
document.querySelector('[data-slot="radio-indicator"]'),
|
|
47
|
+
).toBeTruthy();
|
|
46
48
|
});
|
|
47
49
|
});
|
|
48
50
|
|
|
@@ -60,9 +62,10 @@ describe("RadioGroup composite", () => {
|
|
|
60
62
|
|
|
61
63
|
it("marks defaultValue as checked", () => {
|
|
62
64
|
render(<RadioGroup items={items} defaultValue="b" />);
|
|
63
|
-
expect(
|
|
64
|
-
|
|
65
|
-
|
|
65
|
+
expect(screen.getByRole("radio", { name: "Option B" })).toHaveAttribute(
|
|
66
|
+
"aria-checked",
|
|
67
|
+
"true",
|
|
68
|
+
);
|
|
66
69
|
});
|
|
67
70
|
|
|
68
71
|
it("fires onValueChange when selection changes", async () => {
|
|
@@ -74,16 +77,17 @@ describe("RadioGroup composite", () => {
|
|
|
74
77
|
|
|
75
78
|
it("reflects controlled value", () => {
|
|
76
79
|
render(<RadioGroup items={items} value="a" onValueChange={vi.fn()} />);
|
|
77
|
-
expect(
|
|
78
|
-
|
|
79
|
-
|
|
80
|
+
expect(screen.getByRole("radio", { name: "Option A" })).toHaveAttribute(
|
|
81
|
+
"aria-checked",
|
|
82
|
+
"true",
|
|
83
|
+
);
|
|
80
84
|
});
|
|
81
85
|
|
|
82
86
|
it("disables specific item", () => {
|
|
83
87
|
render(<RadioGroup items={items} />);
|
|
84
|
-
expect(
|
|
85
|
-
|
|
86
|
-
)
|
|
88
|
+
expect(screen.getByRole("radio", { name: "Option C" })).toHaveAttribute(
|
|
89
|
+
"data-disabled",
|
|
90
|
+
);
|
|
87
91
|
});
|
|
88
92
|
|
|
89
93
|
it("disables all items when disabled prop is set", () => {
|
|
@@ -140,7 +144,9 @@ describe("RadioGroup.Legend", () => {
|
|
|
140
144
|
|
|
141
145
|
describe("RadioGroup controlFirst", () => {
|
|
142
146
|
it("applies flex-row-reverse when controlFirst=false", () => {
|
|
143
|
-
render(
|
|
147
|
+
render(
|
|
148
|
+
<RadioGroup items={[{ value: "a", label: "A" }]} controlFirst={false} />,
|
|
149
|
+
);
|
|
144
150
|
const row = document.querySelector(".flex-row-reverse");
|
|
145
151
|
expect(row).toBeTruthy();
|
|
146
152
|
});
|
|
@@ -51,7 +51,11 @@ describe("Select primitives — data-slots", () => {
|
|
|
51
51
|
});
|
|
52
52
|
|
|
53
53
|
it("SelectButton renders data-slot=select-button with type=button by default", () => {
|
|
54
|
-
render(
|
|
54
|
+
render(
|
|
55
|
+
<SelectRoot>
|
|
56
|
+
<SelectButton>Open</SelectButton>
|
|
57
|
+
</SelectRoot>,
|
|
58
|
+
);
|
|
55
59
|
const btn = slot("select-button") as HTMLButtonElement;
|
|
56
60
|
expect(btn).toBeInTheDocument();
|
|
57
61
|
expect(btn.type).toBe("button");
|
|
@@ -235,7 +239,9 @@ describe("Select defaultGetLabel / defaultGetId", () => {
|
|
|
235
239
|
getId={(o) => o.code}
|
|
236
240
|
/>,
|
|
237
241
|
);
|
|
238
|
-
expect(
|
|
242
|
+
expect(
|
|
243
|
+
screen.getByRole("option", { name: "Argentina" }),
|
|
244
|
+
).toBeInTheDocument();
|
|
239
245
|
});
|
|
240
246
|
});
|
|
241
247
|
|
|
@@ -260,11 +266,7 @@ describe("Select disabled items", () => {
|
|
|
260
266
|
{ id: "2", name: "Blocked", blocked: true },
|
|
261
267
|
];
|
|
262
268
|
render(
|
|
263
|
-
<Select
|
|
264
|
-
items={items}
|
|
265
|
-
defaultOpen
|
|
266
|
-
getDisabled={(item) => item.blocked}
|
|
267
|
-
/>,
|
|
269
|
+
<Select items={items} defaultOpen getDisabled={(item) => item.blocked} />,
|
|
268
270
|
);
|
|
269
271
|
expect(
|
|
270
272
|
document.querySelector('[data-slot="select-item"][data-disabled]'),
|
|
@@ -277,9 +279,7 @@ describe("Select disabled items", () => {
|
|
|
277
279
|
describe("Select onValueChange", () => {
|
|
278
280
|
it("fires onValueChange with selected item object (single)", async () => {
|
|
279
281
|
const onChange = vi.fn();
|
|
280
|
-
render(
|
|
281
|
-
<Select items={fruits} defaultOpen onValueChange={onChange} />,
|
|
282
|
-
);
|
|
282
|
+
render(<Select items={fruits} defaultOpen onValueChange={onChange} />);
|
|
283
283
|
|
|
284
284
|
await userEvent.click(screen.getByRole("option", { name: "Banana" }));
|
|
285
285
|
|
|
@@ -353,12 +353,14 @@ export function Select<TItem = unknown>(
|
|
|
353
353
|
multiple,
|
|
354
354
|
className,
|
|
355
355
|
classNames,
|
|
356
|
+
"aria-invalid": ariaInvalid,
|
|
356
357
|
...rest
|
|
357
358
|
} = allProps as SelectBaseProps<TItem> & {
|
|
358
359
|
multiple?: boolean;
|
|
359
360
|
onValueChange?: (value: any) => void;
|
|
360
361
|
value?: any;
|
|
361
362
|
defaultValue?: any;
|
|
363
|
+
"aria-invalid"?: React.AriaAttributes["aria-invalid"];
|
|
362
364
|
};
|
|
363
365
|
|
|
364
366
|
const getLabel: (item: TItem) => string = getLabelProp ?? defaultGetLabel;
|
|
@@ -410,7 +412,13 @@ export function Select<TItem = unknown>(
|
|
|
410
412
|
onValueChange={handleChange as any}
|
|
411
413
|
{...(rest as any)}
|
|
412
414
|
>
|
|
413
|
-
<SelectTrigger
|
|
415
|
+
<SelectTrigger
|
|
416
|
+
className={className}
|
|
417
|
+
// Only forward `aria-invalid` when explicitly set. Base UI's Field
|
|
418
|
+
// integration already sets it from validity state; passing `undefined`
|
|
419
|
+
// here would clobber that value during prop merge and drop the error border.
|
|
420
|
+
{...(ariaInvalid === undefined ? {} : { "aria-invalid": ariaInvalid })}
|
|
421
|
+
>
|
|
414
422
|
<SelectValue placeholder={placeholder} />
|
|
415
423
|
</SelectTrigger>
|
|
416
424
|
<SelectPopup className={classNames?.popup}>
|
|
@@ -411,13 +411,14 @@ const wizardSteps = [
|
|
|
411
411
|
|
|
412
412
|
/**
|
|
413
413
|
* Linear wizard driven by `useStep`. Note the index translation: `useStep` is
|
|
414
|
-
* **0-indexed**, the stepper is **1-indexed**. Feed it `
|
|
414
|
+
* **0-indexed**, the stepper is **1-indexed**. Feed it `index + 1` as `value`
|
|
415
415
|
* and bridge `onValueChange` back with `goTo(value - 1)`.
|
|
416
416
|
*
|
|
417
417
|
* ```tsx
|
|
418
|
-
* const {
|
|
418
|
+
* const [index, { goTo, next, back }] = useStep(steps.length);
|
|
419
|
+
* const currentStep = steps[index];
|
|
419
420
|
* <Stepper
|
|
420
|
-
* value={
|
|
421
|
+
* value={index + 1}
|
|
421
422
|
* onValueChange={(value) => goTo(value - 1)}
|
|
422
423
|
* items={steps}
|
|
423
424
|
* />
|
|
@@ -425,20 +426,15 @@ const wizardSteps = [
|
|
|
425
426
|
*/
|
|
426
427
|
export const Wizard: Story = {
|
|
427
428
|
render: () => {
|
|
428
|
-
const {
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
isLastStep,
|
|
433
|
-
next,
|
|
434
|
-
back,
|
|
435
|
-
goTo,
|
|
436
|
-
} = useStep(wizardSteps);
|
|
429
|
+
const [index, { isFirstStep, isLastStep, next, back, goTo }] = useStep(
|
|
430
|
+
wizardSteps.length,
|
|
431
|
+
);
|
|
432
|
+
const currentStep = wizardSteps[index];
|
|
437
433
|
|
|
438
434
|
return (
|
|
439
435
|
<div className="w-[840px] space-y-6">
|
|
440
436
|
<Stepper
|
|
441
|
-
value={
|
|
437
|
+
value={index + 1}
|
|
442
438
|
onValueChange={(value) => goTo(value - 1)}
|
|
443
439
|
indicators={{ completed: <CheckIcon className="size-3.5" /> }}
|
|
444
440
|
items={wizardSteps.map((s) => ({
|
|
@@ -447,9 +443,9 @@ export const Wizard: Story = {
|
|
|
447
443
|
}))}
|
|
448
444
|
/>
|
|
449
445
|
<div className="rounded-lg border p-6">
|
|
450
|
-
<p className="font-medium text-sm">{
|
|
446
|
+
<p className="font-medium text-sm">{currentStep.title}</p>
|
|
451
447
|
<p className="mt-1 text-muted-foreground text-sm">
|
|
452
|
-
{
|
|
448
|
+
{currentStep.description}
|
|
453
449
|
</p>
|
|
454
450
|
</div>
|
|
455
451
|
<div className="flex justify-between">
|
|
@@ -167,7 +167,9 @@ describe("Stepper data-slots", () => {
|
|
|
167
167
|
|
|
168
168
|
it("StepperTrigger renders with data-slot='stepper-trigger'", () => {
|
|
169
169
|
render(<TwoStepStepper />);
|
|
170
|
-
expect(
|
|
170
|
+
expect(
|
|
171
|
+
document.querySelector('[data-slot="stepper-trigger"]'),
|
|
172
|
+
).toBeTruthy();
|
|
171
173
|
});
|
|
172
174
|
|
|
173
175
|
it("StepperIndicator renders with data-slot='stepper-indicator'", () => {
|
|
@@ -329,9 +331,9 @@ describe("Stepper loading state", () => {
|
|
|
329
331
|
</StepperNav>
|
|
330
332
|
</StepperRoot>,
|
|
331
333
|
);
|
|
332
|
-
expect(
|
|
333
|
-
|
|
334
|
-
);
|
|
334
|
+
expect(
|
|
335
|
+
document.querySelector('[data-slot="stepper-item"]'),
|
|
336
|
+
).toHaveAttribute("data-loading");
|
|
335
337
|
});
|
|
336
338
|
});
|
|
337
339
|
|