@arbor-education/design-system.components 0.1.5 → 0.2.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/formField/fieldset/Fieldset.d.ts +6 -0
- package/dist/components/formField/fieldset/Fieldset.d.ts.map +1 -0
- package/dist/components/formField/fieldset/Fieldset.js +7 -0
- package/dist/components/formField/fieldset/Fieldset.js.map +1 -0
- package/dist/components/formField/fieldset/Fieldset.stories.d.ts +28 -0
- package/dist/components/formField/fieldset/Fieldset.stories.d.ts.map +1 -0
- package/dist/components/formField/fieldset/Fieldset.stories.js +51 -0
- package/dist/components/formField/fieldset/Fieldset.stories.js.map +1 -0
- package/dist/components/formField/fieldset/Fieldset.test.d.ts +2 -0
- package/dist/components/formField/fieldset/Fieldset.test.d.ts.map +1 -0
- package/dist/components/formField/fieldset/Fieldset.test.js +62 -0
- package/dist/components/formField/fieldset/Fieldset.test.js.map +1 -0
- package/dist/components/formField/inputs/checkbox/CheckboxGroup.d.ts +8 -0
- package/dist/components/formField/inputs/checkbox/CheckboxGroup.d.ts.map +1 -0
- package/dist/components/formField/inputs/checkbox/CheckboxGroup.js +8 -0
- package/dist/components/formField/inputs/checkbox/CheckboxGroup.js.map +1 -0
- package/dist/components/formField/inputs/checkbox/CheckboxGroup.test.d.ts +2 -0
- package/dist/components/formField/inputs/checkbox/CheckboxGroup.test.d.ts.map +1 -0
- package/dist/components/formField/inputs/checkbox/CheckboxGroup.test.js +86 -0
- package/dist/components/formField/inputs/checkbox/CheckboxGroup.test.js.map +1 -0
- package/dist/components/formField/inputs/checkbox/CheckboxInput.stories.d.ts +3 -1
- package/dist/components/formField/inputs/checkbox/CheckboxInput.stories.d.ts.map +1 -1
- package/dist/components/formField/inputs/checkbox/CheckboxInput.stories.js +7 -0
- package/dist/components/formField/inputs/checkbox/CheckboxInput.stories.js.map +1 -1
- package/dist/components/formField/inputs/radio/RadioButtonGroup.d.ts +11 -0
- package/dist/components/formField/inputs/radio/RadioButtonGroup.d.ts.map +1 -0
- package/dist/components/formField/inputs/radio/RadioButtonGroup.js +8 -0
- package/dist/components/formField/inputs/radio/RadioButtonGroup.js.map +1 -0
- package/dist/components/formField/inputs/radio/RadioButtonGroup.test.d.ts +2 -0
- package/dist/components/formField/inputs/radio/RadioButtonGroup.test.d.ts.map +1 -0
- package/dist/components/formField/inputs/radio/RadioButtonGroup.test.js +86 -0
- package/dist/components/formField/inputs/radio/RadioButtonGroup.test.js.map +1 -0
- package/dist/components/formField/inputs/radio/RadioButtonInput.stories.d.ts.map +1 -1
- package/dist/components/formField/inputs/radio/RadioButtonInput.stories.js +8 -2
- package/dist/components/formField/inputs/radio/RadioButtonInput.stories.js.map +1 -1
- package/dist/components/separator/Separator.d.ts +7 -0
- package/dist/components/separator/Separator.d.ts.map +1 -0
- package/dist/components/separator/Separator.js +8 -0
- package/dist/components/separator/Separator.js.map +1 -0
- package/dist/components/separator/Separator.stories.d.ts +10 -0
- package/dist/components/separator/Separator.stories.d.ts.map +1 -0
- package/dist/components/separator/Separator.stories.js +12 -0
- package/dist/components/separator/Separator.stories.js.map +1 -0
- package/dist/components/separator/Separator.test.d.ts +2 -0
- package/dist/components/separator/Separator.test.d.ts.map +1 -0
- package/dist/components/separator/Separator.test.js +10 -0
- package/dist/components/separator/Separator.test.js.map +1 -0
- package/dist/components/table/Table.d.ts +13 -0
- package/dist/components/table/Table.d.ts.map +1 -1
- package/dist/components/table/Table.js +43 -7
- package/dist/components/table/Table.js.map +1 -1
- package/dist/components/table/Table.stories.d.ts.map +1 -1
- package/dist/components/table/Table.stories.js +8 -1
- package/dist/components/table/Table.stories.js.map +1 -1
- package/dist/components/table/Table.test.js +254 -2
- package/dist/components/table/Table.test.js.map +1 -1
- package/dist/components/table/pagination/TableSettingsDropdown.d.ts +2 -0
- package/dist/components/table/pagination/TableSettingsDropdown.d.ts.map +1 -0
- package/dist/components/table/pagination/TableSettingsDropdown.js +43 -0
- package/dist/components/table/pagination/TableSettingsDropdown.js.map +1 -0
- package/dist/components/table/useTableSettings.d.ts +22 -0
- package/dist/components/table/useTableSettings.d.ts.map +1 -0
- package/dist/components/table/useTableSettings.js +28 -0
- package/dist/components/table/useTableSettings.js.map +1 -0
- package/dist/index.css +31 -1
- package/dist/index.css.map +1 -1
- package/dist/index.d.ts +2 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +2 -0
- package/dist/index.js.map +1 -1
- package/dist/utils/hooks/useComponentDidUpdate.d.ts +7 -0
- package/dist/utils/hooks/useComponentDidUpdate.d.ts.map +1 -0
- package/dist/utils/hooks/useComponentDidUpdate.js +18 -0
- package/dist/utils/hooks/useComponentDidUpdate.js.map +1 -0
- package/dist/utils/hooks/useComponentDidUpdate.test.d.ts +2 -0
- package/dist/utils/hooks/useComponentDidUpdate.test.d.ts.map +1 -0
- package/dist/utils/hooks/useComponentDidUpdate.test.js +69 -0
- package/dist/utils/hooks/useComponentDidUpdate.test.js.map +1 -0
- package/package.json +1 -1
- package/src/components/formField/fieldset/Fieldset.stories.tsx +89 -0
- package/src/components/formField/fieldset/Fieldset.test.tsx +85 -0
- package/src/components/formField/fieldset/Fieldset.tsx +17 -0
- package/src/components/formField/fieldset/fieldset.scss +19 -0
- package/src/components/formField/inputs/checkbox/CheckboxGroup.test.tsx +127 -0
- package/src/components/formField/inputs/checkbox/CheckboxGroup.tsx +17 -0
- package/src/components/formField/inputs/checkbox/CheckboxInput.stories.tsx +12 -1
- package/src/components/formField/inputs/radio/RadioButtonGroup.test.tsx +190 -0
- package/src/components/formField/inputs/radio/RadioButtonGroup.tsx +22 -0
- package/src/components/formField/inputs/radio/RadioButtonInput.stories.tsx +16 -7
- package/src/components/formField/label/label.scss +1 -1
- package/src/components/separator/Separator.stories.tsx +15 -0
- package/src/components/separator/Separator.test.tsx +10 -0
- package/src/components/separator/Separator.tsx +15 -0
- package/src/components/separator/separator.scss +6 -0
- package/src/components/table/Table.stories.tsx +8 -1
- package/src/components/table/Table.test.tsx +444 -1
- package/src/components/table/Table.tsx +69 -24
- package/src/components/table/pagination/TableSettingsDropdown.tsx +90 -0
- package/src/components/table/table.scss +6 -0
- package/src/components/table/useTableSettings.ts +47 -0
- package/src/index.scss +2 -0
- package/src/index.ts +2 -0
- package/src/utils/hooks/useComponentDidUpdate.test.ts +107 -0
- package/src/utils/hooks/useComponentDidUpdate.ts +19 -0
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
import { describe, expect, expectTypeOf, test, vi } from 'vitest';
|
|
2
2
|
import { render, screen, waitFor } from '@testing-library/react';
|
|
3
|
-
import { Table } from './Table';
|
|
3
|
+
import { Table, TABLE_SPACING } from './Table';
|
|
4
4
|
import '@testing-library/jest-dom/vitest';
|
|
5
5
|
import { BulkActionsDropdown } from 'Components/table/BulkActionsDropdown';
|
|
6
6
|
import { HideColumnsDropdown } from 'Components/table/HideColumnsDropdown';
|
|
7
|
+
import { TableSettingsDropdown } from './pagination/TableSettingsDropdown';
|
|
7
8
|
import userEvent from '@testing-library/user-event';
|
|
8
9
|
import type { GridApi } from 'ag-grid-enterprise';
|
|
9
10
|
|
|
@@ -409,4 +410,446 @@ describe('Table', () => {
|
|
|
409
410
|
expect(container.querySelector('button')).toBeNull();
|
|
410
411
|
});
|
|
411
412
|
});
|
|
413
|
+
|
|
414
|
+
describe('TableSettingsDropdown', () => {
|
|
415
|
+
test('renders settings dropdown button in header', async () => {
|
|
416
|
+
render(
|
|
417
|
+
<Table
|
|
418
|
+
headerContent={<TableSettingsDropdown />}
|
|
419
|
+
/>,
|
|
420
|
+
);
|
|
421
|
+
|
|
422
|
+
await waitFor(() => {
|
|
423
|
+
const button = screen.getByRole('button', { name: /Table settings/i });
|
|
424
|
+
expect(button).toBeInTheDocument();
|
|
425
|
+
});
|
|
426
|
+
});
|
|
427
|
+
|
|
428
|
+
test('opens dropdown when settings button is clicked', async () => {
|
|
429
|
+
render(
|
|
430
|
+
<Table
|
|
431
|
+
headerContent={<TableSettingsDropdown />}
|
|
432
|
+
/>,
|
|
433
|
+
);
|
|
434
|
+
|
|
435
|
+
const settingsButton = screen.getByRole('button', { name: /Table settings/i });
|
|
436
|
+
await userEvent.click(settingsButton);
|
|
437
|
+
|
|
438
|
+
await waitFor(() => {
|
|
439
|
+
expect(screen.getByText('Table spacing')).toBeInTheDocument();
|
|
440
|
+
expect(screen.getByText('Style')).toBeInTheDocument();
|
|
441
|
+
expect(screen.getByText('Reset Table Settings')).toBeInTheDocument();
|
|
442
|
+
});
|
|
443
|
+
});
|
|
444
|
+
|
|
445
|
+
test('displays all table spacing options', async () => {
|
|
446
|
+
render(
|
|
447
|
+
<Table
|
|
448
|
+
headerContent={<TableSettingsDropdown />}
|
|
449
|
+
/>,
|
|
450
|
+
);
|
|
451
|
+
|
|
452
|
+
await userEvent.click(screen.getByRole('button', { name: /Table settings/i }));
|
|
453
|
+
|
|
454
|
+
await waitFor(() => {
|
|
455
|
+
expect(screen.getByLabelText('X-Small')).toBeInTheDocument();
|
|
456
|
+
expect(screen.getByLabelText('Small')).toBeInTheDocument();
|
|
457
|
+
expect(screen.getByLabelText('Medium')).toBeInTheDocument();
|
|
458
|
+
expect(screen.getByLabelText('Large')).toBeInTheDocument();
|
|
459
|
+
});
|
|
460
|
+
});
|
|
461
|
+
|
|
462
|
+
test('Medium spacing is selected by default', async () => {
|
|
463
|
+
render(
|
|
464
|
+
<Table
|
|
465
|
+
headerContent={<TableSettingsDropdown />}
|
|
466
|
+
/>,
|
|
467
|
+
);
|
|
468
|
+
|
|
469
|
+
await userEvent.click(screen.getByRole('button', { name: /Table settings/i }));
|
|
470
|
+
|
|
471
|
+
await waitFor(() => {
|
|
472
|
+
const mediumRadio = screen.getByLabelText('Medium') as HTMLInputElement;
|
|
473
|
+
expect(mediumRadio.checked).toBe(true);
|
|
474
|
+
});
|
|
475
|
+
});
|
|
476
|
+
|
|
477
|
+
test('can change table spacing to Small', async () => {
|
|
478
|
+
render(
|
|
479
|
+
<Table
|
|
480
|
+
headerContent={<TableSettingsDropdown />}
|
|
481
|
+
/>,
|
|
482
|
+
);
|
|
483
|
+
|
|
484
|
+
await userEvent.click(screen.getByRole('button', { name: /Table settings/i }));
|
|
485
|
+
|
|
486
|
+
await waitFor(() => {
|
|
487
|
+
expect(screen.getByLabelText('Small')).toBeInTheDocument();
|
|
488
|
+
});
|
|
489
|
+
|
|
490
|
+
const smallRadio = screen.getByLabelText('Small');
|
|
491
|
+
await userEvent.click(smallRadio);
|
|
492
|
+
|
|
493
|
+
await waitFor(() => {
|
|
494
|
+
expect((smallRadio as HTMLInputElement).checked).toBe(true);
|
|
495
|
+
});
|
|
496
|
+
});
|
|
497
|
+
|
|
498
|
+
test('can change table spacing to Large', async () => {
|
|
499
|
+
render(
|
|
500
|
+
<Table
|
|
501
|
+
headerContent={<TableSettingsDropdown />}
|
|
502
|
+
/>,
|
|
503
|
+
);
|
|
504
|
+
|
|
505
|
+
await userEvent.click(screen.getByRole('button', { name: /Table settings/i }));
|
|
506
|
+
|
|
507
|
+
const largeRadio = screen.getByLabelText('Large');
|
|
508
|
+
await userEvent.click(largeRadio);
|
|
509
|
+
|
|
510
|
+
await waitFor(() => {
|
|
511
|
+
expect((largeRadio as HTMLInputElement).checked).toBe(true);
|
|
512
|
+
});
|
|
513
|
+
});
|
|
514
|
+
|
|
515
|
+
test('can change table spacing to X-Small', async () => {
|
|
516
|
+
render(
|
|
517
|
+
<Table
|
|
518
|
+
headerContent={<TableSettingsDropdown />}
|
|
519
|
+
/>,
|
|
520
|
+
);
|
|
521
|
+
|
|
522
|
+
await userEvent.click(screen.getByRole('button', { name: /Table settings/i }));
|
|
523
|
+
|
|
524
|
+
const xsmallRadio = screen.getByLabelText('X-Small');
|
|
525
|
+
await userEvent.click(xsmallRadio);
|
|
526
|
+
|
|
527
|
+
await waitFor(() => {
|
|
528
|
+
expect((xsmallRadio as HTMLInputElement).checked).toBe(true);
|
|
529
|
+
});
|
|
530
|
+
});
|
|
531
|
+
|
|
532
|
+
test('displays style options with Column borders and Cell colours', async () => {
|
|
533
|
+
render(
|
|
534
|
+
<Table
|
|
535
|
+
headerContent={<TableSettingsDropdown />}
|
|
536
|
+
/>,
|
|
537
|
+
);
|
|
538
|
+
|
|
539
|
+
await userEvent.click(screen.getByRole('button', { name: /Table settings/i }));
|
|
540
|
+
|
|
541
|
+
await waitFor(() => {
|
|
542
|
+
expect(screen.getByLabelText('Column borders')).toBeInTheDocument();
|
|
543
|
+
expect(screen.getByLabelText('Cell colours')).toBeInTheDocument();
|
|
544
|
+
});
|
|
545
|
+
});
|
|
546
|
+
|
|
547
|
+
test('Column borders checkbox is unchecked by default', async () => {
|
|
548
|
+
render(
|
|
549
|
+
<Table
|
|
550
|
+
headerContent={<TableSettingsDropdown />}
|
|
551
|
+
/>,
|
|
552
|
+
);
|
|
553
|
+
|
|
554
|
+
await userEvent.click(screen.getByRole('button', { name: /Table settings/i }));
|
|
555
|
+
|
|
556
|
+
await waitFor(() => {
|
|
557
|
+
const columnBordersCheckbox = screen.getByLabelText('Column borders') as HTMLInputElement;
|
|
558
|
+
expect(columnBordersCheckbox.checked).toBe(false);
|
|
559
|
+
});
|
|
560
|
+
});
|
|
561
|
+
|
|
562
|
+
test('can toggle Column borders checkbox on', async () => {
|
|
563
|
+
render(
|
|
564
|
+
<Table
|
|
565
|
+
headerContent={<TableSettingsDropdown />}
|
|
566
|
+
/>,
|
|
567
|
+
);
|
|
568
|
+
|
|
569
|
+
await userEvent.click(screen.getByRole('button', { name: /Table settings/i }));
|
|
570
|
+
|
|
571
|
+
const columnBordersCheckbox = screen.getByLabelText('Column borders');
|
|
572
|
+
await userEvent.click(columnBordersCheckbox);
|
|
573
|
+
|
|
574
|
+
await waitFor(() => {
|
|
575
|
+
expect((columnBordersCheckbox as HTMLInputElement).checked).toBe(true);
|
|
576
|
+
});
|
|
577
|
+
});
|
|
578
|
+
|
|
579
|
+
test('can toggle Column borders checkbox off after turning it on', async () => {
|
|
580
|
+
render(
|
|
581
|
+
<Table
|
|
582
|
+
headerContent={<TableSettingsDropdown />}
|
|
583
|
+
/>,
|
|
584
|
+
);
|
|
585
|
+
|
|
586
|
+
await userEvent.click(screen.getByRole('button', { name: /Table settings/i }));
|
|
587
|
+
|
|
588
|
+
const columnBordersCheckbox = screen.getByLabelText('Column borders');
|
|
589
|
+
await userEvent.click(columnBordersCheckbox);
|
|
590
|
+
await userEvent.click(columnBordersCheckbox);
|
|
591
|
+
|
|
592
|
+
await waitFor(() => {
|
|
593
|
+
expect((columnBordersCheckbox as HTMLInputElement).checked).toBe(false);
|
|
594
|
+
});
|
|
595
|
+
});
|
|
596
|
+
|
|
597
|
+
test('Cell colours checkbox is unchecked by default', async () => {
|
|
598
|
+
render(
|
|
599
|
+
<Table
|
|
600
|
+
headerContent={<TableSettingsDropdown />}
|
|
601
|
+
/>,
|
|
602
|
+
);
|
|
603
|
+
|
|
604
|
+
await userEvent.click(screen.getByRole('button', { name: /Table settings/i }));
|
|
605
|
+
|
|
606
|
+
await waitFor(() => {
|
|
607
|
+
const cellColoursCheckbox = screen.getByLabelText('Cell colours') as HTMLInputElement;
|
|
608
|
+
expect(cellColoursCheckbox.checked).toBe(false);
|
|
609
|
+
});
|
|
610
|
+
});
|
|
611
|
+
|
|
612
|
+
test('can toggle Cell colours checkbox on', async () => {
|
|
613
|
+
render(
|
|
614
|
+
<Table
|
|
615
|
+
headerContent={<TableSettingsDropdown />}
|
|
616
|
+
/>,
|
|
617
|
+
);
|
|
618
|
+
|
|
619
|
+
await userEvent.click(screen.getByRole('button', { name: /Table settings/i }));
|
|
620
|
+
|
|
621
|
+
const cellColoursCheckbox = screen.getByLabelText('Cell colours');
|
|
622
|
+
await userEvent.click(cellColoursCheckbox);
|
|
623
|
+
|
|
624
|
+
await waitFor(() => {
|
|
625
|
+
expect((cellColoursCheckbox as HTMLInputElement).checked).toBe(true);
|
|
626
|
+
});
|
|
627
|
+
});
|
|
628
|
+
|
|
629
|
+
test('can toggle Cell colours checkbox off after turning it on', async () => {
|
|
630
|
+
render(
|
|
631
|
+
<Table
|
|
632
|
+
headerContent={<TableSettingsDropdown />}
|
|
633
|
+
/>,
|
|
634
|
+
);
|
|
635
|
+
|
|
636
|
+
await userEvent.click(screen.getByRole('button', { name: /Table settings/i }));
|
|
637
|
+
|
|
638
|
+
const cellColoursCheckbox = screen.getByLabelText('Cell colours');
|
|
639
|
+
await userEvent.click(cellColoursCheckbox);
|
|
640
|
+
await userEvent.click(cellColoursCheckbox);
|
|
641
|
+
|
|
642
|
+
await waitFor(() => {
|
|
643
|
+
expect((cellColoursCheckbox as HTMLInputElement).checked).toBe(false);
|
|
644
|
+
});
|
|
645
|
+
});
|
|
646
|
+
|
|
647
|
+
test('displays Reset Table Settings button', async () => {
|
|
648
|
+
render(
|
|
649
|
+
<Table
|
|
650
|
+
headerContent={<TableSettingsDropdown />}
|
|
651
|
+
/>,
|
|
652
|
+
);
|
|
653
|
+
|
|
654
|
+
await userEvent.click(screen.getByRole('button', { name: /Table settings/i }));
|
|
655
|
+
|
|
656
|
+
await waitFor(() => {
|
|
657
|
+
expect(screen.getByRole('button', { name: /Reset Table Settings/i })).toBeInTheDocument();
|
|
658
|
+
});
|
|
659
|
+
});
|
|
660
|
+
|
|
661
|
+
test('reset button resets table spacing to default (Medium)', async () => {
|
|
662
|
+
render(
|
|
663
|
+
<Table
|
|
664
|
+
headerContent={<TableSettingsDropdown />}
|
|
665
|
+
/>,
|
|
666
|
+
);
|
|
667
|
+
|
|
668
|
+
await userEvent.click(screen.getByRole('button', { name: /Table settings/i }));
|
|
669
|
+
|
|
670
|
+
// Change to Large
|
|
671
|
+
const largeRadio = screen.getByLabelText('Large');
|
|
672
|
+
await userEvent.click(largeRadio);
|
|
673
|
+
|
|
674
|
+
await waitFor(() => {
|
|
675
|
+
expect((largeRadio as HTMLInputElement).checked).toBe(true);
|
|
676
|
+
});
|
|
677
|
+
|
|
678
|
+
// Click reset button
|
|
679
|
+
const resetButton = screen.getByRole('button', { name: /Reset Table Settings/i });
|
|
680
|
+
await userEvent.click(resetButton);
|
|
681
|
+
|
|
682
|
+
await waitFor(() => {
|
|
683
|
+
const mediumRadio = screen.getByLabelText('Medium') as HTMLInputElement;
|
|
684
|
+
expect(mediumRadio.checked).toBe(true);
|
|
685
|
+
});
|
|
686
|
+
});
|
|
687
|
+
|
|
688
|
+
test('reset button resets column borders to default (off)', async () => {
|
|
689
|
+
render(
|
|
690
|
+
<Table
|
|
691
|
+
headerContent={<TableSettingsDropdown />}
|
|
692
|
+
/>,
|
|
693
|
+
);
|
|
694
|
+
|
|
695
|
+
await userEvent.click(screen.getByRole('button', { name: /Table settings/i }));
|
|
696
|
+
|
|
697
|
+
// Turn on column borders
|
|
698
|
+
const columnBordersCheckbox = screen.getByLabelText('Column borders');
|
|
699
|
+
await userEvent.click(columnBordersCheckbox);
|
|
700
|
+
|
|
701
|
+
await waitFor(() => {
|
|
702
|
+
expect((columnBordersCheckbox as HTMLInputElement).checked).toBe(true);
|
|
703
|
+
});
|
|
704
|
+
|
|
705
|
+
// Click reset button
|
|
706
|
+
const resetButton = screen.getByRole('button', { name: /Reset Table Settings/i });
|
|
707
|
+
await userEvent.click(resetButton);
|
|
708
|
+
|
|
709
|
+
await waitFor(() => {
|
|
710
|
+
expect((columnBordersCheckbox as HTMLInputElement).checked).toBe(false);
|
|
711
|
+
});
|
|
712
|
+
});
|
|
713
|
+
|
|
714
|
+
test('reset button resets all settings together', async () => {
|
|
715
|
+
render(
|
|
716
|
+
<Table
|
|
717
|
+
headerContent={<TableSettingsDropdown />}
|
|
718
|
+
/>,
|
|
719
|
+
);
|
|
720
|
+
|
|
721
|
+
await userEvent.click(screen.getByRole('button', { name: /Table settings/i }));
|
|
722
|
+
|
|
723
|
+
// Change multiple settings
|
|
724
|
+
const largeRadio = screen.getByLabelText('Large');
|
|
725
|
+
await userEvent.click(largeRadio);
|
|
726
|
+
|
|
727
|
+
const columnBordersCheckbox = screen.getByLabelText('Column borders');
|
|
728
|
+
await userEvent.click(columnBordersCheckbox);
|
|
729
|
+
|
|
730
|
+
await waitFor(() => {
|
|
731
|
+
expect((largeRadio as HTMLInputElement).checked).toBe(true);
|
|
732
|
+
expect((columnBordersCheckbox as HTMLInputElement).checked).toBe(true);
|
|
733
|
+
});
|
|
734
|
+
|
|
735
|
+
// Click reset button
|
|
736
|
+
const resetButton = screen.getByRole('button', { name: /Reset Table Settings/i });
|
|
737
|
+
await userEvent.click(resetButton);
|
|
738
|
+
|
|
739
|
+
await waitFor(() => {
|
|
740
|
+
const mediumRadio = screen.getByLabelText('Medium') as HTMLInputElement;
|
|
741
|
+
expect(mediumRadio.checked).toBe(true);
|
|
742
|
+
expect((columnBordersCheckbox as HTMLInputElement).checked).toBe(false);
|
|
743
|
+
});
|
|
744
|
+
});
|
|
745
|
+
|
|
746
|
+
test('can combine settings dropdown with other header content', async () => {
|
|
747
|
+
render(
|
|
748
|
+
<Table
|
|
749
|
+
headerContent={(
|
|
750
|
+
<>
|
|
751
|
+
<BulkActionsDropdown
|
|
752
|
+
actions={[
|
|
753
|
+
{
|
|
754
|
+
displayName: 'Test Action',
|
|
755
|
+
callback: () => {},
|
|
756
|
+
},
|
|
757
|
+
]}
|
|
758
|
+
/>
|
|
759
|
+
<TableSettingsDropdown />
|
|
760
|
+
</>
|
|
761
|
+
)}
|
|
762
|
+
/>,
|
|
763
|
+
);
|
|
764
|
+
|
|
765
|
+
await waitFor(() => {
|
|
766
|
+
expect(screen.getByText('Actions (1)')).toBeInTheDocument();
|
|
767
|
+
expect(screen.getByRole('button', { name: /Table settings/i })).toBeInTheDocument();
|
|
768
|
+
});
|
|
769
|
+
});
|
|
770
|
+
|
|
771
|
+
test('settings persist when dropdown is closed and reopened', async () => {
|
|
772
|
+
render(
|
|
773
|
+
<Table
|
|
774
|
+
headerContent={<TableSettingsDropdown />}
|
|
775
|
+
/>,
|
|
776
|
+
);
|
|
777
|
+
|
|
778
|
+
// Open dropdown and change settings
|
|
779
|
+
await userEvent.click(screen.getByRole('button', { name: /Table settings/i }));
|
|
780
|
+
|
|
781
|
+
const smallRadio = screen.getByLabelText('Small');
|
|
782
|
+
await userEvent.click(smallRadio);
|
|
783
|
+
|
|
784
|
+
const columnBordersCheckbox = screen.getByLabelText('Column borders');
|
|
785
|
+
await userEvent.click(columnBordersCheckbox);
|
|
786
|
+
|
|
787
|
+
// Close dropdown
|
|
788
|
+
await userEvent.keyboard('{Escape}');
|
|
789
|
+
|
|
790
|
+
// Reopen dropdown
|
|
791
|
+
await userEvent.click(screen.getByRole('button', { name: /Table settings/i }));
|
|
792
|
+
|
|
793
|
+
// Check settings persisted
|
|
794
|
+
await waitFor(() => {
|
|
795
|
+
expect((screen.getByLabelText('Small') as HTMLInputElement).checked).toBe(true);
|
|
796
|
+
expect((screen.getByLabelText('Column borders') as HTMLInputElement).checked).toBe(true);
|
|
797
|
+
});
|
|
798
|
+
});
|
|
799
|
+
});
|
|
800
|
+
|
|
801
|
+
test('onTableSettingsChanged gets called appropriately', async () => {
|
|
802
|
+
const onTableSettingsChanged = vi.fn();
|
|
803
|
+
|
|
804
|
+
render(
|
|
805
|
+
<Table
|
|
806
|
+
headerContent={<TableSettingsDropdown />}
|
|
807
|
+
onTableSettingsChanged={onTableSettingsChanged}
|
|
808
|
+
/>,
|
|
809
|
+
);
|
|
810
|
+
|
|
811
|
+
await userEvent.click(screen.getByRole('button', { name: /Table settings/i }));
|
|
812
|
+
|
|
813
|
+
const largeRadio = screen.getByLabelText('Large');
|
|
814
|
+
await userEvent.click(largeRadio);
|
|
815
|
+
|
|
816
|
+
await waitFor(() => {
|
|
817
|
+
expect((largeRadio as HTMLInputElement).checked).toBe(true);
|
|
818
|
+
});
|
|
819
|
+
expect(onTableSettingsChanged).toHaveBeenCalledExactlyOnceWith(expect.objectContaining({
|
|
820
|
+
tableSpacing: TABLE_SPACING.L,
|
|
821
|
+
}));
|
|
822
|
+
|
|
823
|
+
const columnBordersCheckbox = screen.getByLabelText('Column borders');
|
|
824
|
+
await userEvent.click(columnBordersCheckbox);
|
|
825
|
+
|
|
826
|
+
expect(onTableSettingsChanged).toHaveBeenCalledTimes(2);
|
|
827
|
+
expect(onTableSettingsChanged).toHaveBeenNthCalledWith(2, expect.objectContaining({ hasColumnBorders: true }));
|
|
828
|
+
});
|
|
829
|
+
|
|
830
|
+
test('resetSettings is called appropriately', async () => {
|
|
831
|
+
const onTableSettingsReset = vi.fn();
|
|
832
|
+
|
|
833
|
+
render(
|
|
834
|
+
<Table
|
|
835
|
+
headerContent={<TableSettingsDropdown />}
|
|
836
|
+
onTableSettingsReset={onTableSettingsReset}
|
|
837
|
+
/>,
|
|
838
|
+
);
|
|
839
|
+
|
|
840
|
+
await userEvent.click(screen.getByRole('button', { name: /Table settings/i }));
|
|
841
|
+
|
|
842
|
+
const largeRadio = screen.getByLabelText('Large');
|
|
843
|
+
await userEvent.click(largeRadio);
|
|
844
|
+
|
|
845
|
+
await waitFor(() => {
|
|
846
|
+
expect((largeRadio as HTMLInputElement).checked).toBe(true);
|
|
847
|
+
});
|
|
848
|
+
|
|
849
|
+
// Click reset button
|
|
850
|
+
const resetButton = screen.getByRole('button', { name: /Reset Table Settings/i });
|
|
851
|
+
await userEvent.click(resetButton);
|
|
852
|
+
|
|
853
|
+
expect(onTableSettingsReset).toHaveBeenCalledOnce();
|
|
854
|
+
});
|
|
412
855
|
});
|
|
@@ -2,7 +2,7 @@ import { AllEnterpriseModule, ModuleRegistry, type GridApi } from 'ag-grid-enter
|
|
|
2
2
|
import { AgGridReact, type AgGridReactProps } from 'ag-grid-react';
|
|
3
3
|
import { tableTheme } from './tableTheme';
|
|
4
4
|
import classNames from 'classnames';
|
|
5
|
-
import { useState, type ReactNode } from 'react';
|
|
5
|
+
import { createContext, useState, type ReactNode } from 'react';
|
|
6
6
|
import { TableFooter } from './TableFooter';
|
|
7
7
|
import { TableHeader } from './TableHeader';
|
|
8
8
|
import { GridApiContext } from './GridApiContext';
|
|
@@ -12,6 +12,7 @@ import { PaginationControls } from './pagination/PaginationControls';
|
|
|
12
12
|
import { RowCountInfo } from './pagination/RowCountInfo';
|
|
13
13
|
import { BulkActionsDropdown } from './BulkActionsDropdown';
|
|
14
14
|
import { HideColumnsDropdown } from './HideColumnsDropdown';
|
|
15
|
+
import { useTableSettings, type TableSettings } from './useTableSettings';
|
|
15
16
|
|
|
16
17
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
17
18
|
type TableProps<TData = any> = {
|
|
@@ -22,10 +23,29 @@ type TableProps<TData = any> = {
|
|
|
22
23
|
'footerTestId'?: string;
|
|
23
24
|
'headerContent'?: ReactNode;
|
|
24
25
|
'headerTestId'?: string;
|
|
26
|
+
'onTableSettingsChanged'?: (val: TableSettings) => void;
|
|
27
|
+
'onTableSettingsReset'?: () => void;
|
|
25
28
|
} & AgGridReactProps<TData>;
|
|
26
29
|
|
|
27
30
|
ModuleRegistry.registerModules([AllEnterpriseModule]);
|
|
28
31
|
|
|
32
|
+
export enum TABLE_SPACING {
|
|
33
|
+
XS = 'XS',
|
|
34
|
+
S = 'S',
|
|
35
|
+
M = 'M',
|
|
36
|
+
L = 'L',
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
export const TableSettingsContext = createContext<{ settings: TableSettings; resetSettings: () => void }>({
|
|
40
|
+
settings: {
|
|
41
|
+
hasColumnBorders: false,
|
|
42
|
+
setHasColumnBorders: () => {},
|
|
43
|
+
tableSpacing: TABLE_SPACING.S,
|
|
44
|
+
setTableSpacing: () => {},
|
|
45
|
+
},
|
|
46
|
+
resetSettings: () => {},
|
|
47
|
+
});
|
|
48
|
+
|
|
29
49
|
export const Table = (props: TableProps) => {
|
|
30
50
|
const {
|
|
31
51
|
'data-testid': testId,
|
|
@@ -36,6 +56,8 @@ export const Table = (props: TableProps) => {
|
|
|
36
56
|
footerContent,
|
|
37
57
|
footerTestId,
|
|
38
58
|
onGridReady,
|
|
59
|
+
onTableSettingsChanged,
|
|
60
|
+
onTableSettingsReset,
|
|
39
61
|
...rest
|
|
40
62
|
} = props;
|
|
41
63
|
|
|
@@ -43,31 +65,54 @@ export const Table = (props: TableProps) => {
|
|
|
43
65
|
|
|
44
66
|
const [searchValue, setSearchValue] = useState('');
|
|
45
67
|
|
|
68
|
+
const { settings, resetSettings } = useTableSettings({
|
|
69
|
+
onTableSettingsChanged,
|
|
70
|
+
onTableSettingsReset,
|
|
71
|
+
});
|
|
72
|
+
|
|
73
|
+
const { hasColumnBorders, tableSpacing } = settings;
|
|
74
|
+
|
|
46
75
|
return (
|
|
47
76
|
<GridApiContext.Provider value={gridApi}>
|
|
48
|
-
<
|
|
49
|
-
{
|
|
50
|
-
|
|
51
|
-
{
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
77
|
+
<TableSettingsContext.Provider value={{ settings, resetSettings }}>
|
|
78
|
+
<section data-testid={testId} className={classNames('ds-table__container', wrapperClassName)}>
|
|
79
|
+
{headerContent && (
|
|
80
|
+
<TableHeader data-testid={headerTestId} hasSearch={hasSearch} searchValue={searchValue} setSearchValue={setSearchValue}>
|
|
81
|
+
{headerContent}
|
|
82
|
+
</TableHeader>
|
|
83
|
+
)}
|
|
84
|
+
<AgGridReact
|
|
85
|
+
theme={tableTheme.withParams({
|
|
86
|
+
headerRowBorder: hasColumnBorders,
|
|
87
|
+
rowBorder: hasColumnBorders,
|
|
88
|
+
wrapperBorder: hasColumnBorders,
|
|
89
|
+
columnBorder: hasColumnBorders,
|
|
90
|
+
spacing: {
|
|
91
|
+
// These are offset by one from the usual spacing tokens. We still use the token values to make spacing
|
|
92
|
+
// consistent with other parts of the DS, but --spacing-xsmall was too large for xsmall spacing, and so on
|
|
93
|
+
// for the other tokens
|
|
94
|
+
[TABLE_SPACING.XS]: 0,
|
|
95
|
+
[TABLE_SPACING.S]: 'var(--spacing-xsmall)',
|
|
96
|
+
[TABLE_SPACING.M]: 'var(--spacing-small)',
|
|
97
|
+
[TABLE_SPACING.L]: 'var(--spacing-medium)',
|
|
98
|
+
}[tableSpacing],
|
|
99
|
+
})}
|
|
100
|
+
onGridReady={(event) => {
|
|
101
|
+
const { api } = event;
|
|
102
|
+
setGridApi(api);
|
|
103
|
+
onGridReady?.(event);
|
|
104
|
+
}}
|
|
105
|
+
suppressPaginationPanel
|
|
106
|
+
{...rest}
|
|
107
|
+
{...(hasSearch && { quickFilterText: searchValue })}
|
|
108
|
+
/>
|
|
109
|
+
{footerContent && (
|
|
110
|
+
<TableFooter data-testid={footerTestId}>
|
|
111
|
+
{footerContent}
|
|
112
|
+
</TableFooter>
|
|
113
|
+
)}
|
|
114
|
+
</section>
|
|
115
|
+
</TableSettingsContext.Provider>
|
|
71
116
|
</GridApiContext.Provider>
|
|
72
117
|
);
|
|
73
118
|
};
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
import { Button } from 'Components/button/Button';
|
|
2
|
+
import { Dropdown } from 'Components/dropdown/Dropdown';
|
|
3
|
+
import { CheckboxGroup } from 'Components/formField/inputs/checkbox/CheckboxGroup';
|
|
4
|
+
import { RadioButtonGroup } from 'Components/formField/inputs/radio/RadioButtonGroup';
|
|
5
|
+
import { Separator } from 'Components/separator/Separator';
|
|
6
|
+
import { useContext, useState, type ChangeEvent } from 'react';
|
|
7
|
+
import { TABLE_SPACING, TableSettingsContext } from '../Table';
|
|
8
|
+
|
|
9
|
+
const TABLE_SPACING_NAMES = {
|
|
10
|
+
XS: 'X-Small',
|
|
11
|
+
S: 'Small',
|
|
12
|
+
M: 'Medium',
|
|
13
|
+
L: 'Large',
|
|
14
|
+
};
|
|
15
|
+
|
|
16
|
+
export const TableSettingsDropdown = () => {
|
|
17
|
+
const {
|
|
18
|
+
settings: {
|
|
19
|
+
hasColumnBorders,
|
|
20
|
+
setHasColumnBorders,
|
|
21
|
+
tableSpacing,
|
|
22
|
+
setTableSpacing,
|
|
23
|
+
},
|
|
24
|
+
resetSettings,
|
|
25
|
+
} = useContext(TableSettingsContext);
|
|
26
|
+
|
|
27
|
+
const [cellColours, setCellColours] = useState<boolean>(false);
|
|
28
|
+
|
|
29
|
+
return (
|
|
30
|
+
<Dropdown>
|
|
31
|
+
<Dropdown.Trigger>
|
|
32
|
+
<Button
|
|
33
|
+
variant="secondary"
|
|
34
|
+
iconRightName="settings"
|
|
35
|
+
iconRightScreenReaderText="Table settings"
|
|
36
|
+
borderless
|
|
37
|
+
/>
|
|
38
|
+
</Dropdown.Trigger>
|
|
39
|
+
<Dropdown.Content>
|
|
40
|
+
<RadioButtonGroup
|
|
41
|
+
legend="Table spacing"
|
|
42
|
+
options={Object.values(TABLE_SPACING).map((option) => {
|
|
43
|
+
return {
|
|
44
|
+
name: 'ds-table-spacing',
|
|
45
|
+
label: TABLE_SPACING_NAMES[option],
|
|
46
|
+
value: option,
|
|
47
|
+
};
|
|
48
|
+
})}
|
|
49
|
+
name="ds-table-spacing"
|
|
50
|
+
checkedValue={tableSpacing}
|
|
51
|
+
onChange={(e: ChangeEvent<HTMLInputElement>) => {
|
|
52
|
+
setTableSpacing(e.target.value as TABLE_SPACING);
|
|
53
|
+
}}
|
|
54
|
+
/>
|
|
55
|
+
|
|
56
|
+
<Separator />
|
|
57
|
+
|
|
58
|
+
<CheckboxGroup
|
|
59
|
+
legend="Style"
|
|
60
|
+
options={[
|
|
61
|
+
{
|
|
62
|
+
label: 'Column borders',
|
|
63
|
+
checked: hasColumnBorders,
|
|
64
|
+
onChange: () => {
|
|
65
|
+
setHasColumnBorders(!hasColumnBorders);
|
|
66
|
+
},
|
|
67
|
+
},
|
|
68
|
+
{
|
|
69
|
+
label: 'Cell colours',
|
|
70
|
+
checked: cellColours,
|
|
71
|
+
onChange: () => {
|
|
72
|
+
setCellColours(!cellColours);
|
|
73
|
+
},
|
|
74
|
+
},
|
|
75
|
+
]}
|
|
76
|
+
/>
|
|
77
|
+
|
|
78
|
+
<Separator />
|
|
79
|
+
|
|
80
|
+
<Button
|
|
81
|
+
variant="tertiary"
|
|
82
|
+
iconLeftName="redo"
|
|
83
|
+
onClick={resetSettings}
|
|
84
|
+
>
|
|
85
|
+
Reset Table Settings
|
|
86
|
+
</Button>
|
|
87
|
+
</Dropdown.Content>
|
|
88
|
+
</Dropdown>
|
|
89
|
+
);
|
|
90
|
+
};
|