@iota/apps-ui-kit 0.9.3 → 0.9.5
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 +20 -0
- package/dist/index.d.ts +30 -21
- package/dist/index.es.js +2173 -2066
- package/dist/index.es.js.map +1 -1
- package/dist/index.umd.js +12 -12
- package/dist/index.umd.js.map +1 -1
- package/dist/style.css +1 -1
- package/package.json +2 -2
- package/src/lib/components/atoms/badge/Badge.tsx +13 -6
- package/src/lib/components/atoms/badge/badge.classes.ts +0 -2
- package/src/lib/components/atoms/badge/badge.enums.ts +5 -0
- package/src/lib/components/atoms/button/Button.tsx +4 -2
- package/src/lib/components/atoms/button-segment/ButtonSegment.tsx +3 -1
- 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/molecules/account/Account.tsx +2 -2
- package/src/lib/components/molecules/address/Address.tsx +4 -2
- 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 +9 -2
- 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 +4 -0
- package/src/lib/tailwind/base.presets.ts +42 -0
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.5",
|
|
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.5"
|
|
31
31
|
},
|
|
32
32
|
"peerDependencies": {
|
|
33
33
|
"react": "^18 || ^19",
|
|
@@ -2,8 +2,9 @@
|
|
|
2
2
|
// SPDX-License-Identifier: Apache-2.0
|
|
3
3
|
|
|
4
4
|
import cx from 'classnames';
|
|
5
|
+
import { BadgeSize } from './badge.enums';
|
|
5
6
|
import type { BadgeType } from './badge.enums';
|
|
6
|
-
import { BACKGROUND_COLORS,
|
|
7
|
+
import { BACKGROUND_COLORS, BORDER_COLORS, TEXT_COLORS } from './badge.classes';
|
|
7
8
|
|
|
8
9
|
interface BadgeProps {
|
|
9
10
|
/**
|
|
@@ -14,24 +15,30 @@ interface BadgeProps {
|
|
|
14
15
|
* The label of the badge.
|
|
15
16
|
*/
|
|
16
17
|
label?: string;
|
|
18
|
+
/**
|
|
19
|
+
* The size of the badge
|
|
20
|
+
*/
|
|
21
|
+
size?: BadgeSize;
|
|
17
22
|
}
|
|
18
23
|
|
|
19
|
-
export function Badge({ type, label }: BadgeProps): React.JSX.Element {
|
|
24
|
+
export function Badge({ type, label, size = BadgeSize.Medium }: BadgeProps): React.JSX.Element {
|
|
20
25
|
const backgroundClasses = BACKGROUND_COLORS[type];
|
|
21
26
|
const textClasses = TEXT_COLORS[type];
|
|
22
|
-
const
|
|
27
|
+
const isSmall = size === BadgeSize.Small;
|
|
23
28
|
const labelClasses = label ? 'px-xs py-xxs' : 'h-1.5 w-1.5';
|
|
29
|
+
const textSizeClass = isSmall ? 'text-label-sm' : 'text-label-md';
|
|
24
30
|
|
|
25
31
|
return (
|
|
26
32
|
<div
|
|
27
33
|
className={cx(
|
|
28
|
-
'inline-flex items-center space-x-2 rounded-full
|
|
34
|
+
'inline-flex items-center space-x-2 rounded-full disabled:opacity-30',
|
|
35
|
+
{ border: !isSmall },
|
|
29
36
|
backgroundClasses,
|
|
30
|
-
|
|
37
|
+
{ [BORDER_COLORS[type]]: !isSmall },
|
|
31
38
|
labelClasses,
|
|
32
39
|
)}
|
|
33
40
|
>
|
|
34
|
-
<span className={cx(
|
|
41
|
+
<span className={cx(textSizeClass, textClasses)}>{label}</span>
|
|
35
42
|
</div>
|
|
36
43
|
);
|
|
37
44
|
}
|
|
@@ -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,6 +89,7 @@ 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>}
|
|
@@ -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>
|
|
@@ -134,13 +134,13 @@ export function Account({
|
|
|
134
134
|
<div className="ml-auto flex items-center space-x-2 [&_button]:h-5 [&_button]:w-5 [&_svg]:h-5 [&_svg]:w-5">
|
|
135
135
|
<div className="account-icon-color flex items-center space-x-2 [&_button:not(.locked)]:invisible group-hover:[&_button:not(.locked)]:visible">
|
|
136
136
|
{onOptionsClick && (
|
|
137
|
-
<ButtonUnstyled onClick={onOptionsClick}>
|
|
137
|
+
<ButtonUnstyled onClick={onOptionsClick} aria-label="More options">
|
|
138
138
|
<MoreHoriz />
|
|
139
139
|
</ButtonUnstyled>
|
|
140
140
|
)}
|
|
141
141
|
</div>
|
|
142
142
|
{showSelected && (
|
|
143
|
-
<ButtonUnstyled>
|
|
143
|
+
<ButtonUnstyled aria-label="Checkmark">
|
|
144
144
|
{isSelected ? (
|
|
145
145
|
<CheckmarkFilled className="account-check-active-color h-5 w-5" />
|
|
146
146
|
) : (
|
|
@@ -82,7 +82,8 @@ export function Address({
|
|
|
82
82
|
{isCopyable && (
|
|
83
83
|
<ButtonUnstyled
|
|
84
84
|
onClick={handleCopyClick}
|
|
85
|
-
className="opacity-
|
|
85
|
+
className="opacity-100"
|
|
86
|
+
aria-label="Copy to clipboard"
|
|
86
87
|
>
|
|
87
88
|
<Copy />
|
|
88
89
|
</ButtonUnstyled>
|
|
@@ -90,7 +91,8 @@ export function Address({
|
|
|
90
91
|
{isExternal && (
|
|
91
92
|
<ButtonUnstyled
|
|
92
93
|
onClick={handleOpenClick}
|
|
93
|
-
className="opacity-
|
|
94
|
+
className="opacity-100"
|
|
95
|
+
aria-label="Open in new tab"
|
|
94
96
|
>
|
|
95
97
|
<ArrowTopRight />
|
|
96
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>
|
|
@@ -16,7 +16,9 @@ export type SelectOption =
|
|
|
16
16
|
| { id: string; renderLabel: () => React.JSX.Element }
|
|
17
17
|
| { id: string; label: React.ReactNode };
|
|
18
18
|
|
|
19
|
-
interface SelectProps
|
|
19
|
+
interface SelectProps
|
|
20
|
+
extends Pick<React.HTMLProps<HTMLSelectElement>, 'disabled'>,
|
|
21
|
+
React.AriaAttributes {
|
|
20
22
|
/**
|
|
21
23
|
* The selected option value.
|
|
22
24
|
*/
|
|
@@ -83,6 +85,7 @@ export const Select = forwardRef<HTMLButtonElement, SelectProps>(
|
|
|
83
85
|
value,
|
|
84
86
|
dropdownPosition = DropdownPosition.Bottom,
|
|
85
87
|
size = SelectSize.Default,
|
|
88
|
+
...ariaProps
|
|
86
89
|
},
|
|
87
90
|
ref,
|
|
88
91
|
) => {
|
|
@@ -156,10 +159,13 @@ export const Select = forwardRef<HTMLButtonElement, SelectProps>(
|
|
|
156
159
|
ref={ref}
|
|
157
160
|
onClick={onSelectorClick}
|
|
158
161
|
disabled={disabled}
|
|
162
|
+
aria-expanded={isOpen}
|
|
163
|
+
aria-haspopup="listbox"
|
|
159
164
|
className={cx(
|
|
160
165
|
'select-container select-border-color focus-visible:enabled:select-border-focus-color active:enabled:select-border-focus-color group-[.errored]:select-border-error-color group-[.opened]:select-border-focus-color [&:is(:focus,_:focus-visible,_:active)]:enabled:select-border-focus-color hover:enabled:select-border-hover-color flex flex-row items-center gap-x-3 rounded-lg border py-sm disabled:cursor-not-allowed [&_svg]:h-5 [&_svg]:w-5',
|
|
161
166
|
selectPadding,
|
|
162
167
|
)}
|
|
168
|
+
{...ariaProps}
|
|
163
169
|
>
|
|
164
170
|
{leadingIcon && <span className="select-icon-color">{leadingIcon}</span>}
|
|
165
171
|
|
|
@@ -195,29 +201,31 @@ export const Select = forwardRef<HTMLButtonElement, SelectProps>(
|
|
|
195
201
|
onClick={closeDropdown}
|
|
196
202
|
/>
|
|
197
203
|
)}
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
204
|
+
{isOpen && (
|
|
205
|
+
<div
|
|
206
|
+
className={cx(
|
|
207
|
+
'absolute z-50 min-w-full animate-dropdown-show',
|
|
208
|
+
dropdownPosition === DropdownPosition.Top
|
|
209
|
+
? 'bottom-full origin-bottom'
|
|
210
|
+
: 'top-full origin-top',
|
|
211
|
+
)}
|
|
212
|
+
>
|
|
213
|
+
<Dropdown>
|
|
214
|
+
{options.map((option) => {
|
|
215
|
+
const optionIsString = typeof option === 'string';
|
|
216
|
+
return (
|
|
217
|
+
<ListItem
|
|
218
|
+
onClick={() => handleOptionClick(option)}
|
|
219
|
+
hideBottomBorder
|
|
220
|
+
key={optionIsString ? option : option.id}
|
|
221
|
+
>
|
|
222
|
+
<OptionLabel option={option} />
|
|
223
|
+
</ListItem>
|
|
224
|
+
);
|
|
225
|
+
})}
|
|
226
|
+
</Dropdown>
|
|
227
|
+
</div>
|
|
228
|
+
)}
|
|
221
229
|
</div>
|
|
222
230
|
</InputWrapper>
|
|
223
231
|
);
|