@tui-cruises/mein-schiff-web-react-component-library 3.1.0 → 3.1.2
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/CHANGELOG.md +43 -0
- package/index.tsx +1 -1
- package/package.json +7 -7
- package/src/components/core/Alert/Alert.tsx +7 -1
- package/src/components/core/AlertDialog/AlertDialog.tsx +20 -3
- package/src/components/core/Badge/Badge.tsx +4 -3
- package/src/components/core/BirthdateField/BirthdateField.tsx +16 -15
- package/src/components/core/ButtonGroup/ButtonGroup.tsx +0 -1
- package/src/components/core/Calendar/Calendar.tsx +10 -3
- package/src/components/core/CheckboxField/CheckboxField.tsx +2 -0
- package/src/components/core/Chip/Chip.tsx +101 -0
- package/src/components/core/Chip/index.ts +1 -0
- package/src/components/core/Countdown/Countdown.tsx +4 -1
- package/src/components/core/DataTable/DataTable.tsx +11 -2
- package/src/components/core/Dialog/Dialog.tsx +11 -2
- package/src/components/core/Divider/Divider.tsx +1 -1
- package/src/components/core/Icon/Icon.tsx +3 -15
- package/src/components/core/IconButton/IconButton.tsx +7 -1
- package/src/components/core/InputField/InputField.tsx +26 -3
- package/src/components/core/Pagination/Pagination.tsx +9 -24
- package/src/components/core/PasswordField/PasswordField.tsx +43 -14
- package/src/components/core/PhoneNumberInput/PhoneNumberInput.tsx +81 -56
- package/src/components/core/Pictogram/Pictogram.tsx +9 -3
- package/src/components/core/Popover/Popover.tsx +16 -9
- package/src/components/core/Price/Price.tsx +2 -9
- package/src/components/core/QuantityItem/QuantityItem.tsx +1 -1
- package/src/components/core/RadioField/RadioField.tsx +14 -4
- package/src/components/core/RadixSelect/RadixSelect.tsx +6 -7
- package/src/components/core/Select/Select.tsx +16 -2
- package/src/components/core/SelectField/SelectField.tsx +11 -4
- package/src/components/core/Skeleton/Skeleton.tsx +1 -0
- package/src/components/core/SwitchToggle/SwitchToggle.tsx +9 -12
- package/src/components/core/Tabs/Tabs.tsx +144 -127
- package/src/components/core/Tag/Tag.tsx +14 -2
- package/public/videos/placeholder.mp4 +0 -0
- package/src/assets/images/placeholder-blueish.jpg +0 -0
- package/src/assets/images/placeholder-sepia.jpg +0 -0
- package/src/assets/images/placeholder.jpg +0 -0
- package/src/components/core/Portlist/Portlist.tsx +0 -28
- package/src/components/core/Portlist/index.ts +0 -1
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,49 @@
|
|
|
2
2
|
|
|
3
3
|
All notable changes to this project will be documented in this file. See [standard-version](https://github.com/conventional-changelog/standard-version) for commit guidelines.
|
|
4
4
|
|
|
5
|
+
### [3.1.2](https://bitbucket.org/yours_truly/tuic-mein-schiff-web-react-component-library/compare/v3.1.1...v3.1.2) (2025-11-06)
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
### Features
|
|
9
|
+
|
|
10
|
+
* **Alert:** A11Y enhancements ([fbd789a](https://bitbucket.org/yours_truly/tuic-mein-schiff-web-react-component-library/commit/fbd789ae3e1c5d8ea98c1ad63a92ff8a3b01edd6))
|
|
11
|
+
* **AlertDialog:** A11Y enhancements ([b78fef9](https://bitbucket.org/yours_truly/tuic-mein-schiff-web-react-component-library/commit/b78fef95e6313d0ebcb6e0d894eb649c7fa2fc9a))
|
|
12
|
+
* **BirthdateField:** A11Y enhancements ([545aaa8](https://bitbucket.org/yours_truly/tuic-mein-schiff-web-react-component-library/commit/545aaa851c9f3b061a9708d258b7e306a5972498))
|
|
13
|
+
* **Calendar:** A11Y enhancements ([c83bf5c](https://bitbucket.org/yours_truly/tuic-mein-schiff-web-react-component-library/commit/c83bf5c83cc48ddb1c2d4a5d8f2f18fda552d73f))
|
|
14
|
+
* **Dialog:** A11Y enhancements ([71b3283](https://bitbucket.org/yours_truly/tuic-mein-schiff-web-react-component-library/commit/71b32830d688036255e253579d388584bdbbdc8c))
|
|
15
|
+
* **Icon:** A11Y enhancements ([88249b5](https://bitbucket.org/yours_truly/tuic-mein-schiff-web-react-component-library/commit/88249b5677601c15577a031eef19fc590b5e69f4))
|
|
16
|
+
* **InputField:** A11Y enhancements ([f9834cd](https://bitbucket.org/yours_truly/tuic-mein-schiff-web-react-component-library/commit/f9834cdabfff5c2ac30c6da12d3579f7f11db2bc))
|
|
17
|
+
* **Pagination:** A11Y enhancements ([a807395](https://bitbucket.org/yours_truly/tuic-mein-schiff-web-react-component-library/commit/a807395835832c7e0def06cbec10d10de04aeda6))
|
|
18
|
+
* **PasswordField:** A11Y enhancements ([ffb97e1](https://bitbucket.org/yours_truly/tuic-mein-schiff-web-react-component-library/commit/ffb97e1e35c412a4395f7548532798bbc6ff06f4))
|
|
19
|
+
* **PhoneNumberInput:** A11Y enhancements ([d52df9c](https://bitbucket.org/yours_truly/tuic-mein-schiff-web-react-component-library/commit/d52df9c830339a5f23a13e6eda01c7959b28c4b2))
|
|
20
|
+
* **Pictogram:** A11Y enhancements ([b776286](https://bitbucket.org/yours_truly/tuic-mein-schiff-web-react-component-library/commit/b776286e867f6c0ced29b913705a210ed2496da7))
|
|
21
|
+
* **Popover:** A11Y enhancements ([efc44c2](https://bitbucket.org/yours_truly/tuic-mein-schiff-web-react-component-library/commit/efc44c2d193b7462d7399c3b4528703aa4d7ac11))
|
|
22
|
+
* **RadioField:** A11Y enhancements ([c932dda](https://bitbucket.org/yours_truly/tuic-mein-schiff-web-react-component-library/commit/c932ddafc59113f793645d2d3c494ca92b363e07))
|
|
23
|
+
* **RadixSelect:** A11Y enhancements ([edabf50](https://bitbucket.org/yours_truly/tuic-mein-schiff-web-react-component-library/commit/edabf50e6281b4c0e049330c3611c37ea89499be))
|
|
24
|
+
* **Select:** A11Y enhancements ([afbb337](https://bitbucket.org/yours_truly/tuic-mein-schiff-web-react-component-library/commit/afbb33708ffab2db2fa8cecb92ea7359d01dc1ce))
|
|
25
|
+
* **Select:** A11Y enhancements ([bab7a84](https://bitbucket.org/yours_truly/tuic-mein-schiff-web-react-component-library/commit/bab7a846facf2a5cfb5d9937cde723c1482d6e16))
|
|
26
|
+
* **SelectField:** A11Y enhancements ([edc178c](https://bitbucket.org/yours_truly/tuic-mein-schiff-web-react-component-library/commit/edc178ce216a5d3e70999d1461b893f089f4c176))
|
|
27
|
+
* **SwitchToggle:** A11Y enhancements ([06070db](https://bitbucket.org/yours_truly/tuic-mein-schiff-web-react-component-library/commit/06070dba2c0cadbe23ff61aa7287121001fe744e))
|
|
28
|
+
* **Tabs:** A11Y enhancements ([36f7b11](https://bitbucket.org/yours_truly/tuic-mein-schiff-web-react-component-library/commit/36f7b111999614bfee2d8f0170c2b8343b07dec1))
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
### Bug Fixes
|
|
32
|
+
|
|
33
|
+
* **Chip:** focus style ([a71d57b](https://bitbucket.org/yours_truly/tuic-mein-schiff-web-react-component-library/commit/a71d57be51099ccd8b6df03de8fb13510ddca99c))
|
|
34
|
+
|
|
35
|
+
### [3.1.1](https://bitbucket.org/yours_truly/tuic-mein-schiff-web-react-component-library/compare/v3.1.0...v3.1.1) (2025-10-30)
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
### Features
|
|
39
|
+
|
|
40
|
+
* **Chip:** add Chip component (EC-2491) ([3b7efbe](https://bitbucket.org/yours_truly/tuic-mein-schiff-web-react-component-library/commit/3b7efbe4c8edccb9187bcae9dd72fee1d7cadc07))
|
|
41
|
+
|
|
42
|
+
|
|
43
|
+
### Bug Fixes
|
|
44
|
+
|
|
45
|
+
* **Calendar:** typography ([77578c0](https://bitbucket.org/yours_truly/tuic-mein-schiff-web-react-component-library/commit/77578c01e26b6544f124e427a3a51072d6d9d315))
|
|
46
|
+
* **Tabs:** add hover border style ([e9e45e5](https://bitbucket.org/yours_truly/tuic-mein-schiff-web-react-component-library/commit/e9e45e54cdcb3efd5d5e11bddaeda9106707b499))
|
|
47
|
+
|
|
5
48
|
## [3.1.0](https://bitbucket.org/yours_truly/tuic-mein-schiff-web-react-component-library/compare/v3.0.7...v3.1.0) (2025-10-28)
|
|
6
49
|
|
|
7
50
|
|
package/index.tsx
CHANGED
|
@@ -10,6 +10,7 @@ export * from './src/components/core/ButtonGroup';
|
|
|
10
10
|
export * from './src/components/core/Calendar';
|
|
11
11
|
export * from './src/components/core/Checkbox';
|
|
12
12
|
export * from './src/components/core/CheckboxField';
|
|
13
|
+
export * from './src/components/core/Chip';
|
|
13
14
|
export * from './src/components/core/Countdown';
|
|
14
15
|
export * from './src/components/core/DataTable';
|
|
15
16
|
export * from './src/components/core/Dialog';
|
|
@@ -19,7 +20,6 @@ export * from './src/components/core/FormLabel';
|
|
|
19
20
|
export * from './src/components/core/Icon';
|
|
20
21
|
export * from './src/components/core/LoadingSpinner';
|
|
21
22
|
export * from './src/components/core/Pictogram';
|
|
22
|
-
export * from './src/components/core/Portlist';
|
|
23
23
|
export * from './src/components/core/Price';
|
|
24
24
|
export * from './src/components/core/QuantityItem';
|
|
25
25
|
export * from './src/components/core/RangeSlider';
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@tui-cruises/mein-schiff-web-react-component-library",
|
|
3
|
-
"version": "3.1.
|
|
3
|
+
"version": "3.1.2",
|
|
4
4
|
"main": "./index.tsx",
|
|
5
5
|
"types": "./index.tsx",
|
|
6
6
|
"type": "module",
|
|
@@ -73,10 +73,10 @@
|
|
|
73
73
|
"@babel/preset-env": "^7.26.9",
|
|
74
74
|
"@babel/preset-react": "^7.26.3",
|
|
75
75
|
"@babel/preset-typescript": "^7.26.0",
|
|
76
|
-
"@storybook/addon-a11y": "
|
|
77
|
-
"@storybook/addon-designs": "^
|
|
78
|
-
"@storybook/addon-docs": "
|
|
79
|
-
"@storybook/nextjs": "
|
|
76
|
+
"@storybook/addon-a11y": "10.0.1",
|
|
77
|
+
"@storybook/addon-designs": "^11.0.1",
|
|
78
|
+
"@storybook/addon-docs": "10.0.1",
|
|
79
|
+
"@storybook/nextjs": "10.0.1",
|
|
80
80
|
"@svgr/cli": "^8.0.1",
|
|
81
81
|
"@types/d3": "^7.4.3",
|
|
82
82
|
"@types/lodash": "^4.17.13",
|
|
@@ -89,13 +89,13 @@
|
|
|
89
89
|
"commitizen": "^3.0.0",
|
|
90
90
|
"esbuild": "^0.25.11",
|
|
91
91
|
"eslint": "^8.47.0",
|
|
92
|
-
"eslint-plugin-storybook": "
|
|
92
|
+
"eslint-plugin-storybook": "10.0.1",
|
|
93
93
|
"postcss": "^8.4.26",
|
|
94
94
|
"prettier": "^3.0.3",
|
|
95
95
|
"prettier-plugin-tailwindcss": "^0.4.1",
|
|
96
96
|
"react-markdown": "^10.0.0",
|
|
97
97
|
"standard-version": "^9.5.0",
|
|
98
|
-
"storybook": "
|
|
98
|
+
"storybook": "10.0.1",
|
|
99
99
|
"storybook-version": "^0.1.4",
|
|
100
100
|
"tailwindcss": "^3.4.17",
|
|
101
101
|
"ts-loader": "^9.5.2",
|
|
@@ -24,6 +24,7 @@ export type AlertProps = PropsWithChildren<{
|
|
|
24
24
|
as?: keyof HTMLElementTagNameMap;
|
|
25
25
|
onClose?: () => void | Promise<void>;
|
|
26
26
|
cta?: TextButtonProps;
|
|
27
|
+
ariaLabelClose?: string;
|
|
27
28
|
}>;
|
|
28
29
|
|
|
29
30
|
export const Alert: FC<AlertProps> = ({
|
|
@@ -36,6 +37,7 @@ export const Alert: FC<AlertProps> = ({
|
|
|
36
37
|
as: Element = 'aside',
|
|
37
38
|
onClose,
|
|
38
39
|
className,
|
|
40
|
+
ariaLabelClose = 'Close',
|
|
39
41
|
}) => {
|
|
40
42
|
const [isClosePending, setIsClosePending] = useState(false);
|
|
41
43
|
|
|
@@ -65,8 +67,10 @@ export const Alert: FC<AlertProps> = ({
|
|
|
65
67
|
|
|
66
68
|
const iconName = icon ?? 'warning-circle';
|
|
67
69
|
|
|
70
|
+
const role = mode === 'error' || mode === 'attention' ? 'alert' : 'status';
|
|
71
|
+
|
|
68
72
|
return (
|
|
69
|
-
<Element className={classList}>
|
|
73
|
+
<Element className={classList} role={role}>
|
|
70
74
|
{headline && (
|
|
71
75
|
<div className="flex items-center gap-2">
|
|
72
76
|
{iconName && (
|
|
@@ -90,6 +94,7 @@ export const Alert: FC<AlertProps> = ({
|
|
|
90
94
|
size="sm"
|
|
91
95
|
variant="ghost"
|
|
92
96
|
disabled={isClosePending}
|
|
97
|
+
aria-label={ariaLabelClose}
|
|
93
98
|
/>
|
|
94
99
|
</div>
|
|
95
100
|
)}
|
|
@@ -121,6 +126,7 @@ export const Alert: FC<AlertProps> = ({
|
|
|
121
126
|
size="sm"
|
|
122
127
|
variant="ghost"
|
|
123
128
|
disabled={isClosePending}
|
|
129
|
+
aria-label={ariaLabelClose}
|
|
124
130
|
/>
|
|
125
131
|
</div>
|
|
126
132
|
)}
|
|
@@ -8,6 +8,7 @@ import type {
|
|
|
8
8
|
PropsWithChildren,
|
|
9
9
|
ReactNode,
|
|
10
10
|
} from 'react';
|
|
11
|
+
import { useId } from 'react';
|
|
11
12
|
import * as AlertDialogPrimitive from '@radix-ui/react-alert-dialog';
|
|
12
13
|
import { Button } from '../../core/Button';
|
|
13
14
|
import { ButtonGroup } from '../../core/ButtonGroup';
|
|
@@ -143,6 +144,8 @@ const renderContent = (
|
|
|
143
144
|
title: ReactNode,
|
|
144
145
|
children: ReactNode,
|
|
145
146
|
centerTitle: boolean,
|
|
147
|
+
titleId: string,
|
|
148
|
+
descriptionId: string,
|
|
146
149
|
) => {
|
|
147
150
|
if (!title && !children) {
|
|
148
151
|
return null;
|
|
@@ -152,13 +155,17 @@ const renderContent = (
|
|
|
152
155
|
<div className="space-y-4">
|
|
153
156
|
{title && (
|
|
154
157
|
<AlertDialogPrimitive.Title
|
|
158
|
+
id={titleId}
|
|
155
159
|
className={twJoin('headline-md', centerTitle && 'text-center')}
|
|
156
160
|
>
|
|
157
161
|
{title}
|
|
158
162
|
</AlertDialogPrimitive.Title>
|
|
159
163
|
)}
|
|
160
164
|
{children && (
|
|
161
|
-
<AlertDialogPrimitive.Description
|
|
165
|
+
<AlertDialogPrimitive.Description
|
|
166
|
+
id={descriptionId}
|
|
167
|
+
className="text-lg"
|
|
168
|
+
>
|
|
162
169
|
{children}
|
|
163
170
|
</AlertDialogPrimitive.Description>
|
|
164
171
|
)}
|
|
@@ -255,6 +262,9 @@ export const AlertDialog: FC<Props> = ({
|
|
|
255
262
|
centerItems = true,
|
|
256
263
|
containerClassName,
|
|
257
264
|
}) => {
|
|
265
|
+
const titleId = useId();
|
|
266
|
+
const descriptionId = useId();
|
|
267
|
+
|
|
258
268
|
return (
|
|
259
269
|
<AlertDialogPrimitive.Root open={open} onOpenChange={onOpenChange}>
|
|
260
270
|
<AlertDialogPrimitive.Portal container={container || undefined}>
|
|
@@ -266,6 +276,8 @@ export const AlertDialog: FC<Props> = ({
|
|
|
266
276
|
)}
|
|
267
277
|
>
|
|
268
278
|
<AlertDialogPrimitive.Content
|
|
279
|
+
aria-labelledby={titleId}
|
|
280
|
+
aria-describedby={descriptionId}
|
|
269
281
|
data-track-click-area={EventClickArea.Dialog}
|
|
270
282
|
data-track-dialog={`alert-dialog-${title}`}
|
|
271
283
|
className={twJoin(
|
|
@@ -275,9 +287,14 @@ export const AlertDialog: FC<Props> = ({
|
|
|
275
287
|
containerClassName,
|
|
276
288
|
)}
|
|
277
289
|
>
|
|
278
|
-
<button className="h-0 w-0" name="trap-focus-placeholder" />
|
|
279
290
|
<div className="space-y-8">
|
|
280
|
-
{renderContent(
|
|
291
|
+
{renderContent(
|
|
292
|
+
title,
|
|
293
|
+
children,
|
|
294
|
+
centerItems,
|
|
295
|
+
titleId,
|
|
296
|
+
descriptionId,
|
|
297
|
+
)}
|
|
281
298
|
{renderActionCollection(actions, centerItems)}
|
|
282
299
|
</div>
|
|
283
300
|
</AlertDialogPrimitive.Content>
|
|
@@ -1,10 +1,10 @@
|
|
|
1
|
-
import type { ReactNode } from 'react';
|
|
1
|
+
import type { ReactNode, HTMLAttributes } from 'react';
|
|
2
2
|
import { twJoin } from 'tailwind-merge';
|
|
3
3
|
|
|
4
4
|
/**
|
|
5
5
|
* Props for the Badge component.
|
|
6
6
|
*/
|
|
7
|
-
export type BadgeProps = {
|
|
7
|
+
export type BadgeProps = HTMLAttributes<HTMLDivElement> & {
|
|
8
8
|
/**
|
|
9
9
|
* The content to be displayed inside the badge.
|
|
10
10
|
* Can be a single ReactNode or an array of ReactNodes.
|
|
@@ -49,7 +49,7 @@ const variants = {
|
|
|
49
49
|
* ```
|
|
50
50
|
*/
|
|
51
51
|
const Badge = (props: BadgeProps) => {
|
|
52
|
-
const { className, variant = 'solid', children } = props;
|
|
52
|
+
const { className, variant = 'solid', children, ...rest } = props;
|
|
53
53
|
|
|
54
54
|
return (
|
|
55
55
|
<div
|
|
@@ -59,6 +59,7 @@ const Badge = (props: BadgeProps) => {
|
|
|
59
59
|
variants.variant[variant],
|
|
60
60
|
className,
|
|
61
61
|
)}
|
|
62
|
+
{...rest}
|
|
62
63
|
>
|
|
63
64
|
{children}
|
|
64
65
|
</div>
|
|
@@ -6,8 +6,9 @@ import React, {
|
|
|
6
6
|
forwardRef,
|
|
7
7
|
useEffect,
|
|
8
8
|
InputHTMLAttributes,
|
|
9
|
+
useId,
|
|
9
10
|
} from 'react';
|
|
10
|
-
import {
|
|
11
|
+
import { twMerge } from 'tailwind-merge';
|
|
11
12
|
import { Control as RadixFormControl } from '@radix-ui/react-form';
|
|
12
13
|
|
|
13
14
|
/**
|
|
@@ -44,6 +45,7 @@ export type BirthdateFieldProps = InputAttributes & {
|
|
|
44
45
|
defaultValue?: string; // YYYY-MM-JJ
|
|
45
46
|
readOnly?: Boolean;
|
|
46
47
|
disabled?: Boolean;
|
|
48
|
+
legend?: string;
|
|
47
49
|
};
|
|
48
50
|
|
|
49
51
|
type SetPartFunction = {
|
|
@@ -135,6 +137,7 @@ const BirthdateField = forwardRef<HTMLInputElement, BirthdateFieldProps>(
|
|
|
135
137
|
defaultValue,
|
|
136
138
|
readOnly,
|
|
137
139
|
disabled,
|
|
140
|
+
legend,
|
|
138
141
|
...props
|
|
139
142
|
},
|
|
140
143
|
ref,
|
|
@@ -153,6 +156,7 @@ const BirthdateField = forwardRef<HTMLInputElement, BirthdateFieldProps>(
|
|
|
153
156
|
const dayRef = useRef<HTMLInputElement>(null);
|
|
154
157
|
const monthRef = useRef<HTMLInputElement>(null);
|
|
155
158
|
const yearRef = useRef<HTMLInputElement>(null);
|
|
159
|
+
const baseId = useId();
|
|
156
160
|
|
|
157
161
|
const inputClassNames = twMerge(
|
|
158
162
|
'w-full rounded-md border border-stroke-secondary-40 bg-surface-white p-4 text-center text-sm placeholder-marine-medium-emphasis outline-none transition-all',
|
|
@@ -196,20 +200,22 @@ const BirthdateField = forwardRef<HTMLInputElement, BirthdateFieldProps>(
|
|
|
196
200
|
}
|
|
197
201
|
};
|
|
198
202
|
|
|
199
|
-
// Simple function to generate a "unique" ID by appending a random number
|
|
200
|
-
const uniqueId = (base: string) =>
|
|
201
|
-
`${base}-${Math.floor(Math.random() * 1000)}`;
|
|
202
|
-
|
|
203
203
|
const inputs = [
|
|
204
204
|
{ part: 'day', ref: dayRef, nextRef: monthRef },
|
|
205
205
|
{ part: 'month', ref: monthRef, nextRef: yearRef },
|
|
206
206
|
{ part: 'year', ref: yearRef, nextRef: undefined },
|
|
207
207
|
].map(({ part, ref, nextRef }) => {
|
|
208
208
|
const formatDetail = format[part];
|
|
209
|
-
const id =
|
|
209
|
+
const id = `${baseId}-${part}`;
|
|
210
210
|
if (!formatDetail) return null;
|
|
211
211
|
return (
|
|
212
212
|
<div key={part}>
|
|
213
|
+
<label
|
|
214
|
+
htmlFor={id}
|
|
215
|
+
className="mb-1 inline-block cursor-pointer text-sm text-marine-medium-emphasis"
|
|
216
|
+
>
|
|
217
|
+
{formatDetail.label}
|
|
218
|
+
</label>
|
|
213
219
|
<input
|
|
214
220
|
id={id}
|
|
215
221
|
{...props}
|
|
@@ -235,12 +241,6 @@ const BirthdateField = forwardRef<HTMLInputElement, BirthdateFieldProps>(
|
|
|
235
241
|
: 31
|
|
236
242
|
}
|
|
237
243
|
/>
|
|
238
|
-
<label
|
|
239
|
-
htmlFor={id}
|
|
240
|
-
className="mt-1 inline-block cursor-pointer text-sm text-marine-medium-emphasis"
|
|
241
|
-
>
|
|
242
|
-
{formatDetail.label}
|
|
243
|
-
</label>
|
|
244
244
|
</div>
|
|
245
245
|
);
|
|
246
246
|
});
|
|
@@ -256,9 +256,10 @@ const BirthdateField = forwardRef<HTMLInputElement, BirthdateFieldProps>(
|
|
|
256
256
|
value={combinedValue}
|
|
257
257
|
/>
|
|
258
258
|
</RadixFormControl>
|
|
259
|
-
<
|
|
260
|
-
{
|
|
261
|
-
|
|
259
|
+
<fieldset className={className}>
|
|
260
|
+
{legend && <legend className="sr-only">{legend}</legend>}
|
|
261
|
+
<div className="grid grid-cols-3 gap-3">{inputs}</div>
|
|
262
|
+
</fieldset>
|
|
262
263
|
</>
|
|
263
264
|
);
|
|
264
265
|
},
|
|
@@ -24,6 +24,8 @@ export type CalendarProps = React.ComponentProps<typeof DayPicker> & {
|
|
|
24
24
|
showNextMonthsButtonLabel?: string;
|
|
25
25
|
numberOfMonthsToShowMore?: number;
|
|
26
26
|
pastIsPickable?: boolean;
|
|
27
|
+
previousMonthLabel?: string;
|
|
28
|
+
nextMonthLabel?: string;
|
|
27
29
|
};
|
|
28
30
|
|
|
29
31
|
const DEFAULT_LOCALE: I18nLocale = 'de';
|
|
@@ -51,6 +53,8 @@ function Calendar({
|
|
|
51
53
|
fromMonth,
|
|
52
54
|
pastIsPickable = false,
|
|
53
55
|
toMonth,
|
|
56
|
+
previousMonthLabel,
|
|
57
|
+
nextMonthLabel,
|
|
54
58
|
...props
|
|
55
59
|
}: CalendarProps) {
|
|
56
60
|
const [usedLocale, setUsedLocale] = useState<Locale | undefined>(undefined);
|
|
@@ -220,18 +224,19 @@ function Calendar({
|
|
|
220
224
|
[UI.Month]: 'space-y-4 lg:w-1/2',
|
|
221
225
|
[UI.MonthCaption]:
|
|
222
226
|
'flex justify-center pt-1 relative items-center pointer-events-none',
|
|
223
|
-
[UI.CaptionLabel]:
|
|
227
|
+
[UI.CaptionLabel]:
|
|
228
|
+
'font-semibold text-base text-marine-high-emphasis',
|
|
224
229
|
[UI.Nav]: 'space-x-1 flex items-center',
|
|
225
230
|
[UI.MonthGrid]: 'w-full border-collapse space-y-1',
|
|
226
231
|
[UI.Weekdays]: 'flex w-full flex-row',
|
|
227
232
|
[UI.Weekday]:
|
|
228
|
-
'inline-flex items-center justify-center h-11 w-1/7 font-normal text-
|
|
233
|
+
'inline-flex items-center justify-center h-11 w-1/7 font-normal text-base rounded-sm',
|
|
229
234
|
[UI.DayButton]: twJoin(
|
|
230
235
|
'h-11 w-full p-0 font-normal aria-selected:opacity-100',
|
|
231
236
|
),
|
|
232
237
|
[UI.Week]: 'flex flex-row nowrap gap-x-0.5 w-full mt-0.5',
|
|
233
238
|
[UI.Day]: twJoin(
|
|
234
|
-
'relative w-1/7 rounded-sm p-0 text-center text-
|
|
239
|
+
'relative w-1/7 rounded-sm p-0 text-center text-base focus-within:relative focus-within:z-20',
|
|
235
240
|
'hover:border-stroke-primary-100 hover:bg-surface-primary-60 data-[disabled]:hover:bg-transparent',
|
|
236
241
|
'active:border-stroke-primary-100 active:bg-surface-primary-60',
|
|
237
242
|
'focus:outline-none focus-visible:shadow-focus-state',
|
|
@@ -282,6 +287,7 @@ function Calendar({
|
|
|
282
287
|
variant="secondary"
|
|
283
288
|
className={twJoin('!mr-4 h-5 w-5', navButtonClasses)}
|
|
284
289
|
size="sm"
|
|
290
|
+
aria-label={nextMonthLabel ?? 'Go to next month'}
|
|
285
291
|
{...props}
|
|
286
292
|
/>
|
|
287
293
|
),
|
|
@@ -291,6 +297,7 @@ function Calendar({
|
|
|
291
297
|
variant="secondary"
|
|
292
298
|
iconName="nav-arrow-left"
|
|
293
299
|
size="sm"
|
|
300
|
+
aria-label={previousMonthLabel ?? 'Go to previous month'}
|
|
294
301
|
{...props}
|
|
295
302
|
/>
|
|
296
303
|
),
|
|
@@ -78,6 +78,7 @@ const CheckboxFieldRenderFunction: ForwardRefRenderFunction<
|
|
|
78
78
|
<Checkbox
|
|
79
79
|
{...attrs}
|
|
80
80
|
required={typeof required === 'boolean' ? required : undefined}
|
|
81
|
+
aria-required={required === 'label' ? true : undefined}
|
|
81
82
|
ref={inputRef}
|
|
82
83
|
/>
|
|
83
84
|
|
|
@@ -115,6 +116,7 @@ const CheckboxFieldRenderFunction: ForwardRefRenderFunction<
|
|
|
115
116
|
<Checkbox
|
|
116
117
|
{...attrs}
|
|
117
118
|
required={typeof required === 'boolean' ? required : undefined}
|
|
119
|
+
aria-required={required === 'label' ? true : undefined}
|
|
118
120
|
/>
|
|
119
121
|
</RadixRoot>
|
|
120
122
|
</RadixForm.Control>
|
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
import type { ReactNode, RefObject } from 'react';
|
|
2
|
+
import { twJoin, twMerge } from 'tailwind-merge';
|
|
3
|
+
import { Slot, Slottable } from '@radix-ui/react-slot';
|
|
4
|
+
import { Pictogram, PictogramName } from '../Pictogram';
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* All allowed variants for the Chip component.
|
|
8
|
+
*/
|
|
9
|
+
type Variant = 'text' | 'pictogram';
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* Props for the Chip component.
|
|
13
|
+
*/
|
|
14
|
+
export type ChipProps = {
|
|
15
|
+
asChild?: boolean;
|
|
16
|
+
className?: string;
|
|
17
|
+
variant?: Variant;
|
|
18
|
+
pictogram?: PictogramName;
|
|
19
|
+
on?: 'white' | 'gray';
|
|
20
|
+
children?: ReactNode;
|
|
21
|
+
active?: boolean;
|
|
22
|
+
disabled?: boolean;
|
|
23
|
+
ref?: RefObject<HTMLButtonElement>;
|
|
24
|
+
};
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* A Chip component designed for basic labeling or marking destinations
|
|
28
|
+
*/
|
|
29
|
+
const Chip = ({
|
|
30
|
+
asChild,
|
|
31
|
+
className,
|
|
32
|
+
variant = 'text',
|
|
33
|
+
pictogram,
|
|
34
|
+
on = 'white',
|
|
35
|
+
active = false,
|
|
36
|
+
disabled = false,
|
|
37
|
+
children,
|
|
38
|
+
ref,
|
|
39
|
+
...args
|
|
40
|
+
}: ChipProps) => {
|
|
41
|
+
const Element = asChild ? Slot : 'button';
|
|
42
|
+
|
|
43
|
+
const borderRadius = variant === 'text' ? 'rounded-full' : 'rounded-md';
|
|
44
|
+
const padding = variant === 'text' ? 'px-4 py-3' : 'p-3 lg:p-2';
|
|
45
|
+
const variantClasses = twMerge(
|
|
46
|
+
'border-none text-center text-sm font-semibold transition-all',
|
|
47
|
+
|
|
48
|
+
// Variants
|
|
49
|
+
variant === 'text' && [
|
|
50
|
+
// Shared
|
|
51
|
+
'text-marine-high-emphasis hover:bg-surface-primary-100',
|
|
52
|
+
|
|
53
|
+
// On surfaces
|
|
54
|
+
on === 'white' && 'bg-surface-secondary-7',
|
|
55
|
+
on === 'gray' && 'bg-surface-white',
|
|
56
|
+
|
|
57
|
+
// States
|
|
58
|
+
active && 'bg-surface-primary-100',
|
|
59
|
+
disabled &&
|
|
60
|
+
'bg-surface-secondary-7 shadow-[inset_0_0_0_2px_theme(colors.stroke.secondary-20)]',
|
|
61
|
+
on === 'gray' &&
|
|
62
|
+
disabled &&
|
|
63
|
+
'bg-surface-white shadow-[inset_0_0_0_2px_theme(colors.stroke.secondary-20)]',
|
|
64
|
+
],
|
|
65
|
+
|
|
66
|
+
variant === 'pictogram' && [
|
|
67
|
+
// Shared
|
|
68
|
+
'bg-surface-white shadow-[inset_0_0_0_2px_theme(colors.stroke.primary-100)] hover:shadow-[inset_0_0_0_4px_theme(colors.stroke.primary-100)]',
|
|
69
|
+
|
|
70
|
+
// States
|
|
71
|
+
active && 'bg-surface-primary-100',
|
|
72
|
+
disabled && 'bg-surface-secondary-7 shadow-none',
|
|
73
|
+
on === 'gray' && disabled && 'bg-surface-white shadow-none',
|
|
74
|
+
],
|
|
75
|
+
|
|
76
|
+
// States
|
|
77
|
+
'focus:outline-none focus:transition-none focus-visible:shadow-focus-state',
|
|
78
|
+
disabled && '!pointer-events-none !text-secondary-marine-48',
|
|
79
|
+
);
|
|
80
|
+
|
|
81
|
+
return (
|
|
82
|
+
<Element
|
|
83
|
+
ref={ref}
|
|
84
|
+
{...args}
|
|
85
|
+
className={twJoin(
|
|
86
|
+
'inline-flex items-center justify-center',
|
|
87
|
+
borderRadius,
|
|
88
|
+
padding,
|
|
89
|
+
variantClasses,
|
|
90
|
+
className,
|
|
91
|
+
)}
|
|
92
|
+
>
|
|
93
|
+
<Slottable>{children ?? ''}</Slottable>
|
|
94
|
+
{pictogram && <Pictogram name={pictogram} size="sm" />}
|
|
95
|
+
</Element>
|
|
96
|
+
);
|
|
97
|
+
};
|
|
98
|
+
|
|
99
|
+
Chip.displayName = 'Chip';
|
|
100
|
+
|
|
101
|
+
export { Chip };
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from './Chip';
|
|
@@ -40,7 +40,10 @@ export function Countdown({
|
|
|
40
40
|
}, [destinationDate]);
|
|
41
41
|
|
|
42
42
|
return (
|
|
43
|
-
<div
|
|
43
|
+
<div
|
|
44
|
+
className={twMerge('flex w-full flex-row justify-center', className)}
|
|
45
|
+
role="timer"
|
|
46
|
+
>
|
|
44
47
|
<div className="flex flex-row gap-2 p-3">
|
|
45
48
|
{calculatedSegmentTouples?.map(([label, value], index: number) => {
|
|
46
49
|
return (
|
|
@@ -6,9 +6,15 @@ type DataTableRow = ReactNode;
|
|
|
6
6
|
export type DataTableProps = HTMLAttributes<HTMLTableElement> & {
|
|
7
7
|
headers: DataTableRow[];
|
|
8
8
|
dataRows: DataTableRow[][];
|
|
9
|
+
caption?: string;
|
|
9
10
|
};
|
|
10
11
|
|
|
11
|
-
export const DataTable = ({
|
|
12
|
+
export const DataTable = ({
|
|
13
|
+
headers,
|
|
14
|
+
dataRows,
|
|
15
|
+
caption,
|
|
16
|
+
...attrs
|
|
17
|
+
}: DataTableProps) => {
|
|
12
18
|
const baseClass = 'text-left text-sm text-marine-high-emphasis';
|
|
13
19
|
const cellClass = 'max-w-[250px] gap-2 overflow-x-auto whitespace-normal p-4';
|
|
14
20
|
const headerClass = 'md:text-base font-semibold gap-2 whitespace-normal p-4';
|
|
@@ -28,6 +34,7 @@ export const DataTable = ({ headers, dataRows, ...attrs }: DataTableProps) => {
|
|
|
28
34
|
const renderTableForSmallScreens = () => (
|
|
29
35
|
<div className="overflow-x-auto rounded-md bg-surface-white [clip-path:border-box] md:hidden">
|
|
30
36
|
<table {...attrs} className={tableClass}>
|
|
37
|
+
{caption && <caption>{caption}</caption>}
|
|
31
38
|
<tbody>
|
|
32
39
|
{longestRow.map((_, rowIndex) => (
|
|
33
40
|
<tr key={rowIndex}>
|
|
@@ -36,6 +43,7 @@ export const DataTable = ({ headers, dataRows, ...attrs }: DataTableProps) => {
|
|
|
36
43
|
<th
|
|
37
44
|
key={`${rowIndex}-${colIndex}`}
|
|
38
45
|
className={stickyHeaderClass}
|
|
46
|
+
scope="row"
|
|
39
47
|
>
|
|
40
48
|
{column[rowIndex]}
|
|
41
49
|
</th>
|
|
@@ -58,10 +66,11 @@ export const DataTable = ({ headers, dataRows, ...attrs }: DataTableProps) => {
|
|
|
58
66
|
const renderTableForLargeScreens = () => (
|
|
59
67
|
<div className="hidden overflow-x-auto rounded-md bg-surface-white [clip-path:border-box] md:block">
|
|
60
68
|
<table {...attrs} className={tableClass}>
|
|
69
|
+
{caption && <caption>{caption}</caption>}
|
|
61
70
|
<thead className="bg-surface-primary-40">
|
|
62
71
|
<tr>
|
|
63
72
|
{headers.map((header, i) => (
|
|
64
|
-
<th key={i} className={headerClass}>
|
|
73
|
+
<th key={i} className={headerClass} scope="col">
|
|
65
74
|
{header}
|
|
66
75
|
</th>
|
|
67
76
|
))}
|
|
@@ -6,7 +6,7 @@ import {
|
|
|
6
6
|
formatTrackingString,
|
|
7
7
|
trackEvent,
|
|
8
8
|
} from '../../../libs/tracking';
|
|
9
|
-
import { ComponentProps, FC, PropsWithChildren, ReactNode } from 'react';
|
|
9
|
+
import { ComponentProps, FC, PropsWithChildren, ReactNode, useId } from 'react';
|
|
10
10
|
import { twJoin } from 'tailwind-merge';
|
|
11
11
|
import { IconButton } from '../../core/IconButton';
|
|
12
12
|
|
|
@@ -295,6 +295,9 @@ const DialogContent = ({
|
|
|
295
295
|
disableOnCloseFocusReset,
|
|
296
296
|
...rest
|
|
297
297
|
}: DialogContentProps) => {
|
|
298
|
+
const titleId = useId();
|
|
299
|
+
const descriptionId = useId();
|
|
300
|
+
|
|
298
301
|
return (
|
|
299
302
|
<DialogPrimitive.Portal container={container || undefined}>
|
|
300
303
|
<DialogPrimitive.Overlay
|
|
@@ -316,6 +319,8 @@ const DialogContent = ({
|
|
|
316
319
|
onCloseAutoFocus={createOnCloseAutoFocusHandler(
|
|
317
320
|
disableOnCloseFocusReset,
|
|
318
321
|
)}
|
|
322
|
+
aria-labelledby={titleId}
|
|
323
|
+
aria-describedby={descriptionId}
|
|
319
324
|
data-track-click-area={EventClickArea.Dialog}
|
|
320
325
|
data-track-dialog={
|
|
321
326
|
trackingName ? formatTrackingString(trackingName) : title
|
|
@@ -348,7 +353,10 @@ const DialogContent = ({
|
|
|
348
353
|
!fullscreen && 'rounded-t-md',
|
|
349
354
|
)}
|
|
350
355
|
>
|
|
351
|
-
<DialogPrimitive.Title
|
|
356
|
+
<DialogPrimitive.Title
|
|
357
|
+
id={titleId}
|
|
358
|
+
className="relative max-w-full truncate text-nowrap text-lg font-semibold text-marine-high-emphasis"
|
|
359
|
+
>
|
|
352
360
|
{title}
|
|
353
361
|
</DialogPrimitive.Title>
|
|
354
362
|
{showCloseButton && (
|
|
@@ -365,6 +373,7 @@ const DialogContent = ({
|
|
|
365
373
|
)}
|
|
366
374
|
</div>
|
|
367
375
|
<div
|
|
376
|
+
id={descriptionId}
|
|
368
377
|
className={twJoin(
|
|
369
378
|
'mt-12 flex max-h-[calc(100%_-_theme(space.12))] w-full flex-col overflow-y-auto',
|
|
370
379
|
bodyClassName,
|