atlas-react-kit 0.4.1 → 0.6.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/COMPONENTS.md +135 -41
- package/DESIGN_RULES.md +79 -20
- package/README.md +60 -11
- package/dist/accordion.d.ts +8 -0
- package/dist/accordion.js +20 -0
- package/dist/alert.d.ts +19 -0
- package/dist/alert.js +37 -0
- package/dist/avatar.d.ts +9 -0
- package/dist/avatar.js +16 -0
- package/dist/badge.d.ts +2 -2
- package/dist/badge.js +1 -1
- package/dist/breadcrumb.d.ts +16 -0
- package/dist/breadcrumb.js +33 -0
- package/dist/button.d.ts +6 -5
- package/dist/button.js +7 -6
- package/dist/calendar.d.ts +1 -1
- package/dist/calendar.js +20 -2
- package/dist/checkbox.js +1 -1
- package/dist/color-legend.d.ts +22 -0
- package/dist/color-legend.js +11 -0
- package/dist/combobox.d.ts +4 -1
- package/dist/combobox.js +11 -5
- package/dist/date-picker.js +14 -3
- package/dist/date-time-picker.d.ts +36 -0
- package/dist/date-time-picker.js +105 -0
- package/dist/dropdown-menu.d.ts +26 -0
- package/dist/dropdown-menu.js +56 -0
- package/dist/error-boundary.d.ts +1 -1
- package/dist/field.js +1 -1
- package/dist/form/date-time-picker-field.d.ts +16 -0
- package/dist/form/date-time-picker-field.js +12 -0
- package/dist/form/markdown-field.d.ts +17 -0
- package/dist/form/markdown-field.js +26 -0
- package/dist/form/text-field.d.ts +7 -1
- package/dist/form/text-field.js +3 -3
- package/dist/info-tip.d.ts +27 -0
- package/dist/info-tip.js +63 -0
- package/dist/input.js +1 -1
- package/dist/internal/form-control.d.ts +1 -1
- package/dist/internal/form-control.js +1 -1
- package/dist/internal/tabs-styles.js +3 -3
- package/dist/markdown.d.ts +18 -0
- package/dist/markdown.js +62 -0
- package/dist/meter.d.ts +22 -0
- package/dist/meter.js +17 -0
- package/dist/pagination.d.ts +18 -0
- package/dist/pagination.js +35 -0
- package/dist/progress.d.ts +8 -0
- package/dist/progress.js +13 -0
- package/dist/radio-group.d.ts +13 -0
- package/dist/radio-group.js +20 -0
- package/dist/search-picker.d.ts +30 -0
- package/dist/search-picker.js +100 -0
- package/dist/select.js +2 -2
- package/dist/slider.d.ts +20 -0
- package/dist/slider.js +20 -0
- package/dist/spinner.d.ts +8 -0
- package/dist/spinner.js +13 -0
- package/dist/stat-tile.d.ts +21 -0
- package/dist/stat-tile.js +17 -0
- package/dist/switch.d.ts +9 -0
- package/dist/switch.js +14 -0
- package/dist/table.d.ts +2 -0
- package/dist/table.js +26 -2
- package/dist/tabs.d.ts +6 -3
- package/dist/tabs.js +5 -2
- package/dist/textarea.js +1 -1
- package/dist/theme-provider.d.ts +2 -1
- package/dist/theme-provider.js +28 -4
- package/dist/toggle-group.js +2 -2
- package/dist/toggle.d.ts +11 -1
- package/dist/toggle.js +13 -3
- package/dist/tooltip.d.ts +15 -0
- package/dist/tooltip.js +26 -0
- package/package.json +92 -5
- package/skills/atlas-react-kit/SKILL.md +148 -0
- package/theme.css +28 -14
package/dist/badge.js
CHANGED
|
@@ -3,7 +3,7 @@ import * as React from "react";
|
|
|
3
3
|
import { cva } from "class-variance-authority";
|
|
4
4
|
import { Slot } from "radix-ui";
|
|
5
5
|
import { cn } from "./utils.js";
|
|
6
|
-
const badgeVariants = cva("group/badge inline-flex w-fit shrink-0 items-center justify-center gap-1.5 overflow-hidden rounded-none border-0 bg-transparent px-0 py-0 text-[0.625rem] font-semibold tracking-widest whitespace-nowrap uppercase transition-colors focus-visible:border-ring focus-visible:ring-
|
|
6
|
+
const badgeVariants = cva("group/badge inline-flex w-fit shrink-0 items-center justify-center gap-1.5 overflow-hidden rounded-none border-0 bg-transparent px-0 py-0 text-[0.625rem] font-semibold tracking-widest whitespace-nowrap uppercase transition-colors focus-visible:border-ring focus-visible:ring-2 focus-visible:ring-ring has-data-[icon=inline-end]:pr-0 has-data-[icon=inline-start]:pl-0 aria-invalid:border-destructive aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 [&>svg]:pointer-events-none [&>svg]:size-3!", {
|
|
7
7
|
variants: {
|
|
8
8
|
variant: {
|
|
9
9
|
default: "text-foreground [a]:hover:text-foreground/70",
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import * as React from "react";
|
|
2
|
+
/**
|
|
3
|
+
* Where the current page sits in a hierarchy. The last item is
|
|
4
|
+
* `BreadcrumbPage` (plain text with `aria-current="page"`), not a link.
|
|
5
|
+
*/
|
|
6
|
+
declare function Breadcrumb({ ...props }: React.ComponentProps<"nav">): React.JSX.Element;
|
|
7
|
+
declare function BreadcrumbList({ className, ...props }: React.ComponentProps<"ol">): React.JSX.Element;
|
|
8
|
+
declare function BreadcrumbItem({ className, ...props }: React.ComponentProps<"li">): React.JSX.Element;
|
|
9
|
+
/** Pass `asChild` to render a router link (e.g. Next `Link`) with these styles. */
|
|
10
|
+
declare function BreadcrumbLink({ asChild, className, ...props }: React.ComponentProps<"a"> & {
|
|
11
|
+
asChild?: boolean;
|
|
12
|
+
}): React.JSX.Element;
|
|
13
|
+
declare function BreadcrumbPage({ className, ...props }: React.ComponentProps<"span">): React.JSX.Element;
|
|
14
|
+
declare function BreadcrumbSeparator({ children, className, ...props }: React.ComponentProps<"li">): React.JSX.Element;
|
|
15
|
+
declare function BreadcrumbEllipsis({ className, ...props }: React.ComponentProps<"span">): React.JSX.Element;
|
|
16
|
+
export { Breadcrumb, BreadcrumbEllipsis, BreadcrumbItem, BreadcrumbLink, BreadcrumbList, BreadcrumbPage, BreadcrumbSeparator, };
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import * as React from "react";
|
|
3
|
+
import { Slot } from "radix-ui";
|
|
4
|
+
import { ChevronRightIcon, MoreHorizontalIcon } from "lucide-react";
|
|
5
|
+
import { cn } from "./utils.js";
|
|
6
|
+
/**
|
|
7
|
+
* Where the current page sits in a hierarchy. The last item is
|
|
8
|
+
* `BreadcrumbPage` (plain text with `aria-current="page"`), not a link.
|
|
9
|
+
*/
|
|
10
|
+
function Breadcrumb({ ...props }) {
|
|
11
|
+
return _jsx("nav", { "aria-label": "Breadcrumb", "data-slot": "breadcrumb", ...props });
|
|
12
|
+
}
|
|
13
|
+
function BreadcrumbList({ className, ...props }) {
|
|
14
|
+
return (_jsx("ol", { "data-slot": "breadcrumb-list", className: cn("flex flex-wrap items-center gap-1.5 text-sm break-words text-muted-foreground sm:gap-2", className), ...props }));
|
|
15
|
+
}
|
|
16
|
+
function BreadcrumbItem({ className, ...props }) {
|
|
17
|
+
return (_jsx("li", { "data-slot": "breadcrumb-item", className: cn("inline-flex items-center gap-1.5", className), ...props }));
|
|
18
|
+
}
|
|
19
|
+
/** Pass `asChild` to render a router link (e.g. Next `Link`) with these styles. */
|
|
20
|
+
function BreadcrumbLink({ asChild, className, ...props }) {
|
|
21
|
+
const Comp = asChild ? Slot.Root : "a";
|
|
22
|
+
return (_jsx(Comp, { "data-slot": "breadcrumb-link", className: cn("transition-colors outline-none hover:text-selected-foreground focus-visible:text-selected-foreground focus-visible:underline focus-visible:underline-offset-4", className), ...props }));
|
|
23
|
+
}
|
|
24
|
+
function BreadcrumbPage({ className, ...props }) {
|
|
25
|
+
return (_jsx("span", { "data-slot": "breadcrumb-page", "aria-current": "page", className: cn("font-medium text-foreground", className), ...props }));
|
|
26
|
+
}
|
|
27
|
+
function BreadcrumbSeparator({ children, className, ...props }) {
|
|
28
|
+
return (_jsx("li", { "data-slot": "breadcrumb-separator", role: "presentation", "aria-hidden": "true", className: cn("[&>svg]:size-3.5", className), ...props, children: children ?? _jsx(ChevronRightIcon, {}) }));
|
|
29
|
+
}
|
|
30
|
+
function BreadcrumbEllipsis({ className, ...props }) {
|
|
31
|
+
return (_jsxs("span", { "data-slot": "breadcrumb-ellipsis", role: "presentation", "aria-hidden": "true", className: cn("flex size-6 items-center justify-center", className), ...props, children: [_jsx(MoreHorizontalIcon, { className: "size-4" }), _jsx("span", { className: "sr-only", children: "More" })] }));
|
|
32
|
+
}
|
|
33
|
+
export { Breadcrumb, BreadcrumbEllipsis, BreadcrumbItem, BreadcrumbLink, BreadcrumbList, BreadcrumbPage, BreadcrumbSeparator, };
|
package/dist/button.d.ts
CHANGED
|
@@ -1,14 +1,15 @@
|
|
|
1
1
|
import * as React from "react";
|
|
2
2
|
import { type VariantProps } from "class-variance-authority";
|
|
3
3
|
/**
|
|
4
|
-
* Outline and ghost hover/focus:
|
|
5
|
-
* selected
|
|
4
|
+
* Outline and ghost hover/focus: selected-foreground border, selected wash, and
|
|
5
|
+
* `selected-foreground` text (primary in light mode, a lighter purple that
|
|
6
|
+
* stays readable on dark), no muted grey fill. Used by quiet actions such as
|
|
6
7
|
* "Clear selection" sitting on a selected row.
|
|
7
8
|
*/
|
|
8
|
-
declare const quietButtonInteraction = "hover:border-
|
|
9
|
+
declare const quietButtonInteraction = "hover:border-selected-foreground hover:bg-selected hover:text-selected-foreground focus-visible:text-selected-foreground aria-expanded:border-selected-foreground aria-expanded:bg-selected aria-expanded:text-selected-foreground";
|
|
9
10
|
declare const buttonVariants: (props?: ({
|
|
10
|
-
variant?: "default" | "
|
|
11
|
-
size?: "default" | "
|
|
11
|
+
variant?: "default" | "link" | "destructive" | "secondary" | "outline" | "ghost" | null | undefined;
|
|
12
|
+
size?: "default" | "sm" | "lg" | "xs" | "icon" | "icon-xs" | "icon-sm" | "icon-lg" | null | undefined;
|
|
12
13
|
} & import("class-variance-authority/types").ClassProp) | undefined) => string;
|
|
13
14
|
declare function Button({ className, variant, size, asChild, ...props }: React.ComponentProps<"button"> & VariantProps<typeof buttonVariants> & {
|
|
14
15
|
asChild?: boolean;
|
package/dist/button.js
CHANGED
|
@@ -4,20 +4,21 @@ import { cva } from "class-variance-authority";
|
|
|
4
4
|
import { Slot } from "radix-ui";
|
|
5
5
|
import { cn } from "./utils.js";
|
|
6
6
|
/**
|
|
7
|
-
* Outline and ghost hover/focus:
|
|
8
|
-
* selected
|
|
7
|
+
* Outline and ghost hover/focus: selected-foreground border, selected wash, and
|
|
8
|
+
* `selected-foreground` text (primary in light mode, a lighter purple that
|
|
9
|
+
* stays readable on dark), no muted grey fill. Used by quiet actions such as
|
|
9
10
|
* "Clear selection" sitting on a selected row.
|
|
10
11
|
*/
|
|
11
|
-
const quietButtonInteraction = "hover:border-
|
|
12
|
-
const buttonVariants = cva("group/button inline-flex shrink-0 items-center justify-center rounded-none border border-transparent bg-clip-padding text-xs font-semibold tracking-widest whitespace-nowrap uppercase transition-all outline-none select-none focus-visible:border-ring focus-visible:ring-2 focus-visible:ring-ring
|
|
12
|
+
const quietButtonInteraction = "hover:border-selected-foreground hover:bg-selected hover:text-selected-foreground focus-visible:text-selected-foreground aria-expanded:border-selected-foreground aria-expanded:bg-selected aria-expanded:text-selected-foreground";
|
|
13
|
+
const buttonVariants = cva("group/button inline-flex shrink-0 items-center justify-center rounded-none border border-transparent bg-clip-padding text-xs font-semibold tracking-widest whitespace-nowrap uppercase transition-all outline-none select-none focus-visible:border-ring focus-visible:ring-2 focus-visible:ring-ring active:not-aria-[haspopup]:translate-y-px disabled:pointer-events-none disabled:opacity-50 aria-invalid:border-destructive aria-invalid:ring-2 aria-invalid:ring-destructive/20 dark:aria-invalid:border-destructive/50 dark:aria-invalid:ring-destructive/40 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-3.5", {
|
|
13
14
|
variants: {
|
|
14
15
|
variant: {
|
|
15
16
|
default: "bg-primary text-primary-foreground hover:bg-primary/80",
|
|
16
17
|
outline: `border-border bg-transparent ${quietButtonInteraction}`,
|
|
17
18
|
secondary: "bg-secondary text-secondary-foreground hover:bg-secondary/80 aria-expanded:bg-secondary aria-expanded:text-secondary-foreground",
|
|
18
19
|
ghost: quietButtonInteraction,
|
|
19
|
-
destructive: "bg-destructive/10 text-destructive hover:bg-destructive/
|
|
20
|
-
link: "text-
|
|
20
|
+
destructive: "bg-destructive/10 text-destructive hover:bg-destructive/15 dark:bg-destructive/20 dark:hover:bg-destructive/30",
|
|
21
|
+
link: "text-selected-foreground underline underline-offset-4 hover:underline",
|
|
21
22
|
},
|
|
22
23
|
size: {
|
|
23
24
|
default: "h-10 gap-1.5 px-6 has-data-[icon=inline-end]:pr-4 has-data-[icon=inline-start]:pl-4",
|
package/dist/calendar.d.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import * as React from "react";
|
|
2
2
|
import { DayPicker, type DayButton, type Locale } from "react-day-picker";
|
|
3
3
|
import { Button } from "./button.js";
|
|
4
|
-
declare function Calendar({ className, classNames, showOutsideDays, captionLayout, buttonVariant, locale, formatters, components, ...props }: React.ComponentProps<typeof DayPicker> & {
|
|
4
|
+
declare function Calendar({ className, classNames, showOutsideDays, captionLayout, buttonVariant, locale, formatters, labels, components, ...props }: React.ComponentProps<typeof DayPicker> & {
|
|
5
5
|
buttonVariant?: React.ComponentProps<typeof Button>["variant"];
|
|
6
6
|
}): React.JSX.Element;
|
|
7
7
|
declare function CalendarDayButton({ className, day, modifiers, locale, ...props }: React.ComponentProps<typeof DayButton> & {
|
package/dist/calendar.js
CHANGED
|
@@ -5,11 +5,29 @@ import { DayPicker, getDefaultClassNames, } from "react-day-picker";
|
|
|
5
5
|
import { cn } from "./utils.js";
|
|
6
6
|
import { Button, buttonVariants } from "./button.js";
|
|
7
7
|
import { ChevronLeftIcon, ChevronRightIcon, ChevronDownIcon, } from "lucide-react";
|
|
8
|
-
function Calendar({ className, classNames, showOutsideDays = true, captionLayout = "label", buttonVariant = "ghost", locale, formatters, components, ...props }) {
|
|
8
|
+
function Calendar({ className, classNames, showOutsideDays = true, captionLayout = "label", buttonVariant = "ghost", locale, formatters, labels, components, ...props }) {
|
|
9
9
|
const defaultClassNames = getDefaultClassNames();
|
|
10
10
|
return (_jsx(DayPicker, { showOutsideDays: showOutsideDays, className: cn("group/calendar bg-background p-3 [--cell-radius:0] [--cell-size:--spacing(8)] in-data-[slot=card-content]:bg-transparent in-data-[slot=popover-content]:bg-transparent", String.raw `rtl:**:[.rdp-button\_next>svg]:rotate-180`, String.raw `rtl:**:[.rdp-button\_previous>svg]:rotate-180`, className), captionLayout: captionLayout, locale: locale, formatters: {
|
|
11
11
|
formatMonthDropdown: (date) => date.toLocaleString(locale?.code, { month: "short" }),
|
|
12
12
|
...formatters,
|
|
13
|
+
}, labels: {
|
|
14
|
+
// Day numbers without ordinals ("September 27", not "27th") so the
|
|
15
|
+
// accessible name contains the visible "27" (WCAG 2.5.3 Label in
|
|
16
|
+
// Name); speech users can then say "click 27".
|
|
17
|
+
labelDayButton: (date, modifiers) => {
|
|
18
|
+
let label = date.toLocaleDateString(locale?.code, {
|
|
19
|
+
weekday: "long",
|
|
20
|
+
year: "numeric",
|
|
21
|
+
month: "long",
|
|
22
|
+
day: "numeric",
|
|
23
|
+
});
|
|
24
|
+
if (modifiers.today)
|
|
25
|
+
label = `Today, ${label}`;
|
|
26
|
+
if (modifiers.selected)
|
|
27
|
+
label = `${label}, selected`;
|
|
28
|
+
return label;
|
|
29
|
+
},
|
|
30
|
+
...labels,
|
|
13
31
|
}, classNames: {
|
|
14
32
|
root: cn("w-fit", defaultClassNames.root),
|
|
15
33
|
months: cn("relative flex flex-col gap-4 md:flex-row", defaultClassNames.months),
|
|
@@ -71,6 +89,6 @@ function CalendarDayButton({ className, day, modifiers, locale, ...props }) {
|
|
|
71
89
|
return (_jsx(Button, { ref: ref, variant: "ghost", size: "icon", "data-day": day.date.toLocaleDateString(locale?.code), "data-selected-single": modifiers.selected &&
|
|
72
90
|
!modifiers.range_start &&
|
|
73
91
|
!modifiers.range_end &&
|
|
74
|
-
!modifiers.range_middle, "data-range-start": modifiers.range_start, "data-range-end": modifiers.range_end, "data-range-middle": modifiers.range_middle, className: cn("relative isolate z-10 flex aspect-square size-auto w-full min-w-(--cell-size) flex-col gap-1 border-0 leading-none font-normal group-data-[focused=true]/day:relative group-data-[focused=true]/day:z-10 group-data-[focused=true]/day:border-ring group-data-[focused=true]/day:ring-
|
|
92
|
+
!modifiers.range_middle, "data-range-start": modifiers.range_start, "data-range-end": modifiers.range_end, "data-range-middle": modifiers.range_middle, className: cn("relative isolate z-10 flex aspect-square size-auto w-full min-w-(--cell-size) flex-col gap-1 border-0 leading-none font-normal group-data-[focused=true]/day:relative group-data-[focused=true]/day:z-10 group-data-[focused=true]/day:border-ring group-data-[focused=true]/day:ring-2 group-data-[focused=true]/day:ring-ring data-[range-end=true]:rounded-(--cell-radius) data-[range-end=true]:rounded-r-(--cell-radius) data-[range-end=true]:bg-primary data-[range-end=true]:text-primary-foreground data-[range-middle=true]:rounded-none data-[range-middle=true]:bg-selected data-[range-middle=true]:text-selected-foreground data-[range-start=true]:rounded-(--cell-radius) data-[range-start=true]:rounded-l-(--cell-radius) data-[range-start=true]:bg-primary data-[range-start=true]:text-primary-foreground data-[selected-single=true]:bg-primary data-[selected-single=true]:text-primary-foreground dark:hover:text-foreground [&>span]:text-xs [&>span]:opacity-70", defaultClassNames.day, className), ...props }));
|
|
75
93
|
}
|
|
76
94
|
export { Calendar, CalendarDayButton };
|
package/dist/checkbox.js
CHANGED
|
@@ -5,6 +5,6 @@ import { Checkbox as CheckboxPrimitive } from "radix-ui";
|
|
|
5
5
|
import { cn } from "./utils.js";
|
|
6
6
|
import { CheckIcon } from "lucide-react";
|
|
7
7
|
function Checkbox({ className, ...props }) {
|
|
8
|
-
return (_jsx(CheckboxPrimitive.Root, { "data-slot": "checkbox", className: cn("peer relative flex size-4.5 shrink-0 items-center justify-center rounded-none border border-input bg-transparent transition-shadow outline-none group-has-disabled/field:opacity-50 after:absolute after:-inset-x-3 after:-inset-y-2 focus-visible:border-ring focus-visible:ring-2 focus-visible:ring-ring
|
|
8
|
+
return (_jsx(CheckboxPrimitive.Root, { "data-slot": "checkbox", className: cn("peer relative flex size-4.5 shrink-0 items-center justify-center rounded-none border border-input bg-transparent transition-shadow outline-none group-has-disabled/field:opacity-50 after:absolute after:-inset-x-3 after:-inset-y-2 focus-visible:border-ring focus-visible:ring-2 focus-visible:ring-ring disabled:cursor-not-allowed disabled:opacity-50 aria-invalid:border-destructive aria-invalid:ring-2 aria-invalid:ring-destructive/20 aria-invalid:aria-checked:border-primary dark:aria-invalid:border-destructive/50 dark:aria-invalid:ring-destructive/40 data-checked:border-primary data-checked:bg-primary data-checked:text-primary-foreground dark:data-checked:bg-primary", className), ...props, children: _jsx(CheckboxPrimitive.Indicator, { "data-slot": "checkbox-indicator", className: "grid place-content-center text-current transition-none [&>svg]:size-3.5", children: _jsx(CheckIcon, {}) }) }));
|
|
9
9
|
}
|
|
10
10
|
export { Checkbox };
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import type * as React from "react";
|
|
2
|
+
export type ColorLegendItem = {
|
|
3
|
+
/** CSS color from the app (map bins, status scales). The kit does not own it. */
|
|
4
|
+
color: string;
|
|
5
|
+
range?: string;
|
|
6
|
+
label: string;
|
|
7
|
+
};
|
|
8
|
+
export type ColorLegendProps = {
|
|
9
|
+
title?: string;
|
|
10
|
+
items: ColorLegendItem[];
|
|
11
|
+
caption?: React.ReactNode;
|
|
12
|
+
children?: React.ReactNode;
|
|
13
|
+
"aria-label"?: string;
|
|
14
|
+
className?: string;
|
|
15
|
+
};
|
|
16
|
+
/**
|
|
17
|
+
* Key for a color scale: swatch, optional range, and label. Overlay chrome
|
|
18
|
+
* (absolute position, card fill) is the caller's `className`. Attribution
|
|
19
|
+
* and license lines stay in the app.
|
|
20
|
+
*/
|
|
21
|
+
declare function ColorLegend({ title, items, caption, children, "aria-label": ariaLabel, className, }: ColorLegendProps): React.JSX.Element;
|
|
22
|
+
export { ColorLegend };
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { cn } from "./utils.js";
|
|
3
|
+
/**
|
|
4
|
+
* Key for a color scale: swatch, optional range, and label. Overlay chrome
|
|
5
|
+
* (absolute position, card fill) is the caller's `className`. Attribution
|
|
6
|
+
* and license lines stay in the app.
|
|
7
|
+
*/
|
|
8
|
+
function ColorLegend({ title, items, caption, children, "aria-label": ariaLabel, className, }) {
|
|
9
|
+
return (_jsxs("figure", { "data-slot": "color-legend", "aria-label": ariaLabel, className: cn("flex flex-col gap-2 text-sm", className), children: [title ? (_jsx("figcaption", { className: "font-heading text-xs font-semibold tracking-widest text-muted-foreground uppercase", children: title })) : null, _jsx("ul", { className: "flex flex-col gap-1.5", children: items.map((item) => (_jsxs("li", { className: "flex items-center gap-2", children: [_jsx("span", { "aria-hidden": true, className: "size-3.5 shrink-0 border border-input", style: { backgroundColor: item.color } }), item.range ? (_jsx("span", { className: "w-16 shrink-0 tabular-nums text-muted-foreground", children: item.range })) : null, _jsx("span", { children: item.label })] }, `${item.color}-${item.range ?? ""}-${item.label}`))) }), caption ? (_jsx("p", { className: "text-xs text-muted-foreground", children: caption })) : null, children] }));
|
|
10
|
+
}
|
|
11
|
+
export { ColorLegend };
|
package/dist/combobox.d.ts
CHANGED
|
@@ -14,6 +14,9 @@ type ComboboxProps = {
|
|
|
14
14
|
id?: string;
|
|
15
15
|
className?: string;
|
|
16
16
|
"aria-invalid"?: boolean;
|
|
17
|
+
/** Name the trigger when there is no `<Label htmlFor={id}>`. */
|
|
18
|
+
"aria-label"?: string;
|
|
19
|
+
"aria-labelledby"?: string;
|
|
17
20
|
};
|
|
18
21
|
/**
|
|
19
22
|
* Searchable single-select built from Button, Popover, and Input.
|
|
@@ -22,5 +25,5 @@ type ComboboxProps = {
|
|
|
22
25
|
* Keyboard highlight (arrows, Home/End, PageUp/PageDown) scrolls the active
|
|
23
26
|
* option into view inside the overflow list.
|
|
24
27
|
*/
|
|
25
|
-
export declare function Combobox({ options, value, onValueChange, placeholder, searchPlaceholder, emptyText, disabled, id, className, "aria-invalid": ariaInvalid, }: ComboboxProps): React.JSX.Element;
|
|
28
|
+
export declare function Combobox({ options, value, onValueChange, placeholder, searchPlaceholder, emptyText, disabled, id, className, "aria-invalid": ariaInvalid, "aria-label": ariaLabel, "aria-labelledby": ariaLabelledBy, }: ComboboxProps): React.JSX.Element;
|
|
26
29
|
export {};
|
package/dist/combobox.js
CHANGED
|
@@ -20,7 +20,7 @@ const LISTBOX_PAGE_SIZE = 10;
|
|
|
20
20
|
* Keyboard highlight (arrows, Home/End, PageUp/PageDown) scrolls the active
|
|
21
21
|
* option into view inside the overflow list.
|
|
22
22
|
*/
|
|
23
|
-
export function Combobox({ options, value, onValueChange, placeholder = "Select", searchPlaceholder = "Search", emptyText = "No results", disabled, id, className, "aria-invalid": ariaInvalid, }) {
|
|
23
|
+
export function Combobox({ options, value, onValueChange, placeholder = "Select", searchPlaceholder = "Search", emptyText = "No results", disabled, id, className, "aria-invalid": ariaInvalid, "aria-label": ariaLabel, "aria-labelledby": ariaLabelledBy, }) {
|
|
24
24
|
const [open, setOpen] = React.useState(false);
|
|
25
25
|
const [query, setQuery] = React.useState("");
|
|
26
26
|
const [highlight, setHighlight] = React.useState(0);
|
|
@@ -61,10 +61,17 @@ export function Combobox({ options, value, onValueChange, placeholder = "Select"
|
|
|
61
61
|
setQuery(next);
|
|
62
62
|
setHighlight(0);
|
|
63
63
|
});
|
|
64
|
+
// Closing from here does not go through Radix's onOpenChange, so clear the
|
|
65
|
+
// query too. A stale query would filter the next open while the highlight
|
|
66
|
+
// is computed against the full list, and Enter would pick the wrong option.
|
|
64
67
|
const selectValue = (next) => {
|
|
65
68
|
onValueChange(next);
|
|
66
69
|
setOpen(false);
|
|
70
|
+
setQuery("");
|
|
67
71
|
};
|
|
72
|
+
// Index-based ids: option values may contain spaces, which are not valid
|
|
73
|
+
// in an id or an aria-activedescendant reference.
|
|
74
|
+
const optionId = (index) => `${listId}-option-${index}`;
|
|
68
75
|
const activeOption = filtered[highlight];
|
|
69
76
|
const onSearchKeyDown = (event) => {
|
|
70
77
|
if (event.key === "ArrowDown") {
|
|
@@ -102,11 +109,10 @@ export function Combobox({ options, value, onValueChange, placeholder = "Select"
|
|
|
102
109
|
setHighlight((index) => Math.max(index - LISTBOX_PAGE_SIZE, 0));
|
|
103
110
|
}
|
|
104
111
|
};
|
|
105
|
-
return (_jsxs(Popover, { open: open, onOpenChange: onOpenChange, children: [_jsx(PopoverTrigger, { asChild: true, children: _jsxs(Button, { id: id, type: "button", variant: "outline", role: "combobox", "aria-expanded": open, "aria-controls": listId, "aria-invalid": ariaInvalid, disabled: disabled, className: cn(formControlTriggerClassName, "justify-between", !selected && "text-muted-foreground", className), children: [_jsx("span", { className: "truncate", children: selected?.label ?? placeholder }), _jsx(ChevronDownIcon, { "data-icon": "inline-end", className: "opacity-50" })] }) }), _jsxs(PopoverContent, { align: "start", className: "w-[var(--radix-popover-trigger-width)] gap-0 rounded-none p-0", children: [_jsx("div", { className: "border-b p-2", children: _jsx(Input, { ref: inputRef, value: query, onChange: onQueryChange, onKeyDown: onSearchKeyDown, placeholder: searchPlaceholder, "aria-autocomplete": "list", "aria-controls": listId, "aria-activedescendant": activeOption
|
|
106
|
-
? `${listId}-option-${activeOption.value}`
|
|
107
|
-
: undefined }) }), _jsx("ul", { id: listId, role: "listbox", className: "max-h-60 overflow-y-auto p-1", children: filtered.length === 0 ? (_jsx("li", { className: "px-3 py-4 text-center text-sm text-muted-foreground", children: emptyText })) : (filtered.map((option, index) => {
|
|
112
|
+
return (_jsxs(Popover, { open: open, onOpenChange: onOpenChange, children: [_jsx(PopoverTrigger, { asChild: true, children: _jsxs(Button, { id: id, type: "button", variant: "outline", role: "combobox", "aria-expanded": open, "aria-controls": listId, "aria-invalid": ariaInvalid, "aria-label": ariaLabel, "aria-labelledby": ariaLabelledBy, disabled: disabled, className: cn(formControlTriggerClassName, "justify-between", !selected && "text-muted-foreground", className), children: [_jsx("span", { className: "truncate", children: selected?.label ?? placeholder }), _jsx(ChevronDownIcon, { "data-icon": "inline-end", className: "opacity-50" })] }) }), _jsxs(PopoverContent, { align: "start", className: "w-[var(--radix-popover-trigger-width)] gap-0 rounded-none p-0", children: [_jsx("div", { className: "border-b p-2", children: _jsx(Input, { ref: inputRef, value: query, onChange: onQueryChange, onKeyDown: onSearchKeyDown, placeholder: searchPlaceholder, "aria-autocomplete": "list", "aria-controls": listId, "aria-activedescendant": activeOption ? optionId(highlight) : undefined }) }), _jsx("ul", { id: listId, role: "listbox", className: "max-h-60 overflow-y-auto p-1", children: filtered.length === 0 ? (_jsx("li", { className: "px-3 py-4 text-center text-sm text-muted-foreground", children: emptyText })) : (filtered.map((option, index) => {
|
|
108
113
|
const isSelected = option.value === value;
|
|
109
114
|
const isActive = index === highlight;
|
|
110
|
-
return (_jsx("li", { role: "none", children: _jsxs("button", { ref: isActive ? scrollHighlightedOption : undefined, id:
|
|
115
|
+
return (_jsx("li", { role: "none", children: _jsxs("button", { ref: isActive ? scrollHighlightedOption : undefined, id: optionId(index), type: "button", role: "option", "aria-selected": isSelected, className: cn("relative flex w-full cursor-default items-center gap-2 rounded-none py-2 pr-8 pl-3 text-left text-sm outline-hidden select-none", isSelected && "bg-selected text-selected-foreground", isActive &&
|
|
116
|
+
"bg-accent text-accent-foreground shadow-[inset_2px_0_0_var(--color-ring)]"), onMouseEnter: () => setHighlight(index), onClick: () => selectValue(option.value), children: [_jsx("span", { className: "truncate", children: option.label }), isSelected ? (_jsx(CheckIcon, { className: "pointer-events-none absolute right-2 size-3.5" })) : null] }) }, option.value));
|
|
111
117
|
})) })] })] }));
|
|
112
118
|
}
|
package/dist/date-picker.js
CHANGED
|
@@ -77,11 +77,22 @@ function DatePickerRangeButton({ id, value, onChange, placeholder = "Pick a date
|
|
|
77
77
|
const from = toDate(value?.from);
|
|
78
78
|
const to = toDate(value?.to);
|
|
79
79
|
const selected = from || to ? { from, to } : undefined;
|
|
80
|
-
|
|
81
|
-
|
|
80
|
+
// Opening on a complete range means the next click starts a new one.
|
|
81
|
+
// Without this, Day Picker extends the old range and the popover closes
|
|
82
|
+
// on that first click, so a fresh range needs Clear first.
|
|
83
|
+
const restartRef = React.useRef(false);
|
|
84
|
+
const onOpenChange = (next) => {
|
|
85
|
+
if (next)
|
|
86
|
+
restartRef.current = Boolean(from && to);
|
|
87
|
+
setOpen(next);
|
|
88
|
+
};
|
|
89
|
+
return (_jsxs(DatePickerShell, { id: id, disabled: disabled, ariaInvalid: ariaInvalid, className: className, empty: !from, label: formatRangeTriggerLabel(from, to, placeholder), open: open, onOpenChange: onOpenChange, side: side, children: [_jsx(Calendar, { mode: "range", selected: selected, defaultMonth: defaultMonth ?? from ?? to, numberOfMonths: months, onSelect: (next, day) => {
|
|
90
|
+
const range = restartRef.current ? { from: day, to: day } : next;
|
|
91
|
+
restartRef.current = false;
|
|
92
|
+
onChange(range);
|
|
82
93
|
// First click is a same-day range; keep the popover open so the
|
|
83
94
|
// user can set `to`. Close once the ends differ.
|
|
84
|
-
if (
|
|
95
|
+
if (range?.from && range.to && !isSameDay(range.from, range.to)) {
|
|
85
96
|
setOpen(false);
|
|
86
97
|
}
|
|
87
98
|
} }), _jsx("div", { className: "flex justify-end border-t p-2", children: _jsx(Button, { type: "button", variant: "ghost", size: "sm", disabled: !from && !to, onClick: () => {
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import * as React from "react";
|
|
2
|
+
import { PopoverContent } from "./popover.js";
|
|
3
|
+
/** Default clock increment, in minutes. Must divide 60. */
|
|
4
|
+
export declare const DEFAULT_TIME_STEP = 15;
|
|
5
|
+
export type DateTimePickerButtonProps = {
|
|
6
|
+
/** Controlled instant. `null` or omitted is empty. */
|
|
7
|
+
value?: Date | null;
|
|
8
|
+
onChange: (date: Date | null) => void;
|
|
9
|
+
/**
|
|
10
|
+
* Minute increment for the time selects (1, 5, 15, 30, or 60).
|
|
11
|
+
* Values that do not divide 60 fall back to 15 so the list stays even.
|
|
12
|
+
*/
|
|
13
|
+
timeStep?: number;
|
|
14
|
+
id?: string;
|
|
15
|
+
placeholder?: string;
|
|
16
|
+
disabled?: boolean;
|
|
17
|
+
className?: string;
|
|
18
|
+
"aria-invalid"?: boolean;
|
|
19
|
+
/** Popover side. Defaults to `bottom`; Radix still flips on collision. */
|
|
20
|
+
side?: React.ComponentProps<typeof PopoverContent>["side"];
|
|
21
|
+
/** Month shown when the popover opens; falls back to the selected date. */
|
|
22
|
+
defaultMonth?: Date;
|
|
23
|
+
};
|
|
24
|
+
/**
|
|
25
|
+
* Normalize a minute step so option lists stay even (1, 5, 15, 30, 60).
|
|
26
|
+
* Invalid values fall back to 15 so a bad prop cannot empty the minute list.
|
|
27
|
+
*/
|
|
28
|
+
export declare function resolveTimeStep(step: number | undefined): number;
|
|
29
|
+
/**
|
|
30
|
+
* Calendar plus hour/minute popover trigger styled as a form control (same
|
|
31
|
+
* chrome as Input, SelectTrigger, and DatePickerButton). `value` is a `Date`
|
|
32
|
+
* or `null`. Picking a day keeps the popover open so the time can be set;
|
|
33
|
+
* Clear emits `null`. One month only, clamped to the viewport, so the panel
|
|
34
|
+
* stays on-screen at a 390px width.
|
|
35
|
+
*/
|
|
36
|
+
export declare function DateTimePickerButton({ id, value, onChange, timeStep, placeholder, disabled, className, "aria-invalid": ariaInvalid, side, defaultMonth, }: DateTimePickerButtonProps): React.JSX.Element;
|
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
3
|
+
import * as React from "react";
|
|
4
|
+
import { format } from "date-fns";
|
|
5
|
+
import { CalendarIcon } from "lucide-react";
|
|
6
|
+
import { Button } from "./button.js";
|
|
7
|
+
import { Calendar } from "./calendar.js";
|
|
8
|
+
import { formControlTriggerClassName } from "./internal/form-control.js";
|
|
9
|
+
import { Popover, PopoverContent, PopoverTrigger } from "./popover.js";
|
|
10
|
+
import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue, } from "./select.js";
|
|
11
|
+
import { cn } from "./utils.js";
|
|
12
|
+
/** Default clock increment, in minutes. Must divide 60. */
|
|
13
|
+
export const DEFAULT_TIME_STEP = 15;
|
|
14
|
+
/** Gutter used when the calendar popover collides with the viewport. */
|
|
15
|
+
const DATE_TIME_PICKER_COLLISION_PADDING = 16;
|
|
16
|
+
/**
|
|
17
|
+
* Normalize a minute step so option lists stay even (1, 5, 15, 30, 60).
|
|
18
|
+
* Invalid values fall back to 15 so a bad prop cannot empty the minute list.
|
|
19
|
+
*/
|
|
20
|
+
export function resolveTimeStep(step) {
|
|
21
|
+
if (step == null)
|
|
22
|
+
return DEFAULT_TIME_STEP;
|
|
23
|
+
if (!Number.isInteger(step) || step <= 0 || step > 60 || 60 % step !== 0) {
|
|
24
|
+
return DEFAULT_TIME_STEP;
|
|
25
|
+
}
|
|
26
|
+
return step;
|
|
27
|
+
}
|
|
28
|
+
/** Two-digit clock fragment (`00`–`23` / `00`–`59`). */
|
|
29
|
+
function padTimePart(value) {
|
|
30
|
+
return String(value).padStart(2, "0");
|
|
31
|
+
}
|
|
32
|
+
/**
|
|
33
|
+
* Build a local Date from a calendar day and a clock time.
|
|
34
|
+
* Seconds and milliseconds stay zero so a stepped minute remains exact.
|
|
35
|
+
*/
|
|
36
|
+
function combineDateAndTime(day, hours, minutes) {
|
|
37
|
+
const next = new Date(day);
|
|
38
|
+
next.setHours(hours, minutes, 0, 0);
|
|
39
|
+
return next;
|
|
40
|
+
}
|
|
41
|
+
/**
|
|
42
|
+
* Minute options for `timeStep`, plus the current minute when it is off-step
|
|
43
|
+
* so a loaded value such as 14:07 still appears in the select.
|
|
44
|
+
*/
|
|
45
|
+
function minuteOptions(step, current) {
|
|
46
|
+
const minutes = [];
|
|
47
|
+
for (let minute = 0; minute < 60; minute += step) {
|
|
48
|
+
minutes.push(minute);
|
|
49
|
+
}
|
|
50
|
+
if (current != null && !minutes.includes(current)) {
|
|
51
|
+
minutes.push(current);
|
|
52
|
+
minutes.sort((a, b) => a - b);
|
|
53
|
+
}
|
|
54
|
+
return minutes;
|
|
55
|
+
}
|
|
56
|
+
const HOUR_OPTIONS = Array.from({ length: 24 }, (_, hour) => padTimePart(hour));
|
|
57
|
+
/**
|
|
58
|
+
* Keep the date-time popover open when a portaled Select option is clicked.
|
|
59
|
+
* Select content renders outside the popover, so Radix would otherwise treat
|
|
60
|
+
* that pointer down as an outside dismiss.
|
|
61
|
+
*/
|
|
62
|
+
function preventDismissForPortaledSelect(event) {
|
|
63
|
+
const target = event.target;
|
|
64
|
+
if (target instanceof Element &&
|
|
65
|
+
target.closest("[data-slot=select-content]")) {
|
|
66
|
+
event.preventDefault();
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
/**
|
|
70
|
+
* Calendar plus hour/minute popover trigger styled as a form control (same
|
|
71
|
+
* chrome as Input, SelectTrigger, and DatePickerButton). `value` is a `Date`
|
|
72
|
+
* or `null`. Picking a day keeps the popover open so the time can be set;
|
|
73
|
+
* Clear emits `null`. One month only, clamped to the viewport, so the panel
|
|
74
|
+
* stays on-screen at a 390px width.
|
|
75
|
+
*/
|
|
76
|
+
export function DateTimePickerButton({ id, value, onChange, timeStep, placeholder = "Pick a date and time", disabled, className, "aria-invalid": ariaInvalid, side, defaultMonth, }) {
|
|
77
|
+
const [open, setOpen] = React.useState(false);
|
|
78
|
+
const date = value ?? null;
|
|
79
|
+
const step = resolveTimeStep(timeStep);
|
|
80
|
+
const empty = date == null;
|
|
81
|
+
const label = date ? format(date, "PPP p") : placeholder;
|
|
82
|
+
const hourId = React.useId();
|
|
83
|
+
const minuteId = React.useId();
|
|
84
|
+
return (_jsxs(Popover, { open: open, onOpenChange: setOpen, children: [_jsx(PopoverTrigger, { asChild: true, children: _jsxs(Button, { id: id, type: "button", variant: "outline", disabled: disabled, "aria-invalid": ariaInvalid, "data-empty": empty, className: cn(formControlTriggerClassName, "justify-start data-[empty=true]:text-muted-foreground", className), children: [_jsx(CalendarIcon, { "data-icon": "inline-start" }), label] }) }), _jsxs(PopoverContent, { align: "start", side: side, collisionPadding: DATE_TIME_PICKER_COLLISION_PADDING, onInteractOutside: preventDismissForPortaledSelect, className: "w-auto min-w-0 max-w-[min(100vw-2rem,24rem)] max-h-(--radix-popover-content-available-height) overflow-y-auto rounded-none p-0", children: [_jsx(Calendar, { mode: "single", selected: date ?? undefined, defaultMonth: defaultMonth ?? date ?? undefined, onSelect: (next) => {
|
|
85
|
+
// Re-clicking a selected day would clear it; require Clear instead
|
|
86
|
+
// so a time already set is not dropped by an accidental second tap.
|
|
87
|
+
if (!next)
|
|
88
|
+
return;
|
|
89
|
+
onChange(combineDateAndTime(next, date?.getHours() ?? 0, date?.getMinutes() ?? 0));
|
|
90
|
+
} }), _jsxs("div", { role: "group", "aria-label": "Time", className: "flex min-w-0 flex-col gap-2 border-t p-3", children: [_jsx("p", { className: "text-xs font-semibold tracking-wide uppercase", children: "Time" }), _jsxs("div", { className: "flex min-w-0 items-center gap-2", children: [_jsxs(Select, { value: date ? padTimePart(date.getHours()) : undefined, onValueChange: (nextHour) => {
|
|
91
|
+
if (!date)
|
|
92
|
+
return;
|
|
93
|
+
onChange(combineDateAndTime(date, Number(nextHour), date.getMinutes()));
|
|
94
|
+
}, disabled: empty, children: [_jsx(SelectTrigger, { id: hourId, "aria-label": "Hour", className: "min-w-0 flex-1", children: _jsx(SelectValue, { placeholder: "\u2013\u2013" }) }), _jsx(SelectContent, { children: HOUR_OPTIONS.map((hour) => (_jsx(SelectItem, { value: hour, children: hour }, hour))) })] }), _jsx("span", { className: "text-muted-foreground", "aria-hidden": "true", children: ":" }), _jsxs(Select, { value: date ? padTimePart(date.getMinutes()) : undefined, onValueChange: (nextMinute) => {
|
|
95
|
+
if (!date)
|
|
96
|
+
return;
|
|
97
|
+
onChange(combineDateAndTime(date, date.getHours(), Number(nextMinute)));
|
|
98
|
+
}, disabled: empty, children: [_jsx(SelectTrigger, { id: minuteId, "aria-label": "Minute", className: "min-w-0 flex-1", children: _jsx(SelectValue, { placeholder: "\u2013\u2013" }) }), _jsx(SelectContent, { children: minuteOptions(step, date?.getMinutes()).map((minute) => {
|
|
99
|
+
const value = padTimePart(minute);
|
|
100
|
+
return (_jsx(SelectItem, { value: value, children: value }, value));
|
|
101
|
+
}) })] })] })] }), _jsx("div", { className: "flex justify-end border-t p-2", children: _jsx(Button, { type: "button", variant: "ghost", size: "sm", disabled: empty, onClick: () => {
|
|
102
|
+
onChange(null);
|
|
103
|
+
setOpen(false);
|
|
104
|
+
}, children: "Clear" }) })] })] }));
|
|
105
|
+
}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import * as React from "react";
|
|
2
|
+
import { DropdownMenu as DropdownMenuPrimitive } from "radix-ui";
|
|
3
|
+
/** Action menu for commands (row actions, overflow menus). Use `Select` to pick a value. */
|
|
4
|
+
declare function DropdownMenu({ ...props }: React.ComponentProps<typeof DropdownMenuPrimitive.Root>): React.JSX.Element;
|
|
5
|
+
declare function DropdownMenuPortal({ ...props }: React.ComponentProps<typeof DropdownMenuPrimitive.Portal>): React.JSX.Element;
|
|
6
|
+
declare function DropdownMenuTrigger({ ...props }: React.ComponentProps<typeof DropdownMenuPrimitive.Trigger>): React.JSX.Element;
|
|
7
|
+
declare function DropdownMenuContent({ className, align, sideOffset, collisionPadding, ...props }: React.ComponentProps<typeof DropdownMenuPrimitive.Content>): React.JSX.Element;
|
|
8
|
+
declare function DropdownMenuGroup({ ...props }: React.ComponentProps<typeof DropdownMenuPrimitive.Group>): React.JSX.Element;
|
|
9
|
+
declare function DropdownMenuItem({ className, inset, variant, ...props }: React.ComponentProps<typeof DropdownMenuPrimitive.Item> & {
|
|
10
|
+
inset?: boolean;
|
|
11
|
+
variant?: "default" | "destructive";
|
|
12
|
+
}): React.JSX.Element;
|
|
13
|
+
declare function DropdownMenuCheckboxItem({ className, children, checked, ...props }: React.ComponentProps<typeof DropdownMenuPrimitive.CheckboxItem>): React.JSX.Element;
|
|
14
|
+
declare function DropdownMenuRadioGroup({ ...props }: React.ComponentProps<typeof DropdownMenuPrimitive.RadioGroup>): React.JSX.Element;
|
|
15
|
+
declare function DropdownMenuRadioItem({ className, children, ...props }: React.ComponentProps<typeof DropdownMenuPrimitive.RadioItem>): React.JSX.Element;
|
|
16
|
+
declare function DropdownMenuLabel({ className, inset, ...props }: React.ComponentProps<typeof DropdownMenuPrimitive.Label> & {
|
|
17
|
+
inset?: boolean;
|
|
18
|
+
}): React.JSX.Element;
|
|
19
|
+
declare function DropdownMenuSeparator({ className, ...props }: React.ComponentProps<typeof DropdownMenuPrimitive.Separator>): React.JSX.Element;
|
|
20
|
+
declare function DropdownMenuShortcut({ className, ...props }: React.ComponentProps<"span">): React.JSX.Element;
|
|
21
|
+
declare function DropdownMenuSub({ ...props }: React.ComponentProps<typeof DropdownMenuPrimitive.Sub>): React.JSX.Element;
|
|
22
|
+
declare function DropdownMenuSubTrigger({ className, inset, children, ...props }: React.ComponentProps<typeof DropdownMenuPrimitive.SubTrigger> & {
|
|
23
|
+
inset?: boolean;
|
|
24
|
+
}): React.JSX.Element;
|
|
25
|
+
declare function DropdownMenuSubContent({ className, ...props }: React.ComponentProps<typeof DropdownMenuPrimitive.SubContent>): React.JSX.Element;
|
|
26
|
+
export { DropdownMenu, DropdownMenuCheckboxItem, DropdownMenuContent, DropdownMenuGroup, DropdownMenuItem, DropdownMenuLabel, DropdownMenuPortal, DropdownMenuRadioGroup, DropdownMenuRadioItem, DropdownMenuSeparator, DropdownMenuShortcut, DropdownMenuSub, DropdownMenuSubContent, DropdownMenuSubTrigger, DropdownMenuTrigger, };
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
3
|
+
import * as React from "react";
|
|
4
|
+
import { DropdownMenu as DropdownMenuPrimitive } from "radix-ui";
|
|
5
|
+
import { CheckIcon, ChevronRightIcon } from "lucide-react";
|
|
6
|
+
import { cn } from "./utils.js";
|
|
7
|
+
/** Item highlight and selected chrome shared with `SelectItem`. */
|
|
8
|
+
const menuItemClassName = "relative flex cursor-default items-center gap-2.5 rounded-none px-3 py-2 text-sm outline-hidden select-none focus:bg-accent focus:text-accent-foreground focus:shadow-[inset_2px_0_0_var(--color-ring)] data-disabled:pointer-events-none data-disabled:opacity-50 data-inset:pl-9 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-3.5";
|
|
9
|
+
const menuContentClassName = "z-50 min-w-40 overflow-x-hidden overflow-y-auto rounded-none bg-popover p-1 text-popover-foreground shadow-md ring-1 ring-foreground/10 duration-100 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 data-open:animate-in data-open:fade-in-0 data-open:zoom-in-95 data-closed:animate-out data-closed:fade-out-0 data-closed:zoom-out-95";
|
|
10
|
+
/** Action menu for commands (row actions, overflow menus). Use `Select` to pick a value. */
|
|
11
|
+
function DropdownMenu({ ...props }) {
|
|
12
|
+
return _jsx(DropdownMenuPrimitive.Root, { "data-slot": "dropdown-menu", ...props });
|
|
13
|
+
}
|
|
14
|
+
function DropdownMenuPortal({ ...props }) {
|
|
15
|
+
return (_jsx(DropdownMenuPrimitive.Portal, { "data-slot": "dropdown-menu-portal", ...props }));
|
|
16
|
+
}
|
|
17
|
+
function DropdownMenuTrigger({ ...props }) {
|
|
18
|
+
return (_jsx(DropdownMenuPrimitive.Trigger, { "data-slot": "dropdown-menu-trigger", ...props }));
|
|
19
|
+
}
|
|
20
|
+
function DropdownMenuContent({ className, align = "start", sideOffset = 4, collisionPadding = 8, ...props }) {
|
|
21
|
+
return (_jsx(DropdownMenuPrimitive.Portal, { children: _jsx(DropdownMenuPrimitive.Content, { "data-slot": "dropdown-menu-content", align: align, sideOffset: sideOffset, collisionPadding: collisionPadding, className: cn(menuContentClassName, "max-h-(--radix-dropdown-menu-content-available-height) origin-(--radix-dropdown-menu-content-transform-origin)", className), ...props }) }));
|
|
22
|
+
}
|
|
23
|
+
function DropdownMenuGroup({ ...props }) {
|
|
24
|
+
return (_jsx(DropdownMenuPrimitive.Group, { "data-slot": "dropdown-menu-group", ...props }));
|
|
25
|
+
}
|
|
26
|
+
function DropdownMenuItem({ className, inset, variant = "default", ...props }) {
|
|
27
|
+
return (_jsx(DropdownMenuPrimitive.Item, { "data-slot": "dropdown-menu-item", "data-inset": inset || undefined, "data-variant": variant, className: cn(menuItemClassName, "data-[variant=destructive]:text-destructive data-[variant=destructive]:focus:bg-destructive/10 data-[variant=destructive]:focus:text-destructive", className), ...props }));
|
|
28
|
+
}
|
|
29
|
+
function DropdownMenuCheckboxItem({ className, children, checked, ...props }) {
|
|
30
|
+
return (_jsxs(DropdownMenuPrimitive.CheckboxItem, { "data-slot": "dropdown-menu-checkbox-item", className: cn(menuItemClassName, "pl-9", className), checked: checked, ...props, children: [_jsx("span", { className: "pointer-events-none absolute left-3 flex size-3.5 items-center justify-center", children: _jsx(DropdownMenuPrimitive.ItemIndicator, { children: _jsx(CheckIcon, {}) }) }), children] }));
|
|
31
|
+
}
|
|
32
|
+
function DropdownMenuRadioGroup({ ...props }) {
|
|
33
|
+
return (_jsx(DropdownMenuPrimitive.RadioGroup, { "data-slot": "dropdown-menu-radio-group", ...props }));
|
|
34
|
+
}
|
|
35
|
+
function DropdownMenuRadioItem({ className, children, ...props }) {
|
|
36
|
+
return (_jsxs(DropdownMenuPrimitive.RadioItem, { "data-slot": "dropdown-menu-radio-item", className: cn(menuItemClassName, "pl-9", className), ...props, children: [_jsx("span", { className: "pointer-events-none absolute left-3 flex size-3.5 items-center justify-center", children: _jsx(DropdownMenuPrimitive.ItemIndicator, { children: _jsx("span", { className: "block size-1.5 rounded-full bg-current" }) }) }), children] }));
|
|
37
|
+
}
|
|
38
|
+
function DropdownMenuLabel({ className, inset, ...props }) {
|
|
39
|
+
return (_jsx(DropdownMenuPrimitive.Label, { "data-slot": "dropdown-menu-label", "data-inset": inset || undefined, className: cn("px-3 py-2 text-xs font-semibold tracking-wider text-muted-foreground uppercase data-inset:pl-9", className), ...props }));
|
|
40
|
+
}
|
|
41
|
+
function DropdownMenuSeparator({ className, ...props }) {
|
|
42
|
+
return (_jsx(DropdownMenuPrimitive.Separator, { "data-slot": "dropdown-menu-separator", className: cn("-mx-1 my-1 h-px bg-border", className), ...props }));
|
|
43
|
+
}
|
|
44
|
+
function DropdownMenuShortcut({ className, ...props }) {
|
|
45
|
+
return (_jsx("span", { "data-slot": "dropdown-menu-shortcut", className: cn("ml-auto text-xs tracking-widest text-muted-foreground", className), ...props }));
|
|
46
|
+
}
|
|
47
|
+
function DropdownMenuSub({ ...props }) {
|
|
48
|
+
return _jsx(DropdownMenuPrimitive.Sub, { "data-slot": "dropdown-menu-sub", ...props });
|
|
49
|
+
}
|
|
50
|
+
function DropdownMenuSubTrigger({ className, inset, children, ...props }) {
|
|
51
|
+
return (_jsxs(DropdownMenuPrimitive.SubTrigger, { "data-slot": "dropdown-menu-sub-trigger", "data-inset": inset || undefined, className: cn(menuItemClassName, "data-open:bg-accent data-open:text-accent-foreground", className), ...props, children: [children, _jsx(ChevronRightIcon, { className: "ml-auto" })] }));
|
|
52
|
+
}
|
|
53
|
+
function DropdownMenuSubContent({ className, ...props }) {
|
|
54
|
+
return (_jsx(DropdownMenuPrimitive.SubContent, { "data-slot": "dropdown-menu-sub-content", className: cn(menuContentClassName, "origin-(--radix-dropdown-menu-content-transform-origin)", className), ...props }));
|
|
55
|
+
}
|
|
56
|
+
export { DropdownMenu, DropdownMenuCheckboxItem, DropdownMenuContent, DropdownMenuGroup, DropdownMenuItem, DropdownMenuLabel, DropdownMenuPortal, DropdownMenuRadioGroup, DropdownMenuRadioItem, DropdownMenuSeparator, DropdownMenuShortcut, DropdownMenuSub, DropdownMenuSubContent, DropdownMenuSubTrigger, DropdownMenuTrigger, };
|
package/dist/error-boundary.d.ts
CHANGED
|
@@ -29,6 +29,6 @@ export declare class ErrorBoundary extends Component<ErrorBoundaryProps, ErrorBo
|
|
|
29
29
|
componentDidCatch(error: Error, info: ErrorInfo): void;
|
|
30
30
|
retry: () => void;
|
|
31
31
|
reload: () => void;
|
|
32
|
-
render(): string | number | bigint | boolean |
|
|
32
|
+
render(): string | number | bigint | boolean | Iterable<ReactNode> | Promise<string | number | bigint | boolean | import("react").ReactPortal | import("react").ReactElement<unknown, string | import("react").JSXElementConstructor<any>> | Iterable<ReactNode> | null | undefined> | import("react").JSX.Element | null | undefined;
|
|
33
33
|
}
|
|
34
34
|
export {};
|
package/dist/field.js
CHANGED
|
@@ -39,7 +39,7 @@ function FieldTitle({ className, ...props }) {
|
|
|
39
39
|
return (_jsx("div", { "data-slot": "field-label", className: cn("flex w-fit items-center gap-2 text-xs font-semibold uppercase group-data-[disabled=true]/field:opacity-50 in-data-[slot=field-label]:font-semibold", className), ...props }));
|
|
40
40
|
}
|
|
41
41
|
function FieldDescription({ className, ...props }) {
|
|
42
|
-
return (_jsx("p", { "data-slot": "field-description", className: cn("text-left text-sm leading-normal font-normal tracking-normal text-muted-foreground normal-case group-has-data-horizontal/field:text-balance [[data-variant=legend]+&]:-mt-1.5", "last:mt-0 nth-last-2:-mt-1", "[&>a]:underline [&>a]:underline-offset-4 [&>a:hover]:text-
|
|
42
|
+
return (_jsx("p", { "data-slot": "field-description", className: cn("text-left text-sm leading-normal font-normal tracking-normal text-muted-foreground normal-case group-has-data-horizontal/field:text-balance [[data-variant=legend]+&]:-mt-1.5", "last:mt-0 nth-last-2:-mt-1", "[&>a]:underline [&>a]:underline-offset-4 [&>a:hover]:text-selected-foreground", className), ...props }));
|
|
43
43
|
}
|
|
44
44
|
function FieldSeparator({ children, className, ...props }) {
|
|
45
45
|
return (_jsxs("div", { "data-slot": "field-separator", "data-content": !!children, className: cn("relative -my-2 h-5 text-sm group-data-[variant=outline]/field-group:-mb-2", className), ...props, children: [_jsx(Separator, { className: "absolute inset-0 top-1/2" }), children && (_jsx("span", { className: "relative mx-auto block w-fit bg-background px-2 text-muted-foreground", "data-slot": "field-separator-content", children: children }))] }));
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { type FieldMetaState } from "./field-error.js";
|
|
2
|
+
type Props = {
|
|
3
|
+
value: Date | null;
|
|
4
|
+
onValueChange: (date: Date | null) => void;
|
|
5
|
+
label: string;
|
|
6
|
+
meta?: FieldMetaState;
|
|
7
|
+
placeholder?: string;
|
|
8
|
+
disabled?: boolean;
|
|
9
|
+
/** Minute increment forwarded to the picker. */
|
|
10
|
+
timeStep?: number;
|
|
11
|
+
/** Forwarded to the date-time picker trigger. */
|
|
12
|
+
className?: string;
|
|
13
|
+
};
|
|
14
|
+
/** Date-time picker with built-in field error text and invalid styling. */
|
|
15
|
+
export declare function FormDateTimePickerField({ value, onValueChange, label, meta, placeholder, disabled, timeStep, className, }: Props): import("react").JSX.Element;
|
|
16
|
+
export {};
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
3
|
+
import { useId } from "react";
|
|
4
|
+
import { DateTimePickerButton } from "../date-time-picker.js";
|
|
5
|
+
import { Label } from "../label.js";
|
|
6
|
+
import { FieldError, getFieldErrorMessage, } from "./field-error.js";
|
|
7
|
+
/** Date-time picker with built-in field error text and invalid styling. */
|
|
8
|
+
export function FormDateTimePickerField({ value, onValueChange, label, meta, placeholder, disabled, timeStep, className, }) {
|
|
9
|
+
const errorText = meta ? getFieldErrorMessage(meta.errors[0]) : undefined;
|
|
10
|
+
const id = useId();
|
|
11
|
+
return (_jsxs("div", { className: "flex flex-col gap-1.5", children: [_jsx(Label, { htmlFor: id, children: label }), _jsx(DateTimePickerButton, { id: id, value: value, onChange: onValueChange, placeholder: placeholder, disabled: disabled, timeStep: timeStep, className: className, "aria-invalid": errorText ? true : undefined }), _jsx(FieldError, { text: errorText })] }));
|
|
12
|
+
}
|