@vygruppen/spor-react 11.3.10 → 12.0.1

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 +33 -11
  2. package/.turbo/turbo-typegen.log +22 -0
  3. package/CHANGELOG.md +247 -0
  4. package/dist/index.d.mts +2589 -8303
  5. package/dist/index.d.ts +2589 -8303
  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 +23 -15
  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 +70 -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 +36 -21
  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,41 +1,56 @@
1
+ "use client";
2
+
3
+ import React, { forwardRef } from "react";
1
4
  import {
2
5
  Breadcrumb as ChakraBreadcrumb,
3
- BreadcrumbItem as ChakraBreadcrumbItem,
6
+ BreadcrumbRootProps,
4
7
  BreadcrumbLink as ChakraBreadcrumbLink,
5
- BreadcrumbProps as ChakraBreadcrumbProps,
6
- useColorModeValue,
8
+ BreadcrumbCurrentLink as ChakraBreadcrumbCurrentLink,
9
+ BreadcrumbEllipsis as ChakraBreadcrumbEllipsis,
7
10
  } from "@chakra-ui/react";
8
11
  import { DropdownRightFill18Icon } from "@vygruppen/spor-icon-react";
9
- import React from "react";
10
-
11
- type BreadcrumbProps = Omit<ChakraBreadcrumbProps, "variant"> & {
12
- variant?: "base" | "ghost";
13
- };
14
12
  /**
15
13
  * A breadcrumb component.
16
14
  *
17
15
  * Used to create customizable breadcrumbs.
18
- *
16
+ * BreadcrumbCurrentLink is used to set the last breadcrumb.
17
+ * BreadcrumbLink is used to set the other breadcrumbs.
19
18
  * ```tsx
20
19
  * <Breadcrumb>
21
- * <BreadcrumbItem>
22
20
  * <BreadcrumbLink href="/">Home</BreadcrumbLink>
23
- * </BreadcrumbItem>
24
- * <BreadcrumbItem isCurrentPage={true}>
25
- * <BreadcrumbLink href="/about">About</BreadcrumbLink>
26
- * </BreadcrumbItem>
21
+ * <BreadcrumbLink href="/Breadcrumb">Breadcrumb</BreadcrumbLink>
22
+ * <BreadcrumbCurrentLink href="/about">About</BreadcrumbCurrentLink>
27
23
  * </Breadcrumb>
28
24
  * ```
29
25
  */
30
- export const Breadcrumb = (props: BreadcrumbProps) => {
31
- const iconColor = useColorModeValue("blackAlpha.400", "whiteAlpha.400");
32
- return (
33
- <ChakraBreadcrumb
34
- separator={<DropdownRightFill18Icon color={iconColor} />}
35
- {...props}
36
- />
37
- );
38
- };
26
+ export const Breadcrumb = forwardRef<HTMLDivElement, BreadcrumbRootProps>(
27
+ ({ children, ...props }, ref) => {
28
+ const validChildren = React.Children.toArray(children).filter(
29
+ React.isValidElement,
30
+ );
31
+
32
+ return (
33
+ <ChakraBreadcrumb.Root ref={ref} {...props}>
34
+ <ChakraBreadcrumb.List>
35
+ {validChildren.map((child, index) => {
36
+ const isLast = index === validChildren.length - 1;
37
+ return (
38
+ <React.Fragment key={index}>
39
+ <ChakraBreadcrumb.Item>{child}</ChakraBreadcrumb.Item>
40
+ {!isLast && (
41
+ <ChakraBreadcrumb.Separator aria-hidden="true">
42
+ <DropdownRightFill18Icon />
43
+ </ChakraBreadcrumb.Separator>
44
+ )}
45
+ </React.Fragment>
46
+ );
47
+ })}
48
+ </ChakraBreadcrumb.List>
49
+ </ChakraBreadcrumb.Root>
50
+ );
51
+ },
52
+ );
39
53
 
40
- export const BreadcrumbItem = ChakraBreadcrumbItem;
41
54
  export const BreadcrumbLink = ChakraBreadcrumbLink;
55
+ export const BreadcrumbCurrentLink = ChakraBreadcrumbCurrentLink;
56
+ export const BreadcrumbEllipsis = ChakraBreadcrumbEllipsis;
@@ -1,41 +1,41 @@
1
1
  import {
2
2
  Box,
3
3
  Center,
4
- ButtonProps as ChakraButtonProps,
4
+ Button as ChakraButton,
5
5
  Flex,
6
- forwardRef,
7
- SpaceProps,
8
- useButtonGroup,
9
- useStyleConfig,
6
+ Span,
7
+ type ButtonProps as ChakraButtonProps,
8
+ type RecipeVariantProps,
10
9
  } from "@chakra-ui/react";
