@once-ui-system/core 2.0.0-alpha.0 → 2.0.0-alpha.2

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 (162) hide show
  1. package/AGENTS.md +1 -1
  2. package/LICENSE.md +21 -0
  3. package/ai/catalog.json +11 -4
  4. package/ai/components/Effect.json +1 -1
  5. package/ai/components/Feedback.json +1 -0
  6. package/ai/components/Form.json +15 -0
  7. package/ai/components/Input.json +3 -2
  8. package/ai/components/{Particle.json → ParticleFx.json} +1 -1
  9. package/ai/components/ScrollContainer.json +9 -1
  10. package/ai/components/Textarea.json +3 -2
  11. package/ai/components/ThemeSwitcher.json +2 -1
  12. package/ai/eval-tasks.md +2 -1
  13. package/ai/examples/auth.tsx +1 -2
  14. package/ai/examples/blocks/Dashboard1.tsx +8 -8
  15. package/ai/examples/blocks/Feed3.tsx +4 -4
  16. package/ai/examples/blocks/Footer4.tsx +2 -2
  17. package/ai/examples/blocks/Header2.tsx +1 -1
  18. package/ai/examples/blocks/Header4.tsx +1 -2
  19. package/ai/examples/blocks/Productivity1.tsx +1 -1
  20. package/ai/examples/blocks/Roadmap1.tsx +3 -3
  21. package/ai/examples/blocks/Sidebar1.tsx +1 -1
  22. package/ai/examples/blocks/Sidebar2.tsx +1 -1
  23. package/ai/examples/blocks/Table1.tsx +3 -3
  24. package/ai/examples/blocks/manifest.json +2 -2
  25. package/ai/examples/dashboard.tsx +5 -5
  26. package/ai/examples/marketing-hero.tsx +2 -2
  27. package/ai/examples/pricing.tsx +3 -3
  28. package/ai/examples/settings.tsx +4 -4
  29. package/ai/gotchas.json +26 -2
  30. package/ai/manifest.json +2 -2
  31. package/ai/recipes.md +1 -1
  32. package/ai/rules.compact.md +8 -2
  33. package/ai/rules.md +18 -6
  34. package/ai/spec.json +35 -10
  35. package/ai/tasks/settings.json +1 -1
  36. package/dist/AGENTS.md +1 -1
  37. package/dist/ai/catalog.json +11 -4
  38. package/dist/ai/components/Effect.json +1 -1
  39. package/dist/ai/components/Feedback.json +1 -0
  40. package/dist/ai/components/Form.json +15 -0
  41. package/dist/ai/components/Input.json +3 -2
  42. package/dist/ai/components/{Particle.json → ParticleFx.json} +1 -1
  43. package/dist/ai/components/ScrollContainer.json +9 -1
  44. package/dist/ai/components/Textarea.json +3 -2
  45. package/dist/ai/components/ThemeSwitcher.json +2 -1
  46. package/dist/ai/eval-tasks.md +2 -1
  47. package/dist/ai/examples/blocks/manifest.json +2 -2
  48. package/dist/ai/gotchas.json +26 -2
  49. package/dist/ai/manifest.json +2 -2
  50. package/dist/ai/recipes.md +1 -1
  51. package/dist/ai/rules.compact.md +8 -2
  52. package/dist/ai/rules.md +18 -6
  53. package/dist/ai/spec.json +35 -10
  54. package/dist/ai/tasks/settings.json +1 -1
  55. package/dist/components/Animation.d.ts +1 -2
  56. package/dist/components/Animation.d.ts.map +1 -1
  57. package/dist/components/Animation.js +1 -1
  58. package/dist/components/Animation.js.map +1 -1
  59. package/dist/components/ArrowNavigationContext.d.ts.map +1 -1
  60. package/dist/components/ArrowNavigationContext.js +12 -3
  61. package/dist/components/ArrowNavigationContext.js.map +1 -1
  62. package/dist/components/Avatar.d.ts.map +1 -1
  63. package/dist/components/Avatar.js +1 -1
  64. package/dist/components/Avatar.js.map +1 -1
  65. package/dist/components/Carousel.js +1 -1
  66. package/dist/components/Carousel.js.map +1 -1
  67. package/dist/components/ContextMenu.d.ts +1 -1
  68. package/dist/components/ContextMenu.d.ts.map +1 -1
  69. package/dist/components/CountFx.d.ts.map +1 -1
  70. package/dist/components/CountFx.js +19 -7
  71. package/dist/components/CountFx.js.map +1 -1
  72. package/dist/components/CursorCard.d.ts +1 -1
  73. package/dist/components/CursorCard.d.ts.map +1 -1
  74. package/dist/components/DatePicker.d.ts.map +1 -1
  75. package/dist/components/DatePicker.js +9 -2
  76. package/dist/components/DatePicker.js.map +1 -1
  77. package/dist/components/DropdownWrapper.d.ts +1 -1
  78. package/dist/components/DropdownWrapper.d.ts.map +1 -1
  79. package/dist/components/DropdownWrapper.js +178 -35
  80. package/dist/components/DropdownWrapper.js.map +1 -1
  81. package/dist/components/DropdownWrapper.module.scss +3 -1
  82. package/dist/components/Effect.d.ts +2 -2
  83. package/dist/components/Effect.d.ts.map +1 -1
  84. package/dist/components/Effect.js +2 -2
  85. package/dist/components/Effect.js.map +1 -1
  86. package/dist/components/EmojiPicker.js +1 -1
  87. package/dist/components/EmojiPicker.js.map +1 -1
  88. package/dist/components/Feedback.d.ts +4 -0
  89. package/dist/components/Feedback.d.ts.map +1 -1
  90. package/dist/components/Feedback.js +2 -2
  91. package/dist/components/Feedback.js.map +1 -1
  92. package/dist/components/FocusTrap.d.ts +3 -3
  93. package/dist/components/FocusTrap.d.ts.map +1 -1
  94. package/dist/components/FocusTrap.js +10 -0
  95. package/dist/components/FocusTrap.js.map +1 -1
  96. package/dist/components/Form.d.ts +48 -0
  97. package/dist/components/Form.d.ts.map +1 -0
  98. package/dist/components/Form.js +191 -0
  99. package/dist/components/Form.js.map +1 -0
  100. package/dist/components/Form.module.scss +160 -0
  101. package/dist/components/FormContext.d.ts +20 -0
  102. package/dist/components/FormContext.d.ts.map +1 -0
  103. package/dist/components/FormContext.js +12 -0
  104. package/dist/components/FormContext.js.map +1 -0
  105. package/dist/components/Input.d.ts +3 -0
  106. package/dist/components/Input.d.ts.map +1 -1
  107. package/dist/components/Input.js +13 -2
  108. package/dist/components/Input.js.map +1 -1
  109. package/dist/components/Input.module.scss +27 -6
  110. package/dist/components/OgCard.d.ts.map +1 -1
  111. package/dist/components/OgCard.js +7 -4
  112. package/dist/components/OgCard.js.map +1 -1
  113. package/dist/components/{Particle.d.ts → ParticleFx.d.ts} +9 -4
  114. package/dist/components/ParticleFx.d.ts.map +1 -0
  115. package/dist/components/{Particle.js → ParticleFx.js} +9 -4
  116. package/dist/components/ParticleFx.js.map +1 -0
  117. package/dist/components/ScrollContainer.d.ts +69 -2
  118. package/dist/components/ScrollContainer.d.ts.map +1 -1
  119. package/dist/components/ScrollContainer.js +377 -46
  120. package/dist/components/ScrollContainer.js.map +1 -1
  121. package/dist/components/ScrollContainer.module.scss +131 -0
  122. package/dist/components/Select.d.ts +1 -1
  123. package/dist/components/Select.d.ts.map +1 -1
  124. package/dist/components/Select.js +1 -1
  125. package/dist/components/Select.js.map +1 -1
  126. package/dist/components/Setting.d.ts.map +1 -1
  127. package/dist/components/Setting.js +6 -1
  128. package/dist/components/Setting.js.map +1 -1
  129. package/dist/components/Table.js +2 -2
  130. package/dist/components/Table.js.map +1 -1
  131. package/dist/components/Textarea.d.ts +3 -0
  132. package/dist/components/Textarea.d.ts.map +1 -1
  133. package/dist/components/Textarea.js +22 -6
  134. package/dist/components/Textarea.js.map +1 -1
  135. package/dist/components/ThemeSwitcher.d.ts +16 -0
  136. package/dist/components/ThemeSwitcher.d.ts.map +1 -1
  137. package/dist/components/ThemeSwitcher.js +48 -9
  138. package/dist/components/ThemeSwitcher.js.map +1 -1
  139. package/dist/components/ThemeSwitcher.module.scss +112 -0
  140. package/dist/components/User.js +1 -1
  141. package/dist/components/User.js.map +1 -1
  142. package/dist/components/UserMenu.d.ts +1 -1
  143. package/dist/components/UserMenu.d.ts.map +1 -1
  144. package/dist/components/index.d.ts +2 -1
  145. package/dist/components/index.d.ts.map +1 -1
  146. package/dist/components/index.js +2 -1
  147. package/dist/components/index.js.map +1 -1
  148. package/dist/data/emoji-data.json +10 -0
  149. package/dist/hooks/useArrowNavigation.d.ts.map +1 -1
  150. package/dist/hooks/useArrowNavigation.js +52 -7
  151. package/dist/hooks/useArrowNavigation.js.map +1 -1
  152. package/dist/modules/navigation/MegaMenu.d.ts.map +1 -1
  153. package/dist/modules/navigation/MegaMenu.js +76 -10
  154. package/dist/modules/navigation/MegaMenu.js.map +1 -1
  155. package/dist/package.json +1 -1
  156. package/dist/scripts/validate-ai-code.js +239 -21
  157. package/dist/types.d.ts +14 -0
  158. package/dist/types.d.ts.map +1 -1
  159. package/package.json +1 -1
  160. package/scripts/validate-ai-code.js +239 -21
  161. package/dist/components/Particle.d.ts.map +0 -1
  162. package/dist/components/Particle.js.map +0 -1
