@charcuterie/ui 3.33.0 → 4.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (105) hide show
  1. package/README.md +30 -0
  2. package/dist/Board/Board.d.ts.map +1 -1
  3. package/dist/Board/Board.js +2 -2
  4. package/dist/Board/Board.js.map +1 -1
  5. package/dist/Main/Main.d.ts +18 -19
  6. package/dist/Main/Main.d.ts.map +1 -1
  7. package/dist/Main/Main.js +21 -10
  8. package/dist/Main/Main.js.map +1 -1
  9. package/dist/Main/ScrollMemoryProvider.d.ts +38 -0
  10. package/dist/Main/ScrollMemoryProvider.d.ts.map +1 -0
  11. package/dist/Main/ScrollMemoryProvider.js +30 -0
  12. package/dist/Main/ScrollMemoryProvider.js.map +1 -0
  13. package/dist/Main/scrollMemory.d.ts +54 -28
  14. package/dist/Main/scrollMemory.d.ts.map +1 -1
  15. package/dist/Main/scrollMemory.js +81 -40
  16. package/dist/Main/scrollMemory.js.map +1 -1
  17. package/dist/Main/scrollMemoryContext.d.ts +18 -0
  18. package/dist/Main/scrollMemoryContext.d.ts.map +1 -0
  19. package/dist/Main/scrollMemoryContext.js +18 -0
  20. package/dist/Main/scrollMemoryContext.js.map +1 -0
  21. package/dist/Main/useScrollMemory.d.ts +20 -18
  22. package/dist/Main/useScrollMemory.d.ts.map +1 -1
  23. package/dist/Main/useScrollMemory.js +69 -42
  24. package/dist/Main/useScrollMemory.js.map +1 -1
  25. package/dist/RangeSlider/RangeSlider.d.ts +117 -0
  26. package/dist/RangeSlider/RangeSlider.d.ts.map +1 -0
  27. package/dist/RangeSlider/RangeSlider.js +242 -0
  28. package/dist/RangeSlider/RangeSlider.js.map +1 -0
  29. package/dist/RangeSlider/rangeSliderValue.d.ts +102 -0
  30. package/dist/RangeSlider/rangeSliderValue.d.ts.map +1 -0
  31. package/dist/RangeSlider/rangeSliderValue.js +116 -0
  32. package/dist/RangeSlider/rangeSliderValue.js.map +1 -0
  33. package/dist/SegmentedControl/SegmentedControl.d.ts +12 -1
  34. package/dist/SegmentedControl/SegmentedControl.d.ts.map +1 -1
  35. package/dist/SegmentedControl/SegmentedControl.js +3 -3
  36. package/dist/SegmentedControl/SegmentedControl.js.map +1 -1
  37. package/dist/SegmentedControl/SegmentedOption.d.ts +2 -1
  38. package/dist/SegmentedControl/SegmentedOption.d.ts.map +1 -1
  39. package/dist/SegmentedControl/SegmentedOption.js +7 -2
  40. package/dist/SegmentedControl/SegmentedOption.js.map +1 -1
  41. package/dist/Slider/Slider.d.ts +6 -1
  42. package/dist/Slider/Slider.d.ts.map +1 -1
  43. package/dist/Slider/Slider.js +8 -22
  44. package/dist/Slider/Slider.js.map +1 -1
  45. package/dist/TimecodeInput/TimecodeInput.d.ts +88 -0
  46. package/dist/TimecodeInput/TimecodeInput.d.ts.map +1 -0
  47. package/dist/TimecodeInput/TimecodeInput.js +258 -0
  48. package/dist/TimecodeInput/TimecodeInput.js.map +1 -0
  49. package/dist/TimecodeInput/timecode.d.ts +132 -0
  50. package/dist/TimecodeInput/timecode.d.ts.map +1 -0
  51. package/dist/TimecodeInput/timecode.js +246 -0
  52. package/dist/TimecodeInput/timecode.js.map +1 -0
  53. package/dist/index.d.ts +10 -0
  54. package/dist/index.d.ts.map +1 -1
  55. package/dist/index.js +4 -0
  56. package/dist/index.js.map +1 -1
  57. package/dist/reactRouter/ReactRouterAdapter.d.ts +43 -0
  58. package/dist/reactRouter/ReactRouterAdapter.d.ts.map +1 -0
  59. package/dist/reactRouter/ReactRouterAdapter.js +50 -0
  60. package/dist/reactRouter/ReactRouterAdapter.js.map +1 -0
  61. package/dist/reactRouter/index.d.ts +14 -8
  62. package/dist/reactRouter/index.d.ts.map +1 -1
  63. package/dist/reactRouter/index.js +13 -8
  64. package/dist/reactRouter/index.js.map +1 -1
  65. package/dist/sliderStyles.d.ts +39 -0
  66. package/dist/sliderStyles.d.ts.map +1 -0
  67. package/dist/sliderStyles.js +50 -0
  68. package/dist/sliderStyles.js.map +1 -0
  69. package/package.json +1 -1
  70. package/src/Board/Board.test.tsx +8 -0
  71. package/src/Board/Board.tsx +7 -1
  72. package/src/Main/Main.mdx +35 -7
  73. package/src/Main/Main.stories.tsx +129 -64
  74. package/src/Main/Main.test.tsx +58 -0
  75. package/src/Main/Main.tsx +20 -20
  76. package/src/Main/ScrollMemoryProvider.tsx +48 -0
  77. package/src/Main/scrollMemory.test.ts +70 -16
  78. package/src/Main/scrollMemory.ts +98 -40
  79. package/src/Main/scrollMemoryContext.ts +21 -0
  80. package/src/Main/useScrollMemory.ts +83 -43
  81. package/src/RangeSlider/RangeSlider.mdx +85 -0
  82. package/src/RangeSlider/RangeSlider.stories.tsx +346 -0
  83. package/src/RangeSlider/RangeSlider.test.tsx +452 -0
  84. package/src/RangeSlider/RangeSlider.tsx +595 -0
  85. package/src/RangeSlider/rangeSliderValue.test.ts +217 -0
  86. package/src/RangeSlider/rangeSliderValue.ts +185 -0
  87. package/src/RouterLink/RouterLink.mdx +53 -16
  88. package/src/SegmentedControl/SegmentedControl.stories.tsx +50 -0
  89. package/src/SegmentedControl/SegmentedControl.test.tsx +36 -1
  90. package/src/SegmentedControl/SegmentedControl.tsx +14 -0
  91. package/src/SegmentedControl/SegmentedOption.tsx +7 -0
  92. package/src/Slider/Slider.tsx +23 -29
  93. package/src/TimecodeInput/TimecodeInput.mdx +155 -0
  94. package/src/TimecodeInput/TimecodeInput.stories.tsx +304 -0
  95. package/src/TimecodeInput/TimecodeInput.test.tsx +279 -0
  96. package/src/TimecodeInput/TimecodeInput.tsx +493 -0
  97. package/src/TimecodeInput/timecode.test.ts +236 -0
  98. package/src/TimecodeInput/timecode.ts +391 -0
  99. package/src/index.ts +21 -0
  100. package/src/reactRouter/ReactRouterAdapter.stories.tsx +120 -0
  101. package/src/reactRouter/ReactRouterAdapter.test.tsx +92 -0
  102. package/src/reactRouter/ReactRouterAdapter.tsx +66 -0
  103. package/src/reactRouter/index.ts +14 -8
  104. package/src/sliderStyles.ts +69 -0
  105. package/src/sourceRules.test.ts +29 -3
