@saas-ui/react 2.11.2 → 3.0.0-alpha.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (232) hide show
  1. package/CHANGELOG.md +7 -154
  2. package/dist/index.cjs +8461 -0
  3. package/dist/index.cjs.map +1 -0
  4. package/dist/index.d.cts +26 -0
  5. package/dist/index.d.ts +25 -7
  6. package/dist/index.js +8415 -35
  7. package/dist/index.js.map +1 -1
  8. package/package.json +24 -21
  9. package/src/components/accordion.tsx +47 -0
  10. package/src/components/action-bar.tsx +40 -0
  11. package/src/components/alert.tsx +51 -0
  12. package/src/components/app-shell/app-shell.recipe.ts +52 -0
  13. package/src/components/app-shell/app-shell.stories.tsx +51 -0
  14. package/src/components/app-shell/app-shell.tsx +94 -0
  15. package/src/components/app-shell/index.ts +3 -0
  16. package/src/components/avatar.tsx +74 -0
  17. package/src/components/blockquote.tsx +31 -0
  18. package/src/components/breadcrumbs/breadcrumb.stories.tsx +17 -0
  19. package/src/components/breadcrumbs/breadcrumb.tsx +36 -0
  20. package/src/components/breadcrumbs/index.ts +1 -0
  21. package/src/components/breadcrumbs/namespace.ts +8 -0
  22. package/src/components/button/button.recipe.ts +182 -0
  23. package/src/components/button/button.stories.tsx +99 -0
  24. package/src/components/button/button.tsx +55 -0
  25. package/src/components/button/index.ts +2 -0
  26. package/src/components/checkbox/checkbox.tsx +26 -0
  27. package/src/components/checkbox/index.ts +2 -0
  28. package/src/components/checkbox-card.tsx +57 -0
  29. package/src/components/checkbox.tsx +25 -0
  30. package/src/components/clipboard.tsx +107 -0
  31. package/src/components/close-button/close-button.stories.tsx +12 -0
  32. package/src/components/close-button/close-button.tsx +18 -0
  33. package/src/components/close-button/index.ts +2 -0
  34. package/src/components/color-mode.tsx +65 -0
  35. package/src/components/command/command.recipe.ts +17 -0
  36. package/src/components/command/command.stories.tsx +47 -0
  37. package/src/components/command/command.tsx +50 -0
  38. package/src/components/command/index.ts +1 -0
  39. package/src/components/data-list.tsx +37 -0
  40. package/src/components/dialog/dialog.tsx +66 -0
  41. package/src/components/dialog/index.ts +1 -0
  42. package/src/components/dialog/namespace.ts +18 -0
  43. package/src/components/drawer/drawer.tsx +56 -0
  44. package/src/components/drawer/index.ts +3 -0
  45. package/src/components/drawer/namespace.ts +19 -0
  46. package/src/components/empty-state.tsx +34 -0
  47. package/src/components/field.tsx +33 -0
  48. package/src/components/file-button.tsx +166 -0
  49. package/src/components/grid-list/grid-list.recipe.ts +113 -0
  50. package/src/components/hover-card.tsx +35 -0
  51. package/src/components/icon-badge/icon-badge.recipe.ts +57 -0
  52. package/src/components/icon-badge/icon-badge.stories.tsx +38 -0
  53. package/src/components/icon-badge/icon-badge.tsx +59 -0
  54. package/src/components/icon-badge/index.ts +2 -0
  55. package/src/components/icons/create-icon.tsx +41 -0
  56. package/src/components/icons/icons.tsx +121 -0
  57. package/src/components/icons/index.ts +1 -0
  58. package/src/components/input-group/index.ts +1 -0
  59. package/src/components/input-group/input-group.tsx +46 -0
  60. package/src/components/link/index.ts +2 -0
  61. package/src/components/link/link.stories.tsx +17 -0
  62. package/src/components/link/link.test.tsx +33 -0
  63. package/src/components/link/link.tsx +27 -0
  64. package/src/components/link-button.tsx +12 -0
  65. package/src/components/loading-overlay/index.ts +1 -0
  66. package/src/components/loading-overlay/loading-overlay.recipe.ts +61 -0
  67. package/src/components/loading-overlay/loading-overlay.stories.tsx +68 -0
  68. package/src/components/loading-overlay/loading-overlay.tsx +54 -0
  69. package/src/components/loading-overlay/namespace.ts +7 -0
  70. package/src/components/menu.tsx +108 -0
  71. package/src/components/native-select.tsx +57 -0
  72. package/src/components/navbar/index.ts +1 -0
  73. package/src/components/navbar/namespace.ts +9 -0
  74. package/src/components/navbar/navbar.recipe.ts +109 -0
  75. package/src/components/navbar/navbar.stories.tsx +435 -0
  76. package/src/components/navbar/navbar.test.tsx +49 -0
  77. package/src/components/navbar/navbar.tsx +39 -0
  78. package/src/components/number-input/index.ts +2 -0
  79. package/src/components/number-input/number-input.tsx +41 -0
  80. package/src/components/pagination.tsx +207 -0
  81. package/src/components/password-input/index.ts +2 -0
  82. package/src/components/password-input/password-input.tsx +98 -0
  83. package/src/components/persona/index.ts +2 -0
  84. package/src/components/persona/namespace.ts +18 -0
  85. package/src/components/persona/persona-primitive.tsx +220 -0
  86. package/src/components/persona/persona.recipe.ts +94 -0
  87. package/src/components/persona/persona.stories.tsx +101 -0
  88. package/src/components/persona/persona.tsx +143 -0
  89. package/src/components/pin-input/index.ts +2 -0
  90. package/src/components/pin-input/pin-input.tsx +36 -0
  91. package/src/components/popover.tsx +58 -0
  92. package/src/components/progress-circle.tsx +37 -0
  93. package/src/components/progress.tsx +40 -0
  94. package/src/components/prose.tsx +264 -0
  95. package/src/components/provider.tsx +12 -0
  96. package/src/components/radio/index.ts +2 -0
  97. package/src/components/radio/radio.tsx +27 -0
  98. package/src/components/radio-card.tsx +57 -0
  99. package/src/components/radio.tsx +24 -0
  100. package/src/components/rating.tsx +27 -0
  101. package/src/components/search-input/index.ts +2 -0
  102. package/src/components/search-input/search-input.stories.tsx +63 -0
  103. package/src/components/search-input/search-input.tsx +134 -0
  104. package/src/components/segmented-control.tsx +47 -0
  105. package/src/components/select/index.ts +1 -0
  106. package/src/components/select/namespace.ts +18 -0
  107. package/src/components/select/select.tsx +135 -0
  108. package/src/components/sidebar/index.ts +7 -0
  109. package/src/components/sidebar/namespace.ts +27 -0
  110. package/src/components/sidebar/sidebar-item.recipe.ts +65 -0
  111. package/src/components/sidebar/sidebar.recipe.ts +237 -0
  112. package/src/components/sidebar/sidebar.stories.tsx +903 -0
  113. package/src/components/sidebar/sidebar.tsx +204 -0
  114. package/src/components/skeleton.tsx +44 -0
  115. package/src/components/slider.tsx +53 -0
  116. package/src/components/spinner/index.ts +2 -0
  117. package/src/components/spinner/spinner.stories.tsx +19 -0
  118. package/src/components/spinner/spinner.tsx +21 -0
  119. package/src/components/stat.tsx +75 -0
  120. package/src/components/status.tsx +29 -0
  121. package/src/components/stepper-input.tsx +49 -0
  122. package/src/components/steps/index.ts +1 -0
  123. package/src/components/steps/namespace.ts +16 -0
  124. package/src/components/steps/steps.tsx +82 -0
  125. package/src/components/switch/index.ts +3 -0
  126. package/src/components/switch/switch.tsx +39 -0
  127. package/src/components/tag.tsx +39 -0
  128. package/src/components/timeline.tsx +17 -0
  129. package/src/components/toaster.tsx +43 -0
  130. package/src/components/toggle-tip.tsx +62 -0
  131. package/src/components/tooltip.tsx +46 -0
  132. package/src/index.ts +6 -7
  133. package/src/preset.ts +9 -0
  134. package/src/provider/index.ts +4 -0
  135. package/src/provider/sui-provider.tsx +34 -0
  136. package/src/provider/use-link.test.tsx +60 -0
  137. package/src/provider/use-link.tsx +13 -0
  138. package/src/theme/animation-styles.ts +53 -0
  139. package/src/theme/breakpoints.ts +11 -0
  140. package/src/theme/conditions.ts +26 -0
  141. package/src/theme/fluid-font-sizes.ts +65 -0
  142. package/src/theme/global-css.ts +94 -0
  143. package/src/theme/index.ts +72 -0
  144. package/src/theme/layer-styles.ts +116 -0
  145. package/src/theme/recipes/chakra/accordion.ts +145 -0
  146. package/src/theme/recipes/chakra/action-bar.ts +62 -0
  147. package/src/theme/recipes/chakra/alert.ts +157 -0
  148. package/src/theme/recipes/chakra/avatar.ts +141 -0
  149. package/src/theme/recipes/chakra/badge.ts +67 -0
  150. package/src/theme/recipes/chakra/blockquote.ts +83 -0
  151. package/src/theme/recipes/chakra/breadcrumb.ts +94 -0
  152. package/src/theme/recipes/chakra/card.ts +99 -0
  153. package/src/theme/recipes/chakra/checkbox-card.ts +212 -0
  154. package/src/theme/recipes/chakra/checkbox.ts +70 -0
  155. package/src/theme/recipes/chakra/checkmark.ts +83 -0
  156. package/src/theme/recipes/chakra/code.ts +17 -0
  157. package/src/theme/recipes/chakra/collapsible.ts +20 -0
  158. package/src/theme/recipes/chakra/container.ts +26 -0
  159. package/src/theme/recipes/chakra/data-list.ts +80 -0
  160. package/src/theme/recipes/chakra/dialog.ts +225 -0
  161. package/src/theme/recipes/chakra/drawer.ts +201 -0
  162. package/src/theme/recipes/chakra/editable.ts +88 -0
  163. package/src/theme/recipes/chakra/empty-state.ts +88 -0
  164. package/src/theme/recipes/chakra/field.ts +68 -0
  165. package/src/theme/recipes/chakra/fieldset.ts +62 -0
  166. package/src/theme/recipes/chakra/file-upload.ts +96 -0
  167. package/src/theme/recipes/chakra/heading.ts +27 -0
  168. package/src/theme/recipes/chakra/hover-card.ts +68 -0
  169. package/src/theme/recipes/chakra/icon.ts +30 -0
  170. package/src/theme/recipes/chakra/input-addon.ts +40 -0
  171. package/src/theme/recipes/chakra/input.ts +96 -0
  172. package/src/theme/recipes/chakra/kbd.ts +60 -0
  173. package/src/theme/recipes/chakra/link.ts +37 -0
  174. package/src/theme/recipes/chakra/list.ts +67 -0
  175. package/src/theme/recipes/chakra/mark.ts +27 -0
  176. package/src/theme/recipes/chakra/menu.ts +124 -0
  177. package/src/theme/recipes/chakra/native-select.ts +140 -0
  178. package/src/theme/recipes/chakra/number-input.ts +115 -0
  179. package/src/theme/recipes/chakra/pin-input.ts +27 -0
  180. package/src/theme/recipes/chakra/popover.ts +86 -0
  181. package/src/theme/recipes/chakra/progress-circle.ts +94 -0
  182. package/src/theme/recipes/chakra/progress.ts +127 -0
  183. package/src/theme/recipes/chakra/radio-card.ts +220 -0
  184. package/src/theme/recipes/chakra/radio-group.ts +72 -0
  185. package/src/theme/recipes/chakra/radiomark.ts +107 -0
  186. package/src/theme/recipes/chakra/rating-group.ts +94 -0
  187. package/src/theme/recipes/chakra/segment-group.ts +117 -0
  188. package/src/theme/recipes/chakra/select.ts +282 -0
  189. package/src/theme/recipes/chakra/separator.ts +51 -0
  190. package/src/theme/recipes/chakra/skeleton.ts +53 -0
  191. package/src/theme/recipes/chakra/skip-nav-link.ts +34 -0
  192. package/src/theme/recipes/chakra/slider.ts +178 -0
  193. package/src/theme/recipes/chakra/spinner.ts +32 -0
  194. package/src/theme/recipes/chakra/stat.ts +79 -0
  195. package/src/theme/recipes/chakra/status.ts +48 -0
  196. package/src/theme/recipes/chakra/steps.ts +218 -0
  197. package/src/theme/recipes/chakra/switch.ts +167 -0
  198. package/src/theme/recipes/chakra/table.ts +172 -0
  199. package/src/theme/recipes/chakra/tabs.ts +280 -0
  200. package/src/theme/recipes/chakra/tag.ts +131 -0
  201. package/src/theme/recipes/chakra/textarea.ts +88 -0
  202. package/src/theme/recipes/chakra/timeline.ts +138 -0
  203. package/src/theme/recipes/chakra/toast.ts +96 -0
  204. package/src/theme/recipes/chakra/tooltip.ts +40 -0
  205. package/src/theme/recipes.ts +46 -0
  206. package/src/theme/semantic-tokens/colors.ts +403 -0
  207. package/src/theme/semantic-tokens/radii.ts +7 -0
  208. package/src/theme/semantic-tokens/shadows.ts +52 -0
  209. package/src/theme/slot-recipes.ts +104 -0
  210. package/src/theme/text-styles.ts +39 -0
  211. package/src/theme/tokens/animations.ts +8 -0
  212. package/src/theme/tokens/aspect-ratios.ts +10 -0
  213. package/src/theme/tokens/blurs.ts +12 -0
  214. package/src/theme/tokens/borders.ts +9 -0
  215. package/src/theme/tokens/colors.ts +177 -0
  216. package/src/theme/tokens/cursor.ts +12 -0
  217. package/src/theme/tokens/durations.ts +11 -0
  218. package/src/theme/tokens/easings.ts +10 -0
  219. package/src/theme/tokens/font-sizes.ts +20 -0
  220. package/src/theme/tokens/font-weights.ts +13 -0
  221. package/src/theme/tokens/fonts.ts +15 -0
  222. package/src/theme/tokens/keyframes.ts +173 -0
  223. package/src/theme/tokens/letter-spacing.ts +9 -0
  224. package/src/theme/tokens/line-heights.ts +19 -0
  225. package/src/theme/tokens/radius.ts +18 -0
  226. package/src/theme/tokens/sizes.ts +71 -0
  227. package/src/theme/tokens/spacing.ts +38 -0
  228. package/src/theme/tokens/z-indices.ts +34 -0
  229. package/src/theme/utils.ts +46 -0
  230. package/dist/index.d.mts +0 -8
  231. package/dist/index.mjs +0 -11
  232. package/dist/index.mjs.map +0 -1