@@ -1,66 +1,397 @@
1
1
  "use client";
2
2
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
3
- import { useRef, useState, useEffect, useCallback, forwardRef } from "react";
4
- import { Column, Row, IconButton } from ".";
3
+ import { forwardRef, useCallback, useEffect, useMemo, useRef, useState } from "react";
4
+ import { Column, Flex, IconButton, Row } from ".";
5
+ import styles from "./ScrollContainer.module.scss";
5
6
  const getHorizontalAlignment = (placement) => {
6
- if (placement === "top-start" || placement === "bottom-start")
7
- return "start";
8
- if (placement === "top-end" || placement === "bottom-end")
7
+ if (placement.endsWith("-end"))
9
8
  return "end";
10
- if (placement === "top-center" || placement === "bottom-center")
9
+ if (placement.endsWith("-center"))
11
10
  return "center";
12
- if (placement === "top-between" || placement === "bottom-between")
11
+ if (placement.endsWith("-between"))
13
12
  return "between";
14
13
  return "start";
15
14
  };
16
- const ScrollContainer = forwardRef(({ items, controlPlacement = "top-start", ...flex }, ref) => {
17
- const scrollRef = useRef(null);
18
- const [canScrollLeft, setCanScrollLeft] = useState(false);
19
- const [canScrollRight, setCanScrollRight] = useState(true);
20
- const checkScrollPosition = useCallback(() => {
21
- const element = scrollRef.current;
22
- if (!element)
15
+ /** Past this many pixels a pointer is dragging the track, not clicking a tile. */
16
+ const DRAG_THRESHOLD = 6;
17
+ /** Past this fraction of a tile, let go and the track advances rather than settling back. */
18
+ const COMMIT_RATIO = 0.2;
19
+ /** Past this speed the same is true however short the drag was. */
20
+ const FLICK_VELOCITY = 0.5;
21
+ /** How far a track can be pulled past its own end before it stops following. */
22
+ const RUBBER_BAND = 0.35;
23
+ /** How much smaller each whole step from the front is, when `proximity` is on. */
24
+ const PROXIMITY_FALLOFF = 0.08;
25
+ /** Tiles stop shrinking here, so a long run does not trail off into nothing. */
26
+ const PROXIMITY_FLOOR = 0.72;
27
+ /**
28
+ * A horizontal run of items with controls, drag, optional wrap-around,
29
+ * optional proximity scaling and optional markers.
30
+ *
31
+ * This moves a track with a transform rather than scrolling a box, which is
32
+ * the decision the rest of the component follows from. The previous version
33
+ * was an `overflow-x: auto` row, and a scroll box cannot do any of the three
34
+ * things asked of a carousel: its contents are clipped at its own edge by
35
+ * definition, so no tile can peek past it; its scroll range has two hard ends,
36
+ * so there is nowhere for a wrap-around to go; and the browser owns the
37
+ * easing, so a drag can only set `scrollLeft` and hope. A transform has none
38
+ * of those limits — the track is laid out once and moved, tiles paint wherever
39
+ * they land, the offset is free to run past either end, and the motion is a
40
+ * CSS transition this component controls.
41
+ *
42
+ * What it gives up is the browser's own scrolling: a trackpad's horizontal
43
+ * gesture no longer moves the track, and that is why `draggable` is on by
44
+ * default and the controls are never hidden. Both are real affordances rather
45
+ * than the invisible one a scroll box relies on.
46
+ *
47
+ * Tiles are unstyled. The wrapper each item sits in used to arrive with
48
+ * `aspectRatio="3/4"`, `border`, `radius="xl"` and a width range already set,
49
+ * so anything that was not a tall bordered portrait card had to override four
50
+ * properties before it could begin — and any prop passed to override them
51
+ * landed on every tile, since that is where the rest props go. The wrapper now
52
+ * contributes only what a track item cannot do without, which is refusing to
53
+ * shrink. Sizing stays with the caller, through those same rest props.
54
+ */
55
+ const ScrollContainer = forwardRef(({ items, controlPlacement = "top-start", infinite = false, markers = false, draggable = true, step = 1, clip = false, proximity = false, active, onActiveChange, ...tile }, ref) => {
56
+ const count = items.length;
57
+ const viewportRef = useRef(null);
58
+ const trackRef = useRef(null);
59
+ const [index, setIndex] = useState(0);
60
+ const [tileStep, setTileStep] = useState(0);
61
+ const [perView, setPerView] = useState(1);
62
+ const [dragPx, setDragPx] = useState(0);
63
+ const [animated, setAnimated] = useState(true);
64
+ const [dragging, setDragging] = useState(false);
65
+ /**
66
+ * The last index that still fills the viewport.
67
+ *
68
+ * Without wrap-around there is no reason to advance into empty space once
69
+ * the final tile is already in view, so the end of the run is the last
70
+ * whole screenful rather than the last item.
71
+ */
72
+ const maxIndex = infinite ? Number.POSITIVE_INFINITY : Math.max(0, count - perView);
73
+ /**
74
+ * Wrap-around is three copies of the run with the real one in the middle.
75
+ *
76
+ * Moving off either side of the middle copy lands on a real tile of the
77
+ * neighbouring copy, so the motion is continuous and in the direction of
78
+ * travel. `onTransitionEnd` then puts the index back in range with the
79
+ * transition switched off, which shifts the track by exactly one copy —
80
+ * the same tiles under the same pixels, so nothing moves on screen.
81
+ */
82
+ const rendered = useMemo(() => (infinite && count > 0 ? [...items, ...items, ...items] : items), [infinite, items, count]);
83
+ const origin = infinite ? count : 0;
84
+ const measure = useCallback(() => {
85
+ const viewport = viewportRef.current;
86
+ const track = trackRef.current;
87
+ const first = track?.firstElementChild;
88
+ if (!viewport || !track || !first)
23
89
  return;
24
- const { scrollLeft, scrollWidth, clientWidth } = element;
25
- setCanScrollLeft(scrollLeft > 0);
26
- setCanScrollRight(scrollLeft < scrollWidth - clientWidth - 1);
90
+ const gap = Number.parseFloat(getComputedStyle(track).columnGap) || 0;
91
+ const width = first.offsetWidth + gap;
92
+ setTileStep(width);
93
+ setPerView(width > 0 ? Math.max(1, Math.round(viewport.clientWidth / width)) : 1);
27
94
  }, []);
28
95
  useEffect(() => {
29
- const element = scrollRef.current;
30
- if (!element)
96
+ measure();
97
+ const viewport = viewportRef.current;
98
+ if (!viewport || typeof ResizeObserver === "undefined") {
99
+ window.addEventListener("resize", measure);
100
+ return () => window.removeEventListener("resize", measure);
101
+ }
102
+ // Watches the track's own box too: a tile sized in percentages changes
103
+ // with the viewport, but one sized by its content changes when the
104
+ // content does, and only the track hears about that.
105
+ const observer = new ResizeObserver(measure);
106
+ observer.observe(viewport);
107
+ if (trackRef.current)
108
+ observer.observe(trackRef.current);
109
+ return () => observer.disconnect();
110
+ }, [measure]);
111
+ // A shorter list can leave the index past the end of it.
112
+ useEffect(() => {
113
+ setIndex((current) => Math.min(current, infinite ? current : Math.max(0, count - 1)));
114
+ }, [count, infinite]);
115
+ const go = useCallback((delta) => {
116
+ setAnimated(true);
117
+ setIndex((current) => {
118
+ const next = current + delta;
119
+ return infinite ? next : Math.max(0, Math.min(maxIndex, next));
120
+ });
121
+ }, [infinite, maxIndex]);
122
+ const goTo = useCallback((target) => {
123
+ setAnimated(true);
124
+ setIndex((current) => {
125
+ if (!infinite)
126
+ return Math.max(0, Math.min(maxIndex, target));
127
+ // Take whichever way round is shorter, so a marker near the end of
128
+ // the run does not walk the whole track to reach a neighbour.
129
+ const here = ((current % count) + count) % count;
130
+ const forward = (((target - here) % count) + count) % count;
131
+ return current + (forward <= count - forward ? forward : forward - count);
132
+ });
133
+ }, [count, infinite, maxIndex]);
134
+ /**
135
+ * Which item is in front, counted in `items` rather than in the track.
136
+ *
137
+ * With wrap-around the internal index is free to run past either end —
138
+ * that is what makes the motion continuous — so it is not a number any
139
+ * caller could use. This folds it back into the range of the real run,
140
+ * and it is the only index this component reports or accepts.
141
+ */
142
+ const activeIndex = count > 0 ? ((index % count) + count) % count : 0;
143
+ /**
144
+ * Report the front item, but never on mount.
145
+ *
146
+ * The callback is read through a ref so that a caller passing a fresh
147
+ * arrow function on every render — which is most of them — does not make
148
+ * this fire again for an index that has not moved.
149
+ */
150
+ const onActiveChangeRef = useRef(onActiveChange);
151
+ onActiveChangeRef.current = onActiveChange;
152
+ const reportedRef = useRef(activeIndex);
153
+ useEffect(() => {
154
+ if (reportedRef.current === activeIndex)
155
+ return;
156
+ reportedRef.current = activeIndex;
157
+ onActiveChangeRef.current?.(activeIndex);
158
+ }, [activeIndex]);
159
+ /**
160
+ * Move when `active` changes.
161
+ *
162
+ * Deliberately keyed on `active` alone. Were it to depend on where the run
163
+ * actually is, every drag would be undone a frame after it finished by an
164
+ * effect insisting on the last value the caller passed — the run would
165
+ * fight the pointer. `active` says go here; it does not say stay here.
166
+ */
167
+ // biome-ignore lint/correctness/useExhaustiveDependencies: see above — reacting to the caller's command, not to our own position
168
+ useEffect(() => {
169
+ if (active === undefined || count === 0)
170
+ return;
171
+ goTo(active);
172
+ }, [active, count]);
173
+ /**
174
+ * Put the index back inside the real copy once the motion has finished.
175
+ *
176
+ * Switching the transition off for one frame is what makes the jump
177
+ * invisible: the index changes by a whole copy and the transform changes
178
+ * by exactly one copy's width, so the pixels are identical.
179
+ */
180
+ const handleTransitionEnd = useCallback((event) => {
181
+ // `transitionend` bubbles, so a tile animating its own background would
182
+ // otherwise be read as the track arriving.
183
+ if (event.target !== trackRef.current || event.propertyName !== "transform")
184
+ return;
185
+ if (!infinite || count === 0)
186
+ return;
187
+ if (index >= 0 && index < count)
31
188
  return;
32
- checkScrollPosition();
33
- element.addEventListener("scroll", checkScrollPosition);
34
- window.addEventListener("resize", checkScrollPosition);
35
- return () => {
36
- element.removeEventListener("scroll", checkScrollPosition);
37
- window.removeEventListener("resize", checkScrollPosition);
189
+ setAnimated(false);
190
+ setIndex(((index % count) + count) % count);
191
+ }, [count, index, infinite]);
192
+ /**
193
+ * Put the transition back one frame after the wrap-around jump — but not
194
+ * while a drag is in progress.
195
+ *
196
+ * Without the `dragging` guard this fires for any `animated === false`,
197
+ * and a drag is the other thing that sets it false. One frame in, the
198
+ * transition came back on, and every `dragPx` update after that was eased
199
+ * over `--transition-duration-macro-long` instead of applied: the track
200
+ * crawled toward the pointer at 0.6s a step and never caught up. Measured
201
+ * before the guard — a 164px drag moved the track 46px, in increments of
202
+ * 40, 1, 2, 3. It only looked right on release because the commit works
203
+ * from the raw pointer delta, not from where the track had got to.
204
+ */
205
+ useEffect(() => {
206
+ if (animated || dragging)
207
+ return;
208
+ const frame = requestAnimationFrame(() => setAnimated(true));
209
+ return () => cancelAnimationFrame(frame);
210
+ }, [animated, dragging]);
211
+ const drag = useRef({
212
+ active: false,
213
+ axis: null,
214
+ startX: 0,
215
+ startY: 0,
216
+ lastX: 0,
217
+ lastT: 0,
218
+ velocity: 0,
219
+ moved: false,
220
+ });
221
+ const onPointerDown = (event) => {
222
+ if (!draggable || tileStep === 0 || event.button !== 0)
223
+ return;
224
+ drag.current = {
225
+ active: true,
226
+ axis: null,
227
+ startX: event.clientX,
228
+ startY: event.clientY,
229
+ lastX: event.clientX,
230
+ lastT: event.timeStamp,
231
+ velocity: 0,
232
+ moved: false,
38
233
  };
39
- }, [checkScrollPosition]);
40
- const scroll = (direction) => {
41
- const element = scrollRef.current;
42
- if (!element)
234
+ };
235
+ const onPointerMove = (event) => {
236
+ const state = drag.current;
237
+ if (!state.active)
43
238
  return;
44
- const firstChild = element.firstElementChild;
45
- if (!firstChild)
239
+ const dx = event.clientX - state.startX;
240
+ const dy = event.clientY - state.startY;
241
+ /**
242
+ * Which axis this gesture belongs to is decided once, on the first
243
+ * movement past the threshold, and never revisited.
244
+ *
245
+ * A carousel that takes every gesture takes vertical ones too, and on a
246
+ * phone that means the page stops scrolling wherever a carousel happens
247
+ * to be. Deciding once rather than per-event also stops a diagonal drag
248
+ * from flickering between the two.
249
+ */
250
+ if (state.axis === null) {
251
+ if (Math.abs(dx) < DRAG_THRESHOLD && Math.abs(dy) < DRAG_THRESHOLD)
252
+ return;
253
+ state.axis = Math.abs(dx) > Math.abs(dy) ? "x" : "y";
254
+ if (state.axis === "y") {
255
+ state.active = false;
256
+ return;
257
+ }
258
+ event.currentTarget.setPointerCapture(event.pointerId);
259
+ setAnimated(false);
260
+ setDragging(true);
261
+ }
262
+ const elapsed = event.timeStamp - state.lastT;
263
+ if (elapsed > 0)
264
+ state.velocity = (event.clientX - state.lastX) / elapsed;
265
+ state.lastX = event.clientX;
266
+ state.lastT = event.timeStamp;
267
+ state.moved = true;
268
+ // Past either end there is nothing to show, so the track follows at a
269
+ // fraction of the pointer and springs back on release.
270
+ let offset = dx;
271
+ if (!infinite) {
272
+ const over = index - dx / tileStep;
273
+ if (over < 0)
274
+ offset = dx * RUBBER_BAND;
275
+ else if (over > maxIndex)
276
+ offset = dx * RUBBER_BAND;
277
+ }
278
+ setDragPx(offset);
279
+ };
280
+ const endDrag = (event) => {
281
+ const state = drag.current;
282
+ if (!state.active || state.axis !== "x") {
283
+ drag.current.active = false;
284
+ setDragging(false);
46
285
  return;
47
- const gap = parseFloat(getComputedStyle(element).gap) || 0;
48
- const tileWidth = firstChild.offsetWidth + gap;
49
- const targetScroll = element.scrollLeft + (direction === "right" ? tileWidth : -tileWidth);
50
- element.scrollTo({
51
- left: targetScroll,
52
- behavior: "smooth",
53
- });
286
+ }
287
+ if (event.currentTarget.hasPointerCapture(event.pointerId)) {
288
+ event.currentTarget.releasePointerCapture(event.pointerId);
289
+ }
290
+ const dx = event.clientX - state.startX;
291
+ const travelled = -dx / tileStep;
292
+ const flicked = Math.abs(state.velocity) > FLICK_VELOCITY;
293
+ const committed = Math.abs(travelled) > COMMIT_RATIO || flicked;
294
+ // A flick is a direction, not a distance: it moves one tile whichever
295
+ // way it was thrown, even if the pointer barely left where it started.
296
+ const delta = committed
297
+ ? Math.abs(travelled) < 1
298
+ ? Math.sign(travelled) || -Math.sign(state.velocity)
299
+ : Math.round(travelled)
300
+ : 0;
301
+ state.active = false;
302
+ setDragging(false);
303
+ setDragPx(0);
304
+ go(delta);
305
+ };
306
+ /**
307
+ * A drag that ends on a tile must not also open it.
308
+ *
309
+ * The pointer goes down and up on the same anchor, so the browser fires a
310
+ * click regardless of how far it travelled in between. This swallows that
311
+ * one click during the capture phase, before it reaches the tile.
312
+ */
313
+ const onClickCapture = (event) => {
314
+ if (!drag.current.moved)
315
+ return;
316
+ drag.current.moved = false;
317
+ event.preventDefault();
318
+ event.stopPropagation();
319
+ };
320
+ const onKeyDown = (event) => {
321
+ if (event.key === "ArrowLeft") {
322
+ event.preventDefault();
323
+ go(-step);
324
+ }
325
+ else if (event.key === "ArrowRight") {
326
+ event.preventDefault();
327
+ go(step);
328
+ }
54
329
  };
330
+ const canGoBack = infinite || index > 0;
331
+ const canGoForward = infinite || index < maxIndex;
55
332
  const isTopPlacement = controlPlacement.startsWith("top");
56
- const horizontalAlignment = getHorizontalAlignment(controlPlacement);
57
- return (_jsxs(Column, { fillWidth: true, gap: "8", direction: isTopPlacement ? "column" : "column-reverse", children: [_jsxs(Row, { fillWidth: true, gap: "8", paddingX: "24", horizontal: horizontalAlignment, children: [_jsx(IconButton, { icon: "chevronLeft", "aria-label": "Scroll backward", onClick: () => scroll("left"), disabled: !canScrollLeft, style: { border: "none" } }), _jsx(IconButton, { icon: "chevronRight", "aria-label": "Scroll forward", onClick: () => scroll("right"), disabled: !canScrollRight, style: { border: "none" } })] }), _jsx(Row, { ref: scrollRef, gap: "8", overflowX: "auto", style: {
58
- scrollSnapType: "x mandatory",
59
- scrollbarWidth: "none",
60
- }, children: items.map((item, index) => (_jsx(Column, { maxWidth: 48, minWidth: 28, border: true, radius: "xl", overflow: "hidden", gap: "8", aspectRatio: "3/4", style: {
61
- scrollSnapAlign: "start",
62
- flexShrink: 0,
63
- }, ...flex, children: item }, index))) })] }));
333
+ const markerSide = markers === true ? (isTopPlacement ? "bottom" : "top") : markers;
334
+ const controls = (_jsxs(Row, { fillWidth: true, gap: "8", horizontal: getHorizontalAlignment(controlPlacement), children: [_jsx(IconButton, { icon: "chevronLeft", "aria-label": "Previous", onClick: () => go(-step), disabled: !canGoBack, style: { border: "none" } }), _jsx(IconButton, { icon: "chevronRight", "aria-label": "Next", onClick: () => go(step), disabled: !canGoForward, style: { border: "none" } })] }));
335
+ const markerRow = markerSide ? (_jsx(Row, { fillWidth: true, gap: "8", horizontal: "center", vertical: "center", paddingY: "4", children: items.map((_, i) => (_jsx("button", { type: "button", className: styles.marker, "data-active": i === activeIndex ? "true" : undefined, "aria-label": `Go to item ${i + 1} of ${count}`, "aria-current": i === activeIndex ? "true" : undefined, onClick: () => goTo(i) }, i))) })) : null;
336
+ /**
337
+ * Where the track really is, between two indices, while it is being moved.
338
+ *
339
+ * The settled `index` is a whole number and would step the scaling from
340
+ * one tile to the next, which is the opposite of what this is for: the
341
+ * point is that a tile grows as you drag it towards the front rather than
342
+ * snapping when it arrives. `dragPx` is the live offset, so dividing it by
343
+ * the tile pitch gives the fraction of a step the track has travelled, and
344
+ * the sign is negative because dragging right shows earlier items.
345
+ */
346
+ const falloff = proximity === true ? PROXIMITY_FALLOFF : typeof proximity === "number" ? proximity : 0;
347
+ const scaling = falloff > 0 && tileStep > 0;
348
+ const front = index - (tileStep > 0 ? dragPx / tileStep : 0);
349
+ const offset = -(index + origin) * tileStep + dragPx;
350
+ return (_jsxs(Column, { ref: ref, fillWidth: true, gap: "8", "aria-roledescription": "carousel", children: [markerSide === "top" && markerRow, isTopPlacement && controls, _jsx(Flex, { ref: viewportRef, fillWidth: true, className: clip ? styles.viewportClipped : styles.viewport, "data-dragging": dragging ? "true" : undefined, onPointerDown: onPointerDown, onPointerMove: onPointerMove, onPointerUp: endDrag, onPointerCancel: endDrag, onClickCapture: onClickCapture, onKeyDown: onKeyDown,
351
+ // The track is the thing you move, so it is the thing that takes
352
+ // focus and answers the arrow keys.
353
+ tabIndex: 0, role: "group", "aria-label": "Items", children: _jsx(Row, { ref: trackRef, gap: "8", className: styles.track, onTransitionEnd: handleTransitionEnd, style: {
354
+ transform: `translate3d(${offset}px, 0, 0)`,
355
+ // Spread rather than `transition: animated ? undefined : "none"`.
356
+ // The style object is passed through before it reaches the DOM
357
+ // and an `undefined` value survives that trip as the string
358
+ // "undefined", which is not a valid transition and overrides the
359
+ // one on the class — so the track moved instantly, no
360
+ // `transitionend` ever fired, and the wrap-around never
361
+ // normalised. An absent key cannot be stringified.
362
+ ...(animated ? {} : { transition: "none" }),
363
+ }, children: rendered.map((item, i) => {
364
+ const scale = scaling
365
+ ? Math.max(PROXIMITY_FLOOR, 1 - falloff * Math.abs(i - origin - front))
366
+ : 1;
367
+ return (_jsx(Column
368
+ // Same as above, and with wrap-around the same item appears in
369
+ // three copies, so its own identity would not be unique either.
370
+ // biome-ignore lint/suspicious/noArrayIndexKey: no stable id exists
371
+ , { className: styles.tile,
372
+ // The one sizing default that stays. A tile with no width of
373
+ // its own sizes to its content, which is fine for a card of
374
+ // text and collapses to nothing for anything that fills its
375
+ // parent — so the out-of-the-box carousel would depend on what
376
+ // was put in it. `minWidth` is a floor, not a shape: content
377
+ // wider than this still sets the tile's width.
378
+ minWidth: 20, "aria-hidden": infinite && (i < origin || i >= origin + count) ? "true" : undefined, ...tile, style: {
379
+ ...tile.style,
380
+ // Only when asked. Off, a tile carries no transform at all,
381
+ // so it never becomes a containing block for whatever the
382
+ // caller positioned inside it.
383
+ ...(scaling
384
+ ? {
385
+ transform: `scale(${scale})`,
386
+ // Follows the pointer during a drag and eases with the
387
+ // track afterwards, the same rule the track itself
388
+ // uses — and for the same reason, spread rather than
389
+ // set to `undefined`.
390
+ ...(animated ? {} : { transition: "none" }),
391
+ }
392
+ : {}),
393
+ }, children: item }, i));
394
+ }) }) }), !isTopPlacement && controls, markerSide === "bottom" && markerRow] }));
64
395
  });
65
396
  ScrollContainer.displayName = "ScrollContainer";
66
397
  export { ScrollContainer };
@@ -1 +1 @@
1
- {"version":3,"file":"ScrollContainer.js","sourceRoot":"","sources":["../../src/components/ScrollContainer.tsx"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"ScrollContainer.js","sourceRoot":"","sources":["../../src/components/ScrollContainer.tsx"],"names":[],"mappings":"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"}
@@ -0,0 +1,131 @@
1
+ /*
2
+ * The track paints past the viewport by default.
3
+ *
4
+ * This is the point of moving a transform instead of scrolling a box: tiles
5
+ * either side of the ones in front stay visible, so the run reads as something
6
+ * continuous that has been moved along rather than a window with two hard cuts
7
+ * in it.
8
+ *
9
+ * `overflow: clip` with a large `overflow-clip-margin` rather than
10
+ * `overflow: visible`, because visible overflow is not confined to the
11
+ * direction it is wanted in: a track wider than the page would extend the
12
+ * document's scrollable area and give the whole page a horizontal scrollbar,
13
+ * which is a page-level bug produced by a component that cannot see the page.
14
+ * A clip margin is the same effect with a boundary — tiles paint well past the
15
+ * edges, and nothing reaches far enough to push the document out.
16
+ *
17
+ * `clip` is not `hidden`: `hidden` makes the element a scroll container, which
18
+ * would let a stray focus or a wheel gesture scroll the track sideways and put
19
+ * the transform and the scroll offset into disagreement about where the track
20
+ * is. `clip` cannot scroll, which is what this needs.
21
+ */
22
+ .viewport {
23
+ overflow: clip;
24
+ overflow-clip-margin: 100vw;
25
+ }
26
+
27
+ /* Self-contained: nothing paints outside the component's own box. */
28
+ .viewportClipped {
29
+ overflow: clip;
30
+ }
31
+
32
+ .viewport,
33
+ .viewportClipped {
34
+ /*
35
+ * Horizontal gestures belong to the track and vertical ones to the page.
36
+ * Without this the browser claims the whole gesture before the pointer
37
+ * handler can decide, and a carousel becomes a place where the page stops
38
+ * scrolling.
39
+ */
40
+ touch-action: pan-y;
41
+ cursor: grab;
42
+
43
+ &:focus-visible {
44
+ outline: var(--static-space-2) solid var(--brand-border-strong);
45
+ outline-offset: var(--static-space-2);
46
+ border-radius: var(--radius-m);
47
+ }
48
+
49
+ &[data-dragging="true"] {
50
+ cursor: grabbing;
51
+ /* A drag across tiles selects their text otherwise, and the selection
52
+ highlight follows the pointer across the whole run. */
53
+ user-select: none;
54
+ }
55
+ }
56
+
57
+ .track {
58
+ /*
59
+ * `width: max-content` is what makes a transform track possible at all:
60
+ * the row lays out at the sum of its tiles rather than at the width of its
61
+ * parent, so there is something to move. Without it the tiles would be
62
+ * squeezed into one viewport's width and the transform would move an
63
+ * already-complete layout off the screen.
64
+ */
65
+ width: max-content;
66
+ will-change: transform;
67
+ transition: transform var(--transition-duration-macro-long) var(--transition-eased);
68
+ }
69
+
70
+ .tile {
71
+ /* A track item that can shrink is a track item that has no width of its own
72
+ once the row is wider than its parent. */
73
+ flex-shrink: 0;
74
+
75
+ /*
76
+ * For `proximity`. The scale itself is set per tile from the distance to the
77
+ * front, which only the component can know; the easing belongs here so it
78
+ * matches the track's, and so a tile settles into its new size on the same
79
+ * curve the track settles onto its new offset. During a drag the component
80
+ * turns this off inline and the size follows the pointer.
81
+ *
82
+ * `transform-origin: center` keeps a shrinking tile in its own slot instead
83
+ * of pulling away from one side of the gap.
84
+ */
85
+ transform-origin: center;
86
+ transition: transform var(--transition-duration-macro-long) var(--transition-eased);
87
+ }
88
+
89
+ .marker {
90
+ appearance: none;
91
+ border: 0;
92
+ padding: 0;
93
+ width: var(--static-space-8);
94
+ height: var(--static-space-8);
95
+ border-radius: var(--radius-full);
96
+ background: var(--neutral-alpha-medium);
97
+ cursor: pointer;
98
+ transition:
99
+ background var(--transition-duration-micro-medium) var(--transition-eased),
100
+ width var(--transition-duration-micro-medium) var(--transition-eased);
101
+
102
+ &:hover {
103
+ background: var(--neutral-alpha-strong);
104
+ }
105
+
106
+ &:focus-visible {
107
+ outline: var(--static-space-2) solid var(--brand-border-strong);
108
+ outline-offset: var(--static-space-2);
109
+ }
110
+
111
+ /* The one in front is a bar rather than a brighter dot: the difference
112
+ survives being small, and being colour-blind. */
113
+ &[data-active="true"] {
114
+ width: var(--static-space-20);
115
+ background: var(--brand-solid-strong);
116
+ }
117
+ }
118
+
119
+ @media (prefers-reduced-motion: reduce) {
120
+ .track {
121
+ transition: none;
122
+ }
123
+
124
+ .tile {
125
+ transition: none;
126
+ }
127
+
128
+ .marker {
129
+ transition: none;
130
+ }
131
+ }
@@ -1,6 +1,6 @@
1
1
  import React, { ReactNode } from "react";
2
2
  import { InputProps, OptionProps, DropdownWrapperProps } from ".";
3
- import { Placement } from "@floating-ui/react-dom";
3
+ import type { Placement } from "../types";
4
4
  type SelectOptionType = Omit<OptionProps, "selected">;
5
5
  interface SelectProps extends Omit<InputProps, "onSelect" | "value">, Pick<DropdownWrapperProps, "minHeight" | "minWidth" | "maxWidth"> {
6
6
  options: SelectOptionType[];
@@ -1 +1 @@
1
- {"version":3,"file":"Select.d.ts","sourceRoot":"","sources":["../../src/components/Select.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,EAA2C,SAAS,EAAS,MAAM,OAAO,CAAC;AAEzF,OAAO,EAML,UAAU,EAEV,WAAW,EACX,oBAAoB,EAIrB,MAAM,GAAG,CAAC;AACX,OAAO,EAAE,SAAS,EAAE,MAAM,wBAAwB,CAAC;AAGnD,KAAK,gBAAgB,GAAG,IAAI,CAAC,WAAW,EAAE,UAAU,CAAC,CAAC;AAEtD,UAAU,WACR,SAAQ,IAAI,CAAC,UAAU,EAAE,UAAU,GAAG,OAAO,CAAC,EAC5C,IAAI,CAAC,oBAAoB,EAAE,WAAW,GAAG,UAAU,GAAG,UAAU,CAAC;IACnE,OAAO,EAAE,gBAAgB,EAAE,CAAC;IAC5B,KAAK,CAAC,EAAE,MAAM,GAAG,MAAM,EAAE,CAAC;IAC1B,UAAU,CAAC,EAAE,SAAS,CAAC;IACvB,QAAQ,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,EAAE,KAAK,IAAI,CAAC;IAC9C,SAAS,CAAC,EAAE,SAAS,CAAC;IACtB,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,KAAK,CAAC,EAAE,KAAK,CAAC,aAAa,CAAC;IAC5B,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,QAAQ,CAAC,EAAE,OAAO,CAAC;CACpB;AAoFD,QAAA,MAAM,MAAM,oFA+QX,CAAC;AAGF,OAAO,EAAE,MAAM,EAAE,CAAC"}
1
+ {"version":3,"file":"Select.d.ts","sourceRoot":"","sources":["../../src/components/Select.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,EAA2C,SAAS,EAAS,MAAM,OAAO,CAAC;AAEzF,OAAO,EAML,UAAU,EAEV,WAAW,EACX,oBAAoB,EAIrB,MAAM,GAAG,CAAC;AACX,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,UAAU,CAAC;AAG1C,KAAK,gBAAgB,GAAG,IAAI,CAAC,WAAW,EAAE,UAAU,CAAC,CAAC;AAEtD,UAAU,WACR,SAAQ,IAAI,CAAC,UAAU,EAAE,UAAU,GAAG,OAAO,CAAC,EAC5C,IAAI,CAAC,oBAAoB,EAAE,WAAW,GAAG,UAAU,GAAG,UAAU,CAAC;IACnE,OAAO,EAAE,gBAAgB,EAAE,CAAC;IAC5B,KAAK,CAAC,EAAE,MAAM,GAAG,MAAM,EAAE,CAAC;IAC1B,UAAU,CAAC,EAAE,SAAS,CAAC;IACvB,QAAQ,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,EAAE,KAAK,IAAI,CAAC;IAC9C,SAAS,CAAC,EAAE,SAAS,CAAC;IACtB,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,KAAK,CAAC,EAAE,KAAK,CAAC,aAAa,CAAC;IAC5B,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,QAAQ,CAAC,EAAE,OAAO,CAAC;CACpB;AAoFD,QAAA,MAAM,MAAM,oFA+QX,CAAC;AAGF,OAAO,EAAE,MAAM,EAAE,CAAC"}
@@ -7,7 +7,7 @@ import inputStyles from "./Input.module.scss";
7
7
  // Inner component that uses the arrow navigation context
8
8
  const SearchInput = ({ searchInputId, searchQuery, setSearchQuery, setIsDropdownOpen, handleClearSearch, handleBlur, selectRef, }) => {
9
9
  const { handleKeyDown: navKeyDown } = useArrowNavigationContext();
10
- return (_jsx(Input, { "data-scaling": "90", id: `select-search-${searchInputId}`, placeholder: "Search", height: "s", suffix: searchQuery ? (_jsx(IconButton, { tooltip: "Clear", tooltipPosition: "left", icon: "close", variant: "ghost", size: "s", onClick: handleClearSearch })) : undefined, prefix: _jsx(Icon, { name: "search", size: "xs" }), value: searchQuery, onChange: (e) => setSearchQuery(e.target.value), onClick: (e) => {
10
+ return (_jsx(Input, { "data-scaling": "90", id: `select-search-${searchInputId}`, placeholder: "Search", size: "s", suffix: searchQuery ? (_jsx(IconButton, { tooltip: "Clear", tooltipPosition: "left", icon: "close", variant: "ghost", size: "s", onClick: handleClearSearch })) : undefined, prefix: _jsx(Icon, { name: "search", size: "xs" }), value: searchQuery, onChange: (e) => setSearchQuery(e.target.value), onClick: (e) => {
11
11
  e.stopPropagation();
12
12
  e.preventDefault();
13
13
  setIsDropdownOpen(true);