@vygruppen/spor-react 11.3.10 → 12.0.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 (322) hide show
  1. package/.turbo/turbo-build.log +32 -11
  2. package/.turbo/turbo-typegen.log +23 -0
  3. package/CHANGELOG.md +239 -0
  4. package/dist/index.d.mts +2552 -8319
  5. package/dist/index.d.ts +2552 -8319
  6. package/dist/index.js +9609 -8608
  7. package/dist/index.js.map +1 -1
  8. package/dist/index.mjs +9487 -8455
  9. package/dist/index.mjs.map +1 -1
  10. package/package.json +21 -13
  11. package/src/accordion/Accordion.tsx +96 -45
  12. package/src/accordion/Expandable.tsx +54 -127
  13. package/src/accordion/helpers.ts +31 -0
  14. package/src/accordion/types.ts +60 -0
  15. package/src/alert/Alert.tsx +101 -0
  16. package/src/alert/AlertIcon.tsx +63 -45
  17. package/src/alert/ExpandableAlert.tsx +96 -64
  18. package/src/alert/ServiceAlert.tsx +127 -125
  19. package/src/alert/{index.tsx → index.ts} +1 -2
  20. package/src/breadcrumb/Breadcrumb.tsx +39 -24
  21. package/src/button/Button.tsx +86 -105
  22. package/src/button/ButtonGroup.tsx +45 -20
  23. package/src/button/Clipboard.tsx +82 -0
  24. package/src/button/CloseButton.tsx +4 -3
  25. package/src/button/FloatingActionButton.tsx +35 -41
  26. package/src/button/IconButton.tsx +34 -30
  27. package/src/button/index.tsx +1 -0
  28. package/src/color-mode/color-mode.tsx +75 -0
  29. package/src/color-mode/index.ts +1 -0
  30. package/src/datepicker/Calendar.tsx +17 -8
  31. package/src/datepicker/CalendarCell.tsx +20 -13
  32. package/src/datepicker/CalendarGrid.tsx +18 -10
  33. package/src/datepicker/CalendarHeader.tsx +2 -0
  34. package/src/datepicker/CalendarNavigationButton.tsx +1 -0
  35. package/src/datepicker/CalendarTriggerButton.tsx +43 -45
  36. package/src/datepicker/DateField.tsx +21 -12
  37. package/src/datepicker/DatePicker.tsx +61 -58
  38. package/src/datepicker/DateRangePicker.tsx +52 -58
  39. package/src/datepicker/DateTimeSegment.tsx +13 -5
  40. package/src/datepicker/RangeCalendar.tsx +13 -7
  41. package/src/datepicker/StyledField.tsx +25 -17
  42. package/src/datepicker/TimeField.tsx +10 -8
  43. package/src/datepicker/TimePicker.tsx +48 -45
  44. package/src/datepicker/types.ts +5 -0
  45. package/src/dialog/Dialog.tsx +56 -0
  46. package/src/dialog/Drawer.tsx +187 -0
  47. package/src/dialog/index.ts +2 -0
  48. package/src/dialog/types.ts +26 -0
  49. package/src/image/index.tsx +2 -2
  50. package/src/index.tsx +5 -3
  51. package/src/input/AttachedInputs.tsx +17 -42
  52. package/src/input/CardSelect.tsx +75 -162
  53. package/src/input/Checkbox.tsx +30 -6
  54. package/src/input/CheckboxGroup.tsx +25 -16
  55. package/src/input/ChoiceChip.tsx +58 -77
  56. package/src/input/Combobox.tsx +172 -172
  57. package/src/input/CountryCodeSelect.tsx +42 -28
  58. package/src/input/Dialog.tsx +1 -0
  59. package/src/input/Field.tsx +71 -0
  60. package/src/input/Fieldset.tsx +7 -0
  61. package/src/input/Input.tsx +68 -73
  62. package/src/input/InputGroup.tsx +66 -0
  63. package/src/input/ListBox.tsx +83 -70
  64. package/src/input/NativeSelect.tsx +68 -33
  65. package/src/input/NumericStepper.tsx +173 -171
  66. package/src/input/PasswordInput.tsx +99 -52
  67. package/src/input/PhoneNumberInput.tsx +69 -72
  68. package/src/input/Popover.tsx +1 -0
  69. package/src/input/Radio.tsx +37 -17
  70. package/src/input/SearchInput.tsx +24 -86
  71. package/src/input/Select.tsx +237 -0
  72. package/src/input/Switch.tsx +60 -18
  73. package/src/input/Textarea.tsx +53 -101
  74. package/src/input/{index.tsx → index.ts} +2 -8
  75. package/src/layout/PressableCard.tsx +12 -21
  76. package/src/layout/RadioCard.tsx +68 -101
  77. package/src/layout/Separator.tsx +32 -0
  78. package/src/layout/StaticCard.tsx +13 -33
  79. package/src/layout/index.tsx +3 -7
  80. package/src/linjetag/InfoTag.tsx +16 -9
  81. package/src/linjetag/LineIcon.tsx +74 -28
  82. package/src/linjetag/TravelTag.tsx +38 -27
  83. package/src/link/TextLink.tsx +25 -16
  84. package/src/list/index.tsx +24 -2
  85. package/src/loader/ClientOnly.tsx +8 -7
  86. package/src/loader/ColorInlineLoader.tsx +4 -3
  87. package/src/loader/ColorSpinner.tsx +5 -4
  88. package/src/loader/ContentLoader.tsx +6 -4
  89. package/src/loader/DarkFullScreenLoader.tsx +11 -3
  90. package/src/loader/DarkInlineLoader.tsx +5 -3
  91. package/src/loader/DarkSpinner.tsx +7 -3
  92. package/src/loader/LightFullScreenLoader.tsx +11 -3
  93. package/src/loader/LightInlineLoader.tsx +11 -3
  94. package/src/loader/LightSpinner.tsx +5 -3
  95. package/src/loader/Lottie.tsx +3 -3
  96. package/src/loader/ProgressBar.tsx +83 -84
  97. package/src/loader/ProgressLoader.tsx +120 -75
  98. package/src/loader/Skeleton.tsx +94 -19
  99. package/src/loader/index.tsx +0 -2
  100. package/src/loader/useHydrated.tsx +1 -0
  101. package/src/loader/useRotatingLabel.tsx +2 -1
  102. package/src/logo/CargonetLogo.tsx +89 -89
  103. package/src/logo/VyLogo.tsx +61 -42
  104. package/src/logo/VyLogoPride.tsx +137 -139
  105. package/src/media-controller/JumpButton.tsx +48 -38
  106. package/src/media-controller/PlayPauseButton.tsx +31 -29
  107. package/src/media-controller/SkipButton.tsx +38 -37
  108. package/src/nudge/Nudge.tsx +195 -123
  109. package/src/nudge/index.tsx +0 -1
  110. package/src/pagination/Pagination.tsx +221 -118
  111. package/src/pagination/types.ts +23 -0
  112. package/src/popover/index.tsx +67 -0
  113. package/src/progress-indicator/ProgressDot.tsx +11 -10
  114. package/src/progress-indicator/ProgressIndicator.tsx +28 -15
  115. package/src/provider/SporProvider.tsx +17 -14
  116. package/src/stepper/Stepper.tsx +88 -85
  117. package/src/stepper/StepperContext.tsx +2 -1
  118. package/src/stepper/StepperStep.tsx +28 -21
  119. package/src/tab/Tabs.tsx +62 -12
  120. package/src/tab/index.tsx +1 -9
  121. package/src/table/Table.tsx +35 -30
  122. package/src/table/index.tsx +11 -7
  123. package/src/theme/brand.ts +7 -0
  124. package/src/theme/index.ts +45 -37
  125. package/src/theme/recipes/attached-inputs.ts +43 -0
  126. package/src/theme/recipes/badge.ts +104 -0
  127. package/src/theme/recipes/button.ts +124 -0
  128. package/src/theme/recipes/choice-chip.ts +144 -0
  129. package/src/theme/recipes/close-button.ts +41 -0
  130. package/src/theme/recipes/code.ts +14 -0
  131. package/src/theme/recipes/group.ts +19 -0
  132. package/src/theme/recipes/index.ts +29 -0
  133. package/src/theme/recipes/input.ts +89 -0
  134. package/src/theme/recipes/link.ts +64 -0
  135. package/src/theme/recipes/nudge.ts +12 -0
  136. package/src/theme/recipes/pressable-card.ts +83 -0
  137. package/src/theme/recipes/progress-loader.ts +14 -0
  138. package/src/theme/recipes/separator.ts +85 -0
  139. package/src/theme/recipes/skeleton.ts +57 -0
  140. package/src/theme/recipes/static-card.ts +39 -0
  141. package/src/theme/recipes/textarea.ts +27 -0
  142. package/src/theme/semantic-tokens/colors.ts +22 -0
  143. package/src/theme/semantic-tokens/index.ts +24 -0
  144. package/src/theme/semantic-tokens/radii.ts +14 -0
  145. package/src/theme/semantic-tokens/shadows.ts +17 -0
  146. package/src/theme/slot-recipes/accordion.ts +131 -0
  147. package/src/theme/slot-recipes/alert-expandable.ts +133 -0
  148. package/src/theme/slot-recipes/alert-service.ts +66 -0
  149. package/src/theme/slot-recipes/alert.ts +72 -0
  150. package/src/theme/slot-recipes/anatomy.ts +269 -0
  151. package/src/theme/slot-recipes/breadcrumb.ts +61 -0
  152. package/src/theme/slot-recipes/checkbox.ts +89 -0
  153. package/src/theme/slot-recipes/datepicker.ts +214 -0
  154. package/src/theme/slot-recipes/dialog.ts +221 -0
  155. package/src/theme/slot-recipes/drawer.ts +205 -0
  156. package/src/theme/slot-recipes/field.ts +79 -0
  157. package/src/theme/slot-recipes/floating-action-button.ts +131 -0
  158. package/src/theme/slot-recipes/index.ts +65 -0
  159. package/src/theme/slot-recipes/info-tag.ts +62 -0
  160. package/src/theme/slot-recipes/line-icon.ts +140 -0
  161. package/src/theme/slot-recipes/list.ts +45 -0
  162. package/src/theme/slot-recipes/listbox.ts +72 -0
  163. package/src/theme/slot-recipes/media-controller-button.ts +131 -0
  164. package/src/theme/slot-recipes/native-select.ts +54 -0
  165. package/src/theme/slot-recipes/numeric-stepper.ts +65 -0
  166. package/src/theme/slot-recipes/pagination.ts +41 -0
  167. package/src/theme/slot-recipes/popover.ts +78 -0
  168. package/src/theme/slot-recipes/progress-bar.ts +39 -0
  169. package/src/theme/slot-recipes/progress-indicator.ts +22 -0
  170. package/src/theme/slot-recipes/radio-card.ts +112 -0
  171. package/src/theme/slot-recipes/radio.ts +80 -0
  172. package/src/theme/slot-recipes/select.ts +243 -0
  173. package/src/theme/slot-recipes/stepper.ts +92 -0
  174. package/src/theme/slot-recipes/switch.ts +147 -0
  175. package/src/theme/slot-recipes/table.ts +200 -0
  176. package/src/theme/slot-recipes/tabs.ts +169 -0
  177. package/src/theme/slot-recipes/toast.ts +56 -0
  178. package/src/theme/slot-recipes/travel-tag.ts +192 -0
  179. package/src/theme/tokens/animation-styles.ts +50 -0
  180. package/src/theme/tokens/animations.ts +22 -0
  181. package/src/theme/tokens/aspect-ratios.ts +22 -0
  182. package/src/theme/tokens/blurs.ts +28 -0
  183. package/src/theme/tokens/borders.ts +26 -0
  184. package/src/theme/{foundations → tokens}/breakpoints.ts +0 -1
  185. package/src/theme/tokens/colors.ts +10 -0
  186. package/src/theme/tokens/config.ts +10 -0
  187. package/src/theme/tokens/cursor.ts +28 -0
  188. package/src/theme/tokens/durations.ts +25 -0
  189. package/src/theme/tokens/easings.ts +16 -0
  190. package/src/theme/tokens/font-sizes.ts +30 -0
  191. package/src/theme/tokens/font-weights.ts +31 -0
  192. package/src/theme/tokens/fonts.ts +8 -0
  193. package/src/theme/tokens/global-css.ts +18 -0
  194. package/src/theme/tokens/index.ts +37 -0
  195. package/src/theme/tokens/keyframes.ts +255 -0
  196. package/src/theme/tokens/letter-spacings.ts +19 -0
  197. package/src/theme/tokens/line-heights.ts +19 -0
  198. package/src/theme/tokens/radii.ts +13 -0
  199. package/src/theme/tokens/sizes.ts +51 -0
  200. package/src/theme/tokens/spacing.ts +20 -0
  201. package/src/theme/tokens/text-styles.ts +89 -0
  202. package/src/theme/tokens/z-index.ts +17 -0
  203. package/src/theme/utils/accent-utils.ts +8 -21
  204. package/src/theme/utils/bg-utils.ts +4 -6
  205. package/src/theme/utils/brand-utils.ts +6 -19
  206. package/src/theme/utils/core-utils.ts +91 -0
  207. package/src/theme/utils/floating-utils.ts +20 -39
  208. package/src/theme/utils/ghost-utils.ts +7 -21
  209. package/src/theme/utils/input-utils.ts +32 -37
  210. package/src/theme/utils/outline-utils.ts +4 -11
  211. package/src/theme/utils/surface-utils.ts +5 -19
  212. package/src/theme/utils/types.ts +1 -0
  213. package/src/toast/index.tsx +1 -1
  214. package/src/toast/toast.tsx +105 -0
  215. package/src/transition/index.ts +2 -8
  216. package/src/typography/Badge.tsx +15 -61
  217. package/src/typography/Code.tsx +16 -28
  218. package/src/typography/Heading.tsx +34 -19
  219. package/src/typography/Text.tsx +9 -6
  220. package/src/typography/{index.tsx → index.ts} +1 -0
  221. package/src/util/externals.tsx +13 -27
  222. package/tsconfig.json +5 -1
  223. package/src/accordion/Accordion.test.tsx +0 -20
  224. package/src/alert/BaseAlert.test.tsx +0 -37
  225. package/src/alert/BaseAlert.tsx +0 -34
  226. package/src/alert/ClosableAlert.test.tsx +0 -37
  227. package/src/alert/ClosableAlert.tsx +0 -85
  228. package/src/alert/ExpandableAlert.test.tsx +0 -84
  229. package/src/alert/StaticAlert.tsx +0 -33
  230. package/src/button/Button.test.tsx +0 -23
  231. package/src/datepicker/TimePicker.test.tsx +0 -74
  232. package/src/input/FormControl.tsx +0 -2
  233. package/src/input/FormErrorMessage.tsx +0 -95
  234. package/src/input/FormLabel.tsx +0 -11
  235. package/src/input/InfoSelect.tsx +0 -274
  236. package/src/input/InputElement.tsx +0 -44
  237. package/src/input/RadioGroup.tsx +0 -47
  238. package/src/layout/Divider.tsx +0 -27
  239. package/src/layout/RadioCardGroup.tsx +0 -79
  240. package/src/layout/Stack.tsx +0 -42
  241. package/src/loader/SkeletonCircle.tsx +0 -13
  242. package/src/loader/SkeletonText.tsx +0 -14
  243. package/src/media-controller/index.test.tsx +0 -59
  244. package/src/modal/Drawer.tsx +0 -120
  245. package/src/modal/FullScreenDrawer.tsx +0 -239
  246. package/src/modal/Modal.tsx +0 -15
  247. package/src/modal/ModalHeader.tsx +0 -31
  248. package/src/modal/SimpleDrawer.tsx +0 -51
  249. package/src/modal/index.tsx +0 -5
  250. package/src/nudge/WizardNudge.tsx +0 -107
  251. package/src/theme/components/accordion.ts +0 -102
  252. package/src/theme/components/alert-expandable.ts +0 -125
  253. package/src/theme/components/alert-service.ts +0 -98
  254. package/src/theme/components/alert.ts +0 -71
  255. package/src/theme/components/badge.ts +0 -109
  256. package/src/theme/components/breadcrumb.ts +0 -60
  257. package/src/theme/components/button.ts +0 -125
  258. package/src/theme/components/card-select.ts +0 -117
  259. package/src/theme/components/checkbox.ts +0 -88
  260. package/src/theme/components/choice-chip.ts +0 -161
  261. package/src/theme/components/close-button.ts +0 -48
  262. package/src/theme/components/code.ts +0 -17
  263. package/src/theme/components/datepicker.ts +0 -198
  264. package/src/theme/components/divider.ts +0 -50
  265. package/src/theme/components/drawer.ts +0 -95
  266. package/src/theme/components/fab.ts +0 -109
  267. package/src/theme/components/form-label.ts +0 -17
  268. package/src/theme/components/form.ts +0 -27
  269. package/src/theme/components/index.ts +0 -45
  270. package/src/theme/components/info-select.ts +0 -85
  271. package/src/theme/components/info-tag.ts +0 -63
  272. package/src/theme/components/input.ts +0 -28
  273. package/src/theme/components/line-icon.ts +0 -129
  274. package/src/theme/components/link.ts +0 -78
  275. package/src/theme/components/list.ts +0 -23
  276. package/src/theme/components/listbox.ts +0 -77
  277. package/src/theme/components/media-controller-button.ts +0 -97
  278. package/src/theme/components/modal.ts +0 -96
  279. package/src/theme/components/numeric-stepper.ts +0 -65
  280. package/src/theme/components/pagination.ts +0 -74
  281. package/src/theme/components/popover.ts +0 -68
  282. package/src/theme/components/pressable-card.ts +0 -72
  283. package/src/theme/components/progress-bar.ts +0 -47
  284. package/src/theme/components/progress-indicator.ts +0 -44
  285. package/src/theme/components/radio-card.ts +0 -134
  286. package/src/theme/components/radio.ts +0 -68
  287. package/src/theme/components/select.ts +0 -74
  288. package/src/theme/components/skeleton.ts +0 -40
  289. package/src/theme/components/static-card.ts +0 -82
  290. package/src/theme/components/stepper.ts +0 -100
  291. package/src/theme/components/switch.ts +0 -112
  292. package/src/theme/components/table.ts +0 -161
  293. package/src/theme/components/tabs.ts +0 -135
  294. package/src/theme/components/textarea.ts +0 -33
  295. package/src/theme/components/toast.ts +0 -28
  296. package/src/theme/components/travel-tag.ts +0 -256
  297. package/src/theme/foundations/borders.ts +0 -11
  298. package/src/theme/foundations/colors.ts +0 -12
  299. package/src/theme/foundations/config.ts +0 -5
  300. package/src/theme/foundations/fontSizes.ts +0 -29
  301. package/src/theme/foundations/fontWeights.ts +0 -5
  302. package/src/theme/foundations/fonts.ts +0 -7
  303. package/src/theme/foundations/index.ts +0 -15
  304. package/src/theme/foundations/lineHeights.ts +0 -6
  305. package/src/theme/foundations/radii.ts +0 -12
  306. package/src/theme/foundations/shadows.ts +0 -8
  307. package/src/theme/foundations/sizes.ts +0 -36
  308. package/src/theme/foundations/spacing.ts +0 -31
  309. package/src/theme/foundations/styles.ts +0 -12
  310. package/src/theme/foundations/textStyles.ts +0 -74
  311. package/src/theme/foundations/zIndices.ts +0 -17
  312. package/src/theme/utils/base-utils.ts +0 -104
  313. package/src/theme/utils/focus-utils.ts +0 -10
  314. package/src/toast/ActionToast.test.tsx +0 -22
  315. package/src/toast/ActionToast.tsx +0 -28
  316. package/src/toast/BaseToast.test.tsx +0 -27
  317. package/src/toast/BaseToast.tsx +0 -75
  318. package/src/toast/ClosableToast.test.tsx +0 -17
  319. package/src/toast/ClosableToast.tsx +0 -40
  320. package/src/toast/useToast.tsx +0 -121
  321. package/src/tooltip/Tooltip.tsx +0 -70
  322. package/src/tooltip/index.tsx +0 -1
