@arbor-education/design-system.components 0.12.0 → 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 +6 -0
- package/dist/components/datePicker/DatePicker.d.ts +1 -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/table/Table.d.ts +7 -0
- package/dist/components/table/Table.d.ts.map +1 -1
- package/dist/components/table/Table.js +9 -0
- 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 +49 -1
- 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/index.d.ts +0 -5
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +0 -5
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
- package/src/components/datePicker/DatePicker.tsx +3 -0
- package/src/components/table/Table.stories.tsx +102 -0
- package/src/components/table/Table.test.tsx +82 -3
- package/src/components/table/Table.tsx +9 -0
- package/src/components/table/cellEditors/DateCellEditor.test.tsx +109 -0
- package/src/components/table/cellEditors/DateCellEditor.tsx +27 -0
- package/src/index.ts +0 -5
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { describe, expect, expectTypeOf, test, vi } from 'vitest';
|
|
2
|
-
import { render, screen, waitFor } from '@testing-library/react';
|
|
2
|
+
import { render, screen, waitFor, fireEvent } from '@testing-library/react';
|
|
3
3
|
import { Table } from './Table';
|
|
4
4
|
import '@testing-library/jest-dom/vitest';
|
|
5
5
|
import { BulkActionsDropdown } from 'Components/table/tableControls/BulkActionsDropdown';
|
|
@@ -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
|
/>
|
|
@@ -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,6 +23,7 @@ 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
28
|
import { TableControls, type TableControlsProps, type BulkAction as BulkActionType } from './tableControls/TableControls';
|
|
28
29
|
import type { HideColumnsDropdownProps } from './tableControls/HideColumnsDropdown';
|
|
@@ -30,6 +31,7 @@ import { TABLE_SPACING } from './tableConsts';
|
|
|
30
31
|
import { TableSettingsContext } from './TableSettingsContext';
|
|
31
32
|
import { BooleanCellRenderer } from './cellRenderers/BooleanCellRenderer';
|
|
32
33
|
import { CheckboxCellRenderer } from './cellRenderers/CheckboxCellRenderer';
|
|
34
|
+
import { DefaultCellRenderer } from './cellRenderers/DefaultCellRenderer';
|
|
33
35
|
|
|
34
36
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
35
37
|
type TableProps<TData = any> = {
|
|
@@ -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,12 @@ 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;
|
|
@@ -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
|
+
};
|
package/src/index.ts
CHANGED
|
@@ -35,10 +35,6 @@ export { Separator } from 'Components/separator/Separator';
|
|
|
35
35
|
export { SingleUser } from 'Components/singleUser/SingleUser';
|
|
36
36
|
export { Slideover } from 'Components/slideover/Slideover';
|
|
37
37
|
export { SlideoverManager } from 'Components/slideoverManager/SlideoverManager';
|
|
38
|
-
export { BooleanCellRenderer } from 'Components/table/cellRenderers/BooleanCellRenderer';
|
|
39
|
-
export { DefaultCellRenderer } from 'Components/table/cellRenderers/DefaultCellRenderer';
|
|
40
|
-
export { DSDefaultColDef } from 'Components/table/DSDefaultColDef';
|
|
41
|
-
export { GridApiContext } from 'Components/table/GridApiContext';
|
|
42
38
|
export { Table } from 'Components/table/Table';
|
|
43
39
|
export { Tabs } from 'Components/tabs/Tabs';
|
|
44
40
|
export { Tag } from 'Components/tag/Tag';
|
|
@@ -51,4 +47,3 @@ export { UserDropdown } from 'Components/userDropdown/UserDropdown';
|
|
|
51
47
|
export { ModalUtils } from 'Utils/ModalUtils';
|
|
52
48
|
export { PopupParentContext } from 'Utils/PopupParentContext';
|
|
53
49
|
export { SlideoverUtils } from 'Utils/SlideoverUtils';
|
|
54
|
-
export { CheckboxCellRenderer } from 'Components/table/cellRenderers/CheckboxCellRenderer';
|