@vygruppen/spor-react 11.3.9 → 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 +245 -0
  4. package/dist/index.d.mts +2552 -8319
  5. package/dist/index.d.ts +2552 -8319
  6. package/dist/index.js +9609 -8607
  7. package/dist/index.js.map +1 -1
  8. package/dist/index.mjs +9487 -8454
  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 -100
  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,189 +1,102 @@
1
+ "use client";
1
2
  import {
2
- Box,
3
- BoxProps,
4
- chakra,
5
- Flex,
6
- forwardRef,
7
- ResponsiveValue,
8
- useMultiStyleConfig,
3
+ PopoverRootProps,
4
+ usePopoverContext,
5
+ Portal,
6
+ Popover as ChakraPopover,
9
7
  } from "@chakra-ui/react";
10
8
  import {
11
9
  DropdownDownFill18Icon,
12
10
  DropdownDownFill24Icon,
13
11
  } from "@vygruppen/spor-icon-react";
14
- import React, { useEffect, useRef, useState } from "react";
15
- import { AriaPositionProps, useButton, useOverlayTrigger } from "react-aria";
16
- import { useOverlayTriggerState } from "react-stately";
17
- import { StaticCard } from "..";
18
- import { Dialog } from "./Dialog";
19
- import { Popover } from "./Popover";
12
+ import React, { forwardRef, ReactNode } from "react";
13
+ import { Button, ButtonProps, StaticCard, StaticCardProps } from "..";
20
14
 
21
- type CardSelectProps = BoxProps & {
15
+ export const CardSelect = ({ size = "md", ...props }: PopoverRootProps) => {
16
+ return <ChakraPopover.Root size={size} {...props} />;
17
+ };
18
+
19
+ export const CardSelectContent = forwardRef<HTMLDivElement, StaticCardProps>(
20
+ ({ children, ...props }, ref) => {
21
+ return (
22
+ <Portal>
23
+ <ChakraPopover.Positioner>
24
+ <ChakraPopover.Content ref={ref} padding={0} bg="none">
25
+ <ChakraPopover.Body {...props}>
26
+ <StaticCard
27
+ p="2"
28
+ bg="bg"
29
+ border="sm"
30
+ borderColor="floating.outline"
31
+ {...props}
32
+ >
33
+ {children}
34
+ </StaticCard>
35
+ </ChakraPopover.Body>
36
+ </ChakraPopover.Content>
37
+ </ChakraPopover.Positioner>
38
+ </Portal>
39
+ );
40
+ },
41
+ );
42
+
43
+ export type CardSelectTriggerProps = {
22
44
  /** The design of the trigger button.
23
45
  *
24
46
  * - `ghost` is a transparent button with text
25
- * - `base` is a button with a border and text
47
+ * - `core` is a button with a border and text
26
48
  * - `floating` is a button with a drop shadow (like a card) and text
27
49
  */
28
- variant: "base" | "ghost" | "floating";
29
- /** The size of the trigger button */
30
- size: "sm" | "md" | "lg";
31
- /** Whether the card select is open / active, if controlled */
32
- isOpen?: boolean;
33
- /** The default state of the card select. Defaults to false (closed) */
34
- defaultOpen?: boolean;
35
- /** Callback for when the card select opens or closes. */
36
- onToggle?: (isOpen: boolean) => void;
50
+ variant?: "core" | "ghost" | "floating";
37
51
  /** An optional trigger button icon, rendered to the left of the label */
38
- icon?: React.ReactNode;
39
- /** The content of the card select */
40
- children: React.ReactNode;
41
- /** The horizontalOffset of the popover card */
42
- crossOffset?: number;
43
- /** The position of the popover card */
44
- placement?: AriaPositionProps["placement"];
52
+ icon?: ReactNode;
45
53
  /** Whether or not to show the chevron. Defaults to true */
46
54
  withChevron?: boolean;
47
- /** Defaults to normal */
48
- fontWeight?: ResponsiveValue<"normal" | "bold">;
49
- } & (
50
- | {
51
- /** The text label of the trigger button */
52
- label: string;
53
- }
54
- | {
55
- /** Accessible label for the trigger button */
56
- "aria-label": string;
57
- }
58
- );
55
+ } & Omit<ButtonProps, "variant" | "rightIcon" | "leftIcon">;
59
56
 
