@chassis-ui/react 0.1.0 → 0.1.2

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 (106) hide show
  1. package/README.md +11 -0
  2. package/dist/index.d.ts +682 -237
  3. package/dist/index.js +2 -2
  4. package/dist/style.css +1 -1
  5. package/package.json +32 -25
  6. package/src/components/accordion/Accordion.tsx +2 -2
  7. package/src/components/accordion/AccordionItem.tsx +6 -6
  8. package/src/components/autocomplete/Autocomplete.tsx +4 -4
  9. package/src/components/avatar/Avatar.tsx +5 -2
  10. package/src/components/breadcrumb/Breadcrumb.tsx +11 -2
  11. package/src/components/button/Button.tsx +7 -4
  12. package/src/components/button-group/ButtonGroup.tsx +2 -2
  13. package/src/components/calendar/Calendar.tsx +56 -42
  14. package/src/components/calendar/CalendarMonthGrid.tsx +3 -1
  15. package/src/components/calendar/CalendarMonthYearPicker.tsx +4 -2
  16. package/src/components/calendar/CalendarYearGrid.tsx +5 -3
  17. package/src/components/calendar/RangeCalendar.scss +8 -8
  18. package/src/components/calendar/RangeCalendar.tsx +56 -44
  19. package/src/components/calendar/index.ts +1 -0
  20. package/src/components/calendar/labels.tsx +71 -0
  21. package/src/components/card/Card.tsx +4 -4
  22. package/src/components/card/CardGroup.tsx +1 -1
  23. package/src/components/card/CardImage.tsx +1 -1
  24. package/src/components/carousel/Carousel.tsx +20 -9
  25. package/src/components/carousel/CarouselControlButton.tsx +1 -1
  26. package/src/components/carousel/CarouselPlayPause.tsx +1 -1
  27. package/src/components/carousel/carouselEngine.ts +3 -3
  28. package/src/components/checkbox/Checkbox.tsx +12 -11
  29. package/src/components/checkbox/CheckboxGroup.tsx +1 -1
  30. package/src/components/chip/Chip.tsx +5 -4
  31. package/src/components/chip-input/ChipInput.tsx +12 -4
  32. package/src/components/chip-input/ChipList.tsx +2 -2
  33. package/src/components/close-button/CloseButton.tsx +2 -2
  34. package/src/components/color-input/ColorInput.tsx +2 -2
  35. package/src/components/combobox/Combobox.tsx +2 -2
  36. package/src/components/datagrid/DataGrid.scss +203 -0
  37. package/src/components/datagrid/DataGrid.tsx +259 -0
  38. package/src/components/datagrid/DataGridBody.tsx +162 -0
  39. package/src/components/datagrid/DataGridCell.tsx +47 -0
  40. package/src/components/datagrid/DataGridColumn.tsx +109 -0
  41. package/src/components/datagrid/DataGridHeader.tsx +47 -0
  42. package/src/components/datagrid/DataGridPinBehavior.tsx +225 -0
  43. package/src/components/datagrid/DataGridRow.tsx +48 -0
  44. package/src/components/datagrid/DataGridSelectionCell.tsx +74 -0
  45. package/src/components/datagrid/DataGridTableLayout.ts +30 -0
  46. package/src/components/datagrid/index.ts +14 -0
  47. package/src/components/datagrid/useColumnGeometry.ts +161 -0
  48. package/src/components/datepicker/ClearButton.tsx +4 -1
  49. package/src/components/datepicker/DatePicker.scss +2 -2
  50. package/src/components/datepicker/DatePicker.tsx +179 -147
  51. package/src/components/datepicker/DateRangePicker.tsx +107 -89
  52. package/src/components/datepicker/renderDatePickerShell.tsx +1 -1
  53. package/src/components/drawer/Drawer.tsx +3 -1
  54. package/src/components/file-input/FileInput.tsx +2 -2
  55. package/src/components/floating-input/FloatingInput.tsx +8 -8
  56. package/src/components/form/renderFormCheck.tsx +3 -3
  57. package/src/components/form-field/FormField.tsx +8 -8
  58. package/src/components/form-field/renderFormField.tsx +14 -3
  59. package/src/components/grid/Col.tsx +1 -1
  60. package/src/components/grid/GridItem.tsx +1 -1
  61. package/src/components/grid/Row.tsx +1 -1
  62. package/src/components/input-group/InputGroup.tsx +2 -2
  63. package/src/components/list/List.tsx +5 -5
  64. package/src/components/menu/Menu.tsx +10 -0
  65. package/src/components/menu/MenuSubmenu.tsx +3 -3
  66. package/src/components/menu/MenuSubmenuBack.tsx +1 -1
  67. package/src/components/menu/MenuToggle.tsx +2 -2
  68. package/src/components/modal/Modal.tsx +5 -3
  69. package/src/components/navbar/Navbar.tsx +1 -1
  70. package/src/components/navbar/NavbarBrand.tsx +5 -2
  71. package/src/components/notification/NotificationStack.tsx +1 -1
  72. package/src/components/otp-input/OtpBox.tsx +1 -1
  73. package/src/components/otp-input/OtpInput.tsx +12 -11
  74. package/src/components/pagination/Pagination.tsx +2 -2
  75. package/src/components/pagination/PaginationItem.tsx +23 -4
  76. package/src/components/popover/Popover.tsx +40 -14
  77. package/src/components/progress/Progress.tsx +1 -1
  78. package/src/components/progress/ProgressBar.tsx +1 -1
  79. package/src/components/radio/Radio.tsx +2 -2
  80. package/src/components/radio/RadioGroup.tsx +1 -1
  81. package/src/components/select/Select.tsx +8 -8
  82. package/src/components/skeleton/Skeleton.tsx +1 -1
  83. package/src/components/spinner/Spinner.tsx +2 -2
  84. package/src/components/stepper/Stepper.tsx +5 -5
  85. package/src/components/switch/Switch.tsx +3 -3
  86. package/src/components/table/Table.css +2 -2
  87. package/src/components/table/Table.tsx +30 -7
  88. package/src/components/text-input/TextInput.tsx +2 -2
  89. package/src/components/textarea/Textarea.tsx +2 -2
  90. package/src/components/toast/ToastBody.tsx +1 -1
  91. package/src/components/toast/ToastHeader.tsx +2 -2
  92. package/src/components/toast/Toaster.tsx +1 -1
  93. package/src/components/tooltip/Tooltip.tsx +23 -7
  94. package/src/hooks/useAutoDismiss.ts +4 -1
  95. package/src/hooks/useDialogElement.ts +10 -0
  96. package/src/hooks/useFloatingOverlay.ts +12 -2
  97. package/src/hooks/usePagination.ts +6 -2
  98. package/src/index.ts +226 -0
  99. package/src/types.ts +26 -26
  100. package/src/utils/breakpoints.ts +1 -1
  101. package/src/utils/devWarning.ts +58 -0
  102. package/src/utils/direction.ts +14 -0
  103. package/src/utils/focusRedirect.ts +10 -16
  104. package/src/utils/polymorphic.ts +18 -1
  105. package/src/utils/suppressFocusRingGlobally.ts +22 -7
  106. package/src/utils/triggerElement.ts +25 -0
