@vygruppen/spor-react 13.4.1 → 13.4.3

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.
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@vygruppen/spor-react",
3
3
  "type": "module",
4
- "version": "13.4.1",
4
+ "version": "13.4.3",
5
5
  "exports": {
6
6
  ".": {
7
7
  "types": "./dist/index.d.ts",
@@ -46,7 +46,7 @@
46
46
  "react-stately": "^3.31.1",
47
47
  "react-swipeable": "^7.0.1",
48
48
  "usehooks-ts": "^3.1.0",
49
- "@vygruppen/spor-design-tokens": "5.0.4",
49
+ "@vygruppen/spor-design-tokens": "5.0.5",
50
50
  "@vygruppen/spor-icon-react": "5.0.0",
51
51
  "@vygruppen/spor-loader": "0.7.0"
52
52
  },
@@ -72,7 +72,7 @@ export const DateField = ({
72
72
  <DateTimeSegment
73
73
  key={index}
74
74
  segment={segment}
75
- ariaDescription={t(getAriaLabel(segment.type))}
75
+ ariaLabel={t(getAriaLabel(segment.type))}
76
76
  state={state}
77
77
  />
78
78
  ))}
@@ -115,7 +115,7 @@ export const DatePicker = ({
115
115
  const popoverContent = (
116
116
  <ChakraPopover.Positioner>
117
117
  <ChakraPopover.Content css={styles.calendarPopover}>
118
- <ChakraPopover.Body minWidth="20rem">
118
+ <ChakraPopover.Body minWidth="18rem">
119
119
  <Calendar
120
120
  {...calendarProps}
121
121
  variant={variant}
@@ -10,7 +10,7 @@ type DateTimeSegmentProps = PropsWithChildren<DatePickerVariantProps> & {
10
10
  segment: DateSegment;
11
11
  state: DateFieldState;
12
12
  ariaLabel?: string;
13
- ariaDescription?: string;
13
+ ariaLabelledby?: string;
14
14
  };
15
15
  /**
16
16
  * A date time segment is a part of a date or a time stamp.
@@ -24,7 +24,7 @@ export const DateTimeSegment = ({
24
24
  segment,
25
25
  state,
26
26
  ariaLabel,
27
- ariaDescription,
27
+ ariaLabelledby,
28
28
  variant,
29
29
  }: DateTimeSegmentProps & {
30
30
  ref?: React.Ref<HTMLDivElement>;
@@ -59,8 +59,8 @@ export const DateTimeSegment = ({
59
59
  borderRadius="xs"
60
60
  fontSize={["mobile.sm", "desktop.sm"]}
61
61
  css={styles.dateTimeSegment}
62
- aria-label={ariaDescription}
63
- aria-labelledby={ariaLabel}
62
+ aria-label={ariaLabel}
63
+ aria-labelledby={ariaLabelledby}
64
64
  >
65
65
  {isPaddable(segment.type) ? segment.text.padStart(2, "0") : segment.text}
66
66
  </Box>
@@ -1,5 +1,5 @@
1
1
  "use client";
2
- import { Box, Flex } from "@chakra-ui/react";
2
+ import { Box, Field as ChakraField, Flex } from "@chakra-ui/react";
3
3
  import { CalendarDateTime, Time } from "@internationalized/date";
4
4
  import { useRef } from "react";
5
5
  import { AriaTimeFieldProps, useTimeField } from "react-aria";
@@ -7,6 +7,7 @@ import { DateSegment, TimeFieldState } from "react-stately";
7
7
 
8
8
  import { spor } from "@/util";
9
9
 
10
+ import { createTexts, useTranslation } from "../i18n";
10
11
  import { DateTimeSegment } from "./DateTimeSegment";
11
12
  import { getTimestampFromTime } from "./utils";
12
13
 
@@ -23,6 +24,7 @@ type TimeFieldProps = AriaTimeFieldProps<Time> & {
23
24
  export const TimeField = ({ state, ...props }: TimeFieldProps) => {
24
25
  const ref = useRef<HTMLDivElement>(null);
25
26
  const { labelProps, fieldProps } = useTimeField(props, state, ref);
27
+ const { t } = useTranslation();
26
28
 
27
29
  return (
28
30
  <Box>
@@ -43,10 +45,16 @@ export const TimeField = ({ state, ...props }: TimeFieldProps) => {
43
45
  maxWidth="80%"
44
46
  >
45
47
  {props.label}
48
+ <ChakraField.RequiredIndicator />
46
49
  </spor.label>
47
50
  <Flex {...fieldProps} ref={ref} paddingTop="3" paddingBottom="0.5">
48
51
  {state.segments.map((segment: DateSegment, index) => (
49
- <DateTimeSegment key={index} segment={segment} state={state} />
52
+ <DateTimeSegment
53
+ key={index}
54
+ segment={segment}
55
+ state={state}
56
+ ariaLabel={t(getAriaLabel(segment.type))}
57
+ />
50
58
  ))}
51
59
  </Flex>
52
60
  <input
@@ -57,3 +65,47 @@ export const TimeField = ({ state, ...props }: TimeFieldProps) => {
57
65
  </Box>
58
66
  );
59
67
  };
68
+
69
+ const getAriaLabel = (segmentType: DateSegment["type"]) => {
70
+ switch (segmentType) {
71
+ case "hour": {
72
+ return texts.hour;
73
+ }
74
+ case "minute": {
75
+ return texts.minute;
76
+ }
77
+ case "second": {
78
+ return texts.second;
79
+ }
80
+ default: {
81
+ return texts.default;
82
+ }
83
+ }
84
+ };
85
+
86
+ const texts = createTexts({
87
+ hour: {
88
+ nb: "Velg time",
89
+ nn: "Vel time",
90
+ sv: "Välj timme",
91
+ en: "Choose hour",
92
+ },
93
+ minute: {
94
+ nb: "Velg minutt",
95
+ nn: "Vel minutt",
96
+ sv: "Välj minut",
97
+ en: "Choose minute",
98
+ },
99
+ second: {
100
+ nb: "Velg sekund",
101
+ nn: "Vel sekund",
102
+ sv: "Välj sekund",
103
+ en: "Choose second",
104
+ },
105
+ default: {
106
+ nb: "Velg tid",
107
+ nn: "Vel tid",
108
+ sv: "Välj tid",
109
+ en: "Choose time",
110
+ },
111
+ });
@@ -144,7 +144,6 @@ export const TimePicker = ({
144
144
  opacity={isDisabled ? 0.5 : 1}
145
145
  pointerEvents={isDisabled ? "none" : "auto"}
146
146
  aria-disabled={isDisabled}
147
- aria-live="assertive"
148
147
  aria-label={ariaLabel}
149
148
  position="relative"
150
149
  {...boxProps}
@@ -9,6 +9,7 @@ interface DialogContentProps extends ChakraDialog.ContentProps {
9
9
  portalRef?: React.RefObject<HTMLElement>;
10
10
  backdrop?: boolean;
11
11
  children?: React.ReactNode;
12
+ positionerProps?: ChakraDialog.PositionerProps;
12
13
  }
13
14
 
14
15
  export const DialogContent = ({
@@ -22,13 +23,14 @@ export const DialogContent = ({
22
23
  portalled = true,
23
24
  portalRef,
24
25
  backdrop = true,
26
+ positionerProps,
25
27
  ...rest
26
28
  } = props;
27
29
 
28
30
  return (
29
31
  <Portal disabled={!portalled} container={portalRef}>
30
32
  {backdrop && <ChakraDialog.Backdrop />}
31
- <ChakraDialog.Positioner>
33
+ <ChakraDialog.Positioner {...positionerProps}>
32
34
  <ChakraDialog.Content ref={ref} {...rest} asChild={false}>
33
35
  {children}
34
36
  </ChakraDialog.Content>
@@ -6,6 +6,7 @@ import {
6
6
  defineRecipe,
7
7
  Group,
8
8
  GroupProps,
9
+ IconButtonProps,
9
10
  RecipeVariantProps,
10
11
  useRecipe,
11
12
  } from "@chakra-ui/react";
@@ -40,10 +41,22 @@ export type AttachedInputsProps = RecipeVariantProps<
40
41
  onFlip: () => void;
41
42
  flipAriaLabel: string;
42
43
  }
43
- );
44
+ ) & {
45
+ flipButtonProps?: Omit<
46
+ IconButtonProps,
47
+ | "icon"
48
+ | "aria-label"
49
+ | "onClick"
50
+ | "variant"
51
+ | "size"
52
+ | "orientation"
53
+ | "spinner"
54
+ >;
55
+ };
44
56
 
45
57
  export const AttachedInputs = ({
46
58
  ref,
59
+ flipButtonProps,
47
60
  ...props
48
61
  }: AttachedInputsProps & {
49
62
  ref?: React.Ref<HTMLDivElement>;
@@ -76,6 +89,10 @@ export const AttachedInputs = ({
76
89
  size={["xs", null, "sm"]}
77
90
  aria-label={flipAriaLabel}
78
91
  onClick={onFlip}
92
+ position="absolute"
93
+ bg="bg"
94
+ outlineWidth="1px"
95
+ {...flipButtonProps}
79
96
  />
80
97
  </Box>
81
98
  );
@@ -85,24 +102,20 @@ const SwitchButton = chakra(
85
102
  IconButton,
86
103
  defineRecipe({
87
104
  base: {
88
- position: "absolute !important",
89
- zIndex: "101 !important",
90
- // eslint-disable-next-line spor/use-semantic-tokens
91
- bg: "bg !important",
92
- outlineWidth: "1px !important",
93
-
105
+ zIndex: "101",
94
106
  _focus: {
95
- outlineOffset: "0px !important",
107
+ outlineOffset: "0px",
108
+ alignItems: "center",
96
109
  },
97
110
  },
98
111
  variants: {
99
112
  orientation: {
100
113
  horizontal: {
101
- top: "calc(50% - 18px)",
102
- right: "calc(50% - 18px)",
114
+ top: "calc(50% - 1.1rem)",
115
+ right: "calc(50% - 1.1rem)",
103
116
  },
104
117
  vertical: {
105
- top: "calc(50% - 15px)",
118
+ top: "calc(50% - 1.1rem)",
106
119
  right: "3rem",
107
120
  transform: "rotate(90deg)",
108
121
  },
@@ -14,6 +14,8 @@ export const textareaRecipe = defineRecipe({
14
14
  "&:focus-visible, &:not(:placeholder-shown)": {
15
15
  borderTop: "var(--label-height) solid transparent",
16
16
  },
17
+ fontSize: "mobile.md",
18
+ paddingLeft: 3,
17
19
  },
18
20
  variants: {
19
21
  variant: {
@@ -1,5 +1,4 @@
1
1
  import { defineSlotRecipe } from "@chakra-ui/react";
2
- import tokens from "@vygruppen/spor-design-tokens";
3
2
 
4
3
  import { breadcrumbAnatomy } from "./anatomy";
5
4
 
@@ -15,9 +14,9 @@ export const breadcrumbSlotRecipe = defineSlotRecipe({
15
14
  link: {
16
15
  cursor: "pointer",
17
16
  borderRadius: "xs",
17
+ textDecoration: "underline",
18
18
  },
19
19
  currentLink: {
20
- borderRadius: "xs",
21
20
  cursor: "default",
22
21
  },
23
22
  separator: {
@@ -32,12 +31,10 @@ export const breadcrumbSlotRecipe = defineSlotRecipe({
32
31
  core: {
33
32
  link: {
34
33
  _hover: {
35
- outlineColor: "outline.core.hover",
36
- outlineWidth: tokens.size.stroke.md,
37
- outlineStyle: "solid",
34
+ textDecoration: "none",
35
+
38
36
  _active: {
39
37
  backgroundColor: "surface.core.active",
40
- outline: "none",
41
38
  },
42
39
  },
43
40
  },
@@ -80,6 +80,7 @@ export const datePickerSlotRecipe = defineSlotRecipe({
80
80
  boxShadow: "md",
81
81
  backgroundColor: "surface.floating",
82
82
  minHeight: "min-content",
83
+ maxWidth: "100vw",
83
84
  },
84
85
  rangeCalendarPopover: {
85
86
  width: "43rem",
@@ -3,10 +3,18 @@ import {
3
3
  Badge as ChakraBadge,
4
4
  BadgeProps as ChakraBadgeProps,
5
5
  Box,
6
+ RecipeVariantProps,
6
7
  } from "@chakra-ui/react";
7
8
  import { IconComponent } from "@vygruppen/spor-icon-react";
8
9
 
9
- export type BadgeProps = ChakraBadgeProps & { icon?: IconComponent };
10
+ import { badgeRecipie } from "../theme/recipes/badge";
11
+
12
+ type BadgeVariantProps = RecipeVariantProps<typeof badgeRecipie>;
13
+
14
+ export type BadgeProps = ChakraBadgeProps & {
15
+ colorPalette?: BadgeVariantProps["colorPalette"];
16
+ icon?: IconComponent;
17
+ };
10
18
 
11
19
  export const Badge = function Badge({
12
20
  ref,