@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,149 @@
1
+ "use client";
2
+
3
+ import React from "react";
4
+ import { motion } from "motion/react";
5
+ import { Box, Text } from "@/design-system/elements";
6
+ import Tooltip from "@/design-system/blocks/Tooltip";
7
+ import { useHover } from "./hooks";
8
+ import { StepThemeConfig } from "./types";
9
+ import { IconDCheck } from "@/design-system/icons";
10
+
11
+ interface StepIndicatorProps {
12
+ /** Whether this step is currently active */
13
+ active: boolean;
14
+ /** The step number (1-based) */
15
+ index: number;
16
+ /** The label text for this step */
17
+ label: string;
18
+ /** Whether this step is completed */
19
+ completed: boolean;
20
+ /** Theme configuration */
21
+ variant: StepThemeConfig;
22
+ /** Whether to use simple mode (no numbers/icons) */
23
+ simple?: boolean;
24
+ /** Whether to show labels */
25
+ showLabels?: boolean;
26
+ /** Whether to show tooltips on hover */
27
+ showTooltip?: boolean;
28
+ /** Callback when step is clicked */
29
+ setActive?: (index: number) => void;
30
+ /** Additional props */
31
+ [key: string]: any;
32
+ }
33
+
34
+ interface DotProps {
35
+ state: {
36
+ bg: string;
37
+ color: string;
38
+ };
39
+ variant: StepThemeConfig;
40
+ active: boolean;
41
+ children: React.ReactNode;
42
+ }
43
+
44
+ function Dot({ state, variant, active, children }: DotProps) {
45
+ return (
46
+ <Box
47
+ as={motion.div}
48
+ bg={state.bg}
49
+ color={state.color}
50
+ border=".25rem solid"
51
+ borderColor={variant.borderColor}
52
+ shape="circle"
53
+ flex="none"
54
+ width={`${parseFloat(variant.size) * 8}${variant.unit}`}
55
+ height={`${parseFloat(variant.size) * 8}${variant.unit}`}
56
+ display="flex"
57
+ alignItems="center"
58
+ justifyContent="center"
59
+ initial={{ scale: 0.75 }}
60
+ animate={{ scale: active ? 1.125 : 0.75 }}
61
+ exit={{ scale: 0.75 }}
62
+ // transition={{ type: "spring", stiffness: 500 }}
63
+ style={{ pointerEvents: "none" }}
64
+ >
65
+ {children}
66
+ </Box>
67
+ );
68
+ }
69
+
70
+ function StepIndicator({
71
+ active,
72
+ index,
73
+ label,
74
+ completed,
75
+ variant,
76
+ simple = false,
77
+ showLabels = true,
78
+ showTooltip = true,
79
+ setActive,
80
+ ...rest
81
+ }: StepIndicatorProps) {
82
+ const [hoverRef, isHovered] = useHover();
83
+
84
+ const getCurrentTheme = () => {
85
+ if (active) {
86
+ return variant.presets.active;
87
+ }
88
+ if (completed) {
89
+ return variant.presets.completed;
90
+ }
91
+ return variant.presets.default;
92
+ };
93
+
94
+ const currentTheme = getCurrentTheme();
95
+
96
+ const handleClick = () => {
97
+ if (setActive) {
98
+ setActive(index - 1); // Convert to 0-based index
99
+ }
100
+ };
101
+
102
+ const stepContent = (
103
+ <Box
104
+ display="flex"
105
+ alignItems="center"
106
+ flexDirection="column"
107
+ flex={active ? "auto" : "none"}
108
+ mx="auto"
109
+ position="relative"
110
+ zIndex={isHovered ? 3 : 2}
111
+ cursor={setActive ? "pointer" : "default"}
112
+ onClick={handleClick}
113
+ {...rest}
114
+ ref={hoverRef}
115
+ >
116
+ <Dot active={active} variant={variant} state={currentTheme}>
117
+ {!simple && active && (
118
+ <Text fontSize={variant.fontSize} color="inherit">
119
+ {index}
120
+ </Text>
121
+ )}
122
+ {!simple && completed && (
123
+ <Box as={IconDCheck} size="1.5rem" color="inherit" />
124
+ )}
125
+ </Dot>
126
+
127
+ {showLabels && (
128
+ <Text
129
+ fontWeight="700"
130
+ fontSize={variant.fontSize}
131
+ display={["none", "flex"]}
132
+ color={active ? variant.baseColor : variant.textColor}
133
+ textAlign="center"
134
+ mt="xxs"
135
+ >
136
+ {label}
137
+ </Text>
138
+ )}
139
+ </Box>
140
+ );
141
+
142
+ if (showTooltip) {
143
+ return <Tooltip content={label}>{stepContent}</Tooltip>;
144
+ }
145
+
146
+ return stepContent;
147
+ }
148
+
149
+ export default StepIndicator;
@@ -0,0 +1,164 @@
1
+ "use client";
2
+
3
+ import React from "react";
4
+ import { Box } from "@/design-system/elements";
5
+ import StepIndicator from "./StepIndicator";
6
+ import { BaseStepProps, StepThemeConfig, StepVariant } from "./types";
7
+
8
+ interface StepProgressProps extends BaseStepProps {
9
+ /** Index of the completed step (all steps up to this index are completed) */
10
+ completed?: number;
11
+ }
12
+
13
+ const defaultThemeConfig: Record<StepVariant, StepThemeConfig> = {
14
+ light: {
15
+ baseColor: "primary",
16
+ textColor: "secondary",
17
+ borderColor: "white",
18
+ trackColor: "tertiary",
19
+ completedTrackColor: "accent",
20
+ size: "0.3",
21
+ unit: "rem",
22
+ fontSize: "small",
23
+ presets: {
24
+ active: {
25
+ bg: "accent",
26
+ color: "white",
27
+ },
28
+ completed: {
29
+ bg: "accent",
30
+ color: "white",
31
+ },
32
+ default: {
33
+ bg: "tertiary",
34
+ color: "secondary",
35
+ },
36
+ },
37
+ },
38
+ dark: {
39
+ baseColor: "primary",
40
+ textColor: "secondary",
41
+ borderColor: "tertiary",
42
+ trackColor: "secondary",
43
+ completedTrackColor: "brand",
44
+ size: "0.3",
45
+ unit: "rem",
46
+ fontSize: "small",
47
+ presets: {
48
+ active: {
49
+ bg: "white",
50
+ color: "primary",
51
+ },
52
+ completed: {
53
+ bg: "primary",
54
+ color: "white",
55
+ },
56
+ default: {
57
+ bg: "secondary",
58
+ color: "white",
59
+ },
60
+ },
61
+ },
62
+ };
63
+
64
+ function StepProgress({
65
+ config,
66
+ active,
67
+ variant = "light",
68
+ skin,
69
+ simple = false,
70
+ showLabels = true,
71
+ showEdges = true,
72
+ showTooltip = true,
73
+ childProps,
74
+ setActive,
75
+ ...rest
76
+ }: StepProgressProps) {
77
+ const currentTheme = skin || defaultThemeConfig[variant];
78
+
79
+ // Calculate the progress width based on active step
80
+ const progressWidth = `${
81
+ (active + 1) * (100 / config.length) - 100 / (config.length * 2)
82
+ }%`;
83
+
84
+ return (
85
+ <Box
86
+ display="grid"
87
+ gridTemplateColumns={`repeat(${config.length}, 1fr)`}
88
+ position="relative"
89
+ alignItems="center"
90
+ width="100%"
91
+ {...rest}
92
+ >
93
+ {/* Step Indicators */}
94
+ {config.map((item, i) => (
95
+ <StepIndicator
96
+ key={i}
97
+ active={active === i}
98
+ index={i + 1}
99
+ completed={active > i}
100
+ showLabels={showLabels}
101
+ showTooltip={showTooltip}
102
+ variant={currentTheme}
103
+ simple={simple}
104
+ setActive={setActive}
105
+ {...item}
106
+ {...childProps}
107
+ />
108
+ ))}
109
+
110
+ {/* Edge Circles */}
111
+ {showEdges && (
112
+ <>
113
+ <Box
114
+ size="1rem"
115
+ shape="circle"
116
+ bg={currentTheme.presets.default.bg}
117
+ border="3px solid"
118
+ borderColor={currentTheme.borderColor}
119
+ position="absolute"
120
+ top="50%"
121
+ left="-1px"
122
+ mt="-1.375rem"
123
+ zIndex={1}
124
+ />
125
+ <Box
126
+ width="1rem"
127
+ height="1rem"
128
+ shape="circle"
129
+ bg={currentTheme.presets.default.bg}
130
+ border="3px solid"
131
+ borderColor={currentTheme.borderColor}
132
+ position="absolute"
133
+ top="50%"
134
+ right="0"
135
+ mt="-1.375rem"
136
+ zIndex={1}
137
+ />
138
+ </>
139
+ )}
140
+
141
+ {/* Progress Track */}
142
+ <Box
143
+ width="100%"
144
+ height={`${currentTheme.size}${currentTheme.unit}`}
145
+ bg={currentTheme.trackColor}
146
+ shape="pill"
147
+ position="absolute"
148
+ top="50%"
149
+ mt="-1rem"
150
+ zIndex={0}
151
+ >
152
+ {/* Completed Progress */}
153
+ <Box
154
+ width={progressWidth}
155
+ height="100%"
156
+ bg={currentTheme.completedTrackColor}
157
+ shape="pill"
158
+ />
159
+ </Box>
160
+ </Box>
161
+ );
162
+ }
163
+
164
+ export default StepProgress;
@@ -0,0 +1,197 @@
1
+ "use client";
2
+
3
+ import React from "react";
4
+ import { Box, Text } from "@/design-system/elements";
5
+ import StepProgress from "./StepProgress";
6
+ import { BaseStepProps } from "./types";
7
+ import { useStepNavigation } from "./hooks";
8
+
9
+ interface StepsProps extends Omit<BaseStepProps, "active"> {
10
+ /** Initial active step (0-based) */
11
+ initialStep?: number;
12
+ /** Whether navigation is controlled externally */
13
+ controlled?: boolean;
14
+ /** Current active step when controlled */
15
+ activeStep?: number;
16
+ /** Callback when step changes */
17
+ onStepChange?: (step: number) => void;
18
+ /** Whether to show navigation buttons */
19
+ showNavigation?: boolean;
20
+ /** Custom labels for navigation buttons */
21
+ navigationLabels?: {
22
+ next?: string;
23
+ previous?: string;
24
+ finish?: string;
25
+ };
26
+ /** Whether steps can be clicked to navigate */
27
+ allowStepClick?: boolean;
28
+ /** Validation function for step navigation */
29
+ validateStep?: (
30
+ fromStep: number,
31
+ toStep: number
32
+ ) => boolean | Promise<boolean>;
33
+ /** Loading state */
34
+ loading?: boolean;
35
+ /** Callback when all steps are completed */
36
+ onComplete?: () => void;
37
+ }
38
+
39
+ function Steps({
40
+ config,
41
+ initialStep = 0,
42
+ controlled = false,
43
+ activeStep: controlledActiveStep,
44
+ onStepChange,
45
+ showNavigation = false,
46
+ navigationLabels = {
47
+ next: "Next",
48
+ previous: "Previous",
49
+ finish: "Finish",
50
+ },
51
+ allowStepClick = true,
52
+ validateStep,
53
+ loading = false,
54
+ onComplete,
55
+ variant = "light",
56
+ skin,
57
+ simple = false,
58
+ showLabels = true,
59
+ showEdges = true,
60
+ showTooltip = true,
61
+ childProps,
62
+ ...rest
63
+ }: StepsProps) {
64
+ const {
65
+ activeStep: internalActiveStep,
66
+ nextStep,
67
+ prevStep,
68
+ goToStep,
69
+ isFirst,
70
+ isLast,
71
+ } = useStepNavigation(config.length, initialStep);
72
+
73
+ const activeStep = controlled
74
+ ? controlledActiveStep ?? 0
75
+ : internalActiveStep;
76
+
77
+ const handleStepChange = async (newStep: number) => {
78
+ if (validateStep) {
79
+ const isValid = await validateStep(activeStep, newStep);
80
+ if (!isValid) return;
81
+ }
82
+
83
+ if (controlled) {
84
+ onStepChange?.(newStep);
85
+ } else {
86
+ goToStep(newStep);
87
+ onStepChange?.(newStep);
88
+ }
89
+ };
90
+
91
+ const handleNext = async () => {
92
+ if (isLast && onComplete) {
93
+ onComplete();
94
+ return;
95
+ }
96
+
97
+ if (controlled) {
98
+ onStepChange?.(activeStep + 1);
99
+ } else {
100
+ const newStep = activeStep + 1;
101
+ if (validateStep) {
102
+ const isValid = await validateStep(activeStep, newStep);
103
+ if (!isValid) return;
104
+ }
105
+ nextStep();
106
+ onStepChange?.(newStep);
107
+ }
108
+ };
109
+
110
+ const handlePrevious = () => {
111
+ if (controlled) {
112
+ onStepChange?.(activeStep - 1);
113
+ } else {
114
+ prevStep();
115
+ onStepChange?.(activeStep - 1);
116
+ }
117
+ };
118
+
119
+ const handleStepClick = allowStepClick ? handleStepChange : undefined;
120
+
121
+ return (
122
+ <Box display="flex" flexDirection="column" gap="large">
123
+ {/* Step Progress */}
124
+ <StepProgress
125
+ config={config}
126
+ active={activeStep}
127
+ setActive={handleStepClick}
128
+ variant={variant}
129
+ skin={skin}
130
+ simple={simple}
131
+ showLabels={showLabels}
132
+ showEdges={showEdges}
133
+ showTooltip={showTooltip}
134
+ childProps={childProps}
135
+ {...rest}
136
+ />
137
+
138
+ {/* Navigation Buttons */}
139
+ {showNavigation && (
140
+ <Box
141
+ display="flex"
142
+ justifyContent="space-between"
143
+ alignItems="center"
144
+ gap="medium"
145
+ >
146
+ <Box>
147
+ {!isFirst && (
148
+ <Box
149
+ as="button"
150
+ skin="default"
151
+ px="medium"
152
+ py="small"
153
+ shape="pill"
154
+ cursor="pointer"
155
+ disabled={loading}
156
+ onClick={handlePrevious}
157
+ >
158
+ <Text fontSize="small" color="inherit">
159
+ {navigationLabels.previous}
160
+ </Text>
161
+ </Box>
162
+ )}
163
+ </Box>
164
+
165
+ <Box display="flex" gap="small">
166
+ {/* Step Counter */}
167
+ <Text fontSize="small" color="secondary">
168
+ {activeStep + 1} of {config.length}
169
+ </Text>
170
+ </Box>
171
+
172
+ <Box>
173
+ <Box
174
+ as="button"
175
+ px="medium"
176
+ py="small"
177
+ shape="pill"
178
+ cursor="pointer"
179
+ disabled={loading}
180
+ onClick={handleNext}
181
+ >
182
+ <Text fontSize="small" color="inherit">
183
+ {loading
184
+ ? "Loading..."
185
+ : isLast
186
+ ? navigationLabels.finish
187
+ : navigationLabels.next}
188
+ </Text>
189
+ </Box>
190
+ </Box>
191
+ </Box>
192
+ )}
193
+ </Box>
194
+ );
195
+ }
196
+
197
+ export default Steps;
@@ -0,0 +1,30 @@
1
+ "use client";
2
+
3
+ import React from 'react';
4
+ import StepProgress from './StepProgress';
5
+ import { BaseStepProps } from './types';
6
+
7
+ interface StepsNavProps extends BaseStepProps {
8
+ /** Additional margin top spacing */
9
+ mt?: string | number | object;
10
+ }
11
+
12
+ function StepsNav({
13
+ config,
14
+ active,
15
+ mt = "medium",
16
+ showLabels = true,
17
+ ...rest
18
+ }: StepsNavProps) {
19
+ return (
20
+ <StepProgress
21
+ showLabels={showLabels}
22
+ config={config}
23
+ active={active}
24
+ mt={mt}
25
+ {...rest}
26
+ />
27
+ );
28
+ }
29
+
30
+ export default StepsNav;
@@ -0,0 +1,80 @@
1
+ "use client";
2
+
3
+ import React from "react";
4
+ import { Box } from "@/design-system/elements";
5
+
6
+ import Tooltip from "../Tooltip";
7
+ import { motion } from "motion/react";
8
+
9
+ interface StepsTrackerProps {
10
+ /** Index of the completed step (all steps up to this index are completed) */
11
+ completed?: number;
12
+ config: { label: string }[];
13
+ }
14
+
15
+ interface TrackSegmentProps {
16
+ isCompleted: boolean;
17
+ }
18
+
19
+ interface TrackStepProps {
20
+ isCompleted: boolean;
21
+ isActive?: boolean;
22
+ item: { label: string };
23
+ }
24
+
25
+ function TrackStep({ isCompleted, isActive, item }: TrackStepProps) {
26
+ return (
27
+ <Tooltip content={item.label} placement="bottom" zIndex={100003}>
28
+ <Box
29
+ as={motion.div}
30
+ flex="none"
31
+ bg={isCompleted ? "accent" : "tertiary"}
32
+ shape="circle"
33
+ size="1rem"
34
+ display="flex"
35
+ alignItems="center"
36
+ justifyContent="center"
37
+ initial={{ scale: 0.85 }}
38
+ animate={{ scale: isActive ? 1.125 : 0.85 }}
39
+ exit={{ scale: 0.85 }}
40
+ whileHover={{ scale: 1.125 }}
41
+ //style={{ pointerEvents: "none" }}
42
+ />
43
+ </Tooltip>
44
+ );
45
+ }
46
+
47
+ function TrackSegment({ isCompleted }: TrackSegmentProps) {
48
+ return (
49
+ <Box
50
+ flex="auto"
51
+ height="0.25rem"
52
+ bg={isCompleted ? "accent" : "tertiary"}
53
+ shape="pill"
54
+ alignSelf="center"
55
+ />
56
+ );
57
+ }
58
+
59
+ function StepsTracker({ config, completed = 0, ...rest }: StepsTrackerProps) {
60
+ return (
61
+ <Box display="flex" alignItems="flex-start" gap="xs" width="100%" {...rest}>
62
+ {config.map((item, i) => (
63
+ <React.Fragment key={i}>
64
+ {/* Step Indicator */}
65
+ <TrackStep
66
+ item={item}
67
+ isCompleted={completed >= i}
68
+ isActive={completed === i}
69
+ />
70
+ {/* Track Segment (if not the last step) */}
71
+ {i < config.length - 1 && (
72
+ <TrackSegment isCompleted={completed >= i + 1} />
73
+ )}
74
+ </React.Fragment>
75
+ ))}
76
+ </Box>
77
+ );
78
+ }
79
+
80
+ export default StepsTracker;
@@ -0,0 +1,71 @@
1
+ "use client";
2
+
3
+ import { useCallback, useEffect, useRef, useState } from "react";
4
+
5
+ /**
6
+ * Custom hook for managing hover state on an element
7
+ * @returns A tuple with [ref, isHovered] where ref should be attached to the element
8
+ */
9
+ export function useHover(): [React.RefObject<HTMLElement | null>, boolean] {
10
+ const [isHovered, setIsHovered] = useState(false);
11
+ const ref = useRef<HTMLElement | null>(null);
12
+
13
+ const handleMouseEnter = useCallback(() => setIsHovered(true), []);
14
+ const handleMouseLeave = useCallback(() => setIsHovered(false), []);
15
+
16
+ useEffect(() => {
17
+ const node = ref.current;
18
+ if (node) {
19
+ node.addEventListener("mouseenter", handleMouseEnter);
20
+ node.addEventListener("mouseleave", handleMouseLeave);
21
+
22
+ return () => {
23
+ node.removeEventListener("mouseenter", handleMouseEnter);
24
+ node.removeEventListener("mouseleave", handleMouseLeave);
25
+ };
26
+ }
27
+ }, [handleMouseEnter, handleMouseLeave]);
28
+
29
+ return [ref, isHovered];
30
+ }
31
+
32
+ /**
33
+ * Custom hook for managing step navigation
34
+ * @param totalSteps Total number of steps
35
+ * @param initialStep Initial active step (0-based)
36
+ */
37
+ export function useStepNavigation(totalSteps: number, initialStep = 0) {
38
+ const [activeStep, setActiveStep] = useState(initialStep);
39
+
40
+ const nextStep = useCallback(() => {
41
+ setActiveStep((prev) => Math.min(prev + 1, totalSteps - 1));
42
+ }, [totalSteps]);
43
+
44
+ const prevStep = useCallback(() => {
45
+ setActiveStep((prev) => Math.max(prev - 1, 0));
46
+ }, []);
47
+
48
+ const goToStep = useCallback(
49
+ (step: number) => {
50
+ if (step >= 0 && step < totalSteps) {
51
+ setActiveStep(step);
52
+ }
53
+ },
54
+ [totalSteps]
55
+ );
56
+
57
+ const isFirst = activeStep === 0;
58
+ const isLast = activeStep === totalSteps - 1;
59
+ const progress = totalSteps > 0 ? ((activeStep + 1) / totalSteps) * 100 : 0;
60
+
61
+ return {
62
+ activeStep,
63
+ nextStep,
64
+ prevStep,
65
+ goToStep,
66
+ isFirst,
67
+ isLast,
68
+ progress,
69
+ setActiveStep,
70
+ };
71
+ }
@@ -0,0 +1,16 @@
1
+ "use client";
2
+
3
+ export { default as StepProgress } from "./StepProgress";
4
+ export { default as StepIndicator } from "./StepIndicator";
5
+ export { default as StepsNav } from "./StepsNav";
6
+ export { default as Steps } from "./Steps";
7
+ export { useHover, useStepNavigation } from "./hooks";
8
+ export type {
9
+ StepConfig,
10
+ StepThemeConfig,
11
+ StepVariant,
12
+ BaseStepProps,
13
+ } from "./types";
14
+
15
+ // Default export is the comprehensive Steps component
16
+ export { default } from "./Steps";