@arbor-education/design-system.components 4.6.1 → 4.6.3

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.
Files changed (30) hide show
  1. package/.github/workflows/chromatic.yml +1 -1
  2. package/.nvmrc +1 -1
  3. package/CHANGELOG.md +12 -0
  4. package/dist/components/datePicker/DatePicker.d.ts +2 -0
  5. package/dist/components/datePicker/DatePicker.d.ts.map +1 -1
  6. package/dist/components/datePicker/DatePicker.js +2 -2
  7. package/dist/components/datePicker/DatePicker.js.map +1 -1
  8. package/dist/components/datePicker/DatePicker.stories.d.ts +18 -0
  9. package/dist/components/datePicker/DatePicker.stories.d.ts.map +1 -1
  10. package/dist/components/datePicker/DatePicker.stories.js +30 -8
  11. package/dist/components/datePicker/DatePicker.stories.js.map +1 -1
  12. package/dist/components/datePicker/DatePicker.test.js +9 -1
  13. package/dist/components/datePicker/DatePicker.test.js.map +1 -1
  14. package/dist/components/dateTimePicker/DateTimePicker.d.ts +2 -0
  15. package/dist/components/dateTimePicker/DateTimePicker.d.ts.map +1 -1
  16. package/dist/components/dateTimePicker/DateTimePicker.js +2 -2
  17. package/dist/components/dateTimePicker/DateTimePicker.js.map +1 -1
  18. package/dist/components/dateTimePicker/DateTimePicker.stories.d.ts +18 -0
  19. package/dist/components/dateTimePicker/DateTimePicker.stories.d.ts.map +1 -1
  20. package/dist/components/dateTimePicker/DateTimePicker.stories.js +32 -9
  21. package/dist/components/dateTimePicker/DateTimePicker.stories.js.map +1 -1
  22. package/dist/components/dateTimePicker/DateTimePicker.test.js +9 -1
  23. package/dist/components/dateTimePicker/DateTimePicker.test.js.map +1 -1
  24. package/package.json +1 -1
  25. package/src/components/datePicker/DatePicker.stories.tsx +30 -3
  26. package/src/components/datePicker/DatePicker.test.tsx +15 -0
  27. package/src/components/datePicker/DatePicker.tsx +6 -0
  28. package/src/components/dateTimePicker/DateTimePicker.stories.tsx +32 -1
  29. package/src/components/dateTimePicker/DateTimePicker.test.tsx +15 -0
  30. package/src/components/dateTimePicker/DateTimePicker.tsx +6 -0
@@ -315,6 +315,20 @@ const meta = {
315
315
  type: { summary: 'string' },
316
316
  },
317
317
  },
318
+ 'aria-label': {
319
+ control: 'text',
320
+ description: 'Accessible name for the input when used outside `<FormField>`. Use when there is no visible label.',
321
+ table: {
322
+ type: { summary: 'string' },
323
+ },
324
+ },
325
+ 'aria-labelledby': {
326
+ control: 'text',
327
+ description: 'ID of a visible element that names the input. Prefer this over `aria-label` when a visible label exists.',
328
+ table: {
329
+ type: { summary: 'string' },
330
+ },
331
+ },
318
332
  },
319
333
  } satisfies Meta<typeof DateTimePicker>;
320
334
 