@@ -1,29 +1,31 @@
1
+ import { type ScrollEntry } from "./scrollMemory.ts";
1
2
  /**
2
- * Remember where this history entry was scrolled to, and put it
3
- * back when the reader returns to it.
3
+ * Remember where this history entry was scrolled to, and put it back
4
+ * when the reader returns to it.
4
5
  *
5
- * `scrollMemory.ts` says why the browser will not. This is the
6
- * part that has to survive the two things a real page does:
6
+ * `scrollMemory.ts` says why the browser will not, and what an entry
7
+ * that has never been seen should do. This is the part that has to
8
+ * survive the two things a real page does:
7
9
  *
8
10
  * 1. **The content arrives late.** An offset applied against a
9
- * 600px skeleton clamps to `0` and looks like it did nothing.
10
- * A `ResizeObserver` on the scrollport and on its content
11
- * column re-applies the offset every time either grows, until
12
- * the offset lands or the window closes.
13
- * 2. **The reader scrolls during all that.** Any wheel, touch,
14
- * key or pointer press ends the restore immediately. The
15
- * alternative is a page that jumps out from under somebody who
16
- * has already started reading.
11
+ * 600px skeleton clamps to `0` and looks like it did nothing. A
12
+ * `ResizeObserver` on the scrollport and on its content column
13
+ * re-applies the offset every time either grows, until the
14
+ * offset lands or the window closes.
15
+ * 2. **The reader scrolls during all that.** Any wheel, touch, key
16
+ * or pointer press ends the restore immediately. The alternative
17
+ * is a page that jumps out from under somebody who has already
18
+ * started reading.
17
19
  *
18
20
  * The save is a passive `scroll` listener, suppressed while a
19
21
  * restore is in flight. Without that suppression the feature eats
20
22
  * itself: writing `scrollTop` on a still-short page clamps to `0`
21
- * and fires a `scroll` event reading `0`, which would be saved
22
- * over the very offset being restored.
23
+ * and fires a `scroll` event reading `0`, which would be saved over
24
+ * the very offset being restored.
23
25
  *
24
- * @param scrollKey Identifies the history entry — react-router's
25
- * `useLocation().key`. `undefined` turns the memory off, which is
26
- * what an app with no router gets.
26
+ * @param entry The history entry and the page it belongs to.
27
+ * `null` turns the memory off, which is what an app that renders
28
+ * no `ScrollMemoryProvider` gets.
27
29
  */
28
- export declare const useScrollMemory: (scrollKey: string | undefined) => (node: unknown) => void;
30
+ export declare const useScrollMemory: (entry: ScrollEntry | null | undefined) => (node: unknown) => void;
29
31
  //# sourceMappingURL=useScrollMemory.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"useScrollMemory.d.ts","sourceRoot":"","sources":["../../src/Main/useScrollMemory.ts"],"names":[],"mappings":"AA6BA;;;;;;;;;;;;;;;;;;;;;;;;;;GA0BG;AACH,eAAO,MAAM,eAAe,GAC1B,WAAW,MAAM,GAAG,SAAS,YAaS,OAAO,SA6F9C,CAAA"}
1
+ {"version":3,"file":"useScrollMemory.d.ts","sourceRoot":"","sources":["../../src/Main/useScrollMemory.ts"],"names":[],"mappings":"AAEA,OAAO,EAIL,KAAK,WAAW,EACjB,MAAM,mBAAmB,CAAA;AAwB1B;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2BG;AACH,eAAO,MAAM,eAAe,GAC1B,OAAO,WAAW,GAAG,IAAI,GAAG,SAAS,YAaC,OAAO,SAkI9C,CAAA"}
@@ -1,16 +1,16 @@
1
1
  import { useCallback, useLayoutEffect, useRef } from "react";
2
- import { recallScrollOffset, rememberScrollOffset, } from "./scrollMemory.js";
2
+ import { enterScrollEntry, rememberScrollOffset, resolveScrollOffset, } from "./scrollMemory.js";
3
3
  /**
4
4
  * How long a restore keeps trying while the content is still
5
5
  * arriving.
6
6
  *
7
7
  * The offset cannot be applied until the scrollport is tall enough
8
8
  * to hold it, and on a client-rendered page it is not: the commit
9
- * that changes the route draws a skeleton, and the rows land a
10
- * fetch later. So the restore re-applies as the content grows, and
11
- * gives up after this. A page that takes longer than three seconds
12
- * to fill has already been read from the top, and moving it then
13
- * is a worse answer than leaving it where the reader put it.
9
+ * that changes the route draws a skeleton, and the rows land a fetch
10
+ * later. So the restore re-applies as the content grows, and gives
11
+ * up after this. A page that takes longer than three seconds to fill
12
+ * has already been read from the top, and moving it then is a worse
13
+ * answer than leaving it where the reader put it.
14
14
  */
15
15
  const RESTORE_WINDOW_MS = 3000;
16
16
  /** A scroll the reader asked for. It ends the restore at once. */
@@ -21,38 +21,39 @@ const READER_INTENT_EVENTS = [
21
21
  "wheel",
22
22
  ];
