@funstack/ui 0.1.0-alpha.1 → 0.1.0-alpha.3
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/accordion/accordion-context.mjs.map +1 -1
- package/dist/accordion/accordion-item.mjs +18 -4
- package/dist/accordion/accordion-item.mjs.map +1 -1
- package/dist/accordion/accordion-panel.mjs +2 -3
- package/dist/accordion/accordion-panel.mjs.map +1 -1
- package/dist/accordion/accordion-root.d.mts.map +1 -1
- package/dist/accordion/accordion-root.mjs +32 -14
- package/dist/accordion/accordion-root.mjs.map +1 -1
- package/dist/accordion/accordion-trigger.mjs +4 -5
- package/dist/accordion/accordion-trigger.mjs.map +1 -1
- package/dist/checkbox/checkbox.d.mts +5 -3
- package/dist/checkbox/checkbox.d.mts.map +1 -1
- package/dist/checkbox/checkbox.mjs +25 -9
- package/dist/checkbox/checkbox.mjs.map +1 -1
- package/dist/checkbox-group/checkbox-group-context.mjs.map +1 -1
- package/dist/checkbox-group/checkbox-group-item.d.mts +2 -1
- package/dist/checkbox-group/checkbox-group-item.d.mts.map +1 -1
- package/dist/checkbox-group/checkbox-group-item.mjs +3 -1
- package/dist/checkbox-group/checkbox-group-item.mjs.map +1 -1
- package/dist/checkbox-group/checkbox-group-root.d.mts +5 -2
- package/dist/checkbox-group/checkbox-group-root.d.mts.map +1 -1
- package/dist/checkbox-group/checkbox-group-root.mjs +24 -5
- package/dist/checkbox-group/checkbox-group-root.mjs.map +1 -1
- package/dist/combobox/combobox-clear.d.mts +34 -0
- package/dist/combobox/combobox-clear.d.mts.map +1 -0
- package/dist/combobox/combobox-clear.mjs +58 -0
- package/dist/combobox/combobox-clear.mjs.map +1 -0
- package/dist/combobox/combobox-context.mjs +23 -0
- package/dist/combobox/combobox-context.mjs.map +1 -0
- package/dist/combobox/combobox-group.d.mts +72 -0
- package/dist/combobox/combobox-group.d.mts.map +1 -0
- package/dist/combobox/combobox-group.mjs +104 -0
- package/dist/combobox/combobox-group.mjs.map +1 -0
- package/dist/combobox/combobox-input.d.mts +42 -0
- package/dist/combobox/combobox-input.d.mts.map +1 -0
- package/dist/combobox/combobox-input.mjs +102 -0
- package/dist/combobox/combobox-input.mjs.map +1 -0
- package/dist/combobox/combobox-label.d.mts +22 -0
- package/dist/combobox/combobox-label.d.mts.map +1 -0
- package/dist/combobox/combobox-label.mjs +32 -0
- package/dist/combobox/combobox-label.mjs.map +1 -0
- package/dist/combobox/combobox-list.d.mts +37 -0
- package/dist/combobox/combobox-list.d.mts.map +1 -0
- package/dist/combobox/combobox-list.mjs +70 -0
- package/dist/combobox/combobox-list.mjs.map +1 -0
- package/dist/combobox/combobox-option.d.mts +45 -0
- package/dist/combobox/combobox-option.d.mts.map +1 -0
- package/dist/combobox/combobox-option.mjs +88 -0
- package/dist/combobox/combobox-option.mjs.map +1 -0
- package/dist/combobox/combobox-popup.d.mts +49 -0
- package/dist/combobox/combobox-popup.d.mts.map +1 -0
- package/dist/combobox/combobox-popup.mjs +86 -0
- package/dist/combobox/combobox-popup.mjs.map +1 -0
- package/dist/combobox/combobox-root.d.mts +135 -0
- package/dist/combobox/combobox-root.d.mts.map +1 -0
- package/dist/combobox/combobox-root.mjs +523 -0
- package/dist/combobox/combobox-root.mjs.map +1 -0
- package/dist/combobox/combobox-trigger.d.mts +36 -0
- package/dist/combobox/combobox-trigger.d.mts.map +1 -0
- package/dist/combobox/combobox-trigger.mjs +92 -0
- package/dist/combobox/combobox-trigger.mjs.map +1 -0
- package/dist/combobox/index.d.mts +36 -0
- package/dist/combobox/index.d.mts.map +1 -0
- package/dist/combobox/index.mjs +36 -0
- package/dist/combobox/index.mjs.map +1 -0
- package/dist/dialog/dialog-close.d.mts +17 -10
- package/dist/dialog/dialog-close.d.mts.map +1 -1
- package/dist/dialog/dialog-close.mjs +31 -20
- package/dist/dialog/dialog-close.mjs.map +1 -1
- package/dist/dialog/dialog-context.mjs.map +1 -1
- package/dist/dialog/dialog-form.d.mts +12 -5
- package/dist/dialog/dialog-form.d.mts.map +1 -1
- package/dist/dialog/dialog-form.mjs +16 -28
- package/dist/dialog/dialog-form.mjs.map +1 -1
- package/dist/dialog/dialog-popup.d.mts +10 -4
- package/dist/dialog/dialog-popup.d.mts.map +1 -1
- package/dist/dialog/dialog-popup.mjs +106 -41
- package/dist/dialog/dialog-popup.mjs.map +1 -1
- package/dist/dialog/dialog-root.d.mts +14 -8
- package/dist/dialog/dialog-root.d.mts.map +1 -1
- package/dist/dialog/dialog-root.mjs +66 -11
- package/dist/dialog/dialog-root.mjs.map +1 -1
- package/dist/dialog/dialog-trigger.d.mts +3 -2
- package/dist/dialog/dialog-trigger.d.mts.map +1 -1
- package/dist/dialog/dialog-trigger.mjs.map +1 -1
- package/dist/dialog/index.d.mts +4 -2
- package/dist/dialog/index.d.mts.map +1 -1
- package/dist/dialog/index.mjs +4 -2
- package/dist/dialog/index.mjs.map +1 -1
- package/dist/field/field-control.d.mts +33 -0
- package/dist/field/field-control.d.mts.map +1 -0
- package/dist/field/field-control.mjs +68 -0
- package/dist/field/field-control.mjs.map +1 -0
- package/dist/field/field-description.d.mts +24 -0
- package/dist/field/field-description.d.mts.map +1 -0
- package/dist/field/field-description.mjs +34 -0
- package/dist/field/field-description.mjs.map +1 -0
- package/dist/field/field-error.d.mts +30 -0
- package/dist/field/field-error.d.mts.map +1 -0
- package/dist/field/field-error.mjs +42 -0
- package/dist/field/field-error.mjs.map +1 -0
- package/dist/field/field-label.d.mts +25 -0
- package/dist/field/field-label.d.mts.map +1 -0
- package/dist/field/field-label.mjs +46 -0
- package/dist/field/field-label.mjs.map +1 -0
- package/dist/field/field-root.d.mts +53 -0
- package/dist/field/field-root.d.mts.map +1 -0
- package/dist/field/field-root.mjs +317 -0
- package/dist/field/field-root.mjs.map +1 -0
- package/dist/field/index.d.mts +18 -0
- package/dist/field/index.d.mts.map +1 -0
- package/dist/field/index.mjs +17 -0
- package/dist/field/index.mjs.map +1 -0
- package/dist/form/form-root.d.mts +58 -0
- package/dist/form/form-root.d.mts.map +1 -0
- package/dist/form/form-root.mjs +146 -0
- package/dist/form/form-root.mjs.map +1 -0
- package/dist/form/form-submit.d.mts +31 -0
- package/dist/form/form-submit.d.mts.map +1 -0
- package/dist/form/form-submit.mjs +52 -0
- package/dist/form/form-submit.mjs.map +1 -0
- package/dist/form/index.d.mts +11 -0
- package/dist/form/index.d.mts.map +1 -0
- package/dist/form/index.mjs +11 -0
- package/dist/form/index.mjs.map +1 -0
- package/dist/index.d.mts +46 -2
- package/dist/index.mjs +8 -1
- package/dist/internal/content-focus-probe.mjs +42 -0
- package/dist/internal/content-focus-probe.mjs.map +1 -0
- package/dist/internal/field-context.d.mts +19 -0
- package/dist/internal/field-context.d.mts.map +1 -0
- package/dist/internal/field-context.mjs +14 -0
- package/dist/internal/field-context.mjs.map +1 -0
- package/dist/internal/focus-first-invalid.mjs +67 -0
- package/dist/internal/focus-first-invalid.mjs.map +1 -0
- package/dist/internal/form-status-watcher.mjs +31 -0
- package/dist/internal/form-status-watcher.mjs.map +1 -0
- package/dist/internal/modal-registry.mjs +39 -0
- package/dist/internal/modal-registry.mjs.map +1 -0
- package/dist/internal/platform-attributes.d.mts +12 -1
- package/dist/internal/platform-attributes.d.mts.map +1 -1
- package/dist/internal/types.d.mts +11 -1
- package/dist/internal/types.d.mts.map +1 -1
- package/dist/internal/use-controllable-action.mjs +35 -13
- package/dist/internal/use-controllable-action.mjs.map +1 -1
- package/dist/internal/use-field-control.mjs +107 -0
- package/dist/internal/use-field-control.mjs.map +1 -0
- package/dist/internal/use-form-owner-event.mjs +44 -0
- package/dist/internal/use-form-owner-event.mjs.map +1 -0
- package/dist/internal/use-form-reset.mjs +12 -31
- package/dist/internal/use-form-reset.mjs.map +1 -1
- package/dist/internal/use-hydrated-mount.mjs +21 -0
- package/dist/internal/use-hydrated-mount.mjs.map +1 -0
- package/dist/internal/use-latest.mjs +32 -0
- package/dist/internal/use-latest.mjs.map +1 -0
- package/dist/internal/use-modal-registration.mjs +47 -0
- package/dist/internal/use-modal-registration.mjs.map +1 -0
- package/dist/internal/use-native-group-reconciliation.mjs +6 -5
- package/dist/internal/use-native-group-reconciliation.mjs.map +1 -1
- package/dist/internal/use-native-select-value.mjs +184 -0
- package/dist/internal/use-native-select-value.mjs.map +1 -0
- package/dist/internal/use-popover-popup.mjs +8 -22
- package/dist/internal/use-popover-popup.mjs.map +1 -1
- package/dist/internal/use-popover-root.mjs +58 -23
- package/dist/internal/use-popover-root.mjs.map +1 -1
- package/dist/internal/validity.d.mts +24 -0
- package/dist/internal/validity.d.mts.map +1 -0
- package/dist/internal/validity.mjs +108 -0
- package/dist/internal/validity.mjs.map +1 -0
- package/dist/menu/menu-group.d.mts.map +1 -1
- package/dist/menu/menu-group.mjs +3 -2
- package/dist/menu/menu-group.mjs.map +1 -1
- package/dist/menu/menu-radio-group.mjs +9 -4
- package/dist/menu/menu-radio-group.mjs.map +1 -1
- package/dist/menu/menu-root.mjs.map +1 -1
- package/dist/radio-group/radio-group-root.d.mts +4 -2
- package/dist/radio-group/radio-group-root.d.mts.map +1 -1
- package/dist/radio-group/radio-group-root.mjs +34 -8
- package/dist/radio-group/radio-group-root.mjs.map +1 -1
- package/dist/select/index.d.mts +30 -0
- package/dist/select/index.d.mts.map +1 -0
- package/dist/select/index.mjs +30 -0
- package/dist/select/index.mjs.map +1 -0
- package/dist/select/select-context.mjs +13 -0
- package/dist/select/select-context.mjs.map +1 -0
- package/dist/select/select-dom.mjs +44 -0
- package/dist/select/select-dom.mjs.map +1 -0
- package/dist/select/select-group-label.d.mts +22 -0
- package/dist/select/select-group-label.d.mts.map +1 -0
- package/dist/select/select-group-label.mjs +39 -0
- package/dist/select/select-group-label.mjs.map +1 -0
- package/dist/select/select-group.d.mts +28 -0
- package/dist/select/select-group.d.mts.map +1 -0
- package/dist/select/select-group.mjs +47 -0
- package/dist/select/select-group.mjs.map +1 -0
- package/dist/select/select-option.d.mts +42 -0
- package/dist/select/select-option.d.mts.map +1 -0
- package/dist/select/select-option.mjs +65 -0
- package/dist/select/select-option.mjs.map +1 -0
- package/dist/select/select-root.d.mts +68 -0
- package/dist/select/select-root.d.mts.map +1 -0
- package/dist/select/select-root.mjs +114 -0
- package/dist/select/select-root.mjs.map +1 -0
- package/dist/select/select-separator.d.mts +20 -0
- package/dist/select/select-separator.d.mts.map +1 -0
- package/dist/select/select-separator.mjs +30 -0
- package/dist/select/select-separator.mjs.map +1 -0
- package/dist/select/select-trigger.d.mts +29 -0
- package/dist/select/select-trigger.d.mts.map +1 -0
- package/dist/select/select-trigger.mjs +48 -0
- package/dist/select/select-trigger.mjs.map +1 -0
- package/dist/select/select-value.d.mts +31 -0
- package/dist/select/select-value.d.mts.map +1 -0
- package/dist/select/select-value.mjs +101 -0
- package/dist/select/select-value.mjs.map +1 -0
- package/dist/slider/index.d.mts +32 -0
- package/dist/slider/index.d.mts.map +1 -0
- package/dist/slider/index.mjs +27 -0
- package/dist/slider/index.mjs.map +1 -0
- package/dist/slider/slider-arithmetic.mjs +120 -0
- package/dist/slider/slider-arithmetic.mjs.map +1 -0
- package/dist/slider/slider-context.mjs +13 -0
- package/dist/slider/slider-context.mjs.map +1 -0
- package/dist/slider/slider-indicator.d.mts +22 -0
- package/dist/slider/slider-indicator.d.mts.map +1 -0
- package/dist/slider/slider-indicator.mjs +36 -0
- package/dist/slider/slider-indicator.mjs.map +1 -0
- package/dist/slider/slider-label.d.mts +23 -0
- package/dist/slider/slider-label.d.mts.map +1 -0
- package/dist/slider/slider-label.mjs +44 -0
- package/dist/slider/slider-label.mjs.map +1 -0
- package/dist/slider/slider-root.d.mts +111 -0
- package/dist/slider/slider-root.d.mts.map +1 -0
- package/dist/slider/slider-root.mjs +582 -0
- package/dist/slider/slider-root.mjs.map +1 -0
- package/dist/slider/slider-thumb.d.mts +58 -0
- package/dist/slider/slider-thumb.d.mts.map +1 -0
- package/dist/slider/slider-thumb.mjs +145 -0
- package/dist/slider/slider-thumb.mjs.map +1 -0
- package/dist/slider/slider-track.d.mts +29 -0
- package/dist/slider/slider-track.d.mts.map +1 -0
- package/dist/slider/slider-track.mjs +54 -0
- package/dist/slider/slider-track.mjs.map +1 -0
- package/dist/slider/slider-value.d.mts +34 -0
- package/dist/slider/slider-value.d.mts.map +1 -0
- package/dist/slider/slider-value.mjs +38 -0
- package/dist/slider/slider-value.mjs.map +1 -0
- package/dist/switch/switch.d.mts +5 -3
- package/dist/switch/switch.d.mts.map +1 -1
- package/dist/switch/switch.mjs +24 -8
- package/dist/switch/switch.mjs.map +1 -1
- package/dist/tabs/tabs-root.mjs +13 -3
- package/dist/tabs/tabs-root.mjs.map +1 -1
- package/dist/toast/index.d.mts +25 -0
- package/dist/toast/index.d.mts.map +1 -0
- package/dist/toast/index.mjs +26 -0
- package/dist/toast/index.mjs.map +1 -0
- package/dist/toast/toast-action.d.mts +39 -0
- package/dist/toast/toast-action.d.mts.map +1 -0
- package/dist/toast/toast-action.mjs +64 -0
- package/dist/toast/toast-action.mjs.map +1 -0
- package/dist/toast/toast-close.d.mts +25 -0
- package/dist/toast/toast-close.d.mts.map +1 -0
- package/dist/toast/toast-close.mjs +46 -0
- package/dist/toast/toast-close.mjs.map +1 -0
- package/dist/toast/toast-context.mjs +19 -0
- package/dist/toast/toast-context.mjs.map +1 -0
- package/dist/toast/toast-description.d.mts +24 -0
- package/dist/toast/toast-description.d.mts.map +1 -0
- package/dist/toast/toast-description.mjs +35 -0
- package/dist/toast/toast-description.mjs.map +1 -0
- package/dist/toast/toast-root.d.mts +43 -0
- package/dist/toast/toast-root.d.mts.map +1 -0
- package/dist/toast/toast-root.mjs +204 -0
- package/dist/toast/toast-root.mjs.map +1 -0
- package/dist/toast/toast-title.d.mts +24 -0
- package/dist/toast/toast-title.d.mts.map +1 -0
- package/dist/toast/toast-title.mjs +33 -0
- package/dist/toast/toast-title.mjs.map +1 -0
- package/dist/toast/toast-viewport.d.mts +52 -0
- package/dist/toast/toast-viewport.d.mts.map +1 -0
- package/dist/toast/toast-viewport.mjs +621 -0
- package/dist/toast/toast-viewport.mjs.map +1 -0
- package/dist/toast/toast.d.mts +119 -0
- package/dist/toast/toast.d.mts.map +1 -0
- package/dist/toast/toast.mjs +153 -0
- package/dist/toast/toast.mjs.map +1 -0
- package/package.json +7 -1
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import { RenderProp, StateValue } from "../internal/types.mjs";
|
|
2
|
+
import { SelectRootState } from "./select-root.mjs";
|
|
3
|
+
import { CSSProperties, ComponentPropsWithRef, ReactNode } from "react";
|
|
4
|
+
//#region src/select/select-trigger.d.ts
|
|
5
|
+
export interface SelectTriggerProps extends Omit<ComponentPropsWithRef<"button">, "type" | "className" | "style" | "children"> {
|
|
6
|
+
className?: StateValue<string | undefined, SelectRootState>;
|
|
7
|
+
style?: StateValue<CSSProperties | undefined, SelectRootState>;
|
|
8
|
+
/**
|
|
9
|
+
* Non-interactive content only (HTML content model of a select's button), usually
|
|
10
|
+
* `<Select.Value />`. Not rendered by engines without customizable select (Firefox today).
|
|
11
|
+
*/
|
|
12
|
+
children?: StateValue<ReactNode, SelectRootState>;
|
|
13
|
+
/** Replace the rendered element. Must keep a `<button>`. */
|
|
14
|
+
render?: RenderProp<ComponentPropsWithRef<"button">, SelectRootState>;
|
|
15
|
+
}
|
|
16
|
+
/**
|
|
17
|
+
* The select's own `<button>` (customizable select): replaces the UA button in engines with
|
|
18
|
+
* `appearance: base-select`. Optional; **must be the first child** of `Select.Root`. Its state is
|
|
19
|
+
* the Root's state, so a pending indicator next to `<Select.Value />` goes in its function
|
|
20
|
+
* `children`.
|
|
21
|
+
*
|
|
22
|
+
* Owned keys: `type` (always `"button"`), `data-pending`, `data-disabled`.
|
|
23
|
+
*/
|
|
24
|
+
export declare function SelectTrigger({ className, style, children, render, ...rest }: SelectTriggerProps): ReactNode;
|
|
25
|
+
export declare namespace SelectTrigger {
|
|
26
|
+
var displayName: string;
|
|
27
|
+
}
|
|
28
|
+
//#endregion
|
|
29
|
+
//# sourceMappingURL=select-trigger.d.mts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"select-trigger.d.mts","names":[],"sources":["../../src/select/select-trigger.tsx"],"mappings":";;;;iBASiB,2BAA2B,KAC1C;EAGA,YAAY,+BAA+B;EAC3C,QAAQ,WAAW,2BAA2B;;;;;EAK9C,WAAW,WAAW,WAAW;;EAEjC,SAAS,WAAW,iCAAiC;;;;;;;;;;wBAoBvC,gBAAgB,WAAW,OAAO,UAAU,WAAW,QAAQ,qBAAkB;yBAAjF"}
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { dataAttr } from "../internal/data-attr.mjs";
|
|
3
|
+
import { useRender } from "../internal/use-render.mjs";
|
|
4
|
+
import { useSelectContext } from "./select-context.mjs";
|
|
5
|
+
import { useSelectPartRef } from "./select-dom.mjs";
|
|
6
|
+
//#region src/select/select-trigger.tsx
|
|
7
|
+
function firstChildOfSelect(el) {
|
|
8
|
+
const parent = el.parentElement;
|
|
9
|
+
if (parent?.tagName === "SELECT" && parent.firstElementChild === el) return null;
|
|
10
|
+
return "must be the first child of Select.Root's <select> (HTML content model); elsewhere the browser does not use it as the select's button.";
|
|
11
|
+
}
|
|
12
|
+
/**
|
|
13
|
+
* The select's own `<button>` (customizable select): replaces the UA button in engines with
|
|
14
|
+
* `appearance: base-select`. Optional; **must be the first child** of `Select.Root`. Its state is
|
|
15
|
+
* the Root's state, so a pending indicator next to `<Select.Value />` goes in its function
|
|
16
|
+
* `children`.
|
|
17
|
+
*
|
|
18
|
+
* Owned keys: `type` (always `"button"`), `data-pending`, `data-disabled`.
|
|
19
|
+
*/
|
|
20
|
+
function SelectTrigger({ className, style, children, render, ...rest }) {
|
|
21
|
+
const ctx = useSelectContext("Select.Trigger");
|
|
22
|
+
const state = {
|
|
23
|
+
value: ctx.optimistic,
|
|
24
|
+
pending: ctx.pending,
|
|
25
|
+
disabled: ctx.disabled
|
|
26
|
+
};
|
|
27
|
+
const { ref } = useSelectPartRef("Select.Trigger", "button", firstChildOfSelect);
|
|
28
|
+
return useRender({
|
|
29
|
+
defaultElement: "button",
|
|
30
|
+
render,
|
|
31
|
+
state,
|
|
32
|
+
className,
|
|
33
|
+
style,
|
|
34
|
+
children,
|
|
35
|
+
props: rest,
|
|
36
|
+
libraryProps: {
|
|
37
|
+
type: "button",
|
|
38
|
+
"data-pending": dataAttr(ctx.pending),
|
|
39
|
+
"data-disabled": dataAttr(ctx.disabled)
|
|
40
|
+
},
|
|
41
|
+
ref
|
|
42
|
+
});
|
|
43
|
+
}
|
|
44
|
+
SelectTrigger.displayName = "SelectTrigger";
|
|
45
|
+
//#endregion
|
|
46
|
+
export { SelectTrigger };
|
|
47
|
+
|
|
48
|
+
//# sourceMappingURL=select-trigger.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"select-trigger.mjs","names":[],"sources":["../../src/select/select-trigger.tsx"],"sourcesContent":["\"use client\";\nimport type { ComponentPropsWithRef, CSSProperties, ReactNode } from \"react\";\nimport { dataAttr } from \"../internal/data-attr.js\";\nimport type { RenderProp, StateValue } from \"../internal/types.js\";\nimport { useRender } from \"../internal/use-render.js\";\nimport { useSelectContext } from \"./select-context.js\";\nimport { useSelectPartRef } from \"./select-dom.js\";\nimport type { SelectRootState } from \"./select-root.js\";\n\nexport interface SelectTriggerProps extends Omit<\n ComponentPropsWithRef<\"button\">,\n \"type\" | \"className\" | \"style\" | \"children\"\n> {\n className?: StateValue<string | undefined, SelectRootState>;\n style?: StateValue<CSSProperties | undefined, SelectRootState>;\n /**\n * Non-interactive content only (HTML content model of a select's button), usually\n * `<Select.Value />`. Not rendered by engines without customizable select (Firefox today).\n */\n children?: StateValue<ReactNode, SelectRootState>;\n /** Replace the rendered element. Must keep a `<button>`. */\n render?: RenderProp<ComponentPropsWithRef<\"button\">, SelectRootState>;\n}\n\nfunction firstChildOfSelect(el: HTMLButtonElement): string | null {\n const parent = el.parentElement;\n if (parent?.tagName === \"SELECT\" && parent.firstElementChild === el) return null;\n return (\n \"must be the first child of Select.Root's <select> (HTML content model); elsewhere the \" +\n \"browser does not use it as the select's button.\"\n );\n}\n\n/**\n * The select's own `<button>` (customizable select): replaces the UA button in engines with\n * `appearance: base-select`. Optional; **must be the first child** of `Select.Root`. Its state is\n * the Root's state, so a pending indicator next to `<Select.Value />` goes in its function\n * `children`.\n *\n * Owned keys: `type` (always `\"button\"`), `data-pending`, `data-disabled`.\n */\nexport function SelectTrigger({ className, style, children, render, ...rest }: SelectTriggerProps) {\n const ctx = useSelectContext(\"Select.Trigger\");\n const state: SelectRootState = {\n value: ctx.optimistic,\n pending: ctx.pending,\n disabled: ctx.disabled,\n };\n const { ref } = useSelectPartRef<HTMLButtonElement>(\n \"Select.Trigger\",\n \"button\",\n firstChildOfSelect,\n );\n return useRender<ComponentPropsWithRef<\"button\">, SelectRootState>({\n defaultElement: \"button\",\n render,\n state,\n className,\n style,\n children,\n props: rest,\n libraryProps: {\n // Explicit: Chromium 156 reports `.type === \"submit\"` for a select's button.\n type: \"button\",\n \"data-pending\": dataAttr(ctx.pending),\n \"data-disabled\": dataAttr(ctx.disabled),\n },\n ref,\n });\n}\n\nSelectTrigger.displayName = \"SelectTrigger\";\n"],"mappings":";;;;;;AAwBA,SAAS,mBAAmB,IAAsC;CAChE,MAAM,SAAS,GAAG;CAClB,IAAI,QAAQ,YAAY,YAAY,OAAO,sBAAsB,IAAI,OAAO;CAC5E,OACE;AAGJ;;;;;;;;;AAUA,SAAgB,cAAc,EAAE,WAAW,OAAO,UAAU,QAAQ,GAAG,QAA4B;CACjG,MAAM,MAAM,iBAAiB,gBAAgB;CAC7C,MAAM,QAAyB;EAC7B,OAAO,IAAI;EACX,SAAS,IAAI;EACb,UAAU,IAAI;CAChB;CACA,MAAM,EAAE,QAAQ,iBACd,kBACA,UACA,kBACF;CACA,OAAO,UAA4D;EACjE,gBAAgB;EAChB;EACA;EACA;EACA;EACA;EACA,OAAO;EACP,cAAc;GAEZ,MAAM;GACN,gBAAgB,SAAS,IAAI,OAAO;GACpC,iBAAiB,SAAS,IAAI,QAAQ;EACxC;EACA;CACF,CAAC;AACH;AAEA,cAAc,cAAc"}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import { RenderProp, StateValue } from "../internal/types.mjs";
|
|
2
|
+
import { SelectRootState } from "./select-root.mjs";
|
|
3
|
+
import { CSSProperties, ComponentPropsWithRef } from "react";
|
|
4
|
+
//#region src/select/select-value.d.ts
|
|
5
|
+
export interface SelectValueProps extends Omit<ComponentPropsWithRef<"selectedcontent">, "children" | "dangerouslySetInnerHTML" | "className" | "style"> {
|
|
6
|
+
className?: StateValue<string | undefined, SelectRootState>;
|
|
7
|
+
style?: StateValue<CSSProperties | undefined, SelectRootState>;
|
|
8
|
+
/** Replace the rendered element. Must keep a `<selectedcontent>`. */
|
|
9
|
+
render?: RenderProp<ComponentPropsWithRef<"selectedcontent">, SelectRootState>;
|
|
10
|
+
}
|
|
11
|
+
/**
|
|
12
|
+
* `<selectedcontent>`: the browser clones the selected option's content into it (inside
|
|
13
|
+
* `Select.Trigger`). It has no `children`. Rendered with `suppressHydrationWarning` and an empty
|
|
14
|
+
* `dangerouslySetInnerHTML` so that hydration accepts the content the parser cloned before React
|
|
15
|
+
* ran (design/components/select.md 3.3).
|
|
16
|
+
*
|
|
17
|
+
* Also keeps it fresh: the platform re-clones only on selection changes, so when React changes
|
|
18
|
+
* the selected option's content (a label, a state function, a Suspense boundary resolving inside
|
|
19
|
+
* it), a `MutationObserver` re-assigns `select.value = select.value`, which re-clones without
|
|
20
|
+
* events and without touching the selection or an open picker (6.3). The same refresh follows a
|
|
21
|
+
* form reset, which Chromium does not re-clone for. Not installed where
|
|
22
|
+
* `HTMLSelectedContentElement` is undefined (Firefox today, jsdom): nothing is cloned there.
|
|
23
|
+
*
|
|
24
|
+
* Owned keys: `dangerouslySetInnerHTML`, `suppressHydrationWarning`, `children`.
|
|
25
|
+
*/
|
|
26
|
+
export declare function SelectValue({ className, style, render, ...rest }: SelectValueProps): import("react").ReactNode;
|
|
27
|
+
export declare namespace SelectValue {
|
|
28
|
+
var displayName: string;
|
|
29
|
+
}
|
|
30
|
+
//#endregion
|
|
31
|
+
//# sourceMappingURL=select-value.d.mts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"select-value.d.mts","names":[],"sources":["../../src/select/select-value.tsx"],"mappings":";;;;iBAYiB,yBAAyB,KACxC;EAGA,YAAY,+BAA+B;EAC3C,QAAQ,WAAW,2BAA2B;;EAE9C,SAAS,WAAW,0CAA0C;;;;;;;;;;;;;;;;;wBA2ChD,cAAc,WAAW,OAAO,WAAW,QAAQ,mCAAgB;yBAAnE"}
|
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { useRender } from "../internal/use-render.mjs";
|
|
3
|
+
import { useFormReset } from "../internal/use-form-reset.mjs";
|
|
4
|
+
import { useSelectContext } from "./select-context.mjs";
|
|
5
|
+
import { useSelectPartRef } from "./select-dom.mjs";
|
|
6
|
+
import { useLayoutEffect, useMemo } from "react";
|
|
7
|
+
//#region src/select/select-value.tsx
|
|
8
|
+
const isDev = process.env.NODE_ENV !== "production";
|
|
9
|
+
/** Where the browser clones options into `<selectedcontent>` (Chromium 135+, Safari 27). */
|
|
10
|
+
function supportsSelectedContent() {
|
|
11
|
+
return typeof globalThis !== "undefined" && "HTMLSelectedContentElement" in globalThis;
|
|
12
|
+
}
|
|
13
|
+
/**
|
|
14
|
+
* Whether a mutation record changes what `<selectedcontent>` shows: a record inside the selected
|
|
15
|
+
* option. Attribute records on the option element itself are ignored (option attributes are not
|
|
16
|
+
* cloned, and the library writes `data-*` there); records inside `<selectedcontent>` are never
|
|
17
|
+
* inside an option, so the refresh's own clone does not loop.
|
|
18
|
+
*/
|
|
19
|
+
function touchesSelected(record, selected) {
|
|
20
|
+
if (record.type === "attributes" && record.target === selected) return false;
|
|
21
|
+
return selected.contains(record.target);
|
|
22
|
+
}
|
|
23
|
+
/** Re-clones the selected option into `<selectedcontent>`. */
|
|
24
|
+
function refresh(select) {
|
|
25
|
+
if (select.selectedIndex === -1) return;
|
|
26
|
+
select.value = select.value;
|
|
27
|
+
}
|
|
28
|
+
/**
|
|
29
|
+
* `<selectedcontent>`: the browser clones the selected option's content into it (inside
|
|
30
|
+
* `Select.Trigger`). It has no `children`. Rendered with `suppressHydrationWarning` and an empty
|
|
31
|
+
* `dangerouslySetInnerHTML` so that hydration accepts the content the parser cloned before React
|
|
32
|
+
* ran (design/components/select.md 3.3).
|
|
33
|
+
*
|
|
34
|
+
* Also keeps it fresh: the platform re-clones only on selection changes, so when React changes
|
|
35
|
+
* the selected option's content (a label, a state function, a Suspense boundary resolving inside
|
|
36
|
+
* it), a `MutationObserver` re-assigns `select.value = select.value`, which re-clones without
|
|
37
|
+
* events and without touching the selection or an open picker (6.3). The same refresh follows a
|
|
38
|
+
* form reset, which Chromium does not re-clone for. Not installed where
|
|
39
|
+
* `HTMLSelectedContentElement` is undefined (Firefox today, jsdom): nothing is cloned there.
|
|
40
|
+
*
|
|
41
|
+
* Owned keys: `dangerouslySetInnerHTML`, `suppressHydrationWarning`, `children`.
|
|
42
|
+
*/
|
|
43
|
+
function SelectValue({ className, style, render, ...rest }) {
|
|
44
|
+
const ctx = useSelectContext("Select.Value");
|
|
45
|
+
const { ref, node } = useSelectPartRef("Select.Value", "selectedcontent");
|
|
46
|
+
useLayoutEffect(() => {
|
|
47
|
+
const el = node.current;
|
|
48
|
+
if (el === null) return;
|
|
49
|
+
const select = el.closest("select");
|
|
50
|
+
if (select === null) {
|
|
51
|
+
if (isDev) console.error("Select.Value: rendered outside the Select.Root's <select>; put it inside Select.Trigger, the select's first child.");
|
|
52
|
+
return;
|
|
53
|
+
}
|
|
54
|
+
if (!supportsSelectedContent()) return;
|
|
55
|
+
const observer = new MutationObserver((records) => {
|
|
56
|
+
const selected = select.options[select.selectedIndex];
|
|
57
|
+
if (selected === void 0) return;
|
|
58
|
+
if (records.some((record) => touchesSelected(record, selected))) refresh(select);
|
|
59
|
+
});
|
|
60
|
+
observer.observe(select, {
|
|
61
|
+
childList: true,
|
|
62
|
+
characterData: true,
|
|
63
|
+
attributes: true,
|
|
64
|
+
subtree: true
|
|
65
|
+
});
|
|
66
|
+
return () => {
|
|
67
|
+
observer.disconnect();
|
|
68
|
+
};
|
|
69
|
+
}, [node]);
|
|
70
|
+
const selectRef = useMemo(() => ({ get current() {
|
|
71
|
+
return node.current?.closest("select") ?? null;
|
|
72
|
+
} }), [node]);
|
|
73
|
+
useFormReset(selectRef, () => {
|
|
74
|
+
const select = selectRef.current;
|
|
75
|
+
if (select !== null && supportsSelectedContent()) refresh(select);
|
|
76
|
+
});
|
|
77
|
+
const state = {
|
|
78
|
+
value: ctx.optimistic,
|
|
79
|
+
pending: ctx.pending,
|
|
80
|
+
disabled: ctx.disabled
|
|
81
|
+
};
|
|
82
|
+
return useRender({
|
|
83
|
+
defaultElement: "selectedcontent",
|
|
84
|
+
render,
|
|
85
|
+
state,
|
|
86
|
+
className,
|
|
87
|
+
style,
|
|
88
|
+
children: void 0,
|
|
89
|
+
props: rest,
|
|
90
|
+
libraryProps: {
|
|
91
|
+
suppressHydrationWarning: true,
|
|
92
|
+
dangerouslySetInnerHTML: { __html: "" }
|
|
93
|
+
},
|
|
94
|
+
ref
|
|
95
|
+
});
|
|
96
|
+
}
|
|
97
|
+
SelectValue.displayName = "SelectValue";
|
|
98
|
+
//#endregion
|
|
99
|
+
export { SelectValue };
|
|
100
|
+
|
|
101
|
+
//# sourceMappingURL=select-value.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"select-value.mjs","names":[],"sources":["../../src/select/select-value.tsx"],"sourcesContent":["\"use client\";\nimport { useLayoutEffect, useMemo } from \"react\";\nimport type { ComponentPropsWithRef, CSSProperties } from \"react\";\nimport type { RenderProp, StateValue } from \"../internal/types.js\";\nimport { useFormReset } from \"../internal/use-form-reset.js\";\nimport { useRender } from \"../internal/use-render.js\";\nimport { useSelectContext } from \"./select-context.js\";\nimport { useSelectPartRef } from \"./select-dom.js\";\nimport type { SelectRootState } from \"./select-root.js\";\n\nconst isDev = process.env.NODE_ENV !== \"production\";\n\nexport interface SelectValueProps extends Omit<\n ComponentPropsWithRef<\"selectedcontent\">,\n \"children\" | \"dangerouslySetInnerHTML\" | \"className\" | \"style\"\n> {\n className?: StateValue<string | undefined, SelectRootState>;\n style?: StateValue<CSSProperties | undefined, SelectRootState>;\n /** Replace the rendered element. Must keep a `<selectedcontent>`. */\n render?: RenderProp<ComponentPropsWithRef<\"selectedcontent\">, SelectRootState>;\n}\n\n/** Where the browser clones options into `<selectedcontent>` (Chromium 135+, Safari 27). */\nfunction supportsSelectedContent(): boolean {\n return typeof globalThis !== \"undefined\" && \"HTMLSelectedContentElement\" in globalThis;\n}\n\n/**\n * Whether a mutation record changes what `<selectedcontent>` shows: a record inside the selected\n * option. Attribute records on the option element itself are ignored (option attributes are not\n * cloned, and the library writes `data-*` there); records inside `<selectedcontent>` are never\n * inside an option, so the refresh's own clone does not loop.\n */\nfunction touchesSelected(record: MutationRecord, selected: HTMLOptionElement): boolean {\n if (record.type === \"attributes\" && record.target === selected) return false;\n return selected.contains(record.target);\n}\n\n/** Re-clones the selected option into `<selectedcontent>`. */\nfunction refresh(select: HTMLSelectElement): void {\n // Nothing selected: assigning the value would select the placeholder (probe case 7).\n if (select.selectedIndex === -1) return;\n // The assignment is the re-clone trigger; it fires no event and keeps the selection.\n const current = select.value;\n select.value = current;\n}\n\n/**\n * `<selectedcontent>`: the browser clones the selected option's content into it (inside\n * `Select.Trigger`). It has no `children`. Rendered with `suppressHydrationWarning` and an empty\n * `dangerouslySetInnerHTML` so that hydration accepts the content the parser cloned before React\n * ran (design/components/select.md 3.3).\n *\n * Also keeps it fresh: the platform re-clones only on selection changes, so when React changes\n * the selected option's content (a label, a state function, a Suspense boundary resolving inside\n * it), a `MutationObserver` re-assigns `select.value = select.value`, which re-clones without\n * events and without touching the selection or an open picker (6.3). The same refresh follows a\n * form reset, which Chromium does not re-clone for. Not installed where\n * `HTMLSelectedContentElement` is undefined (Firefox today, jsdom): nothing is cloned there.\n *\n * Owned keys: `dangerouslySetInnerHTML`, `suppressHydrationWarning`, `children`.\n */\nexport function SelectValue({ className, style, render, ...rest }: SelectValueProps) {\n const ctx = useSelectContext(\"Select.Value\");\n const { ref, node } = useSelectPartRef<HTMLElement>(\"Select.Value\", \"selectedcontent\");\n\n useLayoutEffect(() => {\n const el = node.current;\n if (el === null) return;\n const select = el.closest(\"select\");\n if (select === null) {\n if (isDev) {\n console.error(\n \"Select.Value: rendered outside the Select.Root's <select>; put it inside \" +\n \"Select.Trigger, the select's first child.\",\n );\n }\n return;\n }\n if (!supportsSelectedContent()) return;\n const observer = new MutationObserver((records) => {\n const selected = select.options[select.selectedIndex];\n if (selected === undefined) return;\n if (records.some((record) => touchesSelected(record, selected))) refresh(select);\n });\n observer.observe(select, {\n childList: true,\n characterData: true,\n attributes: true,\n subtree: true,\n });\n return () => {\n observer.disconnect();\n };\n }, [node]);\n\n // A form reset changes the selection without re-cloning (Chromium 156: `form.reset()` leaves\n // the old option's content in <selectedcontent>; memo/developer/select.md). `useFormReset`\n // listens on the select's form owner itself (so neither `stopPropagation()` on the form nor a\n // shadow root hides the event), follows a changed owner or `form` attribute, and calls back in\n // a microtask after an uncancelled reset. React's own reset after a form action is a\n // `form.reset()` too.\n const selectRef = useMemo(\n () => ({\n get current(): HTMLSelectElement | null {\n return node.current?.closest(\"select\") ?? null;\n },\n }),\n [node],\n );\n useFormReset(selectRef, () => {\n const select = selectRef.current;\n if (select !== null && supportsSelectedContent()) refresh(select);\n });\n\n const state: SelectRootState = {\n value: ctx.optimistic,\n pending: ctx.pending,\n disabled: ctx.disabled,\n };\n return useRender<ComponentPropsWithRef<\"selectedcontent\">, SelectRootState>({\n defaultElement: \"selectedcontent\",\n render,\n state,\n className,\n style,\n children: undefined,\n props: rest,\n libraryProps: {\n suppressHydrationWarning: true,\n dangerouslySetInnerHTML: { __html: \"\" },\n },\n ref,\n });\n}\n\nSelectValue.displayName = \"SelectValue\";\n"],"mappings":";;;;;;;AAUA,MAAM,QAAQ,QAAQ,IAAI,aAAa;;AAavC,SAAS,0BAAmC;CAC1C,OAAO,OAAO,eAAe,eAAe,gCAAgC;AAC9E;;;;;;;AAQA,SAAS,gBAAgB,QAAwB,UAAsC;CACrF,IAAI,OAAO,SAAS,gBAAgB,OAAO,WAAW,UAAU,OAAO;CACvE,OAAO,SAAS,SAAS,OAAO,MAAM;AACxC;;AAGA,SAAS,QAAQ,QAAiC;CAEhD,IAAI,OAAO,kBAAkB,IAAI;CAGjC,OAAO,QADS,OAAO;AAEzB;;;;;;;;;;;;;;;;AAiBA,SAAgB,YAAY,EAAE,WAAW,OAAO,QAAQ,GAAG,QAA0B;CACnF,MAAM,MAAM,iBAAiB,cAAc;CAC3C,MAAM,EAAE,KAAK,SAAS,iBAA8B,gBAAgB,iBAAiB;CAErF,sBAAsB;EACpB,MAAM,KAAK,KAAK;EAChB,IAAI,OAAO,MAAM;EACjB,MAAM,SAAS,GAAG,QAAQ,QAAQ;EAClC,IAAI,WAAW,MAAM;GACnB,IAAI,OACF,QAAQ,MACN,oHAEF;GAEF;EACF;EACA,IAAI,CAAC,wBAAwB,GAAG;EAChC,MAAM,WAAW,IAAI,kBAAkB,YAAY;GACjD,MAAM,WAAW,OAAO,QAAQ,OAAO;GACvC,IAAI,aAAa,KAAA,GAAW;GAC5B,IAAI,QAAQ,MAAM,WAAW,gBAAgB,QAAQ,QAAQ,CAAC,GAAG,QAAQ,MAAM;EACjF,CAAC;EACD,SAAS,QAAQ,QAAQ;GACvB,WAAW;GACX,eAAe;GACf,YAAY;GACZ,SAAS;EACX,CAAC;EACD,aAAa;GACX,SAAS,WAAW;EACtB;CACF,GAAG,CAAC,IAAI,CAAC;CAQT,MAAM,YAAY,eACT,EACL,IAAI,UAAoC;EACtC,OAAO,KAAK,SAAS,QAAQ,QAAQ,KAAK;CAC5C,EACF,IACA,CAAC,IAAI,CACP;CACA,aAAa,iBAAiB;EAC5B,MAAM,SAAS,UAAU;EACzB,IAAI,WAAW,QAAQ,wBAAwB,GAAG,QAAQ,MAAM;CAClE,CAAC;CAED,MAAM,QAAyB;EAC7B,OAAO,IAAI;EACX,SAAS,IAAI;EACb,UAAU,IAAI;CAChB;CACA,OAAO,UAAqE;EAC1E,gBAAgB;EAChB;EACA;EACA;EACA;EACA,UAAU,KAAA;EACV,OAAO;EACP,cAAc;GACZ,0BAA0B;GAC1B,yBAAyB,EAAE,QAAQ,GAAG;EACxC;EACA;CACF,CAAC;AACH;AAEA,YAAY,cAAc"}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import "../internal/platform-attributes.mjs";
|
|
2
|
+
import { SliderOrientation, SliderRootProps, SliderRootState, SliderValue, SliderValueChangeDetails, SliderValueCommitDetails } from "./slider-root.mjs";
|
|
3
|
+
import { SliderTrack, SliderTrackProps, SliderTrackState } from "./slider-track.mjs";
|
|
4
|
+
import { SliderIndicator, SliderIndicatorProps, SliderIndicatorState } from "./slider-indicator.mjs";
|
|
5
|
+
import { SliderLabel, SliderLabelProps } from "./slider-label.mjs";
|
|
6
|
+
import { SliderThumb, SliderThumbProps, SliderThumbState } from "./slider-thumb.mjs";
|
|
7
|
+
import { SliderValuePart, SliderValueProps, SliderValueState } from "./slider-value.mjs";
|
|
8
|
+
//#region src/slider/index.d.ts
|
|
9
|
+
/**
|
|
10
|
+
* Slider (WAI-ARIA APG Slider and Slider (Multi-Thumb) patterns): `Root` (`role="group"` with
|
|
11
|
+
* several thumbs), `Label`, `Track` (owns the pointer), `Indicator` (the fill), one `Thumb` per
|
|
12
|
+
* value (a styled element containing a visually hidden native `<input type="range">`), and
|
|
13
|
+
* `Value`. Two actions: `valueChangeAction` on every step (a transition; keep it cheap) and
|
|
14
|
+
* `valueCommitAction` once per gesture (the save; uncontrolled state is committed when it
|
|
15
|
+
* resolves and rolls back when it rejects).
|
|
16
|
+
*/
|
|
17
|
+
export declare const Slider: {
|
|
18
|
+
readonly Root: {
|
|
19
|
+
(props: SliderRootProps<number>): import("react").ReactNode;
|
|
20
|
+
(props: SliderRootProps<readonly number[]>): import("react").ReactNode;
|
|
21
|
+
(props: SliderRootProps<SliderValue>): import("react").ReactNode;
|
|
22
|
+
displayName?: string;
|
|
23
|
+
};
|
|
24
|
+
readonly Label: typeof SliderLabel;
|
|
25
|
+
readonly Track: typeof SliderTrack;
|
|
26
|
+
readonly Indicator: typeof SliderIndicator;
|
|
27
|
+
readonly Thumb: typeof SliderThumb;
|
|
28
|
+
readonly Value: typeof SliderValuePart;
|
|
29
|
+
};
|
|
30
|
+
//#endregion
|
|
31
|
+
export type { SliderIndicatorProps, SliderIndicatorState, SliderLabelProps, SliderOrientation, SliderRootProps, SliderRootState, SliderThumbProps, SliderThumbState, SliderTrackProps, SliderTrackState, SliderValue, SliderValueChangeDetails, SliderValueCommitDetails, SliderValueProps, SliderValueState };
|
|
32
|
+
//# sourceMappingURL=index.d.mts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.mts","names":["_$__slider_root_js0.SliderRootProps","_$__slider_root_js0.SliderValue"],"sources":["../../src/slider/index.ts"],"mappings":";;;;;;;;;;;;;;;;qBAkBa;WACX;K,OADWA,0C;;;;;WAEX,cAAK;WACL,cAAK;WACL,kBAAS;WACT,cAAK;WACL,cAAK"}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import { SliderIndicator } from "./slider-indicator.mjs";
|
|
2
|
+
import { SliderLabel } from "./slider-label.mjs";
|
|
3
|
+
import { SliderRoot } from "./slider-root.mjs";
|
|
4
|
+
import { SliderThumb } from "./slider-thumb.mjs";
|
|
5
|
+
import { SliderTrack } from "./slider-track.mjs";
|
|
6
|
+
import { SliderValuePart } from "./slider-value.mjs";
|
|
7
|
+
//#region src/slider/index.ts
|
|
8
|
+
/**
|
|
9
|
+
* Slider (WAI-ARIA APG Slider and Slider (Multi-Thumb) patterns): `Root` (`role="group"` with
|
|
10
|
+
* several thumbs), `Label`, `Track` (owns the pointer), `Indicator` (the fill), one `Thumb` per
|
|
11
|
+
* value (a styled element containing a visually hidden native `<input type="range">`), and
|
|
12
|
+
* `Value`. Two actions: `valueChangeAction` on every step (a transition; keep it cheap) and
|
|
13
|
+
* `valueCommitAction` once per gesture (the save; uncontrolled state is committed when it
|
|
14
|
+
* resolves and rolls back when it rejects).
|
|
15
|
+
*/
|
|
16
|
+
const Slider = {
|
|
17
|
+
Root: SliderRoot,
|
|
18
|
+
Label: SliderLabel,
|
|
19
|
+
Track: SliderTrack,
|
|
20
|
+
Indicator: SliderIndicator,
|
|
21
|
+
Thumb: SliderThumb,
|
|
22
|
+
Value: SliderValuePart
|
|
23
|
+
};
|
|
24
|
+
//#endregion
|
|
25
|
+
export { Slider };
|
|
26
|
+
|
|
27
|
+
//# sourceMappingURL=index.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.mjs","names":[],"sources":["../../src/slider/index.ts"],"sourcesContent":["// Ships the platform attribute typings with this subpath (conventions 7.4). Type-only: the\n// built JS has no import of it.\nimport \"../internal/platform-attributes.js\";\nimport { SliderIndicator } from \"./slider-indicator.js\";\nimport { SliderLabel } from \"./slider-label.js\";\nimport { SliderRoot } from \"./slider-root.js\";\nimport { SliderThumb } from \"./slider-thumb.js\";\nimport { SliderTrack } from \"./slider-track.js\";\nimport { SliderValuePart } from \"./slider-value.js\";\n\n/**\n * Slider (WAI-ARIA APG Slider and Slider (Multi-Thumb) patterns): `Root` (`role=\"group\"` with\n * several thumbs), `Label`, `Track` (owns the pointer), `Indicator` (the fill), one `Thumb` per\n * value (a styled element containing a visually hidden native `<input type=\"range\">`), and\n * `Value`. Two actions: `valueChangeAction` on every step (a transition; keep it cheap) and\n * `valueCommitAction` once per gesture (the save; uncontrolled state is committed when it\n * resolves and rolls back when it rejects).\n */\nexport const Slider = {\n Root: SliderRoot,\n Label: SliderLabel,\n Track: SliderTrack,\n Indicator: SliderIndicator,\n Thumb: SliderThumb,\n Value: SliderValuePart,\n} as const;\n\nexport type {\n SliderValue,\n SliderOrientation,\n SliderRootProps,\n SliderRootState,\n SliderValueChangeDetails,\n SliderValueCommitDetails,\n} from \"./slider-root.js\";\nexport type { SliderLabelProps } from \"./slider-label.js\";\nexport type { SliderTrackProps, SliderTrackState } from \"./slider-track.js\";\nexport type { SliderIndicatorProps, SliderIndicatorState } from \"./slider-indicator.js\";\nexport type { SliderThumbProps, SliderThumbState } from \"./slider-thumb.js\";\nexport type { SliderValueProps, SliderValueState } from \"./slider-value.js\";\n"],"mappings":";;;;;;;;;;;;;;;AAkBA,MAAa,SAAS;CACpB,MAAM;CACN,OAAO;CACP,OAAO;CACP,WAAW;CACX,OAAO;CACP,OAAO;AACT"}
|
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
//#region src/slider/slider-arithmetic.ts
|
|
2
|
+
/** Number of decimal places of `n` as written (`0.1` → 1, `1e-7` → 7, `5` → 0). */
|
|
3
|
+
function decimalsOf(n) {
|
|
4
|
+
if (!Number.isFinite(n)) return 0;
|
|
5
|
+
const text = String(n);
|
|
6
|
+
const exponent = /e-(\d+)$/i.exec(text);
|
|
7
|
+
if (exponent !== null) {
|
|
8
|
+
const mantissa = text.slice(0, exponent.index);
|
|
9
|
+
const dot = mantissa.indexOf(".");
|
|
10
|
+
return Number(exponent[1]) + (dot === -1 ? 0 : mantissa.length - dot - 1);
|
|
11
|
+
}
|
|
12
|
+
const dot = text.indexOf(".");
|
|
13
|
+
return dot === -1 ? 0 : text.length - dot - 1;
|
|
14
|
+
}
|
|
15
|
+
function roundTo(value, decimals) {
|
|
16
|
+
if (decimals <= 0) return Math.round(value);
|
|
17
|
+
return Number(value.toFixed(Math.min(decimals, 100)));
|
|
18
|
+
}
|
|
19
|
+
/** Tolerance for grid computations on binary floating point (`0.3 / 0.1` is `2.9999999999999996`). */
|
|
20
|
+
const EPSILON = 1e-9;
|
|
21
|
+
/**
|
|
22
|
+
* The value a native range with these bounds would hold for `value`: snapped to
|
|
23
|
+
* `min + n × step` (ties toward +∞, the HTML step-mismatch rule), clamped to `[min, max]`, and,
|
|
24
|
+
* when the snapped value exceeds `max`, the last grid point below `max` (so `min 0, max 5,
|
|
25
|
+
* step 2` caps at `4`). Rounded to the decimal places of `step` and `min`. With `max < min` the
|
|
26
|
+
* platform's maximum is `min`.
|
|
27
|
+
*/
|
|
28
|
+
function snap(value, min, max, step) {
|
|
29
|
+
const decimals = Math.max(decimalsOf(step), decimalsOf(min));
|
|
30
|
+
if (!Number.isFinite(value)) return min;
|
|
31
|
+
if (!(max > min)) return roundTo(min, decimals);
|
|
32
|
+
const lastIndex = Math.floor((max - min) / step + EPSILON);
|
|
33
|
+
let index = Math.floor((value - min) / step + .5 + EPSILON);
|
|
34
|
+
if (index > lastIndex) index = lastIndex;
|
|
35
|
+
if (index < 0) index = 0;
|
|
36
|
+
return roundTo(min + index * step, decimals);
|
|
37
|
+
}
|
|
38
|
+
/** Whether `max` is reachable: `max - min` is a whole number of steps. */
|
|
39
|
+
function isMaxReachable(min, max, step) {
|
|
40
|
+
if (!(max > min)) return true;
|
|
41
|
+
const steps = (max - min) / step;
|
|
42
|
+
return Math.abs(steps - Math.round(steps)) < EPSILON * Math.max(1, steps);
|
|
43
|
+
}
|
|
44
|
+
/** Whether `value` is a value a native range with these bounds can hold unchanged. */
|
|
45
|
+
function isOnGrid(value, min, max, step) {
|
|
46
|
+
return Math.abs(snap(value, min, max, step) - value) < EPSILON * Math.max(1, Math.abs(value));
|
|
47
|
+
}
|
|
48
|
+
/** The native `min` / `max` of thumb `index`: the slider's bounds, narrowed by its neighbours. */
|
|
49
|
+
function thumbBounds(values, index, min, max, gap) {
|
|
50
|
+
const decimals = Math.max(decimalsOf(gap), decimalsOf(min));
|
|
51
|
+
const before = values[index - 1];
|
|
52
|
+
const after = values[index + 1];
|
|
53
|
+
return {
|
|
54
|
+
lower: before === void 0 ? min : roundTo(before + gap, decimals),
|
|
55
|
+
upper: after === void 0 ? max : roundTo(after - gap, decimals)
|
|
56
|
+
};
|
|
57
|
+
}
|
|
58
|
+
/**
|
|
59
|
+
* `next` for thumb `index`, snapped to the slider's grid and clamped between its neighbours
|
|
60
|
+
* (`values[i - 1] + gap`, `values[i + 1] - gap`; on the grid, because every thumb shares `step`
|
|
61
|
+
* and `min`). With no room between the neighbours the thumb keeps its value.
|
|
62
|
+
*/
|
|
63
|
+
function clampToNeighbours(values, index, next, min, max, step, gap) {
|
|
64
|
+
const { lower, upper } = thumbBounds(values, index, min, max, gap);
|
|
65
|
+
const current = values[index] ?? next;
|
|
66
|
+
if (lower > upper + EPSILON) return current;
|
|
67
|
+
return Math.min(Math.max(snap(next, min, max, step), lower), upper);
|
|
68
|
+
}
|
|
69
|
+
/**
|
|
70
|
+
* The value a native input with these attributes would hold for `value` (each thumb's bounds come
|
|
71
|
+
* from `reference`, the values it is rendered against). Used to compare a DOM read with the shown
|
|
72
|
+
* value: jsdom does not sanitise a range's value, browsers do, and a consumer's off-grid value is
|
|
73
|
+
* rendered as given and sanitised by the DOM.
|
|
74
|
+
*/
|
|
75
|
+
function sanitize(values, reference, min, max, step, gap) {
|
|
76
|
+
return values.map((value, index) => {
|
|
77
|
+
const { lower, upper } = thumbBounds(reference, index, min, max, gap);
|
|
78
|
+
return snap(value, lower, Math.max(lower, upper), step);
|
|
79
|
+
});
|
|
80
|
+
}
|
|
81
|
+
/** Position of `value` in `[min, max]`, in percent, clamped to `0`–`100`. */
|
|
82
|
+
function percent(value, min, max) {
|
|
83
|
+
if (!(max > min)) return 0;
|
|
84
|
+
const fraction = (value - min) / (max - min);
|
|
85
|
+
return Math.min(100, Math.max(0, fraction * 100));
|
|
86
|
+
}
|
|
87
|
+
/**
|
|
88
|
+
* The thumb a track press at `target` moves: the nearest by value. On a tie (two thumbs at one
|
|
89
|
+
* value, or equidistant thumbs) the thumb that can move toward the pointer: the later one when
|
|
90
|
+
* the pointer is above it, else the earlier one.
|
|
91
|
+
*/
|
|
92
|
+
function nearestThumb(values, target) {
|
|
93
|
+
let best = 0;
|
|
94
|
+
let bestDistance = Number.POSITIVE_INFINITY;
|
|
95
|
+
values.forEach((value, index) => {
|
|
96
|
+
const distance = Math.abs(value - target);
|
|
97
|
+
if (distance < bestDistance - EPSILON) {
|
|
98
|
+
best = index;
|
|
99
|
+
bestDistance = distance;
|
|
100
|
+
} else if (Math.abs(distance - bestDistance) <= EPSILON && target > value) best = index;
|
|
101
|
+
});
|
|
102
|
+
return best;
|
|
103
|
+
}
|
|
104
|
+
/** The platform's default value: the midpoint, snapped to the grid; `min` when `max < min`. */
|
|
105
|
+
function platformDefault(min, max, step) {
|
|
106
|
+
if (!(max > min)) return min;
|
|
107
|
+
return snap(min + (max - min) / 2, min, max, step);
|
|
108
|
+
}
|
|
109
|
+
/** Element-wise equality of two value arrays (within floating-point tolerance). */
|
|
110
|
+
function equalValues(a, b) {
|
|
111
|
+
if (a.length !== b.length) return false;
|
|
112
|
+
return a.every((value, index) => {
|
|
113
|
+
const other = b[index];
|
|
114
|
+
return value === other || Math.abs(value - other) < EPSILON * Math.max(1, Math.abs(value));
|
|
115
|
+
});
|
|
116
|
+
}
|
|
117
|
+
//#endregion
|
|
118
|
+
export { clampToNeighbours, decimalsOf, equalValues, isMaxReachable, isOnGrid, nearestThumb, percent, platformDefault, sanitize, snap, thumbBounds };
|
|
119
|
+
|
|
120
|
+
//# sourceMappingURL=slider-arithmetic.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"slider-arithmetic.mjs","names":[],"sources":["../../src/slider/slider-arithmetic.ts"],"sourcesContent":["// Pure value arithmetic of the Slider (design/components/slider.md 5). No directive: no React,\n// no client-only API. The library computes exactly what the platform's range sanitisation would,\n// so the number it renders is the number the DOM holds and `FormData` posts.\n\n/** Number of decimal places of `n` as written (`0.1` → 1, `1e-7` → 7, `5` → 0). */\nexport function decimalsOf(n: number): number {\n if (!Number.isFinite(n)) return 0;\n const text = String(n);\n const exponent = /e-(\\d+)$/i.exec(text);\n if (exponent !== null) {\n const mantissa = text.slice(0, exponent.index);\n const dot = mantissa.indexOf(\".\");\n return Number(exponent[1]) + (dot === -1 ? 0 : mantissa.length - dot - 1);\n }\n const dot = text.indexOf(\".\");\n return dot === -1 ? 0 : text.length - dot - 1;\n}\n\nfunction roundTo(value: number, decimals: number): number {\n if (decimals <= 0) return Math.round(value);\n // `toFixed` takes at most 100 digits; anything near that is already exact.\n return Number(value.toFixed(Math.min(decimals, 100)));\n}\n\n/** Tolerance for grid computations on binary floating point (`0.3 / 0.1` is `2.9999999999999996`). */\nconst EPSILON = 1e-9;\n\n/**\n * The value a native range with these bounds would hold for `value`: snapped to\n * `min + n × step` (ties toward +∞, the HTML step-mismatch rule), clamped to `[min, max]`, and,\n * when the snapped value exceeds `max`, the last grid point below `max` (so `min 0, max 5,\n * step 2` caps at `4`). Rounded to the decimal places of `step` and `min`. With `max < min` the\n * platform's maximum is `min`.\n */\nexport function snap(value: number, min: number, max: number, step: number): number {\n const decimals = Math.max(decimalsOf(step), decimalsOf(min));\n if (!Number.isFinite(value)) return min;\n if (!(max > min)) return roundTo(min, decimals);\n const lastIndex = Math.floor((max - min) / step + EPSILON);\n let index = Math.floor((value - min) / step + 0.5 + EPSILON);\n if (index > lastIndex) index = lastIndex;\n if (index < 0) index = 0;\n return roundTo(min + index * step, decimals);\n}\n\n/** Whether `max` is reachable: `max - min` is a whole number of steps. */\nexport function isMaxReachable(min: number, max: number, step: number): boolean {\n if (!(max > min)) return true;\n const steps = (max - min) / step;\n return Math.abs(steps - Math.round(steps)) < EPSILON * Math.max(1, steps);\n}\n\n/** Whether `value` is a value a native range with these bounds can hold unchanged. */\nexport function isOnGrid(value: number, min: number, max: number, step: number): boolean {\n return Math.abs(snap(value, min, max, step) - value) < EPSILON * Math.max(1, Math.abs(value));\n}\n\n/** The native `min` / `max` of thumb `index`: the slider's bounds, narrowed by its neighbours. */\nexport function thumbBounds(\n values: readonly number[],\n index: number,\n min: number,\n max: number,\n gap: number,\n): { readonly lower: number; readonly upper: number } {\n const decimals = Math.max(decimalsOf(gap), decimalsOf(min));\n const before = values[index - 1];\n const after = values[index + 1];\n const lower = before === undefined ? min : roundTo(before + gap, decimals);\n const upper = after === undefined ? max : roundTo(after - gap, decimals);\n return { lower, upper };\n}\n\n/**\n * `next` for thumb `index`, snapped to the slider's grid and clamped between its neighbours\n * (`values[i - 1] + gap`, `values[i + 1] - gap`; on the grid, because every thumb shares `step`\n * and `min`). With no room between the neighbours the thumb keeps its value.\n */\nexport function clampToNeighbours(\n values: readonly number[],\n index: number,\n next: number,\n min: number,\n max: number,\n step: number,\n gap: number,\n): number {\n const { lower, upper } = thumbBounds(values, index, min, max, gap);\n const current = values[index] ?? next;\n if (lower > upper + EPSILON) return current;\n return Math.min(Math.max(snap(next, min, max, step), lower), upper);\n}\n\n/**\n * The value a native input with these attributes would hold for `value` (each thumb's bounds come\n * from `reference`, the values it is rendered against). Used to compare a DOM read with the shown\n * value: jsdom does not sanitise a range's value, browsers do, and a consumer's off-grid value is\n * rendered as given and sanitised by the DOM.\n */\nexport function sanitize(\n values: readonly number[],\n reference: readonly number[],\n min: number,\n max: number,\n step: number,\n gap: number,\n): readonly number[] {\n return values.map((value, index) => {\n const { lower, upper } = thumbBounds(reference, index, min, max, gap);\n // The native step base is the input's own `min` attribute (the neighbour-adjusted bound).\n return snap(value, lower, Math.max(lower, upper), step);\n });\n}\n\n/** Position of `value` in `[min, max]`, in percent, clamped to `0`–`100`. */\nexport function percent(value: number, min: number, max: number): number {\n if (!(max > min)) return 0;\n const fraction = (value - min) / (max - min);\n return Math.min(100, Math.max(0, fraction * 100));\n}\n\n/**\n * The thumb a track press at `target` moves: the nearest by value. On a tie (two thumbs at one\n * value, or equidistant thumbs) the thumb that can move toward the pointer: the later one when\n * the pointer is above it, else the earlier one.\n */\nexport function nearestThumb(values: readonly number[], target: number): number {\n let best = 0;\n let bestDistance = Number.POSITIVE_INFINITY;\n values.forEach((value, index) => {\n const distance = Math.abs(value - target);\n if (distance < bestDistance - EPSILON) {\n best = index;\n bestDistance = distance;\n } else if (Math.abs(distance - bestDistance) <= EPSILON && target > value) {\n best = index;\n }\n });\n return best;\n}\n\n/** The platform's default value: the midpoint, snapped to the grid; `min` when `max < min`. */\nexport function platformDefault(min: number, max: number, step: number): number {\n if (!(max > min)) return min;\n return snap(min + (max - min) / 2, min, max, step);\n}\n\n/** Element-wise equality of two value arrays (within floating-point tolerance). */\nexport function equalValues(a: readonly number[], b: readonly number[]): boolean {\n if (a.length !== b.length) return false;\n return a.every((value, index) => {\n const other = b[index] as number;\n return value === other || Math.abs(value - other) < EPSILON * Math.max(1, Math.abs(value));\n });\n}\n"],"mappings":";;AAKA,SAAgB,WAAW,GAAmB;CAC5C,IAAI,CAAC,OAAO,SAAS,CAAC,GAAG,OAAO;CAChC,MAAM,OAAO,OAAO,CAAC;CACrB,MAAM,WAAW,YAAY,KAAK,IAAI;CACtC,IAAI,aAAa,MAAM;EACrB,MAAM,WAAW,KAAK,MAAM,GAAG,SAAS,KAAK;EAC7C,MAAM,MAAM,SAAS,QAAQ,GAAG;EAChC,OAAO,OAAO,SAAS,EAAE,KAAK,QAAQ,KAAK,IAAI,SAAS,SAAS,MAAM;CACzE;CACA,MAAM,MAAM,KAAK,QAAQ,GAAG;CAC5B,OAAO,QAAQ,KAAK,IAAI,KAAK,SAAS,MAAM;AAC9C;AAEA,SAAS,QAAQ,OAAe,UAA0B;CACxD,IAAI,YAAY,GAAG,OAAO,KAAK,MAAM,KAAK;CAE1C,OAAO,OAAO,MAAM,QAAQ,KAAK,IAAI,UAAU,GAAG,CAAC,CAAC;AACtD;;AAGA,MAAM,UAAU;;;;;;;;AAShB,SAAgB,KAAK,OAAe,KAAa,KAAa,MAAsB;CAClF,MAAM,WAAW,KAAK,IAAI,WAAW,IAAI,GAAG,WAAW,GAAG,CAAC;CAC3D,IAAI,CAAC,OAAO,SAAS,KAAK,GAAG,OAAO;CACpC,IAAI,EAAE,MAAM,MAAM,OAAO,QAAQ,KAAK,QAAQ;CAC9C,MAAM,YAAY,KAAK,OAAO,MAAM,OAAO,OAAO,OAAO;CACzD,IAAI,QAAQ,KAAK,OAAO,QAAQ,OAAO,OAAO,KAAM,OAAO;CAC3D,IAAI,QAAQ,WAAW,QAAQ;CAC/B,IAAI,QAAQ,GAAG,QAAQ;CACvB,OAAO,QAAQ,MAAM,QAAQ,MAAM,QAAQ;AAC7C;;AAGA,SAAgB,eAAe,KAAa,KAAa,MAAuB;CAC9E,IAAI,EAAE,MAAM,MAAM,OAAO;CACzB,MAAM,SAAS,MAAM,OAAO;CAC5B,OAAO,KAAK,IAAI,QAAQ,KAAK,MAAM,KAAK,CAAC,IAAI,UAAU,KAAK,IAAI,GAAG,KAAK;AAC1E;;AAGA,SAAgB,SAAS,OAAe,KAAa,KAAa,MAAuB;CACvF,OAAO,KAAK,IAAI,KAAK,OAAO,KAAK,KAAK,IAAI,IAAI,KAAK,IAAI,UAAU,KAAK,IAAI,GAAG,KAAK,IAAI,KAAK,CAAC;AAC9F;;AAGA,SAAgB,YACd,QACA,OACA,KACA,KACA,KACoD;CACpD,MAAM,WAAW,KAAK,IAAI,WAAW,GAAG,GAAG,WAAW,GAAG,CAAC;CAC1D,MAAM,SAAS,OAAO,QAAQ;CAC9B,MAAM,QAAQ,OAAO,QAAQ;CAG7B,OAAO;EAAE,OAFK,WAAW,KAAA,IAAY,MAAM,QAAQ,SAAS,KAAK,QAAQ;EAEzD,OADF,UAAU,KAAA,IAAY,MAAM,QAAQ,QAAQ,KAAK,QAAQ;CACjD;AACxB;;;;;;AAOA,SAAgB,kBACd,QACA,OACA,MACA,KACA,KACA,MACA,KACQ;CACR,MAAM,EAAE,OAAO,UAAU,YAAY,QAAQ,OAAO,KAAK,KAAK,GAAG;CACjE,MAAM,UAAU,OAAO,UAAU;CACjC,IAAI,QAAQ,QAAQ,SAAS,OAAO;CACpC,OAAO,KAAK,IAAI,KAAK,IAAI,KAAK,MAAM,KAAK,KAAK,IAAI,GAAG,KAAK,GAAG,KAAK;AACpE;;;;;;;AAQA,SAAgB,SACd,QACA,WACA,KACA,KACA,MACA,KACmB;CACnB,OAAO,OAAO,KAAK,OAAO,UAAU;EAClC,MAAM,EAAE,OAAO,UAAU,YAAY,WAAW,OAAO,KAAK,KAAK,GAAG;EAEpE,OAAO,KAAK,OAAO,OAAO,KAAK,IAAI,OAAO,KAAK,GAAG,IAAI;CACxD,CAAC;AACH;;AAGA,SAAgB,QAAQ,OAAe,KAAa,KAAqB;CACvE,IAAI,EAAE,MAAM,MAAM,OAAO;CACzB,MAAM,YAAY,QAAQ,QAAQ,MAAM;CACxC,OAAO,KAAK,IAAI,KAAK,KAAK,IAAI,GAAG,WAAW,GAAG,CAAC;AAClD;;;;;;AAOA,SAAgB,aAAa,QAA2B,QAAwB;CAC9E,IAAI,OAAO;CACX,IAAI,eAAe,OAAO;CAC1B,OAAO,SAAS,OAAO,UAAU;EAC/B,MAAM,WAAW,KAAK,IAAI,QAAQ,MAAM;EACxC,IAAI,WAAW,eAAe,SAAS;GACrC,OAAO;GACP,eAAe;EACjB,OAAO,IAAI,KAAK,IAAI,WAAW,YAAY,KAAK,WAAW,SAAS,OAClE,OAAO;CAEX,CAAC;CACD,OAAO;AACT;;AAGA,SAAgB,gBAAgB,KAAa,KAAa,MAAsB;CAC9E,IAAI,EAAE,MAAM,MAAM,OAAO;CACzB,OAAO,KAAK,OAAO,MAAM,OAAO,GAAG,KAAK,KAAK,IAAI;AACnD;;AAGA,SAAgB,YAAY,GAAsB,GAA+B;CAC/E,IAAI,EAAE,WAAW,EAAE,QAAQ,OAAO;CAClC,OAAO,EAAE,OAAO,OAAO,UAAU;EAC/B,MAAM,QAAQ,EAAE;EAChB,OAAO,UAAU,SAAS,KAAK,IAAI,QAAQ,KAAK,IAAI,UAAU,KAAK,IAAI,GAAG,KAAK,IAAI,KAAK,CAAC;CAC3F,CAAC;AACH"}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { createContext, use } from "react";
|
|
3
|
+
//#region src/slider/slider-context.ts
|
|
4
|
+
const SliderContext = createContext(null);
|
|
5
|
+
function useSliderContext(part) {
|
|
6
|
+
const context = use(SliderContext);
|
|
7
|
+
if (context === null) throw new Error(`${part} must be rendered inside a Slider.Root.`);
|
|
8
|
+
return context;
|
|
9
|
+
}
|
|
10
|
+
//#endregion
|
|
11
|
+
export { SliderContext, useSliderContext };
|
|
12
|
+
|
|
13
|
+
//# sourceMappingURL=slider-context.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"slider-context.mjs","names":[],"sources":["../../src/slider/slider-context.ts"],"sourcesContent":["\"use client\";\nimport { createContext, use } from \"react\";\nimport type { RefCallback, RefObject } from \"react\";\nimport type { SliderOrientation, SliderRootState, SliderValue } from \"./slider-root.js\";\n\n/** What the Root routes from an enclosing `Field.Root` to its Thumbs (design 9.4.1). */\nexport interface SliderFieldWiring {\n /** One thumb only: Thumb `index` 0 merges it into its input ref (registers the input). */\n readonly inputRef: RefCallback<HTMLElement> | undefined;\n /** One thumb only: token-merged into Thumb 0's input `aria-describedby`. */\n readonly describedBy: string | undefined;\n /** On every Thumb's input (ARIA 1.2: never on the group element). */\n readonly invalid: \"true\" | \"false\" | undefined;\n /** On every Thumb's styled element. */\n readonly dataInvalid: \"\" | undefined;\n /** The Field's own `name`, for the Thumb's \"name differs from the Field's\" warning. */\n readonly name: string | undefined;\n}\n\nexport interface SliderContextValue {\n /** The Root's state, for `Slider.Label` and `Slider.Value`. */\n readonly state: SliderRootState<SliderValue>;\n /** The values the thumbs show (design 2.2): `live` while held, else optimistic. */\n readonly shown: readonly number[];\n /** `shown` in the prop's shape (`number` or array). */\n readonly shownValue: number | readonly number[];\n readonly min: number;\n readonly max: number;\n readonly step: number;\n /** `minStepsBetweenThumbs × step`. */\n readonly gap: number;\n readonly orientation: SliderOrientation;\n readonly disabled: boolean;\n /** A step or commit dispatched through this Slider is in flight. */\n readonly pending: boolean;\n /** The thumb a pointer is captured on, or `null`. */\n readonly draggingThumb: number | null;\n /** The thumb the latest step or commit moved, or `null` (platform dispatches). */\n readonly pendingThumb: number | null;\n readonly name: string | undefined;\n readonly form: string | undefined;\n readonly getAriaValueText: ((value: number, index: number) => string) | undefined;\n readonly labelId: string;\n readonly thumbId: (index: number) => string;\n /** The Track's element: the geometry reference for pointer math. */\n readonly trackRef: RefObject<HTMLElement | null>;\n\n /** The native `input` of thumb `index` (React `onChange`): one step. */\n readonly inputStep: (index: number, value: number, event: Event) => void;\n /** The native `change` of thumb `index`: the key press's commit. */\n readonly inputCommit: (index: number, event: Event) => void;\n /** `keydown` on thumb `index`: ArrowLeft / ArrowRight normalisation of a vertical slider. */\n readonly inputKeyDown: (index: number, event: KeyboardEvent) => void;\n /** `pointerdown` on a Thumb (`index`) or on the Track (`null`: the nearest thumb). */\n readonly beginGesture: (index: number | null, event: PointerEvent, element: HTMLElement) => void;\n /** Called by each Thumb from a layout effect; returns the unregistration. */\n readonly registerThumb: (index: number, input: HTMLInputElement) => () => void;\n /** Called by each Label from a layout effect; returns the unregistration. */\n readonly registerLabel: () => () => void;\n /** The enclosing Field's wiring (design 9.4), `null` outside a `Field.Root`. */\n readonly field: SliderFieldWiring | null;\n /** Late-mounting Thumbs report here (useNativeGroupReconciliation). */\n readonly onItemMounted: () => void;\n}\n\nexport const SliderContext = createContext<SliderContextValue | null>(null);\n\nexport function useSliderContext(part: string): SliderContextValue {\n const context = use(SliderContext);\n if (context === null) {\n throw new Error(`${part} must be rendered inside a Slider.Root.`);\n }\n return context;\n}\n"],"mappings":";;;AAiEA,MAAa,gBAAgB,cAAyC,IAAI;AAE1E,SAAgB,iBAAiB,MAAkC;CACjE,MAAM,UAAU,IAAI,aAAa;CACjC,IAAI,YAAY,MACd,MAAM,IAAI,MAAM,GAAG,KAAK,wCAAwC;CAElE,OAAO;AACT"}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { RenderProp, StateValue } from "../internal/types.mjs";
|
|
2
|
+
import { SliderTrackState } from "./slider-track.mjs";
|
|
3
|
+
import { CSSProperties, ComponentPropsWithRef, ReactNode } from "react";
|
|
4
|
+
//#region src/slider/slider-indicator.d.ts
|
|
5
|
+
export type SliderIndicatorState = SliderTrackState;
|
|
6
|
+
export interface SliderIndicatorProps extends Omit<ComponentPropsWithRef<"span">, "className" | "style" | "children"> {
|
|
7
|
+
className?: StateValue<string | undefined, SliderIndicatorState>;
|
|
8
|
+
style?: StateValue<CSSProperties | undefined, SliderIndicatorState>;
|
|
9
|
+
children?: StateValue<ReactNode, SliderIndicatorState>;
|
|
10
|
+
render?: RenderProp<ComponentPropsWithRef<"span">, SliderIndicatorState>;
|
|
11
|
+
}
|
|
12
|
+
/**
|
|
13
|
+
* The fill between the first and last thumb (from `min` to the value for one thumb). Renders no
|
|
14
|
+
* inline position: the consumer's CSS places it from the Root's inherited `--slider-start` /
|
|
15
|
+
* `--slider-end`. Owned keys: `data-orientation`, `data-disabled`.
|
|
16
|
+
*/
|
|
17
|
+
export declare function SliderIndicator({ className, style, children, render, ...rest }: SliderIndicatorProps): ReactNode;
|
|
18
|
+
export declare namespace SliderIndicator {
|
|
19
|
+
var displayName: string;
|
|
20
|
+
}
|
|
21
|
+
//#endregion
|
|
22
|
+
//# sourceMappingURL=slider-indicator.d.mts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"slider-indicator.d.mts","names":[],"sources":["../../src/slider/slider-indicator.tsx"],"mappings":";;;;YAQY,uBAAuB;iBAElB,6BAA6B,KAC5C;EAGA,YAAY,+BAA+B;EAC3C,QAAQ,WAAW,2BAA2B;EAC9C,WAAW,WAAW,WAAW;EACjC,SAAS,WAAW,+BAA+B;;;;;;;wBAQrC,kBACd,WACA,OACA,UACA,WACG,QACF,uBAAoB;yBANP"}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { dataAttr } from "../internal/data-attr.mjs";
|
|
3
|
+
import { useRender } from "../internal/use-render.mjs";
|
|
4
|
+
import { useSliderContext } from "./slider-context.mjs";
|
|
5
|
+
//#region src/slider/slider-indicator.tsx
|
|
6
|
+
/**
|
|
7
|
+
* The fill between the first and last thumb (from `min` to the value for one thumb). Renders no
|
|
8
|
+
* inline position: the consumer's CSS places it from the Root's inherited `--slider-start` /
|
|
9
|
+
* `--slider-end`. Owned keys: `data-orientation`, `data-disabled`.
|
|
10
|
+
*/
|
|
11
|
+
function SliderIndicator({ className, style, children, render, ...rest }) {
|
|
12
|
+
const ctx = useSliderContext("Slider.Indicator");
|
|
13
|
+
const state = {
|
|
14
|
+
orientation: ctx.orientation,
|
|
15
|
+
dragging: ctx.draggingThumb !== null,
|
|
16
|
+
disabled: ctx.disabled
|
|
17
|
+
};
|
|
18
|
+
return useRender({
|
|
19
|
+
defaultElement: "span",
|
|
20
|
+
render,
|
|
21
|
+
state,
|
|
22
|
+
className,
|
|
23
|
+
style,
|
|
24
|
+
children,
|
|
25
|
+
props: rest,
|
|
26
|
+
libraryProps: {
|
|
27
|
+
"data-orientation": ctx.orientation,
|
|
28
|
+
"data-disabled": dataAttr(ctx.disabled)
|
|
29
|
+
}
|
|
30
|
+
});
|
|
31
|
+
}
|
|
32
|
+
SliderIndicator.displayName = "SliderIndicator";
|
|
33
|
+
//#endregion
|
|
34
|
+
export { SliderIndicator };
|
|
35
|
+
|
|
36
|
+
//# sourceMappingURL=slider-indicator.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"slider-indicator.mjs","names":[],"sources":["../../src/slider/slider-indicator.tsx"],"sourcesContent":["\"use client\";\nimport type { ComponentPropsWithRef, CSSProperties, ReactNode } from \"react\";\nimport { dataAttr } from \"../internal/data-attr.js\";\nimport type { RenderProp, StateValue } from \"../internal/types.js\";\nimport { useRender } from \"../internal/use-render.js\";\nimport { useSliderContext } from \"./slider-context.js\";\nimport type { SliderTrackState } from \"./slider-track.js\";\n\nexport type SliderIndicatorState = SliderTrackState;\n\nexport interface SliderIndicatorProps extends Omit<\n ComponentPropsWithRef<\"span\">,\n \"className\" | \"style\" | \"children\"\n> {\n className?: StateValue<string | undefined, SliderIndicatorState>;\n style?: StateValue<CSSProperties | undefined, SliderIndicatorState>;\n children?: StateValue<ReactNode, SliderIndicatorState>;\n render?: RenderProp<ComponentPropsWithRef<\"span\">, SliderIndicatorState>;\n}\n\n/**\n * The fill between the first and last thumb (from `min` to the value for one thumb). Renders no\n * inline position: the consumer's CSS places it from the Root's inherited `--slider-start` /\n * `--slider-end`. Owned keys: `data-orientation`, `data-disabled`.\n */\nexport function SliderIndicator({\n className,\n style,\n children,\n render,\n ...rest\n}: SliderIndicatorProps) {\n const ctx = useSliderContext(\"Slider.Indicator\");\n const state: SliderIndicatorState = {\n orientation: ctx.orientation,\n dragging: ctx.draggingThumb !== null,\n disabled: ctx.disabled,\n };\n return useRender<ComponentPropsWithRef<\"span\">, SliderIndicatorState>({\n defaultElement: \"span\",\n render,\n state,\n className,\n style,\n children,\n props: rest,\n libraryProps: {\n \"data-orientation\": ctx.orientation,\n \"data-disabled\": dataAttr(ctx.disabled),\n },\n });\n}\n\nSliderIndicator.displayName = \"SliderIndicator\";\n"],"mappings":";;;;;;;;;;AAyBA,SAAgB,gBAAgB,EAC9B,WACA,OACA,UACA,QACA,GAAG,QACoB;CACvB,MAAM,MAAM,iBAAiB,kBAAkB;CAC/C,MAAM,QAA8B;EAClC,aAAa,IAAI;EACjB,UAAU,IAAI,kBAAkB;EAChC,UAAU,IAAI;CAChB;CACA,OAAO,UAA+D;EACpE,gBAAgB;EAChB;EACA;EACA;EACA;EACA;EACA,OAAO;EACP,cAAc;GACZ,oBAAoB,IAAI;GACxB,iBAAiB,SAAS,IAAI,QAAQ;EACxC;CACF,CAAC;AACH;AAEA,gBAAgB,cAAc"}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { RenderProp, StateValue } from "../internal/types.mjs";
|
|
2
|
+
import { SliderRootState, SliderValue } from "./slider-root.mjs";
|
|
3
|
+
import { CSSProperties, ComponentPropsWithRef, ReactNode } from "react";
|
|
4
|
+
//#region src/slider/slider-label.d.ts
|
|
5
|
+
/** `T` defaults to `SliderValue`; pass it to narrow the state (`<Slider.Label<number>>`). */
|
|
6
|
+
export interface SliderLabelProps<T extends SliderValue = SliderValue> extends Omit<ComponentPropsWithRef<"label">, "htmlFor" | "id" | "className" | "style" | "children"> {
|
|
7
|
+
className?: StateValue<string | undefined, SliderRootState<T>>;
|
|
8
|
+
style?: StateValue<CSSProperties | undefined, SliderRootState<T>>;
|
|
9
|
+
children?: StateValue<ReactNode, SliderRootState<T>>;
|
|
10
|
+
/** Must stay a `<label>` when the slider has one thumb (the `for` association). */
|
|
11
|
+
render?: RenderProp<ComponentPropsWithRef<"label">, SliderRootState<T>>;
|
|
12
|
+
}
|
|
13
|
+
/**
|
|
14
|
+
* The visible name of the slider: `<label for>` naming the only thumb's input, or, with several
|
|
15
|
+
* thumbs, the element whose `id` the Root's `aria-labelledby` (`role="group"`) points at, emitted
|
|
16
|
+
* only while a Label is mounted. Owned keys: `id`, `htmlFor`.
|
|
17
|
+
*/
|
|
18
|
+
export declare function SliderLabel<T extends SliderValue = SliderValue>({ className, style, children, render, ...rest }: SliderLabelProps<T>): ReactNode;
|
|
19
|
+
export declare namespace SliderLabel {
|
|
20
|
+
var displayName: string;
|
|
21
|
+
}
|
|
22
|
+
//#endregion
|
|
23
|
+
//# sourceMappingURL=slider-label.d.mts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"slider-label.d.mts","names":[],"sources":["../../src/slider/slider-label.tsx"],"mappings":";;;;;iBAWiB,iBAAiB,UAAU,cAAc,qBAAqB,KAC7E;EAGA,YAAY,+BAA+B,gBAAgB;EAC3D,QAAQ,WAAW,2BAA2B,gBAAgB;EAC9D,WAAW,WAAW,WAAW,gBAAgB;;EAEjD,SAAS,WAAW,gCAAgC,gBAAgB;;;;;;;wBAQtD,YAAY,UAAU,cAAc,eAClD,WACA,OACA,UACA,WACG,QACF,iBAAiB,KAAE;yBANN"}
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { useRender } from "../internal/use-render.mjs";
|
|
3
|
+
import { useSliderContext } from "./slider-context.mjs";
|
|
4
|
+
import { useCallback, useLayoutEffect, useRef } from "react";
|
|
5
|
+
//#region src/slider/slider-label.tsx
|
|
6
|
+
const isDev = process.env.NODE_ENV !== "production";
|
|
7
|
+
/**
|
|
8
|
+
* The visible name of the slider: `<label for>` naming the only thumb's input, or, with several
|
|
9
|
+
* thumbs, the element whose `id` the Root's `aria-labelledby` (`role="group"`) points at, emitted
|
|
10
|
+
* only while a Label is mounted. Owned keys: `id`, `htmlFor`.
|
|
11
|
+
*/
|
|
12
|
+
function SliderLabel({ className, style, children, render, ...rest }) {
|
|
13
|
+
const ctx = useSliderContext("Slider.Label");
|
|
14
|
+
const { registerLabel } = ctx;
|
|
15
|
+
useLayoutEffect(registerLabel, [registerLabel]);
|
|
16
|
+
const single = ctx.shown.length === 1;
|
|
17
|
+
const warnedElement = useRef(false);
|
|
18
|
+
const libraryRef = useCallback((element) => {
|
|
19
|
+
if (isDev && single && !warnedElement.current && element.tagName !== "LABEL") {
|
|
20
|
+
warnedElement.current = true;
|
|
21
|
+
console.error(`Slider.Label: expected a <label> element but got <${element.tagName.toLowerCase()}>. With one thumb the Label names the input through \`for\`, which only a <label> has.`);
|
|
22
|
+
}
|
|
23
|
+
return () => {};
|
|
24
|
+
}, [single]);
|
|
25
|
+
return useRender({
|
|
26
|
+
defaultElement: "label",
|
|
27
|
+
render,
|
|
28
|
+
state: ctx.state,
|
|
29
|
+
className,
|
|
30
|
+
style,
|
|
31
|
+
children,
|
|
32
|
+
props: rest,
|
|
33
|
+
ref: libraryRef,
|
|
34
|
+
libraryProps: {
|
|
35
|
+
id: ctx.labelId,
|
|
36
|
+
htmlFor: single ? ctx.thumbId(0) : void 0
|
|
37
|
+
}
|
|
38
|
+
});
|
|
39
|
+
}
|
|
40
|
+
SliderLabel.displayName = "SliderLabel";
|
|
41
|
+
//#endregion
|
|
42
|
+
export { SliderLabel };
|
|
43
|
+
|
|
44
|
+
//# sourceMappingURL=slider-label.mjs.map
|