@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,33 +1,26 @@
1
- import { BoxProps, forwardRef, useControllableState } from "@chakra-ui/react";
2
- import React from "react";
3
- import { Input, createTexts, useTranslation } from "..";
1
+ "use client";
2
+ import { useControllableState } from "@chakra-ui/react";
3
+ import React, { forwardRef } from "react";
4
+ import { Input, InputProps, createTexts, useTranslation } from "..";
4
5
  import { AttachedInputs } from "./AttachedInputs";
5
6
  import { CountryCodeSelect } from "./CountryCodeSelect";
6
- import { As } from "@chakra-ui/system";
7
7
 
8
8
  export type CountryCodeAndPhoneNumber = {
9
9
  countryCode: string;
10
10
  nationalNumber: string;
11
11
  };
12
- export type PhoneNumberInputProps = Omit<BoxProps, "onChange"> & {
12
+
13
+ type PhoneNumberInputProps = InputProps & {
13
14
  /** The label. Defaults to a localized version of "Phone number" */
14
15
  label?: string;
15
- /** The root name.
16
- *
17
- * Please note that when specifying the name, the rendered names will be `${name}-country-code` and `${name}-phone-number` unless a name is provided for both countryCode and nationalNumber.
18
- */
19
- name?:
20
- | string
21
- | {
22
- countryCode: string;
23
- nationalNumber: string;
24
- };
25
16
  /** Callback for when the country code or phone number changes */
26
- onChange?: (change: CountryCodeAndPhoneNumber) => void;
17
+ onValueChange?: (change: CountryCodeAndPhoneNumber) => void;
27
18
  /** The optional value of the country code and phone number */
28
19
  value?: CountryCodeAndPhoneNumber;
29
- variant?: "base" | "floating";
30
- isOptional?: boolean;
20
+ /** Returns an extra optional text when true */
21
+ optional?: boolean;
22
+ invalid?: boolean;
23
+ errorText?: string;
31
24
  };
32
25
  /**
33
26
  * A component for entering phone numbers.
@@ -46,80 +39,84 @@ export type PhoneNumberInputProps = Omit<BoxProps, "onChange"> & {
46
39
  * />
47
40
  * ```
48
41
  */
49
- export const PhoneNumberInput = forwardRef<PhoneNumberInputProps, As>(
50
- (
51
- {
52
- label: externalLabel,
53
- name,
54
- value: externalValue,
55
- onChange: externalOnChange,
56
- variant,
57
- isOptional,
58
- ...boxProps
42
+
43
+ export const PhoneNumberInput = forwardRef<
44
+ HTMLInputElement,
45
+ PhoneNumberInputProps
46
+ >((props, ref) => {
47
+ const {
48
+ label: externalLabel,
49
+ value: externalValue,
50
+ onValueChange: externalOnChange,
51
+ variant,
52
+ optional,
53
+ invalid,
54
+ errorText,
55
+ } = props;
56
+
57
+ const { t } = useTranslation();
58
+ const label =
59
+ externalLabel ??
60
+ (optional ? t(texts.phoneNumberOptional) : t(texts.phoneNumber));
61
+
62
+ const [value, onChange] = useControllableState({
63
+ value: externalValue,
64
+ onChange: externalOnChange,
65
+ defaultValue: {
66
+ countryCode: "+47",
67
+ nationalNumber: "",
59
68
  },
60
- ref,
61
- ) => {
62
- const { t } = useTranslation();
63
- const label =
64
- externalLabel ??
65
- (isOptional ? t(texts.phoneNumberOptional) : t(texts.phoneNumber));
66
- const [value, onChange] = useControllableState({
67
- value: externalValue,
68
- onChange: externalOnChange,
69
- defaultValue: {
70
- countryCode: "+47",
71
- nationalNumber: "",
72
- },
69
+ });
70
+
71
+ const handleCountryCodeChange = (details: { value: string[] }) => {
72
+ const countryCode = details.value[0];
73
+ onChange({
74
+ countryCode: countryCode,
75
+ nationalNumber: value.nationalNumber,
73
76
  });
74
- return (
75
- <AttachedInputs {...boxProps}>
77
+ };
78
+
79
+ return (
80
+ <AttachedInputs
81
+ border={invalid ? "1px solid" : "none"}
82
+ borderColor={invalid ? "outline.error" : "none"}
83
+ outline={invalid ? "1px solid" : "none"}
84
+ outlineColor={invalid ? "outline.error" : "none"}
85
+ borderRadius={invalid ? "sm" : "none"}
86
+ >
87
+ <>
76
88
  <CountryCodeSelect
77
- value={value.countryCode}
78
- onChange={(countryCode) =>
79
- onChange({
80
- countryCode: countryCode as string,
81
- nationalNumber: value.nationalNumber,
82
- })
83
- }
84
- name={
85
- name
86
- ? typeof name !== "string" && name.countryCode
87
- ? name.countryCode
88
- : `${name}-country-code`
89
- : "country-code"
90
- }
89
+ value={[value.countryCode]}
90
+ onValueChange={handleCountryCodeChange}
91
91
  height="100%"
92
92
  width="6.25rem"
93
93
  variant={variant}
94
+ data-state="on"
94
95
  />
95
96
  <Input
96
97
  ref={ref}
97
98
  type="tel"
98
- label={label}
99
99
  value={value.nationalNumber}
100
- name={
101
- name
102
- ? typeof name !== "string" && name.nationalNumber
103
- ? name.nationalNumber
104
- : `${name}-phone-number`
105
- : "phone-number"
106
- }
100
+ invalid={invalid}
101
+ errorText={errorText}
107
102
  onChange={(e) => {
103
+ const target = e.target as HTMLInputElement;
108
104
  // Removes everything but numbers, spaces and dashes
109
- const strippedValue = e.target.value.replace(/[^\d\s-]/g, "");
105
+ const strippedValue = target.value.replace(/[^\d\s-]/g, "");
110
106
  onChange({
111
107
  countryCode: value.countryCode,
112
108
  nationalNumber: strippedValue,
113
109
  });
114
110
  }}
115
- position="relative"
116
- left="1px" // Makes the borders overlap
117
111
  variant={variant}
112
+ data-state="on"
113
+ {...props}
114
+ label={label}
118
115
  />
119
- </AttachedInputs>
120
- );
121
- },
122
- );
116
+ </>
117
+ </AttachedInputs>
118
+ );
119
+ });
123
120
 
124
121
  const texts = createTexts({
125
122
  phoneNumber: {
@@ -1,3 +1,4 @@
1
+ "use client";
1
2
  import { Box } from "@chakra-ui/react";
2
3
  import React, { forwardRef, useRef } from "react";
3
4
  import {
@@ -1,25 +1,23 @@
1
- import {
2
- Radio as ChakraRadio,
3
- RadioProps as ChakraRadioProps,
4
- forwardRef,
5
- } from "@chakra-ui/react";
6
- import React from "react";
1
+ "use client";
2
+ import React, { forwardRef, PropsWithChildren } from "react";
3
+ import { RecipeVariantProps } from "@chakra-ui/react";
4
+ import { radioGroupSlotRecipe } from "../theme/slot-recipes/radio";
5
+ import { RadioGroup as ChakraRadioGroup } from "@chakra-ui/react";
7
6
 
8
- export type RadioProps = Exclude<
9
- ChakraRadioProps,
10
- "colorScheme" | "size" | "variant"
11
- >;
7
+ type RadioVariants = RecipeVariantProps<typeof radioGroupSlotRecipe>;
8
+
9
+ export type RadioProps = PropsWithChildren<RadioVariants> &
10
+ ChakraRadioGroup.ItemProps & {
11
+ rootRef?: React.Ref<HTMLDivElement>;
12
+ inputProps?: React.InputHTMLAttributes<HTMLInputElement>;
13
+ };
12
14
 
13
15
  /**
14
16
  * The humble radio button.
15
17
  *
16
18
  * Specify the label as `children` and the value as `value`.
17
19
  *
18
- * ```tsx
19
- * <Radio value="#f00">Red</Radio>
20
- * ```
21
- *
22
- * You typically want to place Radio components in a group with several other Radio components. You can do that with the `RadioGroup` component.
20
+ * Place the Radio components in a group with several other Radio components. You can do that with the `RadioGroup` component.
23
21
  *
24
22
  * ```tsx
25
23
  * <RadioGroup name="ticket">
@@ -28,6 +26,28 @@ export type RadioProps = Exclude<
28
26
  * <Radio value="first-class">First Class</Radio>
29
27
  * </RadioGroup>
30
28
  */
31
- export const Radio = forwardRef<RadioProps, "input">((props, ref) => {
32
- return <ChakraRadio {...props} ref={ref} />;
29
+
30
+ export const Radio = forwardRef<HTMLInputElement, RadioProps>((props, ref) => {
31
+ const { children, inputProps, rootRef, ...rest } = props;
32
+
33
+ return (
34
+ <ChakraRadioGroup.Item ref={rootRef} {...rest}>
35
+ <ChakraRadioGroup.ItemHiddenInput ref={ref} {...inputProps} />
36
+ <ChakraRadioGroup.ItemIndicator />
37
+ {children && (
38
+ <ChakraRadioGroup.ItemText>{children}</ChakraRadioGroup.ItemText>
39
+ )}
40
+ </ChakraRadioGroup.Item>
41
+ );
33
42
  });
43
+
44
+ type RadioGroupProps = Omit<
45
+ ChakraRadioGroup.RootProps,
46
+ "colorPalette" | "variant" | "size"
47
+ > & {};
48
+
49
+ export const RadioGroup = forwardRef<HTMLDivElement, RadioGroupProps>(
50
+ (props, ref) => {
51
+ return <ChakraRadioGroup.Root ref={ref} {...props} aria-labelledby="" />;
52
+ },
53
+ );
@@ -1,116 +1,54 @@
1
- import {
2
- Input as ChakraInput,
3
- InputProps as ChakraInputProps,
4
- IconButton,
5
- LayoutProps,
6
- forwardRef,
7
- useFormControlContext,
8
- } from "@chakra-ui/react";
1
+ "use client";
2
+
9
3
  import {
10
4
  CloseOutline24Icon,
11
5
  SearchOutline24Icon,
12
6
  } from "@vygruppen/spor-icon-react";
13
- import React, { useId } from "react";
14
- import { FormLabel, InputGroup, InputLeftElement, InputRightElement } from ".";
15
- import { createTexts, useTranslation } from "..";
7
+ import React, { forwardRef } from "react";
8
+ import { createTexts, Input, InputProps, useTranslation } from "..";
9
+ import { IconButton } from "../button/IconButton";
16
10
 
17
- export type SearchInputProps = Exclude<
18
- ChakraInputProps,
19
- "variant" | "size" | "leftIcon" | "rightIcon"
20
- > & {
21
- /** Optional label. Defaults to the localized version of "search" */
22
- label?: string | React.ReactNode;
11
+ export type SearchInputProps = InputProps & {
23
12
  /** Callback for when the clear button is clicked */
24
13
  onReset?: () => void;
25
14
  };
15
+
26
16
  /** Simple search input component.
27
17
  *
28
18
  * Includes a search icon, a localized label and a reset button.
29
19
  */
30
- export const SearchInput = forwardRef<SearchInputProps, "input">(
31
- ({ label, onReset, ...props }, ref) => {
32
- const { t } = useTranslation();
33
- const showClearButton = onReset && Boolean(props.value);
34
- const formControlProps = useFormControlContext();
35
- const autoGeneratedId = useId();
36
- const inputId = props.id ?? formControlProps?.id ?? autoGeneratedId;
37
20
 
38
- const { outerProps, innerProps } = getOuterProps(props);
21
+ export const SearchInput = forwardRef<HTMLInputElement, SearchInputProps>(
22
+ (props, ref) => {
23
+ const { t } = useTranslation();
24
+ const { variant = "core", onReset, label, value } = props;
25
+ const clearButton = onReset && value;
39
26
 
40
27
  return (
41
- <InputGroup position="relative" {...outerProps}>
42
- <InputLeftElement pointerEvents="none">
43
- <SearchOutline24Icon />
44
- </InputLeftElement>
45
- <ChakraInput
46
- paddingLeft={7}
47
- paddingRight={7}
48
- {...innerProps}
49
- id={inputId}
50
- type="search"
51
- placeholder=" "
52
- css={{
53
- "&::-webkit-search-cancel-button": {
54
- WebkitAppearance: "none",
55
- },
56
- }}
57
- ref={ref}
58
- data-attachable
59
- />
60
- <FormLabel
61
- htmlFor={inputId}
62
- sx={{
63
- position: "absolute",
64
- left: "2.6rem",
65
- top: "26.9%",
66
- fontSize: "1.13rem",
67
- pointerEvents: "none",
68
- margin: 0,
69
- zIndex: 2,
70
- "input:focus + &, input[data-has-value] + &": {
71
- color: "var(--chakra-colors-gray-600)",
72
- },
73
- "input[data-has-value] + &": {
74
- transform: "translateY(-40%) scale(0.9)",
75
- },
76
- }}
77
- >
78
- {label ?? t(texts.label)}
79
- </FormLabel>
80
- {showClearButton && (
81
- <InputRightElement width="fit-content">
28
+ <Input
29
+ ref={ref}
30
+ type="search"
31
+ variant={variant}
32
+ {...props}
33
+ startElement={<SearchOutline24Icon />}
34
+ endElement={
35
+ clearButton && (
82
36
  <IconButton
83
37
  variant="ghost"
84
38
  type="button"
85
39
  size="sm"
86
- marginRight={1}
87
40
  aria-label={t(texts.reset)}
88
41
  icon={<CloseOutline24Icon />}
89
42
  onClick={onReset}
90
43
  />
91
- </InputRightElement>
92
- )}
93
- </InputGroup>
44
+ )
45
+ }
46
+ label={(label as string) ?? t(texts.label)}
47
+ />
94
48
  );
95
49
  },
96
50
  );
97
51
 
98
- const getOuterProps = (props: Record<string, any>) => {
99
- const layoutKeys = new Set(["w, width, maxW, minW, maxWidth, minWidth"]); // add more keys here if neccessary
100
- const outerProps: LayoutProps = {};
101
- const innerProps: Record<string, any> = {};
102
-
103
- for (const key in props) {
104
- if (layoutKeys.has(key)) {
105
- (outerProps as any)[key] = props[key];
106
- } else {
107
- (innerProps as any)[key] = props[key];
108
- }
109
- }
110
-
111
- return { outerProps, innerProps };
112
- };
113
-
114
52
  const texts = createTexts({
115
53
  label: {
116
54
  nb: "Søk",
@@ -0,0 +1,237 @@
1
+ "use client";
2
+
3
+ import { CloseButton } from "@/button";
4
+ import { selectSlotRecipe } from "@/theme/slot-recipes/select";
5
+ import type {
6
+ SelectRootProps as ChakraSelectRootProps,
7
+ CollectionItem,
8
+ RecipeVariantProps,
9
+ } from "@chakra-ui/react";
10
+ import {
11
+ Box,
12
+ Select as ChakraSelect,
13
+ Portal,
14
+ useSlotRecipe,
15
+ } from "@chakra-ui/react";
16
+ import {
17
+ CheckmarkFill18Icon,
18
+ DropdownDownFill24Icon,
19
+ } from "@vygruppen/spor-icon-react";
20
+ import * as React from "react";
21
+ import { PropsWithChildren } from "react";
22
+
23
+ type SelectVariantProps = RecipeVariantProps<typeof selectSlotRecipe>;
24
+
25
+ export type SelectProps = ChakraSelectRootProps &
26
+ PropsWithChildren<SelectVariantProps> & {
27
+ label?: string;
28
+ };
29
+
30
+ /**
31
+ * A Select component.
32
+ *
33
+ * This component is useful to choose an item from a dropdown list of items. The list has four different variants, core, floating, rightSideSquare, leftSideSquare.
34
+ * The last two variants are useful in attachecdInput for example in the PhoneNumberInput and CountryCodeSelect components.
35
+ *
36
+ * @example
37
+ * ```tsx
38
+ * <Select label="Choose transportation" >
39
+ <SelectItem item={{
40
+ label: "Train",
41
+ value: "train",
42
+ }}>
43
+ item label
44
+ </SelectItem>
45
+ <SelectItem item={{
46
+ label: "Bus",
47
+ value: "Bus",
48
+ }}>
49
+ item label
50
+ </SelectItem>
51
+ </Select>
52
+ * ```
53
+ *
54
+ * @see https://spor.vy.no/components/select
55
+ *
56
+ */
57
+
58
+ export const Select = React.forwardRef<HTMLDivElement, SelectProps>(
59
+ (props, ref) => {
60
+ const { variant = "core", children, positioning, label, ...rest } = props;
61
+ const recipe = useSlotRecipe({ key: "select" });
62
+ const styles = recipe({ variant });
63
+
64
+ return (
65
+ <ChakraSelect.Root
66
+ {...rest}
67
+ ref={ref}
68
+ positioning={{ sameWidth: true, ...positioning }}
69
+ variant={variant}
70
+ css={styles.root}
71
+ position={"relative"}
72
+ >
73
+ <SelectTrigger data-attachable>
74
+ <SelectValueText withPlaceholder={label ? true : false} />
75
+ </SelectTrigger>
76
+ {label && <SelectLabel css={styles.label}>{label}</SelectLabel>}
77
+ <SelectContent css={styles.selectContent}>{children}</SelectContent>
78
+ </ChakraSelect.Root>
79
+ );
80
+ },
81
+ );
82
+
83
+ type SelectItemProps = ChakraSelect.ItemProps &
84
+ React.PropsWithChildren<SelectVariantProps> & {
85
+ children: React.ReactNode;
86
+ description?: React.ReactNode;
87
+ };
88
+
89
+ export const SelectItem = React.forwardRef<HTMLDivElement, SelectItemProps>(
90
+ (props, ref) => {
91
+ const { item, children, description, ...rest } = props;
92
+ const recipe = useSlotRecipe({ key: "select" });
93
+ const styles = recipe();
94
+ return (
95
+ <ChakraSelect.Item item={item} {...rest} ref={ref} css={styles.item}>
96
+ <Box>
97
+ <ChakraSelect.ItemText display="flex">
98
+ {children}
99
+ </ChakraSelect.ItemText>
100
+ {description && <Box css={styles.itemDescription}>{description}</Box>}
101
+ </Box>
102
+
103
+ <ChakraSelect.ItemIndicator>
104
+ <CheckmarkFill18Icon />
105
+ </ChakraSelect.ItemIndicator>
106
+ </ChakraSelect.Item>
107
+ );
108
+ },
109
+ );
110
+
111
+ type SelectItemGroupProps = ChakraSelect.ItemGroupProps &
112
+ React.PropsWithChildren<SelectVariantProps> & {
113
+ label: React.ReactNode;
114
+ children: React.ReactNode;
115
+ };
116
+
117
+ export const SelectItemGroup = React.forwardRef<
118
+ HTMLDivElement,
119
+ SelectItemGroupProps
120
+ >(function SelectItemGroup(props, ref) {
121
+ const { children, label, ...rest } = props;
122
+ return (
123
+ <ChakraSelect.ItemGroup {...rest} ref={ref}>
124
+ <ChakraSelect.ItemGroupLabel>{label}</ChakraSelect.ItemGroupLabel>
125
+ {children}
126
+ </ChakraSelect.ItemGroup>
127
+ );
128
+ });
129
+
130
+ type SelectTriggerProps = ChakraSelect.ControlProps &
131
+ React.PropsWithChildren<SelectVariantProps> & {
132
+ clearable?: boolean;
133
+ children?: React.ReactNode;
134
+ };
135
+
136
+ export const SelectTrigger = React.forwardRef<
137
+ HTMLButtonElement,
138
+ SelectTriggerProps
139
+ >(function SelectTrigger(props, ref) {
140
+ const { children, clearable, ...rest } = props;
141
+ const recipe = useSlotRecipe({ key: "select" });
142
+ const styles = recipe();
143
+ return (
144
+ <ChakraSelect.Control {...rest} css={styles.control}>
145
+ <ChakraSelect.Trigger ref={ref} css={styles.trigger}>
146
+ {children}
147
+ </ChakraSelect.Trigger>
148
+ <ChakraSelect.IndicatorGroup css={styles.indicatorGroup}>
149
+ {clearable && <SelectClearTrigger />}
150
+ <Box css={styles.indicator}>
151
+ <DropdownDownFill24Icon />
152
+ </Box>
153
+ </ChakraSelect.IndicatorGroup>
154
+ </ChakraSelect.Control>
155
+ );
156
+ });
157
+
158
+ type SelectClearTriggerProps = ChakraSelect.ClearTriggerProps &
159
+ React.PropsWithChildren<SelectVariantProps> & {
160
+ children?: React.ReactNode;
161
+ };
162
+
163
+ const SelectClearTrigger = React.forwardRef<
164
+ HTMLButtonElement,
165
+ SelectClearTriggerProps
166
+ >(function SelectClearTrigger(props, ref) {
167
+ return (
168
+ <ChakraSelect.ClearTrigger asChild {...props} ref={ref}>
169
+ <CloseButton
170
+ size="xs"
171
+ focusVisibleRing="inside"
172
+ focusRingWidth="2px"
173
+ pointerEvents="auto"
174
+ />
175
+ </ChakraSelect.ClearTrigger>
176
+ );
177
+ });
178
+
179
+ type SelectContentProps = ChakraSelect.ContentProps &
180
+ React.PropsWithChildren<SelectVariantProps> & {
181
+ portalled?: boolean;
182
+ portalRef?: React.RefObject<HTMLElement>;
183
+ };
184
+
185
+ export const SelectContent = React.forwardRef<
186
+ HTMLDivElement,
187
+ SelectContentProps
188
+ >(function SelectContent(props, ref) {
189
+ const { portalled = true, portalRef, ...rest } = props;
190
+ return (
191
+ <Portal disabled={!portalled} container={portalRef}>
192
+ <ChakraSelect.Positioner>
193
+ <ChakraSelect.Content {...rest} ref={ref} />
194
+ </ChakraSelect.Positioner>
195
+ </Portal>
196
+ );
197
+ });
198
+
199
+ type SelectValueTextProps = Omit<ChakraSelect.ValueTextProps, "children"> &
200
+ React.PropsWithChildren<SelectVariantProps> & {
201
+ children?(items: CollectionItem[]): React.ReactNode;
202
+ placeholder?: string;
203
+ withPlaceholder?: boolean;
204
+ };
205
+
206
+ export const SelectValueText = React.forwardRef<
207
+ HTMLSpanElement,
208
+ SelectValueTextProps
209
+ >(function SelectValueText(props, ref) {
210
+ const { children, withPlaceholder, placeholder, ...rest } = props;
211
+ return (
212
+ <ChakraSelect.ValueText
213
+ {...rest}
214
+ ref={ref}
215
+ placeholder={placeholder}
216
+ paddingTop={withPlaceholder ? "4" : "0"}
217
+ >
218
+ <ChakraSelect.Context>
219
+ {(select: {
220
+ selectedItems: any;
221
+ collection: { stringifyItem: (arg0: any) => any };
222
+ }) => {
223
+ const items = select.selectedItems;
224
+ if (items.length === 0) return placeholder;
225
+ if (children) return children(items);
226
+ if (items.length === 1)
227
+ return select.collection.stringifyItem(items[0]);
228
+ return `${items.length} selected`;
229
+ }}
230
+ </ChakraSelect.Context>
231
+ </ChakraSelect.ValueText>
232
+ );
233
+ });
234
+
235
+ export const SelectLabel = ChakraSelect.Label;
236
+ export const SelectItemText = ChakraSelect.ItemText;
237
+ export const SelectRoot = ChakraSelect.Root;