60
- /**
61
- * A card select component.
62
- *
63
- * This component consists of a trigger button and a card select popover. The trigger button has several different variants and sizes, and can have an optional icon.
64
- *
65
- * ```tsx
66
- * <CardSelect label="Languages" variant="card" size="md">
67
- * <LanguageSettings />
68
- * </CardSelect>
69
- * ```
70
- *
71
- * @see https://spor.vy.no/components/card-select
72
- *
73
- */
74
- export const CardSelect = forwardRef<CardSelectProps, "button">(
57
+ const bgActiveStyleMap = {
58
+ core: "core.surface.active",
59
+ ghost: "ghost.surface.active",
60
+ floating: "floating.surface.active",
61
+ };
62
+
63
+ export const CardSelectTrigger = forwardRef<
64
+ HTMLButtonElement,
65
+ CardSelectTriggerProps
66
+ >(
75
67
  (
76
- {
77
- variant,
78
- size,
79
- isOpen: externalIsOpen,
80
- defaultOpen = false,
81
- onToggle,
82
- icon,
83
- children,
84
- width = "fit-content",
85
- crossOffset = 0,
86
- placement = "bottom",
87
- withChevron = true,
88
- fontWeight = "normal",
89
- ...props
90
- },
91
- externalRef,
68
+ { icon, variant = "core", withChevron = true, size, children, ...props },
69
+ ref,
92
70
  ) => {
93
- const label = "label" in props ? props.label : props["aria-label"];
94
- const internalRef = useRef<HTMLButtonElement>(null);
95
- const triggerRef = (externalRef ??
96
- internalRef) as React.RefObject<HTMLButtonElement>;
97
-
98
- const state = useOverlayTriggerState({
99
- isOpen: externalIsOpen,
100
- onOpenChange: onToggle,
101
- defaultOpen,
102
- });
103
- const { triggerProps, overlayProps } = useOverlayTrigger(
104
- { type: "dialog" },
105
- state,
106
- triggerRef,
107
- );
108
-
109
- const { buttonProps } = useButton(triggerProps, triggerRef);
110
-
111
- const styles = useMultiStyleConfig("CardSelect", {
112
- variant,
113
- size,
114
- });
115
- useForceRerender(state.isOpen);
116
-
117
71
  const ChevronIcon =
118
72
  size === "sm" ? DropdownDownFill18Icon : DropdownDownFill24Icon;
119
73
 
74
+ const { open } = usePopoverContext();
75
+
120
76
  return (
121
- <Box {...props}>
122
- <chakra.button
123
- type="button"
124
- ref={triggerRef}
125
- sx={styles.trigger}
126
- aria-label={label}
127
- {...buttonProps}
128
- width={width}
129
- data-attachable
130
- >
131
- <Flex gap={1.5} alignItems="center">
132
- {icon}
133
- <Box as="span" display={props["aria-label"] ? "none" : "inline"}>
134
- {label}
135
- </Box>
136
- {withChevron ? (
77
+ <ChakraPopover.Trigger asChild ref={ref}>
78
+ <Button
79
+ leftIcon={icon}
80
+ variant={
81
+ variant === "core"
82
+ ? "tertiary"
83
+ : (variant as ButtonProps["variant"])
84
+ }
85
+ size={size}
86
+ bg={open ? bgActiveStyleMap[variant] : undefined}
87
+ rightIcon={
88
+ withChevron ? (
137
89
  <ChevronIcon
138
- transform={state.isOpen ? "rotate(180deg)" : "none"}
90
+ transform={open ? "rotate(180deg)" : undefined}
91
+ transition="transform 0.3s"
139
92
  />
140
- ) : null}
141
- </Flex>
142
- </chakra.button>
143
- {state.isOpen && (
144
- <Popover
145
- state={state}
146
- triggerRef={triggerRef}
147
- offset={size === "sm" ? 6 : 12}
148
- crossOffset={crossOffset}
149
- placement={placement}
150
- containerPadding={0}
151
- >
152
- <StaticCard
153
- colorScheme="white"
154
- size="md"
155
- fontSize={"xs"}
156
- border={"sm"}
157
- borderColor={"silver"}
158
- sx={styles.card}
159
- {...overlayProps}
160
- maxWidth={(triggerRef.current?.clientWidth ?? 1) * 2}
161
- >
162
- <Dialog aria-label={label}>{children}</Dialog>
163
- </StaticCard>
164
- </Popover>
165
- )}
166
- </Box>
93
+ ) : null
94
+ }
95
+ {...props}
96
+ >
97
+ {children}
98
+ </Button>
99
+ </ChakraPopover.Trigger>
167
100
  );
168
101
  },
169
102
  );
170
-
171
- /**
172
- * Hold my beer.
173
- *
174
- * This is a workaround for a "bug" in react-aria where the overlay doesn't
175
- * calculate the placement correctly for some reason.
176
- *
177
- * This is a hack, which forces React to rerender the component one extra time
178
- * after the state changes from closed to open.
179
- *
180
- * There is probably a better way to do this, but I could not come up with one.
181
- */
182
- function useForceRerender(shouldRerender: boolean) {
183
- const [_, update] = useState(false);
184
- useEffect(() => {
185
- if (shouldRerender) {
186
- update((x) => !x);
187
- }
188
- }, [shouldRerender]);
189
- }
@@ -1,11 +1,19 @@
1
+ import { checkboxSlotRecipe } from "@/theme/slot-recipes/checkbox";
1
2
  import {
2
3
  Checkbox as ChakraCheckbox,
3
- CheckboxProps as ChakraCheckboxProps,
4
- forwardRef,
4
+ RecipeVariantProps,
5
5
  } from "@chakra-ui/react";
6
- import React from "react";
6
+ import * as React from "react";
7
+ import { PropsWithChildren } from "react";
8
+
9
+ type CheckboxVariantProps = RecipeVariantProps<typeof checkboxSlotRecipe>;
10
+
11
+ type CheckboxProps = ChakraCheckbox.RootProps &
12
+ PropsWithChildren<CheckboxVariantProps> & {
13
+ inputProps?: React.InputHTMLAttributes<HTMLInputElement>;
14
+ rootRef?: React.Ref<HTMLLabelElement>;
15
+ };
7
16
 
8
- export type CheckboxProps = ChakraCheckboxProps;
9
17
  /**
10
18
  * Creates a checkbox.
11
19
  *
@@ -15,8 +23,24 @@ export type CheckboxProps = ChakraCheckboxProps;
15
23
  * <Checkbox>Accept the terms</Checkbox>
16
24
  * ```
17
25
  *
18
- * Unlike regular inputs, it doesn't require its own `FormControl`.
26
+ * Unlike regular inputs, it doesn't require its own `Field`.
19
27
  *
20
28
  * You can group several of these together with a `CheckboxGroup`.
21
29
  */
22
- export const Checkbox = ChakraCheckbox;
30
+
31
+ export const Checkbox = React.forwardRef<HTMLInputElement, CheckboxProps>(
32
+ (props, ref) => {
33
+ const { children, inputProps, rootRef, ...rest } = props;
34
+ return (
35
+ <ChakraCheckbox.Root ref={rootRef} {...rest}>
36
+ <ChakraCheckbox.HiddenInput ref={ref} {...inputProps} />
37
+ <ChakraCheckbox.Control>
38
+ <ChakraCheckbox.Indicator />
39
+ </ChakraCheckbox.Control>
40
+ {children != null && (
41
+ <ChakraCheckbox.Label>{children}</ChakraCheckbox.Label>
42
+ )}
43
+ </ChakraCheckbox.Root>
44
+ );
45
+ },
46
+ );
@@ -2,19 +2,25 @@ import {
2
2
  CheckboxGroup as ChakraCheckboxGroup,
3
3
  CheckboxGroupProps as ChakraCheckboxGroupProps,
4
4
  Stack,
5
- StackDirection,
6
5
  } from "@chakra-ui/react";
7
- import React from "react";
6
+ import React, { forwardRef } from "react";
8
7
 
9
8
  export type CheckboxGroupProps = Exclude<
10
9
  ChakraCheckboxGroupProps,
11
- "colorScheme" | "size" | "variant"
12
- > & { direction?: StackDirection };
10
+ "colorPalette" | "size" | "variant"
11
+ > & {
12
+ /* Defaults to row */
13
+ direction?: "row" | "column";
14
+ children: React.ReactNode;
15
+ /* Defaults to 1 */
16
+ gap?: number | string;
17
+ [key: string]: any;
18
+ };
13
19
  /**
14
20
  * Used to group several checkboxes together. You can pass the default value, as well as whether or not they're all disabled
15
21
  *
16
22
  * ```tsx
17
- * <CheckboxGroup isDisabled defaultValue={['red', 'blue']}>
23
+ * <CheckboxGroup disabled defaultValue={['red', 'blue']}>
18
24
  * <Checkbox value="red">Red</Checkbox>
19
25
  * <Checkbox value="blue">Blue</Checkbox>
20
26
  * <Checkbox value="green">Green</Checkbox>
@@ -30,14 +36,17 @@ export type CheckboxGroupProps = Exclude<
30
36
  * <Checkbox>First Class</Checkbox>
31
37
  * </CheckboxGroup>
32
38
  */
33
- export const CheckboxGroup = ({
34
- direction = "row",
35
- children,
36
- ...props
37
- }: CheckboxGroupProps) => {
38
- return (
39
- <ChakraCheckboxGroup {...props}>
40
- <Stack direction={direction}>{children}</Stack>
41
- </ChakraCheckboxGroup>
42
- );
43
- };
39
+
40
+ export const CheckboxGroup = forwardRef<HTMLDivElement, CheckboxGroupProps>(
41
+ (props, ref) => {
42
+ const { direction = "row", children, gap = 1, ...rest } = props;
43
+
44
+ return (
45
+ <ChakraCheckboxGroup ref={ref} {...rest}>
46
+ <Stack direction={direction} gap={gap}>
47
+ {children}
48
+ </Stack>
49
+ </ChakraCheckboxGroup>
50
+ );
51
+ },
52
+ );
@@ -1,17 +1,20 @@
1
+ "use client";
2
+ import { choiceChipRecipe } from "@/theme/recipes/choice-chip";
1
3
  import {
2
4
  chakra,
3
- forwardRef,
5
+ RecipeVariantProps,
6
+ Span,
4
7
  useCheckbox,
5
- useMultiStyleConfig,
6
8
  } from "@chakra-ui/react";
7
- import { dataAttr } from "@chakra-ui/utils";
8
9
  import { CloseOutline24Icon } from "@vygruppen/spor-icon-react";
9
- import React, { ChangeEvent, useId } from "react";
10
+ import React, { ChangeEvent, PropsWithChildren, useId } from "react";
10
11
 
11
- export type ChoiceChipProps = {
12
+ type ChoiceChipVariantProps = RecipeVariantProps<typeof choiceChipRecipe>;
13
+
14
+ export type ChoiceChipProps = PropsWithChildren<ChoiceChipVariantProps> & {
12
15
  onChange?: (value: ChangeEvent<HTMLInputElement>) => void;
13
- isChecked?: boolean;
14
- isDisabled?: boolean;
16
+ checked?: boolean;
17
+ disabled?: boolean;
15
18
  defaultChecked?: boolean;
16
19
  /** The button text */
17
20
  children: React.ReactNode;
@@ -19,10 +22,10 @@ export type ChoiceChipProps = {
19
22
  default: React.ReactNode;
20
23
  checked: React.ReactNode;
21
24
  };
22
- size?: "xs" | "sm" | "md" | "lg";
23
25
  chipType?: "icon" | "choice" | "filter";
24
- variant?: "base" | "accent" | "floating";
26
+ "aria-label"?: string;
25
27
  };
28
+
26
29
  /**
27
30
  * Choice chips are checkboxes that look like selectable buttons.
28
31
  *
@@ -44,82 +47,60 @@ export type ChoiceChipProps = {
44
47
  * <ChoiceChip chipType="filter" icon={<Bus24Icon />}>Bus</ChoiceChip>
45
48
  * </Stack>
46
49
  *
47
- * There are also three different variants - `base`, `accent` and `floating`.
50
+ * There are also three different variants - `core`, `accent` and `floating`.
48
51
  *
49
52
  * ```tsx
50
53
  * <Stack flexDirection="row">
51
- * <ChoiceChip variant="base">Bus</ChoiceChip>
54
+ * <ChoiceChip variant="core">Bus</ChoiceChip>
52
55
  * <ChoiceChip variant="accent">Boat</ChoiceChip>
53
56
  * <ChoiceChip variant="floating">Train</ChoiceChip>
54
57
  * </Stack>
55
58
  * ```
56
59
  */
57
- export const ChoiceChip = forwardRef(
58
- (
59
- {
60
- children,
61
- icon,
62
- isDisabled,
63
- size = "sm",
64
- chipType = "choice",
65
- variant = "base",
66
- ...props
67
- }: ChoiceChipProps,
68
- ref,
69
- ) => {
70
- const {
71
- state,
72
- getInputProps,
73
- getCheckboxProps,
74
- getRootProps,
75
- getLabelProps,
76
- } = useCheckbox(props);
77
- const styles = useMultiStyleConfig("ChoiceChip", {
78
- size,
79
- chipType,
80
- variant,
81
- icon,
82
- hasLabel: chipType !== "icon",
83
- });
84
60
 
85
- const id = `choice-chip-${useId()}`;
61
+ const ChoiceChipStyledDiv = chakra("div", choiceChipRecipe);
86
62
 
87
- return (
88
- <chakra.label
89
- {...getRootProps()}
90
- htmlFor={id}
91
- aria-label={String(children)}
92
- >
93
- <chakra.input
94
- {...getInputProps({}, ref)}
95
- id={id}
96
- disabled={isDisabled || state.isDisabled}
97
- />
98
- <chakra.div
99
- {...getLabelProps()}
100
- __css={styles.container}
101
- data-checked={dataAttr(state.isChecked)}
102
- data-hover={dataAttr(state.isHovered)}
103
- data-focus={dataAttr(state.isFocused)}
104
- data-active={dataAttr(state.isActive)}
105
- data-disabled={dataAttr(isDisabled || state.isDisabled)}
106
- >
107
- {icon && (
108
- <chakra.span __css={styles.icon}>
109
- {state.isChecked ? icon.checked : icon.default}
110
- </chakra.span>
111
- )}
112
- {chipType !== "icon" && (
113
- <chakra.span __css={styles.label} {...getCheckboxProps()}>
114
- {children}
115
- </chakra.span>
116
- )}
63
+ export const ChoiceChip = ({
64
+ children,
65
+ icon,
66
+ size = "sm",
67
+ chipType = "choice",
68
+ variant = "core",
69
+ ...props
70
+ }: ChoiceChipProps) => {
71
+ const {
72
+ getControlProps,
73
+ disabled,
74
+ getLabelProps,
75
+ getHiddenInputProps,
76
+ setChecked,
77
+ checked,
78
+ } = useCheckbox(props);
117
79
 
118
- {chipType === "filter" && state.isChecked && (
119
- <CloseOutline24Icon marginLeft={1.5} />
120
- )}
121
- </chakra.div>
122
- </chakra.label>
123
- );
124
- },
125
- );
80
+ return (
81
+ <chakra.label
82
+ {...getLabelProps()}
83
+ aria-label={props["aria-label"] ?? String(children)}
84
+ >
85
+ <chakra.input
86
+ {...getHiddenInputProps()}
87
+ disabled={disabled}
88
+ defaultChecked={checked}
89
+ value={checked ? "on" : "off"}
90
+ type="checkbox"
91
+ aria-checked={checked}
92
+ onClick={() => {
93
+ setChecked(!checked);
94
+ }}
95
+ />
96
+ <ChoiceChipStyledDiv {...getControlProps()} size={size} variant={variant}>
97
+ {icon && <Span>{checked ? icon.checked : icon.default}</Span>}
98
+ {chipType !== "icon" && <Span>{children}</Span>}
99
+
100
+ {chipType === "filter" && checked && (
101
+ <CloseOutline24Icon marginLeft={1.5} />
102
+ )}
103
+ </ChoiceChipStyledDiv>
104
+ </chakra.label>
105
+ );
106
+ };