@@ -0,0 +1,204 @@
1
+ import React, { type HTMLProps } from 'react'
2
+
3
+ import {
4
+ type HTMLChakraProps,
5
+ type SlotRecipeProps,
6
+ createSlotRecipeContext,
7
+ } from '@chakra-ui/react'
8
+ import { Sidebar, useSidebar } from '@saas-ui/core/sidebar'
9
+
10
+ const {
11
+ withContext,
12
+ useRecipeResult,
13
+ StylesProvider,
14
+ ClassNamesProvider,
15
+ useStyles: useSidebarStyles,
16
+ } = createSlotRecipeContext({
17
+ key: 'sidebar',
18
+ })
19
+
20
+ export { useSidebar, useSidebarStyles }
21
+
22
+ export interface SidebarProviderProps
23
+ extends Sidebar.ProviderProps,
24
+ SlotRecipeProps<'sidebar'> {}
25
+
26
+ export const SidebarProvider = function SidebarProvider(
27
+ props: SidebarProviderProps,
28
+ ) {
29
+ return (
30
+ <Sidebar.Provider {...props}>
31
+ <RecipeProvider {...props}>{props.children}</RecipeProvider>
32
+ </Sidebar.Provider>
33
+ )
34
+ }
35
+
36
+ function RecipeProvider(
37
+ props: SlotRecipeProps<'sidebar'> & { children: React.ReactNode },
38
+ ) {
39
+ const { mode } = useSidebar()
40
+
41
+ const { styles, classNames } = useRecipeResult({
42
+ ...props,
43
+ mode,
44
+ })
45
+
46
+ return (
47
+ <StylesProvider value={styles}>
48
+ <ClassNamesProvider value={classNames}>
49
+ {props.children}
50
+ </ClassNamesProvider>
51
+ </StylesProvider>
52
+ )
53
+ }
54
+
55
+ export interface SidebarRootProps
56
+ extends Sidebar.RootProps,
57
+ HTMLChakraProps<'div'> {}
58
+
59
+ /**
60
+ * Side navigation, commonly used as the primary navigation
61
+ *
62
+ * @see Docs https://saas-ui.dev/docs/components/layout/sidebar
63
+ */
64
+ export const SidebarRoot = withContext<HTMLDivElement, SidebarRootProps>(
65
+ Sidebar.Root,
66
+ 'root',
67
+ )
68
+
69
+ export interface SidebarTriggerProps extends HTMLChakraProps<'button'> {}
70
+
71
+ /**
72
+ * Button that toggles the sidebar visibility.
73
+ *
74
+ * @see Docs https://saas-ui.dev/docs/components/layout/sidebar
75
+ */
76
+ export const SidebarTrigger = withContext<
77
+ HTMLButtonElement,
78
+ SidebarTriggerProps
79
+ >(Sidebar.Trigger, 'trigger', {
80
+ forwardAsChild: true,
81
+ })
82
+
83
+ export interface SidebarFlyoutTriggerProps extends HTMLChakraProps<'button'> {}
84
+
85
+ /**
86
+ * Opens the sidebar when hovering over the trigger.
87
+ *
88
+ * @see Docs https://saas-ui.dev/docs/components/layout/sidebar
89
+ */
90
+ export const SidebarFlyoutTrigger = withContext<
91
+ HTMLButtonElement,
92
+ SidebarFlyoutTriggerProps
93
+ >(Sidebar.FlyoutTrigger, 'flyoutTrigger', {
94
+ forwardAsChild: true,
95
+ })
96
+
97
+ /**
98
+ * Overlay shown when sidebar is open on mobile.
99
+ *
100
+ * @see Docs https://saas-ui.dev/docs/components/layout/sidebar
101
+ */
102
+ export const SidebarBackdrop = withContext<
103
+ HTMLDivElement,
104
+ HTMLChakraProps<'div'>
105
+ >(Sidebar.Backdrop, 'backdrop', {
106
+ forwardAsChild: true,
107
+ })
108
+
109
+ /**
110
+ * Sidebar header section.
111
+ *
112
+ * @see Docs https://saas-ui.dev/docs/components/layout/sidebar
113
+ */
114
+ export const SidebarHeader = withContext<
115
+ HTMLDivElement,
116
+ HTMLChakraProps<'div'>
117
+ >(Sidebar.Header, 'header')
118
+
119
+ /**
120
+ * Sidebar body section, used for the main content of the sidebar.
121
+ *
122
+ * @see Docs https://saas-ui.dev/docs/components/layout/sidebar
123
+ */
124
+ export const SidebarBody = withContext<HTMLDivElement, HTMLChakraProps<'div'>>(
125
+ Sidebar.Body,
126
+ 'body',
127
+ )
128
+
129
+ /**
130
+ * Sidebar footer section.
131
+ *
132
+ * @see Docs https://saas-ui.dev/docs/components/layout/sidebar
133
+ */
134
+ export const SidebarFooter = withContext<
135
+ HTMLDivElement,
136
+ HTMLChakraProps<'div'>
137
+ >(Sidebar.Footer, 'footer')
138
+
139
+ /**
140
+ * Sidebar track section.
141
+ *
142
+ * @see Docs https://saas-ui.dev/docs/components/layout/sidebar
143
+ */
144
+ export const SidebarTrack = withContext(Sidebar.Track, 'track', {
145
+ forwardAsChild: true,
146
+ })
147
+
148
+ export const SidebarGroup = withContext<HTMLDivElement, HTMLChakraProps<'div'>>(
149
+ Sidebar.Group,
150
+ 'group',
151
+ {
152
+ defaultProps: {
153
+ role: 'group',
154
+ },
155
+ },
156
+ )
157
+
158
+ export const SidebarGroupHeader = withContext<
159
+ HTMLDivElement,
160
+ HTMLChakraProps<'div'>
161
+ >(Sidebar.GroupHeader, 'groupHeader')
162
+
163
+ export const SidebarGroupTitle = withContext<
164
+ HTMLHeadingElement,
165
+ HTMLChakraProps<'h5'>
166
+ >(Sidebar.GroupTitle, 'groupTitle')
167
+
168
+ export const SidebarGroupEndElement = withContext<
169
+ HTMLDivElement,
170
+ HTMLChakraProps<'div'>
171
+ >(Sidebar.GroupEndElement, 'groupEndElement')
172
+
173
+ export const SidebarGroupContent = withContext<
174
+ HTMLDivElement,
175
+ HTMLChakraProps<'div'>
176
+ >(Sidebar.GroupContent, 'groupContent')
177
+
178
+ const {
179
+ withProvider: withItemProvider,
180
+ withContext: withItemContext,
181
+ useStyles: useSidebarItemStyles,
182
+ } = createSlotRecipeContext({
183
+ key: 'sidebarNavItem',
184
+ })
185
+
186
+ export { useSidebarItemStyles }
187
+
188
+ export const SidebarNavItem = withItemProvider(Sidebar.NavItem, 'item')
189
+
190
+ export interface SidebarNavButtonProps extends HTMLProps<'button'> {
191
+ active?: boolean
192
+ }
193
+
194
+ export const SidebarNavButton = withItemContext<
195
+ HTMLButtonElement,
196
+ Sidebar.NavButtonProps
197
+ >(Sidebar.NavButton, 'button', {
198
+ forwardAsChild: true,
199
+ })
200
+
201
+ export const SidebarNavItemEndElement = withItemContext<
202
+ HTMLDivElement,
203
+ HTMLChakraProps<'div'>
204
+ >(Sidebar.NavItemEndElement, 'endElement')
@@ -0,0 +1,44 @@
1
+ import type {
2
+ SkeletonProps as ChakraSkeletonProps,
3
+ CircleProps,
4
+ } from "@chakra-ui/react"
5
+ import { Skeleton as ChakraSkeleton, Circle, Stack } from "@chakra-ui/react"
6
+ import { forwardRef } from "react"
7
+
8
+ export interface SkeletonCircleProps extends ChakraSkeletonProps {
9
+ size?: CircleProps["size"]
10
+ }
11
+
12
+ export const SkeletonCircle = (props: SkeletonCircleProps) => {
13
+ const { size, ...rest } = props
14
+ return (
15
+ <Circle size={size} asChild>
16
+ <ChakraSkeleton {...rest} />
17
+ </Circle>
18
+ )
19
+ }
20
+
21
+ export interface SkeletonTextProps extends ChakraSkeletonProps {
22
+ noOfLines?: number
23
+ }
24
+
25
+ export const SkeletonText = forwardRef<HTMLDivElement, SkeletonTextProps>(
26
+ function SkeletonText(props, ref) {
27
+ const { noOfLines = 3, gap, ...rest } = props
28
+ return (
29
+ <Stack gap={gap} width="full" ref={ref}>
30
+ {Array.from({ length: noOfLines }).map((_, index) => (
31
+ <ChakraSkeleton
32
+ height="4"
33
+ key={index}
34
+ {...props}
35
+ _last={{ maxW: "80%" }}
36
+ {...rest}
37
+ />
38
+ ))}
39
+ </Stack>
40
+ )
41
+ },
42
+ )
43
+
44
+ export const Skeleton = ChakraSkeleton
@@ -0,0 +1,53 @@
1
+ import { Slider as ChakraSlider } from "@chakra-ui/react"
2
+ import { forwardRef } from "react"
3
+
4
+ export interface SliderProps extends ChakraSlider.RootProps {
5
+ marks?: Array<number | { value: number; label: React.ReactNode }>
6
+ label?: React.ReactNode
7
+ }
8
+
9
+ export const Slider = forwardRef<HTMLDivElement, SliderProps>(
10
+ function Slider(props, ref) {
11
+ const { marks: marksProp, label, ...rest } = props
12
+ const value = props.defaultValue ?? props.value
13
+
14
+ const marks = marksProp?.map((mark) => {
15
+ if (typeof mark === "number") return { value: mark, label: undefined }
16
+ return mark
17
+ })
18
+
19
+ const hasMarkLabel = !!marks?.some((mark) => mark.label)
20
+
21
+ return (
22
+ <ChakraSlider.Root ref={ref} thumbAlignment="center" {...rest}>
23
+ {label && (
24
+ <ChakraSlider.Label fontWeight="medium">{label}</ChakraSlider.Label>
25
+ )}
26
+ <ChakraSlider.Control mb={hasMarkLabel ? "4" : undefined}>
27
+ <ChakraSlider.Track>
28
+ <ChakraSlider.Range />
29
+ </ChakraSlider.Track>
30
+ {value?.map((_, index) => (
31
+ <ChakraSlider.Thumb key={index} index={index}>
32
+ <ChakraSlider.HiddenInput />
33
+ </ChakraSlider.Thumb>
34
+ ))}
35
+ </ChakraSlider.Control>
36
+ {marks?.length && (
37
+ <ChakraSlider.MarkerGroup>
38
+ {marks.map((mark, index) => {
39
+ const value = typeof mark === "number" ? mark : mark.value
40
+ const label = typeof mark === "number" ? undefined : mark.label
41
+ return (
42
+ <ChakraSlider.Marker key={index} value={value}>
43
+ <ChakraSlider.MarkerIndicator />
44
+ {label}
45
+ </ChakraSlider.Marker>
46
+ )
47
+ })}
48
+ </ChakraSlider.MarkerGroup>
49
+ )}
50
+ </ChakraSlider.Root>
51
+ )
52
+ },
53
+ )
@@ -0,0 +1,2 @@
1
+ export { Spinner } from './spinner.tsx'
2
+ export type { SpinnerProps } from './spinner.tsx'
@@ -0,0 +1,19 @@
1
+ import React from 'react'
2
+
3
+ import { Spinner } from './spinner.tsx'
4
+
5
+ export default {
6
+ title: 'Components/Spinner',
7
+ component: Spinner,
8
+ }
9
+
10
+ export const Default = {
11
+ args: {},
12
+ }
13
+
14
+ export const RenderingChildren = {
15
+ args: {
16
+ loading: false,
17
+ children: 'Hello world',
18
+ },
19
+ }
@@ -0,0 +1,21 @@
1
+ import { forwardRef } from 'react'
2
+
3
+ import type { SpinnerProps as ChakraSpinnerProps } from '@chakra-ui/react'
4
+ import { Spinner as ChakraSpinner } from '@chakra-ui/react'
5
+
6
+ export interface SpinnerProps extends ChakraSpinnerProps {
7
+ loading?: boolean
8
+ children?: React.ReactNode
9
+ }
10
+
11
+ export const Spinner = forwardRef<HTMLDivElement, SpinnerProps>(
12
+ function Spinner(props, ref) {
13
+ const { loading, children, ...rest } = props
14
+
15
+ if (loading === false) {
16
+ return <>{children}</>
17
+ }
18
+
19
+ return <ChakraSpinner ref={ref} {...rest} />
20
+ },
21
+ )
@@ -0,0 +1,75 @@
1
+ import {
2
+ Badge,
3
+ type BadgeProps,
4
+ Stat as ChakraStat,
5
+ FormatNumber,
6
+ IconButton,
7
+ } from "@chakra-ui/react"
8
+ import { ToggleTip } from "compositions/ui/toggle-tip"
9
+ import { forwardRef } from "react"
10
+ import { HiOutlineInformationCircle } from "react-icons/hi"
11
+
12
+ interface StatLabelProps extends ChakraStat.LabelProps {
13
+ info?: React.ReactNode
14
+ }
15
+
16
+ export const StatLabel = forwardRef<HTMLDivElement, StatLabelProps>(
17
+ function StatLabel(props, ref) {
18
+ const { info, children, ...rest } = props
19
+ return (
20
+ <ChakraStat.Label {...rest} ref={ref}>
21
+ {children}
22
+ {info && (
23
+ <ToggleTip content={info}>
24
+ <IconButton variant="ghost" aria-label="info" size="2xs">
25
+ <HiOutlineInformationCircle />
26
+ </IconButton>
27
+ </ToggleTip>
28
+ )}
29
+ </ChakraStat.Label>
30
+ )
31
+ },
32
+ )
33
+
34
+ interface StatValueTextProps extends ChakraStat.ValueTextProps {
35
+ value?: number
36
+ formatOptions?: Intl.NumberFormatOptions
37
+ }
38
+
39
+ export const StatValueText = forwardRef<HTMLDivElement, StatValueTextProps>(
40
+ function StatValueText(props, ref) {
41
+ const { value, formatOptions, children, ...rest } = props
42
+ return (
43
+ <ChakraStat.ValueText {...rest} ref={ref}>
44
+ {children ||
45
+ (value != null && <FormatNumber value={value} {...formatOptions} />)}
46
+ </ChakraStat.ValueText>
47
+ )
48
+ },
49
+ )
50
+
51
+ export const StatUpTrend = forwardRef<HTMLDivElement, BadgeProps>(
52
+ function StatUpTrend(props, ref) {
53
+ return (
54
+ <Badge colorPalette="green" gap="0" {...props} ref={ref}>
55
+ <ChakraStat.UpIndicator />
56
+ {props.children}
57
+ </Badge>
58
+ )
59
+ },
60
+ )
61
+
62
+ export const StatDownTrend = forwardRef<HTMLDivElement, BadgeProps>(
63
+ function StatDownTrend(props, ref) {
64
+ return (
65
+ <Badge colorPalette="red" gap="0" {...props} ref={ref}>
66
+ <ChakraStat.DownIndicator />
67
+ {props.children}
68
+ </Badge>
69
+ )
70
+ },
71
+ )
72
+
73
+ export const StatRoot = ChakraStat.Root
74
+ export const StatHelpText = ChakraStat.HelpText
75
+ export const StatValueUnit = ChakraStat.ValueUnit
@@ -0,0 +1,29 @@
1
+ import type { ColorPalette } from "@chakra-ui/react"
2
+ import { Status as ChakraStatus } from "@chakra-ui/react"
3
+ import { forwardRef } from "react"
4
+
5
+ type StatusValue = "success" | "error" | "warning" | "info"
6
+
7
+ export interface StatusProps extends ChakraStatus.RootProps {
8
+ value?: StatusValue
9
+ }
10
+
11
+ const statusMap: Record<StatusValue, ColorPalette> = {
12
+ success: "green",
13
+ error: "red",
14
+ warning: "orange",
15
+ info: "blue",
16
+ }
17
+
18
+ export const Status = forwardRef<HTMLDivElement, StatusProps>(
19
+ function Status(props, ref) {
20
+ const { children, value = "info", ...rest } = props
21
+ const colorPalette = rest.colorPalette ?? statusMap[value]
22
+ return (
23
+ <ChakraStatus.Root ref={ref} {...rest} colorPalette={colorPalette}>
24
+ <ChakraStatus.Indicator />
25
+ {children}
26
+ </ChakraStatus.Root>
27
+ )
28
+ },
29
+ )
@@ -0,0 +1,49 @@
1
+ import { HStack, IconButton, NumberInput } from "@chakra-ui/react"
2
+ import { forwardRef } from "react"
3
+ import { LuMinus, LuPlus } from "react-icons/lu"
4
+
5
+ export interface StepperInputProps extends NumberInput.RootProps {
6
+ label?: React.ReactNode
7
+ }
8
+
9
+ export const StepperInput = forwardRef<HTMLDivElement, StepperInputProps>(
10
+ function StepperInput(props, ref) {
11
+ const { label, ...rest } = props
12
+ return (
13
+ <NumberInput.Root {...rest} unstyled ref={ref}>
14
+ {label && <NumberInput.Label>{label}</NumberInput.Label>}
15
+ <HStack gap="2">
16
+ <DecrementTrigger />
17
+ <NumberInput.ValueText textAlign="center" fontSize="lg" minW="3ch" />
18
+ <IncrementTrigger />
19
+ </HStack>
20
+ </NumberInput.Root>
21
+ )
22
+ },
23
+ )
24
+
25
+ const DecrementTrigger = forwardRef<
26
+ HTMLButtonElement,
27
+ NumberInput.DecrementTriggerProps
28
+ >(function DecrementTrigger(props, ref) {
29
+ return (
30
+ <NumberInput.DecrementTrigger {...props} asChild ref={ref}>
31
+ <IconButton variant="outline" size="sm">
32
+ <LuMinus />
33
+ </IconButton>
34
+ </NumberInput.DecrementTrigger>
35
+ )
36
+ })
37
+
38
+ const IncrementTrigger = forwardRef<
39
+ HTMLButtonElement,
40
+ NumberInput.IncrementTriggerProps
41
+ >(function IncrementTrigger(props, ref) {
42
+ return (
43
+ <NumberInput.IncrementTrigger {...props} asChild ref={ref}>
44
+ <IconButton variant="outline" size="sm">
45
+ <LuPlus />
46
+ </IconButton>
47
+ </NumberInput.IncrementTrigger>
48
+ )
49
+ })
@@ -0,0 +1 @@
1
+ export * as Steps from './namespace.ts'
@@ -0,0 +1,16 @@
1
+ export {
2
+ StepsRoot as Root,
3
+ StepsItem as Item,
4
+ StepsIndicator as Indicator,
5
+ StepsCompletedContent as CompletedContent,
6
+ StepsContent as Content,
7
+ StepsList as List,
8
+ StepsNextTrigger as NextTrigger,
9
+ StepsPrevTrigger as PrevTrigger,
10
+ } from './steps.tsx'
11
+
12
+ export type {
13
+ StepsRootProps as RootProps,
14
+ StepsItemProps as ItemProps,
15
+ StepsIndicatorProps as IndicatorProps,
16
+ } from './steps.tsx'
@@ -0,0 +1,82 @@
1
+ import { Box, Steps as ChakraSteps } from '@chakra-ui/react'
2
+
3
+ import { CheckIcon } from '../icons'
4
+
5
+ interface StepInfoProps {
6
+ title?: React.ReactNode
7
+ description?: React.ReactNode
8
+ }
9
+
10
+ export interface StepsItemProps
11
+ extends Omit<ChakraSteps.ItemProps, 'title'>,
12
+ StepInfoProps {
13
+ completedIcon?: React.ReactNode
14
+ icon?: React.ReactNode
15
+ }
16
+
17
+ export const StepsItem = (props: StepsItemProps) => {
18
+ const { title, description, completedIcon, icon, ...rest } = props
19
+ return (
20
+ <ChakraSteps.Item {...rest}>
21
+ <ChakraSteps.Trigger>
22
+ <ChakraSteps.Indicator>
23
+ <ChakraSteps.Status
24
+ complete={completedIcon || <CheckIcon />}
25
+ incomplete={icon || <ChakraSteps.Number />}
26
+ />
27
+ </ChakraSteps.Indicator>
28
+ <StepInfo title={title} description={description} />
29
+ </ChakraSteps.Trigger>
30
+ <ChakraSteps.Separator />
31
+ </ChakraSteps.Item>
32
+ )
33
+ }
34
+
35
+ const StepInfo = (props: StepInfoProps) => {
36
+ const { title, description } = props
37
+ if (title && description) {
38
+ return (
39
+ <Box>
40
+ <ChakraSteps.Title>{title}</ChakraSteps.Title>
41
+ <ChakraSteps.Description>{description}</ChakraSteps.Description>
42
+ </Box>
43
+ )
44
+ }
45
+ return (
46
+ <>
47
+ {title && <ChakraSteps.Title>{title}</ChakraSteps.Title>}
48
+ {description && (
49
+ <ChakraSteps.Description>{description}</ChakraSteps.Description>
50
+ )}
51
+ </>
52
+ )
53
+ }
54
+
55
+ export interface StepsIndicatorProps {
56
+ completedIcon: React.ReactNode
57
+ icon?: React.ReactNode
58
+ }
59
+
60
+ export const StepsIndicator = (props: StepsIndicatorProps) => {
61
+ const { icon = <ChakraSteps.Number />, completedIcon } = props
62
+ return (
63
+ <ChakraSteps.Indicator>
64
+ <ChakraSteps.Status complete={completedIcon} incomplete={icon} />
65
+ </ChakraSteps.Indicator>
66
+ )
67
+ }
68
+
69
+ export const StepsList = ChakraSteps.List
70
+
71
+ export type StepsRootProps = ChakraSteps.RootProps
72
+ export const StepsRoot = ChakraSteps.Root
73
+ export const StepsContent = ChakraSteps.Content
74
+ export const StepsCompletedContent = ChakraSteps.CompletedContent
75
+
76
+ export const StepsNextTrigger = (props: ChakraSteps.NextTriggerProps) => {
77
+ return <ChakraSteps.NextTrigger {...props} />
78
+ }
79
+
80
+ export const StepsPrevTrigger = (props: ChakraSteps.PrevTriggerProps) => {
81
+ return <ChakraSteps.PrevTrigger {...props} />
82
+ }
@@ -0,0 +1,3 @@
1
+ export { Switch } from './switch.tsx'
2
+
3
+ export type { SwitchProps } from './switch.tsx'
@@ -0,0 +1,39 @@
1
+ import { Switch as ChakraSwitch } from "@chakra-ui/react"
2
+ import { forwardRef } from "react"
3
+
4
+ export interface SwitchProps extends ChakraSwitch.RootProps {
5
+ inputProps?: React.InputHTMLAttributes<HTMLInputElement>
6
+ rootRef?: React.Ref<HTMLLabelElement>
7
+ trackLabel?: { on: React.ReactNode; off: React.ReactNode }
8
+ thumbLabel?: { on: React.ReactNode; off: React.ReactNode }
9
+ }
10
+
11
+ export const Switch = forwardRef<HTMLInputElement, SwitchProps>(
12
+ function Switch(props, ref) {
13
+ const { inputProps, children, rootRef, trackLabel, thumbLabel, ...rest } =
14
+ props
15
+
16
+ return (
17
+ <ChakraSwitch.Root ref={rootRef} {...rest}>
18
+ <ChakraSwitch.HiddenInput ref={ref} {...inputProps} />
19
+ <ChakraSwitch.Control>
20
+ <ChakraSwitch.Thumb>
21
+ {thumbLabel && (
22
+ <ChakraSwitch.ThumbIndicator fallback={thumbLabel?.off}>
23
+ {thumbLabel?.on}
24
+ </ChakraSwitch.ThumbIndicator>
25
+ )}
26
+ </ChakraSwitch.Thumb>
27
+ {trackLabel && (
28
+ <ChakraSwitch.Indicator fallback={trackLabel.off}>
29
+ {trackLabel.on}
30
+ </ChakraSwitch.Indicator>
31
+ )}
32
+ </ChakraSwitch.Control>
33
+ {children != null && (
34
+ <ChakraSwitch.Label>{children}</ChakraSwitch.Label>
35
+ )}
36
+ </ChakraSwitch.Root>
37
+ )
38
+ },
39
+ )
@@ -0,0 +1,39 @@
1
+ import { Tag as ChakraTag } from "@chakra-ui/react"
2
+ import { forwardRef } from "react"
3
+
4
+ export interface TagProps extends ChakraTag.RootProps {
5
+ startElement?: React.ReactNode
6
+ endElement?: React.ReactNode
7
+ onClose?: VoidFunction
8
+ closable?: boolean
9
+ }
10
+
11
+ export const Tag = forwardRef<HTMLSpanElement, TagProps>(
12
+ function Tag(props, ref) {
13
+ const {
14
+ startElement,
15
+ endElement,
16
+ onClose,
17
+ closable = !!onClose,
18
+ children,
19
+ ...rest
20
+ } = props
21
+
22
+ return (
23
+ <ChakraTag.Root ref={ref} {...rest}>
24
+ {startElement && (
25
+ <ChakraTag.StartElement>{startElement}</ChakraTag.StartElement>
26
+ )}
27
+ <ChakraTag.Label>{children}</ChakraTag.Label>
28
+ {endElement && (
29
+ <ChakraTag.EndElement>{endElement}</ChakraTag.EndElement>
30
+ )}
31
+ {closable && (
32
+ <ChakraTag.EndElement>
33
+ <ChakraTag.CloseTrigger onClick={onClose} />
34
+ </ChakraTag.EndElement>
35
+ )}
36
+ </ChakraTag.Root>
37
+ )
38
+ },
39
+ )