@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,89 @@
1
+ "use client";
2
+
3
+ import { Box } from "@/design-system/elements";
4
+ import { motion } from "motion/react";
5
+ import { type ReactNode, useState } from "react";
6
+
7
+ const BOUNCE_VARIANTS = {
8
+ idle: 0.5,
9
+ } as const;
10
+ // 'ease-in': [0.55, 0.055, 0.675, 0.19], // -- ease-in-cubic
11
+ // 'ease-out': [0.23, 1, 0.32, 1], // -- ease-out-quint
12
+ // 'ease-in-out': [0.785, 0.135, 0.15, 0.86], // -- ease-in-out-circ
13
+ const DEFAULT_BOUNCE = 0.5;
14
+
15
+ export type DynamicIslandView = string;
16
+
17
+ export interface DynamicIslandProps {
18
+ view?: DynamicIslandView;
19
+ onViewChange?: (view: DynamicIslandView) => void;
20
+ content?: ReactNode;
21
+ controlIcons?: Record<string, ReactNode>;
22
+ containerProps?: any;
23
+ }
24
+
25
+ export default function DynamicIsland({
26
+ view: controlledView,
27
+ content,
28
+ containerProps,
29
+ }: DynamicIslandProps) {
30
+ const [internalView] = useState<DynamicIslandView>("default");
31
+ const [variantKey] = useState<string>("default");
32
+
33
+ const view = controlledView ?? internalView;
34
+
35
+ return (
36
+ <Box
37
+ as={motion.div}
38
+ layout
39
+ skin="translucent.dark"
40
+ shape="pill"
41
+ minWidth={"6rem"}
42
+ m="0 auto"
43
+ overflow={"hidden"}
44
+ flex="none"
45
+ height={"fit-content"}
46
+ width={"fit-content"}
47
+ display="flex"
48
+ alignItems="center"
49
+ justifyContent={"center"}
50
+ gap="xxxs"
51
+ // style={{ pointerEvents: "initial" }}
52
+ {...containerProps}
53
+ transition={{
54
+ type: "spring",
55
+ bounce:
56
+ BOUNCE_VARIANTS[variantKey as keyof typeof BOUNCE_VARIANTS] ??
57
+ DEFAULT_BOUNCE,
58
+ }}
59
+ >
60
+ <Box
61
+ as={motion.div}
62
+ animate={{
63
+ scale: 1,
64
+ opacity: 1,
65
+ filter: "blur(0px)",
66
+ originX: 0.5,
67
+ originY: 0.5,
68
+ transition: { delay: 0.05 },
69
+ }}
70
+ initial={{
71
+ scale: 0.9,
72
+ opacity: 0,
73
+ filter: "blur(5px)",
74
+ originX: 0.5,
75
+ originY: 0.5,
76
+ }}
77
+ key={view}
78
+ transition={{
79
+ type: "spring",
80
+ bounce:
81
+ BOUNCE_VARIANTS[variantKey as keyof typeof BOUNCE_VARIANTS] ??
82
+ DEFAULT_BOUNCE,
83
+ }}
84
+ >
85
+ {content}
86
+ </Box>
87
+ </Box>
88
+ );
89
+ }
@@ -0,0 +1,2 @@
1
+ export { default as DynamicIsland } from "./DynamicIsland";
2
+ export type { DynamicIslandProps, DynamicIslandView } from "./DynamicIsland";
@@ -0,0 +1,145 @@
1
+ "use client"
2
+ import { motion, AnimatePresence } from "motion/react"
3
+ import Box, { BoxProps } from "@/design-system/elements/box"
4
+
5
+ import Image from "next/image"
6
+
7
+ const FADE_DIRECTION = "to bottom"
8
+
9
+ type FaderProps = BoxProps & {
10
+ image?: string | undefined | null
11
+ fade?: boolean
12
+ fadeColor?: string
13
+ fadeDirection?: string
14
+ imgStyle?: {}
15
+ overlay?: {
16
+ start: { color: string; stop: string }
17
+ end: { color: string; stop: string }
18
+ }
19
+ variants?: {}
20
+ }
21
+
22
+ const overlayOptions = {
23
+ start: {
24
+ color: "transparent",
25
+ stop: "0%",
26
+ },
27
+ end: {
28
+ color: "currentColor",
29
+ stop: "75%",
30
+ },
31
+ }
32
+
33
+ // const fixedStyle = {
34
+ // backgroundAttachment: "fixed",
35
+ // backgroundSize: "cover",
36
+ // };
37
+
38
+ // const defaultStyle = {
39
+ // backgroundSize: "cover",
40
+ // backgroundPosition: "center",
41
+ // };
42
+
43
+ const defaultVariants = {
44
+ enter: {
45
+ opacity: 0,
46
+ scale: 1.2,
47
+ y: 30,
48
+ x: 0,
49
+ filter: "blur(20px)",
50
+ transition: { duration: 0.4 },
51
+ },
52
+ center: {
53
+ opacity: 1,
54
+ scale: 1,
55
+ y: 0,
56
+ x: 0,
57
+ filter: "blur(0px)",
58
+ transition: { duration: 0.4 },
59
+ },
60
+ exit: {
61
+ opacity: 0,
62
+ scale: 1.04,
63
+ y: -30,
64
+ x: 0,
65
+ filter: "blur(20px)",
66
+ transition: { duration: 0.4 },
67
+ },
68
+ hover: {
69
+ opacity: 1,
70
+ scale: 1.04,
71
+ y: 0,
72
+ x: 0,
73
+ transition: { duration: 0.2 },
74
+ },
75
+ }
76
+
77
+ export default function Fader({
78
+ image,
79
+ fade = true,
80
+ fadeColor = "currentColor",
81
+ fadeDirection = FADE_DIRECTION,
82
+ //imgStyle = "fixed",
83
+ overlay = overlayOptions,
84
+ variants = defaultVariants,
85
+ ...props
86
+ }: FaderProps) {
87
+ return (
88
+ <Box
89
+ as={motion.div}
90
+ overflow="hidden"
91
+ position="relative"
92
+ width="100%"
93
+ height="100%"
94
+ {...props}
95
+ >
96
+ {/* Fade overlay */}
97
+ {fade ? (
98
+ <Box
99
+ as={motion.div}
100
+ position={"absolute"}
101
+ color={fadeColor}
102
+ width="100%"
103
+ height="100%"
104
+ top="0"
105
+ bottom="0"
106
+ left="0"
107
+ zIndex={3}
108
+ backgroundImage={`linear-gradient(${fadeDirection}, ${overlay.start.color} ${overlay.start.stop}, ${overlay.end.color} ${overlay.end.stop})`}
109
+ />
110
+ ) : null}
111
+
112
+ {/* Main image */}
113
+
114
+ {image && (
115
+ <AnimatePresence mode="wait">
116
+ <Box
117
+ as={motion.div}
118
+ variants={variants}
119
+ initial="enter"
120
+ animate="center"
121
+ exit="exit"
122
+ transition={{ duration: 2 }}
123
+ width="100%"
124
+ height="100%"
125
+ position="absolute"
126
+ maxWidth="100%"
127
+ top="0"
128
+ left="0"
129
+ zIndex={1}
130
+ >
131
+ <Image
132
+ src={image as string}
133
+ priority={true}
134
+ loading="eager"
135
+ fill
136
+ alt="image"
137
+ sizes="100%"
138
+ style={{ objectFit: "cover" }}
139
+ />
140
+ </Box>
141
+ </AnimatePresence>
142
+ )}
143
+ </Box>
144
+ )
145
+ }
@@ -0,0 +1,116 @@
1
+ # FamilyDrawer Component
2
+
3
+ A sophisticated drawer component with multiple animated views, perfect for wallet management interfaces or any multi-step configuration flow.
4
+
5
+ ## Features
6
+
7
+ - **Multi-view Navigation**: Seamlessly switch between different views (default, key, phrase, remove)
8
+ - **Smooth Animations**: Height-based animations with blur effects during transitions
9
+ - **Design System Integration**: Built using the existing Drawer component and design system elements
10
+ - **Customizable**: Custom trigger buttons, widths, and callbacks
11
+ - **Accessible**: Proper ARIA labels and keyboard navigation support
12
+
13
+ ## Usage
14
+
15
+ ### Basic Usage
16
+
17
+ ```tsx
18
+ import { FamilyDrawer } from "@/design-system/blocks";
19
+
20
+ function MyComponent() {
21
+ return (
22
+ <FamilyDrawer id="wallet-settings" />
23
+ );
24
+ }
25
+ ```
26
+
27
+ ### Advanced Usage
28
+
29
+ ```tsx
30
+ import { FamilyDrawer } from "@/design-system/blocks";
31
+ import { Button, Text } from "@/design-system/elements";
32
+
33
+ function MyComponent() {
34
+ const handleViewChange = (view) => {
35
+ console.log("Current view:", view);
36
+ };
37
+
38
+ return (
39
+ <FamilyDrawer
40
+ id="wallet-settings"
41
+ initialView="default"
42
+ width="400px"
43
+ onViewChange={handleViewChange}
44
+ trigger={
45
+ <Button variant="primary" $size="medium">
46
+ <Text>Custom Trigger</Text>
47
+ </Button>
48
+ }
49
+ />
50
+ );
51
+ }
52
+ ```
53
+
54
+ ## Props
55
+
56
+ | Prop | Type | Default | Description |
57
+ |------|------|---------|-------------|
58
+ | `id` | `string` | **Required** | Unique identifier for the drawer |
59
+ | `initialView` | `FamilyDrawerView` | `"default"` | Initial view to display |
60
+ | `trigger` | `React.ReactNode` | Default settings button | Custom trigger element |
61
+ | `onViewChange` | `(view: FamilyDrawerView) => void` | `undefined` | Callback when view changes |
62
+ | `width` | `string \| number \| object` | `"360px"` | Drawer width (responsive object supported) |
63
+
64
+ ## Views
65
+
66
+ The component includes four built-in views:
67
+
68
+ 1. **Default View** (`"default"`): Main options menu with navigation buttons
69
+ 2. **Key View** (`"key"`): Private key management with security warnings
70
+ 3. **Phrase View** (`"phrase"`): Recovery phrase management with security warnings
71
+ 4. **Remove View** (`"remove"`): Wallet removal confirmation with warnings
72
+
73
+ ## Customization
74
+
75
+ ### Custom Trigger
76
+
77
+ ```tsx
78
+ <FamilyDrawer
79
+ id="custom-drawer"
80
+ trigger={
81
+ <Button variant="ghost" $size="small">
82
+ <IconGear size="1rem" />
83
+ Options
84
+ </Button>
85
+ }
86
+ />
87
+ ```
88
+
89
+ ### Responsive Width
90
+
91
+ ```tsx
92
+ <FamilyDrawer
93
+ id="responsive-drawer"
94
+ width={{ _: "100%", md: "400px" }}
95
+ />
96
+ ```
97
+
98
+ ## Animation Details
99
+
100
+ - **Height Animation**: Smooth height transitions using Framer Motion
101
+ - **View Transitions**: Blur and scale effects during view changes
102
+ - **Timing**: 270ms duration with custom easing curves
103
+ - **Performance**: Uses `react-use-measure` for efficient dimension tracking
104
+
105
+ ## Dependencies
106
+
107
+ - `motion/react` (Framer Motion)
108
+ - `react-use-measure`
109
+ - Design system components (Box, Button, Text, Drawer)
110
+ - Icon components from the project's icon library
111
+
112
+ ## Related Components
113
+
114
+ - [Drawer](../Drawer/README.md) - Base drawer component
115
+ - [Modal](../Modal/README.md) - Alternative overlay component
116
+ - [Popover](../Popover/README.md) - Lightweight overlay component
@@ -0,0 +1,108 @@
1
+ "use client";
2
+
3
+ import React from "react";
4
+ import { Box, Text, Button } from "@/design-system/elements";
5
+ import { Container } from "@/design-system/blocks";
6
+ import FamilyDrawer from "./index";
7
+
8
+ /**
9
+ * Example usage of the FamilyDrawer component
10
+ *
11
+ * This demonstrates how to use the FamilyDrawer with:
12
+ * - Default trigger button
13
+ * - Custom trigger button
14
+ * - View change callback
15
+ * - Custom width
16
+ */
17
+ export const FamilyDrawerExample: React.FC = () => {
18
+ const handleViewChange = (view: string) => {
19
+ console.log("View changed to:", view);
20
+ };
21
+
22
+ return (
23
+ <Container maxWidth="800px" p="large">
24
+ <Box display="flex" flexDirection="column" gap="large">
25
+ <Box>
26
+ <Text as="h1" fontSize="xxlarge" fontWeight="bold" mb="medium">
27
+ FamilyDrawer Examples
28
+ </Text>
29
+ <Text fontSize="medium" color="secondary" lineHeight="relaxed">
30
+ Interactive drawer component with multiple views for wallet management.
31
+ </Text>
32
+ </Box>
33
+
34
+ <Box
35
+ display="flex"
36
+ flexDirection="column"
37
+ gap="large"
38
+ p="large"
39
+ skin="card"
40
+ shape="rounded"
41
+ >
42
+ <Box>
43
+ <Text as="h2" fontSize="large" fontWeight="semibold" mb="small">
44
+ Default Usage
45
+ </Text>
46
+ <Text fontSize="small" color="secondary" mb="medium">
47
+ Basic FamilyDrawer with default settings and trigger button.
48
+ </Text>
49
+ <FamilyDrawer id="example-1" />
50
+ </Box>
51
+
52
+ <Box>
53
+ <Text as="h2" fontSize="large" fontWeight="semibold" mb="small">
54
+ Custom Trigger
55
+ </Text>
56
+ <Text fontSize="small" color="secondary" mb="medium">
57
+ FamilyDrawer with a custom trigger button.
58
+ </Text>
59
+ <FamilyDrawer
60
+ id="example-2"
61
+ trigger={
62
+ <Button variant="primary" $size="small">
63
+ <Text fontSize="small" fontWeight="semibold">
64
+ Wallet Options
65
+ </Text>
66
+ </Button>
67
+ }
68
+ />
69
+ </Box>
70
+
71
+ <Box>
72
+ <Text as="h2" fontSize="large" fontWeight="semibold" mb="small">
73
+ With Callbacks
74
+ </Text>
75
+ <Text fontSize="small" color="secondary" mb="medium">
76
+ FamilyDrawer with view change callback and custom width.
77
+ </Text>
78
+ <FamilyDrawer
79
+ id="example-3"
80
+ onViewChange={handleViewChange}
81
+ width="400px"
82
+ initialView="default"
83
+ />
84
+ </Box>
85
+ </Box>
86
+
87
+ <Box
88
+ p="medium"
89
+ skin="translucent"
90
+ shape="rounded"
91
+ borderLeft="4px solid"
92
+ borderColor="primary"
93
+ >
94
+ <Text fontSize="small" fontWeight="semibold" color="primary" mb="xsmall">
95
+ Usage Notes
96
+ </Text>
97
+ <Text fontSize="small" color="secondary" lineHeight="relaxed">
98
+ Each FamilyDrawer instance requires a unique <code>id</code> prop for proper state management.
99
+ The drawer uses the existing Drawer component from the design system with smooth animations
100
+ between different views.
101
+ </Text>
102
+ </Box>
103
+ </Box>
104
+ </Container>
105
+ );
106
+ };
107
+
108
+ export default FamilyDrawerExample;
@@ -0,0 +1,119 @@
1
+ "use client";
2
+
3
+ import React, { useState, useMemo } from "react";
4
+ import { Box, Button, Text } from "@/design-system/elements";
5
+ import { Drawer, DrawerButton } from "@/design-system/blocks/Drawer";
6
+ import { AnimatePresence, motion } from "motion/react";
7
+ import { IconGear } from "@/design-system/icons";
8
+ import useMeasure from "react-use-measure";
9
+
10
+ import { DefaultView } from "./views/DefaultView";
11
+ import { KeyView } from "./views/KeyView";
12
+ import { PhraseView } from "./views/PhraseView";
13
+ import { RemoveView } from "./views/RemoveView";
14
+
15
+ export type FamilyDrawerView = "default" | "key" | "phrase" | "remove";
16
+
17
+ interface FamilyDrawerProps {
18
+ /** Unique identifier for the drawer */
19
+ id: string;
20
+ /** Initial view to display */
21
+ initialView?: FamilyDrawerView;
22
+ /** Custom trigger button */
23
+ trigger?: React.ReactNode;
24
+ /** Callback when view changes */
25
+ onViewChange?: (view: FamilyDrawerView) => void;
26
+ /** Custom drawer width */
27
+ width?: string | number | object;
28
+ }
29
+
30
+ export const FamilyDrawer: React.FC<FamilyDrawerProps> = ({
31
+ id,
32
+ initialView = "default",
33
+ trigger,
34
+ onViewChange,
35
+ width = "360px",
36
+ }) => {
37
+ const [view, setView] = useState<FamilyDrawerView>(initialView);
38
+ const [elementRef, bounds] = useMeasure();
39
+
40
+ const handleViewChange = (newView: FamilyDrawerView) => {
41
+ setView(newView);
42
+ onViewChange?.(newView);
43
+ };
44
+
45
+ const content = useMemo(() => {
46
+ const commonProps = { setView: handleViewChange };
47
+
48
+ switch (view) {
49
+ case "default":
50
+ return <DefaultView {...commonProps} />;
51
+ case "phrase":
52
+ return <PhraseView {...commonProps} />;
53
+ case "key":
54
+ return <KeyView {...commonProps} />;
55
+ case "remove":
56
+ return <RemoveView {...commonProps} />;
57
+ default:
58
+ return <DefaultView {...commonProps} />;
59
+ }
60
+ }, [view]);
61
+
62
+ const defaultTrigger = (
63
+ <Button
64
+ variant="ghost"
65
+ $size="medium"
66
+ display="flex"
67
+ alignItems="center"
68
+ gap="small"
69
+ shape="rounded"
70
+ skin="translucent"
71
+ >
72
+ <Text fontSize="medium" fontWeight="semibold">
73
+ Settings
74
+ </Text>
75
+ <Box as={IconGear} size="1.25rem" />
76
+ </Button>
77
+ );
78
+
79
+ return (
80
+ <>
81
+ <DrawerButton drawerId={id} label="">
82
+ {trigger || defaultTrigger}
83
+ </DrawerButton>
84
+
85
+ <Drawer id={id} title="Options" width={width}>
86
+ <Box
87
+ as={motion.div}
88
+ animate={{ height: bounds.height || "auto" }}
89
+ transition={{
90
+ type: "tween",
91
+ ease: [0.26, 1, 0.5, 1],
92
+ duration: 0.27,
93
+ }}
94
+ overflow="hidden"
95
+ >
96
+ <Box ref={elementRef} p="medium">
97
+ <AnimatePresence mode="wait" initial={false}>
98
+ <Box
99
+ as={motion.div}
100
+ key={view}
101
+ initial={{ opacity: 0, scale: 0.96, filter: "blur(2px)" }}
102
+ animate={{ opacity: 1, scale: 1, filter: "blur(0px)" }}
103
+ exit={{ opacity: 0, scale: 0.96, filter: "blur(2px)" }}
104
+ transition={{
105
+ duration: 0.27,
106
+ ease: [0.26, 0.08, 0.25, 1],
107
+ }}
108
+ >
109
+ {content}
110
+ </Box>
111
+ </AnimatePresence>
112
+ </Box>
113
+ </Box>
114
+ </Drawer>
115
+ </>
116
+ );
117
+ };
118
+
119
+ export default FamilyDrawer;
@@ -0,0 +1,93 @@
1
+ "use client";
2
+
3
+ import React from "react";
4
+ import { Box, Button, Text } from "@/design-system/elements";
5
+ import { IconLock, IconOWarning, IconText } from "@/design-system/icons";
6
+ import { FamilyDrawerView } from "../index";
7
+
8
+ interface DefaultViewProps {
9
+ setView: (view: FamilyDrawerView) => void;
10
+ }
11
+
12
+ export const DefaultView: React.FC<DefaultViewProps> = ({ setView }) => {
13
+ return (
14
+ <Box>
15
+ <Box
16
+ display="flex"
17
+ alignItems="center"
18
+ justifyContent="space-between"
19
+ borderBottom="1px solid"
20
+ borderColor="base"
21
+ pb="medium"
22
+ mb="medium"
23
+ >
24
+ <Text fontSize="large" fontWeight="semibold" color="primary">
25
+ Options
26
+ </Text>
27
+ </Box>
28
+
29
+ <Box display="flex" flexDirection="column" gap="small">
30
+ <OptionButton
31
+ title="View Private Key"
32
+ icon={<Box as={IconLock} size="1.25rem" />}
33
+ onClick={() => setView("key")}
34
+ />
35
+ <OptionButton
36
+ title="View Recovery Phrase"
37
+ icon={<Box as={IconText} size="1.25rem" />}
38
+ onClick={() => setView("phrase")}
39
+ />
40
+ <OptionButton
41
+ title="Remove Wallet"
42
+ icon={<Box as={IconOWarning} size="1.25rem" />}
43
+ onClick={() => setView("remove")}
44
+ isDestructive
45
+ />
46
+ </Box>
47
+ </Box>
48
+ );
49
+ };
50
+
51
+ interface OptionButtonProps {
52
+ title: string;
53
+ icon: React.ReactNode;
54
+ onClick: () => void;
55
+ isDestructive?: boolean;
56
+ }
57
+
58
+ const OptionButton: React.FC<OptionButtonProps> = ({
59
+ title,
60
+ icon,
61
+ onClick,
62
+ isDestructive = false,
63
+ }) => {
64
+ return (
65
+ <Button
66
+ variant="ghost"
67
+ $size="large"
68
+ onClick={onClick}
69
+ display="flex"
70
+ alignItems="center"
71
+ justifyContent="flex-start"
72
+ gap="medium"
73
+ p="medium"
74
+ shape="rounded"
75
+ skin={isDestructive ? "danger" : "translucent"}
76
+ color={isDestructive ? "danger" : "secondary"}
77
+ hover={isDestructive ? "danger" : "subtle"}
78
+ interactive={{
79
+ hover: {
80
+ color: isDestructive ? "danger" : "primary",
81
+ }
82
+ }}
83
+ width="100%"
84
+ >
85
+ <Box color={isDestructive ? "danger" : "secondary"}>
86
+ {icon}
87
+ </Box>
88
+ <Text fontSize="medium" fontWeight="medium">
89
+ {title}
90
+ </Text>
91
+ </Button>
92
+ );
93
+ };