@arbor-education/design-system.components 0.11.1 → 0.13.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/CHANGELOG.md +14 -0
- package/dist/components/avatar/Avatar.d.ts +4 -0
- package/dist/components/avatar/Avatar.d.ts.map +1 -1
- package/dist/components/avatarGroup/AvatarGroup.d.ts +6 -0
- package/dist/components/avatarGroup/AvatarGroup.d.ts.map +1 -1
- package/dist/components/badge/Badge.d.ts +5 -0
- package/dist/components/badge/Badge.d.ts.map +1 -1
- package/dist/components/banner/Banner.d.ts +7 -1
- package/dist/components/banner/Banner.d.ts.map +1 -1
- package/dist/components/banner/Banner.js +4 -1
- package/dist/components/banner/Banner.js.map +1 -1
- package/dist/components/button/Button.d.ts +5 -0
- package/dist/components/button/Button.d.ts.map +1 -1
- package/dist/components/card/Card.d.ts +3 -0
- package/dist/components/card/Card.d.ts.map +1 -1
- package/dist/components/combobox/Combobox.d.ts +9 -1
- package/dist/components/combobox/Combobox.d.ts.map +1 -1
- package/dist/components/datePicker/DatePicker.d.ts +4 -0
- package/dist/components/datePicker/DatePicker.d.ts.map +1 -1
- package/dist/components/datePicker/DatePicker.js +2 -2
- package/dist/components/datePicker/DatePicker.js.map +1 -1
- package/dist/components/datePicker/DatePicker.stories.d.ts +1 -0
- package/dist/components/datePicker/DatePicker.stories.d.ts.map +1 -1
- package/dist/components/dateTimePicker/DateTimePicker.d.ts +4 -1
- package/dist/components/dateTimePicker/DateTimePicker.d.ts.map +1 -1
- package/dist/components/dateTimePicker/DateTimePicker.stories.d.ts +3 -3
- package/dist/components/dot/Dot.d.ts +4 -0
- package/dist/components/dot/Dot.d.ts.map +1 -1
- package/dist/components/dropdown/Dropdown.d.ts +15 -10
- package/dist/components/dropdown/Dropdown.d.ts.map +1 -1
- package/dist/components/dropdown/Dropdown.js.map +1 -1
- package/dist/components/dropdown/DropdownContent.d.ts +1 -2
- package/dist/components/dropdown/DropdownContent.d.ts.map +1 -1
- package/dist/components/dropdown/DropdownTrigger.d.ts +3 -2
- package/dist/components/dropdown/DropdownTrigger.d.ts.map +1 -1
- package/dist/components/dropdown/DropdownTrigger.js.map +1 -1
- package/dist/components/formField/FormField.d.ts +4 -2
- package/dist/components/formField/FormField.d.ts.map +1 -1
- package/dist/components/formField/fieldset/Fieldset.d.ts +3 -0
- package/dist/components/formField/fieldset/Fieldset.d.ts.map +1 -1
- package/dist/components/formField/inputs/checkbox/CheckboxGroup.d.ts +4 -2
- package/dist/components/formField/inputs/checkbox/CheckboxGroup.d.ts.map +1 -1
- package/dist/components/formField/inputs/checkbox/CheckboxInput.d.ts +3 -0
- package/dist/components/formField/inputs/checkbox/CheckboxInput.d.ts.map +1 -1
- package/dist/components/formField/inputs/colourPickerDropdown/ColourPickerDropdown.d.ts +3 -0
- package/dist/components/formField/inputs/colourPickerDropdown/ColourPickerDropdown.d.ts.map +1 -1
- package/dist/components/formField/inputs/number/NumberInput.d.ts +3 -0
- package/dist/components/formField/inputs/number/NumberInput.d.ts.map +1 -1
- package/dist/components/formField/inputs/radio/RadioButtonGroup.d.ts +3 -0
- package/dist/components/formField/inputs/radio/RadioButtonGroup.d.ts.map +1 -1
- package/dist/components/formField/inputs/radio/RadioButtonInput.d.ts +3 -0
- package/dist/components/formField/inputs/radio/RadioButtonInput.d.ts.map +1 -1
- package/dist/components/formField/inputs/selectDropdown/SelectDropdown.d.ts +3 -0
- package/dist/components/formField/inputs/selectDropdown/SelectDropdown.d.ts.map +1 -1
- package/dist/components/formField/inputs/text/TextInput.d.ts +3 -0
- package/dist/components/formField/inputs/text/TextInput.d.ts.map +1 -1
- package/dist/components/formField/inputs/textArea/TextArea.d.ts +3 -0
- package/dist/components/formField/inputs/textArea/TextArea.d.ts.map +1 -1
- package/dist/components/formField/inputs/time/TimeInput.d.ts +5 -0
- package/dist/components/formField/inputs/time/TimeInput.d.ts.map +1 -1
- package/dist/components/formField/inputs/time/TimeInput.stories.d.ts +1 -1
- package/dist/components/heading/Heading.d.ts +5 -0
- package/dist/components/heading/Heading.d.ts.map +1 -1
- package/dist/components/icon/Icon.d.ts +7 -1
- package/dist/components/icon/Icon.d.ts.map +1 -1
- package/dist/components/modal/Modal.d.ts +16 -4
- package/dist/components/modal/Modal.d.ts.map +1 -1
- package/dist/components/modal/Modal.js.map +1 -1
- package/dist/components/progress/Progress.d.ts +3 -0
- package/dist/components/progress/Progress.d.ts.map +1 -1
- package/dist/components/row/Row.d.ts +3 -0
- package/dist/components/row/Row.d.ts.map +1 -1
- package/dist/components/singleUser/SingleUser.d.ts +3 -0
- package/dist/components/singleUser/SingleUser.d.ts.map +1 -1
- package/dist/components/slideover/Slideover.d.ts +3 -0
- package/dist/components/slideover/Slideover.d.ts.map +1 -1
- package/dist/components/table/Table.d.ts +21 -4
- package/dist/components/table/Table.d.ts.map +1 -1
- package/dist/components/table/Table.js +10 -1
- package/dist/components/table/Table.js.map +1 -1
- package/dist/components/table/Table.stories.d.ts +1 -0
- package/dist/components/table/Table.stories.d.ts.map +1 -1
- package/dist/components/table/Table.stories.js +87 -0
- package/dist/components/table/Table.stories.js.map +1 -1
- package/dist/components/table/Table.test.js +55 -7
- package/dist/components/table/Table.test.js.map +1 -1
- package/dist/components/table/cellEditors/DateCellEditor.d.ts +3 -0
- package/dist/components/table/cellEditors/DateCellEditor.d.ts.map +1 -0
- package/dist/components/table/cellEditors/DateCellEditor.js +13 -0
- package/dist/components/table/cellEditors/DateCellEditor.js.map +1 -0
- package/dist/components/table/cellEditors/DateCellEditor.test.d.ts +2 -0
- package/dist/components/table/cellEditors/DateCellEditor.test.d.ts.map +1 -0
- package/dist/components/table/cellEditors/DateCellEditor.test.js +81 -0
- package/dist/components/table/cellEditors/DateCellEditor.test.js.map +1 -0
- package/dist/components/tag/Tag.d.ts +4 -0
- package/dist/components/tag/Tag.d.ts.map +1 -1
- package/dist/components/toast/Toast.d.ts +5 -0
- package/dist/components/toast/Toast.d.ts.map +1 -1
- package/dist/components/tooltip/Tooltip.d.ts +7 -1
- package/dist/components/tooltip/Tooltip.d.ts.map +1 -1
- package/dist/components/tooltip/Tooltip.js.map +1 -1
- package/dist/components/tooltip/TooltipWrapper.d.ts +3 -0
- package/dist/components/tooltip/TooltipWrapper.d.ts.map +1 -1
- package/dist/components/userDropdown/UserDropdown.d.ts +7 -0
- package/dist/components/userDropdown/UserDropdown.d.ts.map +1 -1
- package/dist/index.d.ts +19 -26
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +17 -17
- package/dist/index.js.map +1 -1
- package/eslint.config.mts +1 -0
- package/package.json +1 -1
- package/src/components/avatar/Avatar.tsx +5 -0
- package/src/components/avatarGroup/AvatarGroup.tsx +7 -0
- package/src/components/badge/Badge.tsx +6 -0
- package/src/components/banner/Banner.tsx +10 -1
- package/src/components/button/Button.tsx +6 -0
- package/src/components/card/Card.tsx +4 -0
- package/src/components/combobox/Combobox.tsx +10 -1
- package/src/components/datePicker/DatePicker.tsx +7 -0
- package/src/components/dateTimePicker/DateTimePicker.tsx +4 -1
- package/src/components/dot/Dot.tsx +5 -0
- package/src/components/dropdown/Dropdown.tsx +13 -3
- package/src/components/dropdown/DropdownContent.tsx +1 -1
- package/src/components/dropdown/DropdownTrigger.tsx +3 -1
- package/src/components/formField/FormField.tsx +5 -1
- package/src/components/formField/fieldset/Fieldset.tsx +4 -0
- package/src/components/formField/inputs/checkbox/CheckboxGroup.tsx +5 -1
- package/src/components/formField/inputs/checkbox/CheckboxInput.tsx +4 -0
- package/src/components/formField/inputs/colourPickerDropdown/ColourPickerDropdown.tsx +4 -0
- package/src/components/formField/inputs/number/NumberInput.tsx +4 -0
- package/src/components/formField/inputs/radio/RadioButtonGroup.tsx +4 -0
- package/src/components/formField/inputs/radio/RadioButtonInput.tsx +4 -0
- package/src/components/formField/inputs/selectDropdown/SelectDropdown.tsx +4 -0
- package/src/components/formField/inputs/text/TextInput.tsx +4 -0
- package/src/components/formField/inputs/textArea/TextArea.tsx +4 -0
- package/src/components/formField/inputs/time/TimeInput.tsx +6 -0
- package/src/components/heading/Heading.tsx +6 -0
- package/src/components/icon/Icon.tsx +8 -1
- package/src/components/modal/Modal.tsx +13 -3
- package/src/components/progress/Progress.tsx +4 -0
- package/src/components/row/Row.tsx +4 -0
- package/src/components/singleUser/SingleUser.tsx +4 -0
- package/src/components/slideover/Slideover.tsx +4 -0
- package/src/components/table/Table.stories.tsx +102 -0
- package/src/components/table/Table.test.tsx +88 -9
- package/src/components/table/Table.tsx +22 -2
- package/src/components/table/cellEditors/DateCellEditor.test.tsx +109 -0
- package/src/components/table/cellEditors/DateCellEditor.tsx +27 -0
- package/src/components/tag/Tag.tsx +5 -0
- package/src/components/toast/Toast.tsx +6 -0
- package/src/components/tooltip/Tooltip.tsx +7 -1
- package/src/components/tooltip/TooltipWrapper.tsx +4 -0
- package/src/components/userDropdown/UserDropdown.tsx +8 -0
- package/src/index.ts +19 -39
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { Fieldset, type FieldsetProps } from 'Components/formField/fieldset/Fieldset';
|
|
2
2
|
import { CheckboxInput, type CheckboxInputProps } from './CheckboxInput';
|
|
3
3
|
|
|
4
|
-
type CheckboxGroupProps = {
|
|
4
|
+
export type CheckboxGroupProps = {
|
|
5
5
|
options: CheckboxInputProps[];
|
|
6
6
|
} & FieldsetProps;
|
|
7
7
|
|
|
@@ -15,3 +15,7 @@ export const CheckboxGroup = (props: CheckboxGroupProps) => {
|
|
|
15
15
|
</Fieldset>
|
|
16
16
|
);
|
|
17
17
|
};
|
|
18
|
+
|
|
19
|
+
export namespace CheckboxGroup {
|
|
20
|
+
export type Props = CheckboxGroupProps;
|
|
21
|
+
}
|
|
@@ -166,3 +166,9 @@ export const TimeInput = forwardRef<HTMLInputElement, TimeInputProps>((props, re
|
|
|
166
166
|
});
|
|
167
167
|
|
|
168
168
|
TimeInput.displayName = 'TimeInput';
|
|
169
|
+
|
|
170
|
+
export namespace TimeInput {
|
|
171
|
+
export type Props = TimeInputProps;
|
|
172
|
+
export type Value = TimeValue;
|
|
173
|
+
export type Granularity = TimeGranularity;
|
|
174
|
+
}
|
|
@@ -36,3 +36,9 @@ export const Heading = (props: HeadingProps) => {
|
|
|
36
36
|
};
|
|
37
37
|
|
|
38
38
|
Heading.InnerContainer = HeadingInnerContainer;
|
|
39
|
+
|
|
40
|
+
export namespace Heading {
|
|
41
|
+
export type Props = HeadingProps;
|
|
42
|
+
export type Level = HeadingLevel;
|
|
43
|
+
export type InnerContainerProps = HeadingSubContainerProps;
|
|
44
|
+
}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { IconSize } from './types';
|
|
1
|
+
import type { CustomIconProps, IconSize } from './types';
|
|
2
2
|
import { allowedIcons, type IconName } from './allowedIcons';
|
|
3
3
|
import classNames from 'classnames';
|
|
4
4
|
|
|
@@ -24,3 +24,10 @@ export const Icon = (props: IconProps) => {
|
|
|
24
24
|
</>
|
|
25
25
|
);
|
|
26
26
|
};
|
|
27
|
+
|
|
28
|
+
export namespace Icon {
|
|
29
|
+
export type Props = IconProps;
|
|
30
|
+
export type Name = IconName;
|
|
31
|
+
export type Size = IconSize;
|
|
32
|
+
export type CustomProps = CustomIconProps;
|
|
33
|
+
}
|
|
@@ -1,12 +1,13 @@
|
|
|
1
1
|
import classNames from 'classnames';
|
|
2
2
|
import { Dialog } from 'radix-ui';
|
|
3
|
-
import { ModalHeader } from './ModalHeader';
|
|
4
|
-
import { ModalFooter } from './ModalFooter';
|
|
5
|
-
import { ModalBody } from './ModalBody';
|
|
3
|
+
import { ModalHeader, type ModalHeaderProps } from './ModalHeader';
|
|
4
|
+
import { ModalFooter, type ModalFooterProps } from './ModalFooter';
|
|
5
|
+
import { ModalBody, type ModalBodyProps } from './ModalBody';
|
|
6
6
|
import { PopupParentContext } from 'Utils/PopupParentContext';
|
|
7
7
|
import { createContext, useRef } from 'react';
|
|
8
8
|
import { ModalCloseButon } from './ModalCloseButton';
|
|
9
9
|
import { ModalTitle } from './ModalTitle';
|
|
10
|
+
import type { ButtonProps } from 'Components/button/Button';
|
|
10
11
|
|
|
11
12
|
type ModalContextValue = {
|
|
12
13
|
closeHandler?: () => void;
|
|
@@ -63,3 +64,12 @@ Modal.Body = ModalBody;
|
|
|
63
64
|
Modal.Footer = ModalFooter;
|
|
64
65
|
Modal.CloseButton = ModalCloseButon;
|
|
65
66
|
Modal.Title = ModalTitle;
|
|
67
|
+
|
|
68
|
+
export namespace Modal {
|
|
69
|
+
export type Props = ModalProps;
|
|
70
|
+
export type HeaderProps = ModalHeaderProps;
|
|
71
|
+
export type BodyProps = ModalBodyProps;
|
|
72
|
+
export type FooterProps = ModalFooterProps;
|
|
73
|
+
export type CloseButtonProps = ButtonProps;
|
|
74
|
+
export type TitleProps = Dialog.DialogTitleProps;
|
|
75
|
+
}
|
|
@@ -1432,6 +1432,108 @@ export const TableWithSemanticColors: Story = {
|
|
|
1432
1432
|
},
|
|
1433
1433
|
};
|
|
1434
1434
|
|
|
1435
|
+
interface DateEditorRowData {
|
|
1436
|
+
id: number;
|
|
1437
|
+
name: { value: string };
|
|
1438
|
+
dateOfBirth: Date;
|
|
1439
|
+
enrollmentDate: Date;
|
|
1440
|
+
graduationDate: Date | null;
|
|
1441
|
+
}
|
|
1442
|
+
|
|
1443
|
+
const dateEditorSampleData: DateEditorRowData[] = [
|
|
1444
|
+
{
|
|
1445
|
+
id: 1,
|
|
1446
|
+
name: { value: 'Alice Johnson' },
|
|
1447
|
+
dateOfBirth: new Date(2008, 4, 15),
|
|
1448
|
+
enrollmentDate: new Date(2022, 8, 1),
|
|
1449
|
+
graduationDate: new Date(2026, 6, 20),
|
|
1450
|
+
},
|
|
1451
|
+
{
|
|
1452
|
+
id: 2,
|
|
1453
|
+
name: { value: 'Bob Smith' },
|
|
1454
|
+
dateOfBirth: new Date(2009, 1, 28),
|
|
1455
|
+
enrollmentDate: new Date(2023, 8, 1),
|
|
1456
|
+
graduationDate: null,
|
|
1457
|
+
},
|
|
1458
|
+
{
|
|
1459
|
+
id: 3,
|
|
1460
|
+
name: { value: 'Charlie Brown' },
|
|
1461
|
+
dateOfBirth: new Date(2007, 10, 3),
|
|
1462
|
+
enrollmentDate: new Date(2021, 8, 1),
|
|
1463
|
+
graduationDate: new Date(2025, 6, 18),
|
|
1464
|
+
},
|
|
1465
|
+
{
|
|
1466
|
+
id: 4,
|
|
1467
|
+
name: { value: 'Diana Prince' },
|
|
1468
|
+
dateOfBirth: new Date(2008, 7, 22),
|
|
1469
|
+
enrollmentDate: new Date(2022, 8, 1),
|
|
1470
|
+
graduationDate: new Date(2026, 6, 20),
|
|
1471
|
+
},
|
|
1472
|
+
{
|
|
1473
|
+
id: 5,
|
|
1474
|
+
name: { value: 'Ethan Hunt' },
|
|
1475
|
+
dateOfBirth: new Date(2009, 11, 10),
|
|
1476
|
+
enrollmentDate: new Date(2023, 8, 1),
|
|
1477
|
+
graduationDate: null,
|
|
1478
|
+
},
|
|
1479
|
+
];
|
|
1480
|
+
|
|
1481
|
+
const dateEditorColDefs: (ColDef | ColGroupDef)[] = [
|
|
1482
|
+
{
|
|
1483
|
+
field: 'name',
|
|
1484
|
+
headerName: 'Student Name',
|
|
1485
|
+
editable: false,
|
|
1486
|
+
valueFormatter: Table.DefaultValueFormatter,
|
|
1487
|
+
},
|
|
1488
|
+
{
|
|
1489
|
+
field: 'dateOfBirth',
|
|
1490
|
+
headerName: 'Date of Birth',
|
|
1491
|
+
cellEditor: 'dsDateCellEditor',
|
|
1492
|
+
valueFormatter: params =>
|
|
1493
|
+
params.value instanceof Date
|
|
1494
|
+
? params.value.toLocaleDateString('en-GB')
|
|
1495
|
+
: params.value ?? '',
|
|
1496
|
+
},
|
|
1497
|
+
{
|
|
1498
|
+
field: 'enrollmentDate',
|
|
1499
|
+
headerName: 'Enrollment Date',
|
|
1500
|
+
cellEditor: 'dsDateCellEditor',
|
|
1501
|
+
valueFormatter: params =>
|
|
1502
|
+
params.value instanceof Date
|
|
1503
|
+
? params.value.toLocaleDateString('en-GB')
|
|
1504
|
+
: params.value ?? '',
|
|
1505
|
+
},
|
|
1506
|
+
{
|
|
1507
|
+
field: 'graduationDate',
|
|
1508
|
+
headerName: 'Graduation Date',
|
|
1509
|
+
cellEditor: 'dsDateCellEditor',
|
|
1510
|
+
valueFormatter: params =>
|
|
1511
|
+
params.value instanceof Date
|
|
1512
|
+
? params.value.toLocaleDateString('en-GB')
|
|
1513
|
+
: params.value ?? '',
|
|
1514
|
+
},
|
|
1515
|
+
];
|
|
1516
|
+
|
|
1517
|
+
export const WithDateCellEditor: Story = {
|
|
1518
|
+
parameters: {
|
|
1519
|
+
docs: {
|
|
1520
|
+
description: {
|
|
1521
|
+
story:
|
|
1522
|
+
'Date columns can use the `dsDateCellEditor` cell editor to provide an inline date picker. Double-click or press Enter on a date cell to open the editor.',
|
|
1523
|
+
},
|
|
1524
|
+
},
|
|
1525
|
+
},
|
|
1526
|
+
args: {
|
|
1527
|
+
rowData: dateEditorSampleData,
|
|
1528
|
+
columnDefs: dateEditorColDefs,
|
|
1529
|
+
defaultColDef: {
|
|
1530
|
+
...defaultColDef,
|
|
1531
|
+
editable: true,
|
|
1532
|
+
},
|
|
1533
|
+
domLayout: 'autoHeight',
|
|
1534
|
+
},
|
|
1535
|
+
};
|
|
1536
|
+
|
|
1435
1537
|
interface BooleanRowData {
|
|
1436
1538
|
id: number;
|
|
1437
1539
|
name: string;
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { describe, expect, expectTypeOf, test, vi } from 'vitest';
|
|
2
|
-
import { render, screen, waitFor } from '@testing-library/react';
|
|
3
|
-
import { Table
|
|
2
|
+
import { render, screen, waitFor, fireEvent } from '@testing-library/react';
|
|
3
|
+
import { Table } from './Table';
|
|
4
4
|
import '@testing-library/jest-dom/vitest';
|
|
5
5
|
import { BulkActionsDropdown } from 'Components/table/tableControls/BulkActionsDropdown';
|
|
6
6
|
import { HideColumnsDropdown } from 'Components/table/tableControls/HideColumnsDropdown';
|
|
@@ -753,7 +753,7 @@ describe('Table', () => {
|
|
|
753
753
|
actions={[
|
|
754
754
|
{
|
|
755
755
|
displayName: 'Test Action',
|
|
756
|
-
callback: () => {},
|
|
756
|
+
callback: () => { },
|
|
757
757
|
},
|
|
758
758
|
]}
|
|
759
759
|
/>
|
|
@@ -817,7 +817,7 @@ describe('Table', () => {
|
|
|
817
817
|
expect((largeRadio as HTMLInputElement).checked).toBe(true);
|
|
818
818
|
});
|
|
819
819
|
expect(onTableSettingsChanged).toHaveBeenCalledExactlyOnceWith(expect.objectContaining({
|
|
820
|
-
tableSpacing:
|
|
820
|
+
tableSpacing: Table.Spacing.L,
|
|
821
821
|
}));
|
|
822
822
|
|
|
823
823
|
const columnBordersCheckbox = screen.getByLabelText('Column borders');
|
|
@@ -896,7 +896,7 @@ describe('Table', () => {
|
|
|
896
896
|
await userEvent.click(largeRadio);
|
|
897
897
|
|
|
898
898
|
await waitFor(() => {
|
|
899
|
-
expect(onTableSpacingChanged).toHaveBeenCalledExactlyOnceWith(
|
|
899
|
+
expect(onTableSpacingChanged).toHaveBeenCalledExactlyOnceWith(Table.Spacing.L);
|
|
900
900
|
});
|
|
901
901
|
|
|
902
902
|
const xsmallRadio = screen.getByLabelText('X-Small');
|
|
@@ -904,7 +904,7 @@ describe('Table', () => {
|
|
|
904
904
|
|
|
905
905
|
await waitFor(() => {
|
|
906
906
|
expect(onTableSpacingChanged).toHaveBeenCalledTimes(2);
|
|
907
|
-
expect(onTableSpacingChanged).toHaveBeenNthCalledWith(2,
|
|
907
|
+
expect(onTableSpacingChanged).toHaveBeenNthCalledWith(2, Table.Spacing.XS);
|
|
908
908
|
});
|
|
909
909
|
});
|
|
910
910
|
|
|
@@ -924,14 +924,14 @@ describe('Table', () => {
|
|
|
924
924
|
await userEvent.click(largeRadio);
|
|
925
925
|
|
|
926
926
|
await waitFor(() => {
|
|
927
|
-
expect(onTableSpacingChanged).toHaveBeenCalledWith(
|
|
927
|
+
expect(onTableSpacingChanged).toHaveBeenCalledWith(Table.Spacing.L);
|
|
928
928
|
});
|
|
929
929
|
|
|
930
930
|
const resetButton = screen.getByRole('button', { name: /Reset Table Settings/i });
|
|
931
931
|
await userEvent.click(resetButton);
|
|
932
932
|
|
|
933
933
|
await waitFor(() => {
|
|
934
|
-
expect(onTableSpacingChanged).toHaveBeenCalledWith(
|
|
934
|
+
expect(onTableSpacingChanged).toHaveBeenCalledWith(Table.Spacing.M);
|
|
935
935
|
});
|
|
936
936
|
});
|
|
937
937
|
|
|
@@ -1049,7 +1049,7 @@ describe('Table', () => {
|
|
|
1049
1049
|
];
|
|
1050
1050
|
|
|
1051
1051
|
const rowData = [
|
|
1052
|
-
{
|
|
1052
|
+
{},
|
|
1053
1053
|
];
|
|
1054
1054
|
await expect(async () => {
|
|
1055
1055
|
render(
|
|
@@ -1487,6 +1487,85 @@ describe('Table', () => {
|
|
|
1487
1487
|
});
|
|
1488
1488
|
});
|
|
1489
1489
|
|
|
1490
|
+
describe('DateCellEditor', () => {
|
|
1491
|
+
const columnDefs = [{
|
|
1492
|
+
field: 'dateOfBirth',
|
|
1493
|
+
headerName: 'Date of Birth',
|
|
1494
|
+
editable: true,
|
|
1495
|
+
cellEditor: 'dsDateCellEditor',
|
|
1496
|
+
}];
|
|
1497
|
+
|
|
1498
|
+
test('opens the date picker editor via grid API', async () => {
|
|
1499
|
+
let gridApi: GridApi;
|
|
1500
|
+
const rowData = [{ dateOfBirth: new Date(2024, 5, 15) }];
|
|
1501
|
+
render(
|
|
1502
|
+
<Table
|
|
1503
|
+
columnDefs={columnDefs}
|
|
1504
|
+
rowData={rowData}
|
|
1505
|
+
onGridReady={(event) => { gridApi = event.api; }}
|
|
1506
|
+
/>,
|
|
1507
|
+
);
|
|
1508
|
+
await waitFor(() => expect(screen.getByRole('grid')).toBeInTheDocument());
|
|
1509
|
+
|
|
1510
|
+
gridApi!.startEditingCell({ rowIndex: 0, colKey: 'dateOfBirth' });
|
|
1511
|
+
|
|
1512
|
+
await waitFor(() => expect(screen.getByRole('button', { name: 'Open date picker' })).toBeInTheDocument());
|
|
1513
|
+
});
|
|
1514
|
+
|
|
1515
|
+
test('autofocuses the date input so a user can type a date without clicking', async () => {
|
|
1516
|
+
let gridApi: GridApi;
|
|
1517
|
+
const onCellValueChanged = vi.fn();
|
|
1518
|
+
const rowData = [{ dateOfBirth: new Date(2024, 5, 15) }];
|
|
1519
|
+
const { container } = render(
|
|
1520
|
+
<Table
|
|
1521
|
+
columnDefs={columnDefs}
|
|
1522
|
+
rowData={rowData}
|
|
1523
|
+
onGridReady={(event) => { gridApi = event.api; }}
|
|
1524
|
+
onCellValueChanged={onCellValueChanged}
|
|
1525
|
+
/>,
|
|
1526
|
+
);
|
|
1527
|
+
await waitFor(() => expect(screen.getByRole('grid')).toBeInTheDocument());
|
|
1528
|
+
|
|
1529
|
+
gridApi!.setFocusedCell(0, 'dateOfBirth');
|
|
1530
|
+
await userEvent.keyboard('{Enter}');
|
|
1531
|
+
|
|
1532
|
+
await waitFor(() => expect(container.querySelector('input[type="date"]')).toBeInTheDocument());
|
|
1533
|
+
const input = container.querySelector('input[type="date"]') as HTMLInputElement;
|
|
1534
|
+
expect(input).toHaveFocus();
|
|
1535
|
+
|
|
1536
|
+
fireEvent.change(input, { target: { value: '2024-07-20' } });
|
|
1537
|
+
await userEvent.keyboard('{Enter}');
|
|
1538
|
+
|
|
1539
|
+
await waitFor(() => {
|
|
1540
|
+
expect(onCellValueChanged).toHaveBeenCalled();
|
|
1541
|
+
});
|
|
1542
|
+
const lastDate: Date = onCellValueChanged.mock.lastCall![0].newValue;
|
|
1543
|
+
expect(lastDate.getFullYear()).toBe(2024);
|
|
1544
|
+
expect(lastDate.getMonth()).toBe(6);
|
|
1545
|
+
expect(lastDate.getDate()).toBe(20);
|
|
1546
|
+
});
|
|
1547
|
+
|
|
1548
|
+
test('opens the editor with the current value and closes it cleanly', async () => {
|
|
1549
|
+
let gridApi: GridApi;
|
|
1550
|
+
const rowData = [{ dateOfBirth: new Date(2024, 5, 15) }];
|
|
1551
|
+
const { container } = render(
|
|
1552
|
+
<Table
|
|
1553
|
+
columnDefs={columnDefs}
|
|
1554
|
+
rowData={rowData}
|
|
1555
|
+
onGridReady={(event) => { gridApi = event.api; }}
|
|
1556
|
+
/>,
|
|
1557
|
+
);
|
|
1558
|
+
await waitFor(() => expect(screen.getByRole('grid')).toBeInTheDocument());
|
|
1559
|
+
|
|
1560
|
+
gridApi!.startEditingCell({ rowIndex: 0, colKey: 'dateOfBirth' });
|
|
1561
|
+
await waitFor(() => expect(container.querySelector('input[type="date"]')).toBeInTheDocument());
|
|
1562
|
+
expect(container.querySelector('input[type="date"]')).toHaveValue('2024-06-15');
|
|
1563
|
+
|
|
1564
|
+
gridApi!.stopEditing();
|
|
1565
|
+
await waitFor(() => expect(container.querySelector('input[type="date"]')).not.toBeInTheDocument());
|
|
1566
|
+
});
|
|
1567
|
+
});
|
|
1568
|
+
|
|
1490
1569
|
describe('CheckboxCellRenderer', () => {
|
|
1491
1570
|
test('renders checkboxes in table cells', async () => {
|
|
1492
1571
|
const columnDefs = [
|
|
@@ -23,12 +23,15 @@ import { tidyTheme } from './theme/tidyTheme';
|
|
|
23
23
|
import { focusFirstFocusableElement } from 'Utils/focusFirstFocusableElement';
|
|
24
24
|
import { BooleanFilter } from './columnFilters/BooleanFilter/BooleanFilter';
|
|
25
25
|
import { TimeFilter } from './columnFilters/TimeFilter/TimeFilter';
|
|
26
|
+
import { DateCellEditor } from './cellEditors/DateCellEditor';
|
|
26
27
|
import { TableSettingsDropdown } from './tableControls/TableSettingsDropdown';
|
|
27
|
-
import { TableControls } from './tableControls/TableControls';
|
|
28
|
+
import { TableControls, type TableControlsProps, type BulkAction as BulkActionType } from './tableControls/TableControls';
|
|
29
|
+
import type { HideColumnsDropdownProps } from './tableControls/HideColumnsDropdown';
|
|
28
30
|
import { TABLE_SPACING } from './tableConsts';
|
|
29
31
|
import { TableSettingsContext } from './TableSettingsContext';
|
|
30
32
|
import { BooleanCellRenderer } from './cellRenderers/BooleanCellRenderer';
|
|
31
33
|
import { CheckboxCellRenderer } from './cellRenderers/CheckboxCellRenderer';
|
|
34
|
+
import { DefaultCellRenderer } from './cellRenderers/DefaultCellRenderer';
|
|
32
35
|
|
|
33
36
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
34
37
|
type TableProps<TData = any> = {
|
|
@@ -48,7 +51,6 @@ setAgGridLicenseKey();
|
|
|
48
51
|
|
|
49
52
|
ModuleRegistry.registerModules([AllEnterpriseModule]);
|
|
50
53
|
|
|
51
|
-
export { TABLE_SPACING } from './tableConsts';
|
|
52
54
|
export { TableSettingsContext } from './TableSettingsContext';
|
|
53
55
|
|
|
54
56
|
export const Table = (props: TableProps) => {
|
|
@@ -183,6 +185,7 @@ export const Table = (props: TableProps) => {
|
|
|
183
185
|
dsSelectDropdownCellRenderer: SelectDropdownCellRenderer,
|
|
184
186
|
dsBooleanFilter: BooleanFilter,
|
|
185
187
|
dsTimeFilter: TimeFilter,
|
|
188
|
+
dsDateCellEditor: DateCellEditor,
|
|
186
189
|
dsCheckboxCellRenderer: CheckboxCellRenderer,
|
|
187
190
|
dsBooleanCellRenderer: BooleanCellRenderer,
|
|
188
191
|
...components,
|
|
@@ -208,6 +211,23 @@ Table.RowCountInfo = RowCountInfo;
|
|
|
208
211
|
Table.BulkActionsDropdown = BulkActionsDropdown;
|
|
209
212
|
Table.HideColumnsDropdown = HideColumnsDropdown;
|
|
210
213
|
Table.ButtonCellRenderer = ButtonCellRenderer;
|
|
214
|
+
Table.BooleanCellRenderer = BooleanCellRenderer;
|
|
215
|
+
Table.DefaultCellRenderer = DefaultCellRenderer;
|
|
216
|
+
Table.DateCellEditor = DateCellEditor;
|
|
217
|
+
Table.DefaultColDef = DSDefaultColDef;
|
|
218
|
+
Table.GridApiContext = GridApiContext;
|
|
219
|
+
Table.CheckboxCellRenderer = CheckboxCellRenderer;
|
|
211
220
|
Table.DefaultValueFormatter = defaultValueFormatter;
|
|
212
221
|
Table.TableSettingsDropdown = TableSettingsDropdown;
|
|
213
222
|
Table.TableControls = TableControls;
|
|
223
|
+
|
|
224
|
+
Table.Spacing = TABLE_SPACING;
|
|
225
|
+
|
|
226
|
+
export namespace Table {
|
|
227
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
228
|
+
export type Props<TData = any> = TableProps<TData>;
|
|
229
|
+
export type ControlsProps = TableControlsProps;
|
|
230
|
+
export type BulkAction = BulkActionType;
|
|
231
|
+
export type HideColumnsProps = HideColumnsDropdownProps;
|
|
232
|
+
export type Spacing = TABLE_SPACING;
|
|
233
|
+
}
|
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
import { describe, expect, test, vi } from 'vitest';
|
|
2
|
+
import { render, screen, within, fireEvent } from '@testing-library/react';
|
|
3
|
+
import userEvent from '@testing-library/user-event';
|
|
4
|
+
import '@testing-library/jest-dom/vitest';
|
|
5
|
+
import { DateCellEditor } from './DateCellEditor';
|
|
6
|
+
import type { CustomCellEditorProps } from 'ag-grid-react';
|
|
7
|
+
|
|
8
|
+
const createMockProps = (overrides: Partial<CustomCellEditorProps> = {}): CustomCellEditorProps => ({
|
|
9
|
+
value: undefined,
|
|
10
|
+
initialValue: undefined,
|
|
11
|
+
onValueChange: vi.fn(),
|
|
12
|
+
colDef: { cellEditorParams: {} },
|
|
13
|
+
...overrides,
|
|
14
|
+
} as CustomCellEditorProps);
|
|
15
|
+
|
|
16
|
+
const getDateField = (container: HTMLElement) => (
|
|
17
|
+
container.querySelector('input[type="date"]') as HTMLInputElement
|
|
18
|
+
);
|
|
19
|
+
|
|
20
|
+
describe('DateCellEditor', () => {
|
|
21
|
+
test('renders a date picker', () => {
|
|
22
|
+
const { container } = render(<DateCellEditor {...createMockProps()} />);
|
|
23
|
+
expect(getDateField(container)).toBeInTheDocument();
|
|
24
|
+
expect(screen.getByRole('button', { name: 'Open date picker' })).toBeInTheDocument();
|
|
25
|
+
});
|
|
26
|
+
|
|
27
|
+
test('displays the provided value', () => {
|
|
28
|
+
const { container } = render(<DateCellEditor {...createMockProps({ value: new Date(2024, 5, 15) })} />);
|
|
29
|
+
expect(getDateField(container)).toHaveValue('2024-06-15');
|
|
30
|
+
});
|
|
31
|
+
|
|
32
|
+
test('displays empty when value is undefined', () => {
|
|
33
|
+
const { container } = render(<DateCellEditor {...createMockProps({ value: undefined })} />);
|
|
34
|
+
expect(getDateField(container)).toHaveValue('');
|
|
35
|
+
});
|
|
36
|
+
|
|
37
|
+
test('displays empty when value is null', () => {
|
|
38
|
+
const { container } = render(<DateCellEditor {...createMockProps({ value: null })} />);
|
|
39
|
+
expect(getDateField(container)).toHaveValue('');
|
|
40
|
+
});
|
|
41
|
+
|
|
42
|
+
test('calls onValueChange when a date is typed', () => {
|
|
43
|
+
const onValueChange = vi.fn();
|
|
44
|
+
const { container } = render(<DateCellEditor {...createMockProps({ onValueChange })} />);
|
|
45
|
+
onValueChange.mockClear();
|
|
46
|
+
|
|
47
|
+
fireEvent.change(getDateField(container), { target: { value: '2024-06-15' } });
|
|
48
|
+
|
|
49
|
+
expect(onValueChange).toHaveBeenCalledWith(expect.any(Date));
|
|
50
|
+
const lastDate: Date = onValueChange.mock.lastCall![0];
|
|
51
|
+
expect(lastDate.getFullYear()).toBe(2024);
|
|
52
|
+
expect(lastDate.getMonth()).toBe(5);
|
|
53
|
+
expect(lastDate.getDate()).toBe(15);
|
|
54
|
+
});
|
|
55
|
+
|
|
56
|
+
test('calls onValueChange when a date is picked from the calendar', async () => {
|
|
57
|
+
const onValueChange = vi.fn();
|
|
58
|
+
const { container } = render(<DateCellEditor {...createMockProps({ onValueChange })} />);
|
|
59
|
+
|
|
60
|
+
// Navigate to a known month via text input first
|
|
61
|
+
fireEvent.change(getDateField(container), { target: { value: '2024-06-01' } });
|
|
62
|
+
onValueChange.mockClear();
|
|
63
|
+
|
|
64
|
+
await userEvent.click(screen.getByRole('button', { name: 'Open date picker' }));
|
|
65
|
+
await userEvent.click(within(screen.getByRole('application')).getByRole('button', { name: /June 20/ }));
|
|
66
|
+
|
|
67
|
+
expect(onValueChange).toHaveBeenCalledWith(expect.any(Date));
|
|
68
|
+
const lastDate: Date = onValueChange.mock.lastCall![0];
|
|
69
|
+
expect(lastDate.getFullYear()).toBe(2024);
|
|
70
|
+
expect(lastDate.getMonth()).toBe(5);
|
|
71
|
+
expect(lastDate.getDate()).toBe(20);
|
|
72
|
+
});
|
|
73
|
+
|
|
74
|
+
test('calls onValueChange with undefined when the date is cleared', () => {
|
|
75
|
+
const onValueChange = vi.fn();
|
|
76
|
+
const { container } = render(
|
|
77
|
+
<DateCellEditor {...createMockProps({ value: new Date(2024, 5, 15), onValueChange })} />,
|
|
78
|
+
);
|
|
79
|
+
onValueChange.mockClear();
|
|
80
|
+
|
|
81
|
+
fireEvent.change(getDateField(container), { target: { value: '' } });
|
|
82
|
+
|
|
83
|
+
expect(onValueChange).toHaveBeenCalledWith(undefined);
|
|
84
|
+
});
|
|
85
|
+
|
|
86
|
+
test('autofocuses the date input on mount', () => {
|
|
87
|
+
const { container } = render(<DateCellEditor {...createMockProps()} />);
|
|
88
|
+
expect(getDateField(container)).toHaveFocus();
|
|
89
|
+
});
|
|
90
|
+
|
|
91
|
+
test('autofocuses the date input even when a value is already set', () => {
|
|
92
|
+
const { container } = render(
|
|
93
|
+
<DateCellEditor {...createMockProps({ value: new Date(2024, 5, 15) })} />,
|
|
94
|
+
);
|
|
95
|
+
expect(getDateField(container)).toHaveFocus();
|
|
96
|
+
});
|
|
97
|
+
|
|
98
|
+
test('passes cellEditorParams through to DatePicker', () => {
|
|
99
|
+
render(
|
|
100
|
+
<DateCellEditor
|
|
101
|
+
{...createMockProps({
|
|
102
|
+
value: undefined,
|
|
103
|
+
colDef: { cellEditorParams: { placeholder: 'Pick a birthday' } },
|
|
104
|
+
})}
|
|
105
|
+
/>,
|
|
106
|
+
);
|
|
107
|
+
expect(screen.getByText('Pick a birthday')).toBeInTheDocument();
|
|
108
|
+
});
|
|
109
|
+
});
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import type { CustomCellEditorProps } from 'ag-grid-react';
|
|
2
|
+
import { DatePicker } from 'Components/datePicker/DatePicker';
|
|
3
|
+
|
|
4
|
+
export const DateCellEditor = (props: CustomCellEditorProps) => {
|
|
5
|
+
const {
|
|
6
|
+
value,
|
|
7
|
+
onValueChange,
|
|
8
|
+
colDef: {
|
|
9
|
+
cellEditorParams,
|
|
10
|
+
},
|
|
11
|
+
} = props;
|
|
12
|
+
|
|
13
|
+
return (
|
|
14
|
+
<DatePicker
|
|
15
|
+
value={value}
|
|
16
|
+
onChange={(newValue) => {
|
|
17
|
+
// intentionally not updating always, because AG Grid controls the component and
|
|
18
|
+
// ends up interfering with things, leading to lots of jank
|
|
19
|
+
if (newValue !== value) {
|
|
20
|
+
onValueChange(newValue);
|
|
21
|
+
}
|
|
22
|
+
}}
|
|
23
|
+
autoFocus
|
|
24
|
+
{...cellEditorParams}
|
|
25
|
+
/>
|
|
26
|
+
);
|
|
27
|
+
};
|