23
23
  /**
24
- * Remember where this history entry was scrolled to, and put it
25
- * back when the reader returns to it.
24
+ * Remember where this history entry was scrolled to, and put it back
25
+ * when the reader returns to it.
26
26
  *
27
- * `scrollMemory.ts` says why the browser will not. This is the
28
- * part that has to survive the two things a real page does:
27
+ * `scrollMemory.ts` says why the browser will not, and what an entry
28
+ * that has never been seen should do. This is the part that has to
29
+ * survive the two things a real page does:
29
30
  *
30
31
  * 1. **The content arrives late.** An offset applied against a
31
- * 600px skeleton clamps to `0` and looks like it did nothing.
32
- * A `ResizeObserver` on the scrollport and on its content
33
- * column re-applies the offset every time either grows, until
34
- * the offset lands or the window closes.
35
- * 2. **The reader scrolls during all that.** Any wheel, touch,
36
- * key or pointer press ends the restore immediately. The
37
- * alternative is a page that jumps out from under somebody who
38
- * has already started reading.
32
+ * 600px skeleton clamps to `0` and looks like it did nothing. A
33
+ * `ResizeObserver` on the scrollport and on its content column
34
+ * re-applies the offset every time either grows, until the
35
+ * offset lands or the window closes.
36
+ * 2. **The reader scrolls during all that.** Any wheel, touch, key
37
+ * or pointer press ends the restore immediately. The alternative
38
+ * is a page that jumps out from under somebody who has already
39
+ * started reading.
39
40
  *
40
41
  * The save is a passive `scroll` listener, suppressed while a
41
42
  * restore is in flight. Without that suppression the feature eats
42
43
  * itself: writing `scrollTop` on a still-short page clamps to `0`
43
- * and fires a `scroll` event reading `0`, which would be saved
44
- * over the very offset being restored.
44
+ * and fires a `scroll` event reading `0`, which would be saved over
45
+ * the very offset being restored.
45
46
  *
46
- * @param scrollKey Identifies the history entry — react-router's
47
- * `useLocation().key`. `undefined` turns the memory off, which is
48
- * what an app with no router gets.
47
+ * @param entry The history entry and the page it belongs to.
48
+ * `null` turns the memory off, which is what an app that renders
49
+ * no `ScrollMemoryProvider` gets.
49
50
  */
