@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
@@ -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 extends Pick<React.HTMLProps<HTMLSelectElement>, 'disabled'> {
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
- <div
199
- className={cx('absolute z-50 min-w-full', {
200
- hidden: !isOpen,
201
- 'top-full':
202
- !dropdownPosition || dropdownPosition === DropdownPosition.Bottom,
203
- 'bottom-full': dropdownPosition === DropdownPosition.Top,
204
- })}
205
- >
206
- <Dropdown>
207
- {options.map((option) => {
208
- const optionIsString = typeof option === 'string';
209
- return (
210
- <ListItem
211
- onClick={() => handleOptionClick(option)}
212
- hideBottomBorder
213
- key={optionIsString ? option : option.id}
214
- >
215
- <OptionLabel option={option} />
216
- </ListItem>
217
- );
218
- })}
219
- </Dropdown>
220
- </div>
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
  );
@@ -6,7 +6,7 @@ import cx from 'classnames';
6
6
  import { Checkbox } from '@/components/atoms/checkbox';
7
7
  import { TableHeaderCellSortOrder } from './tableHeaderCell.enums';
8
8
 
9
- export interface TableHeaderCellProps {
9
+ export interface TableHeaderCellProps extends React.AriaAttributes {
10
10
  /**
11
11
  * The column key.
12
12
  */
@@ -68,6 +68,7 @@ export function TableHeaderCell({
68
68
  onSortClick,
69
69
  onCheckboxChange,
70
70
  sortOrder,
71
+ ...ariaProps
71
72
  }: TableHeaderCellProps): JSX.Element {
72
73
  const handleSort = () => {
73
74
  const newSortOrder =
@@ -107,6 +108,16 @@ export function TableHeaderCell({
107
108
  'cursor-pointer': hasSort,
108
109
  },
109
110
  )}
111
+ aria-sort={
112
+ hasSort
113
+ ? sortOrder === TableHeaderCellSortOrder.Asc
114
+ ? 'ascending'
115
+ : sortOrder === TableHeaderCellSortOrder.Desc
116
+ ? 'descending'
117
+ : 'none'
118
+ : undefined
119
+ }
120
+ {...ariaProps}
110
121
  >
111
122
  <div
112
123
  className={cx(
@@ -7,7 +7,7 @@ import cx from 'classnames';
7
7
  import { AssetMediaRenderer } from '../../molecules/asset-media-renderer';
8
8
  import type { AssetMediaRendererProps } from '../../molecules/asset-media-renderer';
9
9
 
10
- interface VisualAssetBaseProps {
10
+ interface VisualAssetBaseProps extends React.AriaAttributes {
11
11
  /**
12
12
  * The onClick event for the icon.
13
13
  */
@@ -73,6 +73,7 @@ export function VisualAssetCard({
73
73
  <ButtonUnstyled
74
74
  className="visual-asset-icon-color absolute right-2 top-2 z-10 h-9 w-9 cursor-pointer rounded-full p-xs opacity-0 transition-opacity duration-300 group-hover:bg-shader-neutral-light-72 group-hover:opacity-100 [&_svg]:h-5 [&_svg]:w-5"
75
75
  onClick={handleIconClick}
76
+ aria-label="More options"
76
77
  >
77
78
  {icon}
78
79
  </ButtonUnstyled>
@@ -48,6 +48,8 @@ export function AccordionHeader({
48
48
  return (
49
49
  <div
50
50
  onClick={onToggle}
51
+ role="button"
52
+ aria-expanded={isExpanded}
51
53
  className={cx(
52
54
  'state-layer relative flex cursor-pointer items-center justify-between gap-md overflow-hidden rounded-xl py-sm--rs',
53
55
  {
@@ -42,11 +42,15 @@ const DialogOverlay = React.forwardRef<
42
42
  <RadixDialog.Overlay
43
43
  ref={ref}
44
44
  className={cx(
45
- ' dialog-overlay-bg absolute h-full w-full backdrop-blur-md names:backdrop-blur-lg',
45
+ 'dialog-overlay-bg absolute h-full w-full backdrop-blur-md names:backdrop-blur-lg',
46
+ 'data-[state=open]:animate-dialog-overlay-show',
46
47
  )}
47
48
  {...props}
48
49
  >
49
- <DialogClose className={cx('fixed right-3 top-3', { hidden: !showCloseIcon })}>
50
+ <DialogClose
51
+ className={cx('fixed right-3 top-3', { hidden: !showCloseIcon })}
52
+ aria-label="Close"
53
+ >
50
54
  <Close className="button-text-color-neutral" />
51
55
  </DialogClose>
52
56
  </RadixDialog.Overlay>
@@ -104,7 +108,7 @@ const DialogContent = React.forwardRef<
104
108
  : 'overflow-y-auto overflow-x-hidden left-1/2 top-1/2 -translate-x-1/2 -translate-y-1/2 rounded-xl';
105
109
  const widthClass =
106
110
  position === DialogPosition.Right ? 'md:w-96 max-w-[500px]' : customWidth;
107
- const heightClass = position === DialogPosition.Right ? 'h-screen' : 'max-h-[80vh] h-full';
111
+ const heightClass = position === DialogPosition.Right ? 'h-screen' : 'max-h-[90vh] h-full';
108
112
  return (
109
113
  <RadixDialog.Portal container={containerElement}>
110
114
  <DialogContainer isFixedPosition={isFixedPosition}>
@@ -115,6 +119,9 @@ const DialogContent = React.forwardRef<
115
119
  'dialog-content-bg dialog-outline absolute flex flex-col justify-center',
116
120
  dialogPositioning,
117
121
  widthClass,
122
+ position === DialogPosition.Right
123
+ ? 'data-[state=open]:animate-dialog-panel-show'
124
+ : 'data-[state=open]:animate-dialog-content-show',
118
125
  )}
119
126
  {...props}
120
127
  >
@@ -61,6 +61,8 @@ export function Navbar({
61
61
  <div
62
62
  className="state-layer navbar-icon-color relative rounded-full p-xs hover:cursor-pointer sm:hidden [&_svg]:h-6 [&_svg]:w-6"
63
63
  onClick={onToggleNavbar}
64
+ role="button"
65
+ aria-label="Toggle menu"
64
66
  >
65
67
  <MenuIcon />
66
68
  </div>
@@ -38,6 +38,7 @@ export function NavbarSlideout({
38
38
  type={ButtonType.Ghost}
39
39
  onClick={onToggleNavbar}
40
40
  icon={<ArrowBack />}
41
+ aria-label="Close menu"
41
42
  />
42
43
  </div>
43
44
  {items.map((item) => (
@@ -119,6 +119,7 @@ export function Table({
119
119
  icon={<DoubleArrowLeft />}
120
120
  disabled={!paginationOptions.hasFirst}
121
121
  onClick={paginationOptions.onFirst}
122
+ aria-label="First page"
122
123
  />
123
124
  <Button
124
125
  type={ButtonType.Secondary}
@@ -126,6 +127,7 @@ export function Table({
126
127
  icon={<ArrowLeft />}
127
128
  disabled={!paginationOptions.hasPrev}
128
129
  onClick={paginationOptions.onPrev}
130
+ aria-label="Previous page"
129
131
  />
130
132
  <Button
131
133
  type={ButtonType.Secondary}
@@ -133,6 +135,7 @@ export function Table({
133
135
  icon={<ArrowRight />}
134
136
  disabled={!paginationOptions.hasNext}
135
137
  onClick={paginationOptions.onNext}
138
+ aria-label="Next page"
136
139
  />
137
140
  <Button
138
141
  type={ButtonType.Secondary}
@@ -140,6 +143,7 @@ export function Table({
140
143
  icon={<DoubleArrowRight />}
141
144
  disabled={!paginationOptions.hasLast}
142
145
  onClick={paginationOptions.onLast}
146
+ aria-label="Last page"
143
147
  />
144
148
  </>
145
149
  )}
@@ -192,11 +196,13 @@ export function TableBody({ children }: PropsWithChildren): JSX.Element {
192
196
  export interface TableRowCheckboxProps {
193
197
  rowIndex: number;
194
198
  onCheckboxChange: (checked: boolean) => void;
199
+ isDisabled?: boolean;
195
200
  }
196
201
 
197
202
  export function TableRowCheckbox({
198
203
  rowIndex,
199
204
  onCheckboxChange,
205
+ isDisabled,
200
206
  }: TableRowCheckboxProps): React.JSX.Element {
201
207
  const { selectedRowIndexes } = useTableContext();
202
208
 
@@ -207,6 +213,7 @@ export function TableRowCheckbox({
207
213
  onCheckboxChange(event.target.checked);
208
214
  }}
209
215
  isChecked={selectedRowIndexes.has(rowIndex)}
216
+ isDisabled={isDisabled}
210
217
  />
211
218
  </TableCellBase>
212
219
  );
@@ -53,6 +53,48 @@ export const BASE_CONFIG: Config = {
53
53
  backgroundImage: {
54
54
  ...NAMES_GRADIENTS,
55
55
  },
56
+ keyframes: {
57
+ 'dialog-overlay-show': {
58
+ from: { opacity: '0' },
59
+ to: { opacity: '1' },
60
+ },
61
+ 'dialog-content-show': {
62
+ from: {
63
+ opacity: '0',
64
+ transform: 'translate(-50%, -50%) scale(0.92)',
65
+ },
66
+ to: {
67
+ opacity: '1',
68
+ transform: 'translate(-50%, -50%) scale(1)',
69
+ },
70
+ },
71
+ 'dialog-panel-show': {
72
+ from: {
73
+ opacity: '0',
74
+ transform: 'translateX(12px)',
75
+ },
76
+ to: {
77
+ opacity: '1',
78
+ transform: 'translateX(0)',
79
+ },
80
+ },
81
+ 'dropdown-show': {
82
+ from: {
83
+ opacity: '0',
84
+ transform: 'scale(0.94)',
85
+ },
86
+ to: {
87
+ opacity: '1',
88
+ transform: 'scale(1)',
89
+ },
90
+ },
91
+ },
92
+ animation: {
93
+ 'dialog-overlay-show': 'dialog-overlay-show 170ms ease-out',
94
+ 'dialog-content-show': 'dialog-content-show 170ms ease-out',
95
+ 'dialog-panel-show': 'dialog-panel-show 210ms ease-out',
96
+ 'dropdown-show': 'dropdown-show 125ms ease-out',
97
+ },
56
98
  },
57
99
  },
58
100
  };
@@ -3,7 +3,6 @@
3
3
 
4
4
  import type { Meta, StoryObj } from '@storybook/react';
5
5
  import { Account, BadgeType } from '@/components';
6
- import cx from 'classnames';
7
6
 
8
7
  const meta: Meta<typeof Account> = {
9
8
  component: Account,
@@ -21,10 +20,7 @@ export default meta;
21
20
 
22
21
  type Story = StoryObj<typeof meta>;
23
22
 
24
- const Avatar = ({ isLocked }: { isLocked?: boolean }) => {
25
- const circleFillClass = isLocked
26
- ? 'fill-iota-neutral-80 dark:fill-iota-neutral-30 names:fill-names-neutral-30'
27
- : 'fill-iota-primary-30';
23
+ const Avatar = () => {
28
24
  return (
29
25
  <svg
30
26
  xmlns="http://www.w3.org/2000/svg"
@@ -33,7 +29,7 @@ const Avatar = ({ isLocked }: { isLocked?: boolean }) => {
33
29
  viewBox="0 0 33 32"
34
30
  fill="none"
35
31
  >
36
- <circle cx="16.5" cy="16" r="16" className={cx(circleFillClass)} />
32
+ <circle cx="16.5" cy="16" r="16" className="fill-iota-primary-30" />
37
33
  </svg>
38
34
  );
39
35
  };
@@ -42,7 +38,6 @@ export const Default: Story = {
42
38
  args: {
43
39
  title: 'Account',
44
40
  subtitle: '0x0d7...3f37',
45
- isLocked: true,
46
41
  avatarContent: Avatar,
47
42
  },
48
43
  argTypes: {
@@ -50,17 +45,10 @@ export const Default: Story = {
50
45
  control: 'select',
51
46
  options: Object.values(BadgeType),
52
47
  },
53
- isLocked: {
54
- control: 'boolean',
55
- },
56
48
  onOptionsClick: {
57
49
  action: 'onOptionsClick',
58
50
  control: 'none',
59
51
  },
60
- onLockAccountClick: {
61
- action: 'onLockAccount',
62
- control: 'none',
63
- },
64
52
  avatarContent: {
65
53
  control: 'none',
66
54
  },