@iota/apps-ui-kit 0.9.2 → 0.9.4
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 +28 -0
- package/README.md +34 -4
- package/dist/index.d.ts +24 -37
- package/dist/index.es.js +2553 -2465
- package/dist/index.es.js.map +1 -1
- package/dist/index.umd.js +10 -10
- package/dist/index.umd.js.map +1 -1
- package/dist/style.css +1 -1
- package/package.json +3 -3
- package/src/lib/components/atoms/button/Button.tsx +4 -2
- package/src/lib/components/atoms/button-segment/ButtonSegment.tsx +4 -2
- package/src/lib/components/atoms/checkbox/Checkbox.tsx +3 -1
- package/src/lib/components/atoms/header/Header.tsx +2 -0
- package/src/lib/components/atoms/key-value-info/KeyValueInfo.tsx +1 -1
- package/src/lib/components/atoms/list-item/ListItem.tsx +3 -1
- package/src/lib/components/atoms/radio-button/RadioButton.tsx +3 -1
- package/src/lib/components/atoms/snackbar/Snackbar.tsx +4 -4
- package/src/lib/components/atoms/toggle/Toggle.tsx +4 -1
- package/src/lib/components/atoms/toggle/toggle.classes.ts +3 -3
- package/src/lib/components/molecules/account/Account.tsx +6 -46
- package/src/lib/components/molecules/address/Address.tsx +5 -4
- package/src/lib/components/molecules/card/Card.tsx +6 -2
- package/src/lib/components/molecules/chip/Chip.tsx +11 -5
- package/src/lib/components/molecules/display-stats/DisplayStats.tsx +1 -1
- package/src/lib/components/molecules/input/Input.tsx +2 -0
- package/src/lib/components/molecules/navbar-item/NavbarItem.tsx +1 -1
- package/src/lib/components/molecules/navbar-item/NavbarItemHorizontal.tsx +3 -0
- package/src/lib/components/molecules/navbar-item/NavbarItemVertical.tsx +3 -0
- package/src/lib/components/molecules/search/Search.tsx +11 -1
- package/src/lib/components/molecules/select/Select.tsx +32 -24
- package/src/lib/components/molecules/table-header-cell/TableHeaderCell.tsx +12 -1
- package/src/lib/components/molecules/visual-asset-card/VisualAssetCard.tsx +2 -1
- package/src/lib/components/organisms/accordion/Accordion.tsx +2 -0
- package/src/lib/components/organisms/dialog/Dialog.tsx +10 -3
- package/src/lib/components/organisms/navbar/Navbar.tsx +2 -0
- package/src/lib/components/organisms/navbar/NavbarSlideout.tsx +1 -0
- package/src/lib/components/organisms/table/Table.tsx +7 -0
- package/src/lib/tailwind/base.presets.ts +42 -0
- package/src/storybook/stories/molecules/Account.stories.tsx +2 -14
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@iota/apps-ui-kit",
|
|
3
|
-
"version": "0.9.
|
|
3
|
+
"version": "0.9.4",
|
|
4
4
|
"sideEffects": false,
|
|
5
5
|
"repository": "https://github.com/iotaledger/iota",
|
|
6
6
|
"license": "Apache-2.0",
|
|
@@ -27,7 +27,7 @@
|
|
|
27
27
|
"classnames": "^2.5.1",
|
|
28
28
|
"lodash.merge": "^4.6.2",
|
|
29
29
|
"react-number-format": "^5.2.2",
|
|
30
|
-
"@iota/apps-ui-icons": "0.7.
|
|
30
|
+
"@iota/apps-ui-icons": "0.7.4"
|
|
31
31
|
},
|
|
32
32
|
"peerDependencies": {
|
|
33
33
|
"react": "^18 || ^19",
|
|
@@ -43,7 +43,7 @@
|
|
|
43
43
|
"@storybook/react": "^7.1.0",
|
|
44
44
|
"@storybook/react-vite": "^7.1.0",
|
|
45
45
|
"@types/lodash.merge": "^4.6.9",
|
|
46
|
-
"@types/node": "^
|
|
46
|
+
"@types/node": "^24.0.0",
|
|
47
47
|
"@types/react": "^18.3.3",
|
|
48
48
|
"@types/react-dom": "^18.3.0",
|
|
49
49
|
"@vitejs/plugin-react-swc": "^3.3.2",
|
|
@@ -14,7 +14,7 @@ import {
|
|
|
14
14
|
} from './button.classes';
|
|
15
15
|
import cx from 'classnames';
|
|
16
16
|
|
|
17
|
-
export interface ButtonProps {
|
|
17
|
+
export interface ButtonProps extends Omit<React.ButtonHTMLAttributes<HTMLButtonElement>, 'type'> {
|
|
18
18
|
/**
|
|
19
19
|
* The size of the button.
|
|
20
20
|
*/
|
|
@@ -75,6 +75,7 @@ export const Button = forwardRef<HTMLButtonElement, ButtonProps>(
|
|
|
75
75
|
iconAfterText = false,
|
|
76
76
|
tabIndex = 0,
|
|
77
77
|
testId,
|
|
78
|
+
...buttonProps
|
|
78
79
|
},
|
|
79
80
|
ref,
|
|
80
81
|
): React.JSX.Element => {
|
|
@@ -87,9 +88,10 @@ export const Button = forwardRef<HTMLButtonElement, ButtonProps>(
|
|
|
87
88
|
|
|
88
89
|
return (
|
|
89
90
|
<button
|
|
91
|
+
type={htmlType}
|
|
92
|
+
{...buttonProps}
|
|
90
93
|
ref={ref}
|
|
91
94
|
onClick={onClick}
|
|
92
|
-
type={htmlType}
|
|
93
95
|
className={cx(
|
|
94
96
|
'state-layer relative flex items-center justify-center gap-2 rounded-full transition-all duration-150 ease-in disabled:cursor-not-allowed disabled:opacity-40',
|
|
95
97
|
paddingClasses,
|
|
@@ -13,7 +13,7 @@ import cx from 'classnames';
|
|
|
13
13
|
import { ButtonSegmentType } from './buttonSegment.enums';
|
|
14
14
|
import { ButtonUnstyled } from '../button';
|
|
15
15
|
|
|
16
|
-
interface ButtonSegmentProps {
|
|
16
|
+
interface ButtonSegmentProps extends React.AriaAttributes {
|
|
17
17
|
/**
|
|
18
18
|
* The label of the button.
|
|
19
19
|
*/
|
|
@@ -52,6 +52,7 @@ export function ButtonSegment({
|
|
|
52
52
|
onClick,
|
|
53
53
|
type = ButtonSegmentType.Rounded,
|
|
54
54
|
isNested = false,
|
|
55
|
+
...ariaProps
|
|
55
56
|
}: ButtonSegmentProps): React.JSX.Element {
|
|
56
57
|
const isUnderlined = type === ButtonSegmentType.Underlined;
|
|
57
58
|
|
|
@@ -88,10 +89,11 @@ export function ButtonSegment({
|
|
|
88
89
|
},
|
|
89
90
|
)}
|
|
90
91
|
disabled={disabled}
|
|
92
|
+
{...ariaProps}
|
|
91
93
|
>
|
|
92
94
|
<div className={cx('flex flex-row items-center justify-center gap-2', textSize)}>
|
|
93
95
|
{icon && <span>{icon}</span>}
|
|
94
|
-
<span className="
|
|
96
|
+
<span className="text-start font-inter">{label}</span>
|
|
95
97
|
</div>
|
|
96
98
|
</ButtonUnstyled>
|
|
97
99
|
);
|
|
@@ -5,7 +5,7 @@ import { forwardRef, useEffect, useRef } from 'react';
|
|
|
5
5
|
import cx from 'classnames';
|
|
6
6
|
import { Dash, Checkmark } from '@iota/apps-ui-icons';
|
|
7
7
|
|
|
8
|
-
interface CheckboxProps {
|
|
8
|
+
interface CheckboxProps extends React.AriaAttributes {
|
|
9
9
|
/**
|
|
10
10
|
* The label of the checkbox.
|
|
11
11
|
*/
|
|
@@ -46,6 +46,7 @@ export const Checkbox = forwardRef<HTMLInputElement, CheckboxProps>(
|
|
|
46
46
|
isDisabled,
|
|
47
47
|
onCheckedChange,
|
|
48
48
|
name,
|
|
49
|
+
...ariaProps
|
|
49
50
|
}: CheckboxProps,
|
|
50
51
|
ref,
|
|
51
52
|
) => {
|
|
@@ -92,6 +93,7 @@ export const Checkbox = forwardRef<HTMLInputElement, CheckboxProps>(
|
|
|
92
93
|
onChange={(e) => {
|
|
93
94
|
onCheckedChange?.(e);
|
|
94
95
|
}}
|
|
96
|
+
{...ariaProps}
|
|
95
97
|
/>
|
|
96
98
|
<span
|
|
97
99
|
onClick={() => inputRef.current?.click()}
|
|
@@ -46,6 +46,7 @@ export function Header({
|
|
|
46
46
|
type={ButtonType.Ghost}
|
|
47
47
|
onClick={onBack}
|
|
48
48
|
icon={<ArrowBack />}
|
|
49
|
+
aria-label="Back"
|
|
49
50
|
/>
|
|
50
51
|
) : (
|
|
51
52
|
keepSpaceForIcon && <div className="w-9" />
|
|
@@ -64,6 +65,7 @@ export function Header({
|
|
|
64
65
|
onClick={onClose}
|
|
65
66
|
icon={<Close />}
|
|
66
67
|
testId={`close-icon`}
|
|
68
|
+
aria-label="Close"
|
|
67
69
|
/>
|
|
68
70
|
) : (
|
|
69
71
|
keepSpaceForIcon && <div className="w-9" />
|
|
@@ -146,7 +146,7 @@ export function KeyValueInfo({
|
|
|
146
146
|
)}
|
|
147
147
|
<div className="self-center">
|
|
148
148
|
{copyText && (
|
|
149
|
-
<ButtonUnstyled onClick={handleCopyClick}>
|
|
149
|
+
<ButtonUnstyled onClick={handleCopyClick} aria-label="Copy to clipboard">
|
|
150
150
|
<Copy className="key-supporting-text-color" />
|
|
151
151
|
</ButtonUnstyled>
|
|
152
152
|
)}
|
|
@@ -6,7 +6,7 @@ import cx from 'classnames';
|
|
|
6
6
|
import { ArrowRight } from '@iota/apps-ui-icons';
|
|
7
7
|
import { Button, ButtonSize, ButtonType } from '../button';
|
|
8
8
|
|
|
9
|
-
export interface ListItemProps {
|
|
9
|
+
export interface ListItemProps extends React.AriaAttributes {
|
|
10
10
|
/**
|
|
11
11
|
* Has right icon (optional).
|
|
12
12
|
*/
|
|
@@ -36,6 +36,7 @@ export function ListItem({
|
|
|
36
36
|
isDisabled,
|
|
37
37
|
children,
|
|
38
38
|
isHighlighted,
|
|
39
|
+
...ariaProps
|
|
39
40
|
}: PropsWithChildren<ListItemProps>): React.JSX.Element {
|
|
40
41
|
function handleKeyDown(event: React.KeyboardEvent<HTMLDivElement>) {
|
|
41
42
|
if ((event.key === 'Enter' || event.key === ' ') && !isDisabled && onClick) {
|
|
@@ -64,6 +65,7 @@ export function ListItem({
|
|
|
64
65
|
role="button"
|
|
65
66
|
tabIndex={0}
|
|
66
67
|
onKeyDown={handleKeyDown}
|
|
68
|
+
{...ariaProps}
|
|
67
69
|
className={cx(
|
|
68
70
|
'list-item-color relative flex flex-row items-center justify-between px-md py-sm',
|
|
69
71
|
!isDisabled && onClick ? 'cursor-pointer' : 'cursor-default',
|
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
import cx from 'classnames';
|
|
5
5
|
import { RadioOn, RadioOff } from '@iota/apps-ui-icons';
|
|
6
6
|
|
|
7
|
-
interface RadioButtonProps {
|
|
7
|
+
interface RadioButtonProps extends React.AriaAttributes {
|
|
8
8
|
/**
|
|
9
9
|
* The id of the radio button.
|
|
10
10
|
*/
|
|
@@ -48,6 +48,7 @@ function RadioButton({
|
|
|
48
48
|
isChecked,
|
|
49
49
|
isDisabled,
|
|
50
50
|
onChange,
|
|
51
|
+
...ariaProps
|
|
51
52
|
}: RadioButtonProps): React.JSX.Element {
|
|
52
53
|
const RadioIcon = isChecked ? RadioOn : RadioOff;
|
|
53
54
|
|
|
@@ -77,6 +78,7 @@ function RadioButton({
|
|
|
77
78
|
onChange={onChange}
|
|
78
79
|
disabled={isDisabled}
|
|
79
80
|
className={cx('peer appearance-none')}
|
|
81
|
+
{...ariaProps}
|
|
80
82
|
/>
|
|
81
83
|
<span className="radio-icon-color peer-checked:radio-icon-checked-color peer-checked:peer-disabled:radio-icon-checked-disabled-color absolute size-6">
|
|
82
84
|
<RadioIcon className="size-full" />
|
|
@@ -6,6 +6,7 @@ import cx from 'classnames';
|
|
|
6
6
|
import { Close } from '@iota/apps-ui-icons';
|
|
7
7
|
import { SnackbarType } from './snackbar.enums';
|
|
8
8
|
import { BACKGROUND_COLOR, TEXT_COLOR } from './snackbar.classes';
|
|
9
|
+
import { ButtonUnstyled } from '../button';
|
|
9
10
|
|
|
10
11
|
type Renderable = JSX.Element | string | null;
|
|
11
12
|
export interface SnackbarProps {
|
|
@@ -59,10 +60,9 @@ export function Snackbar({
|
|
|
59
60
|
>
|
|
60
61
|
<div className={cx('w-full text-left text-body-md', TEXT_COLOR[type])}>{text}</div>
|
|
61
62
|
{showClose && (
|
|
62
|
-
<Close
|
|
63
|
-
className={cx('h-5 w-5
|
|
64
|
-
|
|
65
|
-
/>
|
|
63
|
+
<ButtonUnstyled onClick={onClose} aria-label="Close">
|
|
64
|
+
<Close className={cx('h-5 w-5', TEXT_COLOR[type])} />
|
|
65
|
+
</ButtonUnstyled>
|
|
66
66
|
)}
|
|
67
67
|
</div>
|
|
68
68
|
);
|
|
@@ -16,7 +16,7 @@ import {
|
|
|
16
16
|
} from './toggle.classes';
|
|
17
17
|
import cx from 'classnames';
|
|
18
18
|
|
|
19
|
-
interface ToggleProps {
|
|
19
|
+
interface ToggleProps extends React.AriaAttributes {
|
|
20
20
|
/**
|
|
21
21
|
* The label for the toggle.
|
|
22
22
|
*/
|
|
@@ -62,6 +62,7 @@ export const Toggle = forwardRef<HTMLInputElement, ToggleProps>(
|
|
|
62
62
|
name,
|
|
63
63
|
size = ToggleSize.Default,
|
|
64
64
|
testId,
|
|
65
|
+
...ariaProps
|
|
65
66
|
}: ToggleProps,
|
|
66
67
|
ref,
|
|
67
68
|
) => {
|
|
@@ -123,8 +124,10 @@ export const Toggle = forwardRef<HTMLInputElement, ToggleProps>(
|
|
|
123
124
|
|
|
124
125
|
<span
|
|
125
126
|
role="switch"
|
|
127
|
+
aria-checked={isToggled}
|
|
126
128
|
onClick={() => inputRef.current?.click()}
|
|
127
129
|
className={toggleClasses}
|
|
130
|
+
{...ariaProps}
|
|
128
131
|
>
|
|
129
132
|
<span className={thumbClasses} />
|
|
130
133
|
</span>
|
|
@@ -17,15 +17,15 @@ export const TOGGLE_SIZE = {
|
|
|
17
17
|
[ToggleSize.Default]: 'h-6 w-12',
|
|
18
18
|
};
|
|
19
19
|
|
|
20
|
-
export const TOGGLE_THUMB = 'absolute rounded-full transition-all duration-200 ease-in';
|
|
20
|
+
export const TOGGLE_THUMB = 'absolute rounded-full transition-all duration-200 ease-in-out';
|
|
21
21
|
export const TOGGLE_THUMB_POSITION = {
|
|
22
22
|
[ToggleSize.Small]: {
|
|
23
23
|
unchecked: 'left-1',
|
|
24
|
-
checked: 'left-
|
|
24
|
+
checked: 'left-[34px] -translate-x-full',
|
|
25
25
|
},
|
|
26
26
|
[ToggleSize.Default]: {
|
|
27
27
|
unchecked: 'left-1',
|
|
28
|
-
checked: 'left-
|
|
28
|
+
checked: 'left-[42px] -translate-x-full',
|
|
29
29
|
},
|
|
30
30
|
};
|
|
31
31
|
export const TOGGLE_THUMB_COLOR = {
|
|
@@ -4,13 +4,7 @@
|
|
|
4
4
|
import cx from 'classnames';
|
|
5
5
|
import type { BadgeType } from '@/components/atoms';
|
|
6
6
|
import { Badge, Tooltip, TooltipPosition, ButtonUnstyled } from '@/components/atoms';
|
|
7
|
-
import {
|
|
8
|
-
LockLocked,
|
|
9
|
-
LockUnlocked,
|
|
10
|
-
MoreHoriz,
|
|
11
|
-
CheckmarkFilled,
|
|
12
|
-
RadioOff,
|
|
13
|
-
} from '@iota/apps-ui-icons';
|
|
7
|
+
import { MoreHoriz, CheckmarkFilled, RadioOff } from '@iota/apps-ui-icons';
|
|
14
8
|
import { Address } from '../address';
|
|
15
9
|
|
|
16
10
|
interface AccountProps {
|
|
@@ -22,26 +16,14 @@ interface AccountProps {
|
|
|
22
16
|
* The subtitle of the account.
|
|
23
17
|
*/
|
|
24
18
|
subtitle: string;
|
|
25
|
-
/**
|
|
26
|
-
* Whether the account is unlocked.
|
|
27
|
-
*/
|
|
28
|
-
isLocked?: boolean;
|
|
29
19
|
/**
|
|
30
20
|
* Handler for more options click.
|
|
31
21
|
*/
|
|
32
22
|
onOptionsClick?: (e: React.MouseEvent<HTMLButtonElement>) => void;
|
|
33
|
-
/**
|
|
34
|
-
* Handler for the lock account icon click.
|
|
35
|
-
*/
|
|
36
|
-
onLockAccountClick?: (e: React.MouseEvent<HTMLButtonElement>) => void;
|
|
37
|
-
/**
|
|
38
|
-
* Handle for the unlock account icon click.
|
|
39
|
-
*/
|
|
40
|
-
onUnlockAccountClick?: (e: React.MouseEvent<HTMLButtonElement>) => void;
|
|
41
23
|
/**
|
|
42
24
|
* Function to render avatar content.
|
|
43
25
|
*/
|
|
44
|
-
avatarContent: (
|
|
26
|
+
avatarContent: () => React.JSX.Element;
|
|
45
27
|
/**
|
|
46
28
|
* The onCopy event of the Address (optional).
|
|
47
29
|
*/
|
|
@@ -97,11 +79,8 @@ export function Account({
|
|
|
97
79
|
subtitle,
|
|
98
80
|
badgeType,
|
|
99
81
|
badgeText,
|
|
100
|
-
isLocked,
|
|
101
82
|
avatarContent,
|
|
102
83
|
onOptionsClick,
|
|
103
|
-
onLockAccountClick,
|
|
104
|
-
onUnlockAccountClick,
|
|
105
84
|
onCopy,
|
|
106
85
|
copyText,
|
|
107
86
|
onOpen,
|
|
@@ -117,17 +96,15 @@ export function Account({
|
|
|
117
96
|
|
|
118
97
|
return (
|
|
119
98
|
<div
|
|
99
|
+
data-testid="account-tile"
|
|
120
100
|
className={cx(
|
|
121
101
|
'state-layer group relative flex w-full items-center justify-between space-x-3 rounded-xl px-sm py-xs hover:cursor-pointer',
|
|
122
102
|
isActive && 'state-active',
|
|
123
|
-
{
|
|
124
|
-
'opacity-60': isLocked && showSelected,
|
|
125
|
-
},
|
|
126
103
|
)}
|
|
127
104
|
>
|
|
128
105
|
<div className="flex w-full items-center gap-x-3">
|
|
129
106
|
<div>
|
|
130
|
-
<Avatar
|
|
107
|
+
<Avatar />
|
|
131
108
|
</div>
|
|
132
109
|
<div className="flex w-full min-w-0 flex-col items-start py-xs">
|
|
133
110
|
<div className="flex w-full min-w-0 items-center space-x-2">
|
|
@@ -157,30 +134,13 @@ export function Account({
|
|
|
157
134
|
<div className="ml-auto flex items-center space-x-2 [&_button]:h-5 [&_button]:w-5 [&_svg]:h-5 [&_svg]:w-5">
|
|
158
135
|
<div className="account-icon-color flex items-center space-x-2 [&_button:not(.locked)]:invisible group-hover:[&_button:not(.locked)]:visible">
|
|
159
136
|
{onOptionsClick && (
|
|
160
|
-
<ButtonUnstyled onClick={onOptionsClick}>
|
|
137
|
+
<ButtonUnstyled onClick={onOptionsClick} aria-label="More options">
|
|
161
138
|
<MoreHoriz />
|
|
162
139
|
</ButtonUnstyled>
|
|
163
140
|
)}
|
|
164
|
-
{onLockAccountClick &&
|
|
165
|
-
onUnlockAccountClick &&
|
|
166
|
-
(isLocked ? (
|
|
167
|
-
<div className="flex items-center">
|
|
168
|
-
<ButtonUnstyled
|
|
169
|
-
onClick={onUnlockAccountClick}
|
|
170
|
-
testId="account-unlock"
|
|
171
|
-
className="locked"
|
|
172
|
-
>
|
|
173
|
-
<LockLocked />
|
|
174
|
-
</ButtonUnstyled>
|
|
175
|
-
</div>
|
|
176
|
-
) : (
|
|
177
|
-
<ButtonUnstyled onClick={onLockAccountClick} testId="account-lock">
|
|
178
|
-
<LockUnlocked />
|
|
179
|
-
</ButtonUnstyled>
|
|
180
|
-
))}
|
|
181
141
|
</div>
|
|
182
142
|
{showSelected && (
|
|
183
|
-
<ButtonUnstyled>
|
|
143
|
+
<ButtonUnstyled aria-label="Checkmark">
|
|
184
144
|
{isSelected ? (
|
|
185
145
|
<CheckmarkFilled className="account-check-active-color h-5 w-5" />
|
|
186
146
|
) : (
|
|
@@ -72,9 +72,8 @@ export function Address({
|
|
|
72
72
|
if (externalLink) {
|
|
73
73
|
const newWindow = window.open(externalLink, '_blank', 'noopener noreferrer');
|
|
74
74
|
if (newWindow) newWindow.opener = null;
|
|
75
|
-
} else {
|
|
76
|
-
onOpen?.(event);
|
|
77
75
|
}
|
|
76
|
+
onOpen?.(event);
|
|
78
77
|
}
|
|
79
78
|
|
|
80
79
|
return (
|
|
@@ -83,7 +82,8 @@ export function Address({
|
|
|
83
82
|
{isCopyable && (
|
|
84
83
|
<ButtonUnstyled
|
|
85
84
|
onClick={handleCopyClick}
|
|
86
|
-
className="opacity-
|
|
85
|
+
className="opacity-100"
|
|
86
|
+
aria-label="Copy to clipboard"
|
|
87
87
|
>
|
|
88
88
|
<Copy />
|
|
89
89
|
</ButtonUnstyled>
|
|
@@ -91,7 +91,8 @@ export function Address({
|
|
|
91
91
|
{isExternal && (
|
|
92
92
|
<ButtonUnstyled
|
|
93
93
|
onClick={handleOpenClick}
|
|
94
|
-
className="opacity-
|
|
94
|
+
className="opacity-100"
|
|
95
|
+
aria-label="Open in new tab"
|
|
95
96
|
>
|
|
96
97
|
<ArrowTopRight />
|
|
97
98
|
</ButtonUnstyled>
|
|
@@ -5,7 +5,7 @@ import cx from 'classnames';
|
|
|
5
5
|
import { CARD_DISABLED_CLASSES, CARD_TYPE_CLASSES } from './card.classes';
|
|
6
6
|
import { CardType } from './card.enums';
|
|
7
7
|
|
|
8
|
-
export interface CardProps {
|
|
8
|
+
export interface CardProps extends React.AriaAttributes {
|
|
9
9
|
/**
|
|
10
10
|
* If `true`, the card will be disabled.
|
|
11
11
|
*/
|
|
@@ -44,25 +44,29 @@ export function Card({
|
|
|
44
44
|
onClick,
|
|
45
45
|
children,
|
|
46
46
|
testId,
|
|
47
|
+
...ariaProps
|
|
47
48
|
}: CardProps) {
|
|
48
49
|
function handleOnClick() {
|
|
49
50
|
if (!isDisabled) {
|
|
50
51
|
onClick?.();
|
|
51
52
|
}
|
|
52
53
|
}
|
|
54
|
+
const isClickable = !isDisabled && onClick;
|
|
53
55
|
return (
|
|
54
56
|
<div
|
|
55
57
|
onClick={handleOnClick}
|
|
58
|
+
role={isClickable ? 'button' : undefined}
|
|
56
59
|
className={cx(
|
|
57
60
|
'relative inline-flex w-full items-center gap-3 rounded-xl px-sm py-xs',
|
|
58
61
|
CARD_TYPE_CLASSES[type],
|
|
59
62
|
{
|
|
60
|
-
'state-layer': isHoverable ||
|
|
63
|
+
'state-layer': isHoverable || isClickable,
|
|
61
64
|
[CARD_DISABLED_CLASSES]: isDisabled,
|
|
62
65
|
'cursor-pointer': onClick,
|
|
63
66
|
},
|
|
64
67
|
)}
|
|
65
68
|
data-testid={testId}
|
|
69
|
+
{...ariaProps}
|
|
66
70
|
>
|
|
67
71
|
{children}
|
|
68
72
|
</div>
|
|
@@ -18,7 +18,7 @@ import {
|
|
|
18
18
|
} from './chip.classes';
|
|
19
19
|
import { ChipSize, ChipType } from './chip.enums';
|
|
20
20
|
|
|
21
|
-
interface ChipProps {
|
|
21
|
+
interface ChipProps extends React.AriaAttributes {
|
|
22
22
|
/**
|
|
23
23
|
* The label of the chip
|
|
24
24
|
*/
|
|
@@ -77,6 +77,7 @@ export function Chip({
|
|
|
77
77
|
trailingElement,
|
|
78
78
|
disabled,
|
|
79
79
|
size = ChipSize.Default,
|
|
80
|
+
...ariaProps
|
|
80
81
|
}: ChipProps) {
|
|
81
82
|
const isOutlineSelected = type === ChipType.Outline && selected;
|
|
82
83
|
const outlineStyle = selected
|
|
@@ -104,6 +105,7 @@ export function Chip({
|
|
|
104
105
|
selected ? 'border-transparent' : BORDER_CLASSES[type],
|
|
105
106
|
)}
|
|
106
107
|
disabled={disabled}
|
|
108
|
+
{...ariaProps}
|
|
107
109
|
>
|
|
108
110
|
<span
|
|
109
111
|
className={cx(
|
|
@@ -128,9 +130,13 @@ export function Chip({
|
|
|
128
130
|
</span>
|
|
129
131
|
{trailingElement}
|
|
130
132
|
{showClose && (
|
|
131
|
-
<
|
|
132
|
-
onClick={
|
|
133
|
-
|
|
133
|
+
<ButtonUnstyled
|
|
134
|
+
onClick={(e) => {
|
|
135
|
+
e.stopPropagation();
|
|
136
|
+
onClose?.();
|
|
137
|
+
}}
|
|
138
|
+
disabled={disabled}
|
|
139
|
+
aria-label="Remove"
|
|
134
140
|
>
|
|
135
141
|
<Close
|
|
136
142
|
className={cx(
|
|
@@ -138,7 +144,7 @@ export function Chip({
|
|
|
138
144
|
disabled ? '' : selected ? 'opacity-100' : CLOSE_ICON_INTERACTIVE,
|
|
139
145
|
)}
|
|
140
146
|
/>
|
|
141
|
-
</
|
|
147
|
+
</ButtonUnstyled>
|
|
142
148
|
)}
|
|
143
149
|
</span>
|
|
144
150
|
</ButtonUnstyled>
|
|
@@ -131,7 +131,7 @@ export function DisplayStats({
|
|
|
131
131
|
)}
|
|
132
132
|
{copyText && (
|
|
133
133
|
<div className="self-center">
|
|
134
|
-
<ButtonUnstyled onClick={handleCopyClick}>
|
|
134
|
+
<ButtonUnstyled onClick={handleCopyClick} aria-label="Copy to clipboard">
|
|
135
135
|
<Copy className="display-stats-copy-icon-color" />
|
|
136
136
|
</ButtonUnstyled>
|
|
137
137
|
</div>
|
|
@@ -241,6 +241,7 @@ function InputTrailingElement({
|
|
|
241
241
|
className="input-icon-color [&_svg]:h-5 [&_svg]:w-5"
|
|
242
242
|
onClick={onClearInput}
|
|
243
243
|
tabIndex={-1}
|
|
244
|
+
aria-label="Clear input"
|
|
244
245
|
>
|
|
245
246
|
<Close />
|
|
246
247
|
</ButtonUnstyled>
|
|
@@ -251,6 +252,7 @@ function InputTrailingElement({
|
|
|
251
252
|
onClick={onToggleButtonClick}
|
|
252
253
|
className="input-icon-color [&_svg]:h-5 [&_svg]:w-5"
|
|
253
254
|
tabIndex={-1}
|
|
255
|
+
aria-label="Toggle visibility"
|
|
254
256
|
>
|
|
255
257
|
{isContentVisible ? <VisibilityOn /> : <VisibilityOff />}
|
|
256
258
|
</ButtonUnstyled>
|
|
@@ -5,7 +5,7 @@ import { NavbarItemHorizontal } from './NavbarItemHorizontal';
|
|
|
5
5
|
import { NavbarItemVertical } from './NavbarItemVertical';
|
|
6
6
|
import { NavbarItemType } from './navbarItem.enums';
|
|
7
7
|
|
|
8
|
-
export interface NavbarItemProps {
|
|
8
|
+
export interface NavbarItemProps extends React.AriaAttributes {
|
|
9
9
|
/**
|
|
10
10
|
* The type of the navbar item.
|
|
11
11
|
*/
|
|
@@ -23,6 +23,7 @@ export function NavbarItemHorizontal({
|
|
|
23
23
|
hasBadge,
|
|
24
24
|
onClick,
|
|
25
25
|
isDisabled = false,
|
|
26
|
+
...ariaProps
|
|
26
27
|
}: Omit<NavbarItemProps, 'type'>): React.JSX.Element {
|
|
27
28
|
const fillClasses = isSelected ? SELECTED_ICON : UNSELECTED_ICON;
|
|
28
29
|
const paddingClasses = text ? PADDING_WITH_TEXT : PADDING_WITHOUT_TEXT;
|
|
@@ -40,9 +41,11 @@ export function NavbarItemHorizontal({
|
|
|
40
41
|
return (
|
|
41
42
|
<div
|
|
42
43
|
onClick={handleClick}
|
|
44
|
+
role="button"
|
|
43
45
|
className={cx(
|
|
44
46
|
'inline-flex cursor-pointer flex-col items-center justify-center space-y-1',
|
|
45
47
|
)}
|
|
48
|
+
{...ariaProps}
|
|
46
49
|
>
|
|
47
50
|
<div
|
|
48
51
|
className={cx(
|
|
@@ -19,6 +19,7 @@ export function NavbarItemVertical({
|
|
|
19
19
|
hasBadge,
|
|
20
20
|
onClick,
|
|
21
21
|
isDisabled = false,
|
|
22
|
+
...ariaProps
|
|
22
23
|
}: Omit<NavbarItemProps, 'type'>): React.JSX.Element {
|
|
23
24
|
const fillClasses = isSelected ? SELECTED_ICON : UNSELECTED_ICON;
|
|
24
25
|
const backgroundColors = isSelected && SELECTED_BACKGROUND;
|
|
@@ -36,11 +37,13 @@ export function NavbarItemVertical({
|
|
|
36
37
|
return (
|
|
37
38
|
<div
|
|
38
39
|
onClick={handleClick}
|
|
40
|
+
role="button"
|
|
39
41
|
className={cx(
|
|
40
42
|
'relative inline-flex w-full flex-row items-center justify-between rounded-full p-sm',
|
|
41
43
|
backgroundColors,
|
|
42
44
|
disabledClasses,
|
|
43
45
|
)}
|
|
46
|
+
{...ariaProps}
|
|
44
47
|
>
|
|
45
48
|
<div className="flex items-center gap-3">
|
|
46
49
|
<div className={cx('inline-flex [&_svg]:h-6 [&_svg]:w-6', fillClasses)}>{icon}</div>
|
|
@@ -19,7 +19,7 @@ export interface Suggestion {
|
|
|
19
19
|
type?: string;
|
|
20
20
|
}
|
|
21
21
|
|
|
22
|
-
export interface SearchProps {
|
|
22
|
+
export interface SearchProps extends React.AriaAttributes {
|
|
23
23
|
/**
|
|
24
24
|
* The value of the search input.
|
|
25
25
|
*/
|
|
@@ -63,6 +63,7 @@ export function Search({
|
|
|
63
63
|
isLoading = false,
|
|
64
64
|
type = SearchBarType.Outlined,
|
|
65
65
|
renderSuggestion,
|
|
66
|
+
...ariaProps
|
|
66
67
|
}: SearchProps): React.JSX.Element {
|
|
67
68
|
const inputRef = useRef<HTMLInputElement>(null);
|
|
68
69
|
const suggestionsListRef = useRef<HTMLDivElement>(null);
|
|
@@ -181,6 +182,11 @@ export function Search({
|
|
|
181
182
|
'search-placeholder-color w-full flex-1 outline-none',
|
|
182
183
|
backgroundColorClass,
|
|
183
184
|
)}
|
|
185
|
+
role="combobox"
|
|
186
|
+
aria-expanded={showSuggestions}
|
|
187
|
+
aria-haspopup="listbox"
|
|
188
|
+
aria-autocomplete="list"
|
|
189
|
+
{...ariaProps}
|
|
184
190
|
/>
|
|
185
191
|
<SearchIcon />
|
|
186
192
|
</div>
|
|
@@ -191,6 +197,7 @@ export function Search({
|
|
|
191
197
|
'absolute left-0 top-full flex w-full flex-col items-center overflow-hidden',
|
|
192
198
|
suggestionsStyle,
|
|
193
199
|
)}
|
|
200
|
+
role="listbox"
|
|
194
201
|
>
|
|
195
202
|
<Divider width="w-11/12" />
|
|
196
203
|
{isLoading ? (
|
|
@@ -207,6 +214,9 @@ export function Search({
|
|
|
207
214
|
'w-full cursor-pointer px-md py-sm',
|
|
208
215
|
selectedIndex === index ? 'search-selected-index-bg-color' : '',
|
|
209
216
|
)}
|
|
217
|
+
role="option"
|
|
218
|
+
aria-selected={selectedIndex === index}
|
|
219
|
+
aria-label={suggestion.label}
|
|
210
220
|
>
|
|
211
221
|
{renderSuggestion(suggestion, index)}
|
|
212
222
|
</div>
|