@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.
- package/.turbo/turbo-build.log +10 -10
- package/CHANGELOG.md +34 -0
- package/dist/{CountryCodeSelect-BF22CLZQ.mjs → CountryCodeSelect-PWHXKGPJ.mjs} +1 -1
- package/dist/{chunk-NTYAUO4O.mjs → chunk-FQLXMFMW.mjs} +1003 -1148
- package/dist/index.d.mts +180 -685
- package/dist/index.d.ts +180 -685
- package/dist/index.js +1455 -1628
- package/dist/index.mjs +1 -1
- package/package.json +1 -1
- package/src/accordion/Accordion.tsx +8 -12
- package/src/accordion/Expandable.tsx +8 -26
- package/src/alert/ExpandableAlert.tsx +2 -2
- package/src/datepicker/CalendarTriggerButton.tsx +17 -13
- package/src/datepicker/DateField.tsx +50 -7
- package/src/datepicker/DatePicker.tsx +15 -4
- package/src/datepicker/DateTimeSegment.tsx +5 -1
- package/src/datepicker/StyledField.tsx +7 -1
- package/src/index.tsx +0 -1
- package/src/input/ChoiceChip.tsx +66 -55
- package/src/input/Combobox.tsx +11 -4
- package/src/input/Input.tsx +5 -1
- package/src/input/ListBox.tsx +4 -0
- package/src/input/NumericStepper.tsx +8 -6
- package/src/layout/StaticCard.tsx +0 -1
- package/src/linjetag/LineIcon.tsx +3 -8
- package/src/linjetag/TravelTag.tsx +11 -2
- package/src/linjetag/{types.d.ts → types.ts} +1 -1
- package/src/theme/components/accordion.ts +7 -40
- package/src/theme/components/datepicker.ts +2 -15
- package/src/theme/components/index.ts +0 -1
- package/src/theme/components/listbox.ts +4 -3
- package/src/accordion/AccordionContext.tsx +0 -27
- package/src/card/Card.tsx +0 -73
- package/src/card/index.tsx +0 -1
- 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,
|
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
@@ -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"
|
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
|
-
<
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
>
|
63
|
-
|
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"
|
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
|
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"
|
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
|
-
|
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
|
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 (
|
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
|
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
|
-
|
74
|
-
|
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
|
25
|
-
if (
|
26
|
-
|
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
|
-
<
|
35
|
+
<IconButton
|
33
36
|
ref={ref}
|
34
|
-
|
35
|
-
|
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
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
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
|
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
|
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
|
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
package/src/input/ChoiceChip.tsx
CHANGED
@@ -54,62 +54,73 @@ export type ChoiceChipProps = {
|
|
54
54
|
* </Stack>
|
55
55
|
* ```
|
56
56
|
*/
|
57
|
-
export const ChoiceChip = forwardRef(
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
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
|
-
|
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
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
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
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
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
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
);
|
115
|
-
});
|
119
|
+
{chipType === "filter" && state.isChecked && (
|
120
|
+
<CloseOutline24Icon marginLeft={1.5} />
|
121
|
+
)}
|
122
|
+
</chakra.div>
|
123
|
+
</chakra.label>
|
124
|
+
);
|
125
|
+
},
|
126
|
+
);
|
package/src/input/Combobox.tsx
CHANGED
@@ -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}
|