@adobe-commerce/elsie 1.6.0-alpha11 → 1.6.0-alpha23

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@adobe-commerce/elsie",
3
- "version": "1.6.0-alpha11",
3
+ "version": "1.6.0-alpha23",
4
4
  "license": "SEE LICENSE IN LICENSE.md",
5
5
  "description": "Domain Package SDK",
6
6
  "engines": {
@@ -18,57 +18,52 @@ export type IconType = keyof typeof import('@adobe-commerce/elsie/icons');
18
18
 
19
19
  const lazyIcons = {
20
20
  Add: lazy(() => import('@adobe-commerce/elsie/icons/Add.svg')),
21
- AddressBook: lazy(() => import('@adobe-commerce/elsie/icons/AddressBook.svg')),
22
21
  Bulk: lazy(() => import('@adobe-commerce/elsie/icons/Bulk.svg')),
23
22
  Burger: lazy(() => import('@adobe-commerce/elsie/icons/Burger.svg')),
24
- Business: lazy(() => import('@adobe-commerce/elsie/icons/Business.svg')),
25
- Card: lazy(() => import('@adobe-commerce/elsie/icons/Card.svg')),
26
23
  Cart: lazy(() => import('@adobe-commerce/elsie/icons/Cart.svg')),
27
24
  Check: lazy(() => import('@adobe-commerce/elsie/icons/Check.svg')),
28
- CheckWithCircle: lazy(() => import('@adobe-commerce/elsie/icons/CheckWithCircle.svg')),
29
25
  ChevronDown: lazy(() => import('@adobe-commerce/elsie/icons/ChevronDown.svg')),
30
- ChevronRight: lazy(() => import('@adobe-commerce/elsie/icons/ChevronRight.svg')),
31
26
  ChevronUp: lazy(() => import('@adobe-commerce/elsie/icons/ChevronUp.svg')),
27
+ ChevronRight: lazy(() => import('@adobe-commerce/elsie/icons/ChevronRight.svg')),
32
28
  Close: lazy(() => import('@adobe-commerce/elsie/icons/Close.svg')),
33
- Coupon: lazy(() => import('@adobe-commerce/elsie/icons/Coupon.svg')),
34
- Date: lazy(() => import('@adobe-commerce/elsie/icons/Date.svg')),
35
- Delivery: lazy(() => import('@adobe-commerce/elsie/icons/Delivery.svg')),
36
- Edit: lazy(() => import('@adobe-commerce/elsie/icons/Edit.svg')),
37
- EmptyBox: lazy(() => import('@adobe-commerce/elsie/icons/EmptyBox.svg')),
38
- Eye: lazy(() => import('@adobe-commerce/elsie/icons/Eye.svg')),
39
- EyeClose: lazy(() => import('@adobe-commerce/elsie/icons/EyeClose.svg')),
40
- Gift: lazy(() => import('@adobe-commerce/elsie/icons/Gift.svg')),
41
- GiftCard: lazy(() => import('@adobe-commerce/elsie/icons/GiftCard.svg')),
42
29
  Heart: lazy(() => import('@adobe-commerce/elsie/icons/Heart.svg')),
43
- HeartFilled: lazy(() => import('@adobe-commerce/elsie/icons/HeartFilled.svg')),
44
- InfoFilled: lazy(() => import('@adobe-commerce/elsie/icons/InfoFilled.svg')),
45
- List: lazy(() => import('@adobe-commerce/elsie/icons/List.svg')),
46
- Locker: lazy(() => import('@adobe-commerce/elsie/icons/Locker.svg')),
47
30
  Minus: lazy(() => import('@adobe-commerce/elsie/icons/Minus.svg')),
48
- Order: lazy(() => import('@adobe-commerce/elsie/icons/Order.svg')),
49
- OrderError: lazy(() => import('@adobe-commerce/elsie/icons/OrderError.svg')),
50
- OrderSuccess: lazy(() => import('@adobe-commerce/elsie/icons/OrderSuccess.svg')),
51
- PaymentError: lazy(() => import('@adobe-commerce/elsie/icons/PaymentError.svg')),
52
31
  Placeholder: lazy(() => import('@adobe-commerce/elsie/icons/Placeholder.svg')),
53
32
  PlaceholderFilled: lazy(
54
33
  () => import('@adobe-commerce/elsie/icons/PlaceholderFilled.svg')
55
34
  ),
56
- Quote: lazy(() => import('@adobe-commerce/elsie/icons/Quote.svg')),
57
35
  Search: lazy(() => import('@adobe-commerce/elsie/icons/Search.svg')),
58
36
  SearchFilled: lazy(() => import('@adobe-commerce/elsie/icons/SearchFilled.svg')),
59
37
  Sort: lazy(() => import('@adobe-commerce/elsie/icons/Sort.svg')),
60
38
  Star: lazy(() => import('@adobe-commerce/elsie/icons/Star.svg')),
61
- Structure: lazy(() => import('@adobe-commerce/elsie/icons/Structure.svg')),
62
- Team: lazy(() => import('@adobe-commerce/elsie/icons/Team.svg')),
63
- Trash: lazy(() => import('@adobe-commerce/elsie/icons/Trash.svg')),
64
- User: lazy(() => import('@adobe-commerce/elsie/icons/User.svg')),
65
39
  View: lazy(() => import('@adobe-commerce/elsie/icons/View.svg')),
66
- Wallet: lazy(() => import('@adobe-commerce/elsie/icons/Wallet.svg')),
40
+ User: lazy(() => import('@adobe-commerce/elsie/icons/User.svg')),
67
41
  Warning: lazy(() => import('@adobe-commerce/elsie/icons/Warning.svg')),
68
- WarningFilled: lazy(() => import('@adobe-commerce/elsie/icons/WarningFilled.svg')),
42
+ Locker: lazy(() => import('@adobe-commerce/elsie/icons/Locker.svg')),
43
+ Wallet: lazy(() => import('@adobe-commerce/elsie/icons/Wallet.svg')),
44
+ Card: lazy(() => import('@adobe-commerce/elsie/icons/Card.svg')),
45
+ Order: lazy(() => import('@adobe-commerce/elsie/icons/Order.svg')),
46
+ Delivery: lazy(() => import('@adobe-commerce/elsie/icons/Delivery.svg')),
47
+ OrderError: lazy(() => import('@adobe-commerce/elsie/icons/OrderError.svg')),
48
+ OrderSuccess: lazy(() => import('@adobe-commerce/elsie/icons/OrderSuccess.svg')),
49
+ PaymentError: lazy(() => import('@adobe-commerce/elsie/icons/PaymentError.svg')),
50
+ CheckWithCircle: lazy(() => import('@adobe-commerce/elsie/icons/CheckWithCircle.svg')),
69
51
  WarningWithCircle: lazy(
70
52
  () => import('@adobe-commerce/elsie/icons/WarningWithCircle.svg')
71
53
  ),
54
+ WarningFilled: lazy(() => import('@adobe-commerce/elsie/icons/WarningFilled.svg')),
55
+ InfoFilled: lazy(() => import('@adobe-commerce/elsie/icons/InfoFilled.svg')),
56
+ HeartFilled: lazy(() => import('@adobe-commerce/elsie/icons/HeartFilled.svg')),
57
+ Trash: lazy(() => import('@adobe-commerce/elsie/icons/Trash.svg')),
58
+ Eye: lazy(() => import('@adobe-commerce/elsie/icons/Eye.svg')),
59
+ EyeClose: lazy(() => import('@adobe-commerce/elsie/icons/EyeClose.svg')),
60
+ Date: lazy(() => import('@adobe-commerce/elsie/icons/Date.svg')),
61
+ AddressBook: lazy(() => import('@adobe-commerce/elsie/icons/AddressBook.svg')),
62
+ EmptyBox: lazy(() => import('@adobe-commerce/elsie/icons/EmptyBox.svg')),
63
+ Coupon: lazy(() => import('@adobe-commerce/elsie/icons/Coupon.svg')),
64
+ Gift: lazy(() => import('@adobe-commerce/elsie/icons/Gift.svg')),
65
+ GiftCard: lazy(() => import('@adobe-commerce/elsie/icons/GiftCard.svg')),
66
+ Edit: lazy(() => import('@adobe-commerce/elsie/icons/Edit.svg')),
72
67
  };
73
68
 
74
69
  export interface IconProps extends Omit<SVGProps<SVGSVGElement>, 'size'> {
@@ -8,7 +8,7 @@
8
8
  *******************************************************************/
9
9
 
10
10
  import type { Meta, StoryObj } from '@storybook/preact';
11
- import { expect, userEvent, waitFor, within } from '@storybook/test';
11
+ import { expect, userEvent, within } from '@storybook/test';
12
12
  import {
13
13
  MultiSelect,
14
14
  type MultiSelectProps,
@@ -430,13 +430,11 @@ export const BulkSelectionActions = {
430
430
  const selectAllButton = canvas.getByTestId('multi-select-select-all');
431
431
  await userEvent.click(selectAllButton);
432
432
 
433
- // Wait for all options to be selected - check tags appear in the tags area
433
+ // All options should now be selected - check tags appear in the tags area
434
434
  const tagsArea = canvas.getByTestId('multi-select-tags-area');
435
- await waitFor(async () => {
436
- await expect(tagsArea).toHaveTextContent('Option 1');
437
- await expect(tagsArea).toHaveTextContent('Option 2');
438
- await expect(tagsArea).toHaveTextContent('Option 10');
439
- });
435
+ await expect(tagsArea).toHaveTextContent('Option 1');
436
+ await expect(tagsArea).toHaveTextContent('Option 2');
437
+ await expect(tagsArea).toHaveTextContent('Option 10');
440
438
 
441
439
  // Deselect All should now be enabled
442
440
  await expect(deselectAllButton).not.toBeDisabled();
@@ -64,8 +64,7 @@
64
64
  align-items: center;
65
65
  }
66
66
 
67
- .dropin-pagination_list-item button,
68
- .dropin-pagination_list-item a {
67
+ .dropin-pagination_list-item button {
69
68
  cursor: pointer;
70
69
  margin: 0;
71
70
  padding: 0;
@@ -73,32 +72,24 @@
73
72
  border: none;
74
73
  font: var(--type-details-caption-1-font);
75
74
  letter-spacing: var(--type-details-caption-1-letter-spacing);
76
- text-decoration: none;
77
75
  }
78
76
 
79
- .dropin-pagination_list-item--active button,
80
- .dropin-pagination_list-item--active a {
77
+ .dropin-pagination_list-item--active button {
81
78
  cursor: default;
82
79
  }
83
80
 
84
81
  .dropin-pagination_list-item--active button:disabled,
85
82
  .dropin-pagination_list-item--ellipsis button,
86
- .dropin-pagination_list-item--ellipsis a,
87
83
  .dropin-pagination-arrow--backward:disabled,
88
- .dropin-pagination-arrow--forward:disabled,
89
- .dropin-pagination-arrow--disabled {
84
+ .dropin-pagination-arrow--forward:disabled {
90
85
  cursor: default;
91
- opacity: 0.5;
92
- pointer-events: none;
93
86
  }
94
87
 
95
- .dropin-pagination button:not(:disabled),
96
- .dropin-pagination a:not([aria-disabled="true"]) {
88
+ .dropin-pagination button:not(:disabled) {
97
89
  color: var(--color-neutral-800);
98
90
  }
99
91
 
100
- .dropin-pagination button,
101
- .dropin-pagination a {
92
+ .dropin-pagination button {
102
93
  appearance: none;
103
94
  -webkit-appearance: none;
104
95
  }
@@ -2,9 +2,9 @@
2
2
  * Copyright 2024 Adobe
3
3
  * All Rights Reserved.
4
4
  *
5
- * NOTICE: Adobe permits you to use, modify, and distribute this
6
- * file in accordance with the terms of the Adobe license agreement
7
- * accompanying it.
5
+ * NOTICE: Adobe permits you to use, modify, and distribute this
6
+ * file in accordance with the terms of the Adobe license agreement
7
+ * accompanying it.
8
8
  *******************************************************************/
9
9
 
10
10
  // https://storybook.js.org/docs/7.0/preact/writing-stories/introduction
@@ -16,8 +16,6 @@ import {
16
16
  } from '@adobe-commerce/elsie/components/Pagination';
17
17
  import { expect, userEvent, within } from '@storybook/test';
18
18
  import { useState } from 'preact/hooks';
19
- import { action } from '@storybook/addon-actions';
20
-
21
19
 
22
20
  /**
23
21
  * A component that divides large content sets into multiple pages, allowing users to navigate through the data with controls like "Next," "Previous," or page numbers, enhancing performance and usability by limiting the number of items displayed per page.
@@ -42,10 +40,6 @@ const meta: Meta<PaginationProps> = {
42
40
  description:
43
41
  'Called when the page number is changed, and it takes the resulting page number.',
44
42
  },
45
- routePage: {
46
- description:
47
- 'Optional function that generates hrefs for each page. When provided, pagination will render anchor tags instead of buttons, enabling proper SEO and link behavior.',
48
- },
49
43
  },
50
44
  };
51
45
 
@@ -121,26 +115,3 @@ export const LongPagination: Story = {
121
115
  );
122
116
  },
123
117
  };
124
-
125
- export const WithAnchors: Story = {
126
- name: 'As anchor tags',
127
- render: () => {
128
- const [currentPage, setCurrentPage] = useState(1);
129
- const totalPages = 10;
130
-
131
- const handlePageChange = (newPage: number, e?: Event) => {
132
- e?.preventDefault();
133
- setCurrentPage(newPage);
134
- action('pageChanged')(newPage, e);
135
- };
136
-
137
- return (
138
- <Pagination
139
- totalPages={totalPages}
140
- currentPage={currentPage}
141
- onChange={handlePageChange}
142
- routePage={(page) => `?page=${page}`}
143
- />
144
- );
145
- },
146
- };
@@ -2,9 +2,9 @@
2
2
  * Copyright 2024 Adobe
3
3
  * All Rights Reserved.
4
4
  *
5
- * NOTICE: Adobe permits you to use, modify, and distribute this
6
- * file in accordance with the terms of the Adobe license agreement
7
- * accompanying it.
5
+ * NOTICE: Adobe permits you to use, modify, and distribute this
6
+ * file in accordance with the terms of the Adobe license agreement
7
+ * accompanying it.
8
8
  *******************************************************************/
9
9
 
10
10
  import { FunctionComponent } from 'preact';
@@ -14,14 +14,12 @@ import { ChevronDown } from '@adobe-commerce/elsie/icons';
14
14
  import { Icon } from '@adobe-commerce/elsie/components/Icon';
15
15
  import { useText } from '@adobe-commerce/elsie/i18n';
16
16
  import '@adobe-commerce/elsie/components/Pagination/Pagination.css';
17
- import { PaginationButton } from './PaginationButton';
18
17
 
19
18
  export interface PaginationProps {
20
19
  className?: string;
21
20
  currentPage?: number;
22
21
  totalPages?: number;
23
- onChange?: (currentPage: number, e?: Event) => void;
24
- routePage?: (page: number) => string;
22
+ onChange?: (currentPage: number) => void;
25
23
  }
26
24
 
27
25
  export type PaginationList = {
@@ -34,7 +32,6 @@ export const Pagination: FunctionComponent<PaginationProps> = ({
34
32
  totalPages = 10,
35
33
  currentPage = 1,
36
34
  onChange,
37
- routePage,
38
35
  className,
39
36
  ...props
40
37
  }) => {
@@ -43,22 +40,22 @@ export const Pagination: FunctionComponent<PaginationProps> = ({
43
40
  forwardButton: 'Dropin.Pagination.forwardButton.ariaLabel',
44
41
  });
45
42
 
46
- const handleForward = useCallback((e?: Event) => {
43
+ const handleForward = useCallback(() => {
47
44
  const nextPage = Math.min(currentPage + 1, totalPages);
48
45
 
49
- onChange?.(nextPage, e);
46
+ onChange?.(nextPage);
50
47
  }, [currentPage, onChange, totalPages]);
51
48
 
52
- const handleBackward = useCallback((e?: Event) => {
49
+ const handleBackward = useCallback(() => {
53
50
  const prevPage = Math.max(currentPage - 1, 1);
54
51
 
55
- onChange?.(prevPage, e);
52
+ onChange?.(prevPage);
56
53
  }, [currentPage, onChange]);
57
54
 
58
55
  const handleSetPage = useCallback(
59
- (currentPage: number | string, e?: Event) => {
56
+ (currentPage: number | string) => {
60
57
  if (isNumber(currentPage)) {
61
- onChange?.(currentPage as number, e);
58
+ onChange?.(currentPage as number);
62
59
  }
63
60
  },
64
61
  [onChange]
@@ -100,20 +97,19 @@ export const Pagination: FunctionComponent<PaginationProps> = ({
100
97
 
101
98
  return (
102
99
  <div {...props} className={classes(['dropin-pagination', className])}>
103
- <PaginationButton
100
+ <button
101
+ type="button"
104
102
  data-testid="prev-button"
105
103
  aria-label={translations.backwardButton}
106
104
  disabled={currentPage === 1}
107
- onClick={(e: Event) => handleBackward(e)}
108
- href={routePage?.(currentPage) ?? undefined}
105
+ onClick={handleBackward}
109
106
  className={classes([
110
107
  'dropin-pagination-arrow',
111
108
  'dropin-pagination-arrow--backward',
112
- ['dropin-pagination-arrow--disabled', currentPage === 1],
113
109
  ])}
114
110
  >
115
111
  <Icon size="24" source={ChevronDown} />
116
- </PaginationButton>
112
+ </button>
117
113
  <ul className="dropin-pagination_list">
118
114
  {(paginationList as PaginationList[]).map((item, index) => (
119
115
  <li
@@ -125,31 +121,29 @@ export const Pagination: FunctionComponent<PaginationProps> = ({
125
121
  [`dropin-pagination_list-item--active`, item.isActive],
126
122
  ])}
127
123
  >
128
- <PaginationButton
124
+ <button
125
+ type="button"
129
126
  data-testid={`set-page-button-${item.page}`}
130
- onClick={(e: Event) => handleSetPage(item.page, e)}
131
- href={routePage?.(item.page as number) ?? undefined}
132
-
127
+ onClick={() => handleSetPage(item.page)}
133
128
  >
134
129
  {item.label}
135
- </PaginationButton>
130
+ </button>
136
131
  </li>
137
132
  ))}
138
133
  </ul>
139
- <PaginationButton
134
+ <button
135
+ type="button"
140
136
  data-testid="next-button"
141
137
  aria-label={translations.forwardButton}
142
138
  disabled={currentPage === totalPages}
143
- onClick={(e: Event) => handleForward(e)}
144
- href={routePage?.(currentPage) ?? undefined}
139
+ onClick={handleForward}
145
140
  className={classes([
146
141
  'dropin-pagination-arrow',
147
142
  'dropin-pagination-arrow--forward',
148
- ['dropin-pagination-arrow--disabled', currentPage === totalPages],
149
143
  ])}
150
144
  >
151
145
  <Icon size="24" source={ChevronDown} />
152
- </PaginationButton>
146
+ </button>
153
147
  </div>
154
148
  );
155
149
  };
@@ -17,6 +17,7 @@
17
17
  }
18
18
 
19
19
  .dropin-table__table {
20
+ border: var(--shape-border-width-1) solid var(--color-neutral-400);
20
21
  border-collapse: collapse;
21
22
  width: 100%;
22
23
  }
@@ -34,9 +35,8 @@
34
35
  letter-spacing: var(--type-body-1-strong-letter-spacing);
35
36
  }
36
37
 
37
- .dropin-table__header__cell,
38
- .dropin-table__body__cell {
39
- padding: var(--spacing-xsmall);
38
+ .dropin-table__header__cell {
39
+ color: var(--color-neutral-800);
40
40
  text-align: left;
41
41
  white-space: nowrap;
42
42
  }
@@ -46,15 +46,26 @@
46
46
  }
47
47
 
48
48
  .dropin-table__header__row {
49
- border-bottom: 2px solid var(--color-neutral-400);
49
+ border-bottom: var(--shape-border-width-1) solid var(--color-neutral-400);
50
+ }
51
+
52
+ .dropin-table__header__row th {
53
+ padding: var(--spacing-small) var(--spacing-medium);
54
+ }
55
+
56
+ .dropin-table__body__row:nth-child(even) {
57
+ background-color: var(--color-neutral-100);
58
+ }
59
+
60
+ .dropin-table__body__row.dropin-table__body__row--expanded {
61
+ background-color: var(--color-neutral-200);
50
62
  }
51
63
 
52
- .dropin-table__body__row {
53
- border-bottom: 1px solid var(--color-neutral-400);
64
+ .dropin-table__body__cell {
65
+ padding: var(--spacing-small) var(--spacing-medium);
54
66
  }
55
67
 
56
68
  .dropin-table__header__sort-button {
57
- margin-left: var(--spacing-xsmall);
58
69
  vertical-align: middle;
59
70
  }
60
71
 
@@ -67,10 +78,29 @@
67
78
  }
68
79
 
69
80
  .dropin-table__row-details__cell {
70
- padding: var(--spacing-small);
71
- background-color: var(--color-neutral-100);
72
- border-top: 1px solid var(--color-neutral-300);
73
- border-bottom: 1px solid var(--color-neutral-400);
81
+ padding: var(--spacing-small) var(--spacing-medium);
82
+ background-color: var(--color-neutral-200);
83
+ }
84
+
85
+ .dropin-table__row-details--expanded .dropin-table__row-details__cell > *:last-child {
86
+ margin: 0;
87
+ }
88
+
89
+ .dropin-table__row-details__cell h1,
90
+ .dropin-table__row-details__cell h2,
91
+ .dropin-table__row-details__cell h3,
92
+ .dropin-table__row-details__cell h4,
93
+ .dropin-table__row-details__cell h5,
94
+ .dropin-table__row-details__cell h6 {
95
+ font: var(--type-body-1-strong-font);
96
+ letter-spacing: var(--type-body-1-strong-letter-spacing);
97
+ margin: 0;
98
+ }
99
+
100
+ .dropin-table__row-details__cell p,
101
+ .dropin-table__row-details__cell span {
102
+ font: var(--type-body-1-default-font);
103
+ letter-spacing: var(--type-body-1-default-letter-spacing);
74
104
  }
75
105
 
76
106
  /* Container query for mobile layout */
@@ -80,20 +110,63 @@
80
110
  display: none;
81
111
  }
82
112
 
113
+ .dropin-table--mobile-layout-stacked .dropin-table__body__row {
114
+ padding: var(--spacing-medium);
115
+ display: block;
116
+ }
117
+
83
118
  .dropin-table--mobile-layout-stacked .dropin-table__body__cell {
84
119
  display: block;
120
+ font: var(--type-body-2-default-font);
121
+ letter-spacing: var(--type-body-2-default-letter-spacing);
122
+ padding: var(--spacing-xsmall) 0;
123
+ }
124
+
125
+ .dropin-table--mobile-layout-stacked .dropin-table__body__cell:first-child {
126
+ padding-top: 0;
127
+ }
128
+
129
+ .dropin-table--mobile-layout-stacked .dropin-table__body__cell:last-child {
130
+ padding-bottom: 0;
85
131
  }
86
132
 
87
133
  .dropin-table--mobile-layout-stacked .dropin-table__body__cell::before {
88
134
  content: attr(data-label);
89
- font-weight: bold;
135
+ font: var(--type-body-2-strong-font);
136
+ letter-spacing: var(--type-body-2-strong-letter-spacing);
90
137
  display: block;
91
138
  margin-bottom: var(--spacing-xxsmall);
92
139
  }
93
140
 
94
141
  .dropin-table--mobile-layout-stacked .dropin-table__row-details__cell {
95
142
  display: block;
96
- padding: var(--spacing-small);
143
+ padding: var(--spacing-medium);
144
+ }
145
+
146
+ .dropin-table--mobile-layout-stacked .dropin-table__row-details__cell > *:first-child {
147
+ border-top: var(--shape-border-width-1) solid var(--color-neutral-400);
148
+ padding-top: var(--spacing-medium);
149
+ margin-top: calc(var(--spacing-medium) * -1);
150
+ }
151
+
152
+ .dropin-table--mobile-layout-stacked .dropin-table__row-details--expanded .dropin-table__row-details__cell > *:last-child {
153
+ margin: 0;
154
+ }
155
+
156
+ .dropin-table--mobile-layout-stacked .dropin-table__row-details__cell h1,
157
+ .dropin-table--mobile-layout-stacked .dropin-table__row-details__cell h2,
158
+ .dropin-table--mobile-layout-stacked .dropin-table__row-details__cell h3,
159
+ .dropin-table--mobile-layout-stacked .dropin-table__row-details__cell h4,
160
+ .dropin-table--mobile-layout-stacked .dropin-table__row-details__cell h5,
161
+ .dropin-table--mobile-layout-stacked .dropin-table__row-details__cell h6 {
162
+ font: var(--type-body-2-strong-font);
163
+ letter-spacing: var(--type-body-2-strong-letter-spacing);
164
+ }
165
+
166
+ .dropin-table--mobile-layout-stacked .dropin-table__row-details__cell p,
167
+ .dropin-table--mobile-layout-stacked .dropin-table__row-details__cell span {
168
+ font: var(--type-body-2-default-font);
169
+ letter-spacing: var(--type-body-2-default-letter-spacing);
97
170
  }
98
171
  }
99
172
 
@@ -11,6 +11,10 @@
11
11
  import type { Meta, StoryObj } from '@storybook/preact';
12
12
  import { useState } from 'preact/hooks';
13
13
  import { Table as TableComponent, TableProps } from '@adobe-commerce/elsie/components/Table';
14
+ import { ActionButton } from '@adobe-commerce/elsie/components/ActionButton';
15
+ import { ActionButtonGroup } from '@adobe-commerce/elsie/components/ActionButtonGroup';
16
+ import { Pagination } from '@adobe-commerce/elsie/components/Pagination';
17
+ import { Picker, type PickerOption } from '@adobe-commerce/elsie/components/Picker';
14
18
 
15
19
  /**
16
20
  * Use the `Table` component to render data in a structured table.
@@ -175,10 +179,10 @@ export const Table: Story = {
175
179
  { key: 'actions', label: 'Actions' },
176
180
  ],
177
181
  rowData: [
178
- { name: 'John', email: 'john@example.com', age: 20, actions: <button>Edit</button> },
179
- { name: 'Jane', email: 'jane@example.com', age: 21, actions: <button>Edit</button> },
180
- { name: 'Jim', email: 'jim@example.com', age: 22, actions: <button>Edit</button> },
181
- { name: 'Jill', email: 'jill@example.com', age: 23, actions: <button>Edit</button> },
182
+ { name: 'John', email: 'john@example.com', age: 20, actions: <ActionButton>Edit</ActionButton> },
183
+ { name: 'Jane', email: 'jane@example.com', age: 21, actions: <ActionButton>Edit</ActionButton> },
184
+ { name: 'Jim', email: 'jim@example.com', age: 22, actions: <ActionButton>Edit</ActionButton> },
185
+ { name: 'Jill', email: 'jill@example.com', age: 23, actions: <ActionButton>Edit</ActionButton> },
182
186
  ],
183
187
  },
184
188
  };
@@ -212,11 +216,11 @@ export const AllSortable: Story = {
212
216
  { key: 'actions', label: 'Actions' },
213
217
  ],
214
218
  rowData: [
215
- { name: 'John', email: 'john@example.com', age: 20, actions: <button>Edit</button> },
216
- { name: 'Jane', email: 'jane@example.com', age: 21, actions: <button>Edit</button> },
217
- { name: 'Jim', email: 'jim@example.com', age: 22, actions: <button>Edit</button> },
218
- { name: 'Jill', email: 'jill@example.com', age: 23, actions: <button>Edit</button> },
219
- { name: 'Jack', email: 'jack@example.com', age: 24, actions: <button>Edit</button> },
219
+ { name: 'John', email: 'john@example.com', age: 20, actions: <ActionButton>Edit</ActionButton> },
220
+ { name: 'Jane', email: 'jane@example.com', age: 21, actions: <ActionButton>Edit</ActionButton> },
221
+ { name: 'Jim', email: 'jim@example.com', age: 22, actions: <ActionButton>Edit</ActionButton> },
222
+ { name: 'Jill', email: 'jill@example.com', age: 23, actions: <ActionButton>Edit</ActionButton> },
223
+ { name: 'Jack', email: 'jack@example.com', age: 24, actions: <ActionButton>Edit</ActionButton> },
220
224
  ],
221
225
  },
222
226
  };
@@ -240,7 +244,7 @@ export const AllSortable: Story = {
240
244
  * { key: 'actions', label: 'Actions' }
241
245
  * ]}
242
246
  * rowData={[
243
- * { id: 1, name: 'John Doe', email: 'john@company.com', phone: '+1-555-0123', department: 'Engineering', position: 'Senior Developer', salary: '$95,000', startDate: '2022-01-15', status: 'Active', actions: <button>Edit</button> }
247
+ * { id: 1, name: 'John Doe', email: 'john@company.com', phone: '+1-555-0123', department: 'Engineering', position: 'Senior Developer', salary: '$95,000', startDate: '2022-01-15', status: 'Active', actions: <ActionButton>Edit</ActionButton> }
244
248
  * ]}
245
249
  * />
246
250
  * ```
@@ -270,7 +274,7 @@ export const WideTable: Story = {
270
274
  salary: '$95,000',
271
275
  startDate: '2022-01-15',
272
276
  status: 'Active',
273
- actions: <button>Edit</button>
277
+ actions: <ActionButton>Edit</ActionButton>
274
278
  },
275
279
  {
276
280
  id: 2,
@@ -282,7 +286,7 @@ export const WideTable: Story = {
282
286
  salary: '$78,000',
283
287
  startDate: '2021-06-20',
284
288
  status: 'Active',
285
- actions: <button>Edit</button>
289
+ actions: <ActionButton>Edit</ActionButton>
286
290
  },
287
291
  {
288
292
  id: 3,
@@ -294,7 +298,7 @@ export const WideTable: Story = {
294
298
  salary: '$110,000',
295
299
  startDate: '2020-03-10',
296
300
  status: 'Active',
297
- actions: <button>Edit</button>
301
+ actions: <ActionButton>Edit</ActionButton>
298
302
  },
299
303
  {
300
304
  id: 4,
@@ -306,7 +310,7 @@ export const WideTable: Story = {
306
310
  salary: '$65,000',
307
311
  startDate: '2023-02-28',
308
312
  status: 'Pending',
309
- actions: <button>Edit</button>
313
+ actions: <ActionButton>Edit</ActionButton>
310
314
  },
311
315
  {
312
316
  id: 5,
@@ -318,7 +322,7 @@ export const WideTable: Story = {
318
322
  salary: '$72,000',
319
323
  startDate: '2022-09-12',
320
324
  status: 'Active',
321
- actions: <button>Edit</button>
325
+ actions: <ActionButton>Edit</ActionButton>
322
326
  },
323
327
  ],
324
328
  },
@@ -341,7 +345,7 @@ export const WideTable: Story = {
341
345
  * user: <div><strong>John Doe</strong><br/>john@example.com<br/>Senior Developer</div>,
342
346
  * description: <div>Lead developer for the<br/>e-commerce platform<br/>with 5+ years experience</div>,
343
347
  * status: <span>Active</span>,
344
- * actions: <div><button>Edit</button><br/><button>Delete</button><br/><button>View</button></div>
348
+ * actions: <div><ActionButton>Edit</ActionButton><br/><ActionButton>Delete</ActionButton><br/><ActionButton>View</ActionButton></div>
345
349
  * }
346
350
  * ]}
347
351
  * />
@@ -375,11 +379,11 @@ export const ComplexCells: Story = {
375
379
  <span>Active</span>
376
380
  ),
377
381
  actions: (
378
- <div>
379
- <button>Edit</button>
380
- <button>Delete</button>
381
- <button>View</button>
382
- </div>
382
+ <ActionButtonGroup>
383
+ <ActionButton value="edit">Edit</ActionButton>
384
+ <ActionButton value="delete">Delete</ActionButton>
385
+ <ActionButton value="view">View</ActionButton>
386
+ </ActionButtonGroup>
383
387
  ),
384
388
  },
385
389
  {
@@ -401,11 +405,11 @@ export const ComplexCells: Story = {
401
405
  <span>Pending</span>
402
406
  ),
403
407
  actions: (
404
- <div>
405
- <button>Edit</button>
406
- <button>Approve</button>
407
- <button>Reject</button>
408
- </div>
408
+ <ActionButtonGroup>
409
+ <ActionButton value="edit">Edit</ActionButton>
410
+ <ActionButton value="approve">Approve</ActionButton>
411
+ <ActionButton value="reject">Reject</ActionButton>
412
+ </ActionButtonGroup>
409
413
  ),
410
414
  },
411
415
  {
@@ -427,11 +431,11 @@ export const ComplexCells: Story = {
427
431
  <span>Inactive</span>
428
432
  ),
429
433
  actions: (
430
- <div>
431
- <button>Edit</button>
432
- <button>Activate</button>
433
- <button>Archive</button>
434
- </div>
434
+ <ActionButtonGroup>
435
+ <ActionButton value="edit">Edit</ActionButton>
436
+ <ActionButton value="activate">Activate</ActionButton>
437
+ <ActionButton value="archive">Archive</ActionButton>
438
+ </ActionButtonGroup>
435
439
  ),
436
440
  },
437
441
  ],
@@ -476,10 +480,10 @@ export const StackedMobileLayout: Story = {
476
480
  { key: 'actions', label: 'Actions' },
477
481
  ],
478
482
  rowData: [
479
- { name: 'John Doe', email: 'john.doe@example.com', age: 28, status: 'Active', actions: <button>Edit</button> },
480
- { name: 'Jane Smith', email: 'jane.smith@example.com', age: 32, status: 'Inactive', actions: <button>Edit</button> },
481
- { name: 'Bob Johnson', email: 'bob.johnson@example.com', age: 45, status: 'Active', actions: <button>Edit</button> },
482
- { name: 'Alice Brown', email: 'alice.brown@example.com', age: 29, status: 'Pending', actions: <button>Edit</button> },
483
+ { name: 'John Doe', email: 'john.doe@example.com', age: 28, status: 'Active', actions: <ActionButton>Edit</ActionButton> },
484
+ { name: 'Jane Smith', email: 'jane.smith@example.com', age: 32, status: 'Inactive', actions: <ActionButton>Edit</ActionButton> },
485
+ { name: 'Bob Johnson', email: 'bob.johnson@example.com', age: 45, status: 'Active', actions: <ActionButton>Edit</ActionButton> },
486
+ { name: 'Alice Brown', email: 'alice.brown@example.com', age: 29, status: 'Pending', actions: <ActionButton>Edit</ActionButton> },
483
487
  ],
484
488
  },
485
489
  };
@@ -520,7 +524,7 @@ export const StackedMobileLayout: Story = {
520
524
  * {
521
525
  * name: 'John',
522
526
  * email: 'john@example.com',
523
- * actions: <button onClick={() => toggleRow(0)}>Toggle Details</button>,
527
+ * actions: <ActionButton onClick={() => toggleRow(0)}>Toggle Details</ActionButton>,
524
528
  * _rowDetails: <div>Additional information...</div>
525
529
  * }
526
530
  * ]}
@@ -550,22 +554,22 @@ export const RowDetails: Story = {
550
554
  email: 'john.doe@company.com',
551
555
  status: 'Active',
552
556
  actions: (
553
- <button onClick={() => toggleRow(0)}>
557
+ <ActionButton onClick={() => toggleRow(0)}>
554
558
  {expandedRows.has(0) ? 'Hide' : 'Show'}
555
- </button>
559
+ </ActionButton>
556
560
  ),
557
561
  _rowDetails: (
558
- <div>
562
+ <>
559
563
  <h3>Employee Details</h3>
560
564
  <p><strong>Department:</strong> Engineering</p>
561
565
  <p><strong>Position:</strong> Senior Developer</p>
562
566
  <p><strong>Start Date:</strong> January 15, 2022</p>
563
567
  <p><strong>Notes:</strong> Excellent performance, leads the frontend team.</p>
564
568
  <div style={{ marginTop: '12px' }}>
565
- <button style={{ marginRight: '8px' }}>Update Details</button>
566
- <button>View Full Profile</button>
569
+ <ActionButton style={{ marginRight: '8px' }}>Update Details</ActionButton>
570
+ <ActionButton>View Full Profile</ActionButton>
567
571
  </div>
568
- </div>
572
+ </>
569
573
  )
570
574
  },
571
575
  {
@@ -573,22 +577,22 @@ export const RowDetails: Story = {
573
577
  email: 'jane.smith@company.com',
574
578
  status: 'Pending',
575
579
  actions: (
576
- <button onClick={() => toggleRow(1)}>
580
+ <ActionButton onClick={() => toggleRow(1)}>
577
581
  {expandedRows.has(1) ? 'Hide' : 'Show'}
578
- </button>
582
+ </ActionButton>
579
583
  ),
580
584
  _rowDetails: (
581
- <div>
585
+ <>
582
586
  <h3>Pending Approval</h3>
583
587
  <p><strong>Department:</strong> Marketing</p>
584
588
  <p><strong>Position:</strong> Marketing Manager</p>
585
589
  <p><strong>Application Date:</strong> December 1, 2024</p>
586
590
  <p><strong>Status:</strong> Awaiting HR approval</p>
587
591
  <div style={{ marginTop: '12px' }}>
588
- <button style={{ marginRight: '8px', backgroundColor: '#22c55e', color: 'white', border: 'none', padding: '6px 12px', borderRadius: '4px' }}>Approve</button>
589
- <button style={{ backgroundColor: '#ef4444', color: 'white', border: 'none', padding: '6px 12px', borderRadius: '4px' }}>Reject</button>
592
+ <ActionButton style={{ marginRight: '8px', backgroundColor: '#22c55e', color: 'white', border: 'none', padding: '6px 12px', borderRadius: '4px' }}>Approve</ActionButton>
593
+ <ActionButton style={{ backgroundColor: '#ef4444', color: 'white', border: 'none', padding: '6px 12px', borderRadius: '4px' }}>Reject</ActionButton>
590
594
  </div>
591
- </div>
595
+ </>
592
596
  )
593
597
  },
594
598
  {
@@ -596,22 +600,22 @@ export const RowDetails: Story = {
596
600
  email: 'bob.johnson@company.com',
597
601
  status: 'Inactive',
598
602
  actions: (
599
- <button onClick={() => toggleRow(2)}>
603
+ <ActionButton onClick={() => toggleRow(2)}>
600
604
  {expandedRows.has(2) ? 'Hide' : 'Show'}
601
- </button>
605
+ </ActionButton>
602
606
  ),
603
607
  _rowDetails: (
604
- <div>
608
+ <>
605
609
  <h3>Account Information</h3>
606
610
  <p><strong>Department:</strong> Sales</p>
607
611
  <p><strong>Position:</strong> Sales Director</p>
608
612
  <p><strong>Last Active:</strong> November 20, 2024</p>
609
613
  <p><strong>Reason:</strong> On extended leave</p>
610
614
  <div style={{ marginTop: '12px' }}>
611
- <button style={{ marginRight: '8px' }}>Reactivate Account</button>
612
- <button>Contact Employee</button>
615
+ <ActionButton style={{ marginRight: '8px' }}>Reactivate Account</ActionButton>
616
+ <ActionButton>Contact Employee</ActionButton>
613
617
  </div>
614
- </div>
618
+ </>
615
619
  )
616
620
  },
617
621
  ];
@@ -704,14 +708,17 @@ export const VNodeLabels: Story = {
704
708
  <strong>👤 User Name</strong>
705
709
  </span>
706
710
  ),
711
+ ariaLabel: 'User Name',
707
712
  },
708
713
  {
709
714
  key: 'email',
710
715
  label: <span style={{ color: '#0066cc' }}>📧 Email Address</span>,
716
+ ariaLabel: 'Email Address',
711
717
  },
712
718
  {
713
719
  key: 'role',
714
720
  label: <em style={{ color: '#666' }}>Role & Department</em>,
721
+ ariaLabel: 'Role & Department',
715
722
  },
716
723
  {
717
724
  key: 'status',
@@ -727,10 +734,12 @@ export const VNodeLabels: Story = {
727
734
  📊 Status
728
735
  </span>
729
736
  ),
737
+ ariaLabel: 'Status',
730
738
  },
731
739
  {
732
740
  key: 'actions',
733
741
  label: <span>⚙️ Actions</span>,
742
+ ariaLabel: 'Actions',
734
743
  },
735
744
  ],
736
745
  rowData: [
@@ -739,23 +748,277 @@ export const VNodeLabels: Story = {
739
748
  email: 'john.doe@company.com',
740
749
  role: 'Senior Developer',
741
750
  status: 'Active',
742
- actions: <button>Edit</button>,
751
+ actions: <ActionButton>Edit</ActionButton>,
743
752
  },
744
753
  {
745
754
  name: 'Jane Smith',
746
755
  email: 'jane.smith@company.com',
747
756
  role: 'Product Manager',
748
757
  status: 'Active',
749
- actions: <button>Edit</button>,
758
+ actions: <ActionButton>Edit</ActionButton>,
750
759
  },
751
760
  {
752
761
  name: 'Bob Johnson',
753
762
  email: 'bob.johnson@company.com',
754
763
  role: 'UX Designer',
755
764
  status: 'Inactive',
756
- actions: <button>Edit</button>,
765
+ actions: <ActionButton>Edit</ActionButton>,
757
766
  },
758
767
  ],
759
768
  },
760
769
  };
761
770
 
771
+ /**
772
+ * Table with pagination to navigate through multiple pages of data.
773
+ * This demonstrates how to integrate the Pagination component with the Table component.
774
+ *
775
+ * **Features**:
776
+ * - Pagination controls below the table
777
+ * - Page state management with useState
778
+ * - Dynamic row data based on current page
779
+ * - Items per page configuration
780
+ *
781
+ * ```tsx
782
+ * const [currentPage, setCurrentPage] = useState(1);
783
+ * const itemsPerPage = 5;
784
+ * const totalItems = 50;
785
+ * const totalPages = Math.ceil(totalItems / itemsPerPage);
786
+ *
787
+ * const paginatedData = allData.slice(
788
+ * (currentPage - 1) * itemsPerPage,
789
+ * currentPage * itemsPerPage
790
+ * );
791
+ *
792
+ * <div>
793
+ * <Table
794
+ * columns={columns}
795
+ * rowData={paginatedData}
796
+ * />
797
+ * <Pagination
798
+ * currentPage={currentPage}
799
+ * totalPages={totalPages}
800
+ * onChange={setCurrentPage}
801
+ * />
802
+ * </div>
803
+ * ```
804
+ */
805
+ export const WithPagination: Story = {
806
+ render: (args) => {
807
+ const [currentPage, setCurrentPage] = useState(1);
808
+ const [pageSize, setPageSize] = useState(5);
809
+
810
+ // Page size options
811
+ const pageSizeOptions: PickerOption[] = [
812
+ { value: '5', text: '5' },
813
+ { value: '10', text: '10' },
814
+ { value: '15', text: '15' },
815
+ ];
816
+
817
+ // Generate sample data (287 items to match screenshot)
818
+ const allData = Array.from({ length: 287 }, (_, index) => ({
819
+ id: index + 1,
820
+ name: `User ${index + 1}`,
821
+ email: `user${index + 1}@example.com`,
822
+ department: ['Engineering', 'Marketing', 'Sales', 'HR', 'Finance'][index % 5],
823
+ status: ['Active', 'Inactive', 'Pending'][index % 3],
824
+ actions: <ActionButton>Edit</ActionButton>,
825
+ }));
826
+
827
+ const totalPages = Math.ceil(allData.length / pageSize);
828
+
829
+ // Calculate item range
830
+ const startItem = (currentPage - 1) * pageSize + 1;
831
+ const endItem = Math.min(currentPage * pageSize, allData.length);
832
+ const totalItems = allData.length;
833
+
834
+ // Get current page data
835
+ const paginatedData = allData.slice(
836
+ (currentPage - 1) * pageSize,
837
+ currentPage * pageSize
838
+ );
839
+
840
+ // Handle page size change
841
+ const handlePageSizeChange = (event: Event) => {
842
+ const target = event.target as HTMLSelectElement;
843
+ const newPageSize = Number(target.value);
844
+ setPageSize(newPageSize);
845
+ setCurrentPage(1); // Reset to first page when page size changes
846
+ };
847
+
848
+ return (
849
+ <div>
850
+ <TableComponent
851
+ {...args}
852
+ columns={[
853
+ { key: 'id', label: 'ID' },
854
+ { key: 'name', label: 'Name' },
855
+ { key: 'email', label: 'Email' },
856
+ { key: 'department', label: 'Department' },
857
+ { key: 'status', label: 'Status' },
858
+ { key: 'actions', label: 'Actions' },
859
+ ]}
860
+ rowData={paginatedData}
861
+ />
862
+ <div style={{ marginTop: 'var(--spacing-small)', display: 'flex', justifyContent: 'space-between', alignItems: 'center' }}>
863
+ <span style={{
864
+ font: 'var(--type-body-1-default-font)',
865
+ letterSpacing: 'var(--type-body-1-default-letter-spacing)',
866
+ color: 'var(--color-neutral-800)'
867
+ }}>
868
+ Items {startItem} to {endItem} of {totalItems} total
869
+ </span>
870
+ <Pagination
871
+ currentPage={currentPage}
872
+ totalPages={totalPages}
873
+ onChange={setCurrentPage}
874
+ />
875
+ <div style={{
876
+ display: 'flex',
877
+ alignItems: 'center',
878
+ gap: 'var(--spacing-xsmall)',
879
+ font: 'var(--type-body-1-default-font)',
880
+ letterSpacing: 'var(--type-body-1-default-letter-spacing)',
881
+ color: 'var(--color-neutral-800)'
882
+ }}>
883
+ <span>Show</span>
884
+ <Picker
885
+ variant="primary"
886
+ size="medium"
887
+ value={String(pageSize)}
888
+ options={pageSizeOptions}
889
+ handleSelect={handlePageSizeChange}
890
+ aria-label="Items per page"
891
+ />
892
+ </div>
893
+ </div>
894
+ </div>
895
+ );
896
+ },
897
+ };
898
+
899
+ /**
900
+ * Table with expandable row details and stacked mobile layout.
901
+ * Combines the expandable rows feature with responsive mobile behavior using container queries.
902
+ *
903
+ * **Features**:
904
+ * - Expandable rows with toggle buttons
905
+ * - Stacked mobile layout when container width ≤ 600px
906
+ * - Row details expand in both desktop and mobile views
907
+ * - Mobile view shows labels above each cell value
908
+ *
909
+ * ```tsx
910
+ * const [expandedRows, setExpandedRows] = useState(new Set());
911
+ *
912
+ * const toggleRow = (rowIndex: number) => {
913
+ * setExpandedRows(prev => {
914
+ * const newSet = new Set(prev);
915
+ * if (newSet.has(rowIndex)) {
916
+ * newSet.delete(rowIndex);
917
+ * } else {
918
+ * newSet.add(rowIndex);
919
+ * }
920
+ * return newSet;
921
+ * });
922
+ * };
923
+ *
924
+ * <Table
925
+ * mobileLayout="stacked"
926
+ * columns={columns}
927
+ * rowData={rowDataWithDetails}
928
+ * expandedRows={expandedRows}
929
+ * />
930
+ * ```
931
+ */
932
+ export const ExpandableRowsWithMobileLayout: Story = {
933
+ render: (args) => {
934
+ const [expandedRows, setExpandedRows] = useState(new Set<number>());
935
+
936
+ const toggleRow = (rowIndex: number) => {
937
+ setExpandedRows((prev) => {
938
+ const newSet = new Set(prev);
939
+ if (newSet.has(rowIndex)) {
940
+ newSet.delete(rowIndex);
941
+ } else {
942
+ newSet.add(rowIndex);
943
+ }
944
+ return newSet;
945
+ });
946
+ };
947
+
948
+ const rowData = [
949
+ {
950
+ name: 'John Doe',
951
+ email: 'john.doe@company.com',
952
+ status: 'Active',
953
+ actions: (
954
+ <ActionButton onClick={() => toggleRow(0)}>
955
+ {expandedRows.has(0) ? 'Hide' : 'Show'}
956
+ </ActionButton>
957
+ ),
958
+ _rowDetails: (
959
+ <>
960
+ <h3>Employee Details</h3>
961
+ <p><strong>Department:</strong> Engineering</p>
962
+ <p><strong>Position:</strong> Senior Developer</p>
963
+ <p><strong>Start Date:</strong> January 15, 2022</p>
964
+ <p><strong>Notes:</strong> Excellent performance, leads the frontend team.</p>
965
+ </>
966
+ )
967
+ },
968
+ {
969
+ name: 'Jane Smith',
970
+ email: 'jane.smith@company.com',
971
+ status: 'Pending',
972
+ actions: (
973
+ <ActionButton onClick={() => toggleRow(1)}>
974
+ {expandedRows.has(1) ? 'Hide' : 'Show'}
975
+ </ActionButton>
976
+ ),
977
+ _rowDetails: (
978
+ <>
979
+ <h3>Pending Approval</h3>
980
+ <p><strong>Department:</strong> Marketing</p>
981
+ <p><strong>Position:</strong> Marketing Manager</p>
982
+ <p><strong>Application Date:</strong> December 1, 2024</p>
983
+ <p><strong>Status:</strong> Awaiting HR approval</p>
984
+ </>
985
+ )
986
+ },
987
+ {
988
+ name: 'Bob Johnson',
989
+ email: 'bob.johnson@company.com',
990
+ status: 'Inactive',
991
+ actions: (
992
+ <ActionButton onClick={() => toggleRow(2)}>
993
+ {expandedRows.has(2) ? 'Hide' : 'Show'}
994
+ </ActionButton>
995
+ ),
996
+ _rowDetails: (
997
+ <>
998
+ <h3>Account Information</h3>
999
+ <p><strong>Department:</strong> Sales</p>
1000
+ <p><strong>Position:</strong> Sales Director</p>
1001
+ <p><strong>Last Active:</strong> November 20, 2024</p>
1002
+ <p><strong>Reason:</strong> On extended leave</p>
1003
+ </>
1004
+ )
1005
+ },
1006
+ ];
1007
+
1008
+ return (
1009
+ <TableComponent
1010
+ {...args}
1011
+ mobileLayout="stacked"
1012
+ columns={[
1013
+ { key: 'name', label: 'Name', ariaLabel: 'Name' },
1014
+ { key: 'email', label: 'Email', ariaLabel: 'Email' },
1015
+ { key: 'status', label: 'Status', ariaLabel: 'Status' },
1016
+ { key: 'actions', label: 'Actions', ariaLabel: 'Actions' },
1017
+ ]}
1018
+ rowData={rowData}
1019
+ expandedRows={expandedRows}
1020
+ />
1021
+ );
1022
+ },
1023
+ };
1024
+
@@ -97,7 +97,8 @@ export const Table: FunctionComponent<TableProps> = ({
97
97
  iconSource = 'ChevronDown';
98
98
  ariaLabel = translations.sortedDescending.replace('{label}', label);
99
99
  } else {
100
- iconSource = 'Sort';
100
+ // Show chevron down when sortable but not sorted
101
+ iconSource = 'ChevronDown';
101
102
  ariaLabel = translations.sortBy.replace('{label}', label);
102
103
  }
103
104
 
@@ -138,7 +139,10 @@ export const Table: FunctionComponent<TableProps> = ({
138
139
 
139
140
  return (
140
141
  <Fragment key={rowIndex}>
141
- <tr className="dropin-table__body__row">
142
+ <tr className={classes([
143
+ 'dropin-table__body__row',
144
+ ['dropin-table__body__row--expanded', isExpanded && hasDetails],
145
+ ])}>
142
146
  {columns.map((column) => {
143
147
  const cell = row[column.key];
144
148
  const label = column.ariaLabel ?? column.label;
@@ -1,48 +1,43 @@
1
1
  export { default as Add } from './Add.svg';
2
- export { default as AddressBook } from './AddressBook.svg';
3
2
  export { default as Bulk } from './Bulk.svg';
4
3
  export { default as Burger } from './Burger.svg';
5
- export { default as Business } from './Business.svg';
6
- export { default as Card } from './Card.svg';
7
4
  export { default as Cart } from './Cart.svg';
8
5
  export { default as Check } from './Check.svg';
9
- export { default as CheckWithCircle } from './CheckWithCircle.svg';
10
6
  export { default as ChevronDown } from './ChevronDown.svg';
11
- export { default as ChevronRight } from './ChevronRight.svg';
12
7
  export { default as ChevronUp } from './ChevronUp.svg';
8
+ export { default as ChevronRight } from './ChevronRight.svg';
13
9
  export { default as Close } from './Close.svg';
14
- export { default as Coupon } from './Coupon.svg';
15
- export { default as Date } from './Date.svg';
16
- export { default as Delivery } from './Delivery.svg';
17
- export { default as Edit } from './Edit.svg';
18
- export { default as EmptyBox } from './EmptyBox.svg';
19
- export { default as Eye } from './Eye.svg';
20
- export { default as EyeClose } from './EyeClose.svg';
21
- export { default as Gift } from './Gift.svg';
22
- export { default as GiftCard } from './GiftCard.svg';
23
10
  export { default as Heart } from './Heart.svg';
24
- export { default as HeartFilled } from './HeartFilled.svg';
25
- export { default as InfoFilled } from './InfoFilled.svg';
26
- export { default as List } from './List.svg';
27
- export { default as Locker } from './Locker.svg';
28
11
  export { default as Minus } from './Minus.svg';
29
- export { default as Order } from './Order.svg';
30
- export { default as OrderError } from './OrderError.svg';
31
- export { default as OrderSuccess } from './OrderSuccess.svg';
32
- export { default as PaymentError } from './PaymentError.svg';
33
12
  export { default as Placeholder } from './Placeholder.svg';
34
13
  export { default as PlaceholderFilled } from './PlaceholderFilled.svg';
35
- export { default as Quote } from './Quote.svg';
36
14
  export { default as Search } from './Search.svg';
37
15
  export { default as SearchFilled } from './SearchFilled.svg';
38
16
  export { default as Sort } from './Sort.svg';
39
17
  export { default as Star } from './Star.svg';
40
- export { default as Structure } from './Structure.svg';
41
- export { default as Team } from './Team.svg';
42
- export { default as Trash } from './Trash.svg';
43
- export { default as User } from './User.svg';
44
18
  export { default as View } from './View.svg';
45
- export { default as Wallet } from './Wallet.svg';
19
+ export { default as User } from './User.svg';
46
20
  export { default as Warning } from './Warning.svg';
47
- export { default as WarningFilled } from './WarningFilled.svg';
21
+ export { default as Locker } from './Locker.svg';
22
+ export { default as Wallet } from './Wallet.svg';
23
+ export { default as Card } from './Card.svg';
24
+ export { default as Order } from './Order.svg';
25
+ export { default as Delivery } from './Delivery.svg';
26
+ export { default as OrderError } from './OrderError.svg';
27
+ export { default as OrderSuccess } from './OrderSuccess.svg';
28
+ export { default as PaymentError } from './PaymentError.svg';
29
+ export { default as CheckWithCircle } from './CheckWithCircle.svg';
48
30
  export { default as WarningWithCircle } from './WarningWithCircle.svg';
31
+ export { default as WarningFilled } from './WarningFilled.svg';
32
+ export { default as InfoFilled } from './InfoFilled.svg';
33
+ export { default as HeartFilled } from './HeartFilled.svg';
34
+ export { default as Trash } from './Trash.svg';
35
+ export { default as Eye } from './Eye.svg';
36
+ export { default as EyeClose } from './EyeClose.svg';
37
+ export { default as Date } from './Date.svg';
38
+ export { default as AddressBook } from './AddressBook.svg';
39
+ export { default as EmptyBox } from './EmptyBox.svg';
40
+ export { default as Coupon } from './Coupon.svg';
41
+ export { default as Gift } from './Gift.svg';
42
+ export { default as GiftCard } from './GiftCard.svg';
43
+ export { default as Edit } from './Edit.svg';
@@ -1,46 +0,0 @@
1
- /********************************************************************
2
- * Copyright 2024 Adobe
3
- * All Rights Reserved.
4
- *
5
- * NOTICE: Adobe permits you to use, modify, and distribute this
6
- * file in accordance with the terms of the Adobe license agreement
7
- * accompanying it.
8
- *******************************************************************/
9
-
10
- import { FunctionComponent, JSX } from 'preact';
11
-
12
- type BaseProps = {
13
- href?: string;
14
- type?: 'button';
15
- disabled?: boolean;
16
- };
17
-
18
- export type PaginationButtonProps = BaseProps &
19
- (
20
- | Omit<JSX.HTMLAttributes<HTMLAnchorElement>, 'type'>
21
- | Omit<JSX.HTMLAttributes<HTMLButtonElement>, 'href'>
22
- );
23
-
24
- export const PaginationButton: FunctionComponent<PaginationButtonProps> = (
25
- props
26
- ) => {
27
- if (props.href) {
28
-
29
- const { href, disabled, ...anchorProps } = props;
30
- return (
31
- <a
32
- href={href}
33
- aria-disabled={disabled}
34
- {...(anchorProps as JSX.HTMLAttributes<HTMLAnchorElement>)}
35
- />
36
- );
37
- }
38
-
39
- const { type = 'button', ...buttonProps } = props;
40
- return (
41
- <button
42
- type={type}
43
- {...(buttonProps as JSX.HTMLAttributes<HTMLButtonElement>)}
44
- />
45
- );
46
- };
@@ -1,3 +0,0 @@
1
- <svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
2
- <path vector-effect="non-scaling-stroke" d="M14 3.25C14.9665 3.25 15.75 4.0335 15.75 5V6C15.75 6.08497 15.7422 6.16827 15.7305 6.25H21C21.9665 6.25 22.75 7.0335 22.75 8V10.6807C22.7498 11.3681 22.3487 11.9754 21.75 12.2598V19C21.75 19.9665 20.9665 20.75 20 20.75H4C3.0335 20.75 2.25 19.9665 2.25 19V12.2598C1.65126 11.9754 1.25018 11.3681 1.25 10.6807V8C1.25 7.0335 2.0335 6.25 3 6.25H8.26953C8.25783 6.16827 8.25 6.08497 8.25 6V5C8.25 4.0335 9.0335 3.25 10 3.25H14ZM14.75 13.7148V14C14.75 14.9665 13.9665 15.75 13 15.75H11C10.0335 15.75 9.25 14.9665 9.25 14V13.7148L3.75 12.6143V19C3.75 19.1381 3.86193 19.25 4 19.25H20C20.1381 19.25 20.25 19.1381 20.25 19V12.6143L14.75 13.7148ZM11 12.75C10.8619 12.75 10.75 12.8619 10.75 13V14C10.75 14.1381 10.8619 14.25 11 14.25H13C13.1381 14.25 13.25 14.1381 13.25 14V13C13.25 12.8619 13.1381 12.75 13 12.75H11ZM3 7.75C2.86193 7.75 2.75 7.86193 2.75 8V10.6807C2.75022 10.7996 2.83447 10.9024 2.95117 10.9258L9.43262 12.2207C9.71926 11.6453 10.3135 11.25 11 11.25H13C13.6862 11.25 14.2786 11.6457 14.5654 12.2207L21.0488 10.9258C21.1655 10.9024 21.2498 10.7996 21.25 10.6807V8C21.25 7.86193 21.1381 7.75 21 7.75H3ZM10 4.75C9.86193 4.75 9.75 4.86193 9.75 5V6C9.75 6.13807 9.86193 6.25 10 6.25H14C14.1381 6.25 14.25 6.13807 14.25 6V5C14.25 4.86193 14.1381 4.75 14 4.75H10Z" fill="currentColor" />
3
- </svg>
@@ -1,3 +0,0 @@
1
- <svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
2
- <path vector-effect="non-scaling-stroke" d="M16.8569 2C18.5138 2 19.8569 3.34315 19.8569 5V19C19.8569 20.6569 18.5138 22 16.8569 22H7.14307L6.98877 21.9961C5.45484 21.9183 4.22469 20.6883 4.14697 19.1543L4.14307 19V5C4.14307 3.39498 5.40374 2.08434 6.98877 2.00391L7.14307 2H16.8569ZM7.14307 3.5C6.31475 3.50013 5.64307 4.17165 5.64307 5V19C5.64307 19.8283 6.31475 20.4999 7.14307 20.5H16.8569C17.6854 20.5 18.3569 19.8284 18.3569 19V5C18.3569 4.17157 17.6854 3.5 16.8569 3.5H7.14307ZM7.71436 15.5713C8.10871 15.5713 8.42897 15.8909 8.4292 16.2852C8.4292 16.6796 8.10884 17 7.71436 17C7.32006 16.9998 7.00049 16.6795 7.00049 16.2852C7.00071 15.891 7.3202 15.5715 7.71436 15.5713ZM16.2866 17H9.85791V15.5H16.2866V17ZM16.2866 12.7148H9.85791V11.2148H16.2866V12.7148ZM7.71436 11.2861C8.10884 11.2861 8.4292 11.6055 8.4292 12C8.42916 12.3945 8.10882 12.7139 7.71436 12.7139C7.32008 12.7136 7.00053 12.3943 7.00049 12C7.00049 11.6057 7.32006 11.2864 7.71436 11.2861ZM7.71436 7C8.10871 7 8.42897 7.31957 8.4292 7.71387C8.4292 8.10836 8.10884 8.42871 7.71436 8.42871C7.32006 8.42848 7.00049 8.10822 7.00049 7.71387C7.00071 7.31971 7.3202 7.00023 7.71436 7ZM16.2866 8.42871H9.85791V6.92871H16.2866V8.42871Z" fill="currentColor"/>
3
- </svg>
@@ -1,3 +0,0 @@
1
- <svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
2
- <path vector-effect="non-scaling-stroke" d="M16.8569 2C18.5138 2 19.8569 3.34315 19.8569 5V19C19.8569 20.6569 18.5138 22 16.8569 22H7.14307L6.98877 21.9961C5.45473 21.9184 4.22469 20.6883 4.14697 19.1543L4.14307 19V5C4.14307 3.39489 5.40362 2.08421 6.98877 2.00391L7.14307 2H16.8569ZM7.14307 3.5C6.31464 3.5 5.64307 4.17157 5.64307 5V19C5.64307 19.8284 6.31464 20.5 7.14307 20.5H16.8569C17.6854 20.5 18.3569 19.8284 18.3569 19V5C18.3569 4.17157 17.6854 3.5 16.8569 3.5H7.14307ZM7.71436 17C8.10871 17 8.42897 17.3196 8.4292 17.7139C8.4292 18.1084 8.10884 18.4287 7.71436 18.4287C7.31993 18.4286 7.00049 18.1083 7.00049 17.7139C7.00071 17.3196 7.32007 17.0001 7.71436 17ZM16.2856 18.4287H9.85693V16.9287H16.2856V18.4287ZM7.71436 14.1426C8.10884 14.1426 8.4292 14.4629 8.4292 14.8574C8.42905 15.2518 8.10875 15.5713 7.71436 15.5713C7.32002 15.5712 7.00064 15.2517 7.00049 14.8574C7.00049 14.463 7.31993 14.1427 7.71436 14.1426ZM16.2856 15.5713H9.85693V14.0713H16.2856V15.5713ZM12.7856 5.6748C13.5717 5.96006 14.1792 6.66301 14.1792 7.57227H12.6792C12.6792 7.34883 12.4515 7.0362 12.0005 7.03613C11.5756 7.03613 11.3506 7.31331 11.3257 7.53223C11.333 7.54311 11.3434 7.56003 11.3608 7.58008C11.4311 7.66062 11.5467 7.75541 11.6958 7.85254C11.84 7.94645 11.9892 8.02578 12.105 8.08203C12.1617 8.10958 12.2084 8.13079 12.2397 8.14453C12.2553 8.15136 12.2679 8.15625 12.2749 8.15918C12.2781 8.16054 12.2807 8.16169 12.2817 8.16211L12.2837 8.16309C12.2851 8.16366 12.2875 8.16419 12.2896 8.16504C12.2938 8.16681 12.2993 8.16999 12.3062 8.17285C12.32 8.17866 12.3396 8.1861 12.3628 8.19629C12.4095 8.21678 12.4744 8.24686 12.5513 8.28418C12.7031 8.35794 12.911 8.46704 13.1235 8.60547C13.3312 8.74079 13.5734 8.92349 13.771 9.15039C13.963 9.37099 14.1792 9.71019 14.1792 10.1436C14.1789 11.0523 13.5713 11.753 12.7856 12.0381V12.7148H11.2856V12.0605C10.4664 11.7925 9.8221 11.0791 9.82178 10.1436H11.3218C11.3223 10.367 11.5499 10.6787 12.0005 10.6787C12.4257 10.6786 12.6498 10.4006 12.6743 10.1816C12.667 10.1709 12.657 10.1542 12.6401 10.1348C12.5699 10.0542 12.4543 9.95949 12.3052 9.8623C12.1609 9.76835 12.0118 9.68909 11.896 9.63281C11.839 9.60514 11.7916 9.58407 11.7603 9.57031L11.7192 9.55273H11.7183L11.7163 9.55176C11.715 9.55122 11.7133 9.55056 11.7114 9.5498C11.7071 9.54803 11.7008 9.5449 11.6938 9.54199C11.6801 9.53621 11.6611 9.5286 11.6382 9.51855C11.5915 9.49808 11.5265 9.46797 11.4497 9.43066C11.2978 9.35687 11.0892 9.24796 10.8765 9.10938C10.6688 8.97407 10.4266 8.7913 10.229 8.56445C10.0371 8.34398 9.82204 8.00515 9.82178 7.57227C9.82178 6.63623 10.466 5.92047 11.2856 5.65234L11.2866 5H12.7866L12.7856 5.6748Z" fill="currentColor"/>
3
- </svg>
@@ -1,8 +0,0 @@
1
- <svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
2
- <rect vector-effect="non-scaling-stroke" x="5" y="5.28076" width="14" height="1.5" rx="0.75" fill="currentColor"/>
3
- <rect vector-effect="non-scaling-stroke" x="8.27539" y="11.2192" width="14" height="1.5" rx="0.75" fill="currentColor"/>
4
- <rect vector-effect="non-scaling-stroke" x="8.44922" y="17.2192" width="14" height="1.5" rx="0.75" fill="currentColor"/>
5
- <circle vector-effect="non-scaling-stroke" cx="2.30078" cy="6.03076" r="0.75" fill="currentColor"/>
6
- <circle vector-effect="non-scaling-stroke" cx="5.67578" cy="11.9692" r="0.75" fill="currentColor"/>
7
- <circle vector-effect="non-scaling-stroke" cx="5.67578" cy="17.9692" r="0.75" fill="currentColor"/>
8
- </svg>
@@ -1,5 +0,0 @@
1
- <svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
2
- <path vector-effect="non-scaling-stroke" d="M10.6047 10.011L10.4765 10.2749C10.4093 10.4774 10.2566 10.6307 10.0551 10.7044C9.43878 10.926 8.91201 11.1763 8.49707 11.4375M13.4262 10.2442L13.2674 10.0908C13.3957 10.3608 13.6094 10.5817 13.872 10.7228C14.3816 10.8972 14.9429 11.145 15.4124 11.4375M11.8262 10.2994C11.246 10.2994 10.7085 10.011 10.3849 9.52631L10.3665 9.49563L10.3482 9.45882C9.5848 8.29306 9.21837 6.90642 9.30998 5.50751C9.35273 4.12087 10.4826 3.01033 11.8628 3.00419H11.9483C13.3347 2.92443 14.5195 3.99202 14.5989 5.37866C14.5989 5.42775 14.5989 5.4707 14.5989 5.51978C14.6844 6.89415 14.3302 8.26238 13.5851 9.41587L13.5362 9.4895C13.2003 9.98648 12.6384 10.281 12.046 10.2871H11.9483C11.9056 10.2871 11.8628 10.2933 11.8201 10.2933L11.8262 10.2994Z" stroke="currentColor" stroke-width="1.5" stroke-linejoin="round"/>
3
- <path vector-effect="non-scaling-stroke" d="M1.125 20.7002C1.14332 20.0069 1.21661 19.3136 1.33875 18.6325C1.47312 18.0128 2.43807 17.3134 3.92214 16.7796C4.12368 16.7059 4.27636 16.5525 4.34354 16.3501L4.47179 16.0862M7.29326 16.3194L7.13447 16.166C7.26272 16.436 7.47648 16.6569 7.73909 16.798C8.83229 17.1722 10.1637 17.884 10.3164 18.6509C10.4446 19.3258 10.5057 20.013 10.4996 20.6941M5.69325 16.3746C5.11306 16.3746 4.57562 16.0862 4.25193 15.6015L4.23361 15.5708L4.21529 15.534C3.45188 14.3683 3.08544 12.9816 3.17705 11.5827C3.2198 10.1961 4.34965 9.08553 5.72989 9.07939H5.8154C7.20175 8.99963 8.38656 10.0672 8.46596 11.4539C8.46596 11.5029 8.46596 11.5459 8.46596 11.595C8.55146 12.9693 8.19724 14.3376 7.45215 15.4911L7.40329 15.5647C7.06739 16.0617 6.50552 16.3562 5.91311 16.3623H5.8154C5.77264 16.3623 5.72989 16.3685 5.68714 16.3685L5.69325 16.3746Z" stroke="currentColor" stroke-width="1.5" stroke-linejoin="round"/>
4
- <path vector-effect="non-scaling-stroke" d="M13.5 20.7002C13.5183 20.0069 13.5916 19.3136 13.7138 18.6325C13.8481 18.0128 14.8131 17.3134 16.2971 16.7796C16.4987 16.7059 16.6514 16.5525 16.7185 16.3501L16.8468 16.0862M19.6683 16.3194L19.5095 16.166C19.6377 16.436 19.8515 16.6569 20.1141 16.798C21.2073 17.1722 22.5387 17.884 22.6914 18.6509C22.8196 19.3258 22.8807 20.013 22.8746 20.6941M18.0682 16.3746C17.4881 16.3746 16.9506 16.0862 16.6269 15.6015L16.6086 15.5708L16.5903 15.534C15.8269 14.3683 15.4604 12.9816 15.552 11.5827C15.5948 10.1961 16.7246 9.08553 18.1049 9.07939H18.1904C19.5767 8.99963 20.7616 10.0672 20.841 11.4539C20.841 11.5029 20.841 11.5459 20.841 11.595C20.9265 12.9693 20.5722 14.3376 19.8271 15.4911L19.7783 15.5647C19.4424 16.0617 18.8805 16.3562 18.2881 16.3623H18.1904C18.1476 16.3623 18.1049 16.3685 18.0621 16.3685L18.0682 16.3746Z" stroke="currentColor" stroke-width="1.5" stroke-linejoin="round"/>
5
- </svg>