@blakesteve/roster 5.10.0 → 5.11.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,87 @@
1
+ import { HTMLAttributes } from 'react';
2
+ import { SliderSnapPoint } from './track';
3
+ export type { SliderSnapPoint };
4
+ /** Every word Slider says. Pass any of them in `labels` to replace it. */
5
+ export interface SliderLabels {
6
+ /** Shown, and said, while there's no value. */
7
+ notSet: string;
8
+ /** What a screen reader hears for a value, with the nearest snap point's label when there is one: "72, Likely". */
9
+ valueText: (value: string, nearest: string | undefined) => string;
10
+ }
11
+ export interface SliderProps extends Omit<HTMLAttributes<HTMLDivElement>, "onChange" | "defaultValue"> {
12
+ /**
13
+ * The value, or `null` for not set: no thumb and an empty track. Pass it to
14
+ * control the slider, `null` included, which is how a consumer offers a
15
+ * clear. Leave it out for an uncontrolled slider that starts from
16
+ * `defaultValue`.
17
+ */
18
+ value?: number | null;
19
+ /**
20
+ * Where an uncontrolled slider starts: `startValue` when left out, the
21
+ * middle unless that's set. `null` starts it not set.
22
+ */
23
+ defaultValue?: number | null;
24
+ /** Each change: a tap, every step of a drag, a key, a snap point. */
25
+ onChange?: (value: number | null) => void;
26
+ /** Once a change is finished: a tap, the end of a drag, a key, a snap point. */
27
+ onCommit?: (value: number) => void;
28
+ /** The lowest value. */
29
+ min?: number;
30
+ /** The highest value. */
31
+ max?: number;
32
+ /** The smallest move: the arrows step by it, and every value lands on it. */
33
+ step?: number;
34
+ /** PageUp and PageDown's move. A tenth of the range, on a step, by default. */
35
+ pageStep?: number;
36
+ /**
37
+ * Where the thumb first appears: an uncontrolled slider's start when
38
+ * `defaultValue` is left out, and where the first arrow or Page key puts it
39
+ * on an empty slider. The middle of the range by default. Home and End go to
40
+ * `min` and `max`.
41
+ */
42
+ startValue?: number;
43
+ /**
44
+ * Named stops, any values and labels. Each gets a chip under the track that
45
+ * moves the thumb to it, and a mark on the track. A point outside `min` to
46
+ * `max` is left out, since the track can't show it.
47
+ */
48
+ snapPoints?: SliderSnapPoint[];
49
+ /** The slider's name, shown above the track. */
50
+ label?: string;
51
+ /** Supporting text under the slider. */
52
+ helperText?: string;
53
+ /** The message for an invalid value. Implies the error state. */
54
+ errorMessage?: string;
55
+ disabled?: boolean;
56
+ /** A form field name: the value is submitted under it, and an empty string while not set. */
57
+ name?: string;
58
+ /** How the value is written, in the readout and in what's said: `(v) => `${v}%`` for a percentage. */
59
+ formatValue?: (value: number) => string;
60
+ /** Every word the slider says, with English defaults. */
61
+ labels?: Partial<SliderLabels>;
62
+ /** Classes for the track's hit area, the element with the slider role. */
63
+ trackClassName?: string;
64
+ /** Classes for the thumb. */
65
+ thumbClassName?: string;
66
+ /** Classes for each snap chip. */
67
+ chipClassName?: string;
68
+ /** Classes for the label. */
69
+ labelClassName?: string;
70
+ /** Classes for the helper text or error message. */
71
+ messageClassName?: string;
72
+ }
73
+ /**
74
+ * A value picked along a track: tapped, dragged, stepped with the keys, or
75
+ * set from a named snap point.
76
+ *
77
+ * It starts with the thumb at `startValue`, the middle by default. Not set is
78
+ * there when it's asked for: `defaultValue={null}`, or `value={null}` when
79
+ * controlled, gives no thumb and an empty track, and a form takes that as a
80
+ * valid answer (an empty string under `name`). The first tap, drag or key sets
81
+ * it, and a consumer controlling `value` can set it back to `null`.
82
+ *
83
+ * One thumb. Two, for a range, is `RangeSlider`, on the same track, so
84
+ * `value` here stays a number.
85
+ */
86
+ declare function Slider({ value: controlled, defaultValue, onChange, onCommit, min, max, step, pageStep, startValue, snapPoints, label, helperText, errorMessage, disabled, name, formatValue, labels: overrides, className, trackClassName, thumbClassName, chipClassName, labelClassName, messageClassName, "aria-invalid": ariaInvalid, "aria-labelledby": ariaLabelledBy, onKeyDown: onKeyDownProp, onPointerDown, onPointerMove, onPointerUp, onPointerCancel, onLostPointerCapture, ...props }: SliderProps): import("react/jsx-runtime").JSX.Element;
87
+ export { Slider };
@@ -0,0 +1,128 @@
1
+ "use client";
2
+ import { jsxs as z, jsx as i } from "react/jsx-runtime";
3
+ import { useId as ve, useState as ge, useReducer as pe, useRef as w } from "react";
4
+ import { cn as A } from "../../../lib/utils.js";
5
+ import { withLabels as me } from "../../../lib/labels.js";
6
+ import { isFieldInvalid as be, withoutInvalidProps as ye } from "../../../internal/field-invalid.js";
7
+ import { useScale as Se, useCommitted as he, useFormReset as we, useTrackPress as ke, inRange as Re, nearestPoint as Ie, along as Ne, thumbClasses as Be, trackClasses as Ce, keyTarget as $e } from "./track.js";
8
+ import { SliderHeader as je, Rail as De, Fill as Fe, Marks as Le, SnapChips as Pe, Message as Te } from "./track-parts.js";
9
+ const Ke = {
10
+ notSet: "Not set",
11
+ valueText: (u, c) => c ? `${u}, ${c}` : u
12
+ };
13
+ function Ge({
14
+ value: u,
15
+ defaultValue: c,
16
+ onChange: E,
17
+ onCommit: k,
18
+ min: n = 0,
19
+ max: o = 100,
20
+ step: R = 1,
21
+ pageStep: H,
22
+ startValue: _,
23
+ snapPoints: q = [],
24
+ label: I,
25
+ helperText: N,
26
+ errorMessage: d,
27
+ disabled: t = !1,
28
+ name: f,
29
+ formatValue: x = String,
30
+ labels: G,
31
+ className: J,
32
+ trackClassName: M,
33
+ thumbClassName: Q,
34
+ chipClassName: U,
35
+ labelClassName: W,
36
+ messageClassName: X,
37
+ "aria-invalid": Y,
38
+ "aria-labelledby": Z,
39
+ onKeyDown: V,
40
+ onPointerDown: ee,
41
+ onPointerMove: re,
42
+ onPointerUp: te,
43
+ onPointerCancel: ie,
44
+ onLostPointerCapture: ne,
45
+ ...v
46
+ }) {
47
+ const g = me(Ke, G), B = ve(), C = `${B}-label`, $ = `${B}-message`, j = Z ?? (I ? C : void 0), l = Se(n, o, R, H), D = l.snap(_ ?? n + (o - n) / 2), p = u !== void 0, [F, L] = ge(c === void 0 ? D : c), P = p ? u : F, r = P === null ? null : l.clamp(P), le = be(!!d, { ...v, "aria-invalid": Y }), T = ye(v), s = he(r), [, se] = pe((e) => e + 1, 0), m = (e, a) => {
48
+ e !== s.current && (s.current = e, p ? se() : L(e), E?.(e), a && e !== null && k?.(e));
49
+ }, K = w(null), O = w(F);
50
+ we(
51
+ K,
52
+ p,
53
+ () => {
54
+ s.current = O.current, L(O.current);
55
+ },
56
+ f
57
+ );
58
+ const b = w(null), { dragging: y, rtl: oe, handlers: ae } = ke({
59
+ trackRef: b,
60
+ disabled: t,
61
+ scale: l,
62
+ min: n,
63
+ max: o,
64
+ values: () => [s.current],
65
+ set: (e, a, fe) => m(a, fe),
66
+ focus: () => b.current?.focus({ preventScroll: !0 }),
67
+ commit: () => s.current !== null && k?.(s.current),
68
+ own: { down: ee, move: re, up: te, cancel: ie, lost: ne }
69
+ }), ue = (e) => {
70
+ if (V?.(e), t) return;
71
+ const a = $e(e, s.current, { scale: l, step: R, start: D, floor: n, ceiling: o, rtl: oe() });
72
+ a !== void 0 && (e.preventDefault(), m(a, !0));
73
+ }, S = Re(q, n, o), h = r === null ? null : x(r), ce = h === null ? g.notSet : g.valueText(h, Ie(S, r)?.label), de = [N || d ? $ : void 0, v["aria-describedby"]].filter(Boolean).join(" ") || void 0;
74
+ return /* @__PURE__ */ z("div", { className: A("rst:font-ui rst:flex rst:min-w-0 rst:flex-col rst:gap-1.5", J), "data-slider": "", children: [
75
+ /* @__PURE__ */ i(je, { labelId: C, label: I, readout: h ?? g.notSet, empty: r === null, disabled: t, labelClassName: W }),
76
+ /* @__PURE__ */ z(
77
+ "div",
78
+ {
79
+ ...T,
80
+ ...ae,
81
+ ref: b,
82
+ role: "slider",
83
+ tabIndex: t ? void 0 : 0,
84
+ "aria-labelledby": j,
85
+ "aria-describedby": de,
86
+ "aria-valuemin": n,
87
+ "aria-valuemax": o,
88
+ "aria-valuenow": r ?? void 0,
89
+ "aria-valuetext": ce,
90
+ "aria-orientation": "horizontal",
91
+ "aria-disabled": t || void 0,
92
+ "aria-invalid": le || void 0,
93
+ "data-dragging": y ? "" : void 0,
94
+ "data-empty": r === null ? "" : void 0,
95
+ onKeyDown: ue,
96
+ className: A(
97
+ Ce(t),
98
+ "rst:group/slider rst:focus-visible:outline-hidden",
99
+ r === null && "rst:focus-visible:ring-2 rst:focus-visible:ring-ring",
100
+ M
101
+ ),
102
+ children: [
103
+ /* @__PURE__ */ i(De, {}),
104
+ r !== null && /* @__PURE__ */ i(Fe, { from: 0, to: l.at(r), dragging: y }),
105
+ /* @__PURE__ */ i(Le, { points: S, at: l.at, filled: (e) => r !== null && r >= e }),
106
+ r !== null && /* @__PURE__ */ i("span", { "aria-hidden": "true", "data-slider-thumb": "", className: Be(y, "rst:group-focus-visible/slider:ring-2 rst:group-focus-visible/slider:ring-ring rst:group-focus-visible/slider:ring-offset-2 rst:ring-offset-background", Q), style: { insetInlineStart: Ne(l.at(r)) } })
107
+ ]
108
+ }
109
+ ),
110
+ /* @__PURE__ */ i(
111
+ Pe,
112
+ {
113
+ points: S,
114
+ labelledBy: j,
115
+ label: T["aria-label"],
116
+ pressed: (e) => r === e,
117
+ pick: (e) => m(e, !0),
118
+ disabled: t,
119
+ chipClassName: U
120
+ }
121
+ ),
122
+ /* @__PURE__ */ i(Te, { id: $, helperText: N, errorMessage: d, disabled: t, className: X }),
123
+ f && /* @__PURE__ */ i("input", { ref: K, type: "hidden", name: f, value: r === null ? "" : String(r), disabled: t, readOnly: !0 })
124
+ ] });
125
+ }
126
+ export {
127
+ Ge as Slider
128
+ };
@@ -0,0 +1 @@
1
+ "use client";"use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const r=require("react/jsx-runtime"),a=require("../../../lib/utils.cjs"),i=require("../../atoms/Chip/Chip.cjs"),s=require("./track.cjs");function d(t){return r.jsxs("div",{className:"rst:flex rst:items-baseline rst:justify-between rst:gap-3",children:[t.label?r.jsx("span",{id:t.labelId,className:a.cn("rst:text-sm rst:font-medium rst:text-[var(--roster-control-text)]",t.disabled&&"rst:opacity-50",t.labelClassName),children:t.label}):r.jsx("span",{}),r.jsx("span",{"aria-hidden":"true","data-slider-readout":"",className:a.cn("rst:text-sm rst:tabular-nums",t.empty?"rst:text-gray-500 rst:dark:text-gray-400":"rst:font-semibold rst:text-[var(--roster-control-text)]",t.disabled&&"rst:opacity-50"),children:t.readout})]})}function o(){return r.jsx("span",{"aria-hidden":"true","data-slider-rail":"",className:"rst:absolute rst:top-1/2 rst:h-2.5 rst:-translate-y-1/2 rst:rounded-full rst:border rst:border-[var(--roster-control-border)] rst:bg-gray-100 rst:dark:bg-gray-800",style:{insetInline:s.INSET}})}function c({from:t,to:e,dragging:n}){return r.jsx("span",{"aria-hidden":"true","data-slider-fill":"",className:a.cn("rst:absolute rst:top-1/2 rst:h-2.5 rst:-translate-y-1/2 rst:rounded-full rst:bg-primary-600 rst:dark:bg-primary-400","rst:forced-colors:forced-color-adjust-none rst:forced-colors:bg-[Highlight]",!n&&"rst:transition-[inset-inline-start,width] rst:duration-150 rst:ease-out rst:motion-reduce:transition-none"),style:{insetInlineStart:s.along(t),width:`calc((100% - ${2*s.INSET}px) * ${e-t})`}})}function u({points:t,at:e,filled:n}){return t.map(l=>r.jsx("span",{"aria-hidden":"true","data-slider-mark":"","data-filled":n(l.value)?"":void 0,className:a.cn("rst:absolute rst:top-1/2 rst:size-1.5 rst:-translate-x-1/2 rst:-translate-y-1/2 rst:rounded-full rst:rtl:translate-x-1/2","rst:transition-colors rst:duration-150 rst:motion-reduce:transition-none rst:forced-colors:forced-color-adjust-none",n(l.value)?"rst:bg-white rst:dark:bg-gray-900 rst:forced-colors:bg-[Canvas]":"rst:bg-[var(--roster-control-border)] rst:forced-colors:bg-[CanvasText]"),style:{insetInlineStart:s.along(e(l.value),s.INSET+s.CAP)}},`${l.value}:${l.label}`))}function b(t){return t.points.length===0?null:r.jsx("div",{role:"group","aria-labelledby":t.labelledBy,"aria-label":t.labelledBy?void 0:t.label,className:"rst:mt-0.5 rst:flex rst:flex-wrap rst:gap-x-2 rst:gap-y-4","data-slider-snaps":"",children:t.points.map(e=>r.jsx(i.Chip,{selected:t.pressed(e.value),onSelectedChange:()=>t.pick(e.value),variant:t.pressed(e.value)?"solid":"outline",colorScheme:t.pressed(e.value)?"primary":"neutral",disabled:t.disabled,className:a.cn("rst:min-w-11 rst:shrink-0 rst:justify-center",t.chipClassName),children:e.label},`${e.value}:${e.label}`))})}function x(t){return!t.helperText&&!t.errorMessage?null:r.jsx("p",{id:t.id,className:a.cn("rst:m-0 rst:text-xs rst:text-left",t.errorMessage?"rst:text-error-600 rst:dark:text-error-400 rst:font-medium":"rst:text-gray-500 rst:dark:text-gray-400",t.disabled&&"rst:opacity-50",t.className),children:t.errorMessage||t.helperText})}exports.Fill=c;exports.Marks=u;exports.Message=x;exports.Rail=o;exports.SliderHeader=d;exports.SnapChips=b;
@@ -0,0 +1,64 @@
1
+ import { SliderSnapPoint } from './track';
2
+ /** The label and the visible number above the track. The number is hidden from screen readers, which hear it as the value. */
3
+ export declare function SliderHeader(props: {
4
+ labelId: string;
5
+ label?: string;
6
+ readout: string;
7
+ empty: boolean;
8
+ disabled: boolean;
9
+ labelClassName?: string;
10
+ }): import("react/jsx-runtime").JSX.Element;
11
+ /**
12
+ * The rail, from the start edge's inset to the end edge's: a light surface
13
+ * edged in the control border's color. With no value it's all there is of
14
+ * the slider, so its edge carries the 3:1 a control's does.
15
+ */
16
+ export declare function Rail(): import("react/jsx-runtime").JSX.Element;
17
+ /** The filled part of the rail, between two shares of it. */
18
+ export declare function Fill({ from, to, dragging }: {
19
+ from: number;
20
+ to: number;
21
+ dragging: boolean;
22
+ }): import("react/jsx-runtime").JSX.Element;
23
+ /**
24
+ * Each snap point's mark: a bead set in the rail, its edge's color on the
25
+ * bare rail and the page's on the fill, so it shows on either.
26
+ */
27
+ export declare function Marks({ points, at, filled }: {
28
+ points: SliderSnapPoint[];
29
+ at: (v: number) => number;
30
+ filled: (v: number) => boolean;
31
+ }): import("react/jsx-runtime").JSX.Element[];
32
+ /**
33
+ * A chip for each snap point, under the track, in a group named as the
34
+ * slider is so the chips are heard as its presets.
35
+ *
36
+ * The clearance is what Chip's 44px target asks of its layout: it reaches up
37
+ * to 8px above and below the chip, so the row sits 8px under the track (the
38
+ * column's 6px and 2px more), where it can't take the bottom of a thumb's
39
+ * target, and wrapped rows are 16px apart. A short label is widened to 44
40
+ * too, since the target is only as wide as the chip, and no chip shrinks: a
41
+ * min-width replaces the flex item's own floor of its label's width, so in a
42
+ * row narrower than a label the chip would otherwise squeeze to 44 under it.
43
+ *
44
+ * A chip only ever moves a value to itself: pressed again, it stays, as a
45
+ * preset does. Pressed swaps outline for solid, as Chip's own selectable
46
+ * does, so it reads without color.
47
+ */
48
+ export declare function SnapChips(props: {
49
+ points: SliderSnapPoint[];
50
+ labelledBy: string | undefined;
51
+ label: string | undefined;
52
+ pressed: (v: number) => boolean;
53
+ pick: (v: number) => void;
54
+ disabled: boolean;
55
+ chipClassName?: string;
56
+ }): import("react/jsx-runtime").JSX.Element | null;
57
+ /** The helper text, or the error in its place. */
58
+ export declare function Message(props: {
59
+ id: string;
60
+ helperText?: string;
61
+ errorMessage?: string;
62
+ disabled: boolean;
63
+ className?: string;
64
+ }): import("react/jsx-runtime").JSX.Element | null;
@@ -0,0 +1,121 @@
1
+ "use client";
2
+ import { jsxs as d, jsx as e } from "react/jsx-runtime";
3
+ import { cn as a } from "../../../lib/utils.js";
4
+ import { Chip as o } from "../../atoms/Chip/Chip.js";
5
+ import { INSET as n, along as i, CAP as c } from "./track.js";
6
+ function g(t) {
7
+ return /* @__PURE__ */ d("div", { className: "rst:flex rst:items-baseline rst:justify-between rst:gap-3", children: [
8
+ t.label ? /* @__PURE__ */ e(
9
+ "span",
10
+ {
11
+ id: t.labelId,
12
+ className: a("rst:text-sm rst:font-medium rst:text-[var(--roster-control-text)]", t.disabled && "rst:opacity-50", t.labelClassName),
13
+ children: t.label
14
+ }
15
+ ) : /* @__PURE__ */ e("span", {}),
16
+ /* @__PURE__ */ e(
17
+ "span",
18
+ {
19
+ "aria-hidden": "true",
20
+ "data-slider-readout": "",
21
+ className: a(
22
+ "rst:text-sm rst:tabular-nums",
23
+ t.empty ? "rst:text-gray-500 rst:dark:text-gray-400" : "rst:font-semibold rst:text-[var(--roster-control-text)]",
24
+ t.disabled && "rst:opacity-50"
25
+ ),
26
+ children: t.readout
27
+ }
28
+ )
29
+ ] });
30
+ }
31
+ function x() {
32
+ return /* @__PURE__ */ e(
33
+ "span",
34
+ {
35
+ "aria-hidden": "true",
36
+ "data-slider-rail": "",
37
+ className: "rst:absolute rst:top-1/2 rst:h-2.5 rst:-translate-y-1/2 rst:rounded-full rst:border rst:border-[var(--roster-control-border)] rst:bg-gray-100 rst:dark:bg-gray-800",
38
+ style: { insetInline: n }
39
+ }
40
+ );
41
+ }
42
+ function h({ from: t, to: r, dragging: l }) {
43
+ return /* @__PURE__ */ e(
44
+ "span",
45
+ {
46
+ "aria-hidden": "true",
47
+ "data-slider-fill": "",
48
+ className: a(
49
+ "rst:absolute rst:top-1/2 rst:h-2.5 rst:-translate-y-1/2 rst:rounded-full rst:bg-primary-600 rst:dark:bg-primary-400",
50
+ "rst:forced-colors:forced-color-adjust-none rst:forced-colors:bg-[Highlight]",
51
+ !l && "rst:transition-[inset-inline-start,width] rst:duration-150 rst:ease-out rst:motion-reduce:transition-none"
52
+ ),
53
+ style: { insetInlineStart: i(t), width: `calc((100% - ${2 * n}px) * ${r - t})` }
54
+ }
55
+ );
56
+ }
57
+ function y({ points: t, at: r, filled: l }) {
58
+ return t.map((s) => /* @__PURE__ */ e(
59
+ "span",
60
+ {
61
+ "aria-hidden": "true",
62
+ "data-slider-mark": "",
63
+ "data-filled": l(s.value) ? "" : void 0,
64
+ className: a(
65
+ "rst:absolute rst:top-1/2 rst:size-1.5 rst:-translate-x-1/2 rst:-translate-y-1/2 rst:rounded-full rst:rtl:translate-x-1/2",
66
+ "rst:transition-colors rst:duration-150 rst:motion-reduce:transition-none rst:forced-colors:forced-color-adjust-none",
67
+ l(s.value) ? "rst:bg-white rst:dark:bg-gray-900 rst:forced-colors:bg-[Canvas]" : "rst:bg-[var(--roster-control-border)] rst:forced-colors:bg-[CanvasText]"
68
+ ),
69
+ style: { insetInlineStart: i(r(s.value), n + c) }
70
+ },
71
+ `${s.value}:${s.label}`
72
+ ));
73
+ }
74
+ function v(t) {
75
+ return t.points.length === 0 ? null : /* @__PURE__ */ e(
76
+ "div",
77
+ {
78
+ role: "group",
79
+ "aria-labelledby": t.labelledBy,
80
+ "aria-label": t.labelledBy ? void 0 : t.label,
81
+ className: "rst:mt-0.5 rst:flex rst:flex-wrap rst:gap-x-2 rst:gap-y-4",
82
+ "data-slider-snaps": "",
83
+ children: t.points.map((r) => /* @__PURE__ */ e(
84
+ o,
85
+ {
86
+ selected: t.pressed(r.value),
87
+ onSelectedChange: () => t.pick(r.value),
88
+ variant: t.pressed(r.value) ? "solid" : "outline",
89
+ colorScheme: t.pressed(r.value) ? "primary" : "neutral",
90
+ disabled: t.disabled,
91
+ className: a("rst:min-w-11 rst:shrink-0 rst:justify-center", t.chipClassName),
92
+ children: r.label
93
+ },
94
+ `${r.value}:${r.label}`
95
+ ))
96
+ }
97
+ );
98
+ }
99
+ function N(t) {
100
+ return !t.helperText && !t.errorMessage ? null : /* @__PURE__ */ e(
101
+ "p",
102
+ {
103
+ id: t.id,
104
+ className: a(
105
+ "rst:m-0 rst:text-xs rst:text-left",
106
+ t.errorMessage ? "rst:text-error-600 rst:dark:text-error-400 rst:font-medium" : "rst:text-gray-500 rst:dark:text-gray-400",
107
+ t.disabled && "rst:opacity-50",
108
+ t.className
109
+ ),
110
+ children: t.errorMessage || t.helperText
111
+ }
112
+ );
113
+ }
114
+ export {
115
+ h as Fill,
116
+ y as Marks,
117
+ N as Message,
118
+ x as Rail,
119
+ g as SliderHeader,
120
+ v as SnapChips
121
+ };
@@ -0,0 +1 @@
1
+ "use client";"use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const h=require("react"),A=require("../../../lib/utils.cjs"),p=22,E=5,I=(t,s=p)=>`calc(${s}px + (100% - ${2*s}px) * ${t})`,X=t=>{const[s,n="0"]=String(t).split("e"),c=s.indexOf(".");return Math.max(0,(c===-1?0:s.length-c-1)-Number(n))};function D(t,s,n,c){const o=Math.max(X(n),X(t)),u=h.useCallback(b=>Math.min(s,Math.max(t,b)),[t,s]),l=h.useCallback((b,M=0)=>{const g=(b-t)/n,C=Math.round(g),R=M===0||Math.abs(g-C)<1e-6?C:M>0?Math.floor(g):Math.ceil(g);return u(Number((t+R*n).toFixed(o)))},[t,n,o,u]),T=h.useCallback(b=>s===t?0:(b-t)/(s-t),[t,s]);return{clamp:u,snap:l,at:T,coarse:c??Math.max(n,l(t+(s-t)/10)-t)}}function L(t,s,n){if(t.defaultPrevented||t.altKey||t.ctrlKey||t.metaKey)return;const c=u=>Math.min(n.ceiling,Math.max(n.floor,u)),o=u=>s===null?n.start:c(n.scale.snap(s+u,u>0?1:-1));switch(t.key){case(n.rtl?"ArrowLeft":"ArrowRight"):case"ArrowUp":return o(n.step);case(n.rtl?"ArrowRight":"ArrowLeft"):case"ArrowDown":return o(-n.step);case"PageUp":return o(n.scale.coarse);case"PageDown":return o(-n.scale.coarse);case"Home":return n.floor;case"End":return n.ceiling;default:return}}function N(t){const[s,n]=h.useState(!1),c=h.useRef(null),o=()=>!!t.trackRef.current&&getComputedStyle(t.trackRef.current).direction==="rtl",u=()=>t.trackRef.current.getBoundingClientRect(),l=r=>{const e=u();let a=(r-e.left-p)/Math.max(1,e.width-2*p);return a=Math.min(1,Math.max(0,a)),o()&&(a=1-a),t.scale.snap(t.min+a*(t.max-t.min))},T=r=>{const e=u();return e.left+p+(e.width-2*p)*(o()?1-t.scale.at(r):t.scale.at(r))},b=r=>t.values().some((e,a)=>e!==r[a]),M=(r,e)=>{try{r.setPointerCapture(e)}catch{}n(!0)},g=(r,e,a)=>{const f=c.current;!f||f.id!==e||(c.current=null,f.mode==="drag"&&(n(!1),r.hasPointerCapture(e)&&r.releasePointerCapture(e),a&&b(f.from)&&t.commit()))},C=(r,e)=>{if(r.thumb!=="either")return r.thumb;const a=t.values()[r.tied[0]];if(e!==a)return r.thumb=e>a?r.tied[r.tied.length-1]:r.tied[0],t.focus(r.thumb),r.thumb};return{dragging:s,rtl:o,handlers:{onPointerDown:r=>{if(t.own.down?.(r),t.disabled||r.button!==0)return;if(c.current){if(!r.isPrimary)return;g(r.currentTarget,c.current.id,!1)}r.preventDefault();const e=r.currentTarget,a=t.values(),f=a.map((i,k)=>({v:i,i:k})).filter(i=>i.v!==null),P=i=>Math.abs(r.clientX-T(i)),d=f.reduce((i,k)=>!i||P(k.v)<P(i.v)?k:i,void 0),m=!!d&&P(d.v)<=p,w=d?f.filter(i=>i.v===d.v).map(i=>i.i):[0];let y=d?d.i:0;if(w.length>1){const i=l(r.clientX);y=m?"either":i<d.v?w[0]:w[w.length-1]}const S=m?T(d.v)-r.clientX:0,x={id:r.pointerId,x:r.clientX,y:r.clientY,thumb:y,tied:w,grab:S,from:a};if(r.pointerType==="mouse"||m){t.focus(y==="either"?w[0]:y),c.current={...x,mode:"drag"},M(e,r.pointerId),!m&&y!=="either"&&t.set(y,l(r.clientX),!1);return}c.current={...x,mode:"pending"}},onPointerMove:r=>{t.own.move?.(r);const e=c.current;if(!e||e.id!==r.pointerId)return;if(e.mode==="pending"){const P=Math.abs(r.clientX-e.x),d=Math.abs(r.clientY-e.y);if(P>7&&P>d){e.mode="drag",M(r.currentTarget,r.pointerId);const m=C(e,l(r.clientX));m!==void 0&&(t.focus(m),t.set(m,l(r.clientX),!1))}else d>10&&(c.current=null);return}const a=l(r.clientX+e.grab),f=C(e,a);f!==void 0&&t.set(f,a,!1)},onPointerUp:r=>{t.own.up?.(r);const e=c.current;if(e&&e.id===r.pointerId&&e.mode==="pending"){c.current=null,e.thumb!=="either"&&(t.focus(e.thumb),t.set(e.thumb,l(r.clientX),!0));return}g(r.currentTarget,r.pointerId,!0)},onPointerCancel:r=>{t.own.cancel?.(r),g(r.currentTarget,r.pointerId,!0)},onLostPointerCapture:r=>{t.own.lost?.(r),r.target===r.currentTarget&&g(r.currentTarget,r.pointerId,!0)}}}}function U(t){const s=h.useRef(t);return h.useLayoutEffect(()=>{s.current=t}),s}function F(t,s,n,c){const o=h.useRef(n);h.useEffect(()=>{o.current=n}),h.useEffect(()=>{const u=t.current?.form;if(!u||s)return;const l=()=>o.current();return u.addEventListener("reset",l),()=>u.removeEventListener("reset",l)},[t,s,c])}const K=(t,s,n)=>t.filter(c=>c.value>=s&&c.value<=n).sort((c,o)=>c.value-o.value),$=(t,s)=>s===null||t.length===0?void 0:t.reduce((n,c)=>Math.abs(c.value-s)<Math.abs(n.value-s)?c:n,t[0]),q=t=>A.cn("rst:relative rst:h-11 rst:w-full rst:touch-pan-y rst:select-none rst:rounded-md",t?"rst:cursor-not-allowed rst:opacity-50":"rst:cursor-pointer"),H=(t,s,n)=>A.cn("rst:absolute rst:top-1/2 rst:size-5 rst:-translate-x-1/2 rst:-translate-y-1/2 rst:rounded-full rst:rtl:translate-x-1/2","rst:border-2 rst:border-primary-600 rst:bg-white rst:elevation-control rst:dark:border-primary-400 rst:dark:bg-gray-900","rst:forced-colors:border-[Highlight]",s,!t&&"rst:transition-[inset-inline-start] rst:duration-150 rst:ease-out rst:motion-reduce:transition-none",n);exports.CAP=E;exports.INSET=p;exports.along=I;exports.inRange=K;exports.keyTarget=L;exports.nearestPoint=$;exports.thumbClasses=H;exports.trackClasses=q;exports.useCommitted=U;exports.useFormReset=F;exports.useScale=D;exports.useTrackPress=N;
@@ -0,0 +1,115 @@
1
+ import { KeyboardEvent, PointerEvent, RefObject } from 'react';
2
+ /** A named stop on the track: a chip under it moves a thumb there. */
3
+ export interface SliderSnapPoint {
4
+ value: number;
5
+ label: string;
6
+ }
7
+ export declare const INSET = 22;
8
+ export declare const CAP = 5;
9
+ /** A place along the rail, as a share of it from the start edge, for `inset-inline-start`. */
10
+ export declare const along: (share: number, inset?: number) => string;
11
+ export interface Scale {
12
+ clamp: (n: number) => number;
13
+ /**
14
+ * The nearest value on a step, in range. `toward` takes the next one that
15
+ * way instead, for a key from a value between steps (a controlled value off
16
+ * the grid, or a `max` that isn't on it): Left from 1 on a 0.3 step lands on
17
+ * 0.9, not 0.6.
18
+ */
19
+ snap: (raw: number, toward?: -1 | 0 | 1) => number;
20
+ /** PageUp and PageDown's move. */
21
+ coarse: number;
22
+ /** A value's share of the range, from `min`. */
23
+ at: (v: number) => number;
24
+ }
25
+ export declare function useScale(min: number, max: number, step: number, pageStep: number | undefined): Scale;
26
+ /**
27
+ * Where a key takes a thumb, or `undefined` for a key that isn't the
28
+ * slider's. The arrows step by `step` and the Page keys by the scale's
29
+ * `coarse`, Home and End go to `floor` and `ceiling`, and a thumb with no
30
+ * value goes to `start` on an arrow or Page key rather than stepping from
31
+ * anywhere. A combination is the app's or the browser's, and so is a key its
32
+ * owner has already handled.
33
+ */
34
+ export declare function keyTarget(event: KeyboardEvent, now: number | null, o: {
35
+ scale: Scale;
36
+ step: number;
37
+ start: number;
38
+ floor: number;
39
+ ceiling: number;
40
+ rtl: boolean;
41
+ }): number | undefined;
42
+ type Handler = ((event: PointerEvent<HTMLDivElement>) => void) | undefined;
43
+ /**
44
+ * The track's pointer, for any number of thumbs.
45
+ *
46
+ * A mouse press, or one on a thumb, drags at once. A touch on the track waits
47
+ * to see which way it goes: across is a drag, down the page is a scroll and
48
+ * sets nothing, and no movement is a tap, set when the finger lifts. A press
49
+ * takes the thumb nearest it, worked out from the values rather than from
50
+ * the drawn thumbs, which may still be easing there. Two thumbs on one spot
51
+ * are told apart by the way the drag first moves: up the range takes the
52
+ * higher one. A press on a thumb keeps where it landed on it, rather than
53
+ * jumping the thumb to the pointer.
54
+ */
55
+ export declare function useTrackPress(o: {
56
+ trackRef: RefObject<HTMLDivElement | null>;
57
+ disabled: boolean;
58
+ scale: Scale;
59
+ min: number;
60
+ max: number;
61
+ /** The values the thumbs are at, by index; `null` for one not placed. */
62
+ values: () => (number | null)[];
63
+ set: (thumb: number, value: number, finished: boolean) => void;
64
+ focus: (thumb: number) => void;
65
+ /** A drag that moved something has ended. */
66
+ commit: () => void;
67
+ /** The consumer's own handlers, called first. */
68
+ own: {
69
+ down: Handler;
70
+ move: Handler;
71
+ up: Handler;
72
+ cancel: Handler;
73
+ lost: Handler;
74
+ };
75
+ }): {
76
+ dragging: boolean;
77
+ rtl: () => boolean;
78
+ handlers: {
79
+ onPointerDown: (event: PointerEvent<HTMLDivElement>) => void;
80
+ onPointerMove: (event: PointerEvent<HTMLDivElement>) => void;
81
+ onPointerUp: (event: PointerEvent<HTMLDivElement>) => void;
82
+ onPointerCancel: (event: PointerEvent<HTMLDivElement>) => void;
83
+ onLostPointerCapture: (event: PointerEvent<HTMLDivElement>) => void;
84
+ };
85
+ };
86
+ /**
87
+ * Keeps a ref on the values the thumbs are at, for the keys and the pointer
88
+ * to step from. Set the moment a change is made, so input that arrives
89
+ * before a render counts every press, and never read from the drawn thumbs,
90
+ * which ease toward the values after them. Each render brings it back to the
91
+ * values, which a controlling owner may have set from outside, or declined.
92
+ */
93
+ export declare function useCommitted<T>(value: T): RefObject<T>;
94
+ /**
95
+ * A form's reset puts an uncontrolled slider back where it started, as it
96
+ * does a native input. A controlled one is its owner's to reset.
97
+ */
98
+ export declare function useFormReset(input: RefObject<HTMLInputElement | null>, controlled: boolean, reset: () => void, name: string | undefined): void;
99
+ /** Snap points in range, in the track's order, low to high from its start, whatever order they came in. */
100
+ export declare const inRange: (points: SliderSnapPoint[], min: number, max: number) => SliderSnapPoint[];
101
+ /** The snap point nearest a value. Halfway between two, the lower one's. */
102
+ export declare const nearestPoint: (points: SliderSnapPoint[], value: number | null) => SliderSnapPoint | undefined;
103
+ /**
104
+ * The track's classes. 44px tall, a thumb's whole target. pan-y: a finger
105
+ * moving down the page still scrolls it; across, it drags.
106
+ */
107
+ export declare const trackClasses: (disabled: boolean) => string;
108
+ /**
109
+ * A thumb's classes: drawn where its value is, eased there unless it's being
110
+ * dragged. Its target is the 44px around it, which the track's height and
111
+ * inset keep on the track. `ring` is the focus ring, for whichever state
112
+ * shows it.
113
+ */
114
+ export declare const thumbClasses: (dragging: boolean, ring: string, className?: string) => string;
115
+ export {};