@hex-core/components 0.2.0 → 1.0.1
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/dist/index.d.ts +69 -16
- package/dist/index.js +146 -53
- package/dist/index.js.map +1 -1
- package/package.json +99 -99
package/dist/index.d.ts
CHANGED
|
@@ -125,11 +125,21 @@ declare const RadioGroup: React$1.ForwardRefExoticComponent<Omit<RadioGroupPrimi
|
|
|
125
125
|
/** A single radio option within a RadioGroup. */
|
|
126
126
|
declare const RadioGroupItem: React$1.ForwardRefExoticComponent<Omit<RadioGroupPrimitive.RadioGroupItemProps & React$1.RefAttributes<HTMLButtonElement>, "ref"> & React$1.RefAttributes<HTMLButtonElement>>;
|
|
127
127
|
|
|
128
|
+
interface SliderProps extends React$1.ComponentPropsWithoutRef<typeof SliderPrimitive.Root> {
|
|
129
|
+
/**
|
|
130
|
+
* Per-thumb accessible labels. When the slider has multiple thumbs, pass
|
|
131
|
+
* one entry per thumb (e.g. ["Minimum", "Maximum"]). For a single-thumb
|
|
132
|
+
* slider, the Root's `aria-label` / `aria-labelledby` is mirrored onto
|
|
133
|
+
* the thumb automatically — pass `thumbLabels` only when those defaults
|
|
134
|
+
* are insufficient.
|
|
135
|
+
*/
|
|
136
|
+
thumbLabels?: string[];
|
|
137
|
+
}
|
|
128
138
|
/**
|
|
129
139
|
* A range input with one or more draggable thumbs.
|
|
130
140
|
* Built on Radix UI Slider with keyboard controls (arrows, Home, End, PageUp/Down).
|
|
131
141
|
*/
|
|
132
|
-
declare const Slider: React$1.ForwardRefExoticComponent<
|
|
142
|
+
declare const Slider: React$1.ForwardRefExoticComponent<SliderProps & React$1.RefAttributes<HTMLSpanElement>>;
|
|
133
143
|
|
|
134
144
|
declare const toggleVariants: (props?: ({
|
|
135
145
|
variant?: "default" | "outline" | null | undefined;
|
|
@@ -175,8 +185,17 @@ declare function Skeleton({ className, ...props }: React$1.HTMLAttributes<HTMLDi
|
|
|
175
185
|
*/
|
|
176
186
|
declare const Progress: React$1.ForwardRefExoticComponent<Omit<ProgressPrimitive.ProgressProps & React$1.RefAttributes<HTMLDivElement>, "ref"> & React$1.RefAttributes<HTMLDivElement>>;
|
|
177
187
|
|
|
188
|
+
interface ScrollAreaProps extends React$1.ComponentPropsWithoutRef<typeof ScrollAreaPrimitive.Root> {
|
|
189
|
+
/**
|
|
190
|
+
* tabIndex applied to the scroll viewport so keyboard users can scroll
|
|
191
|
+
* without a pointer. Defaults to `0` (focusable) — pass `-1` to skip the
|
|
192
|
+
* viewport in the tab order when ScrollArea wraps purely decorative or
|
|
193
|
+
* already-keyboard-reachable content.
|
|
194
|
+
*/
|
|
195
|
+
viewportTabIndex?: number;
|
|
196
|
+
}
|
|
178
197
|
/** A scrollable area with custom-styled scrollbars. Content must be explicitly sized. */
|
|
179
|
-
declare const ScrollArea: React$1.ForwardRefExoticComponent<
|
|
198
|
+
declare const ScrollArea: React$1.ForwardRefExoticComponent<ScrollAreaProps & React$1.RefAttributes<HTMLDivElement>>;
|
|
180
199
|
/** Styled scrollbar track + thumb. Rendered inside ScrollArea automatically. */
|
|
181
200
|
declare const ScrollBar: React$1.ForwardRefExoticComponent<Omit<ScrollAreaPrimitive.ScrollAreaScrollbarProps & React$1.RefAttributes<HTMLDivElement>, "ref"> & React$1.RefAttributes<HTMLDivElement>>;
|
|
182
201
|
|
|
@@ -224,8 +243,22 @@ declare const DialogPortal: React$1.FC<DialogPrimitive.DialogPortalProps>;
|
|
|
224
243
|
declare const DialogClose: React$1.ForwardRefExoticComponent<DialogPrimitive.DialogCloseProps & React$1.RefAttributes<HTMLButtonElement>>;
|
|
225
244
|
/** Dimmed backdrop rendered behind the dialog content. */
|
|
226
245
|
declare const DialogOverlay: React$1.ForwardRefExoticComponent<Omit<DialogPrimitive.DialogOverlayProps & React$1.RefAttributes<HTMLDivElement>, "ref"> & React$1.RefAttributes<HTMLDivElement>>;
|
|
246
|
+
interface DialogContentProps extends React$1.ComponentPropsWithoutRef<typeof DialogPrimitive.Content> {
|
|
247
|
+
/**
|
|
248
|
+
* When `true` (the default), DialogContent caps its height at viewport-2rem
|
|
249
|
+
* and renders children inside a padded inner scroll container. The Close
|
|
250
|
+
* button stays anchored to the (non-scrolling) outer panel so it remains
|
|
251
|
+
* visible even when the user scrolls long content.
|
|
252
|
+
*
|
|
253
|
+
* Pass `scrollable={false}` to opt out — useful when the consumer manages
|
|
254
|
+
* its own scroll surface (e.g. CommandDialog defers scroll to cmdk's
|
|
255
|
+
* internal CommandList).
|
|
256
|
+
*/
|
|
257
|
+
scrollable?: boolean;
|
|
258
|
+
}
|
|
227
259
|
/** The dialog content panel, centered on the overlay. Includes a close button by default. */
|
|
228
|
-
declare const DialogContent: React$1.ForwardRefExoticComponent<
|
|
260
|
+
declare const DialogContent: React$1.ForwardRefExoticComponent<DialogContentProps & React$1.RefAttributes<HTMLDivElement>>;
|
|
261
|
+
|
|
229
262
|
/**
|
|
230
263
|
* Header container inside DialogContent; stacks title and description.
|
|
231
264
|
* @returns A div wrapping title/description with vertical rhythm
|
|
@@ -511,7 +544,11 @@ declare const TableRow: React$1.ForwardRefExoticComponent<React$1.HTMLAttributes
|
|
|
511
544
|
declare const TableHead: React$1.ForwardRefExoticComponent<React$1.ThHTMLAttributes<HTMLTableCellElement> & React$1.RefAttributes<HTMLTableCellElement>>;
|
|
512
545
|
/** `<td>` with consistent padding. */
|
|
513
546
|
declare const TableCell: React$1.ForwardRefExoticComponent<React$1.TdHTMLAttributes<HTMLTableCellElement> & React$1.RefAttributes<HTMLTableCellElement>>;
|
|
514
|
-
/**
|
|
547
|
+
/**
|
|
548
|
+
* Visible `<caption>` rendered below the table. The parent `<Table>` sets
|
|
549
|
+
* `caption-bottom`, so the caption is announced first by screen readers when
|
|
550
|
+
* entering the table, then visually placed below the rows.
|
|
551
|
+
*/
|
|
515
552
|
declare const TableCaption: React$1.ForwardRefExoticComponent<React$1.HTMLAttributes<HTMLTableCaptionElement> & React$1.RefAttributes<HTMLTableCaptionElement>>;
|
|
516
553
|
|
|
517
554
|
/**
|
|
@@ -523,13 +560,24 @@ declare const TableCaption: React$1.ForwardRefExoticComponent<React$1.HTMLAttrib
|
|
|
523
560
|
interface DataTableProps<TData> {
|
|
524
561
|
columns: ColumnDef<TData, unknown>[];
|
|
525
562
|
data: TData[];
|
|
563
|
+
/**
|
|
564
|
+
* Visible caption rendered below the table. Announced by screen readers
|
|
565
|
+
* when the user enters the table. Provide either `caption` or `aria-label`.
|
|
566
|
+
*/
|
|
567
|
+
caption?: React$1.ReactNode;
|
|
568
|
+
/**
|
|
569
|
+
* Accessible label for the table when no visible caption is shown.
|
|
570
|
+
* Forwarded as `aria-label` on the underlying `<table>` element. Kebab-case
|
|
571
|
+
* to match the canonical ARIA prop convention used elsewhere in Hex UI.
|
|
572
|
+
*/
|
|
573
|
+
"aria-label"?: string;
|
|
526
574
|
}
|
|
527
575
|
/**
|
|
528
576
|
* Render a data-driven table from TanStack column definitions.
|
|
529
|
-
* @param props - Columns and
|
|
577
|
+
* @param props - Columns, data, and optional accessible labelling (`caption` or `aria-label`)
|
|
530
578
|
* @returns A styled Table rendered from the TanStack row model
|
|
531
579
|
*/
|
|
532
|
-
declare function DataTable<TData>({ columns, data }: DataTableProps<TData>): react_jsx_runtime.JSX.Element;
|
|
580
|
+
declare function DataTable<TData>({ columns, data, caption, "aria-label": ariaLabel, }: DataTableProps<TData>): react_jsx_runtime.JSX.Element;
|
|
533
581
|
|
|
534
582
|
/**
|
|
535
583
|
* Root nav landmark for pagination controls.
|
|
@@ -690,14 +738,17 @@ declare const CommandGroup: React$1.ForwardRefExoticComponent<Omit<{
|
|
|
690
738
|
value?: string;
|
|
691
739
|
forceMount?: boolean;
|
|
692
740
|
} & React$1.RefAttributes<HTMLDivElement>, "ref"> & React$1.RefAttributes<HTMLDivElement>>;
|
|
693
|
-
/**
|
|
694
|
-
|
|
695
|
-
|
|
696
|
-
|
|
697
|
-
|
|
698
|
-
|
|
699
|
-
|
|
700
|
-
|
|
741
|
+
/**
|
|
742
|
+
* Horizontal rule between groups. Renders as a presentational `<div>` (no role)
|
|
743
|
+
* so it can sit inside CommandList (role=listbox) without violating ARIA's
|
|
744
|
+
* required-children rule for listbox. The line is purely decorative — cmdk's
|
|
745
|
+
* built-in Separator hardcodes `role="separator"`, which axe rejects in this
|
|
746
|
+
* context, so we render the divider directly.
|
|
747
|
+
*
|
|
748
|
+
* The `data-cmdk-separator` attribute is preserved so existing CSS / test
|
|
749
|
+
* selectors that target cmdk's separator continue to match.
|
|
750
|
+
*/
|
|
751
|
+
declare const CommandSeparator: React$1.ForwardRefExoticComponent<React$1.HTMLAttributes<HTMLDivElement> & React$1.RefAttributes<HTMLDivElement>>;
|
|
701
752
|
/** Selectable item. onSelect fires on Enter or click. */
|
|
702
753
|
declare const CommandItem: React$1.ForwardRefExoticComponent<Omit<{
|
|
703
754
|
children?: React$1.ReactNode;
|
|
@@ -746,8 +797,10 @@ interface ComboboxProps {
|
|
|
746
797
|
disabled?: boolean;
|
|
747
798
|
/** Extra class names on the trigger button. */
|
|
748
799
|
className?: string;
|
|
749
|
-
/** Accessible label for the trigger (required when no adjacent visible
|
|
800
|
+
/** Accessible label for the trigger (required when no adjacent visible label). */
|
|
750
801
|
"aria-label"?: string;
|
|
802
|
+
/** Id of an external visible label that names this combobox. */
|
|
803
|
+
"aria-labelledby"?: string;
|
|
751
804
|
}
|
|
752
805
|
/**
|
|
753
806
|
* Searchable select input built on Command + Popover.
|
|
@@ -756,7 +809,7 @@ interface ComboboxProps {
|
|
|
756
809
|
* the trigger; the popover contains a CommandInput and filtered CommandList.
|
|
757
810
|
* @returns A trigger button that opens a filtered option list.
|
|
758
811
|
*/
|
|
759
|
-
declare function Combobox({ options, value, onChange, placeholder, searchPlaceholder, emptyText, disabled, className, "aria-label": ariaLabel, }: ComboboxProps): react_jsx_runtime.JSX.Element;
|
|
812
|
+
declare function Combobox({ options, value, onChange, placeholder, searchPlaceholder, emptyText, disabled, className, "aria-label": ariaLabel, "aria-labelledby": ariaLabelledBy, }: ComboboxProps): react_jsx_runtime.JSX.Element;
|
|
760
813
|
declare namespace Combobox {
|
|
761
814
|
var displayName: string;
|
|
762
815
|
}
|
package/dist/index.js
CHANGED
|
@@ -46,7 +46,9 @@ var buttonVariants = cva(
|
|
|
46
46
|
secondary: [
|
|
47
47
|
"bg-secondary text-secondary-foreground",
|
|
48
48
|
"shadow-sm",
|
|
49
|
-
|
|
49
|
+
// Hover: shadow-elevation only — opacity-based bg shift would push apparent
|
|
50
|
+
// contrast below 3:1 vs --card during hover, regressing WCAG 1.4.11.
|
|
51
|
+
"hover:shadow-md"
|
|
50
52
|
].join(" "),
|
|
51
53
|
ghost: "hover:bg-accent hover:text-accent-foreground",
|
|
52
54
|
link: "text-primary underline-offset-4 hover:underline"
|
|
@@ -288,7 +290,9 @@ var badgeVariants = cva3(
|
|
|
288
290
|
variants: {
|
|
289
291
|
variant: {
|
|
290
292
|
default: "border-transparent bg-primary text-primary-foreground hover:bg-primary/80",
|
|
291
|
-
|
|
293
|
+
// Hover stays at full --secondary fill — opacity-based shift would drop the
|
|
294
|
+
// composite contrast below 3:1 against --card on hover (WCAG 1.4.11).
|
|
295
|
+
secondary: "border-transparent bg-secondary text-secondary-foreground",
|
|
292
296
|
destructive: "border-transparent bg-destructive text-destructive-foreground hover:bg-destructive/80",
|
|
293
297
|
outline: "text-foreground"
|
|
294
298
|
}
|
|
@@ -488,30 +492,46 @@ RadioGroupItem.displayName = "RadioGroupItem";
|
|
|
488
492
|
import * as SliderPrimitive from "@radix-ui/react-slider";
|
|
489
493
|
import * as React10 from "react";
|
|
490
494
|
import { jsx as jsx11, jsxs as jsxs4 } from "react/jsx-runtime";
|
|
491
|
-
var Slider = React10.forwardRef(({ className, ...props }, ref) =>
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
(props.value ?? props.defaultValue ?? [0]).map((_, i) => /* @__PURE__ */ jsx11(
|
|
500
|
-
SliderPrimitive.Thumb,
|
|
501
|
-
{
|
|
502
|
-
className: cn(
|
|
503
|
-
"block h-5 w-5 rounded-full border-2 border-primary bg-background",
|
|
504
|
-
"transition-all duration-[var(--duration-normal,200ms)] ease-out shadow-md",
|
|
505
|
-
"hover:shadow-lg hover:scale-110",
|
|
506
|
-
"focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2",
|
|
507
|
-
"disabled:pointer-events-none disabled:opacity-50"
|
|
508
|
-
)
|
|
509
|
-
},
|
|
510
|
-
i
|
|
511
|
-
))
|
|
512
|
-
]
|
|
495
|
+
var Slider = React10.forwardRef(({ className, thumbLabels, ...props }, ref) => {
|
|
496
|
+
const values = props.value ?? props.defaultValue ?? [0];
|
|
497
|
+
const rootLabel = props["aria-label"];
|
|
498
|
+
const rootLabelledBy = props["aria-labelledby"];
|
|
499
|
+
if (typeof process !== "undefined" && process.env?.NODE_ENV !== "production" && thumbLabels && thumbLabels.length !== values.length) {
|
|
500
|
+
console.warn(
|
|
501
|
+
`Slider: thumbLabels.length (${thumbLabels.length}) does not match value.length (${values.length}). Missing labels fall back to indexed names; extra labels are ignored.`
|
|
502
|
+
);
|
|
513
503
|
}
|
|
514
|
-
|
|
504
|
+
return /* @__PURE__ */ jsxs4(
|
|
505
|
+
SliderPrimitive.Root,
|
|
506
|
+
{
|
|
507
|
+
ref,
|
|
508
|
+
className: cn("relative flex w-full touch-none select-none items-center", className),
|
|
509
|
+
...props,
|
|
510
|
+
children: [
|
|
511
|
+
/* @__PURE__ */ jsx11(SliderPrimitive.Track, { className: "relative h-2 w-full grow overflow-hidden rounded-full bg-secondary", children: /* @__PURE__ */ jsx11(SliderPrimitive.Range, { className: "absolute h-full bg-primary" }) }),
|
|
512
|
+
values.map((_, i) => {
|
|
513
|
+
const explicit = thumbLabels?.[i];
|
|
514
|
+
const fallback = values.length === 1 ? rootLabel : rootLabel ? `${rootLabel} (${i + 1} of ${values.length})` : void 0;
|
|
515
|
+
return /* @__PURE__ */ jsx11(
|
|
516
|
+
SliderPrimitive.Thumb,
|
|
517
|
+
{
|
|
518
|
+
"aria-label": explicit ?? fallback,
|
|
519
|
+
"aria-labelledby": explicit || fallback ? void 0 : rootLabelledBy,
|
|
520
|
+
className: cn(
|
|
521
|
+
"block h-5 w-5 rounded-full border-2 border-primary bg-background",
|
|
522
|
+
"transition-all duration-[var(--duration-normal,200ms)] ease-out shadow-md",
|
|
523
|
+
"hover:shadow-lg hover:scale-110",
|
|
524
|
+
"focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2",
|
|
525
|
+
"disabled:pointer-events-none disabled:opacity-50"
|
|
526
|
+
)
|
|
527
|
+
},
|
|
528
|
+
i
|
|
529
|
+
);
|
|
530
|
+
})
|
|
531
|
+
]
|
|
532
|
+
}
|
|
533
|
+
);
|
|
534
|
+
});
|
|
515
535
|
Slider.displayName = "Slider";
|
|
516
536
|
|
|
517
537
|
// src/primitives/toggle/toggle.tsx
|
|
@@ -666,14 +686,24 @@ Progress.displayName = "Progress";
|
|
|
666
686
|
import * as ScrollAreaPrimitive from "@radix-ui/react-scroll-area";
|
|
667
687
|
import * as React15 from "react";
|
|
668
688
|
import { jsx as jsx17, jsxs as jsxs5 } from "react/jsx-runtime";
|
|
669
|
-
var ScrollArea = React15.forwardRef(({ className, children, ...props }, ref) => /* @__PURE__ */ jsxs5(
|
|
689
|
+
var ScrollArea = React15.forwardRef(({ className, children, viewportTabIndex = 0, ...props }, ref) => /* @__PURE__ */ jsxs5(
|
|
670
690
|
ScrollAreaPrimitive.Root,
|
|
671
691
|
{
|
|
672
692
|
ref,
|
|
673
693
|
className: cn("relative overflow-hidden", className),
|
|
674
694
|
...props,
|
|
675
695
|
children: [
|
|
676
|
-
/* @__PURE__ */ jsx17(
|
|
696
|
+
/* @__PURE__ */ jsx17(
|
|
697
|
+
ScrollAreaPrimitive.Viewport,
|
|
698
|
+
{
|
|
699
|
+
tabIndex: viewportTabIndex,
|
|
700
|
+
className: cn(
|
|
701
|
+
"h-full w-full rounded-[inherit]",
|
|
702
|
+
viewportTabIndex >= 0 && "focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2"
|
|
703
|
+
),
|
|
704
|
+
children
|
|
705
|
+
}
|
|
706
|
+
),
|
|
677
707
|
/* @__PURE__ */ jsx17(ScrollBar, { orientation: "vertical" }),
|
|
678
708
|
/* @__PURE__ */ jsx17(ScrollBar, { orientation: "horizontal" }),
|
|
679
709
|
/* @__PURE__ */ jsx17(ScrollAreaPrimitive.Corner, {})
|
|
@@ -884,15 +914,15 @@ var DialogOverlay = React19.forwardRef(({ className, ...props }, ref) => /* @__P
|
|
|
884
914
|
}
|
|
885
915
|
));
|
|
886
916
|
DialogOverlay.displayName = "DialogOverlay";
|
|
887
|
-
var DialogContent = React19.forwardRef(({ className, children, ...props }, ref) => /* @__PURE__ */ jsxs7(DialogPortal, { children: [
|
|
917
|
+
var DialogContent = React19.forwardRef(({ className, children, scrollable = true, ...props }, ref) => /* @__PURE__ */ jsxs7(DialogPortal, { children: [
|
|
888
918
|
/* @__PURE__ */ jsx21(DialogOverlay, {}),
|
|
889
919
|
/* @__PURE__ */ jsxs7(
|
|
890
920
|
DialogPrimitive.Content,
|
|
891
921
|
{
|
|
892
922
|
ref,
|
|
893
923
|
className: cn(
|
|
894
|
-
"fixed left-[50%] top-[50%] z-50 grid w-full max-w-lg translate-x-[-50%] translate-y-[-50%]
|
|
895
|
-
"border bg-background p-[var(--space-6,1.5rem)] shadow-lg rounded-lg",
|
|
924
|
+
"fixed left-[50%] top-[50%] z-50 grid w-full max-w-lg translate-x-[-50%] translate-y-[-50%]",
|
|
925
|
+
scrollable ? "max-h-[calc(100vh-2rem)] border bg-background shadow-lg rounded-lg" : "gap-[var(--gap-md,1rem)] border bg-background p-[var(--space-6,1.5rem)] shadow-lg rounded-lg",
|
|
896
926
|
"duration-[var(--duration-normal,200ms)] data-[state=open]:animate-in data-[state=closed]:animate-out",
|
|
897
927
|
"data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0",
|
|
898
928
|
"data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95",
|
|
@@ -900,12 +930,12 @@ var DialogContent = React19.forwardRef(({ className, children, ...props }, ref)
|
|
|
900
930
|
),
|
|
901
931
|
...props,
|
|
902
932
|
children: [
|
|
903
|
-
children,
|
|
933
|
+
scrollable ? /* @__PURE__ */ jsx21("div", { className: "grid gap-[var(--gap-md,1rem)] overflow-y-auto p-[var(--space-6,1.5rem)]", children }) : children,
|
|
904
934
|
/* @__PURE__ */ jsxs7(
|
|
905
935
|
DialogPrimitive.Close,
|
|
906
936
|
{
|
|
907
937
|
className: cn(
|
|
908
|
-
"absolute right-4 top-4 rounded-sm opacity-70 ring-offset-background",
|
|
938
|
+
"absolute right-4 top-4 z-10 rounded-sm opacity-70 ring-offset-background bg-background/80 backdrop-blur-sm",
|
|
909
939
|
"transition-all duration-[var(--duration-normal,200ms)] ease-out hover:opacity-100",
|
|
910
940
|
"focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2",
|
|
911
941
|
"disabled:pointer-events-none"
|
|
@@ -1962,7 +1992,10 @@ var TableCaption = React31.forwardRef(({ className, ...props }, ref) => /* @__PU
|
|
|
1962
1992
|
"caption",
|
|
1963
1993
|
{
|
|
1964
1994
|
ref,
|
|
1965
|
-
className: cn(
|
|
1995
|
+
className: cn(
|
|
1996
|
+
"caption-bottom mt-[var(--space-4,1rem)] text-sm text-muted-foreground",
|
|
1997
|
+
className
|
|
1998
|
+
),
|
|
1966
1999
|
...props
|
|
1967
2000
|
}
|
|
1968
2001
|
));
|
|
@@ -1975,13 +2008,19 @@ import {
|
|
|
1975
2008
|
useReactTable
|
|
1976
2009
|
} from "@tanstack/react-table";
|
|
1977
2010
|
import { jsx as jsx35, jsxs as jsxs13 } from "react/jsx-runtime";
|
|
1978
|
-
function DataTable({
|
|
2011
|
+
function DataTable({
|
|
2012
|
+
columns,
|
|
2013
|
+
data,
|
|
2014
|
+
caption,
|
|
2015
|
+
"aria-label": ariaLabel
|
|
2016
|
+
}) {
|
|
1979
2017
|
const table = useReactTable({
|
|
1980
2018
|
data,
|
|
1981
2019
|
columns,
|
|
1982
2020
|
getCoreRowModel: getCoreRowModel()
|
|
1983
2021
|
});
|
|
1984
|
-
return /* @__PURE__ */ jsx35("div", { className: "rounded-md border", children: /* @__PURE__ */ jsxs13(Table, { children: [
|
|
2022
|
+
return /* @__PURE__ */ jsx35("div", { className: "rounded-md border", children: /* @__PURE__ */ jsxs13(Table, { "aria-label": ariaLabel, children: [
|
|
2023
|
+
caption ? /* @__PURE__ */ jsx35(TableCaption, { children: caption }) : null,
|
|
1985
2024
|
/* @__PURE__ */ jsx35(TableHeader, { children: table.getHeaderGroups().map((headerGroup) => /* @__PURE__ */ jsx35(TableRow, { children: headerGroup.headers.map((header) => /* @__PURE__ */ jsx35(TableHead, { children: header.isPlaceholder ? null : flexRender(header.column.columnDef.header, header.getContext()) }, header.id)) }, headerGroup.id)) }),
|
|
1986
2025
|
/* @__PURE__ */ jsx35(TableBody, { children: table.getRowModel().rows?.length ? table.getRowModel().rows.map((row) => /* @__PURE__ */ jsx35(TableRow, { "data-state": row.getIsSelected() && "selected", children: row.getVisibleCells().map((cell) => /* @__PURE__ */ jsx35(TableCell, { children: flexRender(cell.column.columnDef.cell, cell.getContext()) }, cell.id)) }, row.id)) : /* @__PURE__ */ jsx35(TableRow, { children: /* @__PURE__ */ jsx35(TableCell, { colSpan: columns.length, className: "h-24 text-center", children: "No results." }) }) })
|
|
1987
2026
|
] }) });
|
|
@@ -2350,7 +2389,7 @@ function CommandDialog({
|
|
|
2350
2389
|
/* @__PURE__ */ jsx40(DialogTitle, { children: title }),
|
|
2351
2390
|
/* @__PURE__ */ jsx40(DialogDescription, { children: description })
|
|
2352
2391
|
] }),
|
|
2353
|
-
/* @__PURE__ */ jsx40(DialogContent, { className: "overflow-hidden p-0", children: /* @__PURE__ */ jsx40(Command, { className: "[&_[cmdk-group-heading]]:px-[var(--space-2,0.5rem)] [&_[cmdk-group-heading]]:font-medium [&_[cmdk-group-heading]]:text-muted-foreground [&_[cmdk-group]:not([hidden])_~[cmdk-group]]:pt-0 [&_[cmdk-group]]:px-[var(--space-2,0.5rem)] [&_[cmdk-input-wrapper]_svg]:h-5 [&_[cmdk-input-wrapper]_svg]:w-5 [&_[cmdk-input]]:h-12 [&_[cmdk-item]]:px-[var(--space-2,0.5rem)] [&_[cmdk-item]]:py-[var(--space-3,0.75rem)] [&_[cmdk-item]_svg]:h-5 [&_[cmdk-item]_svg]:w-5", children }) })
|
|
2392
|
+
/* @__PURE__ */ jsx40(DialogContent, { className: "overflow-hidden p-0", scrollable: false, children: /* @__PURE__ */ jsx40(Command, { className: "[&_[cmdk-group-heading]]:px-[var(--space-2,0.5rem)] [&_[cmdk-group-heading]]:font-medium [&_[cmdk-group-heading]]:text-muted-foreground [&_[cmdk-group]:not([hidden])_~[cmdk-group]]:pt-0 [&_[cmdk-group]]:px-[var(--space-2,0.5rem)] [&_[cmdk-input-wrapper]_svg]:h-5 [&_[cmdk-input-wrapper]_svg]:w-5 [&_[cmdk-input]]:h-12 [&_[cmdk-item]]:px-[var(--space-2,0.5rem)] [&_[cmdk-item]]:py-[var(--space-3,0.75rem)] [&_[cmdk-item]_svg]:h-5 [&_[cmdk-item]_svg]:w-5", children }) })
|
|
2354
2393
|
] });
|
|
2355
2394
|
}
|
|
2356
2395
|
var CommandInput = React35.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsxs17("div", { className: "flex items-center border-b px-[var(--space-3,0.75rem)]", "cmdk-input-wrapper": "", children: [
|
|
@@ -2409,9 +2448,11 @@ var CommandGroup = React35.forwardRef(({ className, ...props }, ref) => /* @__PU
|
|
|
2409
2448
|
));
|
|
2410
2449
|
CommandGroup.displayName = "CommandGroup";
|
|
2411
2450
|
var CommandSeparator = React35.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx40(
|
|
2412
|
-
|
|
2451
|
+
"div",
|
|
2413
2452
|
{
|
|
2414
2453
|
ref,
|
|
2454
|
+
role: "none",
|
|
2455
|
+
"data-cmdk-separator": "",
|
|
2415
2456
|
className: cn("-mx-[var(--space-1,0.25rem)] h-px bg-border", className),
|
|
2416
2457
|
...props
|
|
2417
2458
|
}
|
|
@@ -2458,9 +2499,11 @@ function Combobox({
|
|
|
2458
2499
|
emptyText = "No results found.",
|
|
2459
2500
|
disabled,
|
|
2460
2501
|
className,
|
|
2461
|
-
"aria-label": ariaLabel
|
|
2502
|
+
"aria-label": ariaLabel,
|
|
2503
|
+
"aria-labelledby": ariaLabelledBy
|
|
2462
2504
|
}) {
|
|
2463
2505
|
const [open, setOpen] = React36.useState(false);
|
|
2506
|
+
const listboxId = React36.useId();
|
|
2464
2507
|
const selected = options.find((o) => o.value === value);
|
|
2465
2508
|
return /* @__PURE__ */ jsxs18(Popover, { open, onOpenChange: setOpen, children: [
|
|
2466
2509
|
/* @__PURE__ */ jsx41(PopoverTrigger, { asChild: true, children: /* @__PURE__ */ jsxs18(
|
|
@@ -2470,7 +2513,9 @@ function Combobox({
|
|
|
2470
2513
|
role: "combobox",
|
|
2471
2514
|
"aria-expanded": open,
|
|
2472
2515
|
"aria-haspopup": "listbox",
|
|
2516
|
+
"aria-controls": open ? listboxId : void 0,
|
|
2473
2517
|
"aria-label": ariaLabel,
|
|
2518
|
+
"aria-labelledby": ariaLabelledBy,
|
|
2474
2519
|
disabled,
|
|
2475
2520
|
className: cn(
|
|
2476
2521
|
"inline-flex h-[var(--control-height-md,2.5rem)] w-[240px] items-center justify-between gap-[var(--gap-sm,0.5rem)] rounded-md border border-input bg-background px-[var(--space-3,0.75rem)] py-[var(--space-2,0.5rem)] text-sm font-normal transition-all duration-[var(--duration-normal,200ms)] ease-out",
|
|
@@ -2502,7 +2547,7 @@ function Combobox({
|
|
|
2502
2547
|
) }),
|
|
2503
2548
|
/* @__PURE__ */ jsx41(PopoverContent, { className: "w-[240px] p-0", align: "start", children: /* @__PURE__ */ jsxs18(Command, { children: [
|
|
2504
2549
|
/* @__PURE__ */ jsx41(CommandInput, { placeholder: searchPlaceholder }),
|
|
2505
|
-
/* @__PURE__ */ jsxs18(CommandList, { children: [
|
|
2550
|
+
/* @__PURE__ */ jsxs18(CommandList, { id: listboxId, children: [
|
|
2506
2551
|
/* @__PURE__ */ jsx41(CommandEmpty, { children: emptyText }),
|
|
2507
2552
|
/* @__PURE__ */ jsx41(CommandGroup, { children: options.map((option) => /* @__PURE__ */ jsxs18(
|
|
2508
2553
|
CommandItem,
|
|
@@ -3706,7 +3751,7 @@ var dialogSchema = {
|
|
|
3706
3751
|
"Putting too many primary actions in DialogFooter"
|
|
3707
3752
|
],
|
|
3708
3753
|
relatedComponents: ["alert-dialog", "popover", "sheet"],
|
|
3709
|
-
accessibilityNotes: "Radix traps focus, handles Escape to close, and wires aria-labelledby/describedby to DialogTitle/DialogDescription. Always include a DialogTitle.",
|
|
3754
|
+
accessibilityNotes: "Radix traps focus, handles Escape to close, and wires aria-labelledby/describedby to DialogTitle/DialogDescription. Always include a DialogTitle. DialogContent is constrained to `max-h-[calc(100vh-2rem)]` and scrolls internally so long content stays inside the focus trap.",
|
|
3710
3755
|
tokenBudget: 600
|
|
3711
3756
|
},
|
|
3712
3757
|
tags: ["dialog", "modal", "overlay", "popup", "form"]
|
|
@@ -4224,6 +4269,24 @@ var sliderSchema = {
|
|
|
4224
4269
|
default: "horizontal",
|
|
4225
4270
|
description: "Slider direction",
|
|
4226
4271
|
enumValues: ["horizontal", "vertical"]
|
|
4272
|
+
},
|
|
4273
|
+
{
|
|
4274
|
+
name: "aria-label",
|
|
4275
|
+
type: "string",
|
|
4276
|
+
required: false,
|
|
4277
|
+
description: "Accessible label for the slider as a whole. Mirrored onto a single thumb automatically; for range sliders prefer thumbLabels."
|
|
4278
|
+
},
|
|
4279
|
+
{
|
|
4280
|
+
name: "aria-labelledby",
|
|
4281
|
+
type: "string",
|
|
4282
|
+
required: false,
|
|
4283
|
+
description: "Id of an external visible label that names the slider."
|
|
4284
|
+
},
|
|
4285
|
+
{
|
|
4286
|
+
name: "thumbLabels",
|
|
4287
|
+
type: "object",
|
|
4288
|
+
required: false,
|
|
4289
|
+
description: "Per-thumb accessible labels (string[]). Required for range sliders so each thumb has a meaningful name (e.g. ['Minimum price', 'Maximum price']). For a single-thumb slider, the Root's aria-label is mirrored onto the thumb automatically and thumbLabels is only needed when overriding that default."
|
|
4227
4290
|
}
|
|
4228
4291
|
],
|
|
4229
4292
|
variants: [],
|
|
@@ -4253,10 +4316,12 @@ var sliderSchema = {
|
|
|
4253
4316
|
"Using Slider for exact values without showing the number",
|
|
4254
4317
|
"Missing min/max bounds",
|
|
4255
4318
|
"Using step=1 for fractional values (set step=0.01)",
|
|
4256
|
-
"Not providing aria-label when there's no visible label"
|
|
4319
|
+
"Not providing aria-label / aria-labelledby when there's no visible label",
|
|
4320
|
+
"Range slider with only Root aria-label and no thumbLabels \u2014 both thumbs fall back to '(N of 2)' indexed names instead of meaningful per-thumb labels",
|
|
4321
|
+
"thumbLabels.length !== value.length \u2014 extra labels are ignored, missing labels fall back to indexed names (dev-mode warning)"
|
|
4257
4322
|
],
|
|
4258
4323
|
relatedComponents: ["input"],
|
|
4259
|
-
accessibilityNotes: "Arrow keys step by step, Home/End jump to min/max, PageUp/PageDown step larger. Radix handles aria-valuemin/max/now. Add aria-label
|
|
4324
|
+
accessibilityNotes: "Arrow keys step by step, Home/End jump to min/max, PageUp/PageDown step larger. Radix handles aria-valuemin/max/now. Each thumb has its own accessible name: explicit via thumbLabels[i], else mirrored from the Root's aria-label (single thumb) or indexed '(i of N)' fallback (range). Add aria-label / aria-labelledby on the Root when there's no visible label.",
|
|
4260
4325
|
tokenBudget: 450
|
|
4261
4326
|
},
|
|
4262
4327
|
tags: ["slider", "range", "form", "numeric", "input"]
|
|
@@ -4683,7 +4748,14 @@ var scrollAreaSchema = {
|
|
|
4683
4748
|
description: "When scrollbars are visible",
|
|
4684
4749
|
enumValues: ["auto", "always", "scroll", "hover"]
|
|
4685
4750
|
},
|
|
4686
|
-
{ name: "className", type: "string", required: false, description: "Set dimensions via Tailwind (e.g. h-72 w-48)" }
|
|
4751
|
+
{ name: "className", type: "string", required: false, description: "Set dimensions via Tailwind (e.g. h-72 w-48)" },
|
|
4752
|
+
{
|
|
4753
|
+
name: "viewportTabIndex",
|
|
4754
|
+
type: "number",
|
|
4755
|
+
required: false,
|
|
4756
|
+
default: 0,
|
|
4757
|
+
description: "tabIndex applied to the scroll viewport. Defaults to 0 so keyboard users can scroll without a pointer; pass -1 to skip the viewport in the tab order when wrapping decorative or already-keyboard-reachable content."
|
|
4758
|
+
}
|
|
4687
4759
|
],
|
|
4688
4760
|
variants: [],
|
|
4689
4761
|
slots: [
|
|
@@ -4713,10 +4785,11 @@ var scrollAreaSchema = {
|
|
|
4713
4785
|
commonMistakes: [
|
|
4714
4786
|
"Forgetting to set height/width \u2014 scrollbars don't appear",
|
|
4715
4787
|
"Using for the whole page",
|
|
4716
|
-
"Nesting ScrollAreas (confusing UX)"
|
|
4788
|
+
"Nesting ScrollAreas (confusing UX)",
|
|
4789
|
+
"Wrapping decorative or already-keyboard-reachable content without setting viewportTabIndex={-1} \u2014 adds an unnecessary tab stop"
|
|
4717
4790
|
],
|
|
4718
4791
|
relatedComponents: [],
|
|
4719
|
-
accessibilityNotes: "
|
|
4792
|
+
accessibilityNotes: "The viewport is keyboard-focusable by default (viewportTabIndex=0) so users can scroll long content via arrow keys / PgUp / PgDn / Home / End without a pointer. Pass viewportTabIndex={-1} when the contents are already in the tab order or purely decorative. For very long lists, consider pagination or virtualization.",
|
|
4720
4793
|
tokenBudget: 350
|
|
4721
4794
|
},
|
|
4722
4795
|
tags: ["scroll-area", "scroll", "overflow", "scrollbar", "layout"]
|
|
@@ -5250,7 +5323,19 @@ var dataTableSchema = {
|
|
|
5250
5323
|
subcategory: "data",
|
|
5251
5324
|
props: [
|
|
5252
5325
|
{ name: "columns", type: "object", required: true, description: "ColumnDef<TData, TValue>[] from @tanstack/react-table" },
|
|
5253
|
-
{ name: "data", type: "object", required: true, description: "Array of row data" }
|
|
5326
|
+
{ name: "data", type: "object", required: true, description: "Array of row data" },
|
|
5327
|
+
{
|
|
5328
|
+
name: "caption",
|
|
5329
|
+
type: "ReactNode",
|
|
5330
|
+
required: false,
|
|
5331
|
+
description: "Visible caption rendered below the table; announced by screen readers when entering the table"
|
|
5332
|
+
},
|
|
5333
|
+
{
|
|
5334
|
+
name: "aria-label",
|
|
5335
|
+
type: "string",
|
|
5336
|
+
required: false,
|
|
5337
|
+
description: "Accessible label forwarded as aria-label on the underlying <table>; use when no visible caption is shown"
|
|
5338
|
+
}
|
|
5254
5339
|
],
|
|
5255
5340
|
variants: [],
|
|
5256
5341
|
slots: [],
|
|
@@ -5274,10 +5359,11 @@ var dataTableSchema = {
|
|
|
5274
5359
|
"Forgetting getCoreRowModel() (table renders nothing)",
|
|
5275
5360
|
"Recreating columns array on every render (breaks memoization \u2014 wrap in useMemo or define outside the component)",
|
|
5276
5361
|
"Using accessorKey with nested paths without accessorFn",
|
|
5277
|
-
"Not adding filter/sort row models when those features are needed"
|
|
5362
|
+
"Not adding filter/sort row models when those features are needed",
|
|
5363
|
+
"Shipping a table without `caption` or `aria-label` \u2014 the table is unlabelled to assistive tech"
|
|
5278
5364
|
],
|
|
5279
5365
|
relatedComponents: ["table", "pagination"],
|
|
5280
|
-
accessibilityNotes: "
|
|
5366
|
+
accessibilityNotes: "Pass either `caption` (visible) or `aria-label` so screen readers announce the table when the user enters it. Add aria-sort to sortable column headers. Announce filter/sort changes via aria-live for dynamic updates.",
|
|
5281
5367
|
tokenBudget: 900
|
|
5282
5368
|
},
|
|
5283
5369
|
tags: ["data-table", "tanstack", "sortable", "filterable", "paginated"]
|
|
@@ -5691,10 +5777,11 @@ var commandSchema = {
|
|
|
5691
5777
|
"Forgetting CommandList \u2014 items won't be scrollable or grouped properly",
|
|
5692
5778
|
"Giving CommandItem non-unique values (breaks filtering and controlled state)",
|
|
5693
5779
|
"Overriding CommandInput className to remove the border/padding \u2014 breaks the \u2318K icon layout",
|
|
5694
|
-
"Not rendering CommandEmpty \u2014 the list looks broken when a search has no matches"
|
|
5780
|
+
"Not rendering CommandEmpty \u2014 the list looks broken when a search has no matches",
|
|
5781
|
+
"Querying CommandSeparator via cmdk's internal Separator state \u2014 Hex UI renders it as a presentational div with role='none' (and the `data-cmdk-separator` attribute preserved for selector compatibility) so it can sit inside CommandList's role=listbox without violating ARIA"
|
|
5695
5782
|
],
|
|
5696
5783
|
relatedComponents: ["combobox", "dialog", "dropdown-menu"],
|
|
5697
|
-
accessibilityNotes: "cmdk wires role=listbox/option and aria-activedescendant. Use the `label` prop on Command for a screen-reader-only name when no visible heading exists.",
|
|
5784
|
+
accessibilityNotes: "cmdk wires role=listbox/option and aria-activedescendant. Use the `label` prop on Command for a screen-reader-only name when no visible heading exists. CommandSeparator renders with role='none' (still selectable via `[data-cmdk-separator]`) so listbox-children rules are satisfied.",
|
|
5698
5785
|
tokenBudget: 900
|
|
5699
5786
|
},
|
|
5700
5787
|
tags: ["command", "cmdk", "palette", "search", "launcher"]
|
|
@@ -5758,7 +5845,13 @@ var comboboxSchema = {
|
|
|
5758
5845
|
name: "aria-label",
|
|
5759
5846
|
type: "string",
|
|
5760
5847
|
required: false,
|
|
5761
|
-
description: "Accessible label \u2014 required when no adjacent visible
|
|
5848
|
+
description: "Accessible label \u2014 required when no adjacent visible label is used"
|
|
5849
|
+
},
|
|
5850
|
+
{
|
|
5851
|
+
name: "aria-labelledby",
|
|
5852
|
+
type: "string",
|
|
5853
|
+
required: false,
|
|
5854
|
+
description: "Id of an external visible label that names the combobox"
|
|
5762
5855
|
}
|
|
5763
5856
|
],
|
|
5764
5857
|
variants: [],
|
|
@@ -5789,10 +5882,10 @@ var comboboxSchema = {
|
|
|
5789
5882
|
"Using the label as the value \u2014 fine if stable, but prefer a short stable `value` string",
|
|
5790
5883
|
"Forgetting to bind value + onChange \u2014 uncontrolled mode doesn't exist on this wrapper",
|
|
5791
5884
|
"Mixing translated labels without keying on value \u2014 label changes won't update selection",
|
|
5792
|
-
"Missing aria-label
|
|
5885
|
+
"Missing aria-label / aria-labelledby \u2014 role='combobox' does not allow name from contents, so without one of these the trigger has no accessible name"
|
|
5793
5886
|
],
|
|
5794
5887
|
relatedComponents: ["command", "popover", "select"],
|
|
5795
|
-
accessibilityNotes: "Trigger has role='combobox' + aria-expanded.
|
|
5888
|
+
accessibilityNotes: "Trigger has role='combobox' + aria-expanded + aria-haspopup='listbox'. aria-controls points at the inner CommandList (a useId-stabilized listbox). Pass aria-label or aria-labelledby \u2014 combobox does not derive its name from contents.",
|
|
5796
5889
|
tokenBudget: 900
|
|
5797
5890
|
},
|
|
5798
5891
|
tags: ["combobox", "select", "search", "cmdk", "input"]
|