@arbor-education/design-system.components 1.0.4 → 2.0.0
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/.github/workflows/fail-on-no-changeset.yml +33 -1
- package/CHANGELOG.md +17 -0
- package/dist/components/breadcrumbs/BreadcrumbCopyButton.d.ts.map +1 -1
- package/dist/components/breadcrumbs/BreadcrumbCopyButton.js +3 -2
- package/dist/components/breadcrumbs/BreadcrumbCopyButton.js.map +1 -1
- package/dist/components/breadcrumbs/BreadcrumbEllipsis.d.ts.map +1 -1
- package/dist/components/breadcrumbs/BreadcrumbEllipsis.js +2 -1
- package/dist/components/breadcrumbs/BreadcrumbEllipsis.js.map +1 -1
- package/dist/components/button/Button.d.ts +17 -8
- package/dist/components/button/Button.d.ts.map +1 -1
- package/dist/components/button/Button.js +5 -6
- package/dist/components/button/Button.js.map +1 -1
- package/dist/components/button/Button.stories.d.ts +17 -36
- package/dist/components/button/Button.stories.d.ts.map +1 -1
- package/dist/components/button/Button.stories.js +165 -214
- package/dist/components/button/Button.stories.js.map +1 -1
- package/dist/components/button/Button.test.d.ts.map +1 -1
- package/dist/components/button/Button.test.js +16 -10
- package/dist/components/button/Button.test.js.map +1 -1
- package/dist/components/datePicker/DatePicker.d.ts.map +1 -1
- package/dist/components/datePicker/DatePicker.js +2 -1
- package/dist/components/datePicker/DatePicker.js.map +1 -1
- package/dist/components/dateTimePicker/DateTimePicker.d.ts.map +1 -1
- package/dist/components/dateTimePicker/DateTimePicker.js +2 -1
- package/dist/components/dateTimePicker/DateTimePicker.js.map +1 -1
- package/dist/components/dropdown/Dropdown.stories.d.ts.map +1 -1
- package/dist/components/dropdown/Dropdown.stories.js +5 -3
- package/dist/components/dropdown/Dropdown.stories.js.map +1 -1
- package/dist/components/emptyState/EmptyState.stories.d.ts.map +1 -1
- package/dist/components/emptyState/EmptyState.stories.js +3 -2
- package/dist/components/emptyState/EmptyState.stories.js.map +1 -1
- package/dist/components/fileUpload/FileUpload.d.ts.map +1 -1
- package/dist/components/fileUpload/FileUpload.js +1 -1
- package/dist/components/fileUpload/FileUpload.js.map +1 -1
- package/dist/components/fileUpload/FileUpload.test.js +4 -4
- package/dist/components/fileUpload/FileUpload.test.js.map +1 -1
- package/dist/components/formField/inputs/colourPickerDropdown/ColourPickerDropdown.d.ts.map +1 -1
- package/dist/components/formField/inputs/colourPickerDropdown/ColourPickerDropdown.js +2 -1
- package/dist/components/formField/inputs/colourPickerDropdown/ColourPickerDropdown.js.map +1 -1
- package/dist/components/formField/inputs/selectDropdown/SelectDropdown.d.ts.map +1 -1
- package/dist/components/formField/inputs/selectDropdown/SelectDropdown.js +2 -1
- package/dist/components/formField/inputs/selectDropdown/SelectDropdown.js.map +1 -1
- package/dist/components/grid/Grid.stories.d.ts.map +1 -1
- package/dist/components/grid/Grid.stories.js +4 -3
- package/dist/components/grid/Grid.stories.js.map +1 -1
- package/dist/components/heading/Heading.stories.d.ts.map +1 -1
- package/dist/components/heading/Heading.stories.js +18 -14
- package/dist/components/heading/Heading.stories.js.map +1 -1
- package/dist/components/icon/Icon.stories.d.ts.map +1 -1
- package/dist/components/icon/Icon.stories.js +30 -31
- package/dist/components/icon/Icon.stories.js.map +1 -1
- package/dist/components/modal/ModalCloseButton.d.ts.map +1 -1
- package/dist/components/modal/ModalCloseButton.js +2 -1
- package/dist/components/modal/ModalCloseButton.js.map +1 -1
- package/dist/components/section/Section.stories.d.ts.map +1 -1
- package/dist/components/section/Section.stories.js +52 -25
- package/dist/components/section/Section.stories.js.map +1 -1
- package/dist/components/table/Table.stories.d.ts.map +1 -1
- package/dist/components/table/Table.stories.js +4 -6
- package/dist/components/table/Table.stories.js.map +1 -1
- package/dist/components/table/pagination/PageSizeSelector.d.ts.map +1 -1
- package/dist/components/table/pagination/PageSizeSelector.js +2 -1
- package/dist/components/table/pagination/PageSizeSelector.js.map +1 -1
- package/dist/components/table/pagination/PaginationControls.d.ts.map +1 -1
- package/dist/components/table/pagination/PaginationControls.js +3 -2
- package/dist/components/table/pagination/PaginationControls.js.map +1 -1
- package/dist/components/table/tableControls/BulkActionsDropdown.d.ts.map +1 -1
- package/dist/components/table/tableControls/BulkActionsDropdown.js +3 -2
- package/dist/components/table/tableControls/BulkActionsDropdown.js.map +1 -1
- package/dist/components/table/tableControls/TableControls.d.ts.map +1 -1
- package/dist/components/table/tableControls/TableControls.js +2 -1
- package/dist/components/table/tableControls/TableControls.js.map +1 -1
- package/dist/components/table/tableControls/TableSettingsDropdown.d.ts.map +1 -1
- package/dist/components/table/tableControls/TableSettingsDropdown.js +2 -1
- package/dist/components/table/tableControls/TableSettingsDropdown.js.map +1 -1
- package/dist/components/toast/Toast.js +1 -1
- package/dist/components/toast/Toast.js.map +1 -1
- package/dist/components/tooltip/Tooltip.stories.js +5 -5
- package/dist/components/tooltip/Tooltip.stories.js.map +1 -1
- package/dist/components/tooltip/TooltipWrapper.stories.js +2 -2
- package/dist/components/tooltip/TooltipWrapper.stories.js.map +1 -1
- package/dist/components/userDropdown/internal/UserDropdownTrigger.d.ts.map +1 -1
- package/dist/components/userDropdown/internal/UserDropdownTrigger.js +3 -2
- package/dist/components/userDropdown/internal/UserDropdownTrigger.js.map +1 -1
- package/dist/index.css +15 -15
- package/dist/index.css.map +1 -1
- package/package.json +1 -1
- package/src/components/breadcrumbs/BreadcrumbCopyButton.tsx +5 -2
- package/src/components/breadcrumbs/BreadcrumbEllipsis.tsx +5 -2
- package/src/components/breadcrumbs/breadcrumbs.scss +2 -2
- package/src/components/button/Button.stories.tsx +205 -230
- package/src/components/button/Button.test.tsx +36 -9
- package/src/components/button/Button.tsx +6 -16
- package/src/components/button/button.scss +8 -8
- package/src/components/datePicker/DatePicker.tsx +5 -3
- package/src/components/dateTimePicker/DateTimePicker.tsx +5 -3
- package/src/components/dropdown/Dropdown.stories.tsx +7 -3
- package/src/components/emptyState/EmptyState.stories.tsx +4 -2
- package/src/components/fileUpload/FileUpload.test.tsx +4 -4
- package/src/components/fileUpload/FileUpload.tsx +8 -4
- package/src/components/formField/inputs/colourPickerDropdown/ColourPickerDropdown.tsx +3 -1
- package/src/components/formField/inputs/selectDropdown/SelectDropdown.tsx +3 -2
- package/src/components/grid/Grid.stories.tsx +17 -4
- package/src/components/heading/Heading.stories.tsx +23 -16
- package/src/components/icon/Icon.stories.tsx +43 -44
- package/src/components/modal/ModalCloseButton.tsx +5 -3
- package/src/components/section/Section.stories.tsx +86 -31
- package/src/components/table/Table.stories.tsx +19 -6
- package/src/components/table/pagination/PageSizeSelector.tsx +3 -1
- package/src/components/table/pagination/PaginationControls.tsx +17 -12
- package/src/components/table/tableControls/BulkActionsDropdown.tsx +3 -1
- package/src/components/table/tableControls/TableControls.tsx +31 -22
- package/src/components/table/tableControls/TableSettingsDropdown.tsx +7 -4
- package/src/components/toast/Toast.tsx +1 -1
- package/src/components/tooltip/Tooltip.stories.tsx +7 -7
- package/src/components/tooltip/TooltipWrapper.stories.tsx +4 -4
- package/src/components/userDropdown/internal/UserDropdownTrigger.tsx +2 -1
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { expect, test, describe, vi } from 'vitest';
|
|
2
2
|
import { Button } from './Button.js';
|
|
3
|
+
import { Icon } from 'Components/icon/Icon';
|
|
3
4
|
import { render, screen, fireEvent } from '@testing-library/react';
|
|
4
5
|
import '@testing-library/jest-dom/vitest';
|
|
5
6
|
|
|
@@ -9,29 +10,55 @@ describe('Button component', () => {
|
|
|
9
10
|
expect(screen.getByText('Button Text')).toBeInTheDocument();
|
|
10
11
|
});
|
|
11
12
|
|
|
12
|
-
test('renders button with
|
|
13
|
-
render(
|
|
13
|
+
test('renders button with an icon after the text', () => {
|
|
14
|
+
render(
|
|
15
|
+
<Button>
|
|
16
|
+
Button Text
|
|
17
|
+
<Icon name="info" screenReaderText="the icon is here" />
|
|
18
|
+
</Button>,
|
|
19
|
+
);
|
|
14
20
|
expect(screen.getByText('the icon is here')).toBeInTheDocument();
|
|
15
21
|
expect(screen.getByText('Button Text')).toBeInTheDocument();
|
|
16
22
|
});
|
|
17
23
|
|
|
18
|
-
test('renders button with
|
|
19
|
-
render(
|
|
24
|
+
test('renders button with an icon before the text', () => {
|
|
25
|
+
render(
|
|
26
|
+
<Button>
|
|
27
|
+
<Icon name="info" screenReaderText="the icon is here" />
|
|
28
|
+
Button Text
|
|
29
|
+
</Button>,
|
|
30
|
+
);
|
|
20
31
|
expect(screen.getByText('the icon is here')).toBeInTheDocument();
|
|
21
32
|
expect(screen.getByText('Button Text')).toBeInTheDocument();
|
|
22
33
|
});
|
|
23
34
|
|
|
24
|
-
test('renders button with
|
|
25
|
-
render(
|
|
35
|
+
test('renders button with an icon before and after the text', () => {
|
|
36
|
+
render(
|
|
37
|
+
<Button>
|
|
38
|
+
<Icon name="info" screenReaderText="the left icon is here" />
|
|
39
|
+
Button Text
|
|
40
|
+
<Icon name="info" screenReaderText="the right icon is here" />
|
|
41
|
+
</Button>,
|
|
42
|
+
);
|
|
26
43
|
expect(screen.getByText('the right icon is here')).toBeInTheDocument();
|
|
27
44
|
expect(screen.getByText('the left icon is here')).toBeInTheDocument();
|
|
28
45
|
expect(screen.getByText('Button Text')).toBeInTheDocument();
|
|
29
46
|
});
|
|
30
47
|
|
|
31
|
-
test('applies
|
|
32
|
-
render(
|
|
48
|
+
test('applies round style when isRound is set', () => {
|
|
49
|
+
render(
|
|
50
|
+
<Button isRound>
|
|
51
|
+
<Icon name="info" screenReaderText="the icon is here" />
|
|
52
|
+
</Button>,
|
|
53
|
+
);
|
|
33
54
|
const button = screen.getByText('the icon is here').closest('button');
|
|
34
|
-
expect(button).toHaveClass('ds-button--
|
|
55
|
+
expect(button).toHaveClass('ds-button--round');
|
|
56
|
+
});
|
|
57
|
+
|
|
58
|
+
test('does not apply round style by default', () => {
|
|
59
|
+
render(<Button>Button Text</Button>);
|
|
60
|
+
const button = screen.getByText('Button Text').closest('button');
|
|
61
|
+
expect(button).not.toHaveClass('ds-button--round');
|
|
35
62
|
});
|
|
36
63
|
|
|
37
64
|
test('applies primary style by default', () => {
|
|
@@ -1,7 +1,5 @@
|
|
|
1
1
|
import classNames from 'classnames';
|
|
2
2
|
import React, { forwardRef, type ButtonHTMLAttributes, type PropsWithChildren } from 'react';
|
|
3
|
-
import type { IconName } from 'Components/icon/allowedIcons';
|
|
4
|
-
import { Icon } from 'Components/icon/Icon';
|
|
5
3
|
|
|
6
4
|
export type ButtonVariant = 'primary' | 'secondary' | 'tertiary' | 'primary-destructive' | 'secondary-destructive' | 'text-link' | 'dropdown';
|
|
7
5
|
|
|
@@ -13,15 +11,12 @@ export type ButtonProps = {
|
|
|
13
11
|
children?: React.ReactNode;
|
|
14
12
|
className?: string;
|
|
15
13
|
error?: boolean;
|
|
16
|
-
[key: string]: unknown;
|
|
14
|
+
[key: `data-${string}`]: unknown;
|
|
17
15
|
hasHorizontalPadding?: boolean;
|
|
18
|
-
|
|
19
|
-
iconRightScreenReaderText?: string;
|
|
20
|
-
iconLeftName?: IconName;
|
|
21
|
-
iconLeftScreenReaderText?: string;
|
|
16
|
+
isRound?: boolean;
|
|
22
17
|
borderless?: boolean;
|
|
23
18
|
onClick?: (event: React.MouseEvent<HTMLButtonElement>, ...otherArgs: unknown[]) => void;
|
|
24
|
-
} & Omit<ButtonHTMLAttributes<HTMLButtonElement>, '
|
|
19
|
+
} & Omit<ButtonHTMLAttributes<HTMLButtonElement>, 'onClick'>;
|
|
25
20
|
|
|
26
21
|
export const Button = forwardRef<HTMLButtonElement, PropsWithChildren<ButtonProps>>((props: ButtonProps, ref) => {
|
|
27
22
|
const {
|
|
@@ -32,10 +27,7 @@ export const Button = forwardRef<HTMLButtonElement, PropsWithChildren<ButtonProp
|
|
|
32
27
|
disabled = false,
|
|
33
28
|
className = '',
|
|
34
29
|
hasHorizontalPadding = true,
|
|
35
|
-
|
|
36
|
-
iconRightScreenReaderText,
|
|
37
|
-
iconLeftName,
|
|
38
|
-
iconLeftScreenReaderText,
|
|
30
|
+
isRound = false,
|
|
39
31
|
borderless = false,
|
|
40
32
|
error = false,
|
|
41
33
|
...rest
|
|
@@ -49,7 +41,7 @@ export const Button = forwardRef<HTMLButtonElement, PropsWithChildren<ButtonProp
|
|
|
49
41
|
{
|
|
50
42
|
'ds-button--error': error,
|
|
51
43
|
'ds-button--no-horizontal-padding': !hasHorizontalPadding,
|
|
52
|
-
'ds-button--
|
|
44
|
+
'ds-button--round': isRound,
|
|
53
45
|
'ds-button--borderless': borderless,
|
|
54
46
|
},
|
|
55
47
|
className,
|
|
@@ -59,9 +51,7 @@ export const Button = forwardRef<HTMLButtonElement, PropsWithChildren<ButtonProp
|
|
|
59
51
|
ref={ref}
|
|
60
52
|
{...rest}
|
|
61
53
|
>
|
|
62
|
-
{
|
|
63
|
-
{children ? <span className="ds-button__content">{children}</span> : children}
|
|
64
|
-
{iconRightName && <Icon name={iconRightName} size={16} screenReaderText={iconRightScreenReaderText || iconRightName} />}
|
|
54
|
+
{children}
|
|
65
55
|
</button>
|
|
66
56
|
);
|
|
67
57
|
});
|
|
@@ -25,20 +25,20 @@
|
|
|
25
25
|
// Button sizes
|
|
26
26
|
&--M {
|
|
27
27
|
height: var(--size-medium);
|
|
28
|
-
}
|
|
29
28
|
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
29
|
+
&.ds-button--round {
|
|
30
|
+
padding: 0;
|
|
31
|
+
width: var(--size-medium);
|
|
32
|
+
}
|
|
33
33
|
}
|
|
34
34
|
|
|
35
35
|
&--S {
|
|
36
36
|
height: var(--size-small);
|
|
37
|
-
}
|
|
38
37
|
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
38
|
+
&.ds-button--round {
|
|
39
|
+
padding: 0;
|
|
40
|
+
width: var(--size-small);
|
|
41
|
+
}
|
|
42
42
|
}
|
|
43
43
|
|
|
44
44
|
// Button text
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import classNames from 'classnames';
|
|
2
2
|
import { Button } from 'Components/button/Button';
|
|
3
|
+
import { Icon } from 'Components/icon/Icon';
|
|
3
4
|
import { TextInput } from 'Components/formField/inputs/text/TextInput';
|
|
4
5
|
import { Popover } from 'radix-ui';
|
|
5
6
|
import {
|
|
@@ -201,9 +202,10 @@ export const DatePicker = (props: DatePickerProps) => {
|
|
|
201
202
|
<Button
|
|
202
203
|
className="ds-date-picker__button"
|
|
203
204
|
variant="text-link"
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
205
|
+
isRound
|
|
206
|
+
>
|
|
207
|
+
<Icon name="date" screenReaderText="Open date picker" />
|
|
208
|
+
</Button>
|
|
207
209
|
</Popover.Trigger>
|
|
208
210
|
<Popover.Portal container={popupParentRef.current}>
|
|
209
211
|
<Popover.Content
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import classNames from 'classnames';
|
|
2
2
|
import { Button } from 'Components/button/Button';
|
|
3
|
+
import { Icon } from 'Components/icon/Icon';
|
|
3
4
|
import type { ComboboxSearchType } from 'Components/combobox/types';
|
|
4
5
|
import {
|
|
5
6
|
formatDateTimeInputValue,
|
|
@@ -275,9 +276,10 @@ export const DateTimePicker = (props: DateTimePickerProps) => {
|
|
|
275
276
|
<Button
|
|
276
277
|
className="ds-date-time-picker__button"
|
|
277
278
|
variant="text-link"
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
279
|
+
isRound
|
|
280
|
+
>
|
|
281
|
+
<Icon name="date" screenReaderText="Open date and time picker" />
|
|
282
|
+
</Button>
|
|
281
283
|
</Popover.Trigger>
|
|
282
284
|
<Popover.Portal container={popupParentRef.current}>
|
|
283
285
|
<Popover.Content
|
|
@@ -881,7 +881,9 @@ export const WithIcons: Story = withDescription(
|
|
|
881
881
|
<div style={{ padding: 'var(--spacing-xlarge)' }}>
|
|
882
882
|
<Dropdown>
|
|
883
883
|
<Dropdown.Trigger>
|
|
884
|
-
<Button variant="secondary"
|
|
884
|
+
<Button variant="secondary" isRound hasHorizontalPadding={false}>
|
|
885
|
+
<Icon name="3-dot" screenReaderText="More actions" />
|
|
886
|
+
</Button>
|
|
885
887
|
</Dropdown.Trigger>
|
|
886
888
|
<Dropdown.Content>
|
|
887
889
|
<Dropdown.Item onSelect={() => console.log('view')}>
|
|
@@ -915,7 +917,9 @@ function IconItemsDropdown() {
|
|
|
915
917
|
return (
|
|
916
918
|
<Dropdown>
|
|
917
919
|
<Dropdown.Trigger>
|
|
918
|
-
<Button variant="secondary"
|
|
920
|
+
<Button variant="secondary" isRound hasHorizontalPadding={false}>
|
|
921
|
+
<Icon name="3-dot" screenReaderText="More actions" />
|
|
922
|
+
</Button>
|
|
919
923
|
</Dropdown.Trigger>
|
|
920
924
|
<Dropdown.Content>
|
|
921
925
|
<Dropdown.Item onSelect={() => console.log('view')}>
|
|
@@ -945,7 +949,7 @@ export default IconItemsDropdown;`,
|
|
|
945
949
|
},
|
|
946
950
|
},
|
|
947
951
|
},
|
|
948
|
-
'Icons inside `Dropdown.Item` children align automatically via the item\'s flex layout (`gap` + `align-items: center`). Use `size={16}` to match the item\'s line height. The trigger here uses an icon-only `Button` with `
|
|
952
|
+
'Icons inside `Dropdown.Item` children align automatically via the item\'s flex layout (`gap` + `align-items: center`). Use `size={16}` to match the item\'s line height. The trigger here uses an icon-only `Button` with `isRound` and a child `Icon` — the classic "more actions" kebab pattern used throughout Arbor\'s table rows. Always pass `screenReaderText` on that `Icon` so screen reader users know what the button does.',
|
|
949
953
|
);
|
|
950
954
|
|
|
951
955
|
export const WithDestructiveAction: Story = withDescription(
|
|
@@ -208,7 +208,8 @@ const TertiaryActionTemplate = () => (
|
|
|
208
208
|
subHeading="Start by adding the content and data blocks you want to see here."
|
|
209
209
|
orientation="vertical"
|
|
210
210
|
actions={(
|
|
211
|
-
<Button type="button" variant="text-link"
|
|
211
|
+
<Button type="button" variant="text-link">
|
|
212
|
+
<Icon name="plus" />
|
|
212
213
|
Add
|
|
213
214
|
</Button>
|
|
214
215
|
)}
|
|
@@ -353,7 +354,8 @@ function EmptyStateTertiaryActionExample() {
|
|
|
353
354
|
subHeading="Start by adding the content and data blocks you want to see here."
|
|
354
355
|
orientation="vertical"
|
|
355
356
|
actions={
|
|
356
|
-
<Button type="button" variant="text-link"
|
|
357
|
+
<Button type="button" variant="text-link">
|
|
358
|
+
<Icon name="plus" />
|
|
357
359
|
Add
|
|
358
360
|
</Button>
|
|
359
361
|
}
|
|
@@ -70,7 +70,7 @@ describe('FileUpload', () => {
|
|
|
70
70
|
<FileUpload uploadedFiles={[{ ...baseFile, onDelete }]} uploadFiles={vi.fn()} />,
|
|
71
71
|
);
|
|
72
72
|
|
|
73
|
-
await userEvent.click(screen.getByRole('button', { name: '
|
|
73
|
+
await userEvent.click(screen.getByRole('button', { name: 'Delete file' }));
|
|
74
74
|
expect(onDelete).toHaveBeenCalledOnce();
|
|
75
75
|
});
|
|
76
76
|
|
|
@@ -81,12 +81,12 @@ describe('FileUpload', () => {
|
|
|
81
81
|
uploadFiles={vi.fn()}
|
|
82
82
|
/>,
|
|
83
83
|
);
|
|
84
|
-
expect(screen.getByRole('button', { name: '
|
|
84
|
+
expect(screen.getByRole('button', { name: 'Download file' })).toBeInTheDocument();
|
|
85
85
|
});
|
|
86
86
|
|
|
87
87
|
test('does not render download button when onDownload is not provided', () => {
|
|
88
88
|
render(<FileUpload uploadedFiles={[baseFile]} uploadFiles={vi.fn()} />);
|
|
89
|
-
expect(screen.queryByRole('button', { name: '
|
|
89
|
+
expect(screen.queryByRole('button', { name: 'Download file' })).not.toBeInTheDocument();
|
|
90
90
|
});
|
|
91
91
|
|
|
92
92
|
test('calls onDownload when download button is clicked', async () => {
|
|
@@ -98,7 +98,7 @@ describe('FileUpload', () => {
|
|
|
98
98
|
/>,
|
|
99
99
|
);
|
|
100
100
|
|
|
101
|
-
await userEvent.click(screen.getByRole('button', { name: '
|
|
101
|
+
await userEvent.click(screen.getByRole('button', { name: 'Download file' }));
|
|
102
102
|
expect(onDownload).toHaveBeenCalledOnce();
|
|
103
103
|
});
|
|
104
104
|
});
|
|
@@ -111,16 +111,20 @@ export const FileUpload = (props: FileUploadProps) => {
|
|
|
111
111
|
{onDownload && (
|
|
112
112
|
<Button
|
|
113
113
|
variant="secondary"
|
|
114
|
-
|
|
114
|
+
isRound
|
|
115
115
|
onClick={onDownload}
|
|
116
|
-
|
|
116
|
+
>
|
|
117
|
+
<Icon name="download" screenReaderText="Download file" />
|
|
118
|
+
</Button>
|
|
117
119
|
)}
|
|
118
120
|
{onDelete && (
|
|
119
121
|
<Button
|
|
120
122
|
variant="secondary"
|
|
121
|
-
|
|
123
|
+
isRound
|
|
122
124
|
onClick={onDelete}
|
|
123
|
-
|
|
125
|
+
>
|
|
126
|
+
<Icon name="trash" screenReaderText="Delete file" />
|
|
127
|
+
</Button>
|
|
124
128
|
)}
|
|
125
129
|
</span>
|
|
126
130
|
{typeof progressPercentage === 'number' && progressPercentage < 100
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { Dropdown } from 'Components/dropdown/Dropdown';
|
|
2
2
|
import { Button } from 'Components/button/Button';
|
|
3
|
+
import { Icon } from 'Components/icon/Icon';
|
|
3
4
|
import { Sketch } from '@uiw/react-color';
|
|
4
5
|
import type { ColorResult } from '@uiw/color-convert';
|
|
5
6
|
import { useEffect, useState } from 'react';
|
|
@@ -31,7 +32,7 @@ export const ColourPickerDropdown = ({ value = '#3cad51', onChange, hasError, di
|
|
|
31
32
|
<input type="hidden" name={id} value={selectedColour} />
|
|
32
33
|
<Dropdown>
|
|
33
34
|
<Dropdown.Trigger disabled={disabled} className="ds-colour-picker-dropdown__trigger">
|
|
34
|
-
<Button variant="dropdown"
|
|
35
|
+
<Button variant="dropdown" error={hasError} id={id} aria-describedby={ariaDescribedBy} aria-invalid={ariaInvalid}>
|
|
35
36
|
<span className="sr-only">
|
|
36
37
|
Toggle colour picker.
|
|
37
38
|
</span>
|
|
@@ -42,6 +43,7 @@ export const ColourPickerDropdown = ({ value = '#3cad51', onChange, hasError, di
|
|
|
42
43
|
{selectedColour}
|
|
43
44
|
</span>
|
|
44
45
|
</div>
|
|
46
|
+
<Icon name="chevron-down" />
|
|
45
47
|
</Button>
|
|
46
48
|
</Dropdown.Trigger>
|
|
47
49
|
<Dropdown.Content className="ds-colour-picker-dropdown__content">
|
|
@@ -4,6 +4,7 @@ import classNames from 'classnames';
|
|
|
4
4
|
import { SelectDropdownItem, type SelectDropdownItemProps } from './items/item/SelectDropdownItem.js';
|
|
5
5
|
import { Dropdown } from 'Components/dropdown/Dropdown';
|
|
6
6
|
import { Button } from 'Components/button/Button';
|
|
7
|
+
import { Icon } from 'Components/icon/Icon';
|
|
7
8
|
|
|
8
9
|
export type SelectDropdownInputProps = {
|
|
9
10
|
'placeholder'?: string;
|
|
@@ -115,13 +116,13 @@ export const SelectDropdown = (props: SelectDropdownInputProps) => {
|
|
|
115
116
|
<Button
|
|
116
117
|
variant="dropdown"
|
|
117
118
|
error={hasError}
|
|
118
|
-
iconRightName="chevron-down"
|
|
119
119
|
id={id}
|
|
120
120
|
aria-describedby={ariaDescribedBy}
|
|
121
121
|
aria-invalid={ariaInvalid}
|
|
122
122
|
className={classNames({ 'ds-select-dropdown--icon-click-only': iconClickOnly })}
|
|
123
123
|
>
|
|
124
|
-
{renderedSelectContent}
|
|
124
|
+
<span className="ds-button__content">{renderedSelectContent}</span>
|
|
125
|
+
<Icon name="chevron-down" />
|
|
125
126
|
</Button>
|
|
126
127
|
</Dropdown.Trigger>
|
|
127
128
|
<Dropdown.Content contentProps={{ onCloseAutoFocus }}>
|
|
@@ -13,6 +13,7 @@ import { Grid } from './Grid.js';
|
|
|
13
13
|
import { Avatar } from 'Components/avatar/Avatar';
|
|
14
14
|
import { Badge } from 'Components/badge/Badge';
|
|
15
15
|
import { Button } from 'Components/button/Button';
|
|
16
|
+
import { Icon } from 'Components/icon/Icon';
|
|
16
17
|
import { DataViewCard } from 'Components/dataViewCard/DataViewCard';
|
|
17
18
|
import { Heading } from 'Components/heading/Heading';
|
|
18
19
|
import { KPICard } from 'Components/kpiCard/KPICard';
|
|
@@ -803,8 +804,14 @@ export const StudentProfilePage: Story = withDescription(
|
|
|
803
804
|
</div>
|
|
804
805
|
</div>
|
|
805
806
|
<div style={actionRowStyle}>
|
|
806
|
-
<Button variant="secondary" size="S"
|
|
807
|
-
|
|
807
|
+
<Button variant="secondary" size="S">
|
|
808
|
+
<Icon name="pencil" />
|
|
809
|
+
Edit
|
|
810
|
+
</Button>
|
|
811
|
+
<Button variant="secondary" size="S">
|
|
812
|
+
<Icon name="file" />
|
|
813
|
+
Print
|
|
814
|
+
</Button>
|
|
808
815
|
<Button variant="primary" size="S">Contact Home</Button>
|
|
809
816
|
</div>
|
|
810
817
|
</div>
|
|
@@ -911,7 +918,10 @@ export const AttendanceDashboard: Story = withDescription(
|
|
|
911
918
|
</div>
|
|
912
919
|
</div>
|
|
913
920
|
<div style={actionRowStyle}>
|
|
914
|
-
<Button variant="secondary" size="S"
|
|
921
|
+
<Button variant="secondary" size="S">
|
|
922
|
+
<Icon name="download" />
|
|
923
|
+
Export
|
|
924
|
+
</Button>
|
|
915
925
|
<Button variant="primary" size="S">Generate Report</Button>
|
|
916
926
|
</div>
|
|
917
927
|
</div>
|
|
@@ -1024,7 +1034,10 @@ export const StaffDirectory: Story = withDescription(
|
|
|
1024
1034
|
<Heading level={1}>Staff Directory</Heading>
|
|
1025
1035
|
<Badge colour="blue">24 staff</Badge>
|
|
1026
1036
|
</div>
|
|
1027
|
-
<Button variant="primary" size="S"
|
|
1037
|
+
<Button variant="primary" size="S">
|
|
1038
|
+
<Icon name="plus" />
|
|
1039
|
+
Add Staff Member
|
|
1040
|
+
</Button>
|
|
1028
1041
|
</div>
|
|
1029
1042
|
</Grid.Column>
|
|
1030
1043
|
</Grid.Row>
|
|
@@ -10,6 +10,7 @@ import {
|
|
|
10
10
|
} from '@storybook/addon-docs/blocks';
|
|
11
11
|
import { Heading } from './Heading.js';
|
|
12
12
|
import { Button } from 'Components/button/Button';
|
|
13
|
+
import { Icon } from 'Components/icon/Icon';
|
|
13
14
|
import { EditableText } from 'Components/editableText/EditableText';
|
|
14
15
|
import { TooltipWrapper } from 'Components/tooltip/TooltipWrapper';
|
|
15
16
|
|
|
@@ -141,7 +142,7 @@ const DEVELOPER_NOTES = [
|
|
|
141
142
|
'- **Keyboard order** — the DOM order is left container then right container, matching reading order and Tab sequence',
|
|
142
143
|
'- **Icon-only buttons in the heading** require a `TooltipWrapper` with an accessible label. A tooltip',
|
|
143
144
|
' on hover alone is not sufficient — it must also appear on keyboard focus, and assistive technology',
|
|
144
|
-
' must be able to read the label. Always pair `
|
|
145
|
+
' must be able to read the label. Always pair a `screenReaderText` on the child `Icon` with `TooltipWrapper`.',
|
|
145
146
|
'- **`id` + `aria-labelledby`** — give the heading an `id` and reference it from an adjacent',
|
|
146
147
|
' `<section aria-labelledby="...">` to associate the landmark with its heading. Screen readers',
|
|
147
148
|
' announce the section name when the user enters the landmark region.',
|
|
@@ -339,9 +340,10 @@ const WithIconOnlyActionTemplate = () => (
|
|
|
339
340
|
<Button
|
|
340
341
|
variant="secondary"
|
|
341
342
|
type="button"
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
343
|
+
isRound
|
|
344
|
+
>
|
|
345
|
+
<Icon name="download" screenReaderText="Download student records" />
|
|
346
|
+
</Button>
|
|
345
347
|
</TooltipWrapper>
|
|
346
348
|
</Heading.InnerContainer>
|
|
347
349
|
</Heading>
|
|
@@ -352,7 +354,8 @@ const WithBackControlLegacyTemplate = () => (
|
|
|
352
354
|
<div style={{ padding: 'var(--spacing-xlarge)' }}>
|
|
353
355
|
<Heading level={1}>
|
|
354
356
|
<Heading.InnerContainer className="medium-spacing-gap">
|
|
355
|
-
<Button variant="tertiary" type="button"
|
|
357
|
+
<Button variant="tertiary" type="button">
|
|
358
|
+
<Icon name="chevron-left" />
|
|
356
359
|
Back
|
|
357
360
|
</Button>
|
|
358
361
|
Attendance register
|
|
@@ -396,7 +399,8 @@ const WithEditableTitleAndMultipleActionsTemplate = () => (
|
|
|
396
399
|
<div style={{ padding: 'var(--spacing-xlarge)' }}>
|
|
397
400
|
<Heading level={1}>
|
|
398
401
|
<Heading.InnerContainer className="medium-spacing-gap">
|
|
399
|
-
<Button variant="tertiary" type="button"
|
|
402
|
+
<Button variant="tertiary" type="button">
|
|
403
|
+
<Icon name="chevron-left" />
|
|
400
404
|
Back
|
|
401
405
|
</Button>
|
|
402
406
|
<EditableText
|
|
@@ -578,7 +582,7 @@ export const WithIconOnlyAction: Story = withDescription(
|
|
|
578
582
|
source: {
|
|
579
583
|
language: 'tsx',
|
|
580
584
|
code: `
|
|
581
|
-
import { Heading, Button, TooltipWrapper } from '@arbor-education/design-system.components';
|
|
585
|
+
import { Heading, Button, Icon, TooltipWrapper } from '@arbor-education/design-system.components';
|
|
582
586
|
|
|
583
587
|
<div style={{ padding: 'var(--spacing-xlarge)' }}>
|
|
584
588
|
<Heading level={1}>
|
|
@@ -588,9 +592,10 @@ import { Heading, Button, TooltipWrapper } from '@arbor-education/design-system.
|
|
|
588
592
|
<Button
|
|
589
593
|
variant="secondary"
|
|
590
594
|
type="button"
|
|
591
|
-
|
|
592
|
-
|
|
593
|
-
|
|
595
|
+
isRound
|
|
596
|
+
>
|
|
597
|
+
<Icon name="download" screenReaderText="Download student records" />
|
|
598
|
+
</Button>
|
|
594
599
|
</TooltipWrapper>
|
|
595
600
|
</Heading.InnerContainer>
|
|
596
601
|
</Heading>
|
|
@@ -604,8 +609,8 @@ import { Heading, Button, TooltipWrapper } from '@arbor-education/design-system.
|
|
|
604
609
|
'Title left, an icon-only action button right. **Icon-only buttons in a heading require a `TooltipWrapper`**',
|
|
605
610
|
'— hover tooltips alone are not sufficient. The tooltip must appear on keyboard focus too, and assistive',
|
|
606
611
|
'technology must be able to read the label. Always pair `TooltipWrapper` with a descriptive',
|
|
607
|
-
'`
|
|
608
|
-
'for sighted keyboard users and `
|
|
612
|
+
'`screenReaderText` on the child `Icon`. This story uses both: `tooltipContent="Download student records"`',
|
|
613
|
+
'for sighted keyboard users and `screenReaderText="Download student records"` for screen reader users.',
|
|
609
614
|
].join(' '),
|
|
610
615
|
);
|
|
611
616
|
|
|
@@ -617,12 +622,13 @@ export const WithBackControlLegacy: Story = withDescription(
|
|
|
617
622
|
source: {
|
|
618
623
|
language: 'tsx',
|
|
619
624
|
code: `
|
|
620
|
-
import { Heading, Button } from '@arbor-education/design-system.components';
|
|
625
|
+
import { Heading, Button, Icon } from '@arbor-education/design-system.components';
|
|
621
626
|
|
|
622
627
|
<div style={{ padding: 'var(--spacing-xlarge)' }}>
|
|
623
628
|
<Heading level={1}>
|
|
624
629
|
<Heading.InnerContainer className="medium-spacing-gap">
|
|
625
|
-
<Button variant="tertiary" type="button"
|
|
630
|
+
<Button variant="tertiary" type="button">
|
|
631
|
+
<Icon name="chevron-left" />
|
|
626
632
|
Back
|
|
627
633
|
</Button>
|
|
628
634
|
Attendance register
|
|
@@ -709,12 +715,13 @@ export const WithEditableTitleAndMultipleActions: Story = withDescription(
|
|
|
709
715
|
source: {
|
|
710
716
|
language: 'tsx',
|
|
711
717
|
code: `
|
|
712
|
-
import { Heading, Button, EditableText } from '@arbor-education/design-system.components';
|
|
718
|
+
import { Heading, Button, Icon, EditableText } from '@arbor-education/design-system.components';
|
|
713
719
|
|
|
714
720
|
<div style={{ padding: 'var(--spacing-xlarge)' }}>
|
|
715
721
|
<Heading level={1}>
|
|
716
722
|
<Heading.InnerContainer className="medium-spacing-gap">
|
|
717
|
-
<Button variant="tertiary" type="button"
|
|
723
|
+
<Button variant="tertiary" type="button">
|
|
724
|
+
<Icon name="chevron-left" />
|
|
718
725
|
Back
|
|
719
726
|
</Button>
|
|
720
727
|
<EditableText text="Autumn term report" onEditSave={() => {}} />
|