@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,142 +1,237 @@
1
- import React from "react";
2
- import { Center, createTexts, useTranslation, Flex, TextLink } from "..";
1
+ "use client";
2
+
3
3
  import {
4
- ListItem,
5
- UnorderedList,
6
- useMultiStyleConfig,
7
- Link,
4
+ Box,
5
+ Pagination as ChakraPagination,
6
+ createContext,
7
+ usePaginationContext,
8
+ useSlotRecipe,
8
9
  } from "@chakra-ui/react";
10
+ import * as React from "react";
9
11
  import {
10
- DropdownLeftFill18Icon,
11
- DropdownRightFill18Icon,
12
+ DropdownRightOutline18Icon,
13
+ DropdownLeftOutline18Icon,
12
14
  } from "@vygruppen/spor-icon-react";
13
-
14
- type PaginationProps = {
15
- /** Specify the total amount of pages */
16
- totalPages: number;
17
- /** Specify the currently selected page */
18
- selectedPage: number;
19
- /** Callback for when a page is clicked */
20
- onPageChange: (selected: number) => void;
21
- };
15
+ import { createTexts, List, ListItem, useTranslation } from "..";
16
+ import { ButtonVariantContext, PaginationRootProps } from "./types";
22
17
 
23
18
  /**
24
19
  * A pagination component is used to navigate between multiple pages.
25
20
  *
26
- * You specify the total amount of pages and the currently selected page.
21
+ * Count is the total number of pages.
22
+ * pageSize is the number of items per page.
23
+ * defaultPage is the default page to show.
24
+ * siblingCount is the number of sibling pages to show.
27
25
  *
28
26
  * ```tsx
29
- * <Pagination
30
- * totalPages={10}
31
- * selectedPage={3}
32
- * onPageChange={handlePageChange}
33
- * />
27
+ * <Pagination count={10} pageSize={1} defaultPage={1}>
28
+ * <PaginationPrevTrigger />
29
+ * <PaginationItems />
30
+ * <PaginationNextTrigger />
31
+ * </Pagination>
34
32
  * ```
35
33
  **/
36
34
 
