@vygruppen/spor-react 9.15.0 → 10.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 (35) hide show
  1. package/.turbo/turbo-build.log +10 -10
  2. package/CHANGELOG.md +34 -0
  3. package/dist/{CountryCodeSelect-BF22CLZQ.mjs → CountryCodeSelect-PWHXKGPJ.mjs} +1 -1
  4. package/dist/{chunk-NTYAUO4O.mjs → chunk-FQLXMFMW.mjs} +1003 -1148
  5. package/dist/index.d.mts +180 -685
  6. package/dist/index.d.ts +180 -685
  7. package/dist/index.js +1455 -1628
  8. package/dist/index.mjs +1 -1
  9. package/package.json +1 -1
  10. package/src/accordion/Accordion.tsx +8 -12
  11. package/src/accordion/Expandable.tsx +8 -26
  12. package/src/alert/ExpandableAlert.tsx +2 -2
  13. package/src/datepicker/CalendarTriggerButton.tsx +17 -13
  14. package/src/datepicker/DateField.tsx +50 -7
  15. package/src/datepicker/DatePicker.tsx +15 -4
  16. package/src/datepicker/DateTimeSegment.tsx +5 -1
  17. package/src/datepicker/StyledField.tsx +7 -1
  18. package/src/index.tsx +0 -1
  19. package/src/input/ChoiceChip.tsx +66 -55
  20. package/src/input/Combobox.tsx +11 -4
  21. package/src/input/Input.tsx +5 -1
  22. package/src/input/ListBox.tsx +4 -0
  23. package/src/input/NumericStepper.tsx +8 -6
  24. package/src/layout/StaticCard.tsx +0 -1
  25. package/src/linjetag/LineIcon.tsx +3 -8
  26. package/src/linjetag/TravelTag.tsx +11 -2
  27. package/src/linjetag/{types.d.ts → types.ts} +1 -1
  28. package/src/theme/components/accordion.ts +7 -40
  29. package/src/theme/components/datepicker.ts +2 -15
  30. package/src/theme/components/index.ts +0 -1
  31. package/src/theme/components/listbox.ts +4 -3
  32. package/src/accordion/AccordionContext.tsx +0 -27
  33. package/src/card/Card.tsx +0 -73
  34. package/src/card/index.tsx +0 -1
  35. package/src/theme/components/card.ts +0 -171
