@zentauri-ui/zentauri-components 1.4.51 → 1.4.62
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +63 -1
- package/cli/registry.json +2 -1
- package/dist/{chunk-UXGHUBNJ.mjs → chunk-2PJF7DLJ.mjs} +3 -3
- package/dist/{chunk-UXGHUBNJ.mjs.map → chunk-2PJF7DLJ.mjs.map} +1 -1
- package/dist/{chunk-WDCIZHXY.mjs → chunk-45FCOQ63.mjs} +5 -3
- package/dist/chunk-45FCOQ63.mjs.map +1 -0
- package/dist/{chunk-RDSPHBHK.mjs → chunk-4ANBTJ5G.mjs} +49 -6
- package/dist/chunk-4ANBTJ5G.mjs.map +1 -0
- package/dist/chunk-4E66ICIR.mjs +158 -0
- package/dist/chunk-4E66ICIR.mjs.map +1 -0
- package/dist/{chunk-XLAFQ24R.js → chunk-4U6FOCFK.js} +22 -14
- package/dist/chunk-4U6FOCFK.js.map +1 -0
- package/dist/{chunk-XWM2S6VV.mjs → chunk-EQSSYK27.mjs} +12 -10
- package/dist/chunk-EQSSYK27.mjs.map +1 -0
- package/dist/{chunk-5QB2KNZQ.js → chunk-FGGYDAX3.js} +5 -3
- package/dist/chunk-FGGYDAX3.js.map +1 -0
- package/dist/{chunk-7HL3A4YF.mjs → chunk-IK75NHRX.mjs} +63 -14
- package/dist/chunk-IK75NHRX.mjs.map +1 -0
- package/dist/{chunk-BORK3BJO.mjs → chunk-J56L4ZQ3.mjs} +10 -10
- package/dist/{chunk-BORK3BJO.mjs.map → chunk-J56L4ZQ3.mjs.map} +1 -1
- package/dist/{chunk-PGH27VTL.mjs → chunk-JF3FKUUP.mjs} +21 -13
- package/dist/chunk-JF3FKUUP.mjs.map +1 -0
- package/dist/{chunk-WZKGRU3U.js → chunk-MQZB5EPD.js} +92 -27
- package/dist/chunk-MQZB5EPD.js.map +1 -0
- package/dist/{chunk-N4NO3SYL.js → chunk-NX3IHMT7.js} +22 -14
- package/dist/chunk-NX3IHMT7.js.map +1 -0
- package/dist/{chunk-BVXTOEBI.mjs → chunk-OG2WM5YK.mjs} +45 -17
- package/dist/chunk-OG2WM5YK.mjs.map +1 -0
- package/dist/{chunk-IXDJ3IPG.mjs → chunk-OXS6UJUG.mjs} +21 -13
- package/dist/chunk-OXS6UJUG.mjs.map +1 -0
- package/dist/{chunk-PCK6LX3K.js → chunk-PFOV3U7W.js} +3 -3
- package/dist/{chunk-PCK6LX3K.js.map → chunk-PFOV3U7W.js.map} +1 -1
- package/dist/{chunk-2PQEXQVR.js → chunk-THCNTPPL.js} +62 -13
- package/dist/chunk-THCNTPPL.js.map +1 -0
- package/dist/chunk-UP6S75V5.js +160 -0
- package/dist/chunk-UP6S75V5.js.map +1 -0
- package/dist/{chunk-P5HUBXUX.js → chunk-V2IWLR4O.js} +48 -5
- package/dist/chunk-V2IWLR4O.js.map +1 -0
- package/dist/{chunk-3OR47XMY.js → chunk-VSKL5LOB.js} +45 -17
- package/dist/chunk-VSKL5LOB.js.map +1 -0
- package/dist/{chunk-E3DZNJAD.js → chunk-Y4EDWZKH.js} +12 -10
- package/dist/chunk-Y4EDWZKH.js.map +1 -0
- package/dist/{chunk-YNCD6TKE.mjs → chunk-Y4IFVO46.mjs} +93 -28
- package/dist/chunk-Y4IFVO46.mjs.map +1 -0
- package/dist/{chunk-BITDSQMR.js → chunk-ZNDHS5OK.js} +10 -10
- package/dist/{chunk-BITDSQMR.js.map → chunk-ZNDHS5OK.js.map} +1 -1
- package/dist/hooks/useFocusManagement/useFocusManagement.d.ts +5 -14
- package/dist/hooks/useFocusManagement/useFocusManagement.d.ts.map +1 -1
- package/dist/hooks/useFocusManagement.js +2 -2
- package/dist/hooks/useFocusManagement.mjs +1 -1
- package/dist/ui/badge/animated.js +2 -2
- package/dist/ui/badge/animated.mjs +1 -1
- package/dist/ui/badge/badge-base.d.ts +1 -1
- package/dist/ui/badge/badge-base.d.ts.map +1 -1
- package/dist/ui/badge/types.d.ts +1 -0
- package/dist/ui/badge/types.d.ts.map +1 -1
- package/dist/ui/badge/variants.d.ts +7 -7
- package/dist/ui/badge.js +4 -4
- package/dist/ui/badge.mjs +2 -2
- package/dist/ui/buttons/animated.js +3 -3
- package/dist/ui/buttons/animated.mjs +1 -1
- package/dist/ui/buttons.js +4 -4
- package/dist/ui/buttons.mjs +2 -2
- package/dist/ui/drawer/animated/drawer-content-animated.d.ts.map +1 -1
- package/dist/ui/drawer/animated.js +17 -18
- package/dist/ui/drawer/animated.js.map +1 -1
- package/dist/ui/drawer/animated.mjs +8 -9
- package/dist/ui/drawer/animated.mjs.map +1 -1
- package/dist/ui/drawer/drawer-base.d.ts +1 -1
- package/dist/ui/drawer/drawer-base.d.ts.map +1 -1
- package/dist/ui/drawer/types.d.ts +1 -0
- package/dist/ui/drawer/types.d.ts.map +1 -1
- package/dist/ui/drawer.js +12 -12
- package/dist/ui/drawer.mjs +2 -2
- package/dist/ui/dropdown/dropdown.d.ts +1 -1
- package/dist/ui/dropdown/dropdown.d.ts.map +1 -1
- package/dist/ui/dropdown/types.d.ts +1 -0
- package/dist/ui/dropdown/types.d.ts.map +1 -1
- package/dist/ui/dropdown/variants.d.ts +1 -1
- package/dist/ui/dropdown.js +25 -7
- package/dist/ui/dropdown.js.map +1 -1
- package/dist/ui/dropdown.mjs +26 -8
- package/dist/ui/dropdown.mjs.map +1 -1
- package/dist/ui/empty-state/animated.js +2 -2
- package/dist/ui/empty-state/animated.mjs +1 -1
- package/dist/ui/empty-state/empty-state-base.d.ts.map +1 -1
- package/dist/ui/empty-state/types.d.ts +1 -0
- package/dist/ui/empty-state/types.d.ts.map +1 -1
- package/dist/ui/empty-state.js +10 -10
- package/dist/ui/empty-state.mjs +2 -2
- package/dist/ui/file-upload/file-upload.d.ts.map +1 -1
- package/dist/ui/file-upload.js +1 -3
- package/dist/ui/file-upload.js.map +1 -1
- package/dist/ui/file-upload.mjs +1 -3
- package/dist/ui/file-upload.mjs.map +1 -1
- package/dist/ui/inputs/input-base.d.ts.map +1 -1
- package/dist/ui/inputs/types.d.ts +3 -1
- package/dist/ui/inputs/types.d.ts.map +1 -1
- package/dist/ui/inputs.js +46 -2
- package/dist/ui/inputs.js.map +1 -1
- package/dist/ui/inputs.mjs +46 -2
- package/dist/ui/inputs.mjs.map +1 -1
- package/dist/ui/modal/animated/modal-content-animated.d.ts.map +1 -1
- package/dist/ui/modal/animated.js +10 -11
- package/dist/ui/modal/animated.js.map +1 -1
- package/dist/ui/modal/animated.mjs +7 -8
- package/dist/ui/modal/animated.mjs.map +1 -1
- package/dist/ui/modal/modal-base.d.ts +4 -2
- package/dist/ui/modal/modal-base.d.ts.map +1 -1
- package/dist/ui/modal.js +13 -13
- package/dist/ui/modal.mjs +3 -3
- package/dist/ui/pagination.js +6 -6
- package/dist/ui/pagination.js.map +1 -1
- package/dist/ui/pagination.mjs +3 -3
- package/dist/ui/pagination.mjs.map +1 -1
- package/dist/ui/progress/animated/progress-animated.d.ts.map +1 -1
- package/dist/ui/progress/animated.js +49 -11
- package/dist/ui/progress/animated.js.map +1 -1
- package/dist/ui/progress/animated.mjs +44 -6
- package/dist/ui/progress/animated.mjs.map +1 -1
- package/dist/ui/progress/progress-base.d.ts.map +1 -1
- package/dist/ui/progress/types.d.ts +3 -0
- package/dist/ui/progress/types.d.ts.map +1 -1
- package/dist/ui/progress.js +9 -9
- package/dist/ui/progress.mjs +2 -2
- package/dist/ui/search/search-bar.d.ts +1 -1
- package/dist/ui/search/search-bar.d.ts.map +1 -1
- package/dist/ui/search/search-suggestion-list.d.ts.map +1 -1
- package/dist/ui/search.js +12 -6
- package/dist/ui/search.js.map +1 -1
- package/dist/ui/search.mjs +12 -6
- package/dist/ui/search.mjs.map +1 -1
- package/dist/ui/select/select.d.ts +1 -1
- package/dist/ui/select/select.d.ts.map +1 -1
- package/dist/ui/select/types.d.ts +1 -0
- package/dist/ui/select/types.d.ts.map +1 -1
- package/dist/ui/select/variants.d.ts +1 -1
- package/dist/ui/select/variants.d.ts.map +1 -1
- package/dist/ui/select.js +121 -39
- package/dist/ui/select.js.map +1 -1
- package/dist/ui/select.mjs +122 -40
- package/dist/ui/select.mjs.map +1 -1
- package/dist/ui/skeleton/variants.d.ts +1 -1
- package/dist/ui/slider/slider.d.ts.map +1 -1
- package/dist/ui/slider/types.d.ts +8 -2
- package/dist/ui/slider/types.d.ts.map +1 -1
- package/dist/ui/slider.js +43 -7
- package/dist/ui/slider.js.map +1 -1
- package/dist/ui/slider.mjs +43 -7
- package/dist/ui/slider.mjs.map +1 -1
- package/dist/ui/spinner/animated/spinner.d.ts.map +1 -1
- package/dist/ui/spinner/animated.js +62 -50
- package/dist/ui/spinner/animated.js.map +1 -1
- package/dist/ui/spinner/animated.mjs +63 -51
- package/dist/ui/spinner/animated.mjs.map +1 -1
- package/dist/ui/stepper/stepper.d.ts +2 -7
- package/dist/ui/stepper/stepper.d.ts.map +1 -1
- package/dist/ui/stepper/types.d.ts +3 -3
- package/dist/ui/stepper/types.d.ts.map +1 -1
- package/dist/ui/stepper/variants.d.ts +1 -1
- package/dist/ui/stepper.js +7 -5
- package/dist/ui/stepper.js.map +1 -1
- package/dist/ui/stepper.mjs +7 -5
- package/dist/ui/stepper.mjs.map +1 -1
- package/dist/ui/table/animated.js +8 -8
- package/dist/ui/table/animated.mjs +2 -2
- package/dist/ui/table/table-base.d.ts +1 -1
- package/dist/ui/table/table-base.d.ts.map +1 -1
- package/dist/ui/table/types.d.ts +5 -1
- package/dist/ui/table/types.d.ts.map +1 -1
- package/dist/ui/table.js +14 -14
- package/dist/ui/table.mjs +1 -1
- package/dist/ui/tabs/animated.js +2 -2
- package/dist/ui/tabs/animated.mjs +1 -1
- package/dist/ui/tabs/tabs-base.d.ts.map +1 -1
- package/dist/ui/tabs/types.d.ts +2 -1
- package/dist/ui/tabs/types.d.ts.map +1 -1
- package/dist/ui/tabs.js +9 -9
- package/dist/ui/tabs.mjs +1 -1
- package/dist/ui/toast/animated.js +7 -7
- package/dist/ui/toast/animated.mjs +1 -1
- package/dist/ui/toast.js +12 -12
- package/dist/ui/toast.mjs +1 -1
- package/dist/ui/toggle/toggle-base.d.ts.map +1 -1
- package/dist/ui/toggle.js +28 -3
- package/dist/ui/toggle.js.map +1 -1
- package/dist/ui/toggle.mjs +29 -4
- package/dist/ui/toggle.mjs.map +1 -1
- package/dist/ui/tooltip/animated.js +3 -3
- package/dist/ui/tooltip/animated.mjs +1 -1
- package/dist/ui/tooltip/tooltip-base.d.ts.map +1 -1
- package/dist/ui/tooltip/types.d.ts +1 -0
- package/dist/ui/tooltip/types.d.ts.map +1 -1
- package/dist/ui/tooltip.js +7 -7
- package/dist/ui/tooltip.mjs +1 -1
- package/dist/ui/typography/blockquote-base.d.ts +6 -0
- package/dist/ui/typography/blockquote-base.d.ts.map +1 -0
- package/dist/ui/typography/blockquote.d.ts +6 -0
- package/dist/ui/typography/blockquote.d.ts.map +1 -0
- package/dist/ui/typography/code-block-base.d.ts +6 -0
- package/dist/ui/typography/code-block-base.d.ts.map +1 -0
- package/dist/ui/typography/code-block.d.ts +6 -0
- package/dist/ui/typography/code-block.d.ts.map +1 -0
- package/dist/ui/typography/heading-base.d.ts +6 -0
- package/dist/ui/typography/heading-base.d.ts.map +1 -0
- package/dist/ui/typography/heading.d.ts +6 -0
- package/dist/ui/typography/heading.d.ts.map +1 -0
- package/dist/ui/typography/index.d.ts +9 -0
- package/dist/ui/typography/index.d.ts.map +1 -0
- package/dist/ui/typography/inline-code-base.d.ts +6 -0
- package/dist/ui/typography/inline-code-base.d.ts.map +1 -0
- package/dist/ui/typography/inline-code.d.ts +6 -0
- package/dist/ui/typography/inline-code.d.ts.map +1 -0
- package/dist/ui/typography/list-base.d.ts +10 -0
- package/dist/ui/typography/list-base.d.ts.map +1 -0
- package/dist/ui/typography/list.d.ts +12 -0
- package/dist/ui/typography/list.d.ts.map +1 -0
- package/dist/ui/typography/text-base.d.ts +6 -0
- package/dist/ui/typography/text-base.d.ts.map +1 -0
- package/dist/ui/typography/text.d.ts +6 -0
- package/dist/ui/typography/text.d.ts.map +1 -0
- package/dist/ui/typography/types.d.ts +56 -0
- package/dist/ui/typography/types.d.ts.map +1 -0
- package/dist/ui/typography/variants.d.ts +16 -0
- package/dist/ui/typography/variants.d.ts.map +1 -0
- package/dist/ui/typography.js +334 -0
- package/dist/ui/typography.js.map +1 -0
- package/dist/ui/typography.mjs +321 -0
- package/dist/ui/typography.mjs.map +1 -0
- package/package.json +1 -1
- package/src/hooks/useFocusManagement/useFocusManagement.test.tsx +8 -0
- package/src/hooks/useFocusManagement/useFocusManagement.ts +162 -33
- package/src/ui/badge/badge-base.tsx +4 -1
- package/src/ui/badge/types.ts +1 -0
- package/src/ui/badge/variants.ts +7 -7
- package/src/ui/buttons/button.test.tsx +1 -1
- package/src/ui/buttons/variants.ts +8 -8
- package/src/ui/drawer/animated/drawer-content-animated.tsx +4 -5
- package/src/ui/drawer/drawer-base.tsx +16 -8
- package/src/ui/drawer/types.ts +1 -0
- package/src/ui/dropdown/dropdown.test.tsx +1 -3
- package/src/ui/dropdown/dropdown.tsx +23 -5
- package/src/ui/dropdown/types.ts +1 -0
- package/src/ui/dropdown/variants.ts +2 -2
- package/src/ui/empty-state/empty-state-base.tsx +9 -1
- package/src/ui/empty-state/types.ts +1 -0
- package/src/ui/file-upload/file-upload.tsx +0 -2
- package/src/ui/inputs/input-base.tsx +60 -6
- package/src/ui/inputs/types.ts +3 -1
- package/src/ui/modal/animated/modal-content-animated.tsx +4 -5
- package/src/ui/modal/modal-base.tsx +19 -9
- package/src/ui/modal/modal.test.tsx +38 -0
- package/src/ui/pagination/pagination.tsx +2 -2
- package/src/ui/progress/animated/progress-animated.tsx +42 -3
- package/src/ui/progress/progress-base.tsx +59 -3
- package/src/ui/progress/types.ts +3 -0
- package/src/ui/search/search-bar.tsx +6 -1
- package/src/ui/search/search-suggestion-list.tsx +14 -6
- package/src/ui/select/select.tsx +97 -6
- package/src/ui/select/types.ts +1 -0
- package/src/ui/select/variants.ts +5 -3
- package/src/ui/slider/slider.test.tsx +25 -1
- package/src/ui/slider/slider.tsx +45 -4
- package/src/ui/slider/types.ts +8 -2
- package/src/ui/spinner/animated/spinner.tsx +4 -0
- package/src/ui/stepper/stepper.test.tsx +6 -7
- package/src/ui/stepper/stepper.tsx +11 -10
- package/src/ui/stepper/types.ts +7 -3
- package/src/ui/table/table-base.tsx +32 -6
- package/src/ui/table/types.ts +8 -1
- package/src/ui/tabs/tabs-base.tsx +71 -10
- package/src/ui/tabs/types.ts +2 -1
- package/src/ui/tabs/variants.ts +1 -1
- package/src/ui/toast/toast-base.tsx +1 -1
- package/src/ui/toggle/toggle-base.tsx +37 -4
- package/src/ui/tooltip/tooltip-base.tsx +119 -22
- package/src/ui/tooltip/types.ts +1 -0
- package/src/ui/tooltip/variants.ts +2 -2
- package/src/ui/typography/blockquote-base.tsx +39 -0
- package/src/ui/typography/blockquote.tsx +8 -0
- package/src/ui/typography/code-block-base.tsx +37 -0
- package/src/ui/typography/code-block.tsx +8 -0
- package/src/ui/typography/heading-base.tsx +59 -0
- package/src/ui/typography/heading.tsx +8 -0
- package/src/ui/typography/index.ts +28 -0
- package/src/ui/typography/inline-code-base.tsx +27 -0
- package/src/ui/typography/inline-code.tsx +8 -0
- package/src/ui/typography/list-base.tsx +88 -0
- package/src/ui/typography/list.tsx +15 -0
- package/src/ui/typography/text-base.tsx +43 -0
- package/src/ui/typography/text.tsx +8 -0
- package/src/ui/typography/types.ts +90 -0
- package/src/ui/typography/typography.test.tsx +80 -0
- package/src/ui/typography/variants.ts +72 -0
- package/dist/chunk-2PQEXQVR.js.map +0 -1
- package/dist/chunk-3OR47XMY.js.map +0 -1
- package/dist/chunk-5QB2KNZQ.js.map +0 -1
- package/dist/chunk-7HL3A4YF.mjs.map +0 -1
- package/dist/chunk-BVXTOEBI.mjs.map +0 -1
- package/dist/chunk-E3DZNJAD.js.map +0 -1
- package/dist/chunk-IXDJ3IPG.mjs.map +0 -1
- package/dist/chunk-N4NO3SYL.js.map +0 -1
- package/dist/chunk-P5HUBXUX.js.map +0 -1
- package/dist/chunk-PGH27VTL.mjs.map +0 -1
- package/dist/chunk-RDSPHBHK.mjs.map +0 -1
- package/dist/chunk-WDCIZHXY.mjs.map +0 -1
- package/dist/chunk-WL5I7RVS.mjs +0 -54
- package/dist/chunk-WL5I7RVS.mjs.map +0 -1
- package/dist/chunk-WZKGRU3U.js.map +0 -1
- package/dist/chunk-XLAFQ24R.js.map +0 -1
- package/dist/chunk-XWM2S6VV.mjs.map +0 -1
- package/dist/chunk-YNCD6TKE.mjs.map +0 -1
- package/dist/chunk-YPLVTUYL.js +0 -56
- package/dist/chunk-YPLVTUYL.js.map +0 -1
package/src/ui/select/select.tsx
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
"use client";
|
|
2
|
-
import { useState, useEffect, useCallback, useRef } from "react";
|
|
2
|
+
import { useState, useEffect, useCallback, useRef, useId } from "react";
|
|
3
3
|
import {
|
|
4
4
|
SelectProps,
|
|
5
5
|
SelectOption,
|
|
@@ -32,6 +32,7 @@ export const Select = ({
|
|
|
32
32
|
onChange,
|
|
33
33
|
multiple = true,
|
|
34
34
|
}: SelectProps) => {
|
|
35
|
+
const listboxId = `${useId()}-listbox`;
|
|
35
36
|
const [internal, setInternal] = useState<string[]>(defaultValue);
|
|
36
37
|
const [open, setOpen] = useState(false);
|
|
37
38
|
const [options, setOptions] = useState<SelectOption[]>([]);
|
|
@@ -97,6 +98,7 @@ export const Select = ({
|
|
|
97
98
|
registerOption,
|
|
98
99
|
options,
|
|
99
100
|
multiple,
|
|
101
|
+
listboxId,
|
|
100
102
|
}}
|
|
101
103
|
>
|
|
102
104
|
<div ref={rootRef} className="relative w-full">
|
|
@@ -110,16 +112,25 @@ export const SelectTrigger = ({
|
|
|
110
112
|
className,
|
|
111
113
|
variant,
|
|
112
114
|
size,
|
|
115
|
+
onClick,
|
|
113
116
|
...props
|
|
114
117
|
}: SelectTriggerProps) => {
|
|
115
|
-
const { open, setOpen } = useSelect();
|
|
118
|
+
const { open, setOpen, listboxId } = useSelect();
|
|
116
119
|
|
|
117
120
|
return (
|
|
118
121
|
<button
|
|
119
122
|
type="button"
|
|
120
|
-
|
|
123
|
+
aria-expanded={open}
|
|
124
|
+
aria-haspopup="listbox"
|
|
125
|
+
aria-controls={listboxId}
|
|
121
126
|
className={cn(selectTriggerVariants({ variant, size }), className)}
|
|
122
127
|
{...props}
|
|
128
|
+
onClick={(event) => {
|
|
129
|
+
onClick?.(event);
|
|
130
|
+
if (!event.defaultPrevented) {
|
|
131
|
+
setOpen(!open);
|
|
132
|
+
}
|
|
133
|
+
}}
|
|
123
134
|
/>
|
|
124
135
|
);
|
|
125
136
|
};
|
|
@@ -161,12 +172,85 @@ export const SelectContent = ({
|
|
|
161
172
|
spacing = "default",
|
|
162
173
|
...props
|
|
163
174
|
}: SelectContentProps) => {
|
|
164
|
-
const { open } = useSelect();
|
|
175
|
+
const { open, listboxId, multiple } = useSelect();
|
|
176
|
+
const panelRef = useRef<HTMLDivElement>(null);
|
|
177
|
+
|
|
178
|
+
useEffect(() => {
|
|
179
|
+
if (!open) {
|
|
180
|
+
return;
|
|
181
|
+
}
|
|
182
|
+
const panel = panelRef.current;
|
|
183
|
+
if (!panel) {
|
|
184
|
+
return;
|
|
185
|
+
}
|
|
186
|
+
const opts = Array.from(
|
|
187
|
+
panel.querySelectorAll<HTMLElement>('[role="option"]'),
|
|
188
|
+
).filter((el) => el.getAttribute("aria-disabled") !== "true");
|
|
189
|
+
requestAnimationFrame(() => opts[0]?.focus());
|
|
190
|
+
}, [open]);
|
|
191
|
+
|
|
192
|
+
useEffect(() => {
|
|
193
|
+
if (!open) {
|
|
194
|
+
return;
|
|
195
|
+
}
|
|
196
|
+
const panel = panelRef.current;
|
|
197
|
+
if (!panel) {
|
|
198
|
+
return;
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
const enabledOptions = () =>
|
|
202
|
+
Array.from(panel.querySelectorAll<HTMLElement>('[role="option"]')).filter(
|
|
203
|
+
(el) => el.getAttribute("aria-disabled") !== "true",
|
|
204
|
+
);
|
|
205
|
+
|
|
206
|
+
const handleKeyDown = (event: KeyboardEvent) => {
|
|
207
|
+
const options = enabledOptions();
|
|
208
|
+
if (options.length === 0) {
|
|
209
|
+
return;
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
const idx = options.findIndex((el) => el === document.activeElement);
|
|
213
|
+
|
|
214
|
+
if (event.key === "ArrowDown") {
|
|
215
|
+
event.preventDefault();
|
|
216
|
+
const next = idx < 0 ? 0 : Math.min(idx + 1, options.length - 1);
|
|
217
|
+
options[next]?.focus();
|
|
218
|
+
return;
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
if (event.key === "ArrowUp") {
|
|
222
|
+
event.preventDefault();
|
|
223
|
+
const prev =
|
|
224
|
+
idx <= 0 ? options.length - 1 : Math.max(idx - 1, 0);
|
|
225
|
+
options[prev]?.focus();
|
|
226
|
+
return;
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
if (event.key === "Home") {
|
|
230
|
+
event.preventDefault();
|
|
231
|
+
options[0]?.focus();
|
|
232
|
+
return;
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
if (event.key === "End") {
|
|
236
|
+
event.preventDefault();
|
|
237
|
+
options[options.length - 1]?.focus();
|
|
238
|
+
}
|
|
239
|
+
};
|
|
240
|
+
|
|
241
|
+
panel.addEventListener("keydown", handleKeyDown);
|
|
242
|
+
return () => panel.removeEventListener("keydown", handleKeyDown);
|
|
243
|
+
}, [open]);
|
|
165
244
|
|
|
166
245
|
if (!open) return null;
|
|
167
246
|
|
|
168
247
|
return (
|
|
169
248
|
<div
|
|
249
|
+
ref={panelRef}
|
|
250
|
+
id={listboxId}
|
|
251
|
+
role="listbox"
|
|
252
|
+
aria-multiselectable={multiple}
|
|
253
|
+
tabIndex={-1}
|
|
170
254
|
className={cn(
|
|
171
255
|
selectContentVariants({ appearance, size, spacing }),
|
|
172
256
|
className,
|
|
@@ -198,10 +282,17 @@ export const SelectItem = ({
|
|
|
198
282
|
<div
|
|
199
283
|
role="option"
|
|
200
284
|
aria-selected={isActive}
|
|
201
|
-
|
|
285
|
+
aria-disabled={disabled ? true : undefined}
|
|
286
|
+
tabIndex={-1}
|
|
202
287
|
onClick={() => !disabled && toggleValue(value)}
|
|
203
288
|
onKeyDown={(e) => {
|
|
204
|
-
if (
|
|
289
|
+
if (disabled) {
|
|
290
|
+
return;
|
|
291
|
+
}
|
|
292
|
+
if (e.key === "Enter" || e.key === " ") {
|
|
293
|
+
e.preventDefault();
|
|
294
|
+
toggleValue(value);
|
|
295
|
+
}
|
|
205
296
|
}}
|
|
206
297
|
data-selected={isActive ? "true" : "false"}
|
|
207
298
|
className={cn(
|
package/src/ui/select/types.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { cva } from "class-variance-authority";
|
|
2
2
|
|
|
3
3
|
export const selectTriggerVariants = cva(
|
|
4
|
-
"flex items-center justify-between rounded-md border transition-all focus:outline-none",
|
|
4
|
+
"flex items-center justify-between rounded-md border transition-all focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-gray-400 focus-visible:ring-offset-2",
|
|
5
5
|
{
|
|
6
6
|
variants: {
|
|
7
7
|
variant: {
|
|
@@ -50,8 +50,10 @@ export const selectTriggerVariants = cva(
|
|
|
50
50
|
},
|
|
51
51
|
);
|
|
52
52
|
|
|
53
|
-
export const selectItemVariants = cva(
|
|
54
|
-
|
|
53
|
+
export const selectItemVariants = cva(
|
|
54
|
+
"cursor-pointer px-3 py-2 rounded-md focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-gray-400 focus-visible:ring-inset",
|
|
55
|
+
{
|
|
56
|
+
variants: {
|
|
55
57
|
appearance: {
|
|
56
58
|
default:
|
|
57
59
|
"bg-white text-gray-900 data-[selected=true]:bg-gray-200 data-[selected=true]:text-gray-900",
|
|
@@ -41,7 +41,9 @@ describe("Slider", () => {
|
|
|
41
41
|
</SliderTrack>
|
|
42
42
|
</Slider>,
|
|
43
43
|
);
|
|
44
|
-
|
|
44
|
+
const thumb = screen.getByRole("slider");
|
|
45
|
+
expect(thumb).toHaveAttribute("aria-valuenow", "25");
|
|
46
|
+
expect(thumb).toHaveAttribute("aria-label", "Level");
|
|
45
47
|
});
|
|
46
48
|
|
|
47
49
|
it("should adjust value with keyboard", async () => {
|
|
@@ -91,4 +93,26 @@ describe("RangeSlider", () => {
|
|
|
91
93
|
);
|
|
92
94
|
expect(screen.getAllByRole("slider")).toHaveLength(2);
|
|
93
95
|
});
|
|
96
|
+
|
|
97
|
+
it("should give each thumb an accessible name when aria-label is set", () => {
|
|
98
|
+
render(<RangeSlider defaultValue={[10, 90]} aria-label="Budget" />);
|
|
99
|
+
const thumbs = screen.getAllByRole("slider");
|
|
100
|
+
expect(thumbs[0]).toHaveAttribute("aria-label", "Budget, minimum");
|
|
101
|
+
expect(thumbs[1]).toHaveAttribute("aria-label", "Budget, maximum");
|
|
102
|
+
});
|
|
103
|
+
|
|
104
|
+
it("should mirror aria-labelledby onto thumbs when aria-label is omitted", () => {
|
|
105
|
+
render(
|
|
106
|
+
<>
|
|
107
|
+
<span id="range-lbl">Volume band</span>
|
|
108
|
+
<RangeSlider
|
|
109
|
+
defaultValue={[10, 90]}
|
|
110
|
+
aria-labelledby="range-lbl"
|
|
111
|
+
/>
|
|
112
|
+
</>,
|
|
113
|
+
);
|
|
114
|
+
const thumbs = screen.getAllByRole("slider");
|
|
115
|
+
expect(thumbs[0]).toHaveAttribute("aria-labelledby", "range-lbl");
|
|
116
|
+
expect(thumbs[1]).toHaveAttribute("aria-labelledby", "range-lbl");
|
|
117
|
+
});
|
|
94
118
|
});
|
package/src/ui/slider/slider.tsx
CHANGED
|
@@ -208,8 +208,21 @@ export function Slider({
|
|
|
208
208
|
size: size ?? "md",
|
|
209
209
|
appearance: appearance ?? "default",
|
|
210
210
|
trackRef,
|
|
211
|
+
"aria-label": ariaLabel,
|
|
212
|
+
"aria-labelledby": ariaLabelledBy,
|
|
211
213
|
}),
|
|
212
|
-
[
|
|
214
|
+
[
|
|
215
|
+
appearance,
|
|
216
|
+
ariaLabel,
|
|
217
|
+
ariaLabelledBy,
|
|
218
|
+
disabled,
|
|
219
|
+
max,
|
|
220
|
+
min,
|
|
221
|
+
setValue,
|
|
222
|
+
size,
|
|
223
|
+
step,
|
|
224
|
+
value,
|
|
225
|
+
],
|
|
213
226
|
);
|
|
214
227
|
|
|
215
228
|
return (
|
|
@@ -303,8 +316,18 @@ export function SliderThumb({
|
|
|
303
316
|
ref: refProp,
|
|
304
317
|
...rest
|
|
305
318
|
}: SliderThumbProps & { ref?: Ref<HTMLDivElement> }) {
|
|
306
|
-
const {
|
|
307
|
-
|
|
319
|
+
const {
|
|
320
|
+
min,
|
|
321
|
+
max,
|
|
322
|
+
value,
|
|
323
|
+
step,
|
|
324
|
+
setValue,
|
|
325
|
+
disabled,
|
|
326
|
+
size,
|
|
327
|
+
trackRef,
|
|
328
|
+
"aria-label": sliderAriaLabel,
|
|
329
|
+
"aria-labelledby": sliderAriaLabelledBy,
|
|
330
|
+
} = useSliderContext("SliderThumb");
|
|
308
331
|
/** Horizontal thumb position; same mapping as `SliderRange` width uses. */
|
|
309
332
|
const pct = max === min ? 0 : ((value - min) / (max - min)) * 100;
|
|
310
333
|
|
|
@@ -414,6 +437,8 @@ export function SliderThumb({
|
|
|
414
437
|
role="slider"
|
|
415
438
|
tabIndex={disabled ? -1 : 0}
|
|
416
439
|
data-slot="slider-thumb"
|
|
440
|
+
aria-label={sliderAriaLabel}
|
|
441
|
+
aria-labelledby={sliderAriaLabelledBy}
|
|
417
442
|
aria-valuemin={min}
|
|
418
443
|
aria-valuemax={max}
|
|
419
444
|
aria-valuenow={value}
|
|
@@ -561,6 +586,13 @@ export function RangeSlider({
|
|
|
561
586
|
|
|
562
587
|
const resolvedSize = size ?? "md";
|
|
563
588
|
|
|
589
|
+
const lowThumbAriaLabel =
|
|
590
|
+
ariaLabel !== undefined ? `${ariaLabel}, minimum` : undefined;
|
|
591
|
+
const highThumbAriaLabel =
|
|
592
|
+
ariaLabel !== undefined ? `${ariaLabel}, maximum` : undefined;
|
|
593
|
+
const thumbAriaLabelledBy =
|
|
594
|
+
ariaLabel === undefined ? ariaLabelledBy : undefined;
|
|
595
|
+
|
|
564
596
|
return (
|
|
565
597
|
<div
|
|
566
598
|
ref={ref}
|
|
@@ -568,7 +600,6 @@ export function RangeSlider({
|
|
|
568
600
|
role="group"
|
|
569
601
|
aria-label={ariaLabel}
|
|
570
602
|
aria-labelledby={ariaLabelledBy}
|
|
571
|
-
aria-valuetext={`${lo} – ${hi}`}
|
|
572
603
|
className={cn(sliderRootVariants({ size: resolvedSize }), className)}
|
|
573
604
|
{...rest}
|
|
574
605
|
>
|
|
@@ -596,6 +627,8 @@ export function RangeSlider({
|
|
|
596
627
|
trackRef={trackRef}
|
|
597
628
|
onMoveClientX={(x) => moveThumb(0, x)}
|
|
598
629
|
onNudge={(delta) => setPair([lo + delta, hi])}
|
|
630
|
+
aria-label={lowThumbAriaLabel}
|
|
631
|
+
aria-labelledby={thumbAriaLabelledBy}
|
|
599
632
|
/>
|
|
600
633
|
<RangeThumb
|
|
601
634
|
disabled={disabled}
|
|
@@ -608,6 +641,8 @@ export function RangeSlider({
|
|
|
608
641
|
trackRef={trackRef}
|
|
609
642
|
onMoveClientX={(x) => moveThumb(1, x)}
|
|
610
643
|
onNudge={(delta) => setPair([lo, hi + delta])}
|
|
644
|
+
aria-label={highThumbAriaLabel}
|
|
645
|
+
aria-labelledby={thumbAriaLabelledBy}
|
|
611
646
|
/>
|
|
612
647
|
</div>
|
|
613
648
|
</div>
|
|
@@ -629,6 +664,8 @@ type RangeThumbProps = {
|
|
|
629
664
|
onMoveClientX: (clientX: number) => void;
|
|
630
665
|
/** Relative keyboard adjustment in value units; parent merges into the pair. */
|
|
631
666
|
onNudge: (delta: number) => void;
|
|
667
|
+
"aria-label"?: string;
|
|
668
|
+
"aria-labelledby"?: string;
|
|
632
669
|
};
|
|
633
670
|
|
|
634
671
|
/** Private thumb implementation shared by the low and high endpoints. */
|
|
@@ -643,6 +680,8 @@ function RangeThumb({
|
|
|
643
680
|
trackRef,
|
|
644
681
|
onMoveClientX,
|
|
645
682
|
onNudge,
|
|
683
|
+
"aria-label": thumbAriaLabel,
|
|
684
|
+
"aria-labelledby": thumbAriaLabelledBy,
|
|
646
685
|
}: RangeThumbProps) {
|
|
647
686
|
const onPointerDown = useCallback(
|
|
648
687
|
(event: ReactPointerEvent<HTMLDivElement>) => {
|
|
@@ -712,6 +751,8 @@ function RangeThumb({
|
|
|
712
751
|
role="slider"
|
|
713
752
|
tabIndex={disabled ? -1 : 0}
|
|
714
753
|
data-slot="range-slider-thumb"
|
|
754
|
+
aria-label={thumbAriaLabel}
|
|
755
|
+
aria-labelledby={thumbAriaLabelledBy}
|
|
715
756
|
aria-valuemin={min}
|
|
716
757
|
aria-valuemax={max}
|
|
717
758
|
aria-valuenow={value}
|
package/src/ui/slider/types.ts
CHANGED
|
@@ -20,9 +20,9 @@ export type SliderProps = SliderRootVariantProps & {
|
|
|
20
20
|
onValueChange?: (value: number) => void;
|
|
21
21
|
disabled?: boolean;
|
|
22
22
|
appearance?: VariantProps<typeof sliderRangeVariants>["appearance"];
|
|
23
|
-
/**
|
|
23
|
+
/** Accessible name for the slider (applied to the focusable thumb). */
|
|
24
24
|
"aria-label"?: string;
|
|
25
|
-
/**
|
|
25
|
+
/** Visible label element id (`aria-labelledby` on the focusable thumb). */
|
|
26
26
|
"aria-labelledby"?: string;
|
|
27
27
|
children?: ReactNode;
|
|
28
28
|
} & Omit<ComponentPropsWithoutRef<"div">, "children" | "defaultValue">;
|
|
@@ -45,7 +45,9 @@ export type RangeSliderProps = SliderRootVariantProps & {
|
|
|
45
45
|
onValueChange?: (value: [number, number]) => void;
|
|
46
46
|
disabled?: boolean;
|
|
47
47
|
appearance?: VariantProps<typeof sliderRangeVariants>["appearance"];
|
|
48
|
+
/** Accessible name for the range control (each thumb gets a distinct suffix). */
|
|
48
49
|
"aria-label"?: string;
|
|
50
|
+
/** Visible label element id for each thumb when `aria-label` is not used. */
|
|
49
51
|
"aria-labelledby"?: string;
|
|
50
52
|
} & Omit<ComponentPropsWithoutRef<"div">, "children" | "defaultValue">;
|
|
51
53
|
|
|
@@ -63,4 +65,8 @@ export type SliderCtx = {
|
|
|
63
65
|
size: NonNullable<SliderProps["size"]>;
|
|
64
66
|
appearance: SliderAppearance;
|
|
65
67
|
trackRef: RefObject<HTMLDivElement | null>;
|
|
68
|
+
/** Mirrored from `<Slider>` so the focusable thumb exposes an accessible name. */
|
|
69
|
+
"aria-label"?: string;
|
|
70
|
+
/** Mirrored from `<Slider>` so the focusable thumb exposes an accessible name. */
|
|
71
|
+
"aria-labelledby"?: string;
|
|
66
72
|
};
|
|
@@ -33,6 +33,7 @@ export function Spinner(props: SpinnerProps) {
|
|
|
33
33
|
initial={false}
|
|
34
34
|
{...rest}
|
|
35
35
|
>
|
|
36
|
+
<span className="sr-only">{ariaLabel}</span>
|
|
36
37
|
<motion.span
|
|
37
38
|
className="block size-full rounded-full border-2 border-current border-t-transparent"
|
|
38
39
|
animate={{ rotate: 360 }}
|
|
@@ -62,6 +63,7 @@ export function Spinner(props: SpinnerProps) {
|
|
|
62
63
|
initial={false}
|
|
63
64
|
{...rest}
|
|
64
65
|
>
|
|
66
|
+
<span className="sr-only">{ariaLabel}</span>
|
|
65
67
|
{[0, 1, 2].map((index) => (
|
|
66
68
|
<motion.span
|
|
67
69
|
key={index}
|
|
@@ -91,6 +93,7 @@ export function Spinner(props: SpinnerProps) {
|
|
|
91
93
|
initial={false}
|
|
92
94
|
{...rest}
|
|
93
95
|
>
|
|
96
|
+
<span className="sr-only">{ariaLabel}</span>
|
|
94
97
|
<motion.span
|
|
95
98
|
className="block size-full rounded-full bg-current"
|
|
96
99
|
animate={{ scale: [0.75, 1, 0.75], opacity: [0.45, 1, 0.45] }}
|
|
@@ -122,6 +125,7 @@ export function Spinner(props: SpinnerProps) {
|
|
|
122
125
|
initial={false}
|
|
123
126
|
{...rest}
|
|
124
127
|
>
|
|
128
|
+
<span className="sr-only">{ariaLabel}</span>
|
|
125
129
|
{[0, 1, 2, 3].map((index) => (
|
|
126
130
|
<motion.span
|
|
127
131
|
key={index}
|
|
@@ -19,7 +19,7 @@ describe("Stepper", () => {
|
|
|
19
19
|
expect(StepperDescription.displayName).toBe("StepperDescription");
|
|
20
20
|
});
|
|
21
21
|
|
|
22
|
-
it("should stamp data-slot on stepper root and use list
|
|
22
|
+
it("should stamp data-slot on stepper root and use ordered list markup", () => {
|
|
23
23
|
render(
|
|
24
24
|
<Stepper>
|
|
25
25
|
<StepperItem>
|
|
@@ -30,11 +30,10 @@ describe("Stepper", () => {
|
|
|
30
30
|
);
|
|
31
31
|
const root = document.querySelector('[data-slot="stepper"]');
|
|
32
32
|
expect(root).toBeTruthy();
|
|
33
|
-
expect(root).
|
|
34
|
-
expect(
|
|
35
|
-
"
|
|
36
|
-
|
|
37
|
-
);
|
|
33
|
+
expect(root?.tagName).toBe("OL");
|
|
34
|
+
expect(
|
|
35
|
+
document.querySelector('[data-slot="stepper-item"]')?.tagName,
|
|
36
|
+
).toBe("LI");
|
|
38
37
|
});
|
|
39
38
|
|
|
40
39
|
it("should apply default upcoming appearance to indicators", () => {
|
|
@@ -153,7 +152,7 @@ describe("Stepper", () => {
|
|
|
153
152
|
});
|
|
154
153
|
|
|
155
154
|
it("should forward ref on Stepper", () => {
|
|
156
|
-
const ref = createRef<
|
|
155
|
+
const ref = createRef<HTMLOListElement>();
|
|
157
156
|
render(
|
|
158
157
|
<Stepper ref={ref}>
|
|
159
158
|
<StepperItem>
|
|
@@ -6,7 +6,6 @@ import {
|
|
|
6
6
|
isValidElement,
|
|
7
7
|
useContext,
|
|
8
8
|
useMemo,
|
|
9
|
-
type Ref,
|
|
10
9
|
} from "react";
|
|
11
10
|
|
|
12
11
|
import { cn } from "../../lib/utils";
|
|
@@ -54,7 +53,7 @@ export function Stepper({
|
|
|
54
53
|
children,
|
|
55
54
|
ref,
|
|
56
55
|
...rest
|
|
57
|
-
}: StepperProps
|
|
56
|
+
}: StepperProps) {
|
|
58
57
|
const items = useMemo(
|
|
59
58
|
() => Children.toArray(children).filter(isValidElement),
|
|
60
59
|
[children],
|
|
@@ -70,11 +69,14 @@ export function Stepper({
|
|
|
70
69
|
|
|
71
70
|
return (
|
|
72
71
|
<StepperContext.Provider value={ctx}>
|
|
73
|
-
<
|
|
72
|
+
<ol
|
|
74
73
|
ref={ref}
|
|
75
74
|
data-slot="stepper"
|
|
76
|
-
|
|
77
|
-
|
|
75
|
+
className={cn(
|
|
76
|
+
stepperVariants({ orientation }),
|
|
77
|
+
"m-0 list-none p-0",
|
|
78
|
+
className,
|
|
79
|
+
)}
|
|
78
80
|
{...rest}
|
|
79
81
|
>
|
|
80
82
|
{items.map((child, index) => (
|
|
@@ -82,7 +84,7 @@ export function Stepper({
|
|
|
82
84
|
{child}
|
|
83
85
|
</StepperIndexContext.Provider>
|
|
84
86
|
))}
|
|
85
|
-
</
|
|
87
|
+
</ol>
|
|
86
88
|
</StepperContext.Provider>
|
|
87
89
|
);
|
|
88
90
|
}
|
|
@@ -94,18 +96,17 @@ export function StepperItem({
|
|
|
94
96
|
ref,
|
|
95
97
|
children,
|
|
96
98
|
...rest
|
|
97
|
-
}: StepperItemProps
|
|
99
|
+
}: StepperItemProps) {
|
|
98
100
|
const { orientation } = useStepper("StepperItem");
|
|
99
101
|
return (
|
|
100
|
-
<
|
|
102
|
+
<li
|
|
101
103
|
ref={ref}
|
|
102
104
|
data-slot="stepper-item"
|
|
103
|
-
role="listitem"
|
|
104
105
|
className={cn(stepperItemVariants({ orientation }), className)}
|
|
105
106
|
{...rest}
|
|
106
107
|
>
|
|
107
108
|
{children}
|
|
108
|
-
</
|
|
109
|
+
</li>
|
|
109
110
|
);
|
|
110
111
|
}
|
|
111
112
|
|
package/src/ui/stepper/types.ts
CHANGED
|
@@ -1,5 +1,9 @@
|
|
|
1
1
|
import type { VariantProps } from "class-variance-authority";
|
|
2
|
-
import type {
|
|
2
|
+
import type {
|
|
3
|
+
ComponentPropsWithoutRef,
|
|
4
|
+
ComponentPropsWithRef,
|
|
5
|
+
ReactNode,
|
|
6
|
+
} from "react";
|
|
3
7
|
|
|
4
8
|
import type { stepperIndicatorVariants, stepperVariants } from "./variants";
|
|
5
9
|
|
|
@@ -8,9 +12,9 @@ type StepperVariantProps = VariantProps<typeof stepperVariants>;
|
|
|
8
12
|
export type StepperProps = StepperVariantProps & {
|
|
9
13
|
size?: VariantProps<typeof stepperIndicatorVariants>["size"];
|
|
10
14
|
children?: ReactNode;
|
|
11
|
-
} & Omit<
|
|
15
|
+
} & Omit<ComponentPropsWithRef<"ol">, "children">;
|
|
12
16
|
|
|
13
|
-
export type StepperItemProps =
|
|
17
|
+
export type StepperItemProps = ComponentPropsWithRef<"li"> & {
|
|
14
18
|
children?: ReactNode;
|
|
15
19
|
};
|
|
16
20
|
|
|
@@ -30,6 +30,7 @@ export function TableBase(props: TableProps) {
|
|
|
30
30
|
size = "md",
|
|
31
31
|
textAlign = "left",
|
|
32
32
|
stickyHeader = false,
|
|
33
|
+
scrollAreaAriaLabel,
|
|
33
34
|
children,
|
|
34
35
|
ref,
|
|
35
36
|
...rest
|
|
@@ -47,11 +48,19 @@ export function TableBase(props: TableProps) {
|
|
|
47
48
|
|
|
48
49
|
return (
|
|
49
50
|
<TableContext.Provider value={ctx}>
|
|
50
|
-
<div
|
|
51
|
+
<div
|
|
52
|
+
data-slot="table-scroll"
|
|
53
|
+
tabIndex={0}
|
|
54
|
+
role="region"
|
|
55
|
+
aria-label={scrollAreaAriaLabel ?? "Scrollable table"}
|
|
56
|
+
className={cn(
|
|
57
|
+
"relative w-full overflow-auto",
|
|
58
|
+
"outline-none focus-visible:ring-2 focus-visible:ring-slate-300 focus-visible:ring-offset-2 focus-visible:ring-offset-slate-950",
|
|
59
|
+
)}
|
|
60
|
+
>
|
|
51
61
|
<table
|
|
52
62
|
ref={ref}
|
|
53
63
|
data-slot="table"
|
|
54
|
-
role="table"
|
|
55
64
|
className={cn(
|
|
56
65
|
tableVariants({ appearance, size, stickyHeader }),
|
|
57
66
|
"w-full min-w-0 table",
|
|
@@ -163,17 +172,34 @@ export function TableCell({
|
|
|
163
172
|
className,
|
|
164
173
|
children,
|
|
165
174
|
ref,
|
|
175
|
+
scope,
|
|
166
176
|
...rest
|
|
167
177
|
}: TableCellProps) {
|
|
168
178
|
const { appearance, size, textAlign } = useTableContext("TableCell");
|
|
179
|
+
const cellClassName = cn(
|
|
180
|
+
tableCellVariants({ appearance, size, textAlign }),
|
|
181
|
+
className,
|
|
182
|
+
);
|
|
183
|
+
|
|
184
|
+
if (scope !== undefined) {
|
|
185
|
+
return (
|
|
186
|
+
<th
|
|
187
|
+
ref={ref}
|
|
188
|
+
data-slot="table-cell"
|
|
189
|
+
scope={scope}
|
|
190
|
+
className={cellClassName}
|
|
191
|
+
{...rest}
|
|
192
|
+
>
|
|
193
|
+
{children}
|
|
194
|
+
</th>
|
|
195
|
+
);
|
|
196
|
+
}
|
|
197
|
+
|
|
169
198
|
return (
|
|
170
199
|
<td
|
|
171
200
|
ref={ref}
|
|
172
201
|
data-slot="table-cell"
|
|
173
|
-
className={
|
|
174
|
-
tableCellVariants({ appearance, size, textAlign }),
|
|
175
|
-
className,
|
|
176
|
-
)}
|
|
202
|
+
className={cellClassName}
|
|
177
203
|
{...rest}
|
|
178
204
|
>
|
|
179
205
|
{children}
|
package/src/ui/table/types.ts
CHANGED
|
@@ -19,6 +19,8 @@ export type TableProps = TableVariantProps &
|
|
|
19
19
|
children?: ReactNode;
|
|
20
20
|
ref?: Ref<HTMLTableElement>;
|
|
21
21
|
textAlign?: "left" | "center" | "right";
|
|
22
|
+
/** Label for the overflow scroll wrapper (keyboard-focusable region). */
|
|
23
|
+
scrollAreaAriaLabel?: string;
|
|
22
24
|
};
|
|
23
25
|
|
|
24
26
|
export type TableSectionProps = {
|
|
@@ -33,9 +35,14 @@ export type TableHeadCellProps = ThHTMLAttributes<HTMLTableCellElement> & {
|
|
|
33
35
|
ref?: Ref<HTMLTableCellElement>;
|
|
34
36
|
};
|
|
35
37
|
|
|
36
|
-
export type TableCellProps =
|
|
38
|
+
export type TableCellProps = Omit<
|
|
39
|
+
TdHTMLAttributes<HTMLTableCellElement>,
|
|
40
|
+
"scope"
|
|
41
|
+
> & {
|
|
37
42
|
ref?: Ref<HTMLTableCellElement>;
|
|
38
43
|
textAlign?: "left" | "center" | "right";
|
|
44
|
+
/** Row/column header scope; when set, the cell renders as `<th>` (required for valid `scope` usage). */
|
|
45
|
+
scope?: ThHTMLAttributes<HTMLTableCellElement>["scope"];
|
|
39
46
|
};
|
|
40
47
|
|
|
41
48
|
export type TableCtx = {
|