37
- export const Pagination = ({
38
- totalPages,
39
- selectedPage,
40
- onPageChange,
41
- }: PaginationProps) => {
35
+ const [RootPropsProvider, useRootProps] = createContext<ButtonVariantContext>({
36
+ name: "RootPropsProvider",
37
+ });
38
+
39
+ export const Pagination = React.forwardRef<HTMLDivElement, PaginationRootProps>(
40
+ (props, ref) => {
41
+ const { getHref, children, ...rest } = props;
42
+ const recipe = useSlotRecipe({ key: "pagination" });
43
+ const styles = recipe();
44
+
45
+ return (
46
+ <RootPropsProvider
47
+ value={{
48
+ getHref,
49
+ }}
50
+ >
51
+ <ChakraPagination.Root
52
+ ref={ref}
53
+ type={getHref ? "link" : "button"}
54
+ {...rest}
55
+ >
56
+ <List css={styles.list}>{children}</List>
57
+ </ChakraPagination.Root>
58
+ </RootPropsProvider>
59
+ );
60
+ },
61
+ );
62
+
63
+ export const PaginationEllipsis = React.forwardRef<
64
+ HTMLDivElement,
65
+ ChakraPagination.EllipsisProps
66
+ >((props, ref) => {
67
+ return (
68
+ <ListItem>
69
+ <ChakraPagination.Ellipsis ref={ref} {...props} asChild>
70
+ <Box cursor="default">...</Box>
71
+ </ChakraPagination.Ellipsis>
72
+ </ListItem>
73
+ );
74
+ });
75
+
76
+ export const PaginationItem = React.forwardRef<
77
+ HTMLButtonElement,
78
+ ChakraPagination.ItemProps
79
+ >((props, ref) => {
80
+ const rootProps = useRootProps();
42
81
  const { t } = useTranslation();
82
+ const { page, totalPages } = usePaginationContext();
43
83
 
44
- const style = useMultiStyleConfig("Pagination", { selectedPage });
45
-
46
- const hasPreviousPage = selectedPage > 1;
47
- const hasNextPage = selectedPage < totalPages;
48
-
49
- const renderPaginationButtons = () => {
50
- const displayPageNumbers = [];
51
- const maxVisiblePages = 8;
52
- if (totalPages <= maxVisiblePages) {
53
- displayPageNumbers.push(
54
- ...Array.from({ length: totalPages }, (_, i) => i + 1),
55
- );
56
- } else {
57
- if (selectedPage <= Math.floor(maxVisiblePages / 2) + 1) {
58
- // If selectedPage is near the beginning, display the first pages.
59
- displayPageNumbers.push(
60
- ...Array.from({ length: maxVisiblePages - 1 }, (_, i) => i + 1),
61
- );
62
- displayPageNumbers.push("...");
63
- displayPageNumbers.push(totalPages);
64
- } else if (selectedPage >= totalPages - Math.floor(maxVisiblePages / 2)) {
65
- // If selectedPage is near the end, display the last pages.
66
- displayPageNumbers.push(1);
67
- displayPageNumbers.push("...");
68
- displayPageNumbers.push(
69
- ...Array.from(
70
- { length: maxVisiblePages - 1 },
71
- (_, i) => totalPages - maxVisiblePages + 2 + i,
72
- ),
73
- );
74
- } else {
75
- // Display pages with "..." in the middle.
76
- displayPageNumbers.push(1);
77
- displayPageNumbers.push("...");
78
- for (
79
- let i = selectedPage - Math.floor((maxVisiblePages - 3) / 2);
80
- i <= selectedPage + Math.floor((maxVisiblePages - 3) / 2);
81
- i++
82
- ) {
83
- displayPageNumbers.push(i);
84
- }
85
- displayPageNumbers.push("...");
86
- displayPageNumbers.push(totalPages);
87
- }
88
- }
89
- return displayPageNumbers.map((pageNumber, index) =>
90
- pageNumber === "..." ? (
91
- <ListItem key={index} sx={style.listItem}>
92
- <Center>...</Center>
93
- </ListItem>
94
- ) : (
95
- <Link
96
- key={index}
97
- as={ListItem}
98
- onClick={() => {
99
- if (pageNumber !== "...") {
100
- onPageChange(+pageNumber);
101
- }
84
+ if (rootProps.getHref) {
85
+ return (
86
+ <ListItem>
87
+ <ChakraPagination.Item
88
+ as={props.as ?? "a"}
89
+ {...{
90
+ href: rootProps.getHref(props.value as number),
91
+ to: rootProps.getHref(props.value as number),
92
+ }}
93
+ ref={ref}
94
+ aria-label={t(texts.pageOf(props.value, totalPages))}
95
+ {...props}
96
+ >
97
+ {props.value}
98
+ </ChakraPagination.Item>
99
+ </ListItem>
100
+ );
101
+ }
102
+
103
+ return (
104
+ <ListItem>
105
+ <ChakraPagination.Item
106
+ as={props.as ?? "button"}
107
+ ref={ref}
108
+ aria-label={t(texts.pageOf(props.value, totalPages))}
109
+ aria-selected={page === props.value}
110
+ {...props}
111
+ >
112
+ {props.value}
113
+ </ChakraPagination.Item>
114
+ </ListItem>
115
+ );
116
+ });
117
+
118
+ export const PaginationPrevTrigger = React.forwardRef<
119
+ HTMLButtonElement,
120
+ ChakraPagination.PrevTriggerProps
121
+ >((props, ref) => {
122
+ const { page } = usePaginationContext();
123
+ const recipe = useSlotRecipe({ key: "pagination" });
124
+ const styles = recipe();
125
+ const { t } = useTranslation();
126
+ const rootProps = useRootProps();
127
+
128
+ if (page <= 1) return null;
129
+
130
+ if (rootProps.getHref) {
131
+ return (
132
+ <ListItem>
133
+ <ChakraPagination.PrevTrigger
134
+ as={props.as ?? "a"}
135
+ asChild
136
+ {...{
137
+ href: rootProps.getHref(props.value as number),
138
+ to: rootProps.getHref(props.value as number),
102
139
  }}
103
- padding={pageNumber === "..." ? 0 : undefined}
104
- sx={pageNumber === selectedPage ? style.activeButton : style.link}
140
+ ref={ref}
141
+ css={styles.item}
142
+ aria-label={t(texts.previousPage)}
143
+ {...props}
105
144
  >
106
- {pageNumber}
107
- </Link>
108
- ),
145
+ <DropdownLeftOutline18Icon />
146
+ </ChakraPagination.PrevTrigger>
147
+ </ListItem>
109
148
  );
110
- };
149
+ }
150
+ return (
151
+ <ListItem>
152
+ <ChakraPagination.PrevTrigger
153
+ ref={ref}
154
+ asChild
155
+ aria-label={t(texts.previousPage)}
156
+ as={props.as || "button"}
157
+ css={styles.item}
158
+ {...props}
159
+ >
160
+ <DropdownLeftOutline18Icon />
161
+ </ChakraPagination.PrevTrigger>
162
+ </ListItem>
163
+ );
164
+ });
165
+
166
+ export const PaginationNextTrigger = React.forwardRef<
167
+ HTMLButtonElement,
168
+ ChakraPagination.NextTriggerProps
169
+ >((props, ref) => {
170
+ const { page, totalPages } = usePaginationContext();
171
+ const recipe = useSlotRecipe({ key: "pagination" });
172
+ const styles = recipe();
173
+ const { t } = useTranslation();
174
+ const rootProps = useRootProps();
175
+
176
+ if (page >= totalPages) return null;
111
177
 
178
+ if (rootProps.getHref) {
179
+ return (
180
+ <ListItem>
181
+ <ChakraPagination.NextTrigger
182
+ ref={ref}
183
+ {...{
184
+ href: rootProps.getHref(props.value as number),
185
+ to: rootProps.getHref(props.value as number),
186
+ }}
187
+ css={styles.item}
188
+ aria-label={t(texts.nextPage)}
189
+ {...props}
190
+ >
191
+ <DropdownRightOutline18Icon />
192
+ </ChakraPagination.NextTrigger>
193
+ </ListItem>
194
+ );
195
+ }
112
196
  return (
113
- <Flex as="nav" aria-label="pagination">
114
- <UnorderedList
115
- display="flex"
116
- listStyleType="none"
117
- gap={[0, 1]}
118
- padding={0}
119
- margin={0}
197
+ <ListItem>
198
+ <ChakraPagination.NextTrigger
199
+ ref={ref}
200
+ css={styles.item}
201
+ aria-label={t(texts.nextPage)}
202
+ as={props.as || "button"}
203
+ {...props}
120
204
  >
121
- <ListItem aria-label={t(texts.previousPage)}>
122
- <TextLink
123
- onClick={() => onPageChange(selectedPage - 1)}
124
- sx={hasPreviousPage ? style.link : style.disabled}
125
- >
126
- <DropdownLeftFill18Icon sx={style.icon} />
127
- </TextLink>
128
- </ListItem>
129
- {renderPaginationButtons()}
130
- <ListItem aria-label={t(texts.nextPage)}>
131
- <TextLink
132
- onClick={() => onPageChange(selectedPage + 1)}
133
- sx={hasNextPage ? style.link : style.disabled}
134
- >
135
- <DropdownRightFill18Icon sx={style.icon} />
136
- </TextLink>
137
- </ListItem>
138
- </UnorderedList>
139
- </Flex>
205
+ <DropdownRightOutline18Icon />
206
+ </ChakraPagination.NextTrigger>
207
+ </ListItem>
208
+ );
209
+ });
210
+
211
+ export const PaginationItems = (
212
+ props: React.HTMLAttributes<HTMLElement> & {},
213
+ ) => {
214
+ return (
215
+ <ChakraPagination.Context>
216
+ {({ pages }) =>
217
+ pages.map((page, index) => {
218
+ return page.type === "ellipsis" ? (
219
+ <PaginationEllipsis
220
+ key={`ellipsis-${index}`}
221
+ index={index}
222
+ {...props}
223
+ />
224
+ ) : (
225
+ <PaginationItem
226
+ key={`pagination-item-${page.value}`}
227
+ value={page.value}
228
+ type="page"
229
+ {...props}
230
+ />
231
+ );
232
+ })
233
+ }
234
+ </ChakraPagination.Context>
140
235
  );
141
236
  };
142
237
 
@@ -153,4 +248,12 @@ const texts = createTexts({
153
248
  en: "Next page",
154
249
  sv: "Nästa sida",
155
250
  },
251
+ pageOf: (page, totalPages) => {
252
+ return {
253
+ nb: `Side ${page} av ${totalPages}`,
254
+ nn: `Side ${page} av ${totalPages}`,
255
+ en: `Page ${page} of ${totalPages}`,
256
+ sv: `Sida ${page} av ${totalPages}`,
257
+ };
258
+ },
156
259
  });
@@ -0,0 +1,23 @@
1
+ import { paginationSlotRecipe } from "@/theme/slot-recipes/pagination";
2
+ import {
3
+ Pagination as ChakraPagination,
4
+ RecipeVariantProps,
5
+ } from "@chakra-ui/react";
6
+
7
+ export type PaginationVariantProps = RecipeVariantProps<
8
+ typeof paginationSlotRecipe
9
+ >;
10
+
11
+ export type ButtonVariantContext = {
12
+ getHref?: (page: number) => string;
13
+ };
14
+
15
+ export type PaginationProps = Omit<
16
+ ChakraPagination.RootProps,
17
+ "type" | "translations"
18
+ > &
19
+ ButtonVariantContext & {};
20
+
21
+ export type PaginationRootProps = Omit<ChakraPagination.RootProps, "type"> &
22
+ React.PropsWithChildren<PaginationVariantProps> &
23
+ ButtonVariantContext & {};
@@ -0,0 +1,67 @@
1
+ "use client";
2
+
3
+ import { CloseButton } from "@/button";
4
+ import { useColorMode } from "@/color-mode";
5
+ import {
6
+ Portal,
7
+ Popover as ChakraPopover,
8
+ usePopoverContext,
9
+ } from "@chakra-ui/react";
10
+ import React, { forwardRef, useEffect } from "react";
11
+
12
+ export const Popover = ChakraPopover.Root;
13
+
14
+ export const PopoverTrigger = forwardRef<
15
+ HTMLButtonElement,
16
+ ChakraPopover.TriggerProps
17
+ >(({ children, ...props }, ref) => {
18
+ const isStringChild = typeof children === "string";
19
+
20
+ return (
21
+ <ChakraPopover.Trigger {...props} ref={ref} asChild={!isStringChild}>
22
+ {children}
23
+ </ChakraPopover.Trigger>
24
+ );
25
+ });
26
+
27
+ export type PopoverProps = ChakraPopover.ContentProps &
28
+ React.RefAttributes<HTMLDivElement> & {
29
+ showCloseButton?: boolean;
30
+ };
31
+
32
+ export const PopoverContent = forwardRef<HTMLDivElement, PopoverProps>(
33
+ ({ children, showCloseButton = false, ...props }, ref) => {
34
+ const { colorMode } = useColorMode();
35
+
36
+ const closeButtonRef = React.useRef<HTMLButtonElement>(null);
37
+
38
+ const { open } = usePopoverContext();
39
+
40
+ useEffect(() => {
41
+ if (showCloseButton && open && closeButtonRef.current) {
42
+ closeButtonRef.current.focus();
43
+ }
44
+ }, [showCloseButton, open]);
45
+
46
+ return (
47
+ <Portal>
48
+ <ChakraPopover.Positioner>
49
+ <ChakraPopover.Content ref={ref} {...props}>
50
+ <ChakraPopover.Arrow />
51
+ {showCloseButton && (
52
+ <div>
53
+ <ChakraPopover.CloseTrigger asChild>
54
+ <CloseButton
55
+ className={colorMode === "dark" ? "light" : "dark"}
56
+ ref={closeButtonRef}
57
+ />
58
+ </ChakraPopover.CloseTrigger>
59
+ </div>
60
+ )}
61
+ <ChakraPopover.Body {...props}>{children}</ChakraPopover.Body>
62
+ </ChakraPopover.Content>
63
+ </ChakraPopover.Positioner>
64
+ </Portal>
65
+ );
66
+ },
67
+ );
@@ -1,23 +1,24 @@
1
- import React from "react";
2
- import { Box } from "..";
3
- import { useMultiStyleConfig } from "@chakra-ui/react";
1
+ "use client";
2
+ import React, { PropsWithChildren } from "react";
3
+ import { chakra, useSlotRecipe } from "@chakra-ui/react";
4
+ import { ProgressIndicatorVariantProps } from "./ProgressIndicator";
4
5
 
5
- type ProgressDot = {
6
+ type ProgressDot = PropsWithChildren<ProgressIndicatorVariantProps> & {
6
7
  isActive: boolean;
7
8
  };
8
9
 
9
10
  export const ProgressDot = ({ isActive }: ProgressDot) => {
10
- const style = useMultiStyleConfig("ProgressIndicator");
11
+ const recipe = useSlotRecipe({ key: "progressIndicator" });
12
+ const style = recipe({});
11
13
  return (
12
- <Box
13
- as="svg"
14
+ <chakra.svg
14
15
  display="block"
15
- __css={style.progressDot}
16
+ css={style.progressDot}
16
17
  xmlns="http://www.w3.org/2000/svg"
17
18
  viewBox="0 0 100 100"
18
19
  aria-current={isActive ? "step" : undefined}
19
20
  >
20
- <Box as="circle" cx="50" cy="50" r="50" />
21
- </Box>
21
+ <chakra.circle as="circle" cx="50" cy="50" r="50" />
22
+ </chakra.svg>
22
23
  );
23
24
  };
@@ -1,12 +1,21 @@
1
- import { useMultiStyleConfig } from "@chakra-ui/react";
2
- import React from "react";
1
+ "use client";
2
+ import { BoxProps, RecipeVariantProps, useSlotRecipe } from "@chakra-ui/react";
3
+ import React, { forwardRef, PropsWithChildren } from "react";
3
4
  import { Box, createTexts, useTranslation } from "..";
4
5
  import { ProgressDot } from "./ProgressDot";
6
+ import { progressIndicatorRecipe } from "../theme/slot-recipes/progress-indicator";
5
7
 
6
- type ProgressIndicatorProps = {
7
- numberOfSteps: number;
8
- activeStep: number;
9
- };
8
+ export type ProgressIndicatorVariantProps = RecipeVariantProps<
9
+ typeof progressIndicatorRecipe
10
+ >;
11
+
12
+ export type ProgressIndicatorProps = BoxProps &
13
+ PropsWithChildren<ProgressIndicatorVariantProps> & {
14
+ children?: React.ReactNode;
15
+ numberOfSteps: number;
16
+ activeStep: number;
17
+ colorPalette?: string;
18
+ };
10
19
 
11
20
  /**
12
21
  * A progress indicator is used to show which step of a process a user is currently in
@@ -21,23 +30,28 @@ type ProgressIndicatorProps = {
21
30
  * />
22
31
  * ```
23
32
  */
24
- export const ProgressIndicator = ({
25
- numberOfSteps,
26
- activeStep,
27
- }: ProgressIndicatorProps) => {
33
+
34
+ export const ProgressIndicator = forwardRef<
35
+ HTMLDivElement,
36
+ ProgressIndicatorProps
37
+ >(({ numberOfSteps, activeStep, colorPalette = "brand" }) => {
28
38
  const { t } = useTranslation();
29
- const style = useMultiStyleConfig("ProgressIndicator");
39
+ const recipe = useSlotRecipe({
40
+ key: "progressIndicator",
41
+ });
42
+
43
+ const styles = recipe({});
30
44
 
31
45
  return (
32
46
  <Box
33
- __css={style.root}
47
+ css={styles.root}
34
48
  role="progressbar"
35
49
  aria-valuemin={1}
36
50
  aria-valuemax={numberOfSteps}
37
51
  aria-valuenow={activeStep}
38
52
  aria-valuetext={t(texts.stepsOf(activeStep, numberOfSteps))}
39
53
  >
40
- <Box __css={style.container}>
54
+ <Box css={styles.container}>
41
55
  {Array.from({ length: numberOfSteps }, (_, i) => (
42
56
  <ProgressDot
43
57
  key={i}
@@ -48,8 +62,7 @@ export const ProgressIndicator = ({
48
62
  </Box>
49
63
  </Box>
50
64
  );
51
- };
52
-
65
+ });
53
66
  const texts = createTexts({
54
67
  stepsOf: (activeStep, numberOfSteps) => ({
55
68
  nb: `Steg ${activeStep} av ${numberOfSteps}`,
@@ -1,11 +1,15 @@
1
- import { ChakraProvider, ChakraProviderProps } from "@chakra-ui/react";
1
+ "use client";
2
2
  import { Global } from "@emotion/react";
3
- import deepmerge from "deepmerge";
4
3
  import React from "react";
5
- import { Language, LanguageProvider } from "..";
6
- import { Brand, brandTheme, theme as defaultSporTheme, fontFaces } from "../";
4
+ import { Language, LanguageProvider, system, themes } from "..";
5
+
6
+ import { Toaster } from "../toast/toast";
7
+
8
+ import { Brand, fontFaces } from "../theme/brand";
9
+ import { ChakraProvider, ChakraProviderProps } from "@chakra-ui/react";
10
+ import { ColorModeProvider } from "../color-mode";
7
11
 
8
- type SporProviderProps = ChakraProviderProps & {
12
+ type SporProviderProps = Omit<ChakraProviderProps, "value"> & {
9
13
  language?: Language;
10
14
  brand?: Brand;
11
15
  };
@@ -35,6 +39,7 @@ type SporProviderProps = ChakraProviderProps & {
35
39
  *
36
40
  * ```tsx
37
41
  * import { extendTheme, SporProvider } from "@vygruppen/spor-react";
42
+ import { theme } from '../../../../apps/docs/app/features/portable-text/code-block/codeTheme';
38
43
  * const theme = extendTheme({
39
44
  * colors: { myApp: { primary: "tomato" } }
40
45
  * });
@@ -47,21 +52,19 @@ type SporProviderProps = ChakraProviderProps & {
47
52
  * ```
48
53
  */
49
54
  export const SporProvider = ({
50
- theme = defaultSporTheme,
51
55
  language = Language.NorwegianBokmal,
52
56
  brand = Brand.VyDigital,
53
57
  children,
54
- ...props
55
58
  }: SporProviderProps) => {
56
- const brandCustomizations = brandTheme[brand] ?? {};
57
-
58
- const extendedTheme = deepmerge(theme, brandCustomizations);
59
-
60
59
  return (
61
60
  <LanguageProvider language={language}>
62
- <ChakraProvider theme={extendedTheme} {...props}>
63
- <Global styles={fontFaces} />
64
- {children}
61
+ <ChakraProvider value={themes[brand] ?? system}>
62
+ <ColorModeProvider>
63
+ <Toaster />
64
+ <Global styles={fontFaces} />
65
+
66
+ {children}
67
+ </ColorModeProvider>
65
68
  </ChakraProvider>
66
69
  </LanguageProvider>
67
70
  );