@godxjp/ui 20.2.1 → 22.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (141) hide show
  1. package/dist/app/app-provider.js +2 -1
  2. package/dist/components/data-display/badge.d.ts +28 -1
  3. package/dist/components/data-display/badge.js +2 -0
  4. package/dist/components/data-display/chat-bubble.d.ts +30 -0
  5. package/dist/components/data-display/chat-bubble.js +229 -0
  6. package/dist/components/data-display/data-table.d.ts +18 -2
  7. package/dist/components/data-display/data-table.js +4 -0
  8. package/dist/components/data-display/descriptions.js +4 -1
  9. package/dist/components/data-display/index.d.ts +5 -3
  10. package/dist/components/data-display/index.js +5 -2
  11. package/dist/components/data-display/popover.d.ts +19 -1
  12. package/dist/components/data-display/popover.js +12 -3
  13. package/dist/components/data-display/progress.d.ts +37 -0
  14. package/dist/components/data-display/progress.js +57 -5
  15. package/dist/components/data-display/scroll-area.js +26 -1
  16. package/dist/components/data-display/tree.d.ts +8 -0
  17. package/dist/components/data-display/tree.js +426 -0
  18. package/dist/components/data-entry/chat-composer.d.ts +50 -0
  19. package/dist/components/data-entry/chat-composer.js +163 -0
  20. package/dist/components/data-entry/chat-suggestion.d.ts +28 -0
  21. package/dist/components/data-entry/chat-suggestion.js +285 -0
  22. package/dist/components/data-entry/date-picker.d.ts +10 -3
  23. package/dist/components/data-entry/date-picker.js +503 -238
  24. package/dist/components/data-entry/form-field.d.ts +1 -1
  25. package/dist/components/data-entry/form-field.js +4 -1
  26. package/dist/components/data-entry/form.js +10 -1
  27. package/dist/components/data-entry/index.d.ts +4 -6
  28. package/dist/components/data-entry/index.js +4 -6
  29. package/dist/components/data-entry/label.d.ts +14 -1
  30. package/dist/components/data-entry/label.js +6 -1
  31. package/dist/components/data-entry/radio.d.ts +27 -6
  32. package/dist/components/data-entry/radio.js +88 -43
  33. package/dist/components/data-entry/search-select.js +8 -1
  34. package/dist/components/data-entry/select.js +2 -0
  35. package/dist/components/data-entry/switch.d.ts +6 -3
  36. package/dist/components/data-entry/switch.js +34 -11
  37. package/dist/components/data-entry/textarea.js +3 -1
  38. package/dist/components/data-entry/tree-utils.d.ts +10 -48
  39. package/dist/components/data-entry/tree-utils.js +1 -154
  40. package/dist/components/layout/mobile-shell.d.ts +1 -1
  41. package/dist/components/layout/mobile-shell.js +2 -0
  42. package/dist/components/navigation/menubar.d.ts +10 -3
  43. package/dist/components/navigation/steps.d.ts +1 -1
  44. package/dist/components/navigation/steps.js +3 -1
  45. package/dist/components/navigation/tabs-scroll.d.ts +27 -0
  46. package/dist/components/navigation/tabs-scroll.js +52 -1
  47. package/dist/components/navigation/tabs.d.ts +2 -2
  48. package/dist/components/navigation/tabs.js +88 -23
  49. package/dist/components/ui/index.d.ts +0 -1
  50. package/dist/components/ui/index.js +0 -1
  51. package/dist/components/ui/segmented.d.ts +15 -1
  52. package/dist/components/ui/segmented.js +13 -6
  53. package/dist/i18n/messages/en.json +48 -2
  54. package/dist/i18n/messages/ja.json +46 -2
  55. package/dist/i18n/messages/vi.json +47 -2
  56. package/dist/lib/datetime/picker-format.d.ts +18 -0
  57. package/dist/lib/datetime/picker-format.js +35 -1
  58. package/dist/lib/field-a11y.d.ts +12 -0
  59. package/dist/lib/field-a11y.js +14 -1
  60. package/dist/lib/tree.d.ts +53 -0
  61. package/dist/lib/tree.js +155 -0
  62. package/dist/props/components/data-display.prop.d.ts +194 -1
  63. package/dist/props/components/data-entry.prop.d.ts +307 -99
  64. package/dist/props/components/index.d.ts +1 -1
  65. package/dist/props/components/layout.prop.d.ts +12 -1
  66. package/dist/props/components/navigation.prop.d.ts +76 -1
  67. package/dist/props/registry.d.ts +156 -19
  68. package/dist/props/registry.js +218 -18
  69. package/dist/props/vocabulary/data.prop.d.ts +12 -0
  70. package/dist/props/vocabulary/index.d.ts +2 -2
  71. package/dist/props/vocabulary/layout.prop.d.ts +11 -0
  72. package/dist/styles/badge-layout.css +4 -0
  73. package/dist/styles/card-layout.css +6 -6
  74. package/dist/styles/control.css +22 -6
  75. package/dist/styles/data-display-layout.css +385 -68
  76. package/dist/styles/data-entry-layout.css +64 -0
  77. package/dist/styles/focus-ring.css +4 -2
  78. package/dist/styles/navigation-layout.css +25 -0
  79. package/dist/styles/shell-layout.css +7 -1
  80. package/dist/styles/table-layout.css +34 -0
  81. package/dist/tokens/base.css +3 -0
  82. package/dist/tokens/components/chat-bubble.css +36 -0
  83. package/dist/tokens/components/chat-composer.css +19 -0
  84. package/dist/tokens/components/data-display.css +9 -6
  85. package/dist/tokens/components/descriptions.css +4 -0
  86. package/dist/tokens/components/navigation.css +6 -0
  87. package/dist/tokens/components/segmented.css +0 -2
  88. package/dist/tokens/components/shell.css +3 -0
  89. package/dist/tokens/components/table.css +3 -0
  90. package/dist/tokens/components/tree.css +27 -0
  91. package/dist/tokens/foundation.css +7 -0
  92. package/docs/COMPONENTS.md +14 -14
  93. package/docs/CONSUMER-RULES.md +24 -1
  94. package/docs/FRAME-COVERAGE-LEDGER.md +1 -1
  95. package/docs/FRAME-COVERAGE-REPORT.md +9 -7
  96. package/docs/TOKENS.md +65 -0
  97. package/docs/data-display/badge.tsx +37 -0
  98. package/docs/data-display/chat-bubble.tsx +397 -0
  99. package/docs/data-display/data-table/index.tsx +18 -0
  100. package/docs/data-display/popover.tsx +41 -1
  101. package/docs/data-display/progress.tsx +28 -0
  102. package/docs/data-display/timeline.tsx +46 -0
  103. package/docs/data-display/tree.tsx +394 -0
  104. package/docs/data-entry/calendar.tsx +2 -2
  105. package/docs/data-entry/chat-composer.tsx +464 -0
  106. package/docs/data-entry/chat-suggestion.tsx +301 -0
  107. package/docs/data-entry/date-picker.tsx +143 -3
  108. package/docs/data-entry/form/examples/invoice-form.tsx +2 -2
  109. package/docs/data-entry/form-field/examples/a11y-contract.tsx +3 -5
  110. package/docs/data-entry/form.tsx +4 -4
  111. package/docs/data-entry/number-input.tsx +31 -0
  112. package/docs/data-entry/segmented.tsx +103 -1
  113. package/docs/layout/mobile-shell.tsx +5 -0
  114. package/docs/navigation/tabs.tsx +149 -0
  115. package/docs/roadmap/ai-chat-components.md +207 -0
  116. package/docs/roadmap/antd-parity.md +155 -0
  117. package/docs/roadmap/badge-tag-chip-count.md +172 -0
  118. package/docs/roadmap/list-masonry.md +159 -0
  119. package/docs/roadmap/parity-audit-data-display-feedback.md +567 -0
  120. package/docs/roadmap/parity-audit-data-entry.md +357 -0
  121. package/docs/roadmap/parity-audit-layout-navigation-general.md +464 -0
  122. package/docs/roadmap/parity-backlog.md +78 -0
  123. package/docs/roadmap/tree-components.md +151 -0
  124. package/docs/showcase/acme-portal.tsx +7 -0
  125. package/docs/showcase/table-tree-rows.tsx +4 -4
  126. package/package.json +13 -23
  127. package/scripts/ui-audit.mjs +17 -4
  128. package/dist/components/data-display/tree-list.d.ts +0 -13
  129. package/dist/components/data-display/tree-list.js +0 -26
  130. package/dist/components/data-entry/date-range-picker.d.ts +0 -11
  131. package/dist/components/data-entry/date-range-picker.js +0 -349
  132. package/dist/components/data-entry/month-picker.d.ts +0 -10
  133. package/dist/components/data-entry/month-picker.js +0 -241
  134. package/dist/components/data-entry/month-range-picker.d.ts +0 -10
  135. package/dist/components/data-entry/month-range-picker.js +0 -301
  136. package/dist/components/ui/date-range-picker.d.ts +0 -1
  137. package/dist/components/ui/date-range-picker.js +0 -2
  138. package/docs/data-display/tree-list.tsx +0 -107
  139. package/docs/data-entry/date-range-picker.tsx +0 -175
  140. package/docs/data-entry/month-picker.tsx +0 -101
  141. package/docs/data-entry/month-range-picker.tsx +0 -115