@@ -1,4 +1,5 @@
1
- import { Box, BoxProps, Center } from "@chakra-ui/react";
1
+ "use client";
2
+ import { Box, BoxProps, Center, VisuallyHidden } from "@chakra-ui/react";
2
3
  import { inlineLoaderLightData } from "@vygruppen/spor-loader";
3
4
  import React from "react";
4
5
  import { ClientOnly } from "./ClientOnly";
@@ -14,12 +15,19 @@ export const LightInlineLoader = ({
14
15
  ...props
15
16
  }: LightInlineLoaderProps) => {
16
17
  return (
17
- <Center {...props}>
18
+ <Center
19
+ height="100%"
20
+ background="white"
21
+ role="status"
22
+ aria-live="polite"
23
+ {...props}
24
+ >
18
25
  <Box width={width} maxWidth={maxWidth}>
19
26
  <ClientOnly>
20
- {() => <Lottie animationData={inlineLoaderLightData} />}
27
+ <Lottie animationData={inlineLoaderLightData} />
21
28
  </ClientOnly>
22
29
  </Box>
30
+ <VisuallyHidden>Loading...</VisuallyHidden>
23
31
  </Center>
24
32
  );
25
33
  };
@@ -1,4 +1,5 @@
1
- import { Box, BoxProps, Center } from "@chakra-ui/react";
1
+ "use client";
2
+ import { Box, BoxProps, Center, VisuallyHidden } from "@chakra-ui/react";
2
3
  import { spinnerLightData } from "@vygruppen/spor-loader";