package/dist/index.mjs CHANGED
@@ -1 +1 @@
1
- export { Accordion, AccordionButton, AccordionIcon, AccordionItem, AccordionPanel, AttachedInputs, Badge, Box, Brand, Breadcrumb, BreadcrumbItem, BreadcrumbLink, Button, ButtonGroup, Card, CardSelect, CargonetLogo, Center, Checkbox, CheckboxGroup, ChoiceChip, ClosableAlert, CloseButton, Code, Collapse, ColorInlineLoader, ColorSpinner, Combobox, Container, ContentLoader, DarkFullScreenLoader, DarkInlineLoader, DarkMode, DarkSpinner, DatePicker, DateRangePicker, Divider, Drawer, DrawerBody, DrawerCloseButton, DrawerContent, DrawerFooter, ModalHeader as DrawerHeader, DrawerOverlay, Expandable, ExpandableAlert, ExpandableItem, Fade, Flex, FloatingActionButton, FormControl, FormErrorMessage, FormHelperText, FormLabel, FullScreenDrawer, Grid, GridItem, HStack, Heading, IconButton, Image, Img, InfoSelect, InfoTag, Input, InputGroup, InputLeftElement, InputRightElement, Item, ItemDescription, ItemLabel, JumpButton, Language, LanguageProvider, LightFullScreenLoader, LightInlineLoader, LightMode, LightSpinner, LineIcon, ListBox, ListItem, Modal, ModalBody, ModalCloseButton, ModalContent, ModalFooter, ModalHeader, ModalOverlay, NativeSelect, Nudge, NumericStepper, OrderedList, Pagination, PasswordInput, PhoneNumberInput, PlayPauseButton, Portal, PressableCard, ProgressBar, ProgressIndicator, ProgressLoader, Radio, RadioCard, RadioCardGroup, RadioCardGroupContext, RadioGroup, ScaleFade, SearchInput, Section, SimpleDrawer, SimpleGrid, Skeleton, SkeletonCircle, SkeletonText, SkipButton, Slide, SlideFade, Spacer, SporProvider, Stack, StaticAlert, StaticCard, Stepper, StepperStep, Switch, Tab, TabList, TabPanel, TabPanels, Table, TableCaption, Tabs, Tbody, Td, Text, TextLink, Textarea, Tfoot, Th, Thead, Time, TimePicker, Tooltip, Tr, TravelTag, UnorderedList, VStack, VyLogo, VyLogoPride, WizardNudge, Wrap, WrapItem, brandTheme, createTexts, defineStyleConfig, extendTheme, fontFaces, slugify, theme, tokens, useBreakpointValue, useClipboard, useColorMode, useColorModePreference, useColorModeValue, useControllableProp, useDisclosure, useMediaQuery, useMergeRefs, useOutsideClick, usePrefersReducedMotion, useSize, useTheme, useToast, useToken, useTranslation } from './chunk-NTYAUO4O.mjs';
1
+ export { Accordion, AccordionButton, AccordionIcon, AccordionItem, AccordionPanel, AttachedInputs, Badge, Box, Brand, Breadcrumb, BreadcrumbItem, BreadcrumbLink, Button, ButtonGroup, CardSelect, CargonetLogo, Center, Checkbox, CheckboxGroup, ChoiceChip, ClosableAlert, CloseButton, Code, Collapse, ColorInlineLoader, ColorSpinner, Combobox, Container, ContentLoader, DarkFullScreenLoader, DarkInlineLoader, DarkMode, DarkSpinner, DatePicker, DateRangePicker, Divider, Drawer, DrawerBody, DrawerCloseButton, DrawerContent, DrawerFooter, ModalHeader as DrawerHeader, DrawerOverlay, Expandable, ExpandableAlert, ExpandableItem, Fade, Flex, FloatingActionButton, FormControl, FormErrorMessage, FormHelperText, FormLabel, FullScreenDrawer, Grid, GridItem, HStack, Heading, IconButton, Image, Img, InfoSelect, InfoTag, Input, InputGroup, InputLeftElement, InputRightElement, Item, ItemDescription, ItemLabel, JumpButton, Language, LanguageProvider, LightFullScreenLoader, LightInlineLoader, LightMode, LightSpinner, LineIcon, ListBox, ListItem, Modal, ModalBody, ModalCloseButton, ModalContent, ModalFooter, ModalHeader, ModalOverlay, NativeSelect, Nudge, NumericStepper, OrderedList, Pagination, PasswordInput, PhoneNumberInput, PlayPauseButton, Portal, PressableCard, ProgressBar, ProgressIndicator, ProgressLoader, Radio, RadioCard, RadioCardGroup, RadioCardGroupContext, RadioGroup, ScaleFade, SearchInput, Section, SimpleDrawer, SimpleGrid, Skeleton, SkeletonCircle, SkeletonText, SkipButton, Slide, SlideFade, Spacer, SporProvider, Stack, StaticAlert, StaticCard, Stepper, StepperStep, Switch, Tab, TabList, TabPanel, TabPanels, Table, TableCaption, Tabs, Tbody, Td, Text, TextLink, Textarea, Tfoot, Th, Thead, Time, TimePicker, Tooltip, Tr, TravelTag, UnorderedList, VStack, VyLogo, VyLogoPride, WizardNudge, Wrap, WrapItem, brandTheme, createTexts, defineStyleConfig, extendTheme, fontFaces, slugify, theme, tokens, useBreakpointValue, useClipboard, useColorMode, useColorModePreference, useColorModeValue, useControllableProp, useDisclosure, useMediaQuery, useMergeRefs, useOutsideClick, usePrefersReducedMotion, useSize, useTheme, useToast, useToken, useTranslation } from './chunk-FQLXMFMW.mjs';
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@vygruppen/spor-react",
3
- "version": "9.15.0",
3
+ "version": "10.0.0",
4
4
  "main": "./dist/index.js",
5
5
  "module": "./dist/index.mjs",
6
6
  "types": "./dist/index.d.ts",
@@ -5,7 +5,6 @@ import {
5
5
  } from "@chakra-ui/react";
6
6
  import React from "react";
7
7
  import { Stack, StackProps } from "../layout";