11
- import React from "react";
10
+ import React, { forwardRef, PropsWithChildren } from "react";
12
11
  import { createTexts, useTranslation } from "../i18n";
13
12
  import { ColorInlineLoader } from "../loader";
13
+ import { buttonRecipe } from "../theme/recipes/button";
14
+
15
+ export type ButtonVariantProps = RecipeVariantProps<typeof buttonRecipe>;
14
16
 
15
17
  export type ButtonProps = Exclude<
16
18
  ChakraButtonProps,
17
- "colorScheme" | "size" | "variant"
18
- > & {
19
- /**
20
- * The size of the button.
21
- *
22
- * Defaults to "md"
23
- * */
24
- size?: "xs" | "sm" | "md" | "lg";
25
- /** The different variants of a button
26
- *
27
- * Defaults to "primary".
28
- *
29
- * "control" is deprecated, and will be removed in a future version
30
- */
31
- variant?:
32
- | "control"
33
- | "primary"
34
- | "secondary"
35
- | "tertiary"
36
- | "ghost"
37
- | "floating";
38
- };
19
+ "size" | "variant" | "colorPalette"
20
+ > &
21
+ PropsWithChildren<ButtonVariantProps> & {
22
+ /* Boolean value for loading state */
23
+ loading?: boolean;
24
+ /* You may display a different loading text */
25
+ loadingText?: React.ReactNode;
26
+ /* Display icon to the left */
27
+ leftIcon?: React.ReactNode;
28
+ /* Display icon to the right */
29
+ rightIcon?: React.ReactNode;
30
+ /* "primary" | "secondary" | "tertiary" | "ghost" | "floating". Defaults to primary. */
31
+ variant: "primary" | "secondary" | "tertiary" | "ghost" | "floating";
32
+ /* "lg" | "md" | "sm" | "xs". Defaults to md. */
33
+ size?: "lg" | "md" | "sm" | "xs";
34
+ /* Link to a downloadable resource. */
35
+ download?: string;
36
+ /* Use this to specify a path combined with as="a" */
37
+ href?: string;
38
+ };
39
39
  /**
40
40
  * Buttons are used to trigger actions.
41
41
  *
@@ -63,86 +63,67 @@ export type ButtonProps = Exclude<
63
63
  *
64
64
  * @see https://spor.vy.no/components/button
65
65
  */
66
- export const Button = forwardRef<ButtonProps, "button">((props, ref) => {
67
- const {
68
- as = "button",
69
- type = "button",
70
- fontWeight,
71
- size,
72
- children,
73
- isLoading,
74
- isDisabled,
75
- leftIcon,
76
- rightIcon,
77
- sx,
78
- ...rest
79
- } = props;
80
- const ariaLabel = useCorrectAriaLabel(props);
81
- const buttonGroup = useButtonGroup();
82
- const finalSize = (size ?? buttonGroup?.size ?? "md") as Required<
83
- ButtonProps["size"]
84
- >;
85
- const styles = useStyleConfig("Button", {
86
- ...buttonGroup,
87
- ...rest,
88
- size: finalSize,
89
- leftIcon,
90
- rightIcon,
91
- });
92
66
 
93
- // We want to explicitly allow to override the fontWeight prop
94
- if (fontWeight) {
95
- styles.fontWeight = fontWeight;
96
- }
67
+ export const Button = forwardRef<HTMLButtonElement, ButtonProps>(
68
+ (props, ref) => {
69
+ const {
70
+ loading,
71
+ disabled,
72
+ loadingText,
73
+ variant = "primary",
74
+ size = "md",
75
+ leftIcon,
76
+ rightIcon,
77
+ type = "button",
78
+ children,
79
+ ...rest
80
+ } = props;
81
+ const ariaLabel = useCorrectAriaLabel(props);
82
+
83
+ const buttonContent = (
84
+ <>
85
+ {leftIcon}
86
+ {children}
87
+ {rightIcon && <Span marginLeft="auto">{rightIcon}</Span>}
88
+ </>
89
+ );
97
90
 
98
- return (
99
- <Box
100
- {...rest}
101
- as={as}
102
- type={type}
103
- sx={{ ...styles, ...sx }}
104
- ref={ref}
105
- aria-label={ariaLabel}
106
- aria-busy={isLoading}
107
- disabled={isDisabled || isLoading}
108
- position="relative"
109
- fontFamily={"Vy Sans"}
110
- >
111
- {isLoading && (
112
- <Center position="absolute" right={0} left={0} top={1} bottom={0}>
113
- <ColorInlineLoader
114
- maxWidth={getLoaderWidth(finalSize)}
115
- width="80%"
116
- marginX={2}
117
- marginY={2}
118
- />
119
- </Center>
120
- )}
121
- <Flex
122
- gap={1}
123
- flex={1}
124
- alignItems="center"
125
- justifyContent={rightIcon ? "space-between" : "center"}
126
- visibility={isLoading ? "hidden" : "visible"}
127
- aria-hidden={isLoading}
91
+ return (
92
+ <ChakraButton
93
+ type={type}
94
+ ref={ref}
95
+ aria-label={ariaLabel}
96
+ aria-busy={loading}
97
+ disabled={disabled || loading}
98
+ position="relative"
99
+ variant={variant}
100
+ size={size}
101
+ {...rest}
128
102
  >
129
- <Flex gap={1} alignItems="center">
130
- {leftIcon}
131
- <Box
132
- visibility={isLoading ? "hidden" : "visible"}
133
- whiteSpace="normal"
134
- textAlign="center"
135
- >
136
- {children}
137
- </Box>
138
- </Flex>
139
- {rightIcon}
140
- </Flex>
141
- </Box>
142
- );
143
- });
103
+ {loading ? (
104
+ <>
105
+ <Flex gap="1" visibility="hidden">
106
+ {buttonContent}
107
+ </Flex>
108
+ <Center position="absolute" right={0} left={0} top={1} bottom={0}>
109
+ <ColorInlineLoader
110
+ maxWidth={getLoaderWidth(size)}
111
+ width="80%"
112
+ marginX={2}
113
+ marginY={2}
114
+ />
115
+ {loadingText && <Box>{loadingText}</Box>}
116
+ </Center>
117
+ </>
118
+ ) : (
119
+ buttonContent
120
+ )}
121
+ </ChakraButton>
122
+ );
123
+ },
124
+ );
144
125
 