3
4
  import React from "react";
4
5
  import { ClientOnly } from "./ClientOnly";
@@ -27,12 +28,13 @@ export const LightSpinner = ({
27
28
  ...props
28
29
  }: LightSpinnerProps) => {
29
30
  return (
30
- <Center flexDirection="column" {...props}>
31
+ <Center flexDirection="column" role="status" aria-live="polite" {...props}>
31
32
  <Box width={width} maxWidth={maxWidth}>
32
33
  <ClientOnly>
33
- {() => <Lottie animationData={spinnerLightData} />}
34
+ <Lottie animationData={spinnerLightData} />
34
35
  </ClientOnly>
35
36
  </Box>
37
+ <VisuallyHidden>Loading...</VisuallyHidden>
36
38
  {children && (
37
39
  <Box marginTop={3} fontWeight="bold">
38
40
  {children}
@@ -1,10 +1,10 @@
1
- import { useLottie } from "lottie-react";
2
1
  import React from "react";
3
2
 
3
+ import ReactLottie from "lottie-react";
4
+
4
5
  /**
5
6
  * A wrapper around Lottie to make it tree-shakeable for SSR.
6
7
  */
7
8
  export default function Lottie({ animationData }: { animationData: any }) {
8
- const { View } = useLottie({ animationData, loop: true });
9
- return <>{View}</>;
9
+ return <ReactLottie animationData={animationData} />;
10
10
  }
@@ -1,40 +1,50 @@
1
- import { Box, BoxProps, Text, useMultiStyleConfig } from "@chakra-ui/react";
2
- import React from "react";
3
- import { useProgressBar } from "react-aria";
4
- import { createTexts, useTranslation } from "..";
1
+ "use client";
2
+ import {
3
+ BoxProps,
4
+ Progress,
5
+ UseProgressProps,
6
+ RecipeVariantProps,
7
+ useSlotRecipe,
8
+ } from "@chakra-ui/react";
9
+ import React, { forwardRef, PropsWithChildren } from "react";
10
+ import { progressBarRecipe } from "../theme/slot-recipes/progress-bar";
5
11
  import { useRotatingLabel } from "./useRotatingLabel";
6
12
 
7
- type ProgressBarProps = BoxProps & {
8
- /** The percentage of progress made.
9
- *
10
- * The value must be between 0 and 100 */
11
- value: number;
12
- /** The height of the progress bar.
13
- * Defaults to .5rem
14
- **/
15
- height?: BoxProps["height"];
16
- /** The width of the progress bar.
17
- *
18
- * Defaults to the width of its container
19
- **/
20
- width?: BoxProps["width"];
13
+ type ProgressBarVariants = RecipeVariantProps<typeof progressBarRecipe>;
21
14
 
22
- /** Pass if no label is passed to the label */
23
- "aria-label": string;
24
- /** Optional text shown below the loader.
25
- *
26
- * If you pass an array of strings, the text will rotate every 5 seconds. If you want to change the delay, pass the delay in milliseconds to the `labelRotationDelay` prop.
27
- */
28
- label: string | string[];
29
- /** The number of milliseconds a label is shown, if an array of strings is passed to the `label` prop.
30
- *
31
- * Defaults to 5000 (5 seconds).
32
- */
33
- labelRotationDelay?: number;
15
+ export type ProgressBarProps = BoxProps &
16
+ UseProgressProps &
17
+ PropsWithChildren<ProgressBarVariants> & {
18
+ children: React.ReactNode;
19
+ /** The height of the progress bar.
20
+ * Defaults to .5rem
21
+ **/
22
+ height?: BoxProps["height"];
23
+ /** The width of the progress bar.
24
+ *
25
+ * Defaults to the width of its container
26
+ **/
27
+ width?: BoxProps["width"];
34
28
 
35
- /** Pass to disable the color of the component */
36
- isActive?: boolean;
37
- };
29
+ /** Pass if no label is passed to the label */
30
+ "aria-label": string;
31
+ /** Optional text shown below the loader.
32
+ *
33
+ * If you pass an array of strings, the text will rotate every 5 seconds. If you want to change the delay, pass the delay in milliseconds to the `labelRotationDelay` prop.
34
+ */
35
+ label: string | string[];
36
+ /** The number of milliseconds a label is shown, if an array of strings is passed to the `label` prop.
37
+ *
38
+ * Defaults to 5000 (5 seconds).
39
+ */
40
+ labelRotationDelay?: number;
41
+
42
+ /** Pass to disable the color of the component */
43
+ isActive?: boolean;
44
+
45
+ /** Pass to show the value text */
46
+ showValueText?: boolean;
47
+ };
38
48
 
39
49
  /**
40
50
  * Shows the progress of a loading process.
@@ -63,57 +73,46 @@ type ProgressBarProps = BoxProps & {
63
73
  * <ProgressBar value={50} aria-label="Loading..." />
64
74
  * ```
65
75
  */
66
- export const ProgressBar = ({
67
- value,
68
- label,
69
- labelRotationDelay = 5000,
70
- height = "0.5rem",
71
- width = "100%",
72
- "aria-label": ariaLabel,
73
- isActive = true,
74
- ...rest
75
- }: ProgressBarProps) => {
76
- const { t } = useTranslation();
77
- const currentLoadingText = useRotatingLabel({
78
- label,
79
- delay: labelRotationDelay,
80
- });
81
- const { labelProps, progressBarProps } = useProgressBar({
82
- isIndeterminate: value === undefined,
83
- value,
84
- "aria-label": ariaLabel || t(texts.label(value)),
85
- });
86
- const styles = useMultiStyleConfig("ProgressBar", { isActive });
87
- return (
88
- <>
89
- <Box
90
- {...progressBarProps}
91
- title={t(texts.label(value))}
92
- __css={styles.container}
93
- {...rest}
94
- >
95
- <Box width={width} __css={styles.background}>
96
- <Box
97
- __css={styles.progress}
98
- height={height}
99
- width={isActive ? `${value}%` : "100%"}
100
- />
101
- </Box>
102
- {currentLoadingText && (
103
- <Text sx={styles.description} {...labelProps}>
76
+
77
+ export const ProgressBar = forwardRef<HTMLDivElement, ProgressBarProps>(
78
+ (
79
+ {
80
+ value,
81
+ colorPalette = "white",
82
+ label,
83
+ labelRotationDelay = 5000,
84
+ isActive = true,
85
+ showValueText = false,
86
+ height = "0.5rem",
87
+ "aria-label": ariaLabel,
88
+ ...rest
89
+ },
90
+ ref,
91
+ ) => {
92
+ const recipe = useSlotRecipe({ key: "progressbar" });
93
+ const styles = recipe({});
94
+ const currentLoadingText = useRotatingLabel({
95
+ label,
96
+ delay: labelRotationDelay,
97
+ });
98
+
99
+ return (
100
+ <Progress.Root css={styles.container} ref={ref} value={value} {...rest}>
101
+ <Progress.Track
102
+ height={height}
103
+ css={isActive ? styles.background : styles.disabledBackground}
104
+ >
105
+ <Progress.Range css={styles.progress} />
106
+ </Progress.Track>
107
+
108
+ {label && (
109
+ <Progress.Label css={styles.description}>
104
110
  {currentLoadingText}
105
- </Text>
111
+ </Progress.Label>
106
112
  )}
107
- </Box>
108
- </>
109
- );
110
- };
111
113
 
112
- const texts = createTexts({
113
- label: (value) => ({
114
- nb: `${value}% ferdig`,
115
- nn: `${value}% ferdig`,
116
- sv: `${value}% klart`,
117
- en: `${value}% done`,
118
- }),
119
- });
114
+ {showValueText && <Progress.ValueText>{value}%</Progress.ValueText>}
115
+ </Progress.Root>
116
+ );
117
+ },
118
+ );
@@ -1,10 +1,22 @@
1
- import { Box, BoxProps, Text } from "@chakra-ui/react";
2
- import React, { useId, useRef } from "react";
1
+ "use client";
2
+ import {
3
+ Box,
4
+ BoxProps,
5
+ chakra,
6
+ RecipeVariantProps,
7
+ Text,
8
+ } from "@chakra-ui/react";
9
+ import React, { forwardRef, useId, useRef, useState, useEffect } from "react";
3
10
  import { useProgressBar } from "react-aria";
4
11
  import { createTexts, useTranslation } from "..";
5
12
  import { useRotatingLabel } from "./useRotatingLabel";
13
+ import { progressLoaderRecipe } from "../theme/recipes/progress-loader";
14
+ export type ProgressLoaderVariantProps = RecipeVariantProps<
15
+ typeof progressLoaderRecipe
16
+ >;
6
17
 
7
- type ProgressLoaderProps = BoxProps & {
18
+ export type ProgressLoaderProps = BoxProps & {
19
+ children: React.ReactNode;
8
20
  /** The percentage of progress made.
9
21
  *
10
22
  * The value must be between 0 and 100 */
@@ -29,6 +41,29 @@ type ProgressLoaderProps = BoxProps & {
29
41
  labelRotationDelay?: number;
30
42
  };
31
43
 
44
+ /**
45
+ * Custom hook to calculate the total length of an SVG path and progress offset.
46
+ * @param value The percentage of progress made (0-100).
47
+ * @returns A ref for the path element, the calculated path length, and the progress offset.
48
+ */
49
+ const usePathLength = (value: number) => {
50
+ const pathRef = useRef<SVGPathElement>(null);
51
+ const [pathLength, setPathLength] = useState(0);
52
+
53
+ useEffect(() => {
54
+ if (pathRef.current) {
55
+ const totalLength = pathRef.current.getTotalLength();
56
+ setPathLength(totalLength);
57
+ }
58
+ }, []);
59
+
60
+ const progressOffset = ((value - 100) / 100) * pathLength;
61
+
62
+ return { pathRef, pathLength, progressOffset };
63
+ };
64
+
65
+ const ProgressLoaderWrapper = chakra("div", progressLoaderRecipe);
66
+
32
67
  /**
33
68
  * Shows the progress of a loading process.
34
69
  *
@@ -56,79 +91,89 @@ type ProgressLoaderProps = BoxProps & {
56
91
  * <ProgressLoader value={50} aria-label="Fetching your trips..." />
57
92
  * ```
58
93
  */
59
- export const ProgressLoader = ({
60
- value,
61
- label,
62
- labelRotationDelay = 5000,
63
- "aria-label": ariaLabel,
64
- width,
65
- ...rest
66
- }: ProgressLoaderProps) => {
67
- const { t } = useTranslation();
68
- const currentLoadingText = useRotatingLabel({
69
- label,
70
- delay: labelRotationDelay,
71
- });
72
- const { labelProps, progressBarProps } = useProgressBar({
73
- isIndeterminate: value === undefined,
94
+
95
+ export const ProgressLoader = forwardRef<HTMLDivElement, ProgressLoaderProps>(
96
+ ({
74
97
  value,
75
- "aria-label": ariaLabel ?? t(texts.fallbackLabel(value ?? "?")),
76
- });
77
- const pathRef = useRef<SVGPathElement>(null);
78
- const progressPathLength = pathRef.current?.getTotalLength() ?? 0;
79
- const progress = ((value - 100) / 100) * progressPathLength;
80
- const id = useId();
81
- return (
82
- <Box {...progressBarProps} minWidth="100px" width={width} {...rest}>
83
- <Box as="svg" viewBox="0 0 246 78" fill="none">
84
- <Box
85
- as="path"
86
- id={`${id}-start-dot`}
87
- d="M14.0479 44.8251C19.4332 44.8251 23.7988 40.5242 23.7988 35.2187C23.7988 29.9133 19.4332 25.6124 14.0479 25.6124C8.66254 25.6124 4.29688 29.9133 4.29688 35.2187C4.29688 40.5242 8.66254 44.8251 14.0479 44.8251Z"
88
- fill="#FFB466"
89
- />
90
- <Box
91
- as="path"
92
- id={`${id}-track`}
93
- d="M204.911 39.1156C204.911 39.1156 175.012 46.8319 157.651 30.4354C140.29 14.0388 121 21.7547 110.391 47.6529C103.22 65.157 78.9634 67.0859 67.9533 47.6529C59.8376 33.3287 36.125 37.1866 36.125 37.1866"
94
- stroke="coralGreen"
95
- strokeWidth="13.6469"
96
- strokeLinecap="round"
97
- strokeLinejoin="round"
98
- />
99
- <Box
100
- as="path"
101
- id={`${id}-progress`}
102
- d="M204.911 39.1156C204.911 39.1156 175.012 46.8319 157.651 30.4354C140.29 14.0388 121 21.7547 110.391 47.6529C103.22 65.157 78.9634 67.0859 67.9533 47.6529C59.8376 33.3287 36.125 37.1866 36.125 37.1866"
103
- stroke="greenHaze"
104
- strokeWidth="13.6469"
105
- strokeLinecap="round"
106
- strokeLinejoin="round"
107
- strokeDasharray={progressPathLength}
108
- strokeDashoffset={progress}
109
- transition="stroke-dashoffset .2s ease-out"
110
- ref={pathRef as any}
111
- />
112
- <Box
113
- as="path"
114
- id={`${id}-end-dot`}
115
- d="M226.025 44.8251C231.411 44.8251 235.776 40.5242 235.776 35.2187C235.776 29.9133 231.411 25.6124 226.025 25.6124C220.64 25.6124 216.274 29.9133 216.274 35.2187C216.274 40.5242 220.64 44.8251 226.025 44.8251Z"
116
- fill="#688CBA"
117
- />
118
- </Box>
119
- {currentLoadingText && (
120
- <Text
121
- textAlign="center"
122
- marginTop={2}
123
- fontWeight="bold"
124
- {...labelProps}
125
- >
126
- {currentLoadingText}
127
- </Text>
128
- )}
129
- </Box>
130
- );
131
- };
98
+ label,
99
+ labelRotationDelay = 5000,
100
+ "aria-label": ariaLabel,
101
+ width,
102
+ ...rest
103
+ }: ProgressLoaderProps) => {
104
+ const { t } = useTranslation();
105
+ const currentLoadingText = useRotatingLabel({
106
+ label,
107
+ delay: labelRotationDelay,
108
+ });
109
+ const { labelProps, progressBarProps } = useProgressBar({
110
+ isIndeterminate: value === undefined,
111
+ value,
112
+ "aria-label": ariaLabel ?? t(texts.fallbackLabel(value ?? "?")),
113
+ });
114
+ const {
115
+ pathRef,
116
+ pathLength: progressPathLength,
117
+ progressOffset,
118
+ } = usePathLength(value);
119
+
120
+ const id = useId();
121
+
122
+ return (
123
+ <ProgressLoaderWrapper
124
+ {...progressBarProps}
125
+ width={width}
126
+ role="progressbar"
127
+ aria-valuenow={value}
128
+ aria-valuemin={0}
129
+ aria-valuemax={100}
130
+ aria-label={ariaLabel ?? t(texts.fallbackLabel(value ?? "?"))}
131
+ {...rest}
132
+ >
133
+ <chakra.svg as="svg" viewBox="0 0 246 78" fill="none">
134
+ <path
135
+ id={`${id}-start-dot`}
136
+ d="M14.0479 44.8251C19.4332 44.8251 23.7988 40.5242 23.7988 35.2187C23.7988 29.9133 19.4332 25.6124 14.0479 25.6124C8.66254 25.6124 4.29688 29.9133 4.29688 35.2187C4.29688 40.5242 8.66254 44.8251 14.0479 44.8251Z"
137
+ fill="#FFB466"
138
+ />
139
+ <path
140
+ id={`${id}-track`}
141
+ d="M204.911 39.1156C204.911 39.1156 175.012 46.8319 157.651 30.4354C140.29 14.0388 121 21.7547 110.391 47.6529C103.22 65.157 78.9634 67.0859 67.9533 47.6529C59.8376 33.3287 36.125 37.1866 36.125 37.1866"
142
+ strokeWidth="13.6469"
143
+ strokeLinecap="round"
144
+ strokeLinejoin="round"
145
+ />
146
+ <path
147
+ id={`${id}-progress`}
148
+ d="M204.911 39.1156C204.911 39.1156 175.012 46.8319 157.651 30.4354C140.29 14.0388 121 21.7547 110.391 47.6529C103.22 65.157 78.9634 67.0859 67.9533 47.6529C59.8376 33.3287 36.125 37.1866 36.125 37.1866"
149
+ strokeWidth="13.6469"
150
+ strokeLinecap="round"
151
+ strokeLinejoin="round"
152
+ strokeDasharray={progressPathLength}
153
+ strokeDashoffset={progressOffset}
154
+ style={{ transition: "stroke-dashoffset .2s ease-out" }}
155
+ ref={pathRef}
156
+ />
157
+ <path
158
+ id={`${id}-end-dot`}
159
+ d="M226.025 44.8251C231.411 44.8251 235.776 40.5242 235.776 35.2187C235.776 29.9133 231.411 25.6124 226.025 25.6124C220.64 25.6124 216.274 29.9133 216.274 35.2187C216.274 40.5242 220.64 44.8251 226.025 44.8251Z"
160
+ fill="#688CBA"
161
+ />
162
+ </chakra.svg>
163
+ {currentLoadingText && (
164
+ <Text
165
+ textAlign="center"
166
+ marginTop={2}
167
+ fontWeight="bold"
168
+ {...labelProps}
169
+ >
170
+ {currentLoadingText}
171
+ </Text>
172
+ )}
173
+ </ProgressLoaderWrapper>
174
+ );
175
+ },
176
+ );
132
177
 
133
178
  const texts = createTexts({
134
179
  fallbackLabel: (value) => ({
@@ -1,22 +1,97 @@
1
+ "use client";
2
+ import { skeletonRecipe } from "@/theme/recipes/skeleton";
3
+ import type {
4
+ SkeletonProps as ChakraSkeletonProps,
5
+ CircleProps,
6
+ RecipeVariantProps,
7
+ } from "@chakra-ui/react";
1
8
  import {
2
- BoxProps,
3
- forwardRef,
4
9
  Skeleton as ChakraSkeleton,
10
+ Circle,
11
+ Stack,
12
+ useRecipe,
5
13
  } from "@chakra-ui/react";
6
- import React from "react";
7
-
8
- export type SkeletonProps = BoxProps & {
9
- isLoaded?: boolean;
10
- };
11
- /**
12
- * Skeleton renders a loading animation for a given box. It works great as a placeholder to avoid layout shifts.
13
- */
14
- export const Skeleton = forwardRef<SkeletonProps, "div">((props, ref) => (
15
- <ChakraSkeleton
16
- {...props}
17
- ref={ref}
18
- aria-busy="true"
19
- aria-hidden="true"
20
- role="alert"
21
- />
22
- ));
14
+ import * as React from "react";
15
+ import { forwardRef } from "react";
16
+
17
+ type SkeletonVariantProps = RecipeVariantProps<typeof skeletonRecipe>;
18
+
19
+ export type SkeletonCircleProps = ChakraSkeletonProps &
20
+ SkeletonVariantProps & {
21
+ size?: CircleProps["size"];
22
+ };
23
+
24
+ export const SkeletonCircle = React.forwardRef<
25
+ HTMLDivElement,
26
+ SkeletonCircleProps
27
+ >(function SkeletonCircle(props, ref) {
28
+ const recipe = useRecipe({ recipe: skeletonRecipe });
29
+
30
+ const [recipeProps, restProps] = recipe.splitVariantProps({
31
+ loading: true,
32
+ variant: "pulse",
33
+ ...props,
34
+ });
35
+
36
+ const { size, css, ...rest } = restProps;
37
+
38
+ return (
39
+ <Circle size={size} asChild ref={ref}>
40
+ <ChakraSkeleton css={{ ...recipe(recipeProps), ...css }} {...rest} />
41
+ </Circle>
42
+ );
43
+ });
44
+
45
+ export type SkeletonTextProps = ChakraSkeletonProps &
46
+ SkeletonVariantProps & {
47
+ noOfLines?: number;
48
+ };
49
+
50
+ export const SkeletonText = forwardRef<HTMLDivElement, SkeletonTextProps>(
51
+ function SkeletonText(props, ref) {
52
+ const recipe = useRecipe({ recipe: skeletonRecipe });
53
+ const [recipeProps, restProps] = recipe.splitVariantProps({
54
+ loading: true,
55
+ variant: "pulse",
56
+ ...props,
57
+ });
58
+ const { noOfLines = 3, height = "0.5rem", gap, css, ...rest } = restProps;
59
+
60
+ return (
61
+ <Stack gap={gap} width="full" ref={ref}>
62
+ {Array.from({ length: noOfLines }).map((_, index) => (
63
+ <ChakraSkeleton
64
+ height={height}
65
+ css={{ ...recipe(recipeProps), ...css }}
66
+ key={index}
67
+ _last={{ maxW: "80%" }}
68
+ {...rest}
69
+ />
70
+ ))}
71
+ </Stack>
72
+ );
73
+ },
74
+ );
75
+
76
+ export type SkeletonProps = ChakraSkeletonProps & SkeletonVariantProps;
77
+
78
+ export const Skeleton = forwardRef<HTMLDivElement, SkeletonTextProps>(
79
+ function SkeletonText(props, ref) {
80
+ const recipe = useRecipe({ recipe: skeletonRecipe });
81
+ const [recipeProps, restProps] = recipe.splitVariantProps({
82
+ loading: true,
83
+ variant: "pulse",
84
+ ...props,
85
+ });
86
+
87
+ const { css, ...rest } = restProps;
88
+
89
+ return (
90
+ <ChakraSkeleton
91
+ ref={ref}
92
+ css={{ ...recipe(recipeProps), ...css }}
93
+ {...rest}
94
+ />
95
+ );
96
+ },
97
+ );
@@ -10,5 +10,3 @@ export * from "./LightSpinner";
10
10
  export * from "./ProgressBar";
11
11
  export * from "./ProgressLoader";
12
12
  export * from "./Skeleton";
13
- export * from "./SkeletonCircle";
14
- export * from "./SkeletonText";
@@ -1,3 +1,4 @@
1
+ "use client";
1
2
  import { useEffect, useState } from "react";
2
3
 
3
4
  // Lifted from remix-utils
@@ -1,5 +1,6 @@
1
- import { useInterval } from "@chakra-ui/react";
1
+ "use client";
2
2
  import { useMemo, useState } from "react";
3
+ import { useInterval } from "usehooks-ts";
3
4
 
4
5
  type UseRotatingLabelArgs = {
5
6
  label?: string | string[];