@@ -1,8 +1,5 @@
1
1
  /** Data Entry component prop types — @see docs/COMPONENTS.md#data-entry */
2
- import type * as CheckboxPrimitive from "@radix-ui/react-checkbox";
3
- import type * as RadioGroupPrimitive from "@radix-ui/react-radio-group";
4
2
  import type * as SliderPrimitive from "@radix-ui/react-slider";
5
- import type * as SwitchPrimitive from "@radix-ui/react-switch";
6
3
  import type { RenderProps as InputOTPRenderProps } from "input-otp";
7
4
  import type { DayPickerProps } from "react-day-picker";
8
5
  import type { DateRange } from "react-day-picker";
@@ -285,6 +282,22 @@ export type FormFieldProp = {
285
282
  label: LabelProp;
286
283
  required?: RequiredProp;
287
284
  helper?: HelperProp;
285
+ /**
286
+ * Which side of the control the helper line sits on — `after` (default, under the input) or
287
+ * `before` (between the label and the input).
288
+ *
289
+ * `before` is for a helper the reader needs BEFORE they answer rather than after: the
290
+ * secondary language of a bilingual form, a unit or format note, a pick-one-of-these
291
+ * preamble. `labelAddon` cannot carry that — it is an inline row beside the label with no
292
+ * wrap, sized for a chip or a help button, so a full sentence squeezes the label instead of
293
+ * taking its own line. Putting the second line inside `label` does work, but costs the
294
+ * string-label fallbacks (`aria-label`, `FieldNameContext`), which fire only when `label` is
295
+ * a plain string.
296
+ *
297
+ * Paint only: the helper keeps its id and stays on the control's `aria-describedby`, so this
298
+ * never changes what a screen reader reads or the order it reads it in.
299
+ */
300
+ helperPlacement?: "before" | "after";
288
301
  error?: ErrorProp;
289
302
  validateStatus?: "success" | "warning" | "error" | "validating";
290
303
  hasFeedback?: boolean;
@@ -316,6 +329,22 @@ export type FormFieldProp = {
316
329
  label: LabelProp;
317
330
  required?: RequiredProp;
318
331
  helper?: HelperProp;
332
+ /**
333
+ * Which side of the control the helper line sits on — `after` (default, under the input) or
334
+ * `before` (between the label and the input).
335
+ *
336
+ * `before` is for a helper the reader needs BEFORE they answer rather than after: the
337
+ * secondary language of a bilingual form, a unit or format note, a pick-one-of-these
338
+ * preamble. `labelAddon` cannot carry that — it is an inline row beside the label with no
339
+ * wrap, sized for a chip or a help button, so a full sentence squeezes the label instead of
340
+ * taking its own line. Putting the second line inside `label` does work, but costs the
341
+ * string-label fallbacks (`aria-label`, `FieldNameContext`), which fire only when `label` is
342
+ * a plain string.
343
+ *
344
+ * Paint only: the helper keeps its id and stays on the control's `aria-describedby`, so this
345
+ * never changes what a screen reader reads or the order it reads it in.
346
+ */
347
+ helperPlacement?: "before" | "after";
319
348
  error?: ErrorProp;
320
349
  validateStatus?: "success" | "warning" | "error" | "validating";
321
350
  hasFeedback?: boolean;
@@ -386,8 +415,20 @@ export type SearchInputProp = FieldA11yProps & {
386
415
  /** Chrome level — antd `variant`. Default `outlined`. */
387
416
  variant?: ControlVariantProp;
388
417
  };
389
- /** @see Checkbox — extends Radix checkbox root props. */
390
- export type CheckboxProp = React.ComponentPropsWithoutRef<typeof CheckboxPrimitive.Root> & {
418
+ /**
419
+ * @see Checkbox
420
+ *
421
+ * Public shape unchanged from the @radix-ui/react-checkbox era — `checked` / `defaultChecked` take
422
+ * the tri-state `"indeterminate"`, `onCheckedChange` reports it back, and `disabled` / `required`
423
+ * keep their HTML spelling. checkbox.tsx translates all of it to react-aria's `isSelected` /
424
+ * `isIndeterminate` / `onChange` / `isDisabled`; none of those names reach a consumer. Written out
425
+ * here rather than derived from a primitive that the component no longer uses.
426
+ */
427
+ export type CheckboxProp = Omit<React.ComponentPropsWithoutRef<"button">, "checked" | "defaultChecked" | "onChange"> & {
428
+ checked?: boolean | "indeterminate";
429
+ defaultChecked?: boolean | "indeterminate";
430
+ onCheckedChange?: (checked: boolean | "indeterminate") => void;
431
+ required?: boolean;
391
432
  /**
392
433
  * antd `indeterminate` — paint the PARTIAL mark (a dash) without changing `checked`. Radix
393
434
  * spells the same state as `checked="indeterminate"`; this is the antd spelling of it, and the
@@ -442,10 +483,30 @@ export type RadioGroupProp = FieldA11yProps & {
442
483
  export type RadioOptionTypeProp = "default" | "button";
443
484
  /** antd `RadioGroupButtonStyle` — the selected button is outlined, or filled with the brand. */
444
485
  export type RadioButtonStyleProp = "outline" | "solid";
445
- /** @see Radio.Item — Radix radio group item. */
446
- export type RadioProp = React.ComponentPropsWithoutRef<typeof RadioGroupPrimitive.Item>;
447
- /** @see Switch — extends Radix switch root props. */
448
- export type SwitchProp = React.ComponentPropsWithoutRef<typeof SwitchPrimitive.Root> & {
486
+ /**
487
+ * @see Radio.Item
488
+ *
489
+ * Public shape unchanged from the @radix-ui/react-radio-group era — `value` / `disabled` keep
490
+ * their HTML spelling; react-aria's `isDisabled` never reaches a consumer.
491
+ */
492
+ export type RadioProp = Omit<React.ComponentPropsWithoutRef<"button">, "value"> & {
493
+ value: string;
494
+ };
495
+ /**
496
+ * @see Switch
497
+ *
498
+ * The PUBLIC shape is unchanged from the @radix-ui/react-switch era — `checked` /
499
+ * `defaultChecked` / `onCheckedChange` / `disabled` / `required` keep their HTML spelling.
500
+ * react-aria-components spells the same five `isSelected` / `defaultSelected` / `onChange` /
501
+ * `isDisabled`, and that translation happens inside `switch.tsx`; none of those names reach a
502
+ * consumer. Written out here rather than derived from a primitive so the surface stops moving
503
+ * whenever the base does.
504
+ */
505
+ export type SwitchProp = Omit<React.ComponentPropsWithoutRef<"button">, "checked" | "defaultChecked" | "onChange" | "value"> & {
506
+ checked?: boolean;
507
+ defaultChecked?: boolean;
508
+ onCheckedChange?: (checked: boolean) => void;
509
+ required?: boolean;
449
510
  size?: "sm" | "md";
450
511
  /**
451
512
  * antd `loading` — the toggle is mid-flight: a spinner replaces the thumb glyph and the control
@@ -579,28 +640,90 @@ export type PickerChromeProp = {
579
640
  };
580
641
  /** date-fns pattern, Intl options (including Japanese era), or a display function. */
581
642
  export type PickerDateFormatProp = string | Intl.DateTimeFormatOptions | ((date: Date) => string);
582
- /** @see DatePicker */
643
+ /**
644
+ * @see DatePicker — ONE date control for every date-shaped question this library used to ask with
645
+ * four components (`DatePicker`, `DateRangePicker`, `MonthPicker`, `MonthRangePicker`).
646
+ *
647
+ * Two axes, both antd's: `picker` chooses the GRANULARITY of a selection, `range` chooses its
648
+ * CARDINALITY. Everything else — bounds, disabling, formatting, clearing, the open triad, the
649
+ * chrome ladder — is written once and therefore behaves the same on all eight combinations.
650
+ *
651
+ * ON THE NAME `picker`. It is antd's own prop name for this axis, and it already shipped here with
652
+ * exactly this union, so keeping it renames nothing and breaks no call site. (`granularity` is
653
+ * react-aria's spelling; this cluster is not on react-aria.) The house rule stated on `TreeProp` —
654
+ * map Ant's KEY-SHAPED names onto this package's controlled vocabulary and do not re-spell the
655
+ * rest — is what the surrounding props already do: `showTime`, `needConfirm`, `allowClear`,
656
+ * `cellRender`, `disabledDate`, `inputReadOnly`, `preserveInvalidOnBlur`, `renderExtraFooter`,
657
+ * `presets`, `order`, `minDate`/`maxDate` are all spelled antd's way, while selection is spelled
658
+ * `value`/`defaultValue`/`onValueChange` rather than antd's `onChange`.
659
+ */
583
660
  export type DatePickerBaseProp = FieldA11yProps & PickerChromeProp & {
584
661
  /** Display format; native submission remains ISO. */
585
662
  format?: PickerDateFormatProp;
586
663
  /** Parser for a custom display function or Intl era display; ISO always remains accepted. */
587
664
  parseFormat?: (text: string) => Date | undefined;
665
+ /**
666
+ * Selectable bounds, inclusive, at day precision (antd `minDate`/`maxDate`).
667
+ *
668
+ * These are the ONLY bounds props. `MonthPicker`/`MonthRangePicker` used to take
669
+ * `fromYear`/`toYear` numbers instead, which expressed strictly less (a whole year is the
670
+ * smallest thing they could say) and — measurably — clamped nothing: they only greyed the
671
+ * grid's year chevrons, while both routes into the value, the grid cells and the typed text,
672
+ * ignored them. `minDate`/`maxDate` are enforced on BOTH routes for every `picker`, so the
673
+ * keyboard is not a way around the rule the mouse obeys. Migration is mechanical:
674
+ * `fromYear={2024}` → `minDate={new Date(2024, 0, 1)}`, `toYear={2027}` →
675
+ * `maxDate={new Date(2027, 11, 31)}`.
676
+ */
588
677
  minDate?: Date;
589
678
  maxDate?: Date;
590
679
  showWeek?: boolean;
591
680
  needConfirm?: boolean;
681
+ /**
682
+ * Which period the PANEL opens on, independently of the value (antd `defaultPickerValue`, and
683
+ * like antd's it is RE-APPLIED every time the panel opens rather than only at mount).
684
+ *
685
+ * Without it a panel can only open on the value or on today, so "open on the fiscal year's
686
+ * start month" and "open on the month of the row being edited" have no expression — the two
687
+ * cases the parity audit files as P1. Only the period matters; the day is ignored.
688
+ */
689
+ defaultPickerValue?: Date;
690
+ /** Controlled panel period (antd `pickerValue`) — wins over `defaultPickerValue` and over the value. */
691
+ pickerValue?: Date;
692
+ /**
693
+ * GRANULARITY of one selection (antd `picker`). `date` picks a day from a month grid; `week`
694
+ * picks a day and normalises it to the locale's week start; `month`, `quarter` and `year` swap
695
+ * the day grid for a period grid and normalise to the period's first day.
696
+ *
697
+ * The emitted value is always a `Date` at the START of the chosen period, so a coarse
698
+ * selection interoperates with a fine one and with `DateRange`.
699
+ */
592
700
  picker?: "date" | "week" | "month" | "quarter" | "year";
701
+ /**
702
+ * Normalise the selection into ascending order (antd `order`; default `true`).
703
+ *
704
+ * ONE rule, applied to whichever value shape is in play: a `range` whose endpoints were picked
705
+ * backwards is SWAPPED, and a `multiple` selection is SORTED. The four split components spelled
706
+ * this two ways — `DatePicker.order` sorted an array, `DateRangePicker.order` swapped a pair,
707
+ * `MonthRangePicker` swapped unconditionally with no prop at all — which read as a collision
708
+ * but is one invariant seen through three value shapes. Set `false` to keep pick order.
709
+ */
593
710
  order?: boolean;
594
711
  showTime?: boolean | Pick<TimePickerProp, "hourStep" | "minuteStep" | "secondStep" | "showSeconds" | "use12Hours" | "disabledTime">;
595
- presets?: {
596
- label: React.ReactNode;
597
- value: Date | (() => Date);
598
- }[];
599
712
  placeholder?: PlaceholderProp;
600
- disabled?: DisabledProp;
713
+ /**
714
+ * Inert control. With `range`, the TUPLE form `[from, to]` locks one endpoint and leaves the
715
+ * other editable (antd's RangePicker `disabled`) — "the start date is fixed by the contract,
716
+ * only the end is negotiable" is a real screen that a scalar cannot say. The tuple is
717
+ * meaningless without `range` and is ignored there.
718
+ */
719
+ disabled?: DisabledProp | [boolean, boolean];
601
720
  className?: ClassNameProp;
602
721
  id?: IdProp;
603
- /** Form field name — emits the value as an ISO-8601 `yyyy-MM-dd` string for native submission. */
722
+ /**
723
+ * Form field name. Submits ISO-8601 at the precision `picker` selects — `2026-03-01` for
724
+ * `date`/`week`, `2026-03` for `month` and `quarter` (the period's first month), `2026` for
725
+ * `year`. With `range`, the pair submits as `${name}_from` / `${name}_to`.
726
+ */
604
727
  name?: NameProp;
605
728
  locale?: DayPickerProps["locale"];
606
729
  fromDate?: Date;
@@ -608,11 +731,11 @@ export type DatePickerBaseProp = FieldA11yProps & PickerChromeProp & {
608
731
  /** Decorate a day cell — 祝日, a booked day, a deadline. @see CalendarCellRenderProp */
609
732
  cellRender?: CalendarCellRenderProp;
610
733
  /**
611
- * Forbid individual dates by predicate — the rule `fromDate`/`toDate` cannot express, because a
734
+ * Forbid individual dates by predicate — the rule `minDate`/`maxDate` cannot express, because a
612
735
  * business calendar is rarely one contiguous range: 土日, a closed accounting period, a 祝日, a
613
736
  * day already fully booked.
614
737
  *
615
- * Applies to BOTH routes into the value. The calendar greys the cell out, and a date typed into
738
+ * Applies to BOTH routes into the value. The grid greys the cell out, and a date typed into
616
739
  * the field is rejected the same way an unparseable one is — otherwise the keyboard becomes a
617
740
  * way around the rule the mouse obeys.
618
741
  */
@@ -623,104 +746,50 @@ export type DatePickerBaseProp = FieldA11yProps & PickerChromeProp & {
623
746
  */
624
747
  allowClear?: AllowClearProp;
625
748
  } & Pick<CalendarFooterProp, "showToday" | "showClose">;
626
- /** Single and multiple selections keep their callback types distinct. */
749
+ /**
750
+ * CARDINALITY. One `Date`, an array of them, or a `DateRange` — each keeps its own callback type,
751
+ * so a consumer never has to narrow what it gets back.
752
+ */
627
753
  export type DatePickerProp = DatePickerBaseProp & ({
754
+ range?: false;
628
755
  multiple?: false;
629
756
  value?: Date;
630
757
  defaultValue?: Date;
631
758
  onValueChange?: (value: Date | undefined) => void;
759
+ presets?: {
760
+ label: React.ReactNode;
761
+ value: Date | (() => Date);
762
+ }[];
632
763
  } | {
764
+ range?: false;
633
765
  multiple: true;
634
766
  value?: Date[];
635
767
  defaultValue?: Date[];
636
768
  onValueChange?: (value: Date[] | undefined) => void;
637
769
  showTime?: false;
638
- });
639
- /** @see MonthPicker */
640
- export type MonthPickerProp = FieldA11yProps & PickerChromeProp & {
641
- value?: ValueProp<Date>;
642
- defaultValue?: DefaultValueProp<Date | undefined>;
643
- onValueChange?: OnValueChangeProp<Date | undefined>;
644
- placeholder?: PlaceholderProp;
645
- disabled?: DisabledProp;
646
- className?: ClassNameProp;
647
- id?: IdProp;
648
- /** Form field name — submits the display text (`yyyy/MM`). */
649
- name?: NameProp;
650
- /** Clamp the year navigation (inclusive). */
651
- fromYear?: number;
652
- toYear?: number;
653
- /**
654
- * Show an inline ✕ to clear the value when one is set (default true). The OBJECT form
655
- * additionally replaces the icon and/or the accessible label (antd `allowClear`).
656
- */
657
- allowClear?: AllowClearProp;
658
- /** Node appended below the month grid (antd `renderExtraFooter`). */
659
- renderExtraFooter?: () => React.ReactNode;
660
- };
661
- /**
662
- * @see MonthRangePicker — both edges are normalized to the FIRST day of their month
663
- * (the `DateRange` shape is shared with DateRangePicker so ranges interop).
664
- */
665
- export type MonthRangePickerProp = FieldA11yProps & PickerChromeProp & {
666
- value?: ValueProp<DateRange>;
667
- defaultValue?: DefaultValueProp<DateRange | undefined>;
668
- onValueChange?: OnValueChangeProp<DateRange | undefined>;
669
- placeholder?: PlaceholderProp;
670
- disabled?: DisabledProp;
671
- className?: ClassNameProp;
672
- id?: IdProp;
673
- /** Form field name — emits the range as `${name}_from` / `${name}_to` `yyyy/MM` fields. */
674
- name?: NameProp;
675
- /** Clamp the year navigation (inclusive). */
676
- fromYear?: number;
677
- toYear?: number;
770
+ presets?: {
771
+ label: React.ReactNode;
772
+ value: Date | (() => Date);
773
+ }[];
774
+ } | {
678
775
  /**
679
- * Show an inline to clear the range when one is set (default true). The OBJECT form
680
- * additionally replaces the icon and/or the accessible label (antd `allowClear`).
776
+ * Two endpoints in one field antd's `DatePicker.RangePicker`, which this library used to
777
+ * ship as two separate components (`DateRangePicker`, `MonthRangePicker`). It composes with
778
+ * `picker`, so a month range is `<DatePicker range picker="month" />`.
681
779
  */
682
- allowClear?: AllowClearProp;
683
- /** Node appended below the month grid (antd `renderExtraFooter`). */
684
- renderExtraFooter?: () => React.ReactNode;
685
- };
686
- /** @see DateRangePicker */
687
- export type DateRangePickerProp = FieldA11yProps & PickerChromeProp & {
688
- /** Display format; native submission remains ISO. */
689
- format?: PickerDateFormatProp;
690
- /** Parser for a custom display function or Intl era display; ISO always remains accepted. */
691
- parseFormat?: (text: string) => Date | undefined;
692
- minDate?: Date;
693
- maxDate?: Date;
694
- showWeek?: boolean;
695
- needConfirm?: boolean;
780
+ range: true;
781
+ multiple?: false;
782
+ value?: DateRange;
783
+ defaultValue?: DateRange;
784
+ onValueChange?: (value: DateRange | undefined) => void;
785
+ showTime?: false;
786
+ /** Which endpoints may stay empty (antd `allowEmpty`), as `[from, to]`. */
787
+ allowEmpty?: [boolean, boolean];
696
788
  presets?: {
697
789
  label: React.ReactNode;
698
790
  value: DateRange | (() => DateRange);
699
791
  }[];
700
- allowEmpty?: [boolean, boolean];
701
- order?: boolean;
702
- value?: ValueProp<DateRange>;
703
- defaultValue?: DefaultValueProp<DateRange | undefined>;
704
- onValueChange?: OnValueChangeProp<DateRange | undefined>;
705
- placeholder?: PlaceholderProp;
706
- disabled?: DisabledProp;
707
- className?: ClassNameProp;
708
- id?: IdProp;
709
- /** Form field name — emits the range as `${name}_from` / `${name}_to` ISO `yyyy-MM-dd` fields. */
710
- name?: NameProp;
711
- locale?: DayPickerProps["locale"];
712
- fromDate?: Date;
713
- toDate?: Date;
714
- /** Decorate a day cell — see `CalendarCellRenderProp`. */
715
- cellRender?: CalendarCellRenderProp;
716
- /** Forbid individual dates by predicate — see `DatePickerProp.disabledDate`. */
717
- disabledDate?: (date: Date) => boolean;
718
- /**
719
- * antd `allowClear` — an inline ✕ that clears the range when one is set (default true). The
720
- * OBJECT form additionally replaces the icon and/or the accessible label.
721
- */
722
- allowClear?: AllowClearProp;
723
- } & Pick<CalendarFooterProp, "showToday" | "showClose">;
792
+ });
724
793
  /**
725
794
  * Which times a TimePicker refuses, in antd's shape: one call returns the two predicates, so a
726
795
  * consumer computing them from the same source (a start time, a shift window) does that work once
@@ -889,6 +958,18 @@ export type SearchSelectBaseProp = {
889
958
  readOnly?: boolean;
890
959
  /** Trigger height tier — forwarded to the underlying Button. Default matches Button's own default. */
891
960
  size?: SizeProp;
961
+ /**
962
+ * Trigger width, the SAME axis `SelectTrigger` carries on the compound API — `full` (default,
963
+ * the width a field wants), `auto` (the width the current label wants), `bounded` (one width
964
+ * from `--control-bounded-width`, for a trigger whose value varies in length).
965
+ *
966
+ * It exists here because the two APIs are one component to a caller: `docs/CONSUMER-RULES.md`
967
+ * rule 5 tells everyone that "a Select outside a form takes `width=\"auto\"`", and until this
968
+ * prop existed that sentence was false for the `options` form — a filter bar with two of them
969
+ * stretched each to full width and stacked them, and the only way out was to wrap each in a
970
+ * `<Flex width={280}>`.
971
+ */
972
+ width?: ControlWidthProp;
892
973
  /**
893
974
  * Validation status (antd `status`). `error` recolours the trigger AND sets `aria-invalid`;
894
975
  * `warning` recolours only. A `status` set here never overrides an `aria-invalid` arriving from
@@ -1376,3 +1457,130 @@ export type BranchScopePickerProp = FieldA11yProps & {
1376
1457
  id?: IdProp;
1377
1458
  className?: ClassNameProp;
1378
1459
  };
1460
+ /**
1461
+ * Which keystroke SENDS and which one breaks the line — Ant Design X `Sender.submitType`.
1462
+ *
1463
+ * `enter` (default) is the chat convention: `Enter` sends, `Shift+Enter` inserts a newline.
1464
+ * `shiftEnter` is the inverse, for composers that hold long, deliberately multi-line drafts.
1465
+ * Neither ever fires while an IME conversion is in flight.
1466
+ * @see ChatComposer
1467
+ */
1468
+ export type ChatComposerSubmitTypeProp = "enter" | "shiftEnter";
1469
+ /**
1470
+ * @see ChatComposer — the message input of a conversation (Ant Design X `Sender`; the industry
1471
+ * calls the control a *composer*, so that is what it is named).
1472
+ *
1473
+ * Built on the real `Textarea` (auto-growing between `--chat-composer-min-height` and
1474
+ * `--chat-composer-max-height`, both derived from the `--control-height` tier) plus real
1475
+ * `Button`s. The `<textarea>` is the semantic focus target: `ref`, `id`, `name` and the whole
1476
+ * `FormField` label/helper/error contract land on it, so a ChatComposer inside a `FormField`
1477
+ * behaves exactly like an `Input` does.
1478
+ */
1479
+ export type ChatComposerProp = Omit<React.HTMLAttributes<HTMLDivElement>, "onSubmit" | "defaultValue" | "prefix" | "onChange" | "onKeyDown"> & FieldA11yProps & {
1480
+ /** Controlled draft text. Pair with `onValueChange` or the box freezes. */
1481
+ value?: ValueProp<string>;
1482
+ /** Uncontrolled initial draft text. */
1483
+ defaultValue?: DefaultValueProp<string>;
1484
+ /** Draft-text change handler — fires on every keystroke, including during an IME conversion. */
1485
+ onValueChange?: OnValueChangeProp<string>;
1486
+ /**
1487
+ * Send the draft. Receives the text as typed; never fires for an empty or whitespace-only
1488
+ * draft, and never while `loading`, `disabled` or `readOnly`.
1489
+ */
1490
+ onSubmit?: (value: string) => void;
1491
+ /** Stop the in-flight response. Only reachable while `loading`. */
1492
+ onCancel?: () => void;
1493
+ /**
1494
+ * A response is streaming. The trailing action becomes CANCEL — exactly one trailing action
1495
+ * exists at a time, the same discipline as the picker trailing-action rule.
1496
+ */
1497
+ loading?: PendingProp;
1498
+ /** Which keystroke sends and which breaks the line. Default `enter`. */
1499
+ submitType?: ChatComposerSubmitTypeProp;
1500
+ /** Empty-state text of the draft box; pass it through `t()` at the call site. */
1501
+ placeholder?: PlaceholderProp;
1502
+ /** Disable the whole composer (draft box and every action). */
1503
+ disabled?: DisabledProp;
1504
+ /** Show the draft without allowing an edit; still focusable and selectable. */
1505
+ readOnly?: boolean;
1506
+ /** Slot ABOVE the draft row — attachments, a reply-to banner, a model picker. */
1507
+ header?: React.ReactNode;
1508
+ /** Slot at the inline START of the draft row — an attach button, an avatar. */
1509
+ prefix?: React.ReactNode;
1510
+ /** Slot BELOW the draft row — a hint line, a token counter. */
1511
+ footer?: React.ReactNode;
1512
+ /** Extra trailing actions, rendered BEFORE the send/cancel action. */
1513
+ actions?: React.ReactNode;
1514
+ /** Control height tier on the shared `--control-height` ladder. Default `md`. */
1515
+ size?: SizeProp;
1516
+ /** Hard ceiling on the draft length, forwarded to the textarea. */
1517
+ maxLength?: number;
1518
+ /** Validation state the composer paints. `error` also reports `aria-invalid`. */
1519
+ status?: ControlStatusProp;
1520
+ /** Accessible name override for the send action (localized default otherwise). */
1521
+ submitLabel?: string;
1522
+ /** Accessible name override for the cancel action (localized default otherwise). */
1523
+ cancelLabel?: string;
1524
+ /** Keydown on the draft box — how `ChatSuggestion` drives its list from the composer. */
1525
+ onKeyDown?: React.KeyboardEventHandler<HTMLTextAreaElement>;
1526
+ name?: NameProp;
1527
+ id?: IdProp;
1528
+ className?: ClassNameProp;
1529
+ };
1530
+ /** @see ChatSuggestion — one row of the trigger-character list. One level of `children` is honoured. */
1531
+ export type ChatSuggestionItemProp = {
1532
+ /** Stable value handed to `onValueChange`, and the search haystack when there is no `label`. */
1533
+ value: string;
1534
+ /** Human row label. Falls back to `value`. */
1535
+ label?: string;
1536
+ /** Secondary line under the label. */
1537
+ description?: string;
1538
+ /** Decorative leading node (an icon). */
1539
+ icon?: React.ReactNode;
1540
+ /** Keep the row visible but unselectable. */
1541
+ disabled?: DisabledProp;
1542
+ /** One level of sub-rows; picking the parent drills into them instead of emitting a value. */
1543
+ children?: readonly ChatSuggestionItemProp[];
1544
+ };
1545
+ /** The render-prop bag `ChatSuggestion` hands to the composer it wraps. */
1546
+ export type ChatSuggestionRenderProp = {
1547
+ /**
1548
+ * Re-read the caret and decide whether the list belongs open — call it from the composer's
1549
+ * `onValueChange`. `false` force-closes; no argument force-opens with an empty query.
1550
+ */
1551
+ onTrigger: (value?: string | false) => void;
1552
+ /** Forward to the composer's `onKeyDown`: arrows move, Enter/Tab pick, Escape closes. */
1553
+ onKeyDown: React.KeyboardEventHandler<HTMLTextAreaElement>;
1554
+ };
1555
+ /**
1556
+ * @see ChatSuggestion — trigger-character autocomplete over a `ChatComposer` (Ant Design X
1557
+ * `Suggestion`).
1558
+ *
1559
+ * The list itself is the existing `Command` (cmdk) inside a `Popover`, so the listbox ARIA comes
1560
+ * from a primitive that already ships it. What this component owns is the part `Command` does not:
1561
+ * spotting the trigger character at the caret in a textarea, tracking the query as the caret
1562
+ * moves, and closing on `Escape` / blur / a word break — `Escape` returns focus to the textarea
1563
+ * and leaves the typed text exactly as it was.
1564
+ */
1565
+ export type ChatSuggestionProp = {
1566
+ /** The rows to offer. One level of `children` is honoured. */
1567
+ items: readonly ChatSuggestionItemProp[];
1568
+ /** Fires with the picked row's `value`. The caller owns what that does to the draft text. */
1569
+ onValueChange?: OnValueChangeProp<string>;
1570
+ /** The character that opens the list when typed at a word boundary. Default `/`. */
1571
+ triggerCharacter?: string;
1572
+ /** Controlled open state. */
1573
+ open?: OpenProp;
1574
+ /** Uncontrolled initial open state. */
1575
+ defaultOpen?: DefaultOpenProp;
1576
+ /** Open-state change handler. */
1577
+ onOpenChange?: OnOpenChangeProp;
1578
+ /** The composer to wrap — receives `{ onTrigger, onKeyDown }`. */
1579
+ children: (props: ChatSuggestionRenderProp) => React.ReactNode;
1580
+ /** Text shown when the query matches nothing (localized default otherwise). */
1581
+ emptyMessage?: EmptyMessageProp;
1582
+ /** Accessible name of the suggestion listbox — a plain string (localized default otherwise). */
1583
+ listLabel?: string;
1584
+ id?: IdProp;
1585
+ className?: ClassNameProp;
1586
+ };
@@ -1,6 +1,6 @@
1
1
  export type { AppLauncherApp, AppLauncherGroup, AppLauncherLabels, AppLauncherProp, AppShellProp, AuthFooterProp, AuthIdentityProp, OrgSwitcherLabels, OrgSwitcherOrganization, OrgSwitcherProp, PageContainerProp, PageInsetProp, SidebarItemProp, SidebarProductProp, SidebarProp, SidebarSectionProp, TopbarProp, } from "./layout.prop.js";
2
2
  export type { ButtonProp } from "./general.prop.js";
3
- export type { InputProp, TextareaProp, FormFieldProp, SearchInputProp, CheckboxProp, CheckboxGroupProp, ChoiceOptionProp, RadioProp, RadioGroupProp, SwitchProp, SliderProp, CalendarProp, DatePickerProp, DateRangePickerProp, TimePickerProp, ColorPickerProp, UploadProp, UploadFileItemProp, UploadVariantProp, TreeOptionProp, TreeFieldNamesProp, CascaderProp, TreeSelectProp, ShowCheckedStrategyProp, TransferProp, TransferItemProp, } from "./data-entry.prop.js";
3
+ export type { InputProp, TextareaProp, FormFieldProp, SearchInputProp, CheckboxProp, CheckboxGroupProp, ChoiceOptionProp, RadioProp, RadioGroupProp, SwitchProp, SliderProp, CalendarProp, DatePickerProp, TimePickerProp, ColorPickerProp, UploadProp, UploadFileItemProp, UploadVariantProp, TreeOptionProp, TreeFieldNamesProp, CascaderProp, TreeSelectProp, ShowCheckedStrategyProp, TransferProp, TransferItemProp, } from "./data-entry.prop.js";
4
4
  export type { AvatarProp, EmptyStateProp, DescriptionsProp, DescriptionsItemProp, BadgeProp, DataTableProp, QrCodeProp, } from "./data-display.prop.js";
5
5
  export type { ChartDatum, ChartSeriesProp, LineChartProp, BarChartProp, AreaChartProp, PieChartProp, } from "./charts.prop.js";
6
6
  export type { AlertQueryErrorProp, AlertProp, AlertTitleProp, AlertContentProp, AlertDescriptionProp, AlertActionsProp, SheetResponsiveProp, SkeletonRowsProp, } from "./feedback.prop.js";
@@ -1,7 +1,7 @@
1
1
  /** Layout component prop types — @see docs/COMPONENTS.md#layout */
2
2
  import type * as React from "react";
3
3
  import type { ComponentType, ReactNode, SVGProps } from "react";
4
- import type { BreadcrumbProp, TitleProp, SubtitleProp, StatusProp, ExtraProp, FooterProp, PageDensityProp, PageContainerVariantProp, CenteredShellWidthProp, CenteredShellAlignProp, CenteredShellPresetProp, ErrorSurfaceModeProp, ErrorSurfaceStatusProp, AuthShellPresetProp, MobileShellHeightProp, OrientationProp, TextAlignProp, TextToneProp, BreakpointProp, GapProp, PadProp, PadRawProp, ClassNameProp, ChildrenProp, IdProp, DisabledProp, DescriptionProp, ActionProp, IconProp, HeadingLevelProp, ToneProp, WidthProp } from "../vocabulary/index.js";
4
+ import type { BreadcrumbProp, TitleProp, SubtitleProp, StatusProp, ExtraProp, FooterProp, PageDensityProp, PageContainerVariantProp, CenteredShellWidthProp, CenteredShellAlignProp, CenteredShellPresetProp, ErrorSurfaceModeProp, ErrorSurfaceStatusProp, AuthShellPresetProp, MobileShellHeightProp, MobileShellWidthProp, OrientationProp, TextAlignProp, TextToneProp, BreakpointProp, GapProp, PadProp, PadRawProp, ClassNameProp, ChildrenProp, IdProp, DisabledProp, DescriptionProp, ActionProp, IconProp, HeadingLevelProp, ToneProp, WidthProp } from "../vocabulary/index.js";
5
5
  import type { EmptyStateToneProp } from "./data-display.prop.js";
6
6
  /**
7
7
  * Arrangement of the page header's title band and its `extra` slot below the 640px step.
@@ -505,6 +505,17 @@ export type MobileShellProp = {
505
505
  * device-frame preview, a phone view embedded in a wider page).
506
506
  */
507
507
  height?: MobileShellHeightProp;
508
+ /**
509
+ * How wide the shell is allowed to get. `"fill"` (default) takes the whole inline size it is
510
+ * given — a real handheld, where that IS the phone. `"phone"` caps it at
511
+ * `--mobile-shell-max-inline-size` and centres the column, for the case `height="fill"` already
512
+ * names on the other axis: a handheld screen rendered on a viewport wider than a handheld.
513
+ *
514
+ * Measured at a 1280px viewport before this axis existed: `max-inline-size: none`, shell 1232px
515
+ * wide, a four-destination tab bar spread across the whole screen. `height` had two named values
516
+ * for exactly these two contexts and `width` had none — the asymmetry was the bug.
517
+ */
518
+ width?: MobileShellWidthProp;
508
519
  className?: ClassNameProp;
509
520
  };
510
521
  /**
@@ -190,7 +190,19 @@ export type StepItemProp = {
190
190
  */
191
191
  export type StepsTypeProp = "default" | "dot" | "inline" | "navigation";
192
192
  /** @see Steps */
193
- export type StepsProp = {
193
+ /**
194
+ * The rest of a native `<ol>`'s attributes ride through to the list element.
195
+ *
196
+ * Not a convenience: without them a consumer had no supported handle on the rendered list at all,
197
+ * so its browser test bound to `.ui-steps-list > li[data-status]` — an INTERNAL class and an
198
+ * internal data attribute, both of which this package is free to rename. A `data-testid` or an
199
+ * `id` on the component is what that test wanted, and every sibling primitive already forwards
200
+ * them.
201
+ *
202
+ * `aria-label` is the one exception: the list names itself from the locale, and a caller-supplied
203
+ * name wins — the same contract Progress and Toolbar follow.
204
+ */
205
+ export type StepsProp = Omit<React.OlHTMLAttributes<HTMLOListElement>, "onChange" | "defaultValue" | "children" | "type"> & {
194
206
  items?: StepItemProp[];
195
207
  value?: number;
196
208
  defaultValue?: number;
@@ -235,6 +247,17 @@ export type TabItemProp = {
235
247
  closable?: boolean;
236
248
  /** Ant Design `Tab.closeIcon` — replaces the default × on this item's remove button. */
237
249
  closeIcon?: React.ReactNode;
250
+ /**
251
+ * Ant Design `Tab.forceRender`. Mounts THIS panel up front and keeps it mounted while another
252
+ * tab is selected, without turning that on for the whole strip the way `destroyOnHidden={false}`
253
+ * does — so the one panel holding a live chart, a scroll position or an unsent draft survives a
254
+ * tab switch while the rest are still destroyed.
255
+ *
256
+ * antd 5.25 also grew a per-item `destroyOnHidden`. It is NOT offered here: on this component
257
+ * "kept mounted" is a single state, so an item-level `destroyOnHidden: false` would be a second
258
+ * prop spelling exactly what `forceRender: true` already says (cardinal rule #32).
259
+ */
260
+ forceRender?: boolean;
238
261
  };
239
262
  /**
240
263
  * @see Tabs — trigger-strip appearance. This is Ant Design's `type` spelled in the library's own
@@ -264,6 +287,32 @@ export type TabsExtraProp = React.ReactNode | {
264
287
  * commas, and an inline `(target, action) => void` leaks its second PARAMETER as a phantom prop.
265
288
  */
266
289
  export type TabsOnEditProp = (target: string | React.MouseEvent<HTMLButtonElement>, action: "add" | "remove") => void;
290
+ /**
291
+ * @see Tabs — what the trigger strip does when there are more tabs than fit its container.
292
+ *
293
+ * This is Ant Design's `more`, mapped onto the `overflow` vocabulary this package already uses
294
+ * for the same question (`FilterBarOverflowProp` on Toolbar) rather than re-spelled: antd names
295
+ * the AFFORDANCE it happens to draw, this library names the BEHAVIOUR and owns the affordance.
296
+ *
297
+ * `scroll` (the default, and what every strip does today) keeps one bounded row that scrolls its
298
+ * own inline overflow, with `TabsList` re-pinning the active — or, under manual activation, the
299
+ * focused — trigger. `menu` keeps all of that AND puts a real button beside the strip listing the
300
+ * tabs currently outside the scrollport.
301
+ *
302
+ * WHERE THIS DELIBERATELY DIVERGES FROM ANTD, and why: antd REMOVES the overflowing tabs from the
303
+ * bar and re-homes them in the dropdown. The WAI-ARIA APG tab pattern requires the tablist to own
304
+ * every tab, and a tab hidden with `display: none` cannot take roving focus — so removing them
305
+ * would make the keyboard route to those tabs disappear along with the pixels. Here the strip
306
+ * still holds and still scrolls to every tab; the menu is an ADDITIONAL pointer route to the ones
307
+ * a mouse user cannot currently see. The APG wins; the affordance is kept.
308
+ */
309
+ export type TabsOverflowProp = "scroll" | "menu";
310
+ /**
311
+ * @see Tabs — Ant Design `onTabClick`. A NAMED alias rather than an inline signature for the same
312
+ * reason as `TabsOnEditProp`: the catalog-sync guard splits an object type on top-level commas,
313
+ * so an inline `(value, event) => void` leaks its second PARAMETER as a phantom prop.
314
+ */
315
+ export type TabsOnTabClickProp = (value: string, event: React.MouseEvent<HTMLButtonElement>) => void;
267
316
  /** @see Tabs — high-level tabs with optional `items` array. */
268
317
  export type TabsProp = {
269
318
  items?: TabItemProp[];
@@ -292,6 +341,32 @@ export type TabsProp = {
292
341
  addIcon?: React.ReactNode;
293
342
  /** Ant Design `hideAdd` — keep `editable-card`'s remove buttons but drop the add button. */
294
343
  hideAdd?: boolean;
344
+ /**
345
+ * Ant Design `removeIcon` — the strip-wide default glyph on `editable-card`'s remove shortcut.
346
+ * A `TabItemProp.closeIcon` on one item still wins over it, which is antd's own precedence.
347
+ */
348
+ closeIcon?: React.ReactNode;
349
+ /**
350
+ * Ant Design `more`. Default `scroll` — the behaviour every strip has today, unchanged.
351
+ * @see TabsOverflowProp for what `menu` adds and where it parts company with antd.
352
+ *
353
+ * The default is deliberately NOT `menu`: switching it would change the rendered bar for every
354
+ * existing consumer at once, and which of the two a dense strip wants is a service decision, not
355
+ * a library one.
356
+ */
357
+ overflow?: TabsOverflowProp;
358
+ /**
359
+ * Ant Design `onTabClick`. Fires on EVERY pointer activation of a trigger — including a click on
360
+ * the tab that is already selected, where `onValueChange` is silent by design. That is the whole
361
+ * reason it is a separate prop and not a re-spelling of `onValueChange` (cardinal rule #32):
362
+ * "the user asked for this tab again" (re-fetch, close a drawer, scroll a panel back to the top)
363
+ * is a different event from "the selection changed".
364
+ *
365
+ * Keyboard activation is NOT routed here, and that is the APG winning over antd: under
366
+ * `activationMode="manual"` the arrow keys move focus without activating, so a key-driven
367
+ * "click" would be a fiction. Use `onValueChange` for selection, whatever moved it.
368
+ */
369
+ onTabClick?: TabsOnTabClickProp;
295
370
  className?: ClassNameProp;
296
371
  listClassName?: ClassNameProp;
297
372
  contentClassName?: ClassNameProp;