@@ -364,6 +378,7 @@ const DisplayFormatDefaultTemplate = () => {
364
378
  value={value}
365
379
  onChange={setValue}
366
380
  id="format-default"
381
+ aria-label="Event start date and time"
367
382
  />
368
383
  <p style={{ margin: 'var(--spacing-small) 0 0', color: 'var(--color-grey-600)' }}>
369
384
  Value:
@@ -387,6 +402,7 @@ const DisplayFormatFriendlyTemplate = () => {
387
402
  value={value}
388
403
  onChange={setValue}
389
404
  id="format-friendly"
405
+ aria-label="Event start date and time"
390
406
  />
391
407
  <p style={{ margin: 'var(--spacing-small) 0 0', color: 'var(--color-grey-600)' }}>
392
408
  Value:
@@ -410,6 +426,7 @@ const WithTimeOptionsTemplate = () => {
410
426
  value={value}
411
427
  onChange={setValue}
412
428
  id="time-options"
429
+ aria-label="Appointment date and time"
413
430
  />
414
431
  <p style={{ margin: 'var(--spacing-small) 0 0', color: 'var(--color-grey-600)' }}>
415
432
  Appointment:
@@ -433,6 +450,7 @@ const GranularitySecondTemplate = () => {
433
450
  value={value}
434
451
  onChange={setValue}
435
452
  id="granularity-second"
453
+ aria-label="Precise date and time"
436
454
  />
437
455
  <p style={{ margin: 'var(--spacing-small) 0 0', color: 'var(--color-grey-600)' }}>
438
456
  Value (with seconds):
@@ -453,6 +471,7 @@ const ControlledWithDisplayTemplate = () => {
453
471
  <div style={{ maxWidth: '280px' }}>
454
472
  <DateTimePicker
455
473
  id="controlled-display"
474
+ aria-label="Event date and time"
456
475
  onChange={setValue}
457
476
  />
458
477
  <p style={{ margin: 'var(--spacing-small) 0 0', color: 'var(--color-grey-600)' }}>
@@ -528,7 +547,8 @@ const WithFormFieldAndErrorTemplate = () => {
528
547
  export const Default: Story = withDescription(
529
548
  {
530
549
  args: {
531
- id: 'default-datetime',
550
+ 'id': 'default-datetime',
551
+ 'aria-label': 'Event start date and time',
532
552
  },
533
553
  render: args => (
534
554
  <div style={{ maxWidth: '280px' }}>
@@ -551,6 +571,7 @@ export const WithDefaultValue: Story = withDescription(
551
571
  {/* 14 April 2026, 14:27 — month is zero-indexed (Apr = 3) */}
552
572
  <DateTimePicker
553
573
  id="default-value-datetime"
574
+ aria-label="Event start date and time"
554
575
  defaultValue={new Date(2026, 3, 14, 14, 27)}
555
576
  />
556
577
  </div>
@@ -570,6 +591,7 @@ function EditEventStart() {
570
591
  return (
571
592
  <DateTimePicker
572
593
  id="event-start"
594
+ aria-label="Event start date and time"
573
595
  defaultValue={eventStart}
574
596
  onChange={(date) => {
575
597
  // date is Date | undefined — not a string
@@ -611,6 +633,7 @@ function PreciseDateTimePickerExample() {
611
633
  value={value}
612
634
  onChange={setValue}
613
635
  id="precise-datetime"
636
+ aria-label="Precise date and time"
614
637
  />
615
638
  );
616
639
  }
@@ -648,6 +671,7 @@ function FormattedDateTimePickerExample() {
648
671
  value={value}
649
672
  onChange={setValue}
650
673
  id="event-datetime"
674
+ aria-label="Event start date and time"
651
675
  />
652
676
  );
653
677
  }
@@ -685,6 +709,7 @@ function FriendlyDateTimePickerExample() {
685
709
  value={value}
686
710
  onChange={setValue}
687
711
  id="event-datetime"
712
+ aria-label="Event start date and time"
688
713
  />
689
714
  );
690
715
  }
@@ -726,6 +751,7 @@ function AppointmentBookingExample() {
726
751
  value={value}
727
752
  onChange={setValue}
728
753
  id="appointment-datetime"
754
+ aria-label="Appointment date and time"
729
755
  />
730
756
  );
731
757
  }
@@ -748,6 +774,7 @@ export const WithPlaceholder: Story = withDescription(
748
774
  <div style={{ maxWidth: '280px' }}>
749
775
  <DateTimePicker
750
776
  id="placeholder-datetime"
777
+ aria-label="Event start date and time"
751
778
  placeholder="Choose event start"
752
779
  />
753
780
  </div>
@@ -764,6 +791,7 @@ function GuidedDateTimePickerExample() {
764
791
  return (
765
792
  <DateTimePicker
766
793
  id="event-start"
794
+ aria-label="Event start date and time"
767
795
  placeholder="Choose event start"
768
796
  onChange={(date) => {
769
797
  console.log('Event start:', date?.toLocaleString('en-GB'));
@@ -790,6 +818,7 @@ export const ErrorState: Story = withDescription(
790
818
  <div style={{ maxWidth: '280px' }}>
791
819
  <DateTimePicker
792
820
  id="error-state-datetime"
821
+ aria-label="Event start date and time"
793
822
  hasError
794
823
  aria-invalid={true}
795
824
  aria-describedby="error-state-datetime-msg"
@@ -818,6 +847,7 @@ function DateTimePickerWithError() {
818
847
  <>
819
848
  <DateTimePicker
820
849
  id="event-start"
850
+ aria-label="Event start date and time"
821
851
  hasError
822
852
  aria-invalid={true}
823
853
  aria-describedby="event-start-error"
@@ -860,6 +890,7 @@ function ControlledDateTimePickerExample() {
860
890
  <div>
861
891
  <DateTimePicker
862
892
  id="event-datetime"
893
+ aria-label="Event date and time"
863
894
  onChange={setValue}
864
895
  />
865
896
  <p>
@@ -27,6 +27,21 @@ describe('DateTimePicker', () => {
27
27
  expect(screen.getByRole('button', { name: 'Open date and time picker' })).toBeInTheDocument();
28
28
  });
29
29
 
30
+ test('names the input with aria-label', () => {
31
+ const { container } = render(<DateTimePicker aria-label="Start date" />);
32
+ expect(screen.getByLabelText('Start date')).toBe(container.querySelector('input[type="datetime-local"]'));
33
+ });
34
+
35
+ test('names the input with aria-labelledby', () => {
36
+ const { container } = render(
37
+ <>
38
+ <span id="start-date-label">Start date</span>
39
+ <DateTimePicker aria-labelledby="start-date-label" />
40
+ </>,
41
+ );
42
+ expect(screen.getByLabelText('Start date')).toBe(container.querySelector('input[type="datetime-local"]'));
43
+ });
44
+
30
45
  test('uses a native datetime-local input with minute stepping by default', () => {
31
46
  const { container } = render(<DateTimePicker />);
32
47
  const input = container.querySelector('input[type="datetime-local"]');
@@ -41,6 +41,8 @@ export type DateTimePickerProps = {
41
41
  'hasError'?: boolean;
42
42
  'aria-describedby'?: string;
43
43
  'aria-invalid'?: boolean;
44
+ 'aria-label'?: string;
45
+ 'aria-labelledby'?: string;
44
46
  'value'?: Date;
45
47
  'defaultValue'?: Date;
46
48
  'granularity'?: TimeGranularity;
@@ -59,6 +61,8 @@ export const DateTimePicker = (props: DateTimePickerProps) => {
59
61
  hasError,
60
62
  'aria-describedby': ariaDescribedBy,
61
63
  'aria-invalid': ariaInvalid,
64
+ 'aria-label': ariaLabel,
65
+ 'aria-labelledby': ariaLabelledBy,
62
66
  value,
63
67
  defaultValue,
64
68
  displayFormat = 'native',
@@ -258,6 +262,8 @@ export const DateTimePicker = (props: DateTimePickerProps) => {
258
262
  hasError={hasError}
259
263
  aria-describedby={ariaDescribedBy}
260
264
  aria-invalid={ariaInvalid}
265
+ aria-label={ariaLabel}
266
+ aria-labelledby={ariaLabelledBy}
261
267
  className="ds-date-time-picker__input"
262
268
  />
263
269
  {showFieldHint