145
- function getLoaderWidth(size: Required<ButtonProps["size"]>) {
126
+ function getLoaderWidth(size: ButtonProps["size"]): string {
146
127
  switch (size) {
147
128
  case "xs":
148
129
  return "4rem";
@@ -158,7 +139,7 @@ function getLoaderWidth(size: Required<ButtonProps["size"]>) {
158
139
 
159
140
  function useCorrectAriaLabel(props: ButtonProps): string {
160
141
  const { t } = useTranslation();
161
- if (props.isLoading) {
142
+ if (props.loading) {
162
143
  return String(props.loadingText) ?? t(texts.loadingText);
163
144
  }
164
145
  return props["aria-label"] as string;
@@ -1,13 +1,21 @@
1
+ "use client";
2
+
1
3
  import {
2
- ButtonGroup as ChakraButtonGroup,
3
- ButtonGroupProps as ChakraButtonGroupProps,
4
- forwardRef,
4
+ type GroupProps as ChakraGroupProps,
5
+ Group as ChakraGroup,
6
+ type RecipeVariantProps,
7
+ chakra,
5
8
  } from "@chakra-ui/react";
6
- import React from "react";
9
+ import React, { forwardRef, PropsWithChildren } from "react";
10
+ import { groupRecipe } from "../theme/recipes/group";
11
+
12
+ export type GroupVariantProps = RecipeVariantProps<typeof groupRecipe>;
13
+
14
+ export type ButtonGroupProps = ChakraGroupProps &
15
+ PropsWithChildren<GroupVariantProps>;
7
16
 
8
- export type ButtonGroupProps = ChakraButtonGroupProps;
9
17
  /**
10
- * Group buttons together with a `ButtonGroup`!
18
+ * Used to group or attach buttons together.
11
19
  *
12
20
  * If you have more than one button next to eachother, you might want to add a `ButtonGroup` to group them.
13
21
  *
@@ -18,26 +26,43 @@ export type ButtonGroupProps = ChakraButtonGroupProps;
18
26
  * </ButtonGroup>
19
27
  * ```
20
28
  *
21
- * You can specify the size of all buttons in a group with the `size` prop. You can also set the same variant across all buttons with the `variant` prop.
29
+ *
30
+ * Attach buttons together with the `attached` prop.
22
31
  *
23
32
  * ```tsx
24
- * <ButtonGroup variant="secondary" size="md">
25
- * <Button>Open</Button>
26
- * <Button>Save</Button>
33
+ * <ButtonGroup attached>
34
+ * <Button variant="primary">Open</Button>
35
+ * <IconButton variant="ghost">
36
+ * <SaveIcon aria-label="Save"/>
37
+ * </IconButton>
27
38
  * </ButtonGroup>
28
39
  * ```
29
40
  *
30
- * Finally, you can join several buttons together with the `isAttached` prop.
41
+ * Use the `grow` prop to make the buttons grow to fill the available space.
31
42
  *
32
43
  * ```tsx
33
- * <ButtonGroup variant="secondary" size="md" isAttached>
34
- * <Button>Open</Button>
35
- * <IconButton>
36
- * <SaveIcon aria-label="Save"/>
37
- * </IconButton>
44
+ * <ButtonGroup grow>
45
+ * <Button variant="primary">Open</Button>
46
+ * <Button variant="secondary">Save</Button>
38
47
  * </ButtonGroup>
39
- * ```
40
48
  */
41
- export const ButtonGroup = forwardRef<ButtonGroupProps, "div">((props, ref) => (
42
- <ChakraButtonGroup {...props} ref={ref} />
43
- ));
49
+
50
+ const Group = chakra(ChakraGroup, groupRecipe);
51
+
52
+ export const ButtonGroup = forwardRef<HTMLDivElement, ButtonGroupProps>(
53
+ (props, ref) => {
54
+ const { children, disabled, grow, attached, ...rest } = props;
55
+
56
+ return (
57
+ <Group
58
+ {...rest}
59
+ ref={ref}
60
+ attached={attached}
61
+ grow={grow}
62
+ disabled={disabled}
63
+ >
64
+ {children}
65
+ </Group>
66
+ );
67
+ },
68
+ );
@@ -0,0 +1,82 @@
1
+ import { Clipboard as ChakraClipboard } from "@chakra-ui/react";
2
+ import * as React from "react";
3
+ import { createTexts, useTranslation } from "@/i18n";
4
+ import {
5
+ CheckmarkFill18Icon,
6
+ CopyOutline18Icon,
7
+ } from "@vygruppen/spor-icon-react";
8
+ import { Button, ButtonProps } from "./Button";
9
+ import { Text } from "@/typography";
10
+
11
+ /**
12
+ *
13
+ * Creates a button that copies text to the clipboard.
14
+ *
15
+ * ```tsx
16
+ * <Clipboard value="Some value to be copied">
17
+ * <ClipboardButton />
18
+ * </Clipboard>
19
+ */
20
+
21
+ const ClipboardIcon = React.forwardRef<
22
+ HTMLDivElement,
23
+ ChakraClipboard.IndicatorProps
24
+ >((props, ref) => {
25
+ return (
26
+ <ChakraClipboard.Indicator
27
+ copied={<CheckmarkFill18Icon />}
28
+ {...props}
29
+ ref={ref}
30
+ >
31
+ <CopyOutline18Icon />
32
+ </ChakraClipboard.Indicator>
33
+ );
34
+ });
35
+
36
+ const ClipboardCopyText = React.forwardRef<
37
+ HTMLDivElement,
38
+ ChakraClipboard.IndicatorProps
39
+ >((props, ref) => {
40
+ const { t } = useTranslation();
41
+ return (
42
+ <ChakraClipboard.Indicator
43
+ copied={<Text variant="xs">{t(texts.copied)}</Text>}
44
+ {...props}
45
+ ref={ref}
46
+ >
47
+ <Text variant="xs">{t(texts.copy)}</Text>
48
+ </ChakraClipboard.Indicator>
49
+ );
50
+ });
51
+
52
+ type ClipboardButtonProps = ButtonProps;
53
+
54
+ export const ClipboardButton = React.forwardRef<
55
+ HTMLButtonElement,
56
+ ClipboardButtonProps
57
+ >((props, ref) => {
58
+ return (
59
+ <ChakraClipboard.Trigger asChild>
60
+ <Button ref={ref} size="xs" leftIcon={<ClipboardIcon />} {...props}>
61
+ <ClipboardCopyText />
62
+ </Button>
63
+ </ChakraClipboard.Trigger>
64
+ );
65
+ });
66
+
67
+ export const Clipboard = ChakraClipboard.Root;
68
+
69
+ const texts = createTexts({
70
+ copy: {
71
+ nb: "Kopier",
72
+ nn: "Kopier",
73
+ en: "Copy",
74
+ sv: "Kopiera",
75
+ },
76
+ copied: {
77
+ nb: "Kopiert",
78
+ nn: "Kopiert",
79
+ en: "Copied",
80
+ sv: "Kopierad",
81
+ },
82
+ });
@@ -1,10 +1,11 @@
1
- import { forwardRef } from "@chakra-ui/react";
1
+ "use client";
2
+
2
3
  import {
3
4
  CloseFill18Icon,
4
5
  CloseFill24Icon,
5
6
  CloseFill30Icon,
6
7
  } from "@vygruppen/spor-icon-react";
7
- import React from "react";
8
+ import React, { forwardRef } from "react";
8
9
  import { createTexts, useTranslation } from "../i18n";
9
10
  import { IconButton, IconButtonProps } from "./IconButton";
10
11
 
@@ -25,7 +26,7 @@ export type CloseButtonProps = Omit<
25
26
  * <CloseButton onClick={closeModal} />
26
27
  * ```
27
28
  */
28
- export const CloseButton = forwardRef<CloseButtonProps, "button">(
29
+ export const CloseButton = forwardRef<HTMLButtonElement, CloseButtonProps>(
29
30
  ({ size = "sm", ...props }, ref) => {
30
31
  const { t } = useTranslation();
31
32
  return (
@@ -1,22 +1,27 @@
1
+ "use client";
2
+
1
3
  import {
2
4
  Box,
3
5
  BoxProps,
4
- ComponentWithAs,
5
- forwardRef,
6
- useMultiStyleConfig,
6
+ RecipeVariantProps,
7
+ Text,
8
+ useSlotRecipe,
7
9
  } from "@chakra-ui/react";
8
- import { motion } from "framer-motion";
9
- import React, { useEffect } from "react";
10
+ import React, { forwardRef, PropsWithChildren, useEffect } from "react";
11
+ import { floatingActionButtonSlotRecipe } from "../theme/slot-recipes/floating-action-button";
10
12
 
11
- const MotionBox = motion(Box);
13
+ type FloatingActionButtonVariantProps = RecipeVariantProps<
14
+ typeof floatingActionButtonSlotRecipe
15
+ >;
12
16
 
13
- type FloatingActionButtonProps = BoxProps & {
14
- variant?: "accent" | "base" | "brand";
15
- placement?: "bottom right" | "bottom left" | "top right" | "top left";
16
- icon: React.ReactNode;
17
- children: React.ReactNode;
18
- isTextVisible?: boolean;
19
- };
17
+ type FloatingActionButtonProps = BoxProps &
18
+ PropsWithChildren<FloatingActionButtonVariantProps> & {
19
+ variant?: "accent" | "core" | "brand";
20
+ placement?: "bottom right" | "bottom left" | "top right" | "top left";
21
+ icon: React.ReactNode;
22
+ children: React.ReactNode;
23
+ isTextVisible?: boolean;
24
+ };
20
25
 
21
26
  /**
22
27
  * Creates a floating action button.
@@ -31,8 +36,8 @@ type FloatingActionButtonProps = BoxProps & {
31
36
  * />
32
37
  */
33
38
  export const FloatingActionButton = forwardRef<
34
- FloatingActionButtonProps,
35
- ComponentWithAs<"a" | "button">
39
+ HTMLButtonElement,
40
+ FloatingActionButtonProps
36
41
  >(
37
42
  (
38
43
  {
@@ -65,39 +70,28 @@ export const FloatingActionButton = forwardRef<
65
70
  setIsTextVisible(!!externalIsTextVisible);
66
71
  }, [externalIsTextVisible]);
67
72
 
68
- const style = useMultiStyleConfig("FloatingActionButton", {
73
+ const recipe = useSlotRecipe({ key: "floatingActionButton" });
74
+ const style = recipe({
69
75
  variant,
70
- isTextVisible,
71
76
  placement,
72
77
  });
78
+
73
79
  return (
74
- <MotionBox
75
- __css={style.container}
76
- aria-label={children}
80
+ <Box
81
+ css={style.root}
82
+ as="button"
83
+ aria-label={typeof children === "string" ? children : undefined}
77
84
  ref={ref}
78
85
  {...props}
86
+ aria-expanded={isTextVisible}
79
87
  >
80
- <Box __css={style.icon}>{icon}</Box>
81
- <MotionBox
82
- animate={isTextVisible ? "show" : "hide"}
83
- initial={externalIsTextVisible ? "show" : "hide"}
84
- variants={{
85
- show: {
86
- opacity: 1,
87
- width: "auto",
88
- visibility: "visible",
89
- },
90
- hide: {
91
- opacity: 0,
92
- width: 0,
93
- visibility: "hidden",
94
- },
95
- }}
96
- __css={style.text}
97
- >
98
- {children}
99
- </MotionBox>
100
- </MotionBox>
88
+ <Box css={style.icon}>{icon}</Box>
89
+ {isTextVisible && (
90
+ <Text data-state="open" css={style.text}>
91
+ {children}
92
+ </Text>
93
+ )}
94
+ </Box>
101
95
  );
102
96
  },
103
97
  );