@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.
Files changed (39) hide show
  1. package/CHANGELOG.md +28 -0
  2. package/README.md +34 -4
  3. package/dist/index.d.ts +24 -37
  4. package/dist/index.es.js +2553 -2465
  5. package/dist/index.es.js.map +1 -1
  6. package/dist/index.umd.js +10 -10
  7. package/dist/index.umd.js.map +1 -1
  8. package/dist/style.css +1 -1
  9. package/package.json +3 -3
  10. package/src/lib/components/atoms/button/Button.tsx +4 -2
  11. package/src/lib/components/atoms/button-segment/ButtonSegment.tsx +4 -2
  12. package/src/lib/components/atoms/checkbox/Checkbox.tsx +3 -1
  13. package/src/lib/components/atoms/header/Header.tsx +2 -0
  14. package/src/lib/components/atoms/key-value-info/KeyValueInfo.tsx +1 -1
  15. package/src/lib/components/atoms/list-item/ListItem.tsx +3 -1
  16. package/src/lib/components/atoms/radio-button/RadioButton.tsx +3 -1
  17. package/src/lib/components/atoms/snackbar/Snackbar.tsx +4 -4
  18. package/src/lib/components/atoms/toggle/Toggle.tsx +4 -1
  19. package/src/lib/components/atoms/toggle/toggle.classes.ts +3 -3
  20. package/src/lib/components/molecules/account/Account.tsx +6 -46
  21. package/src/lib/components/molecules/address/Address.tsx +5 -4
  22. package/src/lib/components/molecules/card/Card.tsx +6 -2
  23. package/src/lib/components/molecules/chip/Chip.tsx +11 -5
  24. package/src/lib/components/molecules/display-stats/DisplayStats.tsx +1 -1
  25. package/src/lib/components/molecules/input/Input.tsx +2 -0
  26. package/src/lib/components/molecules/navbar-item/NavbarItem.tsx +1 -1
  27. package/src/lib/components/molecules/navbar-item/NavbarItemHorizontal.tsx +3 -0
  28. package/src/lib/components/molecules/navbar-item/NavbarItemVertical.tsx +3 -0
  29. package/src/lib/components/molecules/search/Search.tsx +11 -1
  30. package/src/lib/components/molecules/select/Select.tsx +32 -24
  31. package/src/lib/components/molecules/table-header-cell/TableHeaderCell.tsx +12 -1
  32. package/src/lib/components/molecules/visual-asset-card/VisualAssetCard.tsx +2 -1
  33. package/src/lib/components/organisms/accordion/Accordion.tsx +2 -0
  34. package/src/lib/components/organisms/dialog/Dialog.tsx +10 -3
  35. package/src/lib/components/organisms/navbar/Navbar.tsx +2 -0
  36. package/src/lib/components/organisms/navbar/NavbarSlideout.tsx +1 -0
  37. package/src/lib/components/organisms/table/Table.tsx +7 -0
  38. package/src/lib/tailwind/base.presets.ts +42 -0
  39. 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.2",
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.2"
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": "^20.14.10",
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="shrink-0 font-inter">{label}</span>
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 cursor-pointer', TEXT_COLOR[type])}
64
- onClick={onClose}
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-8 -translate-x-full',
24
+ checked: 'left-[34px] -translate-x-full',
25
25
  },
26
26
  [ToggleSize.Default]: {
27
27
  unchecked: 'left-1',
28
- checked: 'left-10 -translate-x-full',
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: ({ isLocked }: { isLocked?: boolean }) => React.JSX.Element;
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 isLocked={isLocked} />
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-0 group-hover:opacity-100"
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-0 group-hover:opacity-100"
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 || (!isDisabled && onClick),
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
- <div
132
- onClick={onClose}
133
- className={cx(disabled ? 'cursor-default' : 'cursor-pointer')}
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
- </div>
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>