@reactberry/system 2.0.0-beta

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 (165) hide show
  1. package/README.md +48 -0
  2. package/package.json +74 -0
  3. package/src/blocks/Accordion/index.tsx +158 -0
  4. package/src/blocks/AnimatedCarousel/index.tsx +188 -0
  5. package/src/blocks/AppleGlow/index.tsx +144 -0
  6. package/src/blocks/Avatar/index.tsx +167 -0
  7. package/src/blocks/Await/index.tsx +45 -0
  8. package/src/blocks/Cards/AnimatedCard/index.tsx +175 -0
  9. package/src/blocks/Cards/FluorescentCard/index.tsx +180 -0
  10. package/src/blocks/Cards/InfoCard/index.tsx +206 -0
  11. package/src/blocks/Cards/TickerCard/index.tsx +125 -0
  12. package/src/blocks/Carousel/index.tsx +216 -0
  13. package/src/blocks/Checkbox/index.tsx +101 -0
  14. package/src/blocks/Collection/index.tsx +59 -0
  15. package/src/blocks/Container/index.tsx +55 -0
  16. package/src/blocks/Controls/Control.tsx +67 -0
  17. package/src/blocks/Controls/index.tsx +11 -0
  18. package/src/blocks/CyclingNumber/index.tsx +78 -0
  19. package/src/blocks/DisplaySet/index.tsx +42 -0
  20. package/src/blocks/Divider/index.tsx +14 -0
  21. package/src/blocks/Draggable/index.tsx +266 -0
  22. package/src/blocks/Drawer/index.tsx +136 -0
  23. package/src/blocks/DynamicIsland/DynamicIsland.tsx +89 -0
  24. package/src/blocks/DynamicIsland/index.tsx +2 -0
  25. package/src/blocks/Fader/index.tsx +145 -0
  26. package/src/blocks/FamilyDrawer/README.md +116 -0
  27. package/src/blocks/FamilyDrawer/example.tsx +108 -0
  28. package/src/blocks/FamilyDrawer/index.tsx +119 -0
  29. package/src/blocks/FamilyDrawer/views/DefaultView.tsx +93 -0
  30. package/src/blocks/FamilyDrawer/views/KeyView.tsx +129 -0
  31. package/src/blocks/FamilyDrawer/views/PhraseView.tsx +129 -0
  32. package/src/blocks/FamilyDrawer/views/RemoveView.tsx +81 -0
  33. package/src/blocks/FieldSet/index.tsx +173 -0
  34. package/src/blocks/Filesystem/index.tsx +198 -0
  35. package/src/blocks/Gallery/Carousel/index.tsx +257 -0
  36. package/src/blocks/Gallery/Modal/index.tsx +83 -0
  37. package/src/blocks/Gallery/index.tsx +57 -0
  38. package/src/blocks/Gallery/utils/animationVariants.ts +18 -0
  39. package/src/blocks/Gallery/utils/aspectRatio.ts +14 -0
  40. package/src/blocks/Gallery/utils/downloadPhoto.ts +24 -0
  41. package/src/blocks/Gallery/utils/range.ts +11 -0
  42. package/src/blocks/GradientMesh/index.tsx +106 -0
  43. package/src/blocks/Group/index.tsx +152 -0
  44. package/src/blocks/Heading/index.tsx +111 -0
  45. package/src/blocks/HorizontalScroller/index.tsx +135 -0
  46. package/src/blocks/Icon/index.tsx +45 -0
  47. package/src/blocks/Indicator/index.tsx +27 -0
  48. package/src/blocks/InlineEditor/index.tsx +216 -0
  49. package/src/blocks/List/index.tsx +657 -0
  50. package/src/blocks/Main/index.tsx +17 -0
  51. package/src/blocks/Marquee/index.tsx +116 -0
  52. package/src/blocks/MaskedField/index.tsx +199 -0
  53. package/src/blocks/Menu/MenuContent.tsx +246 -0
  54. package/src/blocks/Menu/MenuContext.tsx +34 -0
  55. package/src/blocks/Menu/MenuItem.tsx +104 -0
  56. package/src/blocks/Menu/index.tsx +60 -0
  57. package/src/blocks/Modal/index.tsx +268 -0
  58. package/src/blocks/MorphingPopover/index.tsx +294 -0
  59. package/src/blocks/Overlay/Backdrop.tsx +48 -0
  60. package/src/blocks/Overlay/OverscrollGuard.tsx +36 -0
  61. package/src/blocks/Overlay/index.ts +2 -0
  62. package/src/blocks/Parallax/index.tsx +117 -0
  63. package/src/blocks/ParallaxSection/index.tsx +61 -0
  64. package/src/blocks/Placeholder/index.tsx +48 -0
  65. package/src/blocks/Popover/index.tsx +402 -0
  66. package/src/blocks/Progress/getProgressColor.ts +61 -0
  67. package/src/blocks/Progress/index.tsx +179 -0
  68. package/src/blocks/ProgressiveBlur/index.tsx +75 -0
  69. package/src/blocks/README.md +15 -0
  70. package/src/blocks/RenderAsset/index.tsx +18 -0
  71. package/src/blocks/ScrollContainer/index.tsx +93 -0
  72. package/src/blocks/ShinyText/index.tsx +72 -0
  73. package/src/blocks/Skeleton/index.tsx +71 -0
  74. package/src/blocks/Slider/SliderControls.tsx +119 -0
  75. package/src/blocks/Slider/index.tsx +140 -0
  76. package/src/blocks/Slider/useSlider.ts +126 -0
  77. package/src/blocks/Slideshow/index.tsx +177 -0
  78. package/src/blocks/Spotlight/index.tsx +144 -0
  79. package/src/blocks/Steps/StepIndicator.tsx +149 -0
  80. package/src/blocks/Steps/StepProgress.tsx +164 -0
  81. package/src/blocks/Steps/Steps.tsx +197 -0
  82. package/src/blocks/Steps/StepsNav.tsx +30 -0
  83. package/src/blocks/Steps/StepsTracker.tsx +80 -0
  84. package/src/blocks/Steps/hooks.ts +71 -0
  85. package/src/blocks/Steps/index.tsx +16 -0
  86. package/src/blocks/Steps/types.ts +71 -0
  87. package/src/blocks/StickySectionStack/index.tsx +136 -0
  88. package/src/blocks/Switch/index.tsx +85 -0
  89. package/src/blocks/SystemNotice/index.tsx +81 -0
  90. package/src/blocks/Table/README.md +251 -0
  91. package/src/blocks/Table/Table.tsx +207 -0
  92. package/src/blocks/Table/TablePagination.tsx +189 -0
  93. package/src/blocks/Table/index.ts +33 -0
  94. package/src/blocks/Table/useTableControls.ts +331 -0
  95. package/src/blocks/Tag/index.tsx +27 -0
  96. package/src/blocks/TextBreak/index.tsx +96 -0
  97. package/src/blocks/TextReveal/index.tsx +104 -0
  98. package/src/blocks/Thumbnail/index.tsx +26 -0
  99. package/src/blocks/Ticker/index.tsx +112 -0
  100. package/src/blocks/Toast/index.tsx +77 -0
  101. package/src/blocks/Tooltip/index.tsx +174 -0
  102. package/src/blocks/Underlay/index.tsx +104 -0
  103. package/src/blocks/Upload/Dropzone.tsx +92 -0
  104. package/src/blocks/Upload/UploadBtn.tsx +38 -0
  105. package/src/blocks/Upload/index.tsx +61 -0
  106. package/src/blocks/Upload/types.ts +37 -0
  107. package/src/blocks/VideoMarquee/index.tsx +511 -0
  108. package/src/blocks/index.ts +119 -0
  109. package/src/blocks/pagination/Pagination.tsx +148 -0
  110. package/src/blocks/pagination/PaginationList.tsx +41 -0
  111. package/src/blocks/pagination/index.ts +2 -0
  112. package/src/charts/BarChart.tsx +63 -0
  113. package/src/charts/PieChart.tsx +39 -0
  114. package/src/charts/index.ts +3 -0
  115. package/src/charts/utils.ts +103 -0
  116. package/src/docs/README.md +373 -0
  117. package/src/docs/reference/README.md +299 -0
  118. package/src/elements/box.ts +163 -0
  119. package/src/elements/button.ts +49 -0
  120. package/src/elements/field.ts +129 -0
  121. package/src/elements/index.ts +8 -0
  122. package/src/elements/text.ts +47 -0
  123. package/src/elements/utils.js +97 -0
  124. package/src/hooks/use-copy-to-clipboard.tsx +33 -0
  125. package/src/hooks/use-enter-submit.tsx +23 -0
  126. package/src/hooks/use-local-storage.ts +42 -0
  127. package/src/hooks/use-sidebar.tsx +109 -0
  128. package/src/hooks/useAnimatedText.ts +32 -0
  129. package/src/hooks/useAutosizeTextArea.ts +45 -0
  130. package/src/hooks/useBreakpoint.tsx +123 -0
  131. package/src/hooks/useClickOutside.tsx +38 -0
  132. package/src/hooks/useHover.tsx +33 -0
  133. package/src/hooks/useHoverList.tsx +17 -0
  134. package/src/hooks/useKeyboardShortcuts.ts +91 -0
  135. package/src/hooks/useKeypress.ts +27 -0
  136. package/src/hooks/useOverlay.ts +32 -0
  137. package/src/hooks/useReducedMotion.ts +25 -0
  138. package/src/hooks/useStandaloneMode.ts +35 -0
  139. package/src/hooks/useTouchDevice.ts +34 -0
  140. package/src/icons/index.tsx +129 -0
  141. package/src/index.ts +12 -0
  142. package/src/providers/DesignSystemProvider.tsx +35 -0
  143. package/src/providers/StyledComponentsRegistry.tsx +30 -0
  144. package/src/providers/index.ts +2 -0
  145. package/src/themes/README.md +30 -0
  146. package/src/themes/default/assets/badge-avatar.tsx +45 -0
  147. package/src/themes/default/assets/logo.tsx +42 -0
  148. package/src/themes/default/global.ts +138 -0
  149. package/src/themes/default/modes/dark/config.js +49 -0
  150. package/src/themes/default/modes/dark/skins.js +631 -0
  151. package/src/themes/default/modes/dark/theme.js +87 -0
  152. package/src/themes/default/modes/light/config.js +48 -0
  153. package/src/themes/default/modes/light/skins.js +1026 -0
  154. package/src/themes/default/modes/light/theme.js +74 -0
  155. package/src/themes/default/tokens/controls.js +53 -0
  156. package/src/themes/default/tokens/shadows.js +63 -0
  157. package/src/themes/default/tokens/shapes.js +37 -0
  158. package/src/themes/default/tokens/space.js +143 -0
  159. package/src/themes/default/tokens/spectre.js +16 -0
  160. package/src/themes/default/utils.js +523 -0
  161. package/src/themes/index.ts +11 -0
  162. package/src/types.ts +394 -0
  163. package/src/utils/overlayTheme.ts +61 -0
  164. package/src/utils/pickColor.ts +15 -0
  165. package/tsconfig.json +24 -0
