@gerege-systems/ui 0.11.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +234 -0
- package/dist-lib/__tests__/helpers/color.d.ts +9 -0
- package/dist-lib/__tests__/helpers/theme.d.ts +18 -0
- package/dist-lib/components/ui/Accordion.d.ts +21 -0
- package/dist-lib/components/ui/Accordion.js +71 -0
- package/dist-lib/components/ui/Accordion.js.map +1 -0
- package/dist-lib/components/ui/Alert.d.ts +51 -0
- package/dist-lib/components/ui/Alert.js +79 -0
- package/dist-lib/components/ui/Alert.js.map +1 -0
- package/dist-lib/components/ui/Avatar.d.ts +52 -0
- package/dist-lib/components/ui/Avatar.js +94 -0
- package/dist-lib/components/ui/Avatar.js.map +1 -0
- package/dist-lib/components/ui/Badge.d.ts +26 -0
- package/dist-lib/components/ui/Badge.js +76 -0
- package/dist-lib/components/ui/Badge.js.map +1 -0
- package/dist-lib/components/ui/Breadcrumbs.d.ts +33 -0
- package/dist-lib/components/ui/Breadcrumbs.js +52 -0
- package/dist-lib/components/ui/Breadcrumbs.js.map +1 -0
- package/dist-lib/components/ui/Button.d.ts +52 -0
- package/dist-lib/components/ui/Button.js +131 -0
- package/dist-lib/components/ui/Button.js.map +1 -0
- package/dist-lib/components/ui/Calendar.d.ts +15 -0
- package/dist-lib/components/ui/Calendar.js +139 -0
- package/dist-lib/components/ui/Calendar.js.map +1 -0
- package/dist-lib/components/ui/Card.d.ts +39 -0
- package/dist-lib/components/ui/Card.js +97 -0
- package/dist-lib/components/ui/Card.js.map +1 -0
- package/dist-lib/components/ui/Carousel.d.ts +27 -0
- package/dist-lib/components/ui/Carousel.js +174 -0
- package/dist-lib/components/ui/Carousel.js.map +1 -0
- package/dist-lib/components/ui/Chart.d.ts +87 -0
- package/dist-lib/components/ui/Chart.js +487 -0
- package/dist-lib/components/ui/Chart.js.map +1 -0
- package/dist-lib/components/ui/Checkbox.d.ts +28 -0
- package/dist-lib/components/ui/Checkbox.js +70 -0
- package/dist-lib/components/ui/Checkbox.js.map +1 -0
- package/dist-lib/components/ui/Combobox.d.ts +67 -0
- package/dist-lib/components/ui/Combobox.js +195 -0
- package/dist-lib/components/ui/Combobox.js.map +1 -0
- package/dist-lib/components/ui/CommandPalette.d.ts +112 -0
- package/dist-lib/components/ui/CommandPalette.js +179 -0
- package/dist-lib/components/ui/CommandPalette.js.map +1 -0
- package/dist-lib/components/ui/ContextMenu.d.ts +50 -0
- package/dist-lib/components/ui/ContextMenu.js +165 -0
- package/dist-lib/components/ui/ContextMenu.js.map +1 -0
- package/dist-lib/components/ui/DataGrid.d.ts +79 -0
- package/dist-lib/components/ui/DataGrid.js +99 -0
- package/dist-lib/components/ui/DataGrid.js.map +1 -0
- package/dist-lib/components/ui/DatePicker.d.ts +45 -0
- package/dist-lib/components/ui/DatePicker.js +193 -0
- package/dist-lib/components/ui/DatePicker.js.map +1 -0
- package/dist-lib/components/ui/DesignSystemProvider.d.ts +147 -0
- package/dist-lib/components/ui/DesignSystemProvider.js +135 -0
- package/dist-lib/components/ui/DesignSystemProvider.js.map +1 -0
- package/dist-lib/components/ui/Dialog.d.ts +77 -0
- package/dist-lib/components/ui/Dialog.js +165 -0
- package/dist-lib/components/ui/Dialog.js.map +1 -0
- package/dist-lib/components/ui/Drawer.d.ts +44 -0
- package/dist-lib/components/ui/Drawer.js +132 -0
- package/dist-lib/components/ui/Drawer.js.map +1 -0
- package/dist-lib/components/ui/DropdownMenu.d.ts +47 -0
- package/dist-lib/components/ui/DropdownMenu.js +169 -0
- package/dist-lib/components/ui/DropdownMenu.js.map +1 -0
- package/dist-lib/components/ui/EmptyState.d.ts +48 -0
- package/dist-lib/components/ui/EmptyState.js +46 -0
- package/dist-lib/components/ui/EmptyState.js.map +1 -0
- package/dist-lib/components/ui/ErrorState.d.ts +51 -0
- package/dist-lib/components/ui/ErrorState.js +69 -0
- package/dist-lib/components/ui/ErrorState.js.map +1 -0
- package/dist-lib/components/ui/FileUpload.d.ts +26 -0
- package/dist-lib/components/ui/FileUpload.js +111 -0
- package/dist-lib/components/ui/FileUpload.js.map +1 -0
- package/dist-lib/components/ui/Form.d.ts +36 -0
- package/dist-lib/components/ui/Form.js +131 -0
- package/dist-lib/components/ui/Form.js.map +1 -0
- package/dist-lib/components/ui/Icon.d.ts +34 -0
- package/dist-lib/components/ui/Icon.js +32 -0
- package/dist-lib/components/ui/Icon.js.map +1 -0
- package/dist-lib/components/ui/IconButton.d.ts +34 -0
- package/dist-lib/components/ui/IconButton.js +64 -0
- package/dist-lib/components/ui/IconButton.js.map +1 -0
- package/dist-lib/components/ui/Input.d.ts +54 -0
- package/dist-lib/components/ui/Input.js +158 -0
- package/dist-lib/components/ui/Input.js.map +1 -0
- package/dist-lib/components/ui/Kbd.d.ts +16 -0
- package/dist-lib/components/ui/Kbd.js +24 -0
- package/dist-lib/components/ui/Kbd.js.map +1 -0
- package/dist-lib/components/ui/MultiSelect.d.ts +64 -0
- package/dist-lib/components/ui/MultiSelect.js +210 -0
- package/dist-lib/components/ui/MultiSelect.js.map +1 -0
- package/dist-lib/components/ui/Pagination.d.ts +55 -0
- package/dist-lib/components/ui/Pagination.js +153 -0
- package/dist-lib/components/ui/Pagination.js.map +1 -0
- package/dist-lib/components/ui/Popover.d.ts +16 -0
- package/dist-lib/components/ui/Popover.js +35 -0
- package/dist-lib/components/ui/Popover.js.map +1 -0
- package/dist-lib/components/ui/Progress.d.ts +40 -0
- package/dist-lib/components/ui/Progress.js +100 -0
- package/dist-lib/components/ui/Progress.js.map +1 -0
- package/dist-lib/components/ui/RadioGroup.d.ts +27 -0
- package/dist-lib/components/ui/RadioGroup.js +81 -0
- package/dist-lib/components/ui/RadioGroup.js.map +1 -0
- package/dist-lib/components/ui/RelativeTime.d.ts +19 -0
- package/dist-lib/components/ui/RelativeTime.js +31 -0
- package/dist-lib/components/ui/RelativeTime.js.map +1 -0
- package/dist-lib/components/ui/ScrollArea.d.ts +21 -0
- package/dist-lib/components/ui/ScrollArea.js +60 -0
- package/dist-lib/components/ui/ScrollArea.js.map +1 -0
- package/dist-lib/components/ui/Select.d.ts +61 -0
- package/dist-lib/components/ui/Select.js +139 -0
- package/dist-lib/components/ui/Select.js.map +1 -0
- package/dist-lib/components/ui/Separator.d.ts +13 -0
- package/dist-lib/components/ui/Separator.js +26 -0
- package/dist-lib/components/ui/Separator.js.map +1 -0
- package/dist-lib/components/ui/Sheet.d.ts +55 -0
- package/dist-lib/components/ui/Sheet.js +136 -0
- package/dist-lib/components/ui/Sheet.js.map +1 -0
- package/dist-lib/components/ui/Sidebar.d.ts +91 -0
- package/dist-lib/components/ui/Sidebar.js +212 -0
- package/dist-lib/components/ui/Sidebar.js.map +1 -0
- package/dist-lib/components/ui/Skeleton.d.ts +37 -0
- package/dist-lib/components/ui/Skeleton.js +29 -0
- package/dist-lib/components/ui/Skeleton.js.map +1 -0
- package/dist-lib/components/ui/Slider.d.ts +33 -0
- package/dist-lib/components/ui/Slider.js +64 -0
- package/dist-lib/components/ui/Slider.js.map +1 -0
- package/dist-lib/components/ui/Snackbar.d.ts +21 -0
- package/dist-lib/components/ui/Snackbar.js +57 -0
- package/dist-lib/components/ui/Snackbar.js.map +1 -0
- package/dist-lib/components/ui/Spinner.d.ts +23 -0
- package/dist-lib/components/ui/Spinner.js +54 -0
- package/dist-lib/components/ui/Spinner.js.map +1 -0
- package/dist-lib/components/ui/Stepper.d.ts +40 -0
- package/dist-lib/components/ui/Stepper.js +111 -0
- package/dist-lib/components/ui/Stepper.js.map +1 -0
- package/dist-lib/components/ui/Switch.d.ts +33 -0
- package/dist-lib/components/ui/Switch.js +80 -0
- package/dist-lib/components/ui/Switch.js.map +1 -0
- package/dist-lib/components/ui/Table.d.ts +71 -0
- package/dist-lib/components/ui/Table.js +179 -0
- package/dist-lib/components/ui/Table.js.map +1 -0
- package/dist-lib/components/ui/Tabs.d.ts +32 -0
- package/dist-lib/components/ui/Tabs.js +91 -0
- package/dist-lib/components/ui/Tabs.js.map +1 -0
- package/dist-lib/components/ui/TagInput.d.ts +39 -0
- package/dist-lib/components/ui/TagInput.js +111 -0
- package/dist-lib/components/ui/TagInput.js.map +1 -0
- package/dist-lib/components/ui/Textarea.d.ts +34 -0
- package/dist-lib/components/ui/Textarea.js +88 -0
- package/dist-lib/components/ui/Textarea.js.map +1 -0
- package/dist-lib/components/ui/Timeline.d.ts +33 -0
- package/dist-lib/components/ui/Timeline.js +56 -0
- package/dist-lib/components/ui/Timeline.js.map +1 -0
- package/dist-lib/components/ui/Toast.d.ts +53 -0
- package/dist-lib/components/ui/Toast.js +158 -0
- package/dist-lib/components/ui/Toast.js.map +1 -0
- package/dist-lib/components/ui/Tooltip.d.ts +38 -0
- package/dist-lib/components/ui/Tooltip.js +60 -0
- package/dist-lib/components/ui/Tooltip.js.map +1 -0
- package/dist-lib/components/ui/TopNav.d.ts +37 -0
- package/dist-lib/components/ui/TopNav.js +69 -0
- package/dist-lib/components/ui/TopNav.js.map +1 -0
- package/dist-lib/components/ui/Tree.d.ts +51 -0
- package/dist-lib/components/ui/Tree.js +170 -0
- package/dist-lib/components/ui/Tree.js.map +1 -0
- package/dist-lib/hooks/use-debounce.d.ts +19 -0
- package/dist-lib/hooks/use-debounce.js +36 -0
- package/dist-lib/hooks/use-debounce.js.map +1 -0
- package/dist-lib/hooks/use-delayed-loading.d.ts +21 -0
- package/dist-lib/hooks/use-delayed-loading.js +20 -0
- package/dist-lib/hooks/use-delayed-loading.js.map +1 -0
- package/dist-lib/hooks/use-field-ids.d.ts +30 -0
- package/dist-lib/hooks/use-field-ids.js +18 -0
- package/dist-lib/hooks/use-field-ids.js.map +1 -0
- package/dist-lib/hooks/use-media-query.d.ts +11 -0
- package/dist-lib/hooks/use-media-query.js +22 -0
- package/dist-lib/hooks/use-media-query.js.map +1 -0
- package/dist-lib/hooks/use-modifier-key.d.ts +13 -0
- package/dist-lib/hooks/use-modifier-key.js +19 -0
- package/dist-lib/hooks/use-modifier-key.js.map +1 -0
- package/dist-lib/hooks/use-strings.d.ts +5 -0
- package/dist-lib/hooks/use-strings.js +12 -0
- package/dist-lib/hooks/use-strings.js.map +1 -0
- package/dist-lib/hooks/use-toast.d.ts +48 -0
- package/dist-lib/hooks/use-toast.js +67 -0
- package/dist-lib/hooks/use-toast.js.map +1 -0
- package/dist-lib/icon.d.ts +8 -0
- package/dist-lib/icon.js +7 -0
- package/dist-lib/icon.js.map +1 -0
- package/dist-lib/icons/index.d.ts +80 -0
- package/dist-lib/icons/index.js +163 -0
- package/dist-lib/icons/index.js.map +1 -0
- package/dist-lib/illustrations/index.d.ts +10 -0
- package/dist-lib/illustrations/index.js +114 -0
- package/dist-lib/illustrations/index.js.map +1 -0
- package/dist-lib/index.d.ts +68 -0
- package/dist-lib/index.js +291 -0
- package/dist-lib/index.js.map +1 -0
- package/dist-lib/lib/cva.d.ts +6 -0
- package/dist-lib/lib/format.d.ts +65 -0
- package/dist-lib/lib/format.js +95 -0
- package/dist-lib/lib/format.js.map +1 -0
- package/dist-lib/lib/return-focus.d.ts +11 -0
- package/dist-lib/lib/return-focus.js +12 -0
- package/dist-lib/lib/return-focus.js.map +1 -0
- package/dist-lib/lib/strings.d.ts +190 -0
- package/dist-lib/lib/strings.js +141 -0
- package/dist-lib/lib/strings.js.map +1 -0
- package/dist-lib/lib/strings.mn.d.ts +3 -0
- package/dist-lib/lib/strings.mn.js +115 -0
- package/dist-lib/lib/strings.mn.js.map +1 -0
- package/dist-lib/lib/utils.d.ts +11 -0
- package/dist-lib/lib/utils.js +10 -0
- package/dist-lib/lib/utils.js.map +1 -0
- package/dist-lib/styles.css +1 -0
- package/dist-lib/theme.css +840 -0
- package/package.json +158 -0
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import { ComponentPropsWithoutRef, SVGProps } from 'react';
|
|
2
|
+
import * as ProgressPrimitive from '@radix-ui/react-progress';
|
|
3
|
+
export interface ProgressProps extends Omit<ComponentPropsWithoutRef<typeof ProgressPrimitive.Root>, 'value'> {
|
|
4
|
+
/** 0–`max` (default 100). Clamped. Omit for indeterminate. */
|
|
5
|
+
value?: number | null;
|
|
6
|
+
/** Bar height. */
|
|
7
|
+
size?: 'sm' | 'md' | 'lg';
|
|
8
|
+
/** Visual tone. Use `success`/`danger` to colour-code completion state. */
|
|
9
|
+
tone?: 'accent' | 'success' | 'warning' | 'danger';
|
|
10
|
+
}
|
|
11
|
+
/**
|
|
12
|
+
* Linear progress bar.
|
|
13
|
+
*
|
|
14
|
+
* @example
|
|
15
|
+
* <Progress value={uploadPct} aria-label="Upload progress" />
|
|
16
|
+
* <Progress aria-label="Loading" /> // indeterminate
|
|
17
|
+
*
|
|
18
|
+
* @do Always pair Progress with an `aria-label` describing what is progressing.
|
|
19
|
+
* @dont Use a Progress for an unknown-completion task — use a Spinner.
|
|
20
|
+
*/
|
|
21
|
+
export declare const Progress: import('react').ForwardRefExoticComponent<ProgressProps & import('react').RefAttributes<HTMLDivElement>>;
|
|
22
|
+
export interface ProgressCircleProps extends SVGProps<SVGSVGElement> {
|
|
23
|
+
/** 0–100. Omit for indeterminate. */
|
|
24
|
+
value?: number;
|
|
25
|
+
/** `sm` 24 / `md` 36 / `lg` 48, or an explicit pixel size. */
|
|
26
|
+
size?: 'sm' | 'md' | 'lg' | number;
|
|
27
|
+
/** Stroke thickness. */
|
|
28
|
+
thickness?: number;
|
|
29
|
+
/** Visible label for screen readers. */
|
|
30
|
+
'aria-label': string;
|
|
31
|
+
tone?: 'accent' | 'success' | 'warning' | 'danger';
|
|
32
|
+
}
|
|
33
|
+
/**
|
|
34
|
+
* Circular progress ring. Pairs with a numeric label for percentage-style
|
|
35
|
+
* indicators.
|
|
36
|
+
*
|
|
37
|
+
* @example
|
|
38
|
+
* <ProgressCircle value={72} aria-label="Storage used" />
|
|
39
|
+
*/
|
|
40
|
+
export declare const ProgressCircle: import('react').ForwardRefExoticComponent<Omit<ProgressCircleProps, "ref"> & import('react').RefAttributes<SVGSVGElement>>;
|
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { jsx as c, jsxs as N } from "react/jsx-runtime";
|
|
3
|
+
import { forwardRef as h } from "react";
|
|
4
|
+
import * as u from "@radix-ui/react-progress";
|
|
5
|
+
import { cn as m } from "../../lib/utils.js";
|
|
6
|
+
const b = { sm: "h-1", md: "h-1.5", lg: "h-2" }, v = {
|
|
7
|
+
accent: "bg-accent",
|
|
8
|
+
success: "bg-success",
|
|
9
|
+
warning: "bg-warning",
|
|
10
|
+
danger: "bg-danger"
|
|
11
|
+
}, w = h(
|
|
12
|
+
function({ className: o, value: s, max: t = 100, size: l = "md", tone: d = "accent", ...f }, g) {
|
|
13
|
+
const e = s == null || Number.isNaN(s), r = t > 0 ? t : 100, n = e ? 0 : Math.min(r, Math.max(0, s)), a = n / r * 100;
|
|
14
|
+
return /* @__PURE__ */ c(
|
|
15
|
+
u.Root,
|
|
16
|
+
{
|
|
17
|
+
ref: g,
|
|
18
|
+
value: e ? void 0 : n,
|
|
19
|
+
max: r,
|
|
20
|
+
className: m(
|
|
21
|
+
"bg-background-muted relative w-full overflow-hidden rounded-full",
|
|
22
|
+
b[l],
|
|
23
|
+
o
|
|
24
|
+
),
|
|
25
|
+
...f,
|
|
26
|
+
children: /* @__PURE__ */ c(
|
|
27
|
+
u.Indicator,
|
|
28
|
+
{
|
|
29
|
+
className: m(
|
|
30
|
+
"h-full w-full flex-1 transition-transform",
|
|
31
|
+
v[d],
|
|
32
|
+
e && "animate-progress-indeterminate origin-left"
|
|
33
|
+
),
|
|
34
|
+
"data-motion-keep": e ? "" : void 0,
|
|
35
|
+
style: e ? void 0 : { transform: `translateX(-${100 - a}%)` }
|
|
36
|
+
}
|
|
37
|
+
)
|
|
38
|
+
}
|
|
39
|
+
);
|
|
40
|
+
}
|
|
41
|
+
);
|
|
42
|
+
w.displayName = "Progress";
|
|
43
|
+
const x = { sm: 24, md: 36, lg: 48 }, y = {
|
|
44
|
+
accent: "stroke-accent",
|
|
45
|
+
success: "stroke-success",
|
|
46
|
+
warning: "stroke-warning",
|
|
47
|
+
danger: "stroke-danger"
|
|
48
|
+
}, M = h(
|
|
49
|
+
function({ value: o, size: s = "md", thickness: t = 3, className: l, tone: d = "accent", ...f }, g) {
|
|
50
|
+
const e = typeof s == "number" ? s : x[s], r = o === void 0 || Number.isNaN(o), n = r ? 0 : Math.min(100, Math.max(0, o)), a = (e - t) / 2, i = 2 * Math.PI * a, k = r ? 0 : i - n / 100 * i;
|
|
51
|
+
return /* @__PURE__ */ N(
|
|
52
|
+
"svg",
|
|
53
|
+
{
|
|
54
|
+
ref: g,
|
|
55
|
+
width: e,
|
|
56
|
+
height: e,
|
|
57
|
+
viewBox: `0 0 ${e} ${e}`,
|
|
58
|
+
role: "progressbar",
|
|
59
|
+
"aria-valuemin": 0,
|
|
60
|
+
"aria-valuemax": 100,
|
|
61
|
+
"aria-valuenow": r ? void 0 : n,
|
|
62
|
+
"data-motion-keep": r ? "" : void 0,
|
|
63
|
+
className: m("shrink-0", r && "animate-spin", l),
|
|
64
|
+
...f,
|
|
65
|
+
children: [
|
|
66
|
+
/* @__PURE__ */ c(
|
|
67
|
+
"circle",
|
|
68
|
+
{
|
|
69
|
+
cx: e / 2,
|
|
70
|
+
cy: e / 2,
|
|
71
|
+
r: a,
|
|
72
|
+
strokeWidth: t,
|
|
73
|
+
className: "stroke-background-muted fill-none"
|
|
74
|
+
}
|
|
75
|
+
),
|
|
76
|
+
/* @__PURE__ */ c(
|
|
77
|
+
"circle",
|
|
78
|
+
{
|
|
79
|
+
cx: e / 2,
|
|
80
|
+
cy: e / 2,
|
|
81
|
+
r: a,
|
|
82
|
+
strokeWidth: t,
|
|
83
|
+
strokeLinecap: "round",
|
|
84
|
+
strokeDasharray: i,
|
|
85
|
+
strokeDashoffset: r ? i * 0.7 : k,
|
|
86
|
+
className: m(y[d], "fill-none transition-[stroke-dashoffset]"),
|
|
87
|
+
transform: `rotate(-90 ${e / 2} ${e / 2})`
|
|
88
|
+
}
|
|
89
|
+
)
|
|
90
|
+
]
|
|
91
|
+
}
|
|
92
|
+
);
|
|
93
|
+
}
|
|
94
|
+
);
|
|
95
|
+
M.displayName = "ProgressCircle";
|
|
96
|
+
export {
|
|
97
|
+
w as Progress,
|
|
98
|
+
M as ProgressCircle
|
|
99
|
+
};
|
|
100
|
+
//# sourceMappingURL=Progress.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"Progress.js","sources":["../../../src/components/ui/Progress.tsx"],"sourcesContent":["'use client';\n\nimport { forwardRef, type ComponentPropsWithoutRef, type ElementRef, type SVGProps } from 'react';\nimport * as ProgressPrimitive from '@radix-ui/react-progress';\nimport { cn } from '@/lib/utils';\n\n/* -----------------------------------------------------------------------------\n * Linear — bar that fills left-to-right.\n * Circular — SVG ring. Both support determinate (value 0..100) and\n * indeterminate (`value` omitted) states.\n * --------------------------------------------------------------------------- */\n\nexport interface ProgressProps extends Omit<\n ComponentPropsWithoutRef<typeof ProgressPrimitive.Root>,\n 'value'\n> {\n /** 0–`max` (default 100). Clamped. Omit for indeterminate. */\n value?: number | null;\n /** Bar height. */\n size?: 'sm' | 'md' | 'lg';\n /** Visual tone. Use `success`/`danger` to colour-code completion state. */\n tone?: 'accent' | 'success' | 'warning' | 'danger';\n}\n\nconst heightMap = { sm: 'h-1', md: 'h-1.5', lg: 'h-2' } as const;\nconst fillTone = {\n accent: 'bg-accent',\n success: 'bg-success',\n warning: 'bg-warning',\n danger: 'bg-danger',\n} as const;\n\n/**\n * Linear progress bar.\n *\n * @example\n * <Progress value={uploadPct} aria-label=\"Upload progress\" />\n * <Progress aria-label=\"Loading\" /> // indeterminate\n *\n * @do Always pair Progress with an `aria-label` describing what is progressing.\n * @dont Use a Progress for an unknown-completion task — use a Spinner.\n */\nexport const Progress = forwardRef<ElementRef<typeof ProgressPrimitive.Root>, ProgressProps>(\n function Progress({ className, value, max = 100, size = 'md', tone = 'accent', ...props }, ref) {\n const indeterminate = value === undefined || value === null || Number.isNaN(value);\n const safeMax = max > 0 ? max : 100;\n const clamped = indeterminate ? 0 : Math.min(safeMax, Math.max(0, value as number));\n const pct = (clamped / safeMax) * 100;\n return (\n <ProgressPrimitive.Root\n ref={ref}\n value={indeterminate ? undefined : clamped}\n max={safeMax}\n className={cn(\n 'bg-background-muted relative w-full overflow-hidden rounded-full',\n heightMap[size],\n className,\n )}\n {...props}\n >\n <ProgressPrimitive.Indicator\n className={cn(\n 'h-full w-full flex-1 transition-transform',\n fillTone[tone],\n indeterminate && 'animate-progress-indeterminate origin-left',\n )}\n data-motion-keep={indeterminate ? '' : undefined}\n style={indeterminate ? undefined : { transform: `translateX(-${100 - pct}%)` }}\n />\n </ProgressPrimitive.Root>\n );\n },\n);\nProgress.displayName = 'Progress';\n\nexport interface ProgressCircleProps extends SVGProps<SVGSVGElement> {\n /** 0–100. Omit for indeterminate. */\n value?: number;\n /** `sm` 24 / `md` 36 / `lg` 48, or an explicit pixel size. */\n size?: 'sm' | 'md' | 'lg' | number;\n /** Stroke thickness. */\n thickness?: number;\n /** Visible label for screen readers. */\n 'aria-label': string;\n tone?: 'accent' | 'success' | 'warning' | 'danger';\n}\n\nconst circleSize = { sm: 24, md: 36, lg: 48 } as const;\n\nconst circleTone = {\n accent: 'stroke-accent',\n success: 'stroke-success',\n warning: 'stroke-warning',\n danger: 'stroke-danger',\n} as const;\n\n/**\n * Circular progress ring. Pairs with a numeric label for percentage-style\n * indicators.\n *\n * @example\n * <ProgressCircle value={72} aria-label=\"Storage used\" />\n */\nexport const ProgressCircle = forwardRef<SVGSVGElement, ProgressCircleProps>(\n function ProgressCircle(\n { value, size: sizeProp = 'md', thickness = 3, className, tone = 'accent', ...props },\n ref,\n ) {\n const size = typeof sizeProp === 'number' ? sizeProp : circleSize[sizeProp];\n const isIndeterminate = value === undefined || Number.isNaN(value);\n const clamped = isIndeterminate ? 0 : Math.min(100, Math.max(0, value as number));\n const radius = (size - thickness) / 2;\n const circumference = 2 * Math.PI * radius;\n const offset = isIndeterminate ? 0 : circumference - (clamped / 100) * circumference;\n\n return (\n <svg\n ref={ref}\n width={size}\n height={size}\n viewBox={`0 0 ${size} ${size}`}\n role=\"progressbar\"\n aria-valuemin={0}\n aria-valuemax={100}\n aria-valuenow={isIndeterminate ? undefined : clamped}\n data-motion-keep={isIndeterminate ? '' : undefined}\n className={cn('shrink-0', isIndeterminate && 'animate-spin', className)}\n {...props}\n >\n <circle\n cx={size / 2}\n cy={size / 2}\n r={radius}\n strokeWidth={thickness}\n className=\"stroke-background-muted fill-none\"\n />\n <circle\n cx={size / 2}\n cy={size / 2}\n r={radius}\n strokeWidth={thickness}\n strokeLinecap=\"round\"\n strokeDasharray={circumference}\n strokeDashoffset={isIndeterminate ? circumference * 0.7 : offset}\n className={cn(circleTone[tone], 'fill-none transition-[stroke-dashoffset]')}\n transform={`rotate(-90 ${size / 2} ${size / 2})`}\n />\n </svg>\n );\n },\n);\nProgressCircle.displayName = 'ProgressCircle';\n"],"names":["heightMap","fillTone","Progress","forwardRef","className","value","max","size","tone","props","ref","indeterminate","safeMax","clamped","pct","jsx","ProgressPrimitive","cn","circleSize","circleTone","ProgressCircle","sizeProp","thickness","isIndeterminate","radius","circumference","offset","jsxs"],"mappings":";;;;;AAwBA,MAAMA,IAAY,EAAE,IAAI,OAAO,IAAI,SAAS,IAAI,MAAA,GAC1CC,IAAW;AAAA,EACf,QAAQ;AAAA,EACR,SAAS;AAAA,EACT,SAAS;AAAA,EACT,QAAQ;AACV,GAYaC,IAAWC;AAAA,EACtB,SAAkB,EAAE,WAAAC,GAAW,OAAAC,GAAO,KAAAC,IAAM,KAAK,MAAAC,IAAO,MAAM,MAAAC,IAAO,UAAU,GAAGC,EAAA,GAASC,GAAK;AAC9F,UAAMC,IAAuCN,KAAU,QAAQ,OAAO,MAAMA,CAAK,GAC3EO,IAAUN,IAAM,IAAIA,IAAM,KAC1BO,IAAUF,IAAgB,IAAI,KAAK,IAAIC,GAAS,KAAK,IAAI,GAAGP,CAAe,CAAC,GAC5ES,IAAOD,IAAUD,IAAW;AAClC,WACE,gBAAAG;AAAA,MAACC,EAAkB;AAAA,MAAlB;AAAA,QACC,KAAAN;AAAA,QACA,OAAOC,IAAgB,SAAYE;AAAA,QACnC,KAAKD;AAAA,QACL,WAAWK;AAAA,UACT;AAAA,UACAjB,EAAUO,CAAI;AAAA,UACdH;AAAA,QAAA;AAAA,QAED,GAAGK;AAAA,QAEJ,UAAA,gBAAAM;AAAA,UAACC,EAAkB;AAAA,UAAlB;AAAA,YACC,WAAWC;AAAA,cACT;AAAA,cACAhB,EAASO,CAAI;AAAA,cACbG,KAAiB;AAAA,YAAA;AAAA,YAEnB,oBAAkBA,IAAgB,KAAK;AAAA,YACvC,OAAOA,IAAgB,SAAY,EAAE,WAAW,eAAe,MAAMG,CAAG,KAAA;AAAA,UAAK;AAAA,QAAA;AAAA,MAC/E;AAAA,IAAA;AAAA,EAGN;AACF;AACAZ,EAAS,cAAc;AAcvB,MAAMgB,IAAa,EAAE,IAAI,IAAI,IAAI,IAAI,IAAI,GAAA,GAEnCC,IAAa;AAAA,EACjB,QAAQ;AAAA,EACR,SAAS;AAAA,EACT,SAAS;AAAA,EACT,QAAQ;AACV,GASaC,IAAiBjB;AAAA,EAC5B,SACE,EAAE,OAAAE,GAAO,MAAMgB,IAAW,MAAM,WAAAC,IAAY,GAAG,WAAAlB,GAAW,MAAAI,IAAO,UAAU,GAAGC,EAAA,GAC9EC,GACA;AACA,UAAMH,IAAO,OAAOc,KAAa,WAAWA,IAAWH,EAAWG,CAAQ,GACpEE,IAAkBlB,MAAU,UAAa,OAAO,MAAMA,CAAK,GAC3DQ,IAAUU,IAAkB,IAAI,KAAK,IAAI,KAAK,KAAK,IAAI,GAAGlB,CAAe,CAAC,GAC1EmB,KAAUjB,IAAOe,KAAa,GAC9BG,IAAgB,IAAI,KAAK,KAAKD,GAC9BE,IAASH,IAAkB,IAAIE,IAAiBZ,IAAU,MAAOY;AAEvE,WACE,gBAAAE;AAAA,MAAC;AAAA,MAAA;AAAA,QACC,KAAAjB;AAAA,QACA,OAAOH;AAAA,QACP,QAAQA;AAAA,QACR,SAAS,OAAOA,CAAI,IAAIA,CAAI;AAAA,QAC5B,MAAK;AAAA,QACL,iBAAe;AAAA,QACf,iBAAe;AAAA,QACf,iBAAegB,IAAkB,SAAYV;AAAA,QAC7C,oBAAkBU,IAAkB,KAAK;AAAA,QACzC,WAAWN,EAAG,YAAYM,KAAmB,gBAAgBnB,CAAS;AAAA,QACrE,GAAGK;AAAA,QAEJ,UAAA;AAAA,UAAA,gBAAAM;AAAA,YAAC;AAAA,YAAA;AAAA,cACC,IAAIR,IAAO;AAAA,cACX,IAAIA,IAAO;AAAA,cACX,GAAGiB;AAAA,cACH,aAAaF;AAAA,cACb,WAAU;AAAA,YAAA;AAAA,UAAA;AAAA,UAEZ,gBAAAP;AAAA,YAAC;AAAA,YAAA;AAAA,cACC,IAAIR,IAAO;AAAA,cACX,IAAIA,IAAO;AAAA,cACX,GAAGiB;AAAA,cACH,aAAaF;AAAA,cACb,eAAc;AAAA,cACd,iBAAiBG;AAAA,cACjB,kBAAkBF,IAAkBE,IAAgB,MAAMC;AAAA,cAC1D,WAAWT,EAAGE,EAAWX,CAAI,GAAG,0CAA0C;AAAA,cAC1E,WAAW,cAAcD,IAAO,CAAC,IAAIA,IAAO,CAAC;AAAA,YAAA;AAAA,UAAA;AAAA,QAC/C;AAAA,MAAA;AAAA,IAAA;AAAA,EAGN;AACF;AACAa,EAAe,cAAc;"}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import { ComponentPropsWithoutRef, ReactNode } from 'react';
|
|
2
|
+
import * as RadioGroupPrimitive from '@radix-ui/react-radio-group';
|
|
3
|
+
export interface RadioGroupProps extends ComponentPropsWithoutRef<typeof RadioGroupPrimitive.Root> {
|
|
4
|
+
/** Lay out the radios vertically (default) or horizontally. Also drives arrow-key navigation. */
|
|
5
|
+
orientation?: 'horizontal' | 'vertical';
|
|
6
|
+
}
|
|
7
|
+
export declare const RadioGroup: import('react').ForwardRefExoticComponent<RadioGroupProps & import('react').RefAttributes<HTMLDivElement>>;
|
|
8
|
+
export interface RadioItemProps extends Omit<ComponentPropsWithoutRef<typeof RadioGroupPrimitive.Item>, 'asChild'> {
|
|
9
|
+
label?: ReactNode;
|
|
10
|
+
description?: ReactNode;
|
|
11
|
+
hideLabel?: boolean;
|
|
12
|
+
}
|
|
13
|
+
/**
|
|
14
|
+
* One radio option with inline label + description.
|
|
15
|
+
*
|
|
16
|
+
* @example
|
|
17
|
+
* <RadioGroup defaultValue="weekly">
|
|
18
|
+
* <RadioItem value="daily" label="Daily" description="Every morning at 9am" />
|
|
19
|
+
* <RadioItem value="weekly" label="Weekly" description="Monday mornings" />
|
|
20
|
+
* <RadioItem value="never" label="Never" />
|
|
21
|
+
* </RadioGroup>
|
|
22
|
+
*
|
|
23
|
+
* @do Pair every RadioItem with a label — naked radios are unreachable for
|
|
24
|
+
* screen reader users.
|
|
25
|
+
* @dont Use RadioGroup for binary choices — use Switch.
|
|
26
|
+
*/
|
|
27
|
+
export declare const RadioItem: import('react').ForwardRefExoticComponent<RadioItemProps & import('react').RefAttributes<HTMLButtonElement>>;
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { jsx as e, jsxs as c } from "react/jsx-runtime";
|
|
3
|
+
import { forwardRef as f, useId as h } from "react";
|
|
4
|
+
import * as d from "@radix-ui/react-radio-group";
|
|
5
|
+
import { cn as i } from "../../lib/utils.js";
|
|
6
|
+
const y = f(
|
|
7
|
+
function({ className: a, orientation: r = "vertical", ...o }, t) {
|
|
8
|
+
return /* @__PURE__ */ e(
|
|
9
|
+
d.Root,
|
|
10
|
+
{
|
|
11
|
+
ref: t,
|
|
12
|
+
orientation: r,
|
|
13
|
+
className: i(
|
|
14
|
+
"flex gap-3",
|
|
15
|
+
r === "vertical" ? "flex-col" : "flex-row flex-wrap",
|
|
16
|
+
a
|
|
17
|
+
),
|
|
18
|
+
...o
|
|
19
|
+
}
|
|
20
|
+
);
|
|
21
|
+
}
|
|
22
|
+
);
|
|
23
|
+
y.displayName = "RadioGroup";
|
|
24
|
+
const N = f(
|
|
25
|
+
function({
|
|
26
|
+
className: a,
|
|
27
|
+
label: r,
|
|
28
|
+
description: o,
|
|
29
|
+
hideLabel: t,
|
|
30
|
+
id: m,
|
|
31
|
+
disabled: l,
|
|
32
|
+
"aria-describedby": b,
|
|
33
|
+
...p
|
|
34
|
+
}, x) {
|
|
35
|
+
const v = h(), s = m ?? v, n = o ? `${s}-desc` : void 0, g = [n, b].filter(Boolean).join(" ") || void 0;
|
|
36
|
+
return /* @__PURE__ */ c("div", { className: i("flex items-start gap-2.5", a), children: [
|
|
37
|
+
/* @__PURE__ */ e(
|
|
38
|
+
d.Item,
|
|
39
|
+
{
|
|
40
|
+
ref: x,
|
|
41
|
+
id: s,
|
|
42
|
+
disabled: l,
|
|
43
|
+
"aria-describedby": g,
|
|
44
|
+
className: i(
|
|
45
|
+
"bg-card relative mt-0.5 flex size-4 shrink-0 items-center justify-center rounded-full border",
|
|
46
|
+
// WCAG 2.5.8: 16px visual box, ≥24px hit area via an invisible inset halo.
|
|
47
|
+
'before:absolute before:-inset-1.5 before:rounded-full before:content-[""]',
|
|
48
|
+
"transition-colors duration-[var(--duration-fast)] ease-[var(--ease-out)]",
|
|
49
|
+
"focus-visible:ring-ring focus-visible:ring-offset-background outline-none focus-visible:ring-2 focus-visible:ring-offset-2",
|
|
50
|
+
"data-[state=checked]:border-accent",
|
|
51
|
+
"disabled:cursor-not-allowed disabled:opacity-50",
|
|
52
|
+
"border-border-input aria-invalid:border-danger"
|
|
53
|
+
),
|
|
54
|
+
...p,
|
|
55
|
+
children: /* @__PURE__ */ e(d.Indicator, { className: "flex items-center justify-center", children: /* @__PURE__ */ e("span", { className: "bg-accent size-2 rounded-full", "aria-hidden": !0 }) })
|
|
56
|
+
}
|
|
57
|
+
),
|
|
58
|
+
r && /* @__PURE__ */ c("div", { className: "flex flex-col gap-0.5", children: [
|
|
59
|
+
/* @__PURE__ */ e(
|
|
60
|
+
"label",
|
|
61
|
+
{
|
|
62
|
+
htmlFor: s,
|
|
63
|
+
className: i(
|
|
64
|
+
"text-foreground text-sm select-none",
|
|
65
|
+
l && "cursor-not-allowed opacity-50",
|
|
66
|
+
t && "sr-only"
|
|
67
|
+
),
|
|
68
|
+
children: r
|
|
69
|
+
}
|
|
70
|
+
),
|
|
71
|
+
o && /* @__PURE__ */ e("p", { id: n, className: "text-foreground-subtle text-xs", children: o })
|
|
72
|
+
] })
|
|
73
|
+
] });
|
|
74
|
+
}
|
|
75
|
+
);
|
|
76
|
+
N.displayName = "RadioItem";
|
|
77
|
+
export {
|
|
78
|
+
y as RadioGroup,
|
|
79
|
+
N as RadioItem
|
|
80
|
+
};
|
|
81
|
+
//# sourceMappingURL=RadioGroup.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"RadioGroup.js","sources":["../../../src/components/ui/RadioGroup.tsx"],"sourcesContent":["'use client';\n\nimport {\n forwardRef,\n useId,\n type ComponentPropsWithoutRef,\n type ElementRef,\n type ReactNode,\n} from 'react';\nimport * as RadioGroupPrimitive from '@radix-ui/react-radio-group';\nimport { cn } from '@/lib/utils';\n\nexport interface RadioGroupProps extends ComponentPropsWithoutRef<typeof RadioGroupPrimitive.Root> {\n /** Lay out the radios vertically (default) or horizontally. Also drives arrow-key navigation. */\n orientation?: 'horizontal' | 'vertical';\n}\n\nexport const RadioGroup = forwardRef<ElementRef<typeof RadioGroupPrimitive.Root>, RadioGroupProps>(\n function RadioGroup({ className, orientation = 'vertical', ...props }, ref) {\n return (\n <RadioGroupPrimitive.Root\n ref={ref}\n orientation={orientation}\n className={cn(\n 'flex gap-3',\n orientation === 'vertical' ? 'flex-col' : 'flex-row flex-wrap',\n className,\n )}\n {...props}\n />\n );\n },\n);\nRadioGroup.displayName = 'RadioGroup';\n\nexport interface RadioItemProps extends Omit<\n ComponentPropsWithoutRef<typeof RadioGroupPrimitive.Item>,\n 'asChild'\n> {\n label?: ReactNode;\n description?: ReactNode;\n hideLabel?: boolean;\n}\n\n/**\n * One radio option with inline label + description.\n *\n * @example\n * <RadioGroup defaultValue=\"weekly\">\n * <RadioItem value=\"daily\" label=\"Daily\" description=\"Every morning at 9am\" />\n * <RadioItem value=\"weekly\" label=\"Weekly\" description=\"Monday mornings\" />\n * <RadioItem value=\"never\" label=\"Never\" />\n * </RadioGroup>\n *\n * @do Pair every RadioItem with a label — naked radios are unreachable for\n * screen reader users.\n * @dont Use RadioGroup for binary choices — use Switch.\n */\nexport const RadioItem = forwardRef<ElementRef<typeof RadioGroupPrimitive.Item>, RadioItemProps>(\n function RadioItem(\n {\n className,\n label,\n description,\n hideLabel,\n id,\n disabled,\n 'aria-describedby': ariaDescribedby,\n ...props\n },\n ref,\n ) {\n const autoId = useId();\n const fieldId = id ?? autoId;\n const descId = description ? `${fieldId}-desc` : undefined;\n const describedBy = [descId, ariaDescribedby].filter(Boolean).join(' ') || undefined;\n\n return (\n <div className={cn('flex items-start gap-2.5', className)}>\n <RadioGroupPrimitive.Item\n ref={ref}\n id={fieldId}\n disabled={disabled}\n aria-describedby={describedBy}\n className={cn(\n 'bg-card relative mt-0.5 flex size-4 shrink-0 items-center justify-center rounded-full border',\n // WCAG 2.5.8: 16px visual box, ≥24px hit area via an invisible inset halo.\n 'before:absolute before:-inset-1.5 before:rounded-full before:content-[\"\"]',\n 'transition-colors duration-[var(--duration-fast)] ease-[var(--ease-out)]',\n 'focus-visible:ring-ring focus-visible:ring-offset-background outline-none focus-visible:ring-2 focus-visible:ring-offset-2',\n 'data-[state=checked]:border-accent',\n 'disabled:cursor-not-allowed disabled:opacity-50',\n 'border-border-input aria-invalid:border-danger',\n )}\n {...props}\n >\n <RadioGroupPrimitive.Indicator className=\"flex items-center justify-center\">\n <span className=\"bg-accent size-2 rounded-full\" aria-hidden />\n </RadioGroupPrimitive.Indicator>\n </RadioGroupPrimitive.Item>\n\n {label && (\n <div className=\"flex flex-col gap-0.5\">\n <label\n htmlFor={fieldId}\n className={cn(\n 'text-foreground text-sm select-none',\n disabled && 'cursor-not-allowed opacity-50',\n hideLabel && 'sr-only',\n )}\n >\n {label}\n </label>\n {description && (\n <p id={descId} className=\"text-foreground-subtle text-xs\">\n {description}\n </p>\n )}\n </div>\n )}\n </div>\n );\n },\n);\nRadioItem.displayName = 'RadioItem';\n"],"names":["RadioGroup","forwardRef","className","orientation","props","ref","jsx","RadioGroupPrimitive","cn","RadioItem","label","description","hideLabel","id","disabled","ariaDescribedby","autoId","useId","fieldId","descId","describedBy","jsxs"],"mappings":";;;;;AAiBO,MAAMA,IAAaC;AAAA,EACxB,SAAoB,EAAE,WAAAC,GAAW,aAAAC,IAAc,YAAY,GAAGC,EAAA,GAASC,GAAK;AAC1E,WACE,gBAAAC;AAAA,MAACC,EAAoB;AAAA,MAApB;AAAA,QACC,KAAAF;AAAA,QACA,aAAAF;AAAA,QACA,WAAWK;AAAA,UACT;AAAA,UACAL,MAAgB,aAAa,aAAa;AAAA,UAC1CD;AAAA,QAAA;AAAA,QAED,GAAGE;AAAA,MAAA;AAAA,IAAA;AAAA,EAGV;AACF;AACAJ,EAAW,cAAc;AAyBlB,MAAMS,IAAYR;AAAA,EACvB,SACE;AAAA,IACE,WAAAC;AAAA,IACA,OAAAQ;AAAA,IACA,aAAAC;AAAA,IACA,WAAAC;AAAA,IACA,IAAAC;AAAA,IACA,UAAAC;AAAA,IACA,oBAAoBC;AAAA,IACpB,GAAGX;AAAA,EAAA,GAELC,GACA;AACA,UAAMW,IAASC,EAAA,GACTC,IAAUL,KAAMG,GAChBG,IAASR,IAAc,GAAGO,CAAO,UAAU,QAC3CE,IAAc,CAACD,GAAQJ,CAAe,EAAE,OAAO,OAAO,EAAE,KAAK,GAAG,KAAK;AAE3E,6BACG,OAAA,EAAI,WAAWP,EAAG,4BAA4BN,CAAS,GACtD,UAAA;AAAA,MAAA,gBAAAI;AAAA,QAACC,EAAoB;AAAA,QAApB;AAAA,UACC,KAAAF;AAAA,UACA,IAAIa;AAAA,UACJ,UAAAJ;AAAA,UACA,oBAAkBM;AAAA,UAClB,WAAWZ;AAAA,YACT;AAAA;AAAA,YAEA;AAAA,YACA;AAAA,YACA;AAAA,YACA;AAAA,YACA;AAAA,YACA;AAAA,UAAA;AAAA,UAED,GAAGJ;AAAA,UAEJ,UAAA,gBAAAE,EAACC,EAAoB,WAApB,EAA8B,WAAU,oCACvC,UAAA,gBAAAD,EAAC,QAAA,EAAK,WAAU,iCAAgC,eAAW,GAAA,CAAC,EAAA,CAC9D;AAAA,QAAA;AAAA,MAAA;AAAA,MAGDI,KACC,gBAAAW,EAAC,OAAA,EAAI,WAAU,yBACb,UAAA;AAAA,QAAA,gBAAAf;AAAA,UAAC;AAAA,UAAA;AAAA,YACC,SAASY;AAAA,YACT,WAAWV;AAAA,cACT;AAAA,cACAM,KAAY;AAAA,cACZF,KAAa;AAAA,YAAA;AAAA,YAGd,UAAAF;AAAA,UAAA;AAAA,QAAA;AAAA,QAEFC,KACC,gBAAAL,EAAC,KAAA,EAAE,IAAIa,GAAQ,WAAU,kCACtB,UAAAR,EAAA,CACH;AAAA,MAAA,EAAA,CAEJ;AAAA,IAAA,GAEJ;AAAA,EAEJ;AACF;AACAF,EAAU,cAAc;"}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { TimeHTMLAttributes } from 'react';
|
|
2
|
+
import { FormatDateOptions } from '../../lib/format.js';
|
|
3
|
+
export interface RelativeTimeProps extends Omit<TimeHTMLAttributes<HTMLTimeElement>, 'dateTime'> {
|
|
4
|
+
/** The instant to describe. */
|
|
5
|
+
date: Date | number | string;
|
|
6
|
+
/** Reference "now". Default `Date.now()` at render — pass one for stable SSR/tests. */
|
|
7
|
+
now?: Date | number;
|
|
8
|
+
/** Options for the absolute `title` (tooltip). */
|
|
9
|
+
absolute?: FormatDateOptions;
|
|
10
|
+
}
|
|
11
|
+
/**
|
|
12
|
+
* `<time>` showing "5 min ago" with the absolute timestamp as `title` and a
|
|
13
|
+
* machine-readable `dateTime`. Strings come from `UiStrings.relativeTime`.
|
|
14
|
+
* Beyond 30 days it falls back to the absolute date so text never goes stale.
|
|
15
|
+
*
|
|
16
|
+
* @example
|
|
17
|
+
* <RelativeTime date={post.createdAt} />
|
|
18
|
+
*/
|
|
19
|
+
export declare const RelativeTime: import('react').ForwardRefExoticComponent<RelativeTimeProps & import('react').RefAttributes<HTMLTimeElement>>;
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { jsx as N } from "react/jsx-runtime";
|
|
3
|
+
import { forwardRef as h } from "react";
|
|
4
|
+
import { formatDate as v } from "../../lib/format.js";
|
|
5
|
+
import { formatString as a } from "../../lib/strings.js";
|
|
6
|
+
import { useStrings as M } from "../../hooks/use-strings.js";
|
|
7
|
+
import { cn as b } from "../../lib/utils.js";
|
|
8
|
+
const f = 6e4, c = 60 * f, m = 24 * c, R = h(function({ date: n, now: o, absolute: d, className: g, ...p }, T) {
|
|
9
|
+
const t = M().relativeTime, s = n instanceof Date ? n : new Date(n), D = o === void 0 ? Date.now() : o instanceof Date ? o.getTime() : o, l = s.getTime() - D, e = Math.abs(l), r = l > 0, u = v(s, d);
|
|
10
|
+
let i;
|
|
11
|
+
return e < f ? i = t.justNow : e < c ? i = a(r ? t.inMinutes : t.minutesAgo, {
|
|
12
|
+
n: Math.round(e / f)
|
|
13
|
+
}) : e < m ? i = a(r ? t.inHours : t.hoursAgo, {
|
|
14
|
+
n: Math.round(e / c)
|
|
15
|
+
}) : e < 30 * m ? i = a(r ? t.inDays : t.daysAgo, { n: Math.round(e / m) }) : i = u, /* @__PURE__ */ N(
|
|
16
|
+
"time",
|
|
17
|
+
{
|
|
18
|
+
ref: T,
|
|
19
|
+
dateTime: Number.isNaN(s.getTime()) ? void 0 : s.toISOString(),
|
|
20
|
+
title: u,
|
|
21
|
+
className: b("tabular", g),
|
|
22
|
+
...p,
|
|
23
|
+
children: i
|
|
24
|
+
}
|
|
25
|
+
);
|
|
26
|
+
});
|
|
27
|
+
R.displayName = "RelativeTime";
|
|
28
|
+
export {
|
|
29
|
+
R as RelativeTime
|
|
30
|
+
};
|
|
31
|
+
//# sourceMappingURL=RelativeTime.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"RelativeTime.js","sources":["../../../src/components/ui/RelativeTime.tsx"],"sourcesContent":["'use client';\n\nimport { forwardRef, type TimeHTMLAttributes } from 'react';\nimport { formatDate, type FormatDateOptions } from '@/lib/format';\nimport { formatString } from '@/lib/strings';\nimport { useStrings } from '@/hooks/use-strings';\nimport { cn } from '@/lib/utils';\n\nexport interface RelativeTimeProps extends Omit<TimeHTMLAttributes<HTMLTimeElement>, 'dateTime'> {\n /** The instant to describe. */\n date: Date | number | string;\n /** Reference \"now\". Default `Date.now()` at render — pass one for stable SSR/tests. */\n now?: Date | number;\n /** Options for the absolute `title` (tooltip). */\n absolute?: FormatDateOptions;\n}\n\nconst MIN = 60_000;\nconst HOUR = 60 * MIN;\nconst DAY = 24 * HOUR;\n\n/**\n * `<time>` showing \"5 min ago\" with the absolute timestamp as `title` and a\n * machine-readable `dateTime`. Strings come from `UiStrings.relativeTime`.\n * Beyond 30 days it falls back to the absolute date so text never goes stale.\n *\n * @example\n * <RelativeTime date={post.createdAt} />\n */\nexport const RelativeTime = forwardRef<HTMLTimeElement, RelativeTimeProps>(function RelativeTime(\n { date, now, absolute, className, ...props },\n ref,\n) {\n const strings = useStrings().relativeTime;\n const d = date instanceof Date ? date : new Date(date);\n const ref_ = now === undefined ? Date.now() : now instanceof Date ? now.getTime() : now;\n const diff = d.getTime() - ref_;\n const abs = Math.abs(diff);\n const future = diff > 0;\n const title = formatDate(d, absolute);\n\n let label: string;\n if (abs < MIN) label = strings.justNow;\n else if (abs < HOUR)\n label = formatString(future ? strings.inMinutes : strings.minutesAgo, {\n n: Math.round(abs / MIN),\n });\n else if (abs < DAY)\n label = formatString(future ? strings.inHours : strings.hoursAgo, {\n n: Math.round(abs / HOUR),\n });\n else if (abs < 30 * DAY)\n label = formatString(future ? strings.inDays : strings.daysAgo, { n: Math.round(abs / DAY) });\n else label = title;\n\n return (\n <time\n ref={ref}\n dateTime={Number.isNaN(d.getTime()) ? undefined : d.toISOString()}\n title={title}\n className={cn('tabular', className)}\n {...props}\n >\n {label}\n </time>\n );\n});\nRelativeTime.displayName = 'RelativeTime';\n"],"names":["MIN","HOUR","DAY","RelativeTime","forwardRef","date","now","absolute","className","props","ref","strings","useStrings","d","ref_","diff","abs","future","title","formatDate","label","formatString","jsx","cn"],"mappings":";;;;;;;AAiBA,MAAMA,IAAM,KACNC,IAAO,KAAKD,GACZE,IAAM,KAAKD,GAUJE,IAAeC,EAA+C,SACzE,EAAE,MAAAC,GAAM,KAAAC,GAAK,UAAAC,GAAU,WAAAC,GAAW,GAAGC,EAAA,GACrCC,GACA;AACA,QAAMC,IAAUC,IAAa,cACvBC,IAAIR,aAAgB,OAAOA,IAAO,IAAI,KAAKA,CAAI,GAC/CS,IAAOR,MAAQ,SAAY,KAAK,QAAQA,aAAe,OAAOA,EAAI,QAAA,IAAYA,GAC9ES,IAAOF,EAAE,QAAA,IAAYC,GACrBE,IAAM,KAAK,IAAID,CAAI,GACnBE,IAASF,IAAO,GAChBG,IAAQC,EAAWN,GAAGN,CAAQ;AAEpC,MAAIa;AACJ,SAAIJ,IAAMhB,IAAKoB,IAAQT,EAAQ,UACtBK,IAAMf,IACbmB,IAAQC,EAAaJ,IAASN,EAAQ,YAAYA,EAAQ,YAAY;AAAA,IACpE,GAAG,KAAK,MAAMK,IAAMhB,CAAG;AAAA,EAAA,CACxB,IACMgB,IAAMd,IACbkB,IAAQC,EAAaJ,IAASN,EAAQ,UAAUA,EAAQ,UAAU;AAAA,IAChE,GAAG,KAAK,MAAMK,IAAMf,CAAI;AAAA,EAAA,CACzB,IACMe,IAAM,KAAKd,IAClBkB,IAAQC,EAAaJ,IAASN,EAAQ,SAASA,EAAQ,SAAS,EAAE,GAAG,KAAK,MAAMK,IAAMd,CAAG,GAAG,IACzFkB,IAAQF,GAGX,gBAAAI;AAAA,IAAC;AAAA,IAAA;AAAA,MACC,KAAAZ;AAAA,MACA,UAAU,OAAO,MAAMG,EAAE,SAAS,IAAI,SAAYA,EAAE,YAAA;AAAA,MACpD,OAAAK;AAAA,MACA,WAAWK,EAAG,WAAWf,CAAS;AAAA,MACjC,GAAGC;AAAA,MAEH,UAAAW;AAAA,IAAA;AAAA,EAAA;AAGP,CAAC;AACDjB,EAAa,cAAc;"}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { ComponentPropsWithoutRef } from 'react';
|
|
2
|
+
import * as ScrollAreaPrimitive from '@radix-ui/react-scroll-area';
|
|
3
|
+
/**
|
|
4
|
+
* Custom scroll container with consistent styled scrollbars across OS / browsers.
|
|
5
|
+
* Use when the default OS scrollbar would visually clash (sidebars, command
|
|
6
|
+
* palettes, code panes). Falls back to native scroll inside the viewport.
|
|
7
|
+
*
|
|
8
|
+
* @example
|
|
9
|
+
* <ScrollArea className="h-64 rounded-md border border-border">
|
|
10
|
+
* <div className="p-3">…long content…</div>
|
|
11
|
+
* </ScrollArea>
|
|
12
|
+
*/
|
|
13
|
+
export interface ScrollAreaProps extends ComponentPropsWithoutRef<typeof ScrollAreaPrimitive.Root> {
|
|
14
|
+
/**
|
|
15
|
+
* Accessible name of the viewport (a focusable `group` so keyboard users
|
|
16
|
+
* can scroll it). Defaults to `strings.scrollArea.region`.
|
|
17
|
+
*/
|
|
18
|
+
viewportLabel?: string;
|
|
19
|
+
}
|
|
20
|
+
export declare const ScrollArea: import('react').ForwardRefExoticComponent<ScrollAreaProps & import('react').RefAttributes<HTMLDivElement>>;
|
|
21
|
+
export declare const ScrollBar: import('react').ForwardRefExoticComponent<Omit<ScrollAreaPrimitive.ScrollAreaScrollbarProps & import('react').RefAttributes<HTMLDivElement>, "ref"> & import('react').RefAttributes<HTMLDivElement>>;
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { jsxs as d, jsx as l } from "react/jsx-runtime";
|
|
3
|
+
import { forwardRef as s } from "react";
|
|
4
|
+
import * as o from "@radix-ui/react-scroll-area";
|
|
5
|
+
import { cn as n } from "../../lib/utils.js";
|
|
6
|
+
import { useStrings as m } from "../../hooks/use-strings.js";
|
|
7
|
+
const p = s(
|
|
8
|
+
function({ className: e, children: r, viewportLabel: a, ...i }, f) {
|
|
9
|
+
const u = m();
|
|
10
|
+
return /* @__PURE__ */ d(
|
|
11
|
+
o.Root,
|
|
12
|
+
{
|
|
13
|
+
ref: f,
|
|
14
|
+
className: n("relative overflow-hidden", e),
|
|
15
|
+
...i,
|
|
16
|
+
children: [
|
|
17
|
+
/* @__PURE__ */ l(
|
|
18
|
+
o.Viewport,
|
|
19
|
+
{
|
|
20
|
+
role: "group",
|
|
21
|
+
"aria-label": a ?? u.scrollArea.region,
|
|
22
|
+
tabIndex: 0,
|
|
23
|
+
className: n(
|
|
24
|
+
"h-full w-full rounded-[inherit]",
|
|
25
|
+
"focus-visible:ring-ring focus-visible:ring-offset-background outline-none focus-visible:ring-2 focus-visible:ring-offset-2"
|
|
26
|
+
),
|
|
27
|
+
children: r
|
|
28
|
+
}
|
|
29
|
+
),
|
|
30
|
+
/* @__PURE__ */ l(t, {}),
|
|
31
|
+
/* @__PURE__ */ l(o.Corner, {})
|
|
32
|
+
]
|
|
33
|
+
}
|
|
34
|
+
);
|
|
35
|
+
}
|
|
36
|
+
);
|
|
37
|
+
p.displayName = "ScrollArea";
|
|
38
|
+
const t = s(function({ className: e, orientation: r = "vertical", ...a }, i) {
|
|
39
|
+
return /* @__PURE__ */ l(
|
|
40
|
+
o.ScrollAreaScrollbar,
|
|
41
|
+
{
|
|
42
|
+
ref: i,
|
|
43
|
+
orientation: r,
|
|
44
|
+
className: n(
|
|
45
|
+
"flex touch-none transition-colors duration-[var(--duration-fast)] select-none",
|
|
46
|
+
r === "vertical" && "h-full w-2 border-l border-l-transparent p-px",
|
|
47
|
+
r === "horizontal" && "h-2 flex-col border-t border-t-transparent p-px",
|
|
48
|
+
e
|
|
49
|
+
),
|
|
50
|
+
...a,
|
|
51
|
+
children: /* @__PURE__ */ l(o.ScrollAreaThumb, { className: "bg-border-strong relative flex-1 rounded-full" })
|
|
52
|
+
}
|
|
53
|
+
);
|
|
54
|
+
});
|
|
55
|
+
t.displayName = "ScrollBar";
|
|
56
|
+
export {
|
|
57
|
+
p as ScrollArea,
|
|
58
|
+
t as ScrollBar
|
|
59
|
+
};
|
|
60
|
+
//# sourceMappingURL=ScrollArea.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ScrollArea.js","sources":["../../../src/components/ui/ScrollArea.tsx"],"sourcesContent":["'use client';\n\nimport { forwardRef, type ComponentPropsWithoutRef, type ElementRef } from 'react';\nimport * as ScrollAreaPrimitive from '@radix-ui/react-scroll-area';\nimport { cn } from '@/lib/utils';\nimport { useStrings } from '@/hooks/use-strings';\n\n/**\n * Custom scroll container with consistent styled scrollbars across OS / browsers.\n * Use when the default OS scrollbar would visually clash (sidebars, command\n * palettes, code panes). Falls back to native scroll inside the viewport.\n *\n * @example\n * <ScrollArea className=\"h-64 rounded-md border border-border\">\n * <div className=\"p-3\">…long content…</div>\n * </ScrollArea>\n */\nexport interface ScrollAreaProps extends ComponentPropsWithoutRef<typeof ScrollAreaPrimitive.Root> {\n /**\n * Accessible name of the viewport (a focusable `group` so keyboard users\n * can scroll it). Defaults to `strings.scrollArea.region`.\n */\n viewportLabel?: string;\n}\n\nexport const ScrollArea = forwardRef<ElementRef<typeof ScrollAreaPrimitive.Root>, ScrollAreaProps>(\n function ScrollArea({ className, children, viewportLabel, ...props }, ref) {\n const strings = useStrings();\n return (\n <ScrollAreaPrimitive.Root\n ref={ref}\n className={cn('relative overflow-hidden', className)}\n {...props}\n >\n <ScrollAreaPrimitive.Viewport\n role=\"group\"\n aria-label={viewportLabel ?? strings.scrollArea.region}\n tabIndex={0}\n className={cn(\n 'h-full w-full rounded-[inherit]',\n 'focus-visible:ring-ring focus-visible:ring-offset-background outline-none focus-visible:ring-2 focus-visible:ring-offset-2',\n )}\n >\n {children}\n </ScrollAreaPrimitive.Viewport>\n <ScrollBar />\n <ScrollAreaPrimitive.Corner />\n </ScrollAreaPrimitive.Root>\n );\n },\n);\nScrollArea.displayName = 'ScrollArea';\n\nexport const ScrollBar = forwardRef<\n ElementRef<typeof ScrollAreaPrimitive.ScrollAreaScrollbar>,\n ComponentPropsWithoutRef<typeof ScrollAreaPrimitive.ScrollAreaScrollbar>\n>(function ScrollBar({ className, orientation = 'vertical', ...props }, ref) {\n return (\n <ScrollAreaPrimitive.ScrollAreaScrollbar\n ref={ref}\n orientation={orientation}\n className={cn(\n 'flex touch-none transition-colors duration-[var(--duration-fast)] select-none',\n orientation === 'vertical' && 'h-full w-2 border-l border-l-transparent p-px',\n orientation === 'horizontal' && 'h-2 flex-col border-t border-t-transparent p-px',\n className,\n )}\n {...props}\n >\n <ScrollAreaPrimitive.ScrollAreaThumb className=\"bg-border-strong relative flex-1 rounded-full\" />\n </ScrollAreaPrimitive.ScrollAreaScrollbar>\n );\n});\nScrollBar.displayName = 'ScrollBar';\n"],"names":["ScrollArea","forwardRef","className","children","viewportLabel","props","ref","strings","useStrings","jsxs","ScrollAreaPrimitive","cn","jsx","ScrollBar","orientation"],"mappings":";;;;;;AAyBO,MAAMA,IAAaC;AAAA,EACxB,SAAoB,EAAE,WAAAC,GAAW,UAAAC,GAAU,eAAAC,GAAe,GAAGC,EAAA,GAASC,GAAK;AACzE,UAAMC,IAAUC,EAAA;AAChB,WACE,gBAAAC;AAAA,MAACC,EAAoB;AAAA,MAApB;AAAA,QACC,KAAAJ;AAAA,QACA,WAAWK,EAAG,4BAA4BT,CAAS;AAAA,QAClD,GAAGG;AAAA,QAEJ,UAAA;AAAA,UAAA,gBAAAO;AAAA,YAACF,EAAoB;AAAA,YAApB;AAAA,cACC,MAAK;AAAA,cACL,cAAYN,KAAiBG,EAAQ,WAAW;AAAA,cAChD,UAAU;AAAA,cACV,WAAWI;AAAA,gBACT;AAAA,gBACA;AAAA,cAAA;AAAA,cAGD,UAAAR;AAAA,YAAA;AAAA,UAAA;AAAA,4BAEFU,GAAA,EAAU;AAAA,UACX,gBAAAD,EAACF,EAAoB,QAApB,CAAA,CAA2B;AAAA,QAAA;AAAA,MAAA;AAAA,IAAA;AAAA,EAGlC;AACF;AACAV,EAAW,cAAc;AAElB,MAAMa,IAAYZ,EAGvB,SAAmB,EAAE,WAAAC,GAAW,aAAAY,IAAc,YAAY,GAAGT,EAAA,GAASC,GAAK;AAC3E,SACE,gBAAAM;AAAA,IAACF,EAAoB;AAAA,IAApB;AAAA,MACC,KAAAJ;AAAA,MACA,aAAAQ;AAAA,MACA,WAAWH;AAAA,QACT;AAAA,QACAG,MAAgB,cAAc;AAAA,QAC9BA,MAAgB,gBAAgB;AAAA,QAChCZ;AAAA,MAAA;AAAA,MAED,GAAGG;AAAA,MAEJ,UAAA,gBAAAO,EAACF,EAAoB,iBAApB,EAAoC,WAAU,gDAAA,CAAgD;AAAA,IAAA;AAAA,EAAA;AAGrG,CAAC;AACDG,EAAU,cAAc;"}
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
import { ComponentPropsWithoutRef, ReactNode } from 'react';
|
|
2
|
+
import * as SelectPrimitive from '@radix-ui/react-select';
|
|
3
|
+
export declare const Select: import('react').FC<SelectPrimitive.SelectProps>;
|
|
4
|
+
export declare const SelectValue: import('react').ForwardRefExoticComponent<SelectPrimitive.SelectValueProps & import('react').RefAttributes<HTMLSpanElement>>;
|
|
5
|
+
export interface SelectTriggerProps extends Omit<ComponentPropsWithoutRef<typeof SelectPrimitive.Trigger>, 'children'> {
|
|
6
|
+
/**
|
|
7
|
+
* Placeholder shown when no value is selected. Also used as the trigger's
|
|
8
|
+
* accessible name when no `aria-label` / `aria-labelledby` / `id` (external
|
|
9
|
+
* `<Label htmlFor>`) is supplied — `role="combobox"` takes no name from
|
|
10
|
+
* its content.
|
|
11
|
+
*/
|
|
12
|
+
placeholder?: string;
|
|
13
|
+
/** Trigger height — matches Input sizes. */
|
|
14
|
+
size?: 'sm' | 'md' | 'lg';
|
|
15
|
+
/** Visual tone — `error` swaps the border + ring to danger. */
|
|
16
|
+
tone?: 'default' | 'error';
|
|
17
|
+
}
|
|
18
|
+
export declare const SelectTrigger: import('react').ForwardRefExoticComponent<SelectTriggerProps & import('react').RefAttributes<HTMLButtonElement>>;
|
|
19
|
+
export declare const SelectScrollUpButton: import('react').ForwardRefExoticComponent<Omit<SelectPrimitive.SelectScrollUpButtonProps & import('react').RefAttributes<HTMLDivElement>, "ref"> & import('react').RefAttributes<HTMLDivElement>>;
|
|
20
|
+
export declare const SelectScrollDownButton: import('react').ForwardRefExoticComponent<Omit<SelectPrimitive.SelectScrollDownButtonProps & import('react').RefAttributes<HTMLDivElement>, "ref"> & import('react').RefAttributes<HTMLDivElement>>;
|
|
21
|
+
export declare const SelectContent: import('react').ForwardRefExoticComponent<Omit<SelectPrimitive.SelectContentProps & import('react').RefAttributes<HTMLDivElement>, "ref"> & import('react').RefAttributes<HTMLDivElement>>;
|
|
22
|
+
export declare const SelectLabel: import('react').ForwardRefExoticComponent<Omit<SelectPrimitive.SelectLabelProps & import('react').RefAttributes<HTMLDivElement>, "ref"> & import('react').RefAttributes<HTMLDivElement>>;
|
|
23
|
+
export interface SelectItemProps extends ComponentPropsWithoutRef<typeof SelectPrimitive.Item> {
|
|
24
|
+
/** Icon shown to the left of the label. */
|
|
25
|
+
leadingIcon?: ReactNode;
|
|
26
|
+
}
|
|
27
|
+
export declare const SelectItem: import('react').ForwardRefExoticComponent<SelectItemProps & import('react').RefAttributes<HTMLDivElement>>;
|
|
28
|
+
export declare const SelectSeparator: import('react').ForwardRefExoticComponent<Omit<SelectPrimitive.SelectSeparatorProps & import('react').RefAttributes<HTMLDivElement>, "ref"> & import('react').RefAttributes<HTMLDivElement>>;
|
|
29
|
+
/** Optional grouping with a label header. Pure composition over Radix Group + Label. */
|
|
30
|
+
export interface SelectGroupProps extends ComponentPropsWithoutRef<typeof SelectPrimitive.Group> {
|
|
31
|
+
label?: ReactNode;
|
|
32
|
+
}
|
|
33
|
+
export declare const SelectGroup: import('react').ForwardRefExoticComponent<SelectGroupProps & import('react').RefAttributes<HTMLDivElement>>;
|
|
34
|
+
/**
|
|
35
|
+
* Compose `Select` + `SelectTrigger` + `SelectContent` + `SelectItem` for a
|
|
36
|
+
* single-choice picker. Keyboard, type-ahead, and ARIA come from Radix.
|
|
37
|
+
*
|
|
38
|
+
* @example Basic
|
|
39
|
+
* <Select onValueChange={setStatus}>
|
|
40
|
+
* <SelectTrigger placeholder="Status" />
|
|
41
|
+
* <SelectContent>
|
|
42
|
+
* <SelectItem value="open">Open</SelectItem>
|
|
43
|
+
* <SelectItem value="closed">Closed</SelectItem>
|
|
44
|
+
* </SelectContent>
|
|
45
|
+
* </Select>
|
|
46
|
+
*
|
|
47
|
+
* @example Grouped
|
|
48
|
+
* <SelectContent>
|
|
49
|
+
* <SelectGroup label="People">
|
|
50
|
+
* <SelectItem value="anu">Anu</SelectItem>
|
|
51
|
+
* <SelectItem value="bat">Bat</SelectItem>
|
|
52
|
+
* </SelectGroup>
|
|
53
|
+
* <SelectSeparator />
|
|
54
|
+
* <SelectGroup label="Bots">
|
|
55
|
+
* <SelectItem value="robo">Robo</SelectItem>
|
|
56
|
+
* </SelectGroup>
|
|
57
|
+
* </SelectContent>
|
|
58
|
+
*
|
|
59
|
+
* @do Use `placeholder` on the trigger when there is no default value.
|
|
60
|
+
* @dont Use Select for more than ~12 options — switch to `Combobox`.
|
|
61
|
+
*/
|
|
@@ -0,0 +1,139 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { jsx as t, jsxs as d } from "react/jsx-runtime";
|
|
3
|
+
import { forwardRef as l } from "react";
|
|
4
|
+
import * as a from "@radix-ui/react-select";
|
|
5
|
+
import { Check as S, ChevronDown as x, ChevronUp as v, ChevronsUpDown as N } from "../../icons/index.js";
|
|
6
|
+
import { cn as c } from "../../lib/utils.js";
|
|
7
|
+
import { useStrings as y } from "../../hooks/use-strings.js";
|
|
8
|
+
const G = a.Root, L = a.Value, w = l(function({ className: r, placeholder: o, size: e = "md", tone: i = "default", ...n }, g) {
|
|
9
|
+
const b = y(), h = !!(n["aria-label"] || n["aria-labelledby"] || n.id);
|
|
10
|
+
return /* @__PURE__ */ d(
|
|
11
|
+
a.Trigger,
|
|
12
|
+
{
|
|
13
|
+
ref: g,
|
|
14
|
+
"aria-label": h ? void 0 : o ?? b.select.placeholder,
|
|
15
|
+
className: c(
|
|
16
|
+
"bg-card text-foreground inline-flex w-full items-center justify-between gap-2 rounded-md border text-lg md:text-sm",
|
|
17
|
+
"[&>span]:min-w-0 [&>span]:truncate",
|
|
18
|
+
"transition-colors duration-[var(--duration-fast)] ease-[var(--ease-out)]",
|
|
19
|
+
"outline-none",
|
|
20
|
+
"focus-visible:ring-offset-background focus-visible:ring-2 focus-visible:ring-offset-2",
|
|
21
|
+
"disabled:cursor-not-allowed disabled:opacity-50",
|
|
22
|
+
"data-[placeholder]:text-foreground-subtle",
|
|
23
|
+
e === "sm" && "h-8 px-2.5",
|
|
24
|
+
e === "md" && "h-9 px-3",
|
|
25
|
+
e === "lg" && "h-10 px-3.5",
|
|
26
|
+
i === "default" ? "border-border-input focus-visible:border-accent focus-visible:ring-ring" : "border-danger focus-visible:border-danger focus-visible:ring-danger",
|
|
27
|
+
r
|
|
28
|
+
),
|
|
29
|
+
...n,
|
|
30
|
+
children: [
|
|
31
|
+
/* @__PURE__ */ t(a.Value, { placeholder: o }),
|
|
32
|
+
/* @__PURE__ */ t(a.Icon, { asChild: !0, children: /* @__PURE__ */ t(N, { className: "text-foreground-subtle size-4 shrink-0", "aria-hidden": !0 }) })
|
|
33
|
+
]
|
|
34
|
+
}
|
|
35
|
+
);
|
|
36
|
+
});
|
|
37
|
+
w.displayName = "SelectTrigger";
|
|
38
|
+
const u = "flex h-6 cursor-default items-center justify-center text-foreground-subtle", m = l(function({ className: r, ...o }, e) {
|
|
39
|
+
return /* @__PURE__ */ t(a.ScrollUpButton, { ref: e, className: c(u, r), ...o, children: /* @__PURE__ */ t(v, { className: "size-4", "aria-hidden": !0 }) });
|
|
40
|
+
});
|
|
41
|
+
m.displayName = "SelectScrollUpButton";
|
|
42
|
+
const p = l(function({ className: r, ...o }, e) {
|
|
43
|
+
return /* @__PURE__ */ t(a.ScrollDownButton, { ref: e, className: c(u, r), ...o, children: /* @__PURE__ */ t(x, { className: "size-4", "aria-hidden": !0 }) });
|
|
44
|
+
});
|
|
45
|
+
p.displayName = "SelectScrollDownButton";
|
|
46
|
+
const B = l(function({ className: r, children: o, position: e = "popper", ...i }, n) {
|
|
47
|
+
return /* @__PURE__ */ t(a.Portal, { children: /* @__PURE__ */ d(
|
|
48
|
+
a.Content,
|
|
49
|
+
{
|
|
50
|
+
ref: n,
|
|
51
|
+
position: e,
|
|
52
|
+
className: c(
|
|
53
|
+
"z-[var(--z-popover)] max-h-96 min-w-[var(--radix-select-trigger-width)]",
|
|
54
|
+
"border-border bg-popover text-popover-foreground overflow-hidden rounded-lg border",
|
|
55
|
+
"shadow-md",
|
|
56
|
+
"data-[state=open]:animate-in data-[state=closed]:animate-out",
|
|
57
|
+
"data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0",
|
|
58
|
+
"data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95",
|
|
59
|
+
e === "popper" && "data-[side=bottom]:translate-y-1 data-[side=top]:-translate-y-1",
|
|
60
|
+
r
|
|
61
|
+
),
|
|
62
|
+
...i,
|
|
63
|
+
children: [
|
|
64
|
+
/* @__PURE__ */ t(m, {}),
|
|
65
|
+
/* @__PURE__ */ t(a.Viewport, { className: "p-1", children: o }),
|
|
66
|
+
/* @__PURE__ */ t(p, {})
|
|
67
|
+
]
|
|
68
|
+
}
|
|
69
|
+
) });
|
|
70
|
+
});
|
|
71
|
+
B.displayName = "SelectContent";
|
|
72
|
+
const f = l(function({ className: r, ...o }, e) {
|
|
73
|
+
return /* @__PURE__ */ t(
|
|
74
|
+
a.Label,
|
|
75
|
+
{
|
|
76
|
+
ref: e,
|
|
77
|
+
className: c("text-foreground-subtle px-2 py-1.5 text-xs font-medium", r),
|
|
78
|
+
...o
|
|
79
|
+
}
|
|
80
|
+
);
|
|
81
|
+
});
|
|
82
|
+
f.displayName = "SelectLabel";
|
|
83
|
+
const C = l(
|
|
84
|
+
function({ className: r, children: o, leadingIcon: e, ...i }, n) {
|
|
85
|
+
return /* @__PURE__ */ d(
|
|
86
|
+
a.Item,
|
|
87
|
+
{
|
|
88
|
+
ref: n,
|
|
89
|
+
className: c(
|
|
90
|
+
"relative flex w-full cursor-default items-center gap-2 select-none",
|
|
91
|
+
"text-foreground rounded-sm px-2 py-1.5 pr-8 text-sm outline-none",
|
|
92
|
+
"data-[highlighted]:bg-background-muted data-[highlighted]:text-foreground",
|
|
93
|
+
"data-[disabled]:pointer-events-none data-[disabled]:opacity-50",
|
|
94
|
+
r
|
|
95
|
+
),
|
|
96
|
+
...i,
|
|
97
|
+
children: [
|
|
98
|
+
e && /* @__PURE__ */ t("span", { className: "text-foreground-subtle flex items-center [&_svg]:size-4", children: e }),
|
|
99
|
+
/* @__PURE__ */ t(a.ItemText, { children: o }),
|
|
100
|
+
/* @__PURE__ */ t("span", { className: "absolute right-2 flex items-center justify-center", children: /* @__PURE__ */ t(a.ItemIndicator, { children: /* @__PURE__ */ t(S, { className: "text-accent size-4", "aria-hidden": !0 }) }) })
|
|
101
|
+
]
|
|
102
|
+
}
|
|
103
|
+
);
|
|
104
|
+
}
|
|
105
|
+
);
|
|
106
|
+
C.displayName = "SelectItem";
|
|
107
|
+
const z = l(function({ className: r, ...o }, e) {
|
|
108
|
+
return /* @__PURE__ */ t(
|
|
109
|
+
a.Separator,
|
|
110
|
+
{
|
|
111
|
+
ref: e,
|
|
112
|
+
className: c("bg-border -mx-1 my-1 h-px", r),
|
|
113
|
+
...o
|
|
114
|
+
}
|
|
115
|
+
);
|
|
116
|
+
});
|
|
117
|
+
z.displayName = "SelectSeparator";
|
|
118
|
+
const I = l(
|
|
119
|
+
function({ label: r, children: o, ...e }, i) {
|
|
120
|
+
return /* @__PURE__ */ d(a.Group, { ref: i, ...e, children: [
|
|
121
|
+
r && /* @__PURE__ */ t(f, { children: r }),
|
|
122
|
+
o
|
|
123
|
+
] });
|
|
124
|
+
}
|
|
125
|
+
);
|
|
126
|
+
I.displayName = "SelectGroup";
|
|
127
|
+
export {
|
|
128
|
+
G as Select,
|
|
129
|
+
B as SelectContent,
|
|
130
|
+
I as SelectGroup,
|
|
131
|
+
C as SelectItem,
|
|
132
|
+
f as SelectLabel,
|
|
133
|
+
p as SelectScrollDownButton,
|
|
134
|
+
m as SelectScrollUpButton,
|
|
135
|
+
z as SelectSeparator,
|
|
136
|
+
w as SelectTrigger,
|
|
137
|
+
L as SelectValue
|
|
138
|
+
};
|
|
139
|
+
//# sourceMappingURL=Select.js.map
|