50
- export const useScrollMemory = (scrollKey) => {
51
+ export const useScrollMemory = (entry) => {
51
52
  const elementRef = useRef(null);
52
53
  const isRestoringRef = useRef(false);
53
- // A ref rather than a query for the `<main>` id: the effect
54
- // below runs in the same commit that mounts the node, and only a
55
- // ref can say which node that was.
54
+ // A ref rather than a query for the `<main>` id: the effect below
55
+ // runs in the same commit that mounts the node, and only a ref can
56
+ // say which node that was.
56
57
  //
57
58
  // `unknown` in, narrowed here, so the returned function is both a
58
59
  // `RefCallback<HTMLElement>` and something `mergeRefs` accepts —
@@ -62,34 +63,55 @@ export const useScrollMemory = (scrollKey) => {
62
63
  elementRef.current =
63
64
  node instanceof HTMLElement ? node : null;
64
65
  }, []);
66
+ const key = entry?.key;
67
+ const path = entry?.path;
65
68
  useLayoutEffect(() => {
66
69
  const element = elementRef.current;
67
- if (!element || scrollKey === undefined) {
70
+ if (!element ||
71
+ key === undefined ||
72
+ path === undefined) {
68
73
  return undefined;
69
74
  }
70
- const offset = recallScrollOffset(scrollKey);
71
- // The arrow defers the read of `applyOffset`, so the three
72
- // pieces can be declared in the order they depend on each
73
- // other rather than in the order they are used.
75
+ const currentEntry = { key, path };
76
+ // `null` means leave the scrollport alone: a search param
77
+ // changed and the reader did not go anywhere. It is read BEFORE
78
+ // this entry becomes the current one, because the answer depends
79
+ // on the page the reader is arriving from.
80
+ const offset = resolveScrollOffset(currentEntry);
81
+ enterScrollEntry(currentEntry);
82
+ // Seed the entry now rather than waiting for a `scroll` event.
83
+ // A reader who opens a group and then follows a link never
84
+ // scrolls in between, so without this the entry they came from
85
+ // is one the memory has never seen — and Back would send them to
86
+ // the top of a list they were half-way down.
87
+ rememberScrollOffset(currentEntry, offset ?? element.scrollTop);
88
+ // The arrow defers the read of `applyOffset`, so the pieces can
89
+ // be declared in the order they depend on each other rather than
90
+ // in the order they are used.
74
91
  const observer = new ResizeObserver(() => {
75
92
  applyOffset();
76
93
  });
77
94
  const deadline = globalThis.setTimeout(() => {
78
95
  stopRestoring();
79
96
  }, RESTORE_WINDOW_MS);
80
- const stopRestoring = () => {
81
- if (!isRestoringRef.current) {
82
- return;
83
- }
84
- isRestoringRef.current = false;
97
+ let isRestoring = offset !== null;
98
+ const teardown = () => {
85
99
  observer.disconnect();
86
100
  globalThis.clearTimeout(deadline);
87
101
  for (const eventName of READER_INTENT_EVENTS) {
88
102
  element.removeEventListener(eventName, stopRestoring);
89
103
  }
90
104
  };
105
+ const stopRestoring = () => {
106
+ if (!isRestoring) {
107
+ return;
108
+ }
109
+ isRestoring = false;
110
+ isRestoringRef.current = false;
111
+ teardown();
112
+ };
91
113
  const applyOffset = () => {
92
- if (!isRestoringRef.current) {
114
+ if (!isRestoring || offset === null) {
93
115
  return;
94
116
  }
95
117
  element.scrollTop = offset;
@@ -102,9 +124,9 @@ export const useScrollMemory = (scrollKey) => {
102
124
  if (isRestoringRef.current) {
103
125
  return;
104
126
  }
105
- rememberScrollOffset(scrollKey, element.scrollTop);
127
+ rememberScrollOffset(currentEntry, element.scrollTop);
106
128
  };
107
- isRestoringRef.current = true;
129
+ isRestoringRef.current = isRestoring;
108
130
  for (const eventName of READER_INTENT_EVENTS) {
109
131
  element.addEventListener(eventName, stopRestoring, {
110
132
  passive: true,
@@ -122,10 +144,15 @@ export const useScrollMemory = (scrollKey) => {
122
144
  });
123
145
  applyOffset();
124
146
  return () => {
125
- stopRestoring();
147
+ // Unconditional, unlike `stopRestoring` — a restore that
148
+ // already landed still has an observer and four listeners on
149
+ // an element the next entry is about to use, and a stale
150
+ // observer that survives its effect applies a stale offset.
151
+ isRestoring = false;
152
+ teardown();
126
153
  element.removeEventListener("scroll", onScroll);
127
154
  };
128
- }, [scrollKey]);
155
+ }, [key, path]);
129
156
  return setElement;
130
157
  };
131
158
  //# sourceMappingURL=useScrollMemory.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"useScrollMemory.js","sourceRoot":"","sources":["../../src/Main/useScrollMemory.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"useScrollMemory.js","sourceRoot":"","sources":["../../src/Main/useScrollMemory.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,eAAe,EAAE,MAAM,EAAE,MAAM,OAAO,CAAA;AAE5D,OAAO,EACL,gBAAgB,EAChB,oBAAoB,EACpB,mBAAmB,GAEpB,MAAM,mBAAmB,CAAA;AAE1B;;;;;;;;;;;GAWG;AACH,MAAM,iBAAiB,GAAG,IAAI,CAAA;AAE9B,kEAAkE;AAClE,MAAM,oBAAoB,GAAG;IAC3B,SAAS;IACT,aAAa;IACb,YAAY;IACZ,OAAO;CACC,CAAA;AAEV;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2BG;AACH,MAAM,CAAC,MAAM,eAAe,GAAG,CAC7B,KAAqC,EACrC,EAAE;IACF,MAAM,UAAU,GAAG,MAAM,CAAqB,IAAI,CAAC,CAAA;IACnD,MAAM,cAAc,GAAG,MAAM,CAAC,KAAK,CAAC,CAAA;IAEpC,kEAAkE;IAClE,mEAAmE;IACnE,2BAA2B;IAC3B,EAAE;IACF,kEAAkE;IAClE,iEAAiE;IACjE,iEAAiE;IACjE,4BAA4B;IAC5B,MAAM,UAAU,GAAG,WAAW,CAAC,CAAC,IAAa,EAAE,EAAE;QAC/C,UAAU,CAAC,OAAO;YAChB,IAAI,YAAY,WAAW,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,CAAA;IAC7C,CAAC,EAAE,EAAE,CAAC,CAAA;IAEN,MAAM,GAAG,GAAG,KAAK,EAAE,GAAG,CAAA;IACtB,MAAM,IAAI,GAAG,KAAK,EAAE,IAAI,CAAA;IAExB,eAAe,CAAC,GAAG,EAAE;QACnB,MAAM,OAAO,GAAG,UAAU,CAAC,OAAO,CAAA;QAElC,IACE,CAAC,OAAO;YACR,GAAG,KAAK,SAAS;YACjB,IAAI,KAAK,SAAS,EAClB,CAAC;YACD,OAAO,SAAS,CAAA;QAClB,CAAC;QAED,MAAM,YAAY,GAAG,EAAE,GAAG,EAAE,IAAI,EAAE,CAAA;QAElC,0DAA0D;QAC1D,gEAAgE;QAChE,iEAAiE;QACjE,2CAA2C;QAC3C,MAAM,MAAM,GAAG,mBAAmB,CAAC,YAAY,CAAC,CAAA;QAEhD,gBAAgB,CAAC,YAAY,CAAC,CAAA;QAE9B,+DAA+D;QAC/D,2DAA2D;QAC3D,+DAA+D;QAC/D,iEAAiE;QACjE,6CAA6C;QAC7C,oBAAoB,CAClB,YAAY,EACZ,MAAM,IAAI,OAAO,CAAC,SAAS,CAC5B,CAAA;QAED,gEAAgE;QAChE,iEAAiE;QACjE,8BAA8B;QAC9B,MAAM,QAAQ,GAAG,IAAI,cAAc,CAAC,GAAG,EAAE;YACvC,WAAW,EAAE,CAAA;QACf,CAAC,CAAC,CAAA;QAEF,MAAM,QAAQ,GAAG,UAAU,CAAC,UAAU,CAAC,GAAG,EAAE;YAC1C,aAAa,EAAE,CAAA;QACjB,CAAC,EAAE,iBAAiB,CAAC,CAAA;QAErB,IAAI,WAAW,GAAG,MAAM,KAAK,IAAI,CAAA;QAEjC,MAAM,QAAQ,GAAG,GAAG,EAAE;YACpB,QAAQ,CAAC,UAAU,EAAE,CAAA;YACrB,UAAU,CAAC,YAAY,CAAC,QAAQ,CAAC,CAAA;YAEjC,KAAK,MAAM,SAAS,IAAI,oBAAoB,EAAE,CAAC;gBAC7C,OAAO,CAAC,mBAAmB,CACzB,SAAS,EACT,aAAa,CACd,CAAA;YACH,CAAC;QACH,CAAC,CAAA;QAED,MAAM,aAAa,GAAG,GAAG,EAAE;YACzB,IAAI,CAAC,WAAW,EAAE,CAAC;gBACjB,OAAM;YACR,CAAC;YAED,WAAW,GAAG,KAAK,CAAA;YACnB,cAAc,CAAC,OAAO,GAAG,KAAK,CAAA;YAC9B,QAAQ,EAAE,CAAA;QACZ,CAAC,CAAA;QAED,MAAM,WAAW,GAAG,GAAG,EAAE;YACvB,IAAI,CAAC,WAAW,IAAI,MAAM,KAAK,IAAI,EAAE,CAAC;gBACpC,OAAM;YACR,CAAC;YAED,OAAO,CAAC,SAAS,GAAG,MAAM,CAAA;YAE1B,wDAAwD;YACxD,IAAI,OAAO,CAAC,SAAS,KAAK,MAAM,EAAE,CAAC;gBACjC,aAAa,EAAE,CAAA;YACjB,CAAC;QACH,CAAC,CAAA;QAED,MAAM,QAAQ,GAAG,GAAG,EAAE;YACpB,IAAI,cAAc,CAAC,OAAO,EAAE,CAAC;gBAC3B,OAAM;YACR,CAAC;YAED,oBAAoB,CAAC,YAAY,EAAE,OAAO,CAAC,SAAS,CAAC,CAAA;QACvD,CAAC,CAAA;QAED,cAAc,CAAC,OAAO,GAAG,WAAW,CAAA;QAEpC,KAAK,MAAM,SAAS,IAAI,oBAAoB,EAAE,CAAC;YAC7C,OAAO,CAAC,gBAAgB,CAAC,SAAS,EAAE,aAAa,EAAE;gBACjD,OAAO,EAAE,IAAI;aACd,CAAC,CAAA;QACJ,CAAC;QAED,2DAA2D;QAC3D,6DAA6D;QAC7D,yCAAyC;QACzC,QAAQ,CAAC,OAAO,CAAC,OAAO,CAAC,CAAA;QAEzB,KAAK,MAAM,KAAK,IAAI,KAAK,CAAC,IAAI,CAAC,OAAO,CAAC,QAAQ,CAAC,EAAE,CAAC;YACjD,QAAQ,CAAC,OAAO,CAAC,KAAK,CAAC,CAAA;QACzB,CAAC;QAED,OAAO,CAAC,gBAAgB,CAAC,QAAQ,EAAE,QAAQ,EAAE;YAC3C,OAAO,EAAE,IAAI;SACd,CAAC,CAAA;QAEF,WAAW,EAAE,CAAA;QAEb,OAAO,GAAG,EAAE;YACV,yDAAyD;YACzD,6DAA6D;YAC7D,yDAAyD;YACzD,4DAA4D;YAC5D,WAAW,GAAG,KAAK,CAAA;YACnB,QAAQ,EAAE,CAAA;YACV,OAAO,CAAC,mBAAmB,CAAC,QAAQ,EAAE,QAAQ,CAAC,CAAA;QACjD,CAAC,CAAA;IACH,CAAC,EAAE,CAAC,GAAG,EAAE,IAAI,CAAC,CAAC,CAAA;IAEf,OAAO,UAAU,CAAA;AACnB,CAAC,CAAA"}
@@ -0,0 +1,117 @@
1
+ import type { IntentName } from "@charcuterie/tokens";
2
+ import type { ComponentPropsWithRef, ReactNode } from "react";
3
+ import type { SliderSize } from "../sliderStyles.ts";
4
+ import type { RangeSliderValue } from "./rangeSliderValue.ts";
5
+ /**
6
+ * A position along the range, drawn as a mark on the bar.
7
+ *
8
+ * Prop-driven and nothing more: a chapter list, a scene index, a set
9
+ * of preset prices. The component holds no model of what a tick
10
+ * means, and `label` is optional because a mark that needs no words
11
+ * is the common case.
12
+ */
13
+ export type RangeSliderTick = {
14
+ label?: string;
15
+ value: number;
16
+ };
17
+ export type RangeSliderProps = Omit<ComponentPropsWithRef<"div">, "children" | "defaultValue" | "onChange"> & {
18
+ intent?: IntentName;
19
+ isDisabled?: boolean;
20
+ isLabelVisible?: boolean;
21
+ /**
22
+ * Read-only in the `aria-readonly` sense: focusable, full contrast,
23
+ * announced as unchangeable — the same distinction `Slider` draws.
24
+ * A clip already sent to a renderer is this, not `isDisabled`: the
25
+ * span is still worth reading.
26
+ */
27
+ isReadOnly?: boolean;
28
+ isValueShown?: boolean;
29
+ /** Required. Each thumb's own name is built from it. */
30
+ label: string;
31
+ /** PageUp / PageDown. Defaults to a tenth of the range, as `Slider`'s does. */
32
+ largeStep?: number;
33
+ max?: number;
34
+ min?: number;
35
+ /**
36
+ * Fires on every movement — each arrow key, and each pointer sample
37
+ * while dragging. Use it to paint. See `onChangeEnd` for committing.
38
+ */
39
+ onChange?: (value: RangeSliderValue) => void;
40
+ /**
41
+ * Fires once, when the interaction ends: pointer release, or key up.
42
+ *
43
+ * The same split `Slider` settled, for the same reason. A clip
44
+ * preview that re-seeks a player from `onChange` issues one seek per
45
+ * pointer sample and arrives at the right frame **last**, behind a
46
+ * queue of stale ones.
47
+ */
48
+ onChangeEnd?: (value: RangeSliderValue) => void;
49
+ size?: SliderSize;
50
+ step?: number;
51
+ /**
52
+ * Marks along the bar. Positions in the same units as `value`, so a
53
+ * film's chapters are the offsets the app already has.
54
+ *
55
+ * A `label` is centred on its own mark and clamped inside the bar at
56
+ * both ends. Two marks closer together than a label box will overlap:
57
+ * the component draws what it is given, and a caller with dense marks
58
+ * passes the words only where there is room for them.
59
+ */
60
+ ticks?: readonly RangeSliderTick[];
61
+ /**
62
+ * Seeds the range; it does not control it. A drag paints from the
63
+ * component's own value, so a caller that commits on `onChangeEnd`
64
+ * alone still sees the thumbs follow the pointer.
65
+ */
66
+ value?: RangeSliderValue;
67
+ /**
68
+ * How each end reads aloud and, when `isValueShown`, on screen.
69
+ * This is what keeps timecodes out of the library: the component
70
+ * knows a number, the app knows it is 21:14.
71
+ */
72
+ valueFormat?: (value: number) => string;
73
+ };
74
+ /**
75
+ * A two-thumb range control: a span picked out along a bar, with an
76
+ * independently focusable handle at each end.
77
+ *
78
+ * It exists because QueuePilot lets a user play **only a section** of
79
+ * a video, and a clip's start and end are a shape `Slider` states it
80
+ * is not: *"a two-thumb range is a different widget with its own
81
+ * focus model"*
82
+ * ([decision](../../../../docs/decisions/2026-09-01-a-two-thumb-range-is-its-own-component-and-shares-the-bar.md)).
83
+ *
84
+ * ## Why this is a component and not `Slider isRange`
85
+ *
86
+ * `Combobox`'s `isMultiple` and `DatePicker`'s `isRange` are modes
87
+ * because neither changes the widget's role and both share nearly
88
+ * everything. Both halves of that test fail here.
89
+ *
90
+ * `Slider` puts `role="slider"`, the tab stop and the pointer target
91
+ * **on the track**, because one track reports one value. Two values
92
+ * cannot live on one accessible object, so here the role moves to the
93
+ * thumbs, the track becomes a `role="group"` carrying the label, and
94
+ * the tab stops go from one to two. A mode that rewrote its own role
95
+ * would break `getByRole("slider", { name })` in every consumer that
96
+ * had ever used the single-value one.
97
+ *
98
+ * What the two genuinely share is the arithmetic
99
+ * (`Slider/sliderValue.ts`, called rather than copied) and the bar
100
+ * (`../sliderStyles.ts`) — so a range slider snaps on the same grid
101
+ * and paints as the same control.
102
+ *
103
+ * ## The thumbs clamp, they do not swap
104
+ *
105
+ * A thumb dragged past its partner stops on it and the range collapses
106
+ * to zero width. The thumbs never trade identities mid-drag: the
107
+ * handle under the pointer is the one the user grabbed, and the
108
+ * focused handle is the one an arrow key moves. Each thumb reports the
109
+ * other as its own `aria-valuemin` / `aria-valuemax`, which is how a
110
+ * screen reader is told where this handle stops.
111
+ *
112
+ * A press on the bar moves the **nearer** thumb. When the two sit on
113
+ * the same value, the press's side decides — which is what lets a
114
+ * collapsed range be pulled open again in either direction.
115
+ */
116
+ export declare const RangeSlider: ({ className, intent, isDisabled, isLabelVisible, isReadOnly, isValueShown, label, largeStep, max, min, onChange, onChangeEnd, size, step, ticks, value, valueFormat, ...divProps }: RangeSliderProps) => ReactNode;
117
+ //# sourceMappingURL=RangeSlider.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"RangeSlider.d.ts","sourceRoot":"","sources":["../../src/RangeSlider/RangeSlider.tsx"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,qBAAqB,CAAA;AACrD,OAAO,KAAK,EACV,qBAAqB,EAGrB,SAAS,EACV,MAAM,OAAO,CAAA;AAWd,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,oBAAoB,CAAA;AAWpD,OAAO,KAAK,EAEV,gBAAgB,EACjB,MAAM,uBAAuB,CAAA;AAQ9B;;;;;;;GAOG;AACH,MAAM,MAAM,eAAe,GAAG;IAC5B,KAAK,CAAC,EAAE,MAAM,CAAA;IACd,KAAK,EAAE,MAAM,CAAA;CACd,CAAA;AAED,MAAM,MAAM,gBAAgB,GAAG,IAAI,CACjC,qBAAqB,CAAC,KAAK,CAAC,EAC5B,UAAU,GAAG,cAAc,GAAG,UAAU,CACzC,GAAG;IACF,MAAM,CAAC,EAAE,UAAU,CAAA;IACnB,UAAU,CAAC,EAAE,OAAO,CAAA;IACpB,cAAc,CAAC,EAAE,OAAO,CAAA;IACxB;;;;;OAKG;IACH,UAAU,CAAC,EAAE,OAAO,CAAA;IACpB,YAAY,CAAC,EAAE,OAAO,CAAA;IACtB,wDAAwD;IACxD,KAAK,EAAE,MAAM,CAAA;IACb,+EAA+E;IAC/E,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB,GAAG,CAAC,EAAE,MAAM,CAAA;IACZ,GAAG,CAAC,EAAE,MAAM,CAAA;IACZ;;;OAGG;IACH,QAAQ,CAAC,EAAE,CAAC,KAAK,EAAE,gBAAgB,KAAK,IAAI,CAAA;IAC5C;;;;;;;OAOG;IACH,WAAW,CAAC,EAAE,CAAC,KAAK,EAAE,gBAAgB,KAAK,IAAI,CAAA;IAC/C,IAAI,CAAC,EAAE,UAAU,CAAA;IACjB,IAAI,CAAC,EAAE,MAAM,CAAA;IACb;;;;;;;;OAQG;IACH,KAAK,CAAC,EAAE,SAAS,eAAe,EAAE,CAAA;IAClC;;;;OAIG;IACH,KAAK,CAAC,EAAE,gBAAgB,CAAA;IACxB;;;;OAIG;IACH,WAAW,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,MAAM,CAAA;CACxC,CAAA;AAOD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAyCG;AACH,eAAO,MAAM,WAAW,GAAI,oLAmBzB,gBAAgB,KAAG,SA8ZrB,CAAA"}
@@ -0,0 +1,242 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { useUniqueId } from "@charcuterie/logic";
3
+ import { useRef, useState } from "react";
4
+ import { FOCUS_RING_CLASS, INTENT_SOLID_FILL_CLASS, } from "../intentStyles.js";
5
+ import { fromFraction, toPercent, } from "../Slider/sliderValue.js";
6
+ import { SLIDER_ROW_CLASS, SLIDER_THUMB_CLASS, SLIDER_THUMB_OFFSET, SLIDER_THUMB_SIZE_CLASS, SLIDER_TRACK_CLASS, SLIDER_TRACK_SIZE_CLASS, } from "../sliderStyles.js";
7
+ import { toClassName } from "../toClassName.js";
8
+ import { VisuallyHidden } from "../VisuallyHidden/VisuallyHidden.js";
9
+ import { getNearerThumb, getThumbBounds, moveThumb, snapRange, } from "./rangeSliderValue.js";
10
+ /** Half the tick-label box, which is what centres it on its mark. */
11
+ const TICK_LABEL_INLINE_SIZE = "4.5rem";
12
+ const TICK_LABEL_HALF = "2.25rem";
13
+ /**
14
+ * A two-thumb range control: a span picked out along a bar, with an
15
+ * independently focusable handle at each end.
16
+ *
17
+ * It exists because QueuePilot lets a user play **only a section** of
18
+ * a video, and a clip's start and end are a shape `Slider` states it
19
+ * is not: *"a two-thumb range is a different widget with its own
20
+ * focus model"*
21
+ * ([decision](../../../../docs/decisions/2026-09-01-a-two-thumb-range-is-its-own-component-and-shares-the-bar.md)).
22
+ *
23
+ * ## Why this is a component and not `Slider isRange`
24
+ *
25
+ * `Combobox`'s `isMultiple` and `DatePicker`'s `isRange` are modes
26
+ * because neither changes the widget's role and both share nearly
27
+ * everything. Both halves of that test fail here.
28
+ *
29
+ * `Slider` puts `role="slider"`, the tab stop and the pointer target
30
+ * **on the track**, because one track reports one value. Two values
31
+ * cannot live on one accessible object, so here the role moves to the
32
+ * thumbs, the track becomes a `role="group"` carrying the label, and
33
+ * the tab stops go from one to two. A mode that rewrote its own role
34
+ * would break `getByRole("slider", { name })` in every consumer that
35
+ * had ever used the single-value one.
36
+ *
37
+ * What the two genuinely share is the arithmetic
38
+ * (`Slider/sliderValue.ts`, called rather than copied) and the bar
39
+ * (`../sliderStyles.ts`) — so a range slider snaps on the same grid
40
+ * and paints as the same control.
41
+ *
42
+ * ## The thumbs clamp, they do not swap
43
+ *
44
+ * A thumb dragged past its partner stops on it and the range collapses
45
+ * to zero width. The thumbs never trade identities mid-drag: the
46
+ * handle under the pointer is the one the user grabbed, and the
47
+ * focused handle is the one an arrow key moves. Each thumb reports the
48
+ * other as its own `aria-valuemin` / `aria-valuemax`, which is how a
49
+ * screen reader is told where this handle stops.
50
+ *
51
+ * A press on the bar moves the **nearer** thumb. When the two sit on
52
+ * the same value, the press's side decides — which is what lets a
53
+ * collapsed range be pulled open again in either direction.
54
+ */
55
+ export const RangeSlider = ({ className, intent = "accent", isDisabled = false, isLabelVisible = false, isReadOnly = false, isValueShown = false, label, largeStep, max = 100, min = 0, onChange, onChangeEnd, size = "md", step = 1, ticks, value = { end: max, start: min }, valueFormat, ...divProps }) => {
56
+ const labelId = useUniqueId();
57
+ const trackRef = useRef(null);
58
+ const startThumbRef = useRef(null);
59
+ const endThumbRef = useRef(null);
60
+ // Null means "not dragging". The thumb rides along with the value
61
+ // because a drag has to keep moving the handle it picked up, even
62
+ // once the pointer has travelled past the other one and the "nearer"
63
+ // answer has changed.
64
+ const [drag, setDrag] = useState(null);
65
+ const isInert = isDisabled || isReadOnly;
66
+ const bounds = { max, min, step };
67
+ const committed = snapRange(value, bounds);
68
+ const shown = drag?.range ?? committed;
69
+ const bigStep = largeStep == null
70
+ ? (Math.max(min, max) - Math.min(min, max)) / 10
71
+ : largeStep;
72
+ const startPercent = toPercent(shown.start, min, max);
73
+ const endPercent = toPercent(shown.end, min, max);
74
+ const emit = (next, thumb, isEnd) => {
75
+ if (next.start !== shown.start ||
76
+ next.end !== shown.end) {
77
+ onChange?.(next);
78
+ }
79
+ if (isEnd) {
80
+ setDrag(null);
81
+ onChangeEnd?.(next);
82
+ return;
83
+ }
84
+ setDrag({ range: next, thumb });
85
+ };
86
+ /** The value the pointer at `clientX` is pointing at. */
87
+ const valueAt = (clientX) => {
88
+ const track = trackRef.current;
89
+ if (!track)
90
+ return shown.start;
91
+ const box = track.getBoundingClientRect();
92
+ if (box.width <= 0)
93
+ return shown.start;
94
+ // `left`/`width` are physical, from the layout box, and stay
95
+ // physical on purpose — `isRtl` is what turns them into a value.
96
+ // The logical-properties rule is about `className`, not geometry.
97
+ const fraction = (clientX - box.left) / box.width;
98
+ const isRtl = getComputedStyle(track).direction === "rtl";
99
+ return fromFraction(fraction, min, max, step, isRtl);
100
+ };
101
+ const onPointerDown = (event) => {
102
+ if (isInert || event.button !== 0)
103
+ return;
104
+ // The press is ours, and the default is what would undo it: a
105
+ // mousedown on a non-focusable element moves focus to the body,
106
+ // so the handle this handler just focused would lose it again a
107
+ // tick later. `Slider` never needed this because its pointer
108
+ // target IS its focusable element; here the bar is the target and
109
+ // the thumb is the tab stop.
110
+ event.preventDefault();
111
+ const at = valueAt(event.clientX);
112
+ const thumb = getNearerThumb({ at, range: shown });
113
+ // Capture on the GROUP rather than on the thumb, so a drag that
114
+ // leaves the bar vertically keeps reporting — and so a fast drag
115
+ // that outruns the thumb it is moving does not hand the pointer to
116
+ // the element underneath.
117
+ event.currentTarget.setPointerCapture(event.pointerId);
118
+ // Focus follows the grab. A pointer user who then reaches for the
119
+ // arrow keys is moving the handle they were just dragging, which
120
+ // is the only answer that does not need looking at.
121
+ //
122
+ // The handle wears its focus ring for the length of the drag,
123
+ // which is a script `focus()` matching `:focus-visible`. On a
124
+ // one-thumb control that would be the ring-after-a-click the house
125
+ // style rejects; here it is the answer to "which of the two am I
126
+ // holding", and it is the same mark the keyboard path leaves.
127
+ const thumbElement = thumb === "start"
128
+ ? startThumbRef.current
129
+ : endThumbRef.current;
130
+ thumbElement?.focus();
131
+ emit(moveThumb({ bounds, next: at, range: shown, thumb }), thumb, false);
132
+ };
133
+ const onPointerMove = (event) => {
134
+ if (isInert || drag == null)
135
+ return;
136
+ emit(moveThumb({
137
+ bounds,
138
+ next: valueAt(event.clientX),
139
+ range: shown,
140
+ thumb: drag.thumb,
141
+ }), drag.thumb, false);
142
+ };
143
+ const onPointerUp = (event) => {
144
+ if (isInert || drag == null)
145
+ return;
146
+ event.currentTarget.releasePointerCapture(event.pointerId);
147
+ emit(moveThumb({
148
+ bounds,
149
+ next: valueAt(event.clientX),
150
+ range: shown,
151
+ thumb: drag.thumb,
152
+ }), drag.thumb, true);
153
+ };
154
+ /**
155
+ * `Slider`'s key handling, per thumb. Home and End are absolute and
156
+ * are clamped at the other thumb like any other movement, so End on
157
+ * the start handle means "as far right as this handle goes".
158
+ */
159
+ const getKeyedValue = (event, current) => {
160
+ switch (event.key) {
161
+ case "ArrowDown":
162
+ case "ArrowLeft":
163
+ return current - step;
164
+ case "ArrowRight":
165
+ case "ArrowUp":
166
+ return current + step;
167
+ case "End":
168
+ return Math.max(min, max);
169
+ case "Home":
170
+ return Math.min(min, max);
171
+ case "PageDown":
172
+ return current - bigStep;
173
+ case "PageUp":
174
+ return current + bigStep;
175
+ default:
176
+ return null;
177
+ }
178
+ };
179
+ const onThumbKeyDown = (thumb) => (event) => {
180
+ if (isInert)
181
+ return;
182
+ const next = getKeyedValue(event, shown[thumb]);
183
+ if (next == null)
184
+ return;
185
+ event.preventDefault();
186
+ // Keys commit immediately, as `Slider`'s do: a key press is a
187
+ // discrete interaction with no release to wait for.
188
+ emit(moveThumb({ bounds, next, range: shown, thumb }), thumb, true);
189
+ };
190
+ const renderThumb = (thumb) => {
191
+ const thumbBounds = getThumbBounds({
192
+ bounds,
193
+ range: shown,
194
+ thumb,
195
+ });
196
+ const percent = thumb === "start" ? startPercent : endPercent;
197
+ return (_jsx("span", { "aria-disabled": isDisabled || undefined, "aria-label": `${label} ${thumb}`, "aria-orientation": "horizontal", "aria-readonly": isReadOnly || undefined, "aria-valuemax": thumbBounds.max, "aria-valuemin": thumbBounds.min, "aria-valuenow": shown[thumb], "aria-valuetext": valueFormat?.(shown[thumb]), className: toClassName(SLIDER_THUMB_CLASS, SLIDER_THUMB_SIZE_CLASS[size], INTENT_SOLID_FILL_CLASS[intent], FOCUS_RING_CLASS, isReadOnly ? "cursor-default" : ""), onKeyDown: onThumbKeyDown(thumb), ref: thumb === "start" ? startThumbRef : endThumbRef, role: "slider",
198
+ // Pulled back by half its own width so it sits ON the value
199
+ // rather than starting at it. `margin-inline-start`, not
200
+ // `translate: -50%`: `translate` is physical, so in RTL it
201
+ // would shift the thumb the wrong way and 0% would hang off
202
+ // the start edge.
203
+ style: {
204
+ insetInlineStart: `${percent}%`,
205
+ marginInlineStart: SLIDER_THUMB_OFFSET[size],
206
+ }, tabIndex: isDisabled ? -1 : 0 }, thumb));
207
+ };
208
+ const shownText = valueFormat == null
209
+ ? `${shown.start} to ${shown.end}`
210
+ : `${valueFormat(shown.start)} to ${valueFormat(shown.end)}`;
211
+ return (_jsxs("div", { ...divProps, className: toClassName("flex flex-col gap-1",
212
+ // A definite floor, for `Slider`'s reason: the root has no
213
+ // intrinsic width of its own, so in a shrink-to-fit parent it
214
+ // would collapse to the width of a thumb with every gate
215
+ // still green.
216
+ "min-w-40", className), children: [isLabelVisible || isValueShown ? (_jsxs("div", { className: "flex items-baseline justify-between gap-2 text-sm", children: [isLabelVisible ? (_jsx("span", { className: "text-content-secondary", id: labelId, children: label })) : (_jsx(VisuallyHidden, { id: labelId, children: label })), isValueShown ? (_jsx("span", { className: "text-content-muted tabular-nums", children: shownText })) : null] })) : (_jsx(VisuallyHidden, { id: labelId, children: label })), _jsxs("div", { "aria-labelledby": labelId, className: toClassName(SLIDER_ROW_CLASS,
217
+ // NOT `ARIA_DISABLED_CLASS`, for the reason `Slider` gives:
218
+ // that constant paints a box-shaped control, and this
219
+ // control's body is a 2px bar inside a 40px row.
220
+ //
221
+ // `pointer-events-none` is load-bearing rather than
222
+ // cosmetic — without a real `:disabled` the hover rules
223
+ // still match.
224
+ isDisabled
225
+ ? "pointer-events-none opacity-55"
226
+ : "", isReadOnly ? "cursor-default" : ""), onPointerCancel: onPointerUp, onPointerDown: onPointerDown, onPointerMove: onPointerMove, onPointerUp: onPointerUp, ref: trackRef, role: "group", children: [_jsx("span", { className: toClassName(SLIDER_TRACK_CLASS, SLIDER_TRACK_SIZE_CLASS[size]), children: _jsx("span", { className: toClassName("block h-full rounded-full", INTENT_SOLID_FILL_CLASS[intent]), style: {
227
+ inlineSize: `${endPercent - startPercent}%`,
228
+ marginInlineStart: `${startPercent}%`,
229
+ } }) }), ticks?.map((tick) => (_jsx("span", { "aria-hidden": "true", className: "absolute h-2 w-px bg-border-strong", style: {
230
+ insetInlineStart: `${toPercent(tick.value, min, max)}%`,
231
+ } }, tick.value))), renderThumb("start"), renderThumb("end")] }), ticks?.some((tick) => tick.label != null) ? (_jsx("div", { "aria-hidden": "true", className: "relative h-4 w-full text-content-muted text-xs", children: ticks.map((tick) => tick.label == null ? null : (_jsx("span", { className: "absolute text-center",
232
+ // Centred on its mark, and `clamp`ed so the first and
233
+ // last labels stay inside the bar instead of hanging
234
+ // off its ends. A fixed box is what makes the centring
235
+ // possible at all: the label's own width is not known
236
+ // here, and `translate: -50%` is physical.
237
+ style: {
238
+ inlineSize: TICK_LABEL_INLINE_SIZE,
239
+ insetInlineStart: `clamp(0rem, calc(${toPercent(tick.value, min, max)}% - ${TICK_LABEL_HALF}), calc(100% - ${TICK_LABEL_INLINE_SIZE}))`,
240
+ }, children: tick.label }, tick.value))) })) : null] }));
241
+ };
242
+ //# sourceMappingURL=RangeSlider.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"RangeSlider.js","sourceRoot":"","sources":["../../src/RangeSlider/RangeSlider.tsx"],"names":[],"mappings":"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"}