@@ -0,0 +1,511 @@
1
+ "use client";
2
+
3
+ import { animate } from "motion";
4
+ import {
5
+ AnimatePresence,
6
+ motion,
7
+ useAnimationFrame,
8
+ useMotionValue,
9
+ useMotionValueEvent,
10
+ } from "motion/react";
11
+ import { useEffect, useRef, useState } from "react";
12
+ import useMeasure from "react-use-measure";
13
+
14
+ import { Box, Text } from "@/design-system/elements";
15
+ import { ControlLeft, ControlRight } from "../Controls/Control";
16
+
17
+ export interface VideoMarqueeItem {
18
+ id: string;
19
+ src?: string;
20
+ embedUrl?: string;
21
+ sourceUrl?: string;
22
+ imageSrc?: string;
23
+ poster?: string;
24
+ title: string;
25
+ handle: string;
26
+ description?: string;
27
+ }
28
+
29
+ export interface VideoMarqueeProps {
30
+ items: VideoMarqueeItem[];
31
+ speed?: number;
32
+ direction?: "left" | "right";
33
+ pauseOnHover?: boolean;
34
+ gap?: string | number;
35
+ showControls?: boolean;
36
+ showDots?: boolean;
37
+ showPlayPause?: boolean;
38
+ }
39
+
40
+ interface VideoMarqueeCardProps {
41
+ item: VideoMarqueeItem;
42
+ cardRef?: React.Ref<any>;
43
+ ariaHidden?: boolean;
44
+ onHoverStart?: () => void;
45
+ onHoverEnd?: () => void;
46
+ }
47
+
48
+ interface VideoMarqueeFooterControlsProps {
49
+ itemsCount: number;
50
+ activeIndex: number;
51
+ isAutoPlaying: boolean;
52
+ showDots: boolean;
53
+ showPlayPause: boolean;
54
+ onDotClick: (index: number) => void;
55
+ onTogglePlayPause: () => void;
56
+ }
57
+
58
+ const DEFAULT_CARD_STEP = 304;
59
+
60
+ const dotVariants = {
61
+ enter: {
62
+ opacity: 0.2,
63
+ width: ".5rem",
64
+ },
65
+ center: {
66
+ opacity: 0.7,
67
+ width: "2rem",
68
+ },
69
+ exit: {
70
+ opacity: 0.1,
71
+ width: ".5rem",
72
+ },
73
+ hover: {
74
+ opacity: 1,
75
+ scale: 1.1,
76
+ },
77
+ };
78
+
79
+ function wrapOffset(offset: number, sequenceWidth: number) {
80
+ if (!sequenceWidth) {
81
+ return offset;
82
+ }
83
+
84
+ const wrapped = ((offset % sequenceWidth) + sequenceWidth) % sequenceWidth;
85
+ return wrapped === 0 ? 0 : wrapped - sequenceWidth;
86
+ }
87
+
88
+ function VideoMarqueeCard({
89
+ item,
90
+ cardRef,
91
+ ariaHidden,
92
+ onHoverStart,
93
+ onHoverEnd,
94
+ }: VideoMarqueeCardProps) {
95
+ const isEmbed = Boolean(item.embedUrl);
96
+ const isImage =
97
+ Boolean(item.imageSrc) ||
98
+ (!item.embedUrl && !item.src && Boolean(item.poster));
99
+ const badgeLabel = isEmbed || isImage ? "TikTok" : "Demo reel";
100
+
101
+ return (
102
+ <Box
103
+ ref={cardRef}
104
+ as={motion.article}
105
+ width="18rem"
106
+ style={{ maxWidth: "calc(100vw - 3rem)" }}
107
+ border="1px solid rgba(255, 255, 255, 0.12)"
108
+ bg="rgba(255, 255, 255, 0.05)"
109
+ overflow="hidden"
110
+ position="relative"
111
+ aspect="9/16"
112
+ shape="roundedLarge"
113
+ aria-hidden={ariaHidden}
114
+ whileHover={{ y: -6, scale: 1.01 }}
115
+ transition={{ duration: 0.2, ease: "easeOut" }}
116
+ display="flex"
117
+ flexDirection="column"
118
+ onMouseEnter={onHoverStart}
119
+ onMouseLeave={onHoverEnd}
120
+ >
121
+ <Box
122
+ position="absolute"
123
+ top="0.75rem"
124
+ left="0.75rem"
125
+ zIndex={2}
126
+ px="0.625rem"
127
+ py="0.375rem"
128
+ bg="rgba(0, 0, 0, 0.58)"
129
+ color="white"
130
+ style={{ backdropFilter: "blur(10px)" }}
131
+ >
132
+ <Text fontSize="0.75rem" fontWeight="700">
133
+ {badgeLabel}
134
+ </Text>
135
+ </Box>
136
+
137
+ <Box position="relative" flex="1 1 auto" minHeight="0">
138
+ {item.embedUrl ? (
139
+ <Box
140
+ as="iframe"
141
+ src={item.embedUrl}
142
+ title={`${item.title} TikTok embed`}
143
+ width="100%"
144
+ height="100%"
145
+ border="0"
146
+ loading="lazy"
147
+ allowFullScreen
148
+ allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share"
149
+ />
150
+ ) : item.imageSrc || item.poster ? (
151
+ <Box
152
+ as="img"
153
+ src={item.imageSrc || item.poster}
154
+ alt={item.title}
155
+ display="block"
156
+ width="100%"
157
+ height="100%"
158
+ style={{ objectFit: "cover" }}
159
+ />
160
+ ) : (
161
+ <Box
162
+ as="video"
163
+ src={item.src}
164
+ poster={item.poster}
165
+ display="block"
166
+ width="100%"
167
+ height="100%"
168
+ muted
169
+ autoPlay
170
+ loop
171
+ playsInline
172
+ preload="metadata"
173
+ style={{ objectFit: "cover" }}
174
+ />
175
+ )}
176
+ </Box>
177
+
178
+ <Box
179
+ p="1rem"
180
+ color="white"
181
+ bg={isEmbed || isImage ? "rgba(0, 0, 0, 0.92)" : "transparent"}
182
+ position={isEmbed || isImage ? "relative" : "absolute"}
183
+ left={isEmbed || isImage ? undefined : "0"}
184
+ right={isEmbed || isImage ? undefined : "0"}
185
+ bottom={isEmbed || isImage ? undefined : "0"}
186
+ background={
187
+ isEmbed || isImage
188
+ ? undefined
189
+ : "linear-gradient(180deg, rgba(0, 0, 0, 0) 0%, rgba(0, 0, 0, 0.82) 100%)"
190
+ }
191
+ >
192
+ <Text as="div" fontSize="1rem" fontWeight="700">
193
+ {item.title}
194
+ </Text>
195
+ <Text as="div" fontSize="0.875rem" opacity={0.72}>
196
+ {item.handle}
197
+ </Text>
198
+ {item.description && (
199
+ <Text as="div" fontSize="0.875rem" lineHeight={1.4} mt="0.5rem">
200
+ {item.description}
201
+ </Text>
202
+ )}
203
+ {item.sourceUrl && (
204
+ <Text
205
+ as="a"
206
+ href={item.sourceUrl}
207
+ target="_blank"
208
+ rel="noreferrer"
209
+ fontSize="0.75rem"
210
+ fontWeight="700"
211
+ mt="0.625rem"
212
+ style={{
213
+ display: "inline-block",
214
+ textDecoration: "none",
215
+ color: "inherit",
216
+ }}
217
+ >
218
+ Open on TikTok
219
+ </Text>
220
+ )}
221
+ </Box>
222
+ </Box>
223
+ );
224
+ }
225
+
226
+ function VideoMarqueeFooterControls({
227
+ itemsCount,
228
+ activeIndex,
229
+ isAutoPlaying,
230
+ showDots,
231
+ showPlayPause,
232
+ onDotClick,
233
+ onTogglePlayPause,
234
+ }: VideoMarqueeFooterControlsProps) {
235
+ if ((!showDots && !showPlayPause) || itemsCount <= 1) {
236
+ return null;
237
+ }
238
+
239
+ return (
240
+ <Box
241
+ display="flex"
242
+ alignItems="center"
243
+ justifyContent="center"
244
+ gap="s"
245
+ py="m"
246
+ >
247
+ {showDots && (
248
+ <AnimatePresence>
249
+ <Box
250
+ display="flex"
251
+ alignItems="center"
252
+ justifyContent="center"
253
+ gap="xsmall"
254
+ >
255
+ {Array.from({ length: itemsCount }).map((_, index) => (
256
+ <Box
257
+ as={motion.button}
258
+ key={index}
259
+ type="button"
260
+ variants={dotVariants}
261
+ initial="enter"
262
+ animate={index === activeIndex ? "center" : "enter"}
263
+ whileHover="hover"
264
+ exit="exit"
265
+ flex="none"
266
+ height="0.5rem"
267
+ border="0"
268
+ p="0"
269
+ bg="black"
270
+ shape="rounded"
271
+ cursor="pointer"
272
+ onClick={() => onDotClick(index)}
273
+ aria-label={`Go to demo ${index + 1}`}
274
+ />
275
+ ))}
276
+ </Box>
277
+ </AnimatePresence>
278
+ )}
279
+
280
+ {showPlayPause && (
281
+ <Box
282
+ as={motion.button}
283
+ type="button"
284
+ border="1px solid rgba(0, 0, 0, 0.12)"
285
+ bg="white"
286
+ color="black"
287
+ px="1rem"
288
+ py="0.5rem"
289
+ shape="pill"
290
+ cursor="pointer"
291
+ whileTap={{ scale: 0.97 }}
292
+ onClick={onTogglePlayPause}
293
+ aria-pressed={isAutoPlaying}
294
+ >
295
+ <Text as="span" fontSize="0.875rem" fontWeight="700">
296
+ {isAutoPlaying ? "Pause" : "Play"}
297
+ </Text>
298
+ </Box>
299
+ )}
300
+ </Box>
301
+ );
302
+ }
303
+
304
+ export default function VideoMarquee({
305
+ items,
306
+ speed = 42,
307
+ direction = "left",
308
+ pauseOnHover = true,
309
+ gap = "1rem",
310
+ showControls = true,
311
+ showDots = true,
312
+ showPlayPause = true,
313
+ }: VideoMarqueeProps) {
314
+ const [sequenceRef, { width: sequenceWidth }] = useMeasure();
315
+ const [cardRef, { width: cardWidth }] = useMeasure();
316
+ const x = useMotionValue(0);
317
+ const animationRef = useRef<ReturnType<typeof animate> | null>(null);
318
+ const [isHovered, setIsHovered] = useState(false);
319
+ const [isDragging, setIsDragging] = useState(false);
320
+ const [isSettling, setIsSettling] = useState(false);
321
+ const [isAutoPlaying, setIsAutoPlaying] = useState(true);
322
+ const [activeIndex, setActiveIndex] = useState(0);
323
+
324
+ const pixelsPerSecond = Math.max(speed, 1);
325
+ const autoDirection = direction === "left" ? -1 : 1;
326
+ const itemStep =
327
+ (items.length ? sequenceWidth / items.length : 0) ||
328
+ cardWidth ||
329
+ DEFAULT_CARD_STEP;
330
+ const isPaused =
331
+ !isAutoPlaying || (pauseOnHover && isHovered) || isDragging || isSettling;
332
+
333
+ const getTravel = (offset: number) => {
334
+ if (!sequenceWidth) {
335
+ return 0;
336
+ }
337
+
338
+ const wrapped = wrapOffset(offset, sequenceWidth);
339
+ return ((-wrapped % sequenceWidth) + sequenceWidth) % sequenceWidth;
340
+ };
341
+
342
+ useEffect(() => {
343
+ if (!sequenceWidth) {
344
+ return;
345
+ }
346
+
347
+ x.set(wrapOffset(x.get(), sequenceWidth));
348
+ }, [sequenceWidth, x]);
349
+
350
+ useEffect(() => {
351
+ return () => {
352
+ animationRef.current?.stop();
353
+ };
354
+ }, []);
355
+
356
+ useAnimationFrame((_, delta) => {
357
+ if (!sequenceWidth || isPaused) {
358
+ return;
359
+ }
360
+
361
+ const distance = (pixelsPerSecond * delta) / 1000;
362
+ const next = x.get() + distance * autoDirection;
363
+ x.set(wrapOffset(next, sequenceWidth));
364
+ });
365
+
366
+ useMotionValueEvent(x, "change", (latest) => {
367
+ if (!sequenceWidth || !itemStep) {
368
+ return;
369
+ }
370
+
371
+ const travel = getTravel(latest);
372
+ const nextIndex = Math.round(travel / itemStep) % items.length;
373
+ setActiveIndex(nextIndex);
374
+ });
375
+
376
+ const animateTo = (target: number) => {
377
+ if (!sequenceWidth) {
378
+ return;
379
+ }
380
+
381
+ animationRef.current?.stop();
382
+ setIsSettling(true);
383
+
384
+ const controls = animate(x, wrapOffset(target, sequenceWidth), {
385
+ duration: 0.35,
386
+ ease: "easeOut",
387
+ onComplete: () => {
388
+ x.set(wrapOffset(x.get(), sequenceWidth));
389
+ setIsSettling(false);
390
+ animationRef.current = null;
391
+ },
392
+ });
393
+
394
+ animationRef.current = controls;
395
+ };
396
+
397
+ const stepBy = (stepDirection: "prev" | "next") => {
398
+ const step = itemStep || DEFAULT_CARD_STEP;
399
+ const delta = stepDirection === "next" ? -step : step;
400
+ animateTo(x.get() + delta);
401
+ };
402
+
403
+ const goToIndex = (targetIndex: number) => {
404
+ if (!itemStep || !items.length) {
405
+ return;
406
+ }
407
+
408
+ const currentIndex =
409
+ Math.round(getTravel(x.get()) / itemStep) % items.length;
410
+ let deltaIndex = targetIndex - currentIndex;
411
+
412
+ if (Math.abs(deltaIndex) > items.length / 2) {
413
+ deltaIndex += deltaIndex > 0 ? -items.length : items.length;
414
+ }
415
+
416
+ animateTo(x.get() - deltaIndex * itemStep);
417
+ };
418
+
419
+ const snapToClosest = () => {
420
+ if (!itemStep) {
421
+ return;
422
+ }
423
+
424
+ const snappedIndex =
425
+ Math.round(getTravel(x.get()) / itemStep) % items.length;
426
+ goToIndex(snappedIndex);
427
+ };
428
+
429
+ const renderSequence = ({
430
+ withRefs = false,
431
+ ariaHidden = false,
432
+ }: {
433
+ withRefs?: boolean;
434
+ ariaHidden?: boolean;
435
+ }) => (
436
+ <Box
437
+ ref={withRefs ? sequenceRef : undefined}
438
+ display="flex"
439
+ gap={gap}
440
+ pr={gap}
441
+ aria-hidden={ariaHidden || undefined}
442
+ >
443
+ {items.map((item, index) => (
444
+ <VideoMarqueeCard
445
+ key={`${item.id}-${ariaHidden ? "duplicate" : "primary"}`}
446
+ item={item}
447
+ cardRef={withRefs && index === 0 ? cardRef : undefined}
448
+ ariaHidden={ariaHidden}
449
+ onHoverStart={pauseOnHover ? () => setIsHovered(true) : undefined}
450
+ onHoverEnd={pauseOnHover ? () => setIsHovered(false) : undefined}
451
+ />
452
+ ))}
453
+ </Box>
454
+ );
455
+
456
+ if (!items.length) {
457
+ return null;
458
+ }
459
+
460
+ return (
461
+ <Box
462
+ position="relative"
463
+ overflow={"hidden"}
464
+ p="l"
465
+ >
466
+ <Box
467
+ as={motion.div}
468
+ drag="x"
469
+ dragElastic={0.04}
470
+ style={{
471
+ x,
472
+ display: "flex",
473
+ width: "max-content",
474
+ cursor: isDragging ? "grabbing" : "grab",
475
+ }}
476
+ onDragStart={() => {
477
+ animationRef.current?.stop();
478
+ setIsDragging(true);
479
+ }}
480
+ onDragEnd={() => {
481
+ setIsDragging(false);
482
+ snapToClosest();
483
+ }}
484
+ >
485
+ {renderSequence({ withRefs: true })}
486
+ {renderSequence({ ariaHidden: true })}
487
+ </Box>
488
+
489
+ {showControls && items.length > 1 && (
490
+ <>
491
+ <ControlLeft left="0.5rem" onClick={() => stepBy("prev")} />
492
+ <ControlRight
493
+ right="0.5rem"
494
+ left="auto"
495
+ onClick={() => stepBy("next")}
496
+ />
497
+ </>
498
+ )}
499
+
500
+ <VideoMarqueeFooterControls
501
+ itemsCount={items.length}
502
+ activeIndex={activeIndex}
503
+ isAutoPlaying={isAutoPlaying}
504
+ showDots={showDots}
505
+ showPlayPause={showPlayPause}
506
+ onDotClick={goToIndex}
507
+ onTogglePlayPause={() => setIsAutoPlaying((current) => !current)}
508
+ />
509
+ </Box>
510
+ );
511
+ }
@@ -0,0 +1,119 @@
1
+ // Core layout blocks
2
+ export { default as Container } from "./Container";
3
+ export { default as Main } from "./Main";
4
+ export { default as Divider } from "./Divider";
5
+ export { default as Heading } from "./Heading";
6
+
7
+ // UI components
8
+ export { default as Avatar } from "./Avatar";
9
+ export { default as Icon } from "./Icon";
10
+ export { Tag } from "./Tag";
11
+ export { default as Skeleton } from "./Skeleton";
12
+ export { default as Placeholder } from "./Placeholder";
13
+ export { default as Thumbnail } from "./Thumbnail";
14
+
15
+ // Interactive components
16
+ export { default as Switch } from "./Switch";
17
+ export { default as Tooltip } from "./Tooltip";
18
+ export { default as Popover } from "./Popover";
19
+ export { default as MorphingPopover } from "./MorphingPopover";
20
+ export { Menu, MenuItem, MenuContent } from "./Menu";
21
+ export { default as Accordion } from "./Accordion";
22
+ export { Drawer, DrawerButton } from "./Drawer";
23
+ export { default as FamilyDrawer } from "./FamilyDrawer";
24
+ export { default as SystemNotice } from "./SystemNotice";
25
+ export { default as Toast } from "./Toast";
26
+
27
+ // Layout components
28
+ export { default as Collection } from "./Collection";
29
+ export { default as Group } from "./Group";
30
+ export { default as List } from "./List";
31
+ export { default as ScrollContainer } from "./ScrollContainer";
32
+ export { default as HorizontalScroller } from "./HorizontalScroller";
33
+ export { default as Filesystem } from "./Filesystem";
34
+
35
+ // Pagination components
36
+ export { Pagination } from "./pagination/Pagination";
37
+ export { default as PaginationList } from "./pagination/PaginationList";
38
+
39
+ // Table components
40
+ export {
41
+ Table,
42
+ TableHeader,
43
+ TableBody,
44
+ TableFooter,
45
+ TableRow,
46
+ TableCell,
47
+ TableHeaderCell,
48
+ TablePagination,
49
+ useTableControls,
50
+ useTableFilters,
51
+ useFilteredTableControls,
52
+ } from "./Table";
53
+
54
+ // Form components
55
+ export { default as Checkbox } from "./Checkbox";
56
+ export type { CheckboxProps } from "./Checkbox";
57
+ export { default as FieldSet } from "./FieldSet";
58
+ export { default as Controls } from "./Controls";
59
+ export { default as InlineEditor } from "./InlineEditor";
60
+ export { MaskedField, maskPresets } from "./MaskedField";
61
+ export type { MaskPresetType, MaskedFieldProps } from "./MaskedField";
62
+
63
+ // Display components
64
+ export { default as Progress } from "./Progress";
65
+ export { default as Gallery } from "./Gallery";
66
+ export { Slideshow, wrap } from "./Slideshow";
67
+ export { default as Carousel } from "./Carousel";
68
+ export { default as Slider } from "./Slider";
69
+ export { default as AnimatedCarousel } from "./AnimatedCarousel";
70
+ export { default as Marquee } from "./Marquee";
71
+ export { default as VideoMarquee } from "./VideoMarquee";
72
+ export { default as Ticker } from "./Ticker";
73
+ export { default as CyclingNumber } from "./CyclingNumber";
74
+ export { DynamicIsland } from "./DynamicIsland";
75
+ export type { DynamicIslandProps, DynamicIslandView } from "./DynamicIsland";
76
+
77
+ // Effects and animations
78
+ export { default as Fader } from "./Fader";
79
+ export { default as Parallax } from "./Parallax";
80
+ export { default as ParallaxSection } from "./ParallaxSection";
81
+ export { default as Spotlight } from "./Spotlight";
82
+ export { default as ShinyText } from "./ShinyText";
83
+ export { default as StickySectionStack } from "./StickySectionStack";
84
+ export { default as TextBreak } from "./TextBreak";
85
+ export { default as TextReveal } from "./TextReveal";
86
+ export { default as GradientMesh } from "./GradientMesh";
87
+ export { default as AnimatedCard } from "./Cards/AnimatedCard";
88
+ export { default as FluorescentCard } from "./Cards/FluorescentCard";
89
+ export { default as ProgressiveBlur } from "./ProgressiveBlur";
90
+ export type { ProgressiveBlurProps } from "./ProgressiveBlur";
91
+ export { default as AppleGlow } from "./AppleGlow";
92
+ export type { AppleGlowProps } from "./AppleGlow";
93
+
94
+ // Utility components
95
+ export { Await } from "./Await";
96
+ export { default as RenderAsset } from "./RenderAsset";
97
+ export { DraggableContainer, DraggablePanel, PanelHeader } from "./Draggable";
98
+ export { default as Underlay } from "./Underlay";
99
+ export { default as DisplaySet } from "./DisplaySet";
100
+
101
+ // Steps components
102
+ export {
103
+ Steps,
104
+ StepProgress,
105
+ StepIndicator,
106
+ StepsNav,
107
+ useHover,
108
+ useStepNavigation,
109
+ } from "./Steps";
110
+ export type {
111
+ StepConfig,
112
+ StepThemeConfig,
113
+ StepVariant,
114
+ BaseStepProps,
115
+ } from "./Steps";
116
+
117
+ // Card components
118
+ export { default as InfoCard } from "./Cards/InfoCard";
119
+ export { default as TickerCard } from "./Cards/TickerCard";