8
- import { AccordionProvider } from "./AccordionContext";
9
8
  export {
10
9
  AccordionButton,
11
10
  AccordionIcon,
@@ -27,7 +26,6 @@ export type AccordionProps = Omit<ChakraAccordionProps, "variant" | "size"> & {
27
26
  * - `floating` renders a version with a drop shadow
28
27
  */
29
28
  variant?: "ghost" | "base" | "floating";
30
- size?: "sm" | "md" | "lg";
31
29
  /** The margin between accordion items */
32
30
  spacing?: StackProps["spacing"];
33
31
  };
@@ -35,7 +33,7 @@ export type AccordionProps = Omit<ChakraAccordionProps, "variant" | "size"> & {
35
33
  * Wraps a set of ExpandableItem or AccordionItem components.
36
34
  *
37
35
  * ```tsx
38
- * <Accordion variant="ghost" size="md">
36
+ * <Accordion variant="ghost">
39
37
  * <ExpandableItem title="Is Spor easy?" headingLevel="h3">
40
38
  * Yes
41
39
  * </ExpandableItem>
@@ -54,15 +52,13 @@ export const Accordion = forwardRef<AccordionProps, "div">(
54
52
  ? [props.defaultIndex]
55
53
  : props.defaultIndex;
56
54
  return (
57
- <AccordionProvider size={props.size}>
58
- <ChakraAccordion
59
- {...props}
60
- ref={ref}
61
- defaultIndex={defaultIndex as number[] | undefined}
62
- >
63
- <Stack spacing={spacing}>{children}</Stack>
64
- </ChakraAccordion>
65
- </AccordionProvider>
55
+ <ChakraAccordion
56
+ {...props}
57
+ ref={ref}
58
+ defaultIndex={defaultIndex as number[] | undefined}
59
+ >
60
+ <Stack spacing={spacing}>{children}</Stack>
61
+ </ChakraAccordion>
66
62
  );
67
63
  },
68
64
  );
@@ -9,7 +9,6 @@ import {
9
9
  } from "@chakra-ui/react";
10
10
  import React from "react";
11
11
  import { Accordion, AccordionProps } from "./Accordion";
12
- import { useAccordionContext } from "./AccordionContext";
13
12
 
14
13
  type HeadingLevel = "h2" | "h3" | "h4" | "h5" | "h6";
15
14
  type ExpandableProps = Omit<
@@ -25,10 +24,7 @@ type ExpandableProps = Omit<
25
24
  /**
26
25
  * Icon shown to the left of the title
27
26
  *
28
- * Make sure it's the outlined version of the icon.
29
- *
30
- * If the size is set to `sm` or `md` the icon should be 24px.
31
- * If the size is set to `lg`, the icon should be 30px.
27
+ * Make sure it's the 24px outlined version of the icon
32
28
  */
33
29
  leftIcon?: React.ReactNode;
34
30
 
@@ -46,7 +42,7 @@ type ExpandableProps = Omit<
46
42
  * If you want several expandables in a row, use the `Accordion` and `ExpandableItem` components instead.
47
43
  *
48
44
  * ```tsx
49
- * <Expandable title="Click for more" variant="base" size="lg">
45
+ * <Expandable title="Click for more" variant="base">
50
46
  * <Text>MORE! 🎉</Text>
51
47
  * </Expandable>
52
48
  * ```
@@ -56,7 +52,6 @@ export const Expandable = ({
56
52
  headingLevel,
57
53
  title,
58
54
  leftIcon,
59
- size = "md",
60
55
  defaultOpen,
61
56
  isOpen,
62
57
  onChange = () => {},
@@ -67,8 +62,6 @@ export const Expandable = ({
67
62
  {...rest}
68
63
  index={isOpen ? 0 : undefined}
69
64
  defaultIndex={defaultOpen ? 0 : undefined}
70
- allowMultiple={true}
71
- size={size}
72
65
  onChange={(expandedIndex) => onChange(expandedIndex === 0)}
73
66
  >
74
67
  <ExpandableItem
@@ -92,7 +85,7 @@ export type ExpandableItemProps = Omit<AccordionItemProps, "title"> & {
92
85
  /**
93
86
  * Icon shown to the left of the title
94
87
  *
95
- * Make sure it's the 30px outlined version of the icon
88
+ * Make sure it's the 24px outlined version of the icon
96
89
  */
97
90
  leftIcon?: React.ReactNode;
98
91
  };
@@ -100,7 +93,7 @@ export type ExpandableItemProps = Omit<AccordionItemProps, "title"> & {
100
93
  * An item in a set of Expandables. Must be wrapped in an `<Accordion>` component.
101
94
  *
102
95
  * ```tsx
103
- * <Accordion variant="ghost" size="md">
96
+ * <Accordion variant="ghost">
104
97
  * <ExpandableItem title="Is Spor easy?" headingLevel="h3">
105
98
  * Yes
106
99
  * </ExpandableItem>
@@ -119,8 +112,7 @@ export const ExpandableItem = ({
119
112
  leftIcon,
120
113
  ...rest
121
114
  }: ExpandableItemProps) => {
122
- const { size } = useAccordionContext();
123
- warnAboutMismatchingIcon({ icon: leftIcon, size });
115
+ warnAboutMismatchingIcon({ icon: leftIcon });
124
116
  return (
125
117
  <AccordionItem {...rest}>
126
118
  <Box as={headingLevel}>
@@ -139,9 +131,8 @@ export const ExpandableItem = ({
139
131
 
140
132
  type WarnAboutMismatchingIcon = {
141
133
  icon: any;
142
- size: AccordionProps["size"];
143
134
  };
144
- const warnAboutMismatchingIcon = ({ icon, size }: WarnAboutMismatchingIcon) => {
135
+ const warnAboutMismatchingIcon = ({ icon }: WarnAboutMismatchingIcon) => {
145
136
  if (process.env.NODE_ENV !== "production") {
146
137
  const displayName = icon?.type?.render?.displayName;
147
138
  if (!displayName) {
@@ -156,18 +147,9 @@ const warnAboutMismatchingIcon = ({ icon, size }: WarnAboutMismatchingIcon) => {
156
147
  );
157
148
  return;
158
149
  }
159
- if (size === "lg" && !displayName.includes("30Icon")) {
160
- console.warn(
161
- `The icon you passed was of the wrong size for the lg size. You passed ${displayName}, replace it with ${displayName.replace(
162
- /(\d{2})Icon/,
163
- "30Icon",
164
- )}.`,
165
- );
166
- return;
167
- }
168
- if (["md" || "sm"].includes(size!) && !displayName.includes("24Icon")) {
150
+ if (!displayName.includes("24Icon")) {
169
151
  console.warn(
170
- `The icon you passed was of the wrong size for the ${size} size. You passed ${displayName}, replace it with ${displayName.replace(
152
+ `The icon you passed was of the wrong size. You passed ${displayName}, replace it with ${displayName.replace(
171
153
  /(\d{2})Icon/,
172
154
  "24Icon",
173
155
  )}.`,
@@ -70,8 +70,8 @@ export const ExpandableAlert = ({
70
70
  // Truncate the title to one line
71
71
  display: "-webkit-box",
72
72
  overflow: "hidden",
73
- "-webkit-line-clamp": "1",
74
- "-webkit-box-orient": "vertical",
73
+ WebkitLineClamp: "1",
74
+ WebkitBoxOrient: "vertical",
75
75
  }}
76
76
  color="darkGrey"
77
77
  >
@@ -7,39 +7,43 @@ import {
7
7
  ResponsiveValue,
8
8
  } from "@chakra-ui/react";
9
9
  import { CalendarOutline24Icon } from "@vygruppen/spor-icon-react";
10
- import React from "react";
10
+ import React, { KeyboardEventHandler } from "react";
11
11
  import { AriaButtonProps } from "react-aria";
12
- import { createTexts, useTranslation } from "..";
12
+ import { IconButton, createTexts, useTranslation } from "..";
13
13
 
14
14
  type CalendarTriggerButtonProps = AriaButtonProps<"button"> & {
15
15
  variant: ResponsiveValue<"base" | "floating" | "ghost">;
16
+ isDisabled?: boolean;
17
+ ariaLabelledby?: string;
16
18
  };
17
19
  export const CalendarTriggerButton = forwardRef<CalendarTriggerButtonProps, As>(
18
- ({ variant, ...buttonProps }, ref) => {
20
+ ({ variant, isDisabled, ariaLabelledby, ...buttonProps }, ref) => {
19
21
  const { t } = useTranslation();
20
22
  const styles = useMultiStyleConfig("Datepicker", { variant });
21
23
 
22
24
  const { onPress, ...filteredButtonProps } = buttonProps;
23
25
 
24
- const handleOnPress = (event: KeyboardEvent) => {
25
- if (onPress) {
26
- if (event.key == "Enter" || event.key == " ") onPress(event as any);
26
+ const handleCommand: KeyboardEventHandler = (event) => {
27
+ if (event.key === "Enter" || event.key === " ") {
28
+ event.preventDefault();
29
+ onPress?.(event as any);
27
30
  }
28
31
  };
29
32
 
30
33
  return (
31
34
  <PopoverAnchor>
32
- <Box
35
+ <IconButton
33
36
  ref={ref}
34
- as="button"
35
- type="button"
37
+ role="button"
38
+ icon={<CalendarOutline24Icon />}
36
39
  aria-label={t(texts.openCalendar)}
37
40
  sx={styles.calendarTriggerButton}
41
+ variant="ghost"
38
42
  {...filteredButtonProps}
39
- onKeyUp={handleOnPress}
40
- >
41
- <CalendarOutline24Icon />
42
- </Box>
43
+ isDisabled={isDisabled}
44
+ onKeyDown={handleCommand}
45
+ aria-labelledby={ariaLabelledby}
46
+ />
43
47
  </PopoverAnchor>
44
48
  );
45
49
  },
@@ -1,11 +1,12 @@
1
1
  import { Box, Flex, FormLabel, useMultiStyleConfig } from "@chakra-ui/react";
2
2
  import { DateValue, GregorianCalendar } from "@internationalized/date";
3
3
  import { DOMAttributes, FocusableElement } from "@react-types/shared";
4
- import React, { RefObject, forwardRef, useRef } from "react";
4
+ import React, { RefObject, forwardRef, useId, useRef } from "react";
5
5
  import { AriaDateFieldProps, useDateField } from "react-aria";
6
- import { useDateFieldState } from "react-stately";
6
+ import { DateSegment, useDateFieldState } from "react-stately";
7
7
  import { DateTimeSegment } from "./DateTimeSegment";
8
8
  import { useCurrentLocale } from "./utils";
9
+ import { createTexts, useTranslation } from "../i18n";
9
10
 
10
11
  function createCalendar(identifier: string) {
11
12
  switch (identifier) {
@@ -20,9 +21,10 @@ type DateFieldProps = AriaDateFieldProps<DateValue> & {
20
21
  label?: React.ReactNode;
21
22
  labelProps?: DOMAttributes<FocusableElement>;
22
23
  name?: string;
24
+ labelId?: string;
23
25
  };
24
26
  export const DateField = forwardRef<HTMLDivElement, DateFieldProps>(
25
- (props, externalRef) => {
27
+ ({ labelId, ...props }, externalRef) => {
26
28
  const locale = useCurrentLocale();
27
29
  const styles = useMultiStyleConfig("Datepicker", {});
28
30
  const state = useDateFieldState({
@@ -31,9 +33,11 @@ export const DateField = forwardRef<HTMLDivElement, DateFieldProps>(
31
33
  createCalendar,
32
34
  });
33
35
 
36
+ const { t } = useTranslation();
37
+
34
38
  const internalRef = useRef(null);
35
39
  const ref = externalRef ?? internalRef;
36
- const { fieldProps, labelProps } = useDateField(
40
+ const { fieldProps } = useDateField(
37
41
  props,
38
42
  state,
39
43
  ref as RefObject<HTMLDivElement>,
@@ -43,18 +47,23 @@ export const DateField = forwardRef<HTMLDivElement, DateFieldProps>(
43
47
  <Box minWidth="6rem" width="100%">
44
48
  {props.label && (
45
49
  <FormLabel
46
- {...props.labelProps}
47
- {...labelProps}
48
50
  sx={styles.inputLabel}
49
51
  position="absolute"
50
52
  paddingTop="2px"
53
+ id={labelId}
51
54
  >
52
55
  {props.label}
53
56
  </FormLabel>
54
57
  )}
55
58
  <Flex {...fieldProps} ref={ref} paddingTop="3" paddingBottom="0.5">
56
59
  {state.segments.map((segment, i) => (
57
- <DateTimeSegment key={i} segment={segment} state={state} />
60
+ <DateTimeSegment
61
+ key={i}
62
+ segment={segment}
63
+ ariaDescription={t(getAriaLabel(segment.type))}
64
+ ariaLabel={labelId}
65
+ state={state}
66
+ />
58
67
  ))}
59
68
  </Flex>
60
69
  <input
@@ -66,3 +75,37 @@ export const DateField = forwardRef<HTMLDivElement, DateFieldProps>(
66
75
  );
67
76
  },
68
77
  );
78
+
79
+ const texts = createTexts({
80
+ day: {
81
+ nb: "Velg dag",
82
+ nn: "Vel dag",
83
+ sv: "Välj dag",
84
+ en: "Choose day",
85
+ },
86
+ month: {
87
+ nb: "Velg måned",
88
+ nn: "Vel månad",
89
+ sv: "Välj månad",
90
+ en: "Choose month",
91
+ },
92
+ year: {
93
+ nb: "Velg år",
94
+ nn: "Vel år",
95
+ sv: "Välj år",
96
+ en: "Choose year",
97
+ },
98
+ });
99
+
100
+ const getAriaLabel = (segmentType: DateSegment["type"]) => {
101
+ switch (segmentType) {
102
+ case "day":
103
+ return texts.day;
104
+ case "month":
105
+ return texts.month;
106
+ case "year":
107
+ return texts.year;
108
+ default:
109
+ return texts.day;
110
+ }
111
+ };
@@ -2,7 +2,6 @@ import {
2
2
  Box,
3
3
  BoxProps,
4
4
  FocusLock,
5
- InputGroup,
6
5
  Popover,
7
6
  PopoverAnchor,
8
7
  PopoverArrow,
@@ -10,12 +9,13 @@ import {
10
9
  PopoverContent,
11
10
  PopoverTrigger,
12
11
  Portal,
12
+ InputGroup,
13
13
  ResponsiveValue,
14
14
  useFormControlContext,
15
15
  useMultiStyleConfig,
16
16
  } from "@chakra-ui/react";
17
17
  import { DateValue } from "@internationalized/date";
18
- import React, { ReactNode, forwardRef, useRef } from "react";
18
+ import React, { ReactNode, forwardRef, useId, useRef } from "react";
19
19
  import { AriaDatePickerProps, I18nProvider, useDatePicker } from "react-aria";
20
20
  import { useDatePickerState } from "react-stately";
21
21
  import { FormErrorMessage } from "..";
@@ -68,7 +68,6 @@ export const DatePicker = forwardRef<HTMLDivElement, DatePickerProps>(
68
68
  const internalRef = useRef<HTMLDivElement>(null);
69
69
  const ref = externalRef ?? internalRef;
70
70
  const {
71
- groupProps,
72
71
  labelProps,
73
72
  fieldProps,
74
73
  buttonProps,
@@ -81,6 +80,9 @@ export const DatePicker = forwardRef<HTMLDivElement, DatePickerProps>(
81
80
  ref as React.MutableRefObject<HTMLDivElement>,
82
81
  );
83
82
 
83
+ const labelId = `label-${useId()}`;
84
+ const inputGroupId = `input-group-${useId()}`;
85
+
84
86
  const styles = useMultiStyleConfig("Datepicker", { variant });
85
87
  const locale = useCurrentLocale();
86
88
 
@@ -118,24 +120,33 @@ export const DatePicker = forwardRef<HTMLDivElement, DatePickerProps>(
118
120
  onClose={state.close}
119
121
  flip={false}
120
122
  >
121
- <InputGroup {...groupProps} display="inline-flex">
123
+ <InputGroup
124
+ display="inline-flex"
125
+ id={inputGroupId}
126
+ aria-labelledby={labelId}
127
+ >
122
128
  <PopoverAnchor>
123
129
  <StyledField
124
130
  variant={variant}
125
131
  onClick={onFieldClick}
126
132
  paddingX={3}
127
133
  minHeight={minHeight}
134
+ isDisabled={props.isDisabled}
135
+ ariaLabelledby={labelId}
128
136
  >
129
137
  <PopoverTrigger>
130
138
  <CalendarTriggerButton
131
139
  variant={variant}
132
140
  ref={ref}
141
+ isDisabled={props.isDisabled}
142
+ ariaLabelledby={labelId}
133
143
  {...buttonProps}
134
144
  />
135
145
  </PopoverTrigger>
136
146
  <DateField
137
147
  label={props.label}
138
148
  labelProps={labelProps}
149
+ labelId={labelId}
139
150
  name={props.name}
140
151
  {...fieldProps}
141
152
  />
@@ -6,6 +6,8 @@ import { DateFieldState, DateSegment } from "react-stately";
6
6
  type DateTimeSegmentProps = {
7
7
  segment: DateSegment;
8
8
  state: DateFieldState;
9
+ ariaLabel?: string;
10
+ ariaDescription?: string;
9
11
  };
10
12
  /**
11
13
  * A date time segment is a part of a date or a time stamp.
@@ -15,7 +17,7 @@ type DateTimeSegmentProps = {
15
17
  * This component should be used with the react-aria library, and is not meant to be used directly.
16
18
  * */
17
19
  export const DateTimeSegment = forwardRef<HTMLDivElement, DateTimeSegmentProps>(
18
- ({ segment, state }, externalRef) => {
20
+ ({ segment, state, ariaLabel, ariaDescription }, externalRef) => {
19
21
  const internalRef = useRef(null);
20
22
  const ref = externalRef ?? internalRef;
21
23
 
@@ -42,6 +44,8 @@ export const DateTimeSegment = forwardRef<HTMLDivElement, DateTimeSegmentProps>(
42
44
  borderRadius="xs"
43
45
  fontSize={["mobile.sm", "desktop.sm"]}
44
46
  sx={styles.dateTimeSegment}
47
+ aria-description={ariaDescription}
48
+ aria-labelledby={ariaLabel}
45
49
  >
46
50
  {isPaddable(segment.type)
47
51
  ? segment.text.padStart(2, "0")
@@ -11,19 +11,25 @@ import React from "react";
11
11
 
12
12
  type StyledFieldProps = BoxProps & {
13
13
  variant: ResponsiveValue<"base" | "floating" | "ghost">;
14
+ isDisabled?: boolean;
15
+ ariaLabelledby?: string;
14
16
  };
15
17
  export const StyledField = forwardRef<StyledFieldProps, As>(
16
- ({ children, variant, ...otherProps }, ref) => {
18
+ ({ children, variant, isDisabled, ariaLabelledby, ...otherProps }, ref) => {
17
19
  const { isInvalid } = useFormControlContext() ?? {
18
20
  isInvalid: false,
19
21
  };
22
+
20
23
  const styles = useMultiStyleConfig("Datepicker", { variant });
24
+
21
25
  return (
22
26
  <Box
23
27
  {...otherProps}
24
28
  __css={styles.wrapper}
25
29
  ref={ref}
26
30
  aria-invalid={isInvalid}
31
+ aria-disabled={isDisabled}
32
+ aria-labelledby={ariaLabelledby}
27
33
  >
28
34
  {children}
29
35
  </Box>
package/src/index.tsx CHANGED
@@ -3,7 +3,6 @@ export * from "./accordion";
3
3
  export * from "./alert";
4
4
  export * from "./breadcrumb";
5
5
  export * from "./button";
6
- export * from "./card";
7
6
  export * from "./datepicker";
8
7
  export * from "./i18n";
9
8
  export * from "./image";
@@ -54,62 +54,73 @@ export type ChoiceChipProps = {
54
54
  * </Stack>
55
55
  * ```
56
56
  */
57
- export const ChoiceChip = forwardRef((props: ChoiceChipProps, ref) => {
58
- const {
59
- children,
60
- icon,
61
- isDisabled,
62
- size = "sm",
63
- chipType = "choice",
64
- variant = "base",
65
- } = props;
57
+ export const ChoiceChip = forwardRef(
58
+ (
59
+ {
60
+ children,
61
+ icon,
62
+ isChecked,
63
+ isDisabled,
64
+ size = "sm",
65
+ chipType = "choice",
66
+ variant = "base",
67
+ ...props
68
+ }: ChoiceChipProps,
69
+ ref,
70
+ ) => {
71
+ const {
72
+ state,
73
+ getInputProps,
74
+ getCheckboxProps,
75
+ getRootProps,
76
+ getLabelProps,
77
+ } = useCheckbox(props);
78
+ const styles = useMultiStyleConfig("ChoiceChip", {
79
+ size,
80
+ chipType,
81
+ variant,
82
+ icon,
83
+ hasLabel: chipType !== "icon",
84
+ });
66
85
 
67
- const {
68
- state,
69
- getInputProps,
70
- getCheckboxProps,
71
- getRootProps,
72
- getLabelProps,
73
- } = useCheckbox(props);
74
- const styles = useMultiStyleConfig("ChoiceChip", {
75
- size,
76
- chipType,
77
- variant,
78
- icon,
79
- hasLabel: Boolean(children),
80
- });
86
+ const id = `choice-chip-${useId()}`;
81
87
 
82
- const id = `choice-chip-${useId()}`;
83
-
84
- return (
85
- <chakra.label
86
- htmlFor={id}
87
- {...getRootProps()}
88
- aria-label={String(children)}
89
- >
90
- <chakra.input {...getInputProps({}, ref)} id={id} disabled={isDisabled} />
91
- <chakra.div
92
- {...getLabelProps()}
93
- __css={styles.container}
94
- data-checked={dataAttr(state.isChecked)}
95
- data-hover={dataAttr(state.isHovered)}
96
- data-focus={dataAttr(state.isFocused)}
97
- data-active={dataAttr(state.isActive)}
98
- data-disabled={dataAttr(state.isDisabled)}
88
+ return (
89
+ <chakra.label
90
+ htmlFor={id}
91
+ {...getRootProps()}
92
+ aria-label={String(children)}
99
93
  >
100
- {icon && (
101
- <chakra.span __css={styles.icon}>
102
- {state.isChecked ? icon.checked : icon.default}
103
- </chakra.span>
104
- )}
94
+ <chakra.input
95
+ {...getInputProps({}, ref)}
96
+ id={id}
97
+ disabled={isDisabled}
98
+ />
99
+ <chakra.div
100
+ {...getLabelProps()}
101
+ __css={styles.container}
102
+ data-checked={dataAttr(state.isChecked)}
103
+ data-hover={dataAttr(state.isHovered)}
104
+ data-focus={dataAttr(state.isFocused)}
105
+ data-active={dataAttr(state.isActive)}
106
+ data-disabled={dataAttr(state.isDisabled)}
107
+ >
108
+ {icon && (
109
+ <chakra.span __css={styles.icon}>
110
+ {state.isChecked ? icon.checked : icon.default}
111
+ </chakra.span>
112
+ )}
113
+ {chipType !== "icon" && (
114
+ <chakra.span __css={styles.label} {...getCheckboxProps()}>
115
+ {children}
116
+ </chakra.span>
117
+ )}
105
118
 
106
- <chakra.span __css={styles.label} {...getCheckboxProps()}>
107
- {chipType !== "icon" && children}
108
- </chakra.span>
109
- {chipType === "filter" && state.isChecked && (
110
- <CloseOutline24Icon marginLeft={1.5} />
111
- )}
112
- </chakra.div>
113
- </chakra.label>
114
- );
115
- });
119
+ {chipType === "filter" && state.isChecked && (
120
+ <CloseOutline24Icon marginLeft={1.5} />
121
+ )}
122
+ </chakra.div>
123
+ </chakra.label>
124
+ );
125
+ },
126
+ );
@@ -1,4 +1,4 @@
1
- import React, { useEffect, useRef, useState } from "react";
1
+ import React, { useEffect, useId, useRef, useState } from "react";
2
2
  import { AriaComboBoxProps, useComboBox, useFilter } from "react-aria";
3
3
  import { useComboBoxState } from "react-stately";
4
4
  import { ColorSpinner, Input, InputProps, ListBox } from "..";
@@ -93,16 +93,17 @@ export function Combobox<T extends object>({
93
93
 
94
94
  const fallbackInputRef = useRef<HTMLInputElement>(null);
95
95
  const inputRef = externalInputRef ?? fallbackInputRef;
96
- const listBoxRef = useRef(null);
96
+ const listBoxRef = useRef<HTMLUListElement>(null);
97
97
  const popoverRef = useRef(null);
98
98
 
99
+ const listboxId = `${useId()}-listbox`;
100
+
99
101
  const inputWidth = useInputWidth(inputRef);
100
102
 
101
103
  const state = useComboBoxState({
102
104
  allowsEmptyCollection: Boolean(emptyContent),
103
105
  defaultFilter: contains,
104
106
  shouldCloseOnBlur: true,
105
- label,
106
107
  ...rest,
107
108
  });
108
109
 
@@ -133,6 +134,7 @@ export function Combobox<T extends object>({
133
134
  inputRef,
134
135
  listBoxRef,
135
136
  popoverRef,
137
+ label,
136
138
  },
137
139
  state,
138
140
  );
@@ -143,7 +145,11 @@ export function Combobox<T extends object>({
143
145
  {...styleProps(comboBoxProps)}
144
146
  aria-haspopup="listbox"
145
147
  ref={inputRef}
148
+ role="combobox"
146
149
  label={label}
150
+ aria-expanded={state.isOpen}
151
+ aria-autocomplete="list"
152
+ aria-controls={listboxId}
147
153
  borderBottomLeftRadius={
148
154
  state.isOpen && !isLoading ? 0 : borderBottomLeftRadius
149
155
  }
@@ -169,7 +175,7 @@ export function Combobox<T extends object>({
169
175
  )
170
176
  }
171
177
  />
172
-
178
+ <span aria-hidden="true" data-trigger="multiselect"></span>
173
179
  {state.isOpen && !isLoading && (
174
180
  <Popover
175
181
  state={state}
@@ -186,6 +192,7 @@ export function Combobox<T extends object>({
186
192
  <ListBox
187
193
  {...listBoxProps}
188
194
  state={state}
195
+ id={listboxId}
189
196
  listBoxRef={listBoxRef}
190
197
  emptyContent={emptyContent}
191
198
  maxWidth={inputWidth}