@vygruppen/spor-react 13.4.6 → 13.6.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/.turbo/turbo-postinstall.log +2 -2
- package/CHANGELOG.md +24 -0
- package/dist/index.cjs +102 -16
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +41 -6
- package/dist/index.d.ts +41 -6
- package/dist/index.mjs +102 -16
- package/dist/index.mjs.map +1 -1
- package/package.json +3 -2
- package/src/accordion/Accordion.stories.tsx +51 -0
- package/src/alert/Alert.stories.tsx +45 -0
- package/src/button/Button.stories.tsx +69 -0
- package/src/datepicker/DatePicker.tsx +5 -3
- package/src/datepicker/DateRangePicker.tsx +3 -0
- package/src/datepicker/DateTimeSegment.tsx +0 -1
- package/src/datepicker/StyledField.tsx +2 -2
- package/src/datepicker/TimeField.tsx +0 -2
- package/src/datepicker/TimePicker.tsx +5 -2
- package/src/datepicker/types.ts +1 -0
- package/src/input/Input.stories.tsx +62 -0
- package/src/layout/RadioCard.tsx +3 -0
- package/src/theme/brand.ts +5 -0
- package/src/theme/index.ts +4 -0
- package/src/theme/semantic-tokens/colors.ts +13 -0
- package/src/theme/semantic-tokens/index.ts +10 -1
- package/src/theme/slot-recipes/anatomy.ts +1 -0
- package/src/theme/slot-recipes/datepicker.ts +17 -0
- package/src/theme/slot-recipes/radio-card.ts +52 -0
- package/src/toast/toast.tsx +24 -0
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@vygruppen/spor-react",
|
|
3
3
|
"type": "module",
|
|
4
|
-
"version": "13.
|
|
4
|
+
"version": "13.6.0",
|
|
5
5
|
"exports": {
|
|
6
6
|
".": {
|
|
7
7
|
"types": "./dist/index.d.ts",
|
|
@@ -46,13 +46,14 @@
|
|
|
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
|
|
49
|
+
"@vygruppen/spor-design-tokens": "5.1.0",
|
|
50
50
|
"@vygruppen/spor-icon-react": "5.0.2",
|
|
51
51
|
"@vygruppen/spor-loader": "0.7.0"
|
|
52
52
|
},
|
|
53
53
|
"devDependencies": {
|
|
54
54
|
"@react-types/datepicker": "^3.10.0",
|
|
55
55
|
"@react-types/shared": "^3.27.0",
|
|
56
|
+
"@storybook/react": "^8",
|
|
56
57
|
"@testing-library/jest-dom": "^6.9.1",
|
|
57
58
|
"@testing-library/react": "^16.3.2",
|
|
58
59
|
"@testing-library/user-event": "^14.6.1",
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
import type { Meta, StoryObj } from "@storybook/react";
|
|
2
|
+
import {
|
|
3
|
+
Accordion,
|
|
4
|
+
Box,
|
|
5
|
+
Expandable,
|
|
6
|
+
ExpandableItem,
|
|
7
|
+
} from "@vygruppen/spor-react";
|
|
8
|
+
|
|
9
|
+
const meta = {
|
|
10
|
+
title: "Components/Accordion",
|
|
11
|
+
component: Accordion,
|
|
12
|
+
} satisfies Meta<typeof Accordion>;
|
|
13
|
+
|
|
14
|
+
export default meta;
|
|
15
|
+
|
|
16
|
+
type Story = StoryObj<typeof meta>;
|
|
17
|
+
|
|
18
|
+
export const Grouped: Story = {
|
|
19
|
+
render: () => (
|
|
20
|
+
<Box>
|
|
21
|
+
<Accordion collapsible defaultValue={["refunds"]}>
|
|
22
|
+
<ExpandableItem value="refunds" title="Can I change my ticket?">
|
|
23
|
+
Yes, ticket changes depend on fare rules and route availability.
|
|
24
|
+
</ExpandableItem>
|
|
25
|
+
<ExpandableItem value="pets" title="Can I bring my pet?">
|
|
26
|
+
Small pets are usually allowed if they do not disturb other
|
|
27
|
+
passengers.
|
|
28
|
+
</ExpandableItem>
|
|
29
|
+
<ExpandableItem value="bike" title="Can I bring a bicycle?">
|
|
30
|
+
Bicycle availability varies between departures and must be reserved
|
|
31
|
+
when required.
|
|
32
|
+
</ExpandableItem>
|
|
33
|
+
</Accordion>
|
|
34
|
+
</Box>
|
|
35
|
+
),
|
|
36
|
+
};
|
|
37
|
+
|
|
38
|
+
export const SingleExpandable: Story = {
|
|
39
|
+
render: () => (
|
|
40
|
+
<Box>
|
|
41
|
+
<Expandable
|
|
42
|
+
title="Read more about onboard services"
|
|
43
|
+
variant="floating"
|
|
44
|
+
defaultValue={["single-expandable"]}
|
|
45
|
+
>
|
|
46
|
+
Wi‑Fi, power outlets, and accessible seating may vary by train set and
|
|
47
|
+
route.
|
|
48
|
+
</Expandable>
|
|
49
|
+
</Box>
|
|
50
|
+
),
|
|
51
|
+
};
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import type { Meta, StoryObj } from "@storybook/react";
|
|
2
|
+
import { Alert, Flex } from "@vygruppen/spor-react";
|
|
3
|
+
|
|
4
|
+
const meta = {
|
|
5
|
+
title: "Components/Alert",
|
|
6
|
+
component: Alert,
|
|
7
|
+
args: {
|
|
8
|
+
title: "Traffic update",
|
|
9
|
+
children: "Track work may affect departures this afternoon.",
|
|
10
|
+
},
|
|
11
|
+
} satisfies Meta<typeof Alert>;
|
|
12
|
+
|
|
13
|
+
export default meta;
|
|
14
|
+
|
|
15
|
+
type Story = StoryObj<typeof meta>;
|
|
16
|
+
|
|
17
|
+
const variants = [
|
|
18
|
+
"info",
|
|
19
|
+
"important",
|
|
20
|
+
"alt",
|
|
21
|
+
"error",
|
|
22
|
+
"error-secondary",
|
|
23
|
+
"success",
|
|
24
|
+
] as const;
|
|
25
|
+
|
|
26
|
+
export const Overview: Story = {
|
|
27
|
+
render: () => (
|
|
28
|
+
<Flex gap={2} direction="column">
|
|
29
|
+
{variants.map((variant) => (
|
|
30
|
+
<Alert key={variant} variant={variant} title={variant}>
|
|
31
|
+
Example of the {variant} alert variant.
|
|
32
|
+
</Alert>
|
|
33
|
+
))}
|
|
34
|
+
</Flex>
|
|
35
|
+
),
|
|
36
|
+
};
|
|
37
|
+
|
|
38
|
+
export const Closable: Story = {
|
|
39
|
+
args: {
|
|
40
|
+
variant: "info",
|
|
41
|
+
closable: true,
|
|
42
|
+
title: "Dismissible message",
|
|
43
|
+
children: "This alert can be closed by the user.",
|
|
44
|
+
},
|
|
45
|
+
};
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
import type { Meta, StoryObj } from "@storybook/react";
|
|
2
|
+
import { Box, Button, Flex } from "@vygruppen/spor-react";
|
|
3
|
+
|
|
4
|
+
const meta = {
|
|
5
|
+
title: "Components/Button",
|
|
6
|
+
component: Button,
|
|
7
|
+
args: {
|
|
8
|
+
children: "Book trip",
|
|
9
|
+
},
|
|
10
|
+
} satisfies Meta<typeof Button>;
|
|
11
|
+
|
|
12
|
+
export default meta;
|
|
13
|
+
|
|
14
|
+
type Story = StoryObj<typeof meta>;
|
|
15
|
+
|
|
16
|
+
const variants = [
|
|
17
|
+
"primary",
|
|
18
|
+
"secondary",
|
|
19
|
+
"tertiary",
|
|
20
|
+
"ghost",
|
|
21
|
+
"floating",
|
|
22
|
+
] as const;
|
|
23
|
+
const sizes = ["lg", "md", "sm", "xs"] as const;
|
|
24
|
+
|
|
25
|
+
const icon = (symbol: string) => <span aria-hidden="true">{symbol}</span>;
|
|
26
|
+
|
|
27
|
+
export const Overview: Story = {
|
|
28
|
+
render: () => (
|
|
29
|
+
<Box display="grid" gap={4}>
|
|
30
|
+
{sizes.map((size) => (
|
|
31
|
+
<Flex key={size} alignItems="center" gap={2}>
|
|
32
|
+
{variants.map((variant) => (
|
|
33
|
+
<Button key={`${size}-${variant}`} size={size} variant={variant}>
|
|
34
|
+
{variant}
|
|
35
|
+
</Button>
|
|
36
|
+
))}
|
|
37
|
+
</Flex>
|
|
38
|
+
))}
|
|
39
|
+
</Box>
|
|
40
|
+
),
|
|
41
|
+
};
|
|
42
|
+
|
|
43
|
+
export const WithIcons: Story = {
|
|
44
|
+
render: () => (
|
|
45
|
+
<Flex gap={4}>
|
|
46
|
+
<Button leftIcon={icon("←")}>Left icon</Button>
|
|
47
|
+
<Button rightIcon={icon("→")}>Right icon</Button>
|
|
48
|
+
<Button leftIcon={icon("★")} rightIcon={icon("→")} variant="secondary">
|
|
49
|
+
Both icons
|
|
50
|
+
</Button>
|
|
51
|
+
</Flex>
|
|
52
|
+
),
|
|
53
|
+
};
|
|
54
|
+
|
|
55
|
+
export const States: Story = {
|
|
56
|
+
render: () => (
|
|
57
|
+
<Flex gap={4}>
|
|
58
|
+
<Button loading loadingText="Loading">
|
|
59
|
+
Loading
|
|
60
|
+
</Button>
|
|
61
|
+
<Button disabled variant="secondary">
|
|
62
|
+
Disabled
|
|
63
|
+
</Button>
|
|
64
|
+
<Button loading variant="ghost" leftIcon={icon("⟳")}>
|
|
65
|
+
Refreshing
|
|
66
|
+
</Button>
|
|
67
|
+
</Flex>
|
|
68
|
+
),
|
|
69
|
+
};
|
|
@@ -56,6 +56,7 @@ type DatePickerProps = Omit<AriaDatePickerProps<DateValue>, "onChange"> &
|
|
|
56
56
|
* A date picker component.
|
|
57
57
|
*
|
|
58
58
|
* There are three different variants –`core`, `floating` and `ghost`.
|
|
59
|
+
* There are two different sizes - `sm` and `md`
|
|
59
60
|
*
|
|
60
61
|
* ```tsx
|
|
61
62
|
* <DatePicker label="Dato" variant="core" />
|
|
@@ -65,6 +66,7 @@ type DatePickerProps = Omit<AriaDatePickerProps<DateValue>, "onChange"> &
|
|
|
65
66
|
export const DatePicker = ({
|
|
66
67
|
ref: externalRef,
|
|
67
68
|
variant,
|
|
69
|
+
size,
|
|
68
70
|
errorText,
|
|
69
71
|
minHeight,
|
|
70
72
|
showYearNavigation,
|
|
@@ -144,12 +146,13 @@ export const DatePicker = ({
|
|
|
144
146
|
invalid={invalid}
|
|
145
147
|
helperText={helperText}
|
|
146
148
|
required={props.required}
|
|
149
|
+
size={size}
|
|
147
150
|
>
|
|
148
151
|
<PopoverAnchor>
|
|
149
152
|
<StyledField
|
|
150
153
|
variant={variant}
|
|
154
|
+
size={size}
|
|
151
155
|
onClick={onFieldClick}
|
|
152
|
-
paddingX={3}
|
|
153
156
|
minHeight={minHeight}
|
|
154
157
|
isDisabled={props.isDisabled}
|
|
155
158
|
isActive={props.isActive}
|
|
@@ -162,8 +165,7 @@ export const DatePicker = ({
|
|
|
162
165
|
) : (
|
|
163
166
|
<ChakraPopover.Trigger asChild>
|
|
164
167
|
<CalendarTriggerButton
|
|
165
|
-
|
|
166
|
-
paddingRight={1}
|
|
168
|
+
marginLeft={1}
|
|
167
169
|
variant={variant}
|
|
168
170
|
ref={ref}
|
|
169
171
|
{...buttonProps}
|
|
@@ -52,12 +52,14 @@ type DateRangePickerProps = Omit<
|
|
|
52
52
|
* A date range picker component.
|
|
53
53
|
*
|
|
54
54
|
* There are three variants to choose from – `core`, `floating` and `ghost`.
|
|
55
|
+
* There are two different sizes - `sm` and `md`
|
|
55
56
|
*
|
|
56
57
|
* ```tsx
|
|
57
58
|
* <DateRangePicker startLabel="From" startName="from" endLabel="To" endName="to" variant="core" />
|
|
58
59
|
* ```
|
|
59
60
|
*/ export function DateRangePicker({
|
|
60
61
|
variant = "core",
|
|
62
|
+
size,
|
|
61
63
|
minHeight,
|
|
62
64
|
startName,
|
|
63
65
|
endName,
|
|
@@ -135,6 +137,7 @@ type DateRangePickerProps = Omit<
|
|
|
135
137
|
alignItems="center"
|
|
136
138
|
paddingX={3}
|
|
137
139
|
variant={variant}
|
|
140
|
+
size={size}
|
|
138
141
|
onClick={onFieldClick}
|
|
139
142
|
minHeight={minHeight}
|
|
140
143
|
>
|
|
@@ -29,6 +29,7 @@ export const StyledField = function StyledField({
|
|
|
29
29
|
isDisabled,
|
|
30
30
|
isActive,
|
|
31
31
|
overrideBorderColor,
|
|
32
|
+
size,
|
|
32
33
|
...otherProps
|
|
33
34
|
} = props;
|
|
34
35
|
const { invalid } = useFieldContext() ?? {
|
|
@@ -38,7 +39,7 @@ export const StyledField = function StyledField({
|
|
|
38
39
|
const recipe = useSlotRecipe({
|
|
39
40
|
key: "datePicker",
|
|
40
41
|
});
|
|
41
|
-
const styles = recipe({ variant });
|
|
42
|
+
const styles = recipe({ variant, size });
|
|
42
43
|
|
|
43
44
|
return (
|
|
44
45
|
<Box
|
|
@@ -51,7 +52,6 @@ export const StyledField = function StyledField({
|
|
|
51
52
|
ref={ref}
|
|
52
53
|
aria-invalid={invalid}
|
|
53
54
|
aria-disabled={isDisabled}
|
|
54
|
-
fontSize={["mobile.md", "desktop.md"]}
|
|
55
55
|
>
|
|
56
56
|
{children}
|
|
57
57
|
</Box>
|
|
@@ -50,6 +50,11 @@ type TimePickerProps = Omit<BoxProps, "defaultValue" | "onChange"> &
|
|
|
50
50
|
* Defaults to "core".
|
|
51
51
|
*/
|
|
52
52
|
variant?: "core" | "floating" | "ghost";
|
|
53
|
+
/**
|
|
54
|
+
* The size of the time picker.
|
|
55
|
+
* Defaults to "md".
|
|
56
|
+
*/
|
|
57
|
+
size?: "sm" | "md";
|
|
53
58
|
};
|
|
54
59
|
/** A time picker component.
|
|
55
60
|
*
|
|
@@ -137,10 +142,8 @@ export const TimePicker = ({
|
|
|
137
142
|
<Field as="time" {...boxProps}>
|
|
138
143
|
<StyledField
|
|
139
144
|
width="fit-content"
|
|
140
|
-
paddingX={2}
|
|
141
145
|
alignItems="center"
|
|
142
146
|
justifyContent="space-between"
|
|
143
|
-
gap={2}
|
|
144
147
|
opacity={isDisabled ? 0.5 : 1}
|
|
145
148
|
pointerEvents={isDisabled ? "none" : "auto"}
|
|
146
149
|
aria-disabled={isDisabled}
|
package/src/datepicker/types.ts
CHANGED
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
import type { Meta, StoryObj } from "@storybook/react";
|
|
2
|
+
import { Box, Flex, Input, SearchInput, Textarea } from "@vygruppen/spor-react";
|
|
3
|
+
import { useState } from "react";
|
|
4
|
+
|
|
5
|
+
const meta = {
|
|
6
|
+
title: "Components/Input",
|
|
7
|
+
component: Input,
|
|
8
|
+
} satisfies Meta<typeof Input>;
|
|
9
|
+
|
|
10
|
+
export default meta;
|
|
11
|
+
|
|
12
|
+
type Story = StoryObj<typeof meta>;
|
|
13
|
+
|
|
14
|
+
export const Overview: Story = {
|
|
15
|
+
render: () => (
|
|
16
|
+
<Flex direction="column" gap={4}>
|
|
17
|
+
<Input label="Name" helperText="Enter your full name" />
|
|
18
|
+
<Input
|
|
19
|
+
label="Email"
|
|
20
|
+
variant="floating"
|
|
21
|
+
type="email"
|
|
22
|
+
helperText="Used for booking updates"
|
|
23
|
+
/>
|
|
24
|
+
<Input label="Disabled field" disabled value="Unavailable" />
|
|
25
|
+
</Flex>
|
|
26
|
+
),
|
|
27
|
+
};
|
|
28
|
+
|
|
29
|
+
export const Textareas: Story = {
|
|
30
|
+
render: () => (
|
|
31
|
+
<Flex direction="column" gap={4}>
|
|
32
|
+
<Textarea label="Message" helperText="Share additional travel details" />
|
|
33
|
+
<Textarea
|
|
34
|
+
label="Accessibility needs"
|
|
35
|
+
variant="floating"
|
|
36
|
+
helperText="Optional"
|
|
37
|
+
defaultValue="Wheelchair assistance at Oslo S."
|
|
38
|
+
/>
|
|
39
|
+
</Flex>
|
|
40
|
+
),
|
|
41
|
+
};
|
|
42
|
+
|
|
43
|
+
export const Search: Story = {
|
|
44
|
+
render: () => {
|
|
45
|
+
const SearchExample = () => {
|
|
46
|
+
const [value, setValue] = useState("Oslo");
|
|
47
|
+
|
|
48
|
+
return (
|
|
49
|
+
<Box>
|
|
50
|
+
<SearchInput
|
|
51
|
+
label="Search departures"
|
|
52
|
+
value={value}
|
|
53
|
+
onChange={(event) => setValue(event.target.value)}
|
|
54
|
+
onReset={() => setValue("")}
|
|
55
|
+
/>
|
|
56
|
+
</Box>
|
|
57
|
+
);
|
|
58
|
+
};
|
|
59
|
+
|
|
60
|
+
return <SearchExample />;
|
|
61
|
+
},
|
|
62
|
+
};
|
package/src/layout/RadioCard.tsx
CHANGED
|
@@ -36,10 +36,12 @@ type RadioCardItemProps = Exclude<
|
|
|
36
36
|
RadioCardVariantProps & {
|
|
37
37
|
inputProps?: React.InputHTMLAttributes<HTMLInputElement>;
|
|
38
38
|
ariaLabel?: string;
|
|
39
|
+
showIndicator?: boolean;
|
|
39
40
|
};
|
|
40
41
|
|
|
41
42
|
export const RadioCard = ({
|
|
42
43
|
ref,
|
|
44
|
+
showIndicator = false,
|
|
43
45
|
...props
|
|
44
46
|
}: RadioCardItemProps & {
|
|
45
47
|
ref?: React.Ref<HTMLInputElement>;
|
|
@@ -61,6 +63,7 @@ export const RadioCard = ({
|
|
|
61
63
|
{...inputProps}
|
|
62
64
|
/>
|
|
63
65
|
<ChakraRadioCard.ItemControl id={itemControlId} aria-hidden>
|
|
66
|
+
{showIndicator && <ChakraRadioCard.ItemIndicator />}
|
|
64
67
|
{children}
|
|
65
68
|
</ChakraRadioCard.ItemControl>
|
|
66
69
|
</ChakraRadioCard.Item>
|
package/src/theme/brand.ts
CHANGED
|
@@ -1,6 +1,11 @@
|
|
|
1
1
|
export enum Brand {
|
|
2
2
|
VyDigital = "VyDigital",
|
|
3
|
+
/**
|
|
4
|
+
* @deprecated The VyUtvikling theme is deprecated and will be removed in a
|
|
5
|
+
* future major version. Use {@link Brand.VyTeknologi} instead.
|
|
6
|
+
*/
|
|
3
7
|
VyUtvikling = "VyUtvikling",
|
|
8
|
+
VyTeknologi = "VyTeknologi",
|
|
4
9
|
CargoNet = "CargoNet",
|
|
5
10
|
}
|
|
6
11
|
|
package/src/theme/index.ts
CHANGED
|
@@ -3,7 +3,12 @@ import tokens from "@vygruppen/spor-design-tokens/raw-tokens";
|
|
|
3
3
|
|
|
4
4
|
export enum Brand {
|
|
5
5
|
VyDigital = "VyDigital",
|
|
6
|
+
/**
|
|
7
|
+
* @deprecated The VyUtvikling theme is deprecated and will be removed in a
|
|
8
|
+
* future major version. Use {@link Brand.VyTeknologi} instead.
|
|
9
|
+
*/
|
|
6
10
|
VyUtvikling = "VyUtvikling",
|
|
11
|
+
VyTeknologi = "VyTeknologi",
|
|
7
12
|
CargoNet = "CargoNet",
|
|
8
13
|
}
|
|
9
14
|
|
|
@@ -11,10 +16,18 @@ export const vyDigitalColors = defineSemanticTokens.colors({
|
|
|
11
16
|
...tokens.color["vy-digital"].color.vyDigital,
|
|
12
17
|
});
|
|
13
18
|
|
|
19
|
+
/**
|
|
20
|
+
* @deprecated The VyUtvikling theme is deprecated and will be removed in a
|
|
21
|
+
* future major version. Use {@link vyTeknologiColors} instead.
|
|
22
|
+
*/
|
|
14
23
|
export const vyUtviklingColors = defineSemanticTokens.colors({
|
|
15
24
|
...tokens.color["vy-utvikling"].color.vyUtvikling,
|
|
16
25
|
});
|
|
17
26
|
|
|
27
|
+
export const vyTeknologiColors = defineSemanticTokens.colors({
|
|
28
|
+
...tokens.color["vy-teknologi"].color.vyTeknologi,
|
|
29
|
+
});
|
|
30
|
+
|
|
18
31
|
export const cargonetColors = defineSemanticTokens.colors({
|
|
19
32
|
...tokens.color["cargonet"].color.cargonet,
|
|
20
33
|
});
|
|
@@ -1,5 +1,10 @@
|
|
|
1
1
|
import { Brand } from "../brand";
|
|
2
|
-
import {
|
|
2
|
+
import {
|
|
3
|
+
cargonetColors,
|
|
4
|
+
vyDigitalColors,
|
|
5
|
+
vyTeknologiColors,
|
|
6
|
+
vyUtviklingColors,
|
|
7
|
+
} from "./colors";
|
|
3
8
|
import { radii } from "./radii";
|
|
4
9
|
import { shadows } from "./shadows";
|
|
5
10
|
|
|
@@ -13,6 +18,10 @@ export const semanticTokens = {
|
|
|
13
18
|
...baseSemanticTokens,
|
|
14
19
|
colors: vyUtviklingColors,
|
|
15
20
|
},
|
|
21
|
+
[Brand.VyTeknologi]: {
|
|
22
|
+
...baseSemanticTokens,
|
|
23
|
+
colors: vyTeknologiColors,
|
|
24
|
+
},
|
|
16
25
|
[Brand.CargoNet]: {
|
|
17
26
|
...baseSemanticTokens,
|
|
18
27
|
colors: cargonetColors,
|
|
@@ -13,6 +13,8 @@ export const datePickerSlotRecipe = defineSlotRecipe({
|
|
|
13
13
|
display: "flex",
|
|
14
14
|
flex: 1,
|
|
15
15
|
paddingY: 0.5,
|
|
16
|
+
paddingX: 2,
|
|
17
|
+
gap: 1.5,
|
|
16
18
|
alignItems: "center",
|
|
17
19
|
_hover: {
|
|
18
20
|
zIndex: "docked",
|
|
@@ -237,8 +239,23 @@ export const datePickerSlotRecipe = defineSlotRecipe({
|
|
|
237
239
|
},
|
|
238
240
|
},
|
|
239
241
|
},
|
|
242
|
+
size: {
|
|
243
|
+
sm: {
|
|
244
|
+
wrapper: {
|
|
245
|
+
fontSize: ["mobile.xs", "desktop.xs"],
|
|
246
|
+
paddingX: 1,
|
|
247
|
+
gap: 1,
|
|
248
|
+
},
|
|
249
|
+
},
|
|
250
|
+
md: {
|
|
251
|
+
wrapper: {
|
|
252
|
+
fontSize: ["mobile.sm", "desktop.sm"],
|
|
253
|
+
},
|
|
254
|
+
},
|
|
255
|
+
},
|
|
240
256
|
},
|
|
241
257
|
defaultVariants: {
|
|
242
258
|
variant: "core",
|
|
259
|
+
size: "md",
|
|
243
260
|
},
|
|
244
261
|
});
|
|
@@ -37,6 +37,58 @@ export const radioCardSlotRecipe = defineSlotRecipe({
|
|
|
37
37
|
fontWeight: "bold",
|
|
38
38
|
fontSize: "inherit",
|
|
39
39
|
},
|
|
40
|
+
itemControl: {
|
|
41
|
+
display: "flex",
|
|
42
|
+
alignItems: "flex-start",
|
|
43
|
+
justifyContent: "flex-start",
|
|
44
|
+
},
|
|
45
|
+
|
|
46
|
+
itemIndicator: {
|
|
47
|
+
display: "inline-flex",
|
|
48
|
+
flexShrink: 0,
|
|
49
|
+
alignItems: "center",
|
|
50
|
+
justifyContent: "center",
|
|
51
|
+
borderWidth: "2px",
|
|
52
|
+
borderColor: "outline.core",
|
|
53
|
+
borderRadius: "xl",
|
|
54
|
+
width: 3,
|
|
55
|
+
height: 3,
|
|
56
|
+
marginRight: 2,
|
|
57
|
+
marginTop: 0.5,
|
|
58
|
+
|
|
59
|
+
_checked: {
|
|
60
|
+
borderColor: "surface.brand",
|
|
61
|
+
},
|
|
62
|
+
_hover: {
|
|
63
|
+
borderColor: "surface.brand.hover",
|
|
64
|
+
"& .dot": {
|
|
65
|
+
backgroundColor: "surface.brand.hover",
|
|
66
|
+
},
|
|
67
|
+
},
|
|
68
|
+
|
|
69
|
+
_disabled: {
|
|
70
|
+
pointerEvents: "none",
|
|
71
|
+
backgroundColor: "surface.disabled",
|
|
72
|
+
borderColor: "outline.disabled",
|
|
73
|
+
"& .dot": {
|
|
74
|
+
backgroundColor: "outline.disabled",
|
|
75
|
+
},
|
|
76
|
+
},
|
|
77
|
+
_focusVisible: {
|
|
78
|
+
outlineWidth: "2px",
|
|
79
|
+
outlineColor: "outline.focus",
|
|
80
|
+
outlineStyle: "solid",
|
|
81
|
+
outlineOffset: "1px",
|
|
82
|
+
},
|
|
83
|
+
|
|
84
|
+
"& .dot": {
|
|
85
|
+
height: "full",
|
|
86
|
+
width: "full",
|
|
87
|
+
borderRadius: "xl",
|
|
88
|
+
backgroundColor: "surface.brand",
|
|
89
|
+
scale: "0.5",
|
|
90
|
+
},
|
|
91
|
+
},
|
|
40
92
|
},
|
|
41
93
|
variants: {
|
|
42
94
|
variant: {
|
package/src/toast/toast.tsx
CHANGED
|
@@ -10,6 +10,7 @@ import {
|
|
|
10
10
|
} from "@chakra-ui/react";
|
|
11
11
|
|
|
12
12
|
import { AlertIcon } from "@/alert/AlertIcon";
|
|
13
|
+
import { Button, CloseButton } from "@/button";
|
|
13
14
|
|
|
14
15
|
const toaster = createToaster({
|
|
15
16
|
placement: "bottom",
|
|
@@ -18,11 +19,18 @@ const toaster = createToaster({
|
|
|
18
19
|
|
|
19
20
|
type Variant = "info" | "success" | "error";
|
|
20
21
|
|
|
22
|
+
type ToastAction = {
|
|
23
|
+
label: string;
|
|
24
|
+
onClick: () => void;
|
|
25
|
+
};
|
|
26
|
+
|
|
21
27
|
type ToastProps = {
|
|
22
28
|
duration?: number;
|
|
23
29
|
text: string;
|
|
24
30
|
variant: Variant;
|
|
25
31
|
id?: string;
|
|
32
|
+
action?: ToastAction;
|
|
33
|
+
closable?: boolean;
|
|
26
34
|
} & Pick<BoxProps, "width">;
|
|
27
35
|
|
|
28
36
|
export const createToast = ({
|
|
@@ -31,13 +39,17 @@ export const createToast = ({
|
|
|
31
39
|
id,
|
|
32
40
|
duration = 6000,
|
|
33
41
|
width = "sm",
|
|
42
|
+
action,
|
|
43
|
+
closable = false,
|
|
34
44
|
}: ToastProps) =>
|
|
35
45
|
toaster.create({
|
|
36
46
|
description: text,
|
|
37
47
|
type: variant,
|
|
38
48
|
id: id ?? crypto.randomUUID(),
|
|
39
49
|
duration,
|
|
50
|
+
action,
|
|
40
51
|
meta: { width },
|
|
52
|
+
closable: closable,
|
|
41
53
|
});
|
|
42
54
|
|
|
43
55
|
export const Toaster = () => {
|
|
@@ -56,6 +68,18 @@ export const Toaster = () => {
|
|
|
56
68
|
<Stack gap="1" flex="1" maxWidth="100%">
|
|
57
69
|
<Toast.Description>{toast.description}</Toast.Description>
|
|
58
70
|
</Stack>
|
|
71
|
+
{toast.action && (
|
|
72
|
+
<Toast.ActionTrigger onClick={toast.action.onClick}>
|
|
73
|
+
<Button variant="ghost" size="xs">
|
|
74
|
+
{toast.action.label}
|
|
75
|
+
</Button>
|
|
76
|
+
</Toast.ActionTrigger>
|
|
77
|
+
)}
|
|
78
|
+
{toast.closable && (
|
|
79
|
+
<Toast.CloseTrigger>
|
|
80
|
+
<CloseButton size="xs" />
|
|
81
|
+
</Toast.CloseTrigger>
|
|
82
|
+
)}
|
|
59
83
|
</Toast.Root>
|
|
60
84
|
)}
|
|
61
85
|
</ChakraToaster>
|