package/dist/style.css CHANGED
@@ -1 +1 @@
1
- @layer components{.notification.showing{opacity:0}.datepicker-body{position:relative}.datepicker-months-month.selected,.datepicker-years-year.selected{color:var(--cx-primary-contrast);background-color:var(--cx-primary)}.datepicker-months-month.selected:hover,.datepicker-years-year.selected:hover{background-color:var(--cx-primary)}.datepicker-date-outside>.datepicker-date-btn{color:var(--cx-day-disabled-fg-color)}.datepicker-date-weekend:where(:not(.datepicker-date-selected):not(.datepicker-date-unavailable))>.datepicker-date-btn:where(:not([aria-disabled=true])){color:var(--cx-fg-subtle)}.datepicker-date-unavailable:where(:not(.datepicker-date-selected))>.datepicker-date-btn{color:var(--cx-day-disabled-fg-color);text-decoration:line-through}.datepicker-date-selected>.datepicker-date-btn,.datepicker-date-selected.datepicker-date[aria-current=date]>.datepicker-date-btn{color:var(--cx-primary-contrast);background-color:var(--cx-primary)}.datepicker-date-in-range{color:var(--cx-day-range-fg-color);background-color:var(--cx-day-range-bg-color)}.datepicker-date-in-range>.datepicker-date-btn:hover{background-color:unset}.datepicker-date-in-range.datepicker-date-range-start{border-start-start-radius:var(--cx-border-radius-medium);border-end-start-radius:var(--cx-border-radius-medium)}.datepicker-date-in-range.datepicker-date-range-end{border-start-end-radius:var(--cx-border-radius-medium);border-end-end-radius:var(--cx-border-radius-medium)}.datepicker-date-btn:is(.datepicker-date-range-start,.datepicker-date-range-end),.datepicker-date-btn:is(.datepicker-date-range-start,.datepicker-date-range-end):hover{color:var(--cx-primary-contrast);background-color:var(--cx-primary)}.datepicker-date-btn.datepicker-date-range-start:not(.datepicker-date-range-end){border-start-end-radius:0;border-end-end-radius:0}.datepicker-date-btn.datepicker-date-range-end:not(.datepicker-date-range-start){border-start-start-radius:0;border-end-start-radius:0}.datepicker-date[aria-current=date]>.datepicker-date-btn.datepicker-date-range-start,.datepicker-date[aria-current=date]>.datepicker-date-btn.datepicker-date-range-end{color:var(--cx-primary-contrast);background-color:var(--cx-primary)}.datepicker-presets{gap:var(--cx-gap);padding-inline:0 var(--cx-padding-x);border-inline-end:var(--cx-border-width-medium) solid var(--cx-border-subtle);flex-direction:column;margin:0;list-style:none;display:flex}.datepicker-preset{padding:var(--cx-space-2xsmall) var(--cx-space-xsmall);color:var(--cx-fg-main);text-align:start;white-space:nowrap;cursor:pointer;border-radius:var(--cx-border-radius-medium);background-color:#0000;border:0}.datepicker-preset:hover{background-color:var(--cx-bg-hover)}.datepicker-preset:focus-visible{outline:var(--cx-border-width-xlarge) solid var(--cx-primary);outline-offset:-1px}.datepicker-preset.selected{color:var(--cx-primary-contrast);background-color:var(--cx-primary)}.datepicker-preset.selected:hover{background-color:var(--cx-primary)}.datepicker[hidden]{display:none}}.datepicker-field{align-items:center;width:fit-content;display:flex}.datepicker-segment{padding-inline:var(--cx-space-3xsmall);border-radius:var(--cx-border-radius-small);outline:0}.datepicker-segment.placeholder{color:var(--cx-form-idle-fg-inactive)}.datepicker-segment:focus{color:var(--cx-primary-contrast);background-color:var(--cx-primary)}.daterangepicker-separator{margin-inline:var(--cx-gap);color:var(--cx-fg-subtle)}.table-sort-icon{opacity:.6;margin-inline-start:var(--cx-space-2xsmall);font-size:.75em;display:inline-block}[aria-sort=ascending] .table-sort-icon,[aria-sort=descending] .table-sort-icon{opacity:1}[role=columnheader][aria-sort]{cursor:pointer;user-select:none}.table-selection-cell{text-align:center;width:1%;padding-inline-end:0}.table [role=row]:focus-visible,.table [role=gridcell]:focus-visible,.table [role=columnheader]:focus-visible,.table [role=rowheader]:focus-visible{outline:var(--cx-border-width-xlarge) solid var(--cx-primary);outline-offset:-2px}
1
+ @layer components{.notification.showing{opacity:0}.datepicker-body{position:relative}.datepicker-months-month.selected,.datepicker-years-year.selected{color:var(--cx-primary-contrast);background-color:var(--cx-primary)}.datepicker-months-month.selected:hover,.datepicker-years-year.selected:hover{background-color:var(--cx-primary)}.datepicker-date-outside>.datepicker-date-btn{color:var(--cx-day-disabled-fg-color)}.datepicker-date-weekend:where(:not(.datepicker-date-selected):not(.datepicker-date-unavailable))>.datepicker-date-btn:where(:not([aria-disabled=true])){color:var(--cx-fg-subtle)}.datepicker-date-unavailable:where(:not(.datepicker-date-selected))>.datepicker-date-btn{color:var(--cx-day-disabled-fg-color);text-decoration:line-through}.datepicker-date-selected>.datepicker-date-btn,.datepicker-date-selected.datepicker-date[aria-current=date]>.datepicker-date-btn{color:var(--cx-primary-contrast);background-color:var(--cx-primary)}.datepicker-date-in-range{color:var(--cx-day-range-fg-color);background-color:var(--cx-day-range-bg-color)}.datepicker-date-in-range>.datepicker-date-btn:hover{background-color:unset}.datepicker-date-in-range.datepicker-date-range-start{border-start-start-radius:var(--cx-border-radius-md);border-end-start-radius:var(--cx-border-radius-md)}.datepicker-date-in-range.datepicker-date-range-end{border-start-end-radius:var(--cx-border-radius-md);border-end-end-radius:var(--cx-border-radius-md)}.datepicker-date-btn:is(.datepicker-date-range-start,.datepicker-date-range-end),.datepicker-date-btn:is(.datepicker-date-range-start,.datepicker-date-range-end):hover{color:var(--cx-primary-contrast);background-color:var(--cx-primary)}.datepicker-date-btn.datepicker-date-range-start:not(.datepicker-date-range-end){border-start-end-radius:0;border-end-end-radius:0}.datepicker-date-btn.datepicker-date-range-end:not(.datepicker-date-range-start){border-start-start-radius:0;border-end-start-radius:0}.datepicker-date[aria-current=date]>.datepicker-date-btn.datepicker-date-range-start,.datepicker-date[aria-current=date]>.datepicker-date-btn.datepicker-date-range-end{color:var(--cx-primary-contrast);background-color:var(--cx-primary)}.datepicker-presets{gap:var(--cx-gap);padding-inline:0 var(--cx-padding-x);border-inline-end:var(--cx-border-width-md) solid var(--cx-border-subtle);flex-direction:column;margin:0;list-style:none;display:flex}.datepicker-preset{padding:var(--cx-space-2xs) var(--cx-space-xs);color:var(--cx-fg-main);text-align:start;white-space:nowrap;cursor:pointer;border-radius:var(--cx-border-radius-md);background-color:#0000;border:0}.datepicker-preset:hover{background-color:var(--cx-bg-hover)}.datepicker-preset:focus-visible{outline:var(--cx-border-width-xl) solid var(--cx-primary);outline-offset:-1px}.datepicker-preset.selected{color:var(--cx-primary-contrast);background-color:var(--cx-primary)}.datepicker-preset.selected:hover{background-color:var(--cx-primary)}.datagrid{--cx-fg-color:var(--cx-table-td-fg-color,var(--cx-default-fg-main));--cx-bg-color:var(--cx-table-td-bg-color,var(--cx-default-bg-main));--cx-th-fg-color:var(--cx-table-th-fg-color,var(--cx-default-fg-main));--cx-th-bg-color:var(--cx-table-th-bg-color,var(--cx-default-bg-evident));--cx-hover-fg-color:var(--cx-table-hover-fg-color,var(--cx-default-fg-main));--cx-hover-bg-color:var(--cx-table-hover-bg-color,var(--cx-default-bg-evident));--cx-active-fg-color:var(--cx-table-active-fg-color,var(--cx-default-fg-main));--cx-active-bg-color:var(--cx-table-active-bg-color,var(--cx-default-bg-highlight));--cx-border-width:var(--cx-table-border-width,var(--cx-border-width-medium));--cx-border-color:var(--cx-table-border-color,var(--cx-default-border-subtle));--cx-cue-color:var(--cx-table-cue-color,var(--cx-default-cue-main));--cx-cell-padding-y:var(--cx-table-cell-padding-y,.5rem);--cx-cell-padding-x:var(--cx-table-cell-padding-x,.5rem);--cx-datagrid-pin-cue-shadow-start:inset 6px 0 6px -6px #0000004d;--cx-datagrid-pin-cue-shadow-end:inset -6px 0 6px -6px #0000004d;--cx-td-font-family:var(--cx-table-td-font-family,var(--cx-font-family-text));--cx-td-font-size:var(--cx-table-td-font-size,var(--cx-font-size-small));--cx-td-font-weight:var(--cx-table-td-font-weight,var(--cx-font-weight-normal));--cx-td-line-height:var(--cx-table-td-line-height,var(--cx-line-height-small));--cx-th-font-family:var(--cx-table-th-font-family,var(--cx-font-family-text));--cx-th-font-size:var(--cx-table-th-font-size,var(--cx-font-size-small));--cx-th-font-weight:var(--cx-table-th-font-weight,var(--cx-font-weight-strong));--cx-th-line-height:var(--cx-table-th-line-height,var(--cx-line-height-small));width:100%;height:400px;vertical-align:var(--cx-table-cell-vertical-align,top);border-color:var(--cx-border-color);display:block;position:relative;overflow:auto}.datagrid [role=columnheader],.datagrid [role=gridcell],.datagrid [role=rowheader]{box-sizing:border-box;height:100%;padding:var(--cx-cell-padding-y) var(--cx-cell-padding-x);color:var(--cx-fg-color);background-color:var(--cx-bg-color);border-color:var(--cx-border-color);border-style:solid;border-width:0 0 var(--cx-border-width) 0;font:var(--cx-td-font-weight) var(--cx-td-font-size)/var(--cx-td-line-height) var(--cx-td-font-family)}.datagrid .datagrid-header [role=columnheader]{--cx-fg-color:var(--cx-th-fg-color);--cx-bg-color:var(--cx-th-bg-color);font:var(--cx-th-font-weight) var(--cx-th-font-size)/var(--cx-th-line-height) var(--cx-th-font-family)}.datagrid [role=row][data-selected]>*{--cx-fg-color:var(--cx-active-fg-color);--cx-bg-color:var(--cx-active-bg-color)}.datagrid.hoverable [role=row]:not([data-selected]):hover>*{--cx-fg-color:var(--cx-hover-fg-color);--cx-bg-color:var(--cx-hover-bg-color)}.datagrid.bordered{border:var(--cx-border-width) solid var(--cx-border-color)}.datagrid.bordered [role=columnheader],.datagrid.bordered [role=gridcell],.datagrid.bordered [role=rowheader]{border-width:0 var(--cx-border-width) var(--cx-border-width) 0}.datagrid.borderless [role=columnheader],.datagrid.borderless [role=gridcell],.datagrid.borderless [role=rowheader]{border-width:0}.datagrid [role=row]:focus-visible,.datagrid [role=gridcell]:focus-visible,.datagrid [role=columnheader]:focus-visible,.datagrid [role=rowheader]:focus-visible{outline:var(--cx-border-width-xl) solid var(--cx-primary);outline-offset:-2px}.datagrid [role=columnheader][data-allows-sorting]{cursor:pointer;user-select:none}.datagrid .datagrid-sort-icon{opacity:.6;margin-inline-start:var(--cx-space-2xs);font-size:.75em;display:inline-block}.datagrid [data-sort-direction] .datagrid-sort-icon{opacity:1}.datagrid :has(>.datagrid-header),.datagrid :has(>.datagrid-body){overflow:visible!important}.datagrid .datagrid-selection-cell{text-align:center;padding-inline-end:0}.datagrid-footer{--cx-fg-color:var(--cx-table-td-fg-color,var(--cx-default-fg-main));--cx-bg-color:var(--cx-table-td-bg-color,var(--cx-default-bg-main));--cx-border-width:var(--cx-table-border-width,var(--cx-border-width-medium));--cx-border-color:var(--cx-table-border-color,var(--cx-default-border-subtle));--cx-cell-padding-y:var(--cx-table-cell-padding-y,.5rem);--cx-cell-padding-x:var(--cx-table-cell-padding-x,.5rem);box-sizing:border-box;padding:var(--cx-cell-padding-y) var(--cx-cell-padding-x);color:var(--cx-fg-color);background-color:var(--cx-bg-color);border-color:var(--cx-border-color);border-style:solid;border-width:var(--cx-border-width) 0 0 0}.datagrid-footer.borderless{border-width:0}.datepicker[hidden]{display:none}}.datepicker-field{align-items:center;width:fit-content;display:flex}.datepicker-segment{padding-inline:var(--cx-space-3xs);border-radius:var(--cx-border-radius-sm);outline:0}.datepicker-segment.placeholder{color:var(--cx-form-idle-fg-inactive)}.datepicker-segment:focus{color:var(--cx-primary-contrast);background-color:var(--cx-primary)}.daterangepicker-separator{margin-inline:var(--cx-gap);color:var(--cx-fg-subtle)}.table-sort-icon{opacity:.6;margin-inline-start:var(--cx-space-2xs);font-size:.75em;display:inline-block}[aria-sort=ascending] .table-sort-icon,[aria-sort=descending] .table-sort-icon{opacity:1}[role=columnheader][aria-sort]{cursor:pointer;user-select:none}.table-selection-cell{text-align:center;width:1%;padding-inline-end:0}.table [role=row]:focus-visible,.table [role=gridcell]:focus-visible,.table [role=columnheader]:focus-visible,.table [role=rowheader]:focus-visible{outline:var(--cx-border-width-xl) solid var(--cx-primary);outline-offset:-2px}
package/package.json CHANGED
@@ -1,10 +1,7 @@
1
1
  {
2
2
  "name": "@chassis-ui/react",
3
- "version": "0.1.0",
3
+ "version": "0.1.2",
4
4
  "type": "module",
5
- "engines": {
6
- "node": ">=24"
7
- },
8
5
  "description": "Chassis UI Components Library for React.js",
9
6
  "keywords": [
10
7
  "react",
@@ -36,17 +33,25 @@
36
33
  "./style.css": "./dist/style.css"
37
34
  },
38
35
  "sideEffects": [
39
- "./src/utils/suppressFocusRingGlobally.ts"
36
+ "./dist/index.js",
37
+ "./dist/style.css"
38
+ ],
39
+ "browserslist": [
40
+ "chrome >= 107",
41
+ "edge >= 107",
42
+ "firefox >= 104",
43
+ "safari >= 16"
40
44
  ],
41
45
  "files": [
42
46
  "dist/",
43
47
  "src/"
44
48
  ],
45
49
  "dependencies": {
46
- "@internationalized/date": "^3.12.2",
50
+ "@internationalized/date": "^3.12.4",
47
51
  "classnames": "^2.3.1",
48
- "react-aria": "^3.0.0",
49
- "react-stately": "^3.0.0",
52
+ "react-aria": "^3.52.0",
53
+ "react-aria-components": "^1.20.0",
54
+ "react-stately": "^3.50.0",
50
55
  "react-transition-group": "^4.4.2"
51
56
  },
52
57
  "devDependencies": {
@@ -55,34 +60,34 @@
55
60
  "@chassis-ui/css": "^0.4.0-0",
56
61
  "@chassis-ui/tokens": "^0.4.0",
57
62
  "@playwright/test": "1.62.1",
58
- "@storybook/addon-a11y": "^10.5.6",
59
- "@storybook/addon-docs": "^10.5.6",
60
- "@storybook/addon-themes": "^10.5.8",
61
- "@storybook/addon-vitest": "^10.5.8",
62
- "@storybook/react-vite": "^10.5.6",
63
- "@testing-library/jest-dom": "^6.0.0",
64
- "@testing-library/react": "^16.0.0",
65
- "@testing-library/user-event": "^14.6.1",
66
- "@tsdown/css": "^0.22.14",
63
+ "@storybook/addon-a11y": "^10.6.0",
64
+ "@storybook/addon-docs": "^10.6.0",
65
+ "@storybook/addon-themes": "^10.6.0",
66
+ "@storybook/addon-vitest": "^10.6.0",
67
+ "@storybook/react-vite": "^10.6.0",
68
+ "@testing-library/jest-dom": "^7.0.1",
69
+ "@testing-library/react": "^16.3.3",
70
+ "@testing-library/user-event": "^14.6.7",
71
+ "@tsdown/css": "^0.23.0",
67
72
  "@types/react": "^19.0.0",
68
- "@types/react-dom": "^19.0.0",
73
+ "@types/react-dom": "^19.2.7",
69
74
  "@types/react-transition-group": "^4.4.11",
70
- "@vitejs/plugin-react": "^6.0.4",
75
+ "@vitejs/plugin-react": "^6.1.1",
71
76
  "@vitest/browser-playwright": "4.1.10",
72
77
  "@vitest/coverage-istanbul": "^4.1.10",
73
78
  "bundlewatch": "^0.4.2",
74
79
  "http-server": "^14.1.1",
75
80
  "jest-axe": "^11.0.0",
76
- "jsdom": "^30.0.0",
81
+ "jsdom": "^30.0.1",
77
82
  "playwright": "^1.62.1",
78
- "postcss": "^8.5.23",
83
+ "postcss": "^8.5.28",
79
84
  "postcss-prefix-custom-properties": "^0.1.0",
80
- "publint": "^0.3.23",
85
+ "publint": "^0.3.24",
81
86
  "react": "^19.0.0",
82
87
  "react-dom": "^19.0.0",
83
- "sass": "^1.101.0",
84
- "storybook": "^10.5.10",
85
- "tsdown": "0.22.14",
88
+ "sass": "^1.104.0",
89
+ "storybook": "^10.6.0",
90
+ "tsdown": "0.23.0",
86
91
  "tslib": "^2.6.0",
87
92
  "typescript": "^6.0.3",
88
93
  "vitest": "^4.1.10"
@@ -102,6 +107,8 @@
102
107
  "lint:prettier": "prettier -c --cache --ignore-path ../../.gitignore --ignore-path ../../.prettierignore .",
103
108
  "format": "prettier --write --ignore-path ../../.gitignore --ignore-path ../../.prettierignore .",
104
109
  "check:bundle": "bundlewatch --config .bundlewatch.config.json",
110
+ "check:types": "tsc --noEmit -p tsconfig.json",
111
+ "check:rsc": "ts-node --project ../../build/tsconfig.json ./scripts/check-rsc-directive.ts",
105
112
  "check:package": "publint && attw --pack . --profile esm-only --exclude-entrypoints ./style.css",
106
113
  "check:api": "ts-node --project ../../build/tsconfig.json ./scripts/check-api-surface.ts",
107
114
  "check:api:update": "ts-node --project ../../build/tsconfig.json ./scripts/check-api-surface.ts --update",
@@ -88,9 +88,9 @@ export interface AccordionProps extends HTMLAttributes<HTMLDivElement> {
88
88
  */
89
89
  onExpandedChange?: (keys: Array<number | string>) => void
90
90
  /**
91
- * Size the component small or large.
91
+ * Size the component sm or lg.
92
92
  */
93
- size?: 'small' | 'large'
93
+ size?: 'sm' | 'lg'
94
94
  }
95
95
 
96
96
  export const Accordion = forwardRef<HTMLDivElement, AccordionProps>(
@@ -2,6 +2,7 @@ import React, { forwardRef, DetailsHTMLAttributes, useContext } from 'react'
2
2
  import classNames from 'classnames'
3
3
 
4
4
  import { AccordionContext } from './context'
5
+ import { devWarning } from '../../utils/devWarning'
5
6
 
6
7
  export interface AccordionItemProps extends DetailsHTMLAttributes<HTMLDetailsElement> {
7
8
  /**
@@ -29,12 +30,11 @@ export interface AccordionItemProps extends DetailsHTMLAttributes<HTMLDetailsEle
29
30
 
30
31
  export const AccordionItem = forwardRef<HTMLDetailsElement, AccordionItemProps>(
31
32
  ({ children, alwaysOpen, className, name, open, itemKey: _itemKey, ...rest }, ref) => {
32
- if (_itemKey !== undefined) {
33
- console.warn(
34
- 'AccordionItem: the itemKey prop is deprecated and no longer used — the native ' +
35
- '<details> element manages its own state. It will be removed in a future major version.'
36
- )
37
- }
33
+ devWarning(
34
+ _itemKey !== undefined,
35
+ 'AccordionItem: the itemKey prop is deprecated and no longer used — the native ' +
36
+ '<details> element manages its own state. It will be removed in a future major version.'
37
+ )
38
38
 
39
39
  const context = useContext(AccordionContext)
40
40
  const isAlwaysOpen = alwaysOpen ?? context.alwaysOpen
@@ -141,9 +141,9 @@ export interface AutocompleteProps extends Omit<
141
141
  */
142
142
  searchPlaceholder?: string
143
143
  /**
144
- * Size the component small or large.
144
+ * Size the component sm or lg.
145
145
  */
146
- size?: 'small' | 'large'
146
+ size?: 'sm' | 'lg'
147
147
  /**
148
148
  * Set component validation state to valid.
149
149
  */
@@ -386,7 +386,7 @@ export const Autocomplete = ({
386
386
  className={classNames(
387
387
  'form-input',
388
388
  'combobox',
389
- { small: size === 'small', large: size === 'large', disabled },
389
+ { sm: size === 'sm', lg: size === 'lg', disabled },
390
390
  { 'is-invalid': invalid, 'is-valid': valid },
391
391
  className
392
392
  )}
@@ -419,7 +419,7 @@ export const Autocomplete = ({
419
419
  <div className="combobox-search">
420
420
  <input
421
421
  autoComplete="off"
422
- className="form-input combobox-search-input small"
422
+ className="form-input combobox-search-input sm"
423
423
  {...inputHtmlProps}
424
424
  ref={inputRef}
425
425
  />
@@ -5,7 +5,8 @@ import { ContextColor, ExtendedSizing } from '../../types'
5
5
  import {
6
6
  createPolymorphicComponent,
7
7
  PolymorphicComponentProps,
8
- PolymorphicRef
8
+ PolymorphicRef,
9
+ PolymorphicRefWithFallback
9
10
  } from '../../utils/polymorphic'
10
11
  import { Link } from '../link/Link'
11
12
  import { Badge } from '../badge'
@@ -68,7 +69,9 @@ export type AvatarProps<C extends ElementType = 'span'> = PolymorphicComponentPr
68
69
  >
69
70
 
70
71
  type AvatarComponent = (<C extends ElementType = 'span'>(
71
- props: AvatarProps<C> & { ref?: PolymorphicRef<C> }
72
+ props: AvatarProps<C> & {
73
+ ref?: PolymorphicRefWithFallback<C, HTMLSpanElement | HTMLAnchorElement>
74
+ }
72
75
  ) => ReactElement | null) & { displayName?: string }
73
76
 
74
77
  function AvatarRender<C extends ElementType = 'span'>(
@@ -15,6 +15,15 @@ export interface BreadcrumbItemDef {
15
15
  }
16
16
 
17
17
  export interface BreadcrumbProps extends HTMLAttributes<HTMLOListElement> {
18
+ /**
19
+ * Accessible name of the wrapping `<nav>` landmark. Defaults to the English `'breadcrumb'`;
20
+ * override it to translate the landmark, or to tell two breadcrumb trails on the same page
21
+ * apart (landmarks of the same role need distinct names to be distinguishable in a screen
22
+ * reader's landmark list).
23
+ *
24
+ * @default 'breadcrumb'
25
+ */
26
+ 'aria-label'?: string
18
27
  /**
19
28
  * A string of all className you want applied to the component.
20
29
  */
@@ -27,7 +36,7 @@ export interface BreadcrumbProps extends HTMLAttributes<HTMLOListElement> {
27
36
  }
28
37
 
29
38
  export const Breadcrumb = forwardRef<HTMLOListElement, BreadcrumbProps>(
30
- ({ children, className, items, ...rest }, ref) => {
39
+ ({ 'aria-label': ariaLabel = 'breadcrumb', children, className, items, ...rest }, ref) => {
31
40
  const _className = classNames('breadcrumb', className)
32
41
 
33
42
  const autoContent = items
@@ -47,7 +56,7 @@ export const Breadcrumb = forwardRef<HTMLOListElement, BreadcrumbProps>(
47
56
  : null
48
57
 
49
58
  return (
50
- <nav aria-label="breadcrumb">
59
+ <nav aria-label={ariaLabel}>
51
60
  <ol className={_className} {...rest} ref={ref}>
52
61
  {autoContent ?? children}
53
62
  </ol>
@@ -13,7 +13,8 @@ import { useButtonSemantics, useDisabledAnchorGuard } from '../../hooks'
13
13
  import {
14
14
  createPolymorphicComponent,
15
15
  PolymorphicComponentProps,
16
- PolymorphicRef
16
+ PolymorphicRef,
17
+ PolymorphicRefWithFallback
17
18
  } from '../../utils/polymorphic'
18
19
 
19
20
  type ButtonOwnProps<C extends ElementType> = {
@@ -53,9 +54,9 @@ type ButtonOwnProps<C extends ElementType> = {
53
54
  */
54
55
  shape?: Shapes
55
56
  /**
56
- * Size the component small or large.
57
+ * Size the component sm or lg.
57
58
  */
58
- size?: 'small' | 'large'
59
+ size?: 'sm' | 'lg'
59
60
  /**
60
61
  * Specifies the type of button. Always specify the type attribute for the `<button>` element.
61
62
  * Different browsers may use different default types for the `<button>` element.
@@ -75,7 +76,9 @@ export type ButtonProps<C extends ElementType = 'button'> = PolymorphicComponent
75
76
  >
76
77
 
77
78
  type ButtonComponent = (<C extends ElementType = 'button'>(
78
- props: ButtonProps<C> & { ref?: PolymorphicRef<C> }
79
+ props: ButtonProps<C> & {
80
+ ref?: PolymorphicRefWithFallback<C, HTMLButtonElement | HTMLAnchorElement>
81
+ }
79
82
  ) => ReactElement | null) & { displayName?: string }
80
83
 
81
84
  function ButtonRender<C extends ElementType = 'button'>(
@@ -17,9 +17,9 @@ type ButtonGroupOwnProps<C extends ElementType> = {
17
17
  */
18
18
  component?: C
19
19
  /**
20
- * Size the component small or large.
20
+ * Size the component sm or lg.
21
21
  */
22
- size?: 'small' | 'large'
22
+ size?: 'sm' | 'lg'
23
23
  /**
24
24
  * Create a set of buttons that appear vertically stacked rather than horizontally. Split button dropdowns are not supported here.
25
25
  */
@@ -18,6 +18,7 @@ import { CalendarNavButton } from './CalendarNavButton'
18
18
  import { CalendarWeekGrid } from './CalendarWeekGrid'
19
19
  import { mergeIsDateUnavailable } from '../../utils/mergeIsDateUnavailable'
20
20
  import './Calendar.scss'
21
+ import { CalendarLabels, CalendarLabelsProvider } from './labels'
21
22
 
22
23
  interface CalendarBaseProps extends Omit<
23
24
  HTMLAttributes<HTMLDivElement>,
@@ -55,6 +56,14 @@ interface CalendarBaseProps extends Omit<
55
56
  * shown but cannot be selected.
56
57
  */
57
58
  isDateUnavailable?: (date: DateValue) => boolean
59
+ /**
60
+ * Overrides for the handful of strings this component renders itself rather than getting from
61
+ * the active locale (the year view's paging arrows, its live-region announcements, and the
62
+ * month/year header buttons). Everything else — month and weekday names, the calendar system —
63
+ * follows `I18nProvider`'s locale via react-aria and needs no override. Merged over the English
64
+ * defaults, so passing one key leaves the rest alone.
65
+ */
66
+ labels?: Partial<CalendarLabels>
58
67
  /**
59
68
  * The maximum allowed date that a user may select.
60
69
  */
@@ -71,7 +80,7 @@ interface CalendarBaseProps extends Omit<
71
80
  unavailableDates?: string[]
72
81
  /**
73
82
  * Number of months to display side by side, sharing one selection. Wraps to multiple rows in
74
- * a narrow container (e.g. a popover on a small screen) rather than overflowing — the wrap is
83
+ * a narrow container (e.g. a popover on a sm screen) rather than overflowing — the wrap is
75
84
  * driven by the calendar's own width, not the viewport, so it adapts correctly regardless of
76
85
  * where the calendar is embedded.
77
86
  *
@@ -145,6 +154,7 @@ export const Calendar = forwardRef<HTMLDivElement, CalendarProps>((props, forwar
145
154
  disabled,
146
155
  firstDayOfWeek = 'mon',
147
156
  isDateUnavailable,
157
+ labels,
148
158
  maxValue,
149
159
  minValue,
150
160
  onChange,
@@ -231,52 +241,56 @@ export const Calendar = forwardRef<HTMLDivElement, CalendarProps>((props, forwar
231
241
  const nextButton = <CalendarNavButton buttonProps={nextButtonProps} direction="next" />
232
242
 
233
243
  return (
234
- <div
235
- {...mergeProps(calendarProps, rest)}
236
- className={classNames('datepicker', className)}
237
- data-cx-inline="true"
238
- ref={ref}
239
- >
240
- {visibleMonths === 1 ? (
241
- <CalendarMonthYearPicker
242
- monthStart={state.visibleRange.start}
243
- nextArrow={nextButton}
244
- prevArrow={prevButton}
245
- state={state}
246
- >
247
- <CalendarWeekGrid
248
- firstDayOfWeek={firstDayOfWeek}
249
- renderCell={(date) => <CalendarCell date={date} locale={locale} state={state} />}
244
+ <CalendarLabelsProvider labels={labels}>
245
+ <div
246
+ {...mergeProps(calendarProps, rest)}
247
+ className={classNames('datepicker', className)}
248
+ data-cx-inline="true"
249
+ ref={ref}
250
+ >
251
+ {visibleMonths === 1 ? (
252
+ <CalendarMonthYearPicker
253
+ monthStart={state.visibleRange.start}
254
+ nextArrow={nextButton}
255
+ prevArrow={prevButton}
250
256
  state={state}
251
- />
252
- </CalendarMonthYearPicker>
253
- ) : (
254
- <>
255
- {/* `.datepicker[data-cx-inline]` (the root above) is already `position: relative` in
257
+ >
258
+ <CalendarWeekGrid
259
+ firstDayOfWeek={firstDayOfWeek}
260
+ renderCell={(date) => <CalendarCell date={date} locale={locale} state={state} />}
261
+ state={state}
262
+ />
263
+ </CalendarMonthYearPicker>
264
+ ) : (
265
+ <>
266
+ {/* `.datepicker[data-cx-inline]` (the root above) is already `position: relative` in
256
267
  chassis-css, so this overlay needs no extra positioning wrapper of its own — unlike
257
268
  `RangeCalendar`, which has a `presets` column sharing that root and so scopes its
258
269
  own copy of this overlay to a nested `.datepicker-body` instead. */}
259
- {!hasPickerView && (
260
- <div className="datepicker-controls">
261
- {prevButton}
262
- {nextButton}
270
+ {!hasPickerView && (
271
+ <div className="datepicker-controls">
272
+ {prevButton}
273
+ {nextButton}
274
+ </div>
275
+ )}
276
+ <div className="datepicker-grid">
277
+ {[...new Array(visibleMonths).keys()].map((monthIndex) => (
278
+ <CalendarMonthBlock
279
+ firstDayOfWeek={firstDayOfWeek}
280
+ key={monthIndex}
281
+ monthIndex={monthIndex}
282
+ onViewChange={(view) =>
283
+ setMonthViews((prev) => ({ ...prev, [monthIndex]: view }))
284
+ }
285
+ renderCell={(date) => <CalendarCell date={date} locale={locale} state={state} />}
286
+ state={state}
287
+ />
288
+ ))}
263
289
  </div>
264
- )}
265
- <div className="datepicker-grid">
266
- {[...new Array(visibleMonths).keys()].map((monthIndex) => (
267
- <CalendarMonthBlock
268
- firstDayOfWeek={firstDayOfWeek}
269
- key={monthIndex}
270
- monthIndex={monthIndex}
271
- onViewChange={(view) => setMonthViews((prev) => ({ ...prev, [monthIndex]: view }))}
272
- renderCell={(date) => <CalendarCell date={date} locale={locale} state={state} />}
273
- state={state}
274
- />
275
- ))}
276
- </div>
277
- </>
278
- )}
279
- </div>
290
+ </>
291
+ )}
292
+ </div>
293
+ </CalendarLabelsProvider>
280
294
  )
281
295
  })
282
296
 
@@ -5,6 +5,7 @@ import { CalendarState, RangeCalendarState } from 'react-stately'
5
5
  import { CalendarDate } from '@internationalized/date'
6
6
 
7
7
  import { isWholeUnitDisabled } from '../../utils/isWholeUnitDisabled'
8
+ import { useCalendarLabels } from './labels'
8
9
 
9
10
  interface CalendarMonthGridProps {
10
11
  // Whether to render the visually-hidden `aria-live` announcement of this view's current header
@@ -27,6 +28,7 @@ export const CalendarMonthGrid = ({
27
28
  onSelect,
28
29
  state
29
30
  }: CalendarMonthGridProps) => {
31
+ const labels = useCalendarLabels()
30
32
  const monthFormatter = useDateFormatter({
31
33
  calendar: monthStart.calendar.identifier,
32
34
  month: 'short',
@@ -55,7 +57,7 @@ export const CalendarMonthGrid = ({
55
57
  </div>
56
58
  {announce && (
57
59
  <span role="status" className="visually-hidden">
58
- {`Select month, ${yearFormatter.format(monthStart.toDate(state.timeZone))}`}
60
+ {`${labels.selectMonth}, ${yearFormatter.format(monthStart.toDate(state.timeZone))}`}
59
61
  </span>
60
62
  )}
61
63
  <div className="datepicker-content">
@@ -6,6 +6,7 @@ import { CalendarDate } from '@internationalized/date'
6
6
  import { CalendarMonthGrid } from './CalendarMonthGrid'
7
7
  import { CalendarYearGrid } from './CalendarYearGrid'
8
8
  import { setVisibleRangeStart } from '../../utils/setVisibleRangeStart'
9
+ import { useCalendarLabels } from './labels'
9
10
 
10
11
  interface CalendarMonthYearPickerProps {
11
12
  // The day grid, shown in the default 'days' view — owned by the caller (`Calendar` and
@@ -49,6 +50,7 @@ export const CalendarMonthYearPicker = ({
49
50
  prevArrow,
50
51
  state
51
52
  }: CalendarMonthYearPickerProps) => {
53
+ const labels = useCalendarLabels()
52
54
  const [view, setView] = useState<'days' | 'months' | 'years'>('days')
53
55
  const containerRef = useRef<HTMLDivElement>(null)
54
56
  // Skipped on mount — there's no prior view to restore focus from yet, and stealing focus
@@ -129,7 +131,7 @@ export const CalendarMonthYearPicker = ({
129
131
  {prevArrow}
130
132
  <div className="datepicker-header-content">
131
133
  <button
132
- aria-label={`Month: ${monthFormatter.format(monthStart.toDate(state.timeZone))}`}
134
+ aria-label={`${labels.month}: ${monthFormatter.format(monthStart.toDate(state.timeZone))}`}
133
135
  className="datepicker-month"
134
136
  disabled={state.isDisabled}
135
137
  onClick={() => changeView('months')}
@@ -138,7 +140,7 @@ export const CalendarMonthYearPicker = ({
138
140
  {monthFormatter.format(monthStart.toDate(state.timeZone))}
139
141
  </button>
140
142
  <button
141
- aria-label={`Year: ${yearFormatter.format(monthStart.toDate(state.timeZone))}`}
143
+ aria-label={`${labels.year}: ${yearFormatter.format(monthStart.toDate(state.timeZone))}`}
142
144
  className="datepicker-year"
143
145
  disabled={state.isDisabled}
144
146
  onClick={() => changeView('years')}
@@ -5,6 +5,7 @@ import { CalendarState, RangeCalendarState } from 'react-stately'
5
5
  import { CalendarDate, toCalendarDate } from '@internationalized/date'
6
6
 
7
7
  import { isWholeUnitDisabled } from '../../utils/isWholeUnitDisabled'
8
+ import { useCalendarLabels } from './labels'
8
9
 
9
10
  interface CalendarYearGridProps {
10
11
  // Whether to render the visually-hidden `aria-live` announcement of this view's current header
@@ -31,6 +32,7 @@ export const CalendarYearGrid = ({
31
32
  onSelect,
32
33
  state
33
34
  }: CalendarYearGridProps) => {
35
+ const labels = useCalendarLabels()
34
36
  const yearFormatter = useDateFormatter({
35
37
  calendar: monthStart.calendar.identifier,
36
38
  timeZone: state.timeZone,
@@ -76,7 +78,7 @@ export const CalendarYearGrid = ({
76
78
  <>
77
79
  <div className="datepicker-header">
78
80
  <button
79
- aria-label="Previous years"
81
+ aria-label={labels.previousYears}
80
82
  className="datepicker-arrow datepicker-arrow-prev"
81
83
  disabled={isPrevDisabled}
82
84
  onClick={() => setPageStart((start) => start - YEARS_PER_PAGE)}
@@ -88,7 +90,7 @@ export const CalendarYearGrid = ({
88
90
  </button>
89
91
  </div>
90
92
  <button
91
- aria-label="Next years"
93
+ aria-label={labels.nextYears}
92
94
  className="datepicker-arrow datepicker-arrow-next"
93
95
  disabled={isNextDisabled}
94
96
  onClick={() => setPageStart((start) => start + YEARS_PER_PAGE)}
@@ -97,7 +99,7 @@ export const CalendarYearGrid = ({
97
99
  </div>
98
100
  {announce && (
99
101
  <span role="status" className="visually-hidden">
100
- {`Select year, ${rangeLabel}`}
102
+ {`${labels.selectYear}, ${rangeLabel}`}
101
103
  </span>
102
104
  )}
103
105
  <div className="datepicker-content">
@@ -19,13 +19,13 @@
19
19
  }
20
20
 
21
21
  .datepicker-date-in-range.datepicker-date-range-start {
22
- @include border-top-start-radius(var(--border-radius-medium));
23
- @include border-bottom-start-radius(var(--border-radius-medium));
22
+ @include border-top-start-radius(var(--border-radius-md));
23
+ @include border-bottom-start-radius(var(--border-radius-md));
24
24
  }
25
25
 
26
26
  .datepicker-date-in-range.datepicker-date-range-end {
27
- @include border-top-end-radius(var(--border-radius-medium));
28
- @include border-bottom-end-radius(var(--border-radius-medium));
27
+ @include border-top-end-radius(var(--border-radius-md));
28
+ @include border-bottom-end-radius(var(--border-radius-md));
29
29
  }
30
30
 
31
31
  .datepicker-date-btn:is(.datepicker-date-range-start, .datepicker-date-range-end),
@@ -60,18 +60,18 @@
60
60
  padding-inline: 0 var(--padding-x);
61
61
  margin: 0;
62
62
  list-style: none;
63
- border-inline-end: var(--border-width-medium) solid var(--border-subtle);
63
+ border-inline-end: var(--border-width-md) solid var(--border-subtle);
64
64
  }
65
65
 
66
66
  .datepicker-preset {
67
- padding: var(--space-2xsmall) var(--space-xsmall);
67
+ padding: var(--space-2xs) var(--space-xs);
68
68
  color: var(--fg-main);
69
69
  text-align: start;
70
70
  white-space: nowrap;
71
71
  cursor: pointer;
72
72
  background-color: transparent;
73
73
  border: 0;
74
- @include border-radius(var(--border-radius-medium));
74
+ @include border-radius(var(--border-radius-md));
75
75
  }
76
76
 
77
77
  .datepicker-preset:hover {
@@ -79,7 +79,7 @@
79
79
  }
80
80
 
81
81
  .datepicker-preset:focus-visible {
82
- outline: var(--border-width-xlarge) solid var(--primary);
82
+ outline: var(--border-width-xl) solid var(--primary);
83
83
  outline-offset: -1px;
84
84
  }
85
85