@misoto22/design 0.3.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/dist/components/Accordion/Accordion.d.ts +34 -0
- package/dist/components/Accordion/Accordion.js +37 -0
- package/dist/components/Accordion/Accordion.js.map +1 -0
- package/dist/components/Alert/Alert.d.ts +32 -0
- package/dist/components/Alert/Alert.js +49 -0
- package/dist/components/Alert/Alert.js.map +1 -0
- package/dist/components/AppShell/AppShell.d.ts +38 -0
- package/dist/components/AppShell/AppShell.js +92 -0
- package/dist/components/AppShell/AppShell.js.map +1 -0
- package/dist/components/Avatar/Avatar.d.ts +29 -0
- package/dist/components/Avatar/Avatar.js +39 -0
- package/dist/components/Avatar/Avatar.js.map +1 -0
- package/dist/components/Badge/Badge.d.ts +30 -0
- package/dist/components/Badge/Badge.js +29 -0
- package/dist/components/Badge/Badge.js.map +1 -0
- package/dist/components/Breadcrumb/Breadcrumb.d.ts +31 -0
- package/dist/components/Breadcrumb/Breadcrumb.js +31 -0
- package/dist/components/Breadcrumb/Breadcrumb.js.map +1 -0
- package/dist/components/Button/Button.d.ts +70 -0
- package/dist/components/Button/Button.js +81 -0
- package/dist/components/Button/Button.js.map +1 -0
- package/dist/components/Calendar/Calendar.d.ts +28 -0
- package/dist/components/Calendar/Calendar.js +87 -0
- package/dist/components/Calendar/Calendar.js.map +1 -0
- package/dist/components/Card/Card.d.ts +49 -0
- package/dist/components/Card/Card.js +64 -0
- package/dist/components/Card/Card.js.map +1 -0
- package/dist/components/Checkbox/Checkbox.d.ts +23 -0
- package/dist/components/Checkbox/Checkbox.js +24 -0
- package/dist/components/Checkbox/Checkbox.js.map +1 -0
- package/dist/components/Collapsible/Collapsible.d.ts +31 -0
- package/dist/components/Collapsible/Collapsible.js +35 -0
- package/dist/components/Collapsible/Collapsible.js.map +1 -0
- package/dist/components/Combobox/Combobox.d.ts +63 -0
- package/dist/components/Combobox/Combobox.js +151 -0
- package/dist/components/Combobox/Combobox.js.map +1 -0
- package/dist/components/Command/Command.d.ts +98 -0
- package/dist/components/Command/Command.js +166 -0
- package/dist/components/Command/Command.js.map +1 -0
- package/dist/components/ContextMenu/ContextMenu.d.ts +38 -0
- package/dist/components/ContextMenu/ContextMenu.js +79 -0
- package/dist/components/ContextMenu/ContextMenu.js.map +1 -0
- package/dist/components/DatePicker/DatePicker.d.ts +98 -0
- package/dist/components/DatePicker/DatePicker.js +214 -0
- package/dist/components/DatePicker/DatePicker.js.map +1 -0
- package/dist/components/Dialog/Dialog.d.ts +48 -0
- package/dist/components/Dialog/Dialog.js +72 -0
- package/dist/components/Dialog/Dialog.js.map +1 -0
- package/dist/components/DropdownMenu/DropdownMenu.d.ts +49 -0
- package/dist/components/DropdownMenu/DropdownMenu.js +89 -0
- package/dist/components/DropdownMenu/DropdownMenu.js.map +1 -0
- package/dist/components/EmptyState/EmptyState.d.ts +31 -0
- package/dist/components/EmptyState/EmptyState.js +30 -0
- package/dist/components/EmptyState/EmptyState.js.map +1 -0
- package/dist/components/ErrorState/ErrorState.d.ts +34 -0
- package/dist/components/ErrorState/ErrorState.js +32 -0
- package/dist/components/ErrorState/ErrorState.js.map +1 -0
- package/dist/components/Field/Field.d.ts +44 -0
- package/dist/components/Field/Field.js +54 -0
- package/dist/components/Field/Field.js.map +1 -0
- package/dist/components/FigureBand/FigureBand.d.ts +51 -0
- package/dist/components/FigureBand/FigureBand.js +52 -0
- package/dist/components/FigureBand/FigureBand.js.map +1 -0
- package/dist/components/FloatingIconButton/FloatingIconButton.d.ts +29 -0
- package/dist/components/FloatingIconButton/FloatingIconButton.js +32 -0
- package/dist/components/FloatingIconButton/FloatingIconButton.js.map +1 -0
- package/dist/components/Input/Input.d.ts +22 -0
- package/dist/components/Input/Input.js +21 -0
- package/dist/components/Input/Input.js.map +1 -0
- package/dist/components/Kbd/Kbd.d.ts +20 -0
- package/dist/components/Kbd/Kbd.js +21 -0
- package/dist/components/Kbd/Kbd.js.map +1 -0
- package/dist/components/LinkArrow/LinkArrow.d.ts +24 -0
- package/dist/components/LinkArrow/LinkArrow.js +24 -0
- package/dist/components/LinkArrow/LinkArrow.js.map +1 -0
- package/dist/components/NativeSelect/NativeSelect.d.ts +27 -0
- package/dist/components/NativeSelect/NativeSelect.js +46 -0
- package/dist/components/NativeSelect/NativeSelect.js.map +1 -0
- package/dist/components/NavItem/NavItem.d.ts +39 -0
- package/dist/components/NavItem/NavItem.js +31 -0
- package/dist/components/NavItem/NavItem.js.map +1 -0
- package/dist/components/Pagination/Pagination.d.ts +44 -0
- package/dist/components/Pagination/Pagination.js +109 -0
- package/dist/components/Pagination/Pagination.js.map +1 -0
- package/dist/components/Popover/Popover.d.ts +39 -0
- package/dist/components/Popover/Popover.js +57 -0
- package/dist/components/Popover/Popover.js.map +1 -0
- package/dist/components/Progress/Progress.d.ts +31 -0
- package/dist/components/Progress/Progress.js +45 -0
- package/dist/components/Progress/Progress.js.map +1 -0
- package/dist/components/RadioGroup/RadioGroup.d.ts +43 -0
- package/dist/components/RadioGroup/RadioGroup.js +43 -0
- package/dist/components/RadioGroup/RadioGroup.js.map +1 -0
- package/dist/components/ScrollArea/ScrollArea.d.ts +31 -0
- package/dist/components/ScrollArea/ScrollArea.js +54 -0
- package/dist/components/ScrollArea/ScrollArea.js.map +1 -0
- package/dist/components/SearchableMenu/SearchableMenu.d.ts +59 -0
- package/dist/components/SearchableMenu/SearchableMenu.js +79 -0
- package/dist/components/SearchableMenu/SearchableMenu.js.map +1 -0
- package/dist/components/Select/Select.d.ts +71 -0
- package/dist/components/Select/Select.js +114 -0
- package/dist/components/Select/Select.js.map +1 -0
- package/dist/components/Separator/Separator.d.ts +30 -0
- package/dist/components/Separator/Separator.js +35 -0
- package/dist/components/Separator/Separator.js.map +1 -0
- package/dist/components/Sheet/Sheet.d.ts +38 -0
- package/dist/components/Sheet/Sheet.js +68 -0
- package/dist/components/Sheet/Sheet.js.map +1 -0
- package/dist/components/Skeleton/Skeleton.d.ts +63 -0
- package/dist/components/Skeleton/Skeleton.js +44 -0
- package/dist/components/Skeleton/Skeleton.js.map +1 -0
- package/dist/components/Slider/Slider.d.ts +35 -0
- package/dist/components/Slider/Slider.js +52 -0
- package/dist/components/Slider/Slider.js.map +1 -0
- package/dist/components/Spinner/Spinner.d.ts +50 -0
- package/dist/components/Spinner/Spinner.js +48 -0
- package/dist/components/Spinner/Spinner.js.map +1 -0
- package/dist/components/StatusDot/StatusDot.d.ts +29 -0
- package/dist/components/StatusDot/StatusDot.js +44 -0
- package/dist/components/StatusDot/StatusDot.js.map +1 -0
- package/dist/components/StatusPill/StatusPill.d.ts +25 -0
- package/dist/components/StatusPill/StatusPill.js +31 -0
- package/dist/components/StatusPill/StatusPill.js.map +1 -0
- package/dist/components/Switch/Switch.d.ts +23 -0
- package/dist/components/Switch/Switch.js +23 -0
- package/dist/components/Switch/Switch.js.map +1 -0
- package/dist/components/Table/Table.d.ts +96 -0
- package/dist/components/Table/Table.js +136 -0
- package/dist/components/Table/Table.js.map +1 -0
- package/dist/components/Tabs/Tabs.d.ts +35 -0
- package/dist/components/Tabs/Tabs.js +48 -0
- package/dist/components/Tabs/Tabs.js.map +1 -0
- package/dist/components/Tag/Tag.d.ts +28 -0
- package/dist/components/Tag/Tag.js +22 -0
- package/dist/components/Tag/Tag.js.map +1 -0
- package/dist/components/Textarea/Textarea.d.ts +20 -0
- package/dist/components/Textarea/Textarea.js +32 -0
- package/dist/components/Textarea/Textarea.js.map +1 -0
- package/dist/components/Toast/Toast.d.ts +24 -0
- package/dist/components/Toast/Toast.js +41 -0
- package/dist/components/Toast/Toast.js.map +1 -0
- package/dist/components/ToggleGroup/ToggleGroup.d.ts +41 -0
- package/dist/components/ToggleGroup/ToggleGroup.js +78 -0
- package/dist/components/ToggleGroup/ToggleGroup.js.map +1 -0
- package/dist/components/Tooltip/Tooltip.d.ts +43 -0
- package/dist/components/Tooltip/Tooltip.js +40 -0
- package/dist/components/Tooltip/Tooltip.js.map +1 -0
- package/dist/fonts/hanken-grotesk-300.woff2 +0 -0
- package/dist/fonts/hanken-grotesk-400.woff2 +0 -0
- package/dist/fonts/hanken-grotesk-500.woff2 +0 -0
- package/dist/fonts/hanken-grotesk-600.woff2 +0 -0
- package/dist/fonts/hanken-grotesk-700.woff2 +0 -0
- package/dist/fonts/ibm-plex-mono-400.woff2 +0 -0
- package/dist/fonts/ibm-plex-mono-500.woff2 +0 -0
- package/dist/fonts/ibm-plex-mono-600.woff2 +0 -0
- package/dist/fonts/newsreader-300.woff2 +0 -0
- package/dist/fonts/newsreader-400.woff2 +0 -0
- package/dist/fonts/newsreader-500.woff2 +0 -0
- package/dist/fonts/newsreader-600.woff2 +0 -0
- package/dist/fonts.css +96 -0
- package/dist/index.d.ts +77 -0
- package/dist/index.js +63 -0
- package/dist/index.js.map +1 -0
- package/dist/keyframes.css +212 -0
- package/dist/lib/cn.d.ts +21 -0
- package/dist/lib/cn.js +9 -0
- package/dist/lib/cn.js.map +1 -0
- package/dist/lib/control.d.ts +31 -0
- package/dist/lib/control.js +14 -0
- package/dist/lib/control.js.map +1 -0
- package/dist/lib/index.d.ts +4 -0
- package/dist/lib/index.js +11 -0
- package/dist/lib/index.js.map +1 -0
- package/dist/lib/overlay-container.d.ts +38 -0
- package/dist/lib/overlay-container.js +15 -0
- package/dist/lib/overlay-container.js.map +1 -0
- package/dist/lib/useSelectionIndicator.d.ts +29 -0
- package/dist/lib/useSelectionIndicator.js +45 -0
- package/dist/lib/useSelectionIndicator.js.map +1 -0
- package/dist/semantic.css +127 -0
- package/dist/styles.css +98 -0
- package/dist/themes.css +115 -0
- package/dist/tokens/brand.d.ts +47 -0
- package/dist/tokens/brand.js +38 -0
- package/dist/tokens/brand.js.map +1 -0
- package/dist/tokens.css +323 -0
- package/dist/tokens.d.ts +153 -0
- package/dist/tokens.js +766 -0
- package/dist/tokens.json +765 -0
- package/package.json +130 -0
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
import * as react from 'react';
|
|
2
|
+
import { ComponentProps } from 'react';
|
|
3
|
+
import { DateRange } from 'react-day-picker';
|
|
4
|
+
export { DateRange } from 'react-day-picker';
|
|
5
|
+
import { Calendar } from '../Calendar/Calendar.js';
|
|
6
|
+
|
|
7
|
+
/** A named shortcut in the rail beside the calendar. */
|
|
8
|
+
interface DatePreset<T> {
|
|
9
|
+
label: string;
|
|
10
|
+
/** Computed when clicked, not when rendered — "today" must mean today. */
|
|
11
|
+
value: () => T;
|
|
12
|
+
}
|
|
13
|
+
/**
|
|
14
|
+
* The shortcuts a range picker is asked for on nearly every screen it appears
|
|
15
|
+
* on, so they ship rather than being rebuilt per dashboard.
|
|
16
|
+
*
|
|
17
|
+
* Computed on click: a preset list built at render time freezes "today" at
|
|
18
|
+
* whenever the page loaded, which is wrong for anything left open overnight.
|
|
19
|
+
*/
|
|
20
|
+
declare const RANGE_PRESETS: DatePreset<DateRange>[];
|
|
21
|
+
/** The single-date equivalent. */
|
|
22
|
+
declare const DATE_PRESETS: DatePreset<Date>[];
|
|
23
|
+
interface DatePickerProps {
|
|
24
|
+
value?: Date;
|
|
25
|
+
defaultValue?: Date;
|
|
26
|
+
onValueChange?: (value: Date | undefined) => void;
|
|
27
|
+
/** Names the control. Required — the trigger's text is a value, not a label. */
|
|
28
|
+
label: string;
|
|
29
|
+
placeholder?: string;
|
|
30
|
+
disabled?: boolean;
|
|
31
|
+
/** Days the reader may not choose. Passed straight to the calendar. */
|
|
32
|
+
disabledDates?: ComponentProps<typeof Calendar>['disabled'];
|
|
33
|
+
/** How the chosen date is printed on the trigger. */
|
|
34
|
+
format?: (date: Date) => string;
|
|
35
|
+
/**
|
|
36
|
+
* Shortcuts shown beside the grid. Pass `true` for the built-in set, an array
|
|
37
|
+
* for your own, or leave it off for none.
|
|
38
|
+
*/
|
|
39
|
+
presets?: boolean | DatePreset<Date>[];
|
|
40
|
+
className?: string;
|
|
41
|
+
}
|
|
42
|
+
/**
|
|
43
|
+
* A date, chosen from a calendar.
|
|
44
|
+
*
|
|
45
|
+
* A trigger and a `Calendar` in a `Popover` — not a new component so much as
|
|
46
|
+
* the composition people otherwise assemble slightly differently on every
|
|
47
|
+
* screen.
|
|
48
|
+
*
|
|
49
|
+
* It is deliberately NOT a text input with a calendar attached. A typed date
|
|
50
|
+
* needs parsing, and parsing needs a format, and a format is a locale argument
|
|
51
|
+
* nobody wins. When typing genuinely matters — a birth date, a long way back —
|
|
52
|
+
* the calendar's month and year are dropdowns, which is the same journey
|
|
53
|
+
* without the ambiguity.
|
|
54
|
+
*
|
|
55
|
+
* @example
|
|
56
|
+
* <Field label="Publish on"><DatePicker label="Publish on" /></Field>
|
|
57
|
+
*/
|
|
58
|
+
declare function DatePicker({ value, defaultValue, onValueChange, label, placeholder, disabled, disabledDates, format, presets, className, }: DatePickerProps): react.JSX.Element;
|
|
59
|
+
interface DateRangePickerProps {
|
|
60
|
+
value?: DateRange;
|
|
61
|
+
defaultValue?: DateRange;
|
|
62
|
+
onValueChange?: (value: DateRange | undefined) => void;
|
|
63
|
+
label: string;
|
|
64
|
+
placeholder?: string;
|
|
65
|
+
disabled?: boolean;
|
|
66
|
+
disabledDates?: ComponentProps<typeof Calendar>['disabled'];
|
|
67
|
+
/** How many months are shown side by side. Falls back to one under `sm`. */
|
|
68
|
+
months?: number;
|
|
69
|
+
format?: (date: Date) => string;
|
|
70
|
+
/**
|
|
71
|
+
* Shortcuts shown beside the grid — Last 30 days and its neighbours. `true`
|
|
72
|
+
* for the built-in set, an array for your own.
|
|
73
|
+
*
|
|
74
|
+
* On by default here and off on the single picker, because "last 30 days" is
|
|
75
|
+
* most of what a range picker is ever asked for, while a single date is
|
|
76
|
+
* usually a specific one.
|
|
77
|
+
*/
|
|
78
|
+
presets?: boolean | DatePreset<DateRange>[];
|
|
79
|
+
className?: string;
|
|
80
|
+
}
|
|
81
|
+
/**
|
|
82
|
+
* A span of dates — a stay, a reporting period, a filter.
|
|
83
|
+
*
|
|
84
|
+
* Two months side by side, because a range that crosses a month boundary is the
|
|
85
|
+
* common case, and paging back and forth to see both ends is what makes a range
|
|
86
|
+
* picker tiring. They stack under `sm`, where two would not fit — the calendar's
|
|
87
|
+
* own `months` class already carries that, so there is nothing to override.
|
|
88
|
+
*
|
|
89
|
+
* The panel stays open until both ends are chosen: a range is not a value until
|
|
90
|
+
* it has a second date, and closing on the first one would mean re-opening to
|
|
91
|
+
* finish.
|
|
92
|
+
*
|
|
93
|
+
* @example
|
|
94
|
+
* <DateRangePicker label="Reporting period" />
|
|
95
|
+
*/
|
|
96
|
+
declare function DateRangePicker({ value, defaultValue, onValueChange, label, placeholder, disabled, disabledDates, months, format, presets, className, }: DateRangePickerProps): react.JSX.Element;
|
|
97
|
+
|
|
98
|
+
export { DATE_PRESETS, DatePicker, type DatePickerProps, type DatePreset, DateRangePicker, type DateRangePickerProps, RANGE_PRESETS, DatePicker as default };
|
|
@@ -0,0 +1,214 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { jsx, jsxs } from "react/jsx-runtime";
|
|
3
|
+
import { CalendarDays } from "lucide-react";
|
|
4
|
+
import { useRef, useState } from "react";
|
|
5
|
+
import { cn } from "../../lib/cn.js";
|
|
6
|
+
import { Calendar } from "../Calendar/Calendar.js";
|
|
7
|
+
import { Popover, PopoverContent, PopoverTrigger } from "../Popover/Popover.js";
|
|
8
|
+
const daysAgo = (n) => {
|
|
9
|
+
const to = /* @__PURE__ */ new Date();
|
|
10
|
+
const from = /* @__PURE__ */ new Date();
|
|
11
|
+
from.setDate(from.getDate() - (n - 1));
|
|
12
|
+
return { from, to };
|
|
13
|
+
};
|
|
14
|
+
const RANGE_PRESETS = [
|
|
15
|
+
{ label: "Last 7 days", value: () => daysAgo(7) },
|
|
16
|
+
{ label: "Last 30 days", value: () => daysAgo(30) },
|
|
17
|
+
{ label: "Last 90 days", value: () => daysAgo(90) },
|
|
18
|
+
{ label: "Last 12 months", value: () => daysAgo(365) },
|
|
19
|
+
{
|
|
20
|
+
label: "Month to date",
|
|
21
|
+
value: () => {
|
|
22
|
+
const to = /* @__PURE__ */ new Date();
|
|
23
|
+
return { from: new Date(to.getFullYear(), to.getMonth(), 1), to };
|
|
24
|
+
}
|
|
25
|
+
},
|
|
26
|
+
{
|
|
27
|
+
label: "Year to date",
|
|
28
|
+
value: () => {
|
|
29
|
+
const to = /* @__PURE__ */ new Date();
|
|
30
|
+
return { from: new Date(to.getFullYear(), 0, 1), to };
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
];
|
|
34
|
+
const DATE_PRESETS = [
|
|
35
|
+
{ label: "Today", value: () => /* @__PURE__ */ new Date() },
|
|
36
|
+
{
|
|
37
|
+
label: "Tomorrow",
|
|
38
|
+
value: () => {
|
|
39
|
+
const date = /* @__PURE__ */ new Date();
|
|
40
|
+
date.setDate(date.getDate() + 1);
|
|
41
|
+
return date;
|
|
42
|
+
}
|
|
43
|
+
},
|
|
44
|
+
{
|
|
45
|
+
label: "In a week",
|
|
46
|
+
value: () => {
|
|
47
|
+
const date = /* @__PURE__ */ new Date();
|
|
48
|
+
date.setDate(date.getDate() + 7);
|
|
49
|
+
return date;
|
|
50
|
+
}
|
|
51
|
+
},
|
|
52
|
+
{
|
|
53
|
+
label: "In a month",
|
|
54
|
+
value: () => {
|
|
55
|
+
const date = /* @__PURE__ */ new Date();
|
|
56
|
+
date.setMonth(date.getMonth() + 1);
|
|
57
|
+
return date;
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
];
|
|
61
|
+
function PresetRail({
|
|
62
|
+
presets,
|
|
63
|
+
onPick,
|
|
64
|
+
label
|
|
65
|
+
}) {
|
|
66
|
+
return /* @__PURE__ */ jsx(
|
|
67
|
+
"div",
|
|
68
|
+
{
|
|
69
|
+
role: "group",
|
|
70
|
+
"aria-label": label,
|
|
71
|
+
className: "flex shrink-0 flex-col gap-0.5 border-b border-(--rule) p-2 sm:border-b-0 sm:border-e max-sm:flex-row max-sm:flex-wrap",
|
|
72
|
+
children: presets.map((preset) => /* @__PURE__ */ jsx(
|
|
73
|
+
"button",
|
|
74
|
+
{
|
|
75
|
+
type: "button",
|
|
76
|
+
onClick: () => onPick(preset.value()),
|
|
77
|
+
className: "rounded-(--radius-sm) px-2.5 py-1.5 text-start text-[13px] text-(--ink-2) transition-colors duration-(--duration-fast) hover:bg-(--stone) hover:text-(--ink)",
|
|
78
|
+
children: preset.label
|
|
79
|
+
},
|
|
80
|
+
preset.label
|
|
81
|
+
))
|
|
82
|
+
}
|
|
83
|
+
);
|
|
84
|
+
}
|
|
85
|
+
const TRIGGER = "flex w-full items-center justify-between gap-2 rounded-(--radius) border border-(--rule-2) bg-(--paper) px-(--field-px) py-(--field-py) text-start text-sm transition-colors duration-(--duration-fast) hover:border-(--rule-hard) disabled:opacity-(--disabled-opacity) disabled:pointer-events-none";
|
|
86
|
+
const formatDate = (date) => new Intl.DateTimeFormat(void 0, { dateStyle: "medium" }).format(date);
|
|
87
|
+
function DatePicker({
|
|
88
|
+
value,
|
|
89
|
+
defaultValue,
|
|
90
|
+
onValueChange,
|
|
91
|
+
label,
|
|
92
|
+
placeholder = "Pick a date",
|
|
93
|
+
disabled = false,
|
|
94
|
+
disabledDates,
|
|
95
|
+
format = formatDate,
|
|
96
|
+
presets,
|
|
97
|
+
className
|
|
98
|
+
}) {
|
|
99
|
+
const rail = presets === true ? DATE_PRESETS : presets || void 0;
|
|
100
|
+
const [open, setOpen] = useState(false);
|
|
101
|
+
const [uncontrolled, setUncontrolled] = useState(defaultValue);
|
|
102
|
+
const current = value ?? uncontrolled;
|
|
103
|
+
const choose = (next) => {
|
|
104
|
+
if (value === void 0) setUncontrolled(next);
|
|
105
|
+
onValueChange?.(next);
|
|
106
|
+
if (next) setOpen(false);
|
|
107
|
+
};
|
|
108
|
+
return /* @__PURE__ */ jsxs(Popover, { open, onOpenChange: setOpen, children: [
|
|
109
|
+
/* @__PURE__ */ jsxs(
|
|
110
|
+
PopoverTrigger,
|
|
111
|
+
{
|
|
112
|
+
"aria-label": label,
|
|
113
|
+
disabled,
|
|
114
|
+
className: cn(TRIGGER, current ? "text-(--ink)" : "text-(--ink-3-aa)", className),
|
|
115
|
+
children: [
|
|
116
|
+
current ? format(current) : placeholder,
|
|
117
|
+
/* @__PURE__ */ jsx(CalendarDays, { size: 14, strokeWidth: 1.5, "aria-hidden": true, className: "shrink-0 text-(--ink-3-aa)" })
|
|
118
|
+
]
|
|
119
|
+
}
|
|
120
|
+
),
|
|
121
|
+
/* @__PURE__ */ jsx(PopoverContent, { label, align: "start", className: "w-auto overflow-hidden p-0", children: /* @__PURE__ */ jsxs("div", { className: "flex flex-col sm:flex-row", children: [
|
|
122
|
+
rail && /* @__PURE__ */ jsx(PresetRail, { presets: rail, onPick: choose, label: `${label} shortcuts` }),
|
|
123
|
+
/* @__PURE__ */ jsx(
|
|
124
|
+
Calendar,
|
|
125
|
+
{
|
|
126
|
+
mode: "single",
|
|
127
|
+
selected: current,
|
|
128
|
+
onSelect: choose,
|
|
129
|
+
disabled: disabledDates,
|
|
130
|
+
autoFocus: true
|
|
131
|
+
}
|
|
132
|
+
)
|
|
133
|
+
] }) })
|
|
134
|
+
] });
|
|
135
|
+
}
|
|
136
|
+
function DateRangePicker({
|
|
137
|
+
value,
|
|
138
|
+
defaultValue,
|
|
139
|
+
onValueChange,
|
|
140
|
+
label,
|
|
141
|
+
placeholder = "Pick a range",
|
|
142
|
+
disabled = false,
|
|
143
|
+
disabledDates,
|
|
144
|
+
months = 2,
|
|
145
|
+
format = formatDate,
|
|
146
|
+
presets = true,
|
|
147
|
+
className
|
|
148
|
+
}) {
|
|
149
|
+
const rail = presets === true ? RANGE_PRESETS : presets || void 0;
|
|
150
|
+
const [open, setOpen] = useState(false);
|
|
151
|
+
const [uncontrolled, setUncontrolled] = useState(defaultValue);
|
|
152
|
+
const current = value ?? uncontrolled;
|
|
153
|
+
const clicks = useRef(0);
|
|
154
|
+
const choose = (next) => {
|
|
155
|
+
clicks.current += 1;
|
|
156
|
+
if (value === void 0) setUncontrolled(next);
|
|
157
|
+
onValueChange?.(next);
|
|
158
|
+
if (clicks.current >= 2 && next?.from && next.to) setOpen(false);
|
|
159
|
+
};
|
|
160
|
+
const setPanel = (next) => {
|
|
161
|
+
if (next) clicks.current = 0;
|
|
162
|
+
setOpen(next);
|
|
163
|
+
};
|
|
164
|
+
const complete = current?.from && current.to && current.from.getTime() !== current.to.getTime();
|
|
165
|
+
const printed = current?.from ? complete ? `${format(current.from)} \u2013 ${format(current.to)}` : `${format(current.from)} \u2013 \u2026` : placeholder;
|
|
166
|
+
return /* @__PURE__ */ jsxs(Popover, { open, onOpenChange: setPanel, children: [
|
|
167
|
+
/* @__PURE__ */ jsxs(
|
|
168
|
+
PopoverTrigger,
|
|
169
|
+
{
|
|
170
|
+
"aria-label": label,
|
|
171
|
+
disabled,
|
|
172
|
+
className: cn(TRIGGER, current?.from ? "text-(--ink)" : "text-(--ink-3-aa)", className),
|
|
173
|
+
children: [
|
|
174
|
+
/* @__PURE__ */ jsx("span", { className: "truncate", children: printed }),
|
|
175
|
+
/* @__PURE__ */ jsx(CalendarDays, { size: 14, strokeWidth: 1.5, "aria-hidden": true, className: "shrink-0 text-(--ink-3-aa)" })
|
|
176
|
+
]
|
|
177
|
+
}
|
|
178
|
+
),
|
|
179
|
+
/* @__PURE__ */ jsx(PopoverContent, { label, align: "start", className: "w-auto overflow-hidden p-0", children: /* @__PURE__ */ jsxs("div", { className: "flex flex-col sm:flex-row", children: [
|
|
180
|
+
rail && /* @__PURE__ */ jsx(
|
|
181
|
+
PresetRail,
|
|
182
|
+
{
|
|
183
|
+
presets: rail,
|
|
184
|
+
onPick: (next) => {
|
|
185
|
+
if (value === void 0) setUncontrolled(next);
|
|
186
|
+
onValueChange?.(next);
|
|
187
|
+
setOpen(false);
|
|
188
|
+
},
|
|
189
|
+
label: `${label} shortcuts`
|
|
190
|
+
}
|
|
191
|
+
),
|
|
192
|
+
/* @__PURE__ */ jsx(
|
|
193
|
+
Calendar,
|
|
194
|
+
{
|
|
195
|
+
mode: "range",
|
|
196
|
+
selected: current,
|
|
197
|
+
onSelect: choose,
|
|
198
|
+
disabled: disabledDates,
|
|
199
|
+
numberOfMonths: months,
|
|
200
|
+
autoFocus: true
|
|
201
|
+
}
|
|
202
|
+
)
|
|
203
|
+
] }) })
|
|
204
|
+
] });
|
|
205
|
+
}
|
|
206
|
+
var DatePicker_default = DatePicker;
|
|
207
|
+
export {
|
|
208
|
+
DATE_PRESETS,
|
|
209
|
+
DatePicker,
|
|
210
|
+
DateRangePicker,
|
|
211
|
+
RANGE_PRESETS,
|
|
212
|
+
DatePicker_default as default
|
|
213
|
+
};
|
|
214
|
+
//# sourceMappingURL=DatePicker.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../../src/components/DatePicker/DatePicker.tsx"],"sourcesContent":["'use client'\n\nimport { CalendarDays } from 'lucide-react'\nimport { useRef, useState, type ComponentProps } from 'react'\nimport type { DateRange } from 'react-day-picker'\nimport { cn } from '../../lib/cn'\nimport { Calendar } from '../Calendar/Calendar'\nimport { Popover, PopoverContent, PopoverTrigger } from '../Popover/Popover'\n\nexport type { DateRange }\n\n/** A named shortcut in the rail beside the calendar. */\nexport interface DatePreset<T> {\n label: string\n /** Computed when clicked, not when rendered — \"today\" must mean today. */\n value: () => T\n}\n\n/** `n` days back from today, inclusive of today. */\nconst daysAgo = (n: number): DateRange => {\n const to = new Date()\n const from = new Date()\n from.setDate(from.getDate() - (n - 1))\n return { from, to }\n}\n\n/**\n * The shortcuts a range picker is asked for on nearly every screen it appears\n * on, so they ship rather than being rebuilt per dashboard.\n *\n * Computed on click: a preset list built at render time freezes \"today\" at\n * whenever the page loaded, which is wrong for anything left open overnight.\n */\nexport const RANGE_PRESETS: DatePreset<DateRange>[] = [\n { label: 'Last 7 days', value: () => daysAgo(7) },\n { label: 'Last 30 days', value: () => daysAgo(30) },\n { label: 'Last 90 days', value: () => daysAgo(90) },\n { label: 'Last 12 months', value: () => daysAgo(365) },\n {\n label: 'Month to date',\n value: () => {\n const to = new Date()\n return { from: new Date(to.getFullYear(), to.getMonth(), 1), to }\n },\n },\n {\n label: 'Year to date',\n value: () => {\n const to = new Date()\n return { from: new Date(to.getFullYear(), 0, 1), to }\n },\n },\n]\n\n/** The single-date equivalent. */\nexport const DATE_PRESETS: DatePreset<Date>[] = [\n { label: 'Today', value: () => new Date() },\n {\n label: 'Tomorrow',\n value: () => {\n const date = new Date()\n date.setDate(date.getDate() + 1)\n return date\n },\n },\n {\n label: 'In a week',\n value: () => {\n const date = new Date()\n date.setDate(date.getDate() + 7)\n return date\n },\n },\n {\n label: 'In a month',\n value: () => {\n const date = new Date()\n date.setMonth(date.getMonth() + 1)\n return date\n },\n },\n]\n\n/**\n * The rail of shortcuts.\n *\n * A `<nav>`-less list of plain buttons rather than a menu: they set the same\n * value the grid beside them sets, so they are part of one control and should\n * Tab in the same pass rather than opening something.\n */\nfunction PresetRail<T>({\n presets,\n onPick,\n label,\n}: {\n presets: DatePreset<T>[]\n onPick: (value: T) => void\n label: string\n}) {\n return (\n <div\n role=\"group\"\n aria-label={label}\n className=\"flex shrink-0 flex-col gap-0.5 border-b border-(--rule) p-2 sm:border-b-0 sm:border-e max-sm:flex-row max-sm:flex-wrap\"\n >\n {presets.map((preset) => (\n <button\n key={preset.label}\n type=\"button\"\n onClick={() => onPick(preset.value())}\n className=\"rounded-(--radius-sm) px-2.5 py-1.5 text-start text-[13px] text-(--ink-2) transition-colors duration-(--duration-fast) hover:bg-(--stone) hover:text-(--ink)\"\n >\n {preset.label}\n </button>\n ))}\n </div>\n )\n}\n\nconst TRIGGER =\n 'flex w-full items-center justify-between gap-2 rounded-(--radius) border border-(--rule-2) bg-(--paper) px-(--field-px) py-(--field-py) text-start text-sm transition-colors duration-(--duration-fast) hover:border-(--rule-hard) disabled:opacity-(--disabled-opacity) disabled:pointer-events-none'\n\n/**\n * The visitor's own locale, not a fixed `dd/mm/yyyy`.\n *\n * `03/04` is March the fourth in one country and the third of April in the\n * next, and there is no format that is unambiguous to everyone. `Intl` already\n * knows which one this reader expects.\n */\nconst formatDate = (date: Date) =>\n new Intl.DateTimeFormat(undefined, { dateStyle: 'medium' }).format(date)\n\nexport interface DatePickerProps {\n value?: Date\n defaultValue?: Date\n onValueChange?: (value: Date | undefined) => void\n /** Names the control. Required — the trigger's text is a value, not a label. */\n label: string\n placeholder?: string\n disabled?: boolean\n /** Days the reader may not choose. Passed straight to the calendar. */\n disabledDates?: ComponentProps<typeof Calendar>['disabled']\n /** How the chosen date is printed on the trigger. */\n format?: (date: Date) => string\n /**\n * Shortcuts shown beside the grid. Pass `true` for the built-in set, an array\n * for your own, or leave it off for none.\n */\n presets?: boolean | DatePreset<Date>[]\n className?: string\n}\n\n/**\n * A date, chosen from a calendar.\n *\n * A trigger and a `Calendar` in a `Popover` — not a new component so much as\n * the composition people otherwise assemble slightly differently on every\n * screen.\n *\n * It is deliberately NOT a text input with a calendar attached. A typed date\n * needs parsing, and parsing needs a format, and a format is a locale argument\n * nobody wins. When typing genuinely matters — a birth date, a long way back —\n * the calendar's month and year are dropdowns, which is the same journey\n * without the ambiguity.\n *\n * @example\n * <Field label=\"Publish on\"><DatePicker label=\"Publish on\" /></Field>\n */\nexport function DatePicker({\n value,\n defaultValue,\n onValueChange,\n label,\n placeholder = 'Pick a date',\n disabled = false,\n disabledDates,\n format = formatDate,\n presets,\n className,\n}: DatePickerProps) {\n const rail = presets === true ? DATE_PRESETS : presets || undefined\n const [open, setOpen] = useState(false)\n const [uncontrolled, setUncontrolled] = useState<Date | undefined>(defaultValue)\n const current = value ?? uncontrolled\n\n const choose = (next: Date | undefined) => {\n if (value === undefined) setUncontrolled(next)\n onValueChange?.(next)\n if (next) setOpen(false)\n }\n\n return (\n <Popover open={open} onOpenChange={setOpen}>\n <PopoverTrigger\n aria-label={label}\n disabled={disabled}\n className={cn(TRIGGER, current ? 'text-(--ink)' : 'text-(--ink-3-aa)', className)}\n >\n {current ? format(current) : placeholder}\n <CalendarDays size={14} strokeWidth={1.5} aria-hidden className=\"shrink-0 text-(--ink-3-aa)\" />\n </PopoverTrigger>\n <PopoverContent label={label} align=\"start\" className=\"w-auto overflow-hidden p-0\">\n <div className=\"flex flex-col sm:flex-row\">\n {rail && <PresetRail presets={rail} onPick={choose} label={`${label} shortcuts`} />}\n <Calendar\n mode=\"single\"\n selected={current}\n onSelect={choose}\n disabled={disabledDates}\n autoFocus\n />\n </div>\n </PopoverContent>\n </Popover>\n )\n}\n\nexport interface DateRangePickerProps {\n value?: DateRange\n defaultValue?: DateRange\n onValueChange?: (value: DateRange | undefined) => void\n label: string\n placeholder?: string\n disabled?: boolean\n disabledDates?: ComponentProps<typeof Calendar>['disabled']\n /** How many months are shown side by side. Falls back to one under `sm`. */\n months?: number\n format?: (date: Date) => string\n /**\n * Shortcuts shown beside the grid — Last 30 days and its neighbours. `true`\n * for the built-in set, an array for your own.\n *\n * On by default here and off on the single picker, because \"last 30 days\" is\n * most of what a range picker is ever asked for, while a single date is\n * usually a specific one.\n */\n presets?: boolean | DatePreset<DateRange>[]\n className?: string\n}\n\n/**\n * A span of dates — a stay, a reporting period, a filter.\n *\n * Two months side by side, because a range that crosses a month boundary is the\n * common case, and paging back and forth to see both ends is what makes a range\n * picker tiring. They stack under `sm`, where two would not fit — the calendar's\n * own `months` class already carries that, so there is nothing to override.\n *\n * The panel stays open until both ends are chosen: a range is not a value until\n * it has a second date, and closing on the first one would mean re-opening to\n * finish.\n *\n * @example\n * <DateRangePicker label=\"Reporting period\" />\n */\nexport function DateRangePicker({\n value,\n defaultValue,\n onValueChange,\n label,\n placeholder = 'Pick a range',\n disabled = false,\n disabledDates,\n months = 2,\n format = formatDate,\n presets = true,\n className,\n}: DateRangePickerProps) {\n const rail = presets === true ? RANGE_PRESETS : presets || undefined\n const [open, setOpen] = useState(false)\n const [uncontrolled, setUncontrolled] = useState<DateRange | undefined>(defaultValue)\n const current = value ?? uncontrolled\n\n /**\n * How many days have been clicked since the panel opened.\n *\n * Counted, rather than inferred from the range being \"complete\", because the\n * first click returns `{ from: day, to: day }` — a complete range by any\n * reading of the value. Closing on that meant every attempt at a range\n * produced a one-day one and shut the panel, which is the opposite of what a\n * range picker is for.\n */\n const clicks = useRef(0)\n\n const choose = (next: DateRange | undefined) => {\n clicks.current += 1\n if (value === undefined) setUncontrolled(next)\n onValueChange?.(next)\n if (clicks.current >= 2 && next?.from && next.to) setOpen(false)\n }\n\n const setPanel = (next: boolean) => {\n if (next) clicks.current = 0\n setOpen(next)\n }\n\n const complete = current?.from && current.to && current.from.getTime() !== current.to.getTime()\n const printed = current?.from\n ? complete\n ? `${format(current.from)} – ${format(current.to!)}`\n : `${format(current.from)} – …`\n : placeholder\n\n return (\n <Popover open={open} onOpenChange={setPanel}>\n <PopoverTrigger\n aria-label={label}\n disabled={disabled}\n className={cn(TRIGGER, current?.from ? 'text-(--ink)' : 'text-(--ink-3-aa)', className)}\n >\n <span className=\"truncate\">{printed}</span>\n <CalendarDays size={14} strokeWidth={1.5} aria-hidden className=\"shrink-0 text-(--ink-3-aa)\" />\n </PopoverTrigger>\n <PopoverContent label={label} align=\"start\" className=\"w-auto overflow-hidden p-0\">\n <div className=\"flex flex-col sm:flex-row\">\n {rail && (\n <PresetRail\n presets={rail}\n onPick={(next) => {\n // A preset is a complete range in one gesture, so the panel\n // closes — unlike a first click on the grid, which is half an\n // answer.\n if (value === undefined) setUncontrolled(next)\n onValueChange?.(next)\n setOpen(false)\n }}\n label={`${label} shortcuts`}\n />\n )}\n <Calendar\n mode=\"range\"\n selected={current}\n onSelect={choose}\n disabled={disabledDates}\n numberOfMonths={months}\n autoFocus\n />\n </div>\n </PopoverContent>\n </Popover>\n )\n}\n\nexport default DatePicker\n"],"mappings":";AA0GQ,cAuFF,YAvFE;AAxGR,SAAS,oBAAoB;AAC7B,SAAS,QAAQ,gBAAqC;AAEtD,SAAS,UAAU;AACnB,SAAS,gBAAgB;AACzB,SAAS,SAAS,gBAAgB,sBAAsB;AAYxD,MAAM,UAAU,CAAC,MAAyB;AACxC,QAAM,KAAK,oBAAI,KAAK;AACpB,QAAM,OAAO,oBAAI,KAAK;AACtB,OAAK,QAAQ,KAAK,QAAQ,KAAK,IAAI,EAAE;AACrC,SAAO,EAAE,MAAM,GAAG;AACpB;AASO,MAAM,gBAAyC;AAAA,EACpD,EAAE,OAAO,eAAe,OAAO,MAAM,QAAQ,CAAC,EAAE;AAAA,EAChD,EAAE,OAAO,gBAAgB,OAAO,MAAM,QAAQ,EAAE,EAAE;AAAA,EAClD,EAAE,OAAO,gBAAgB,OAAO,MAAM,QAAQ,EAAE,EAAE;AAAA,EAClD,EAAE,OAAO,kBAAkB,OAAO,MAAM,QAAQ,GAAG,EAAE;AAAA,EACrD;AAAA,IACE,OAAO;AAAA,IACP,OAAO,MAAM;AACX,YAAM,KAAK,oBAAI,KAAK;AACpB,aAAO,EAAE,MAAM,IAAI,KAAK,GAAG,YAAY,GAAG,GAAG,SAAS,GAAG,CAAC,GAAG,GAAG;AAAA,IAClE;AAAA,EACF;AAAA,EACA;AAAA,IACE,OAAO;AAAA,IACP,OAAO,MAAM;AACX,YAAM,KAAK,oBAAI,KAAK;AACpB,aAAO,EAAE,MAAM,IAAI,KAAK,GAAG,YAAY,GAAG,GAAG,CAAC,GAAG,GAAG;AAAA,IACtD;AAAA,EACF;AACF;AAGO,MAAM,eAAmC;AAAA,EAC9C,EAAE,OAAO,SAAS,OAAO,MAAM,oBAAI,KAAK,EAAE;AAAA,EAC1C;AAAA,IACE,OAAO;AAAA,IACP,OAAO,MAAM;AACX,YAAM,OAAO,oBAAI,KAAK;AACtB,WAAK,QAAQ,KAAK,QAAQ,IAAI,CAAC;AAC/B,aAAO;AAAA,IACT;AAAA,EACF;AAAA,EACA;AAAA,IACE,OAAO;AAAA,IACP,OAAO,MAAM;AACX,YAAM,OAAO,oBAAI,KAAK;AACtB,WAAK,QAAQ,KAAK,QAAQ,IAAI,CAAC;AAC/B,aAAO;AAAA,IACT;AAAA,EACF;AAAA,EACA;AAAA,IACE,OAAO;AAAA,IACP,OAAO,MAAM;AACX,YAAM,OAAO,oBAAI,KAAK;AACtB,WAAK,SAAS,KAAK,SAAS,IAAI,CAAC;AACjC,aAAO;AAAA,IACT;AAAA,EACF;AACF;AASA,SAAS,WAAc;AAAA,EACrB;AAAA,EACA;AAAA,EACA;AACF,GAIG;AACD,SACE;AAAA,IAAC;AAAA;AAAA,MACC,MAAK;AAAA,MACL,cAAY;AAAA,MACZ,WAAU;AAAA,MAET,kBAAQ,IAAI,CAAC,WACZ;AAAA,QAAC;AAAA;AAAA,UAEC,MAAK;AAAA,UACL,SAAS,MAAM,OAAO,OAAO,MAAM,CAAC;AAAA,UACpC,WAAU;AAAA,UAET,iBAAO;AAAA;AAAA,QALH,OAAO;AAAA,MAMd,CACD;AAAA;AAAA,EACH;AAEJ;AAEA,MAAM,UACJ;AASF,MAAM,aAAa,CAAC,SAClB,IAAI,KAAK,eAAe,QAAW,EAAE,WAAW,SAAS,CAAC,EAAE,OAAO,IAAI;AAsClE,SAAS,WAAW;AAAA,EACzB;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA,cAAc;AAAA,EACd,WAAW;AAAA,EACX;AAAA,EACA,SAAS;AAAA,EACT;AAAA,EACA;AACF,GAAoB;AAClB,QAAM,OAAO,YAAY,OAAO,eAAe,WAAW;AAC1D,QAAM,CAAC,MAAM,OAAO,IAAI,SAAS,KAAK;AACtC,QAAM,CAAC,cAAc,eAAe,IAAI,SAA2B,YAAY;AAC/E,QAAM,UAAU,SAAS;AAEzB,QAAM,SAAS,CAAC,SAA2B;AACzC,QAAI,UAAU,OAAW,iBAAgB,IAAI;AAC7C,oBAAgB,IAAI;AACpB,QAAI,KAAM,SAAQ,KAAK;AAAA,EACzB;AAEA,SACE,qBAAC,WAAQ,MAAY,cAAc,SACjC;AAAA;AAAA,MAAC;AAAA;AAAA,QACC,cAAY;AAAA,QACZ;AAAA,QACA,WAAW,GAAG,SAAS,UAAU,iBAAiB,qBAAqB,SAAS;AAAA,QAE/E;AAAA,oBAAU,OAAO,OAAO,IAAI;AAAA,UAC7B,oBAAC,gBAAa,MAAM,IAAI,aAAa,KAAK,eAAW,MAAC,WAAU,8BAA6B;AAAA;AAAA;AAAA,IAC/F;AAAA,IACA,oBAAC,kBAAe,OAAc,OAAM,SAAQ,WAAU,8BACpD,+BAAC,SAAI,WAAU,6BACZ;AAAA,cAAQ,oBAAC,cAAW,SAAS,MAAM,QAAQ,QAAQ,OAAO,GAAG,KAAK,cAAc;AAAA,MACjF;AAAA,QAAC;AAAA;AAAA,UACC,MAAK;AAAA,UACL,UAAU;AAAA,UACV,UAAU;AAAA,UACV,UAAU;AAAA,UACV,WAAS;AAAA;AAAA,MACX;AAAA,OACF,GACF;AAAA,KACF;AAEJ;AAwCO,SAAS,gBAAgB;AAAA,EAC9B;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA,cAAc;AAAA,EACd,WAAW;AAAA,EACX;AAAA,EACA,SAAS;AAAA,EACT,SAAS;AAAA,EACT,UAAU;AAAA,EACV;AACF,GAAyB;AACvB,QAAM,OAAO,YAAY,OAAO,gBAAgB,WAAW;AAC3D,QAAM,CAAC,MAAM,OAAO,IAAI,SAAS,KAAK;AACtC,QAAM,CAAC,cAAc,eAAe,IAAI,SAAgC,YAAY;AACpF,QAAM,UAAU,SAAS;AAWzB,QAAM,SAAS,OAAO,CAAC;AAEvB,QAAM,SAAS,CAAC,SAAgC;AAC9C,WAAO,WAAW;AAClB,QAAI,UAAU,OAAW,iBAAgB,IAAI;AAC7C,oBAAgB,IAAI;AACpB,QAAI,OAAO,WAAW,KAAK,MAAM,QAAQ,KAAK,GAAI,SAAQ,KAAK;AAAA,EACjE;AAEA,QAAM,WAAW,CAAC,SAAkB;AAClC,QAAI,KAAM,QAAO,UAAU;AAC3B,YAAQ,IAAI;AAAA,EACd;AAEA,QAAM,WAAW,SAAS,QAAQ,QAAQ,MAAM,QAAQ,KAAK,QAAQ,MAAM,QAAQ,GAAG,QAAQ;AAC9F,QAAM,UAAU,SAAS,OACrB,WACE,GAAG,OAAO,QAAQ,IAAI,CAAC,WAAM,OAAO,QAAQ,EAAG,CAAC,KAChD,GAAG,OAAO,QAAQ,IAAI,CAAC,mBACzB;AAEJ,SACE,qBAAC,WAAQ,MAAY,cAAc,UACjC;AAAA;AAAA,MAAC;AAAA;AAAA,QACC,cAAY;AAAA,QACZ;AAAA,QACA,WAAW,GAAG,SAAS,SAAS,OAAO,iBAAiB,qBAAqB,SAAS;AAAA,QAEtF;AAAA,8BAAC,UAAK,WAAU,YAAY,mBAAQ;AAAA,UACpC,oBAAC,gBAAa,MAAM,IAAI,aAAa,KAAK,eAAW,MAAC,WAAU,8BAA6B;AAAA;AAAA;AAAA,IAC/F;AAAA,IACA,oBAAC,kBAAe,OAAc,OAAM,SAAQ,WAAU,8BACpD,+BAAC,SAAI,WAAU,6BACZ;AAAA,cACC;AAAA,QAAC;AAAA;AAAA,UACC,SAAS;AAAA,UACT,QAAQ,CAAC,SAAS;AAIhB,gBAAI,UAAU,OAAW,iBAAgB,IAAI;AAC7C,4BAAgB,IAAI;AACpB,oBAAQ,KAAK;AAAA,UACf;AAAA,UACA,OAAO,GAAG,KAAK;AAAA;AAAA,MACjB;AAAA,MAEF;AAAA,QAAC;AAAA;AAAA,UACC,MAAK;AAAA,UACL,UAAU;AAAA,UACV,UAAU;AAAA,UACV,UAAU;AAAA,UACV,gBAAgB;AAAA,UAChB,WAAS;AAAA;AAAA,MACX;AAAA,OACF,GACF;AAAA,KACF;AAEJ;AAEA,IAAO,qBAAQ;","names":[]}
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import * as react from 'react';
|
|
2
|
+
import { ComponentProps, ReactNode } from 'react';
|
|
3
|
+
import * as DialogPrimitive from '@radix-ui/react-dialog';
|
|
4
|
+
|
|
5
|
+
/** Radix Dialog root + trigger + close, re-exported as typed passthroughs. */
|
|
6
|
+
declare const Dialog: react.FC<DialogPrimitive.DialogProps>;
|
|
7
|
+
declare const DialogTrigger: react.ForwardRefExoticComponent<DialogPrimitive.DialogTriggerProps & react.RefAttributes<HTMLButtonElement>>;
|
|
8
|
+
declare const DialogClose: react.ForwardRefExoticComponent<DialogPrimitive.DialogCloseProps & react.RefAttributes<HTMLButtonElement>>;
|
|
9
|
+
interface DialogContentProps extends Omit<ComponentProps<typeof DialogPrimitive.Content>, 'title' | 'className'> {
|
|
10
|
+
/** Heading text. When omitted, a visually-hidden title is rendered for a11y. */
|
|
11
|
+
title?: ReactNode;
|
|
12
|
+
/** Sub-heading under the title. */
|
|
13
|
+
description?: ReactNode;
|
|
14
|
+
className?: string;
|
|
15
|
+
/** Show the top-right close control (default true). */
|
|
16
|
+
showClose?: boolean;
|
|
17
|
+
/**
|
|
18
|
+
* Keeps the title for assistive tech and hides it visually.
|
|
19
|
+
*
|
|
20
|
+
* For a surface whose purpose is obvious to anyone who can see it — a command
|
|
21
|
+
* palette, a media lightbox — where a printed heading would be furniture. The
|
|
22
|
+
* title itself is never optional: Radix requires one, and a modal with no
|
|
23
|
+
* accessible name drops a screen reader into an unnamed region.
|
|
24
|
+
*/
|
|
25
|
+
hideTitle?: boolean;
|
|
26
|
+
}
|
|
27
|
+
/**
|
|
28
|
+
* A modal surface: portal → scrim → centred panel.
|
|
29
|
+
*
|
|
30
|
+
* Radix owns the focus trap, the escape key, the scroll lock and the
|
|
31
|
+
* `aria-modal` wiring — all of which a hand-rolled dialog gets subtly wrong,
|
|
32
|
+
* usually by leaving focus behind in the page underneath.
|
|
33
|
+
*
|
|
34
|
+
* Radix requires a `Dialog.Title` whether or not one is shown, so a dialog
|
|
35
|
+
* without a visible heading still renders a hidden one rather than logging a
|
|
36
|
+
* warning and shipping an unnamed modal.
|
|
37
|
+
*
|
|
38
|
+
* @example
|
|
39
|
+
* <Dialog>
|
|
40
|
+
* <DialogTrigger asChild><Button>Delete</Button></DialogTrigger>
|
|
41
|
+
* <DialogContent title="Delete file" description="This cannot be undone.">
|
|
42
|
+
* <DialogClose asChild><Button variant="secondary">Cancel</Button></DialogClose>
|
|
43
|
+
* </DialogContent>
|
|
44
|
+
* </Dialog>
|
|
45
|
+
*/
|
|
46
|
+
declare function DialogContent({ title, description, children, className, showClose, hideTitle, ...rest }: DialogContentProps): react.JSX.Element;
|
|
47
|
+
|
|
48
|
+
export { Dialog, DialogClose, DialogContent, type DialogContentProps, DialogTrigger, Dialog as default };
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { jsx, jsxs } from "react/jsx-runtime";
|
|
3
|
+
import * as DialogPrimitive from "@radix-ui/react-dialog";
|
|
4
|
+
import { X } from "lucide-react";
|
|
5
|
+
import { cn } from "../../lib/cn.js";
|
|
6
|
+
const Dialog = DialogPrimitive.Root;
|
|
7
|
+
const DialogTrigger = DialogPrimitive.Trigger;
|
|
8
|
+
const DialogClose = DialogPrimitive.Close;
|
|
9
|
+
function DialogHeader({
|
|
10
|
+
title,
|
|
11
|
+
description,
|
|
12
|
+
hidden
|
|
13
|
+
}) {
|
|
14
|
+
if (title === void 0 && description === void 0) return null;
|
|
15
|
+
return /* @__PURE__ */ jsxs("div", { className: cn("mb-4 flex flex-col gap-1 pe-8", hidden && "sr-only"), children: [
|
|
16
|
+
title !== void 0 && /* @__PURE__ */ jsx(DialogPrimitive.Title, { className: "m-0 font-heading text-[length:var(--fs-item)] font-normal text-(--ink)", children: title }),
|
|
17
|
+
description !== void 0 && /* @__PURE__ */ jsx(DialogPrimitive.Description, { className: "m-0 text-sm leading-relaxed text-(--ink-3-aa)", children: description })
|
|
18
|
+
] });
|
|
19
|
+
}
|
|
20
|
+
function DialogContent({
|
|
21
|
+
title,
|
|
22
|
+
description,
|
|
23
|
+
children,
|
|
24
|
+
className,
|
|
25
|
+
showClose = true,
|
|
26
|
+
hideTitle = false,
|
|
27
|
+
...rest
|
|
28
|
+
}) {
|
|
29
|
+
return /* @__PURE__ */ jsxs(DialogPrimitive.Portal, { children: [
|
|
30
|
+
/* @__PURE__ */ jsx(
|
|
31
|
+
DialogPrimitive.Overlay,
|
|
32
|
+
{
|
|
33
|
+
"data-m22-animated": true,
|
|
34
|
+
className: "fixed inset-0 z-(--z-overlay) bg-(--scrim) data-[state=open]:animate-[m22-fade-in_var(--duration-fast)_var(--ease)]"
|
|
35
|
+
}
|
|
36
|
+
),
|
|
37
|
+
/* @__PURE__ */ jsxs(
|
|
38
|
+
DialogPrimitive.Content,
|
|
39
|
+
{
|
|
40
|
+
"data-m22-animated": true,
|
|
41
|
+
className: cn(
|
|
42
|
+
"fixed left-1/2 top-1/2 z-(--z-modal) max-h-[85vh] w-[min(92vw,32rem)] -translate-x-1/2 -translate-y-1/2 overflow-auto rounded-(--radius-lg) border border-(--rule-2) bg-(--paper) p-6 scroll-slim",
|
|
43
|
+
"data-[state=open]:animate-[m22-panel-in_var(--duration-base)_var(--ease)]",
|
|
44
|
+
className
|
|
45
|
+
),
|
|
46
|
+
...rest,
|
|
47
|
+
children: [
|
|
48
|
+
/* @__PURE__ */ jsx(DialogHeader, { title, description, hidden: hideTitle }),
|
|
49
|
+
title === void 0 && /* @__PURE__ */ jsx(DialogPrimitive.Title, { className: "sr-only", children: "Dialog" }),
|
|
50
|
+
showClose && /* @__PURE__ */ jsx(
|
|
51
|
+
DialogPrimitive.Close,
|
|
52
|
+
{
|
|
53
|
+
"aria-label": "Close",
|
|
54
|
+
className: "absolute end-3 top-3 grid size-9 place-items-center rounded-(--radius-pill) text-(--ink-3-aa) transition-colors duration-(--duration-fast) hover:bg-(--stone) hover:text-(--ink)",
|
|
55
|
+
children: /* @__PURE__ */ jsx(X, { size: 16, strokeWidth: 1.5, "aria-hidden": true })
|
|
56
|
+
}
|
|
57
|
+
),
|
|
58
|
+
children
|
|
59
|
+
]
|
|
60
|
+
}
|
|
61
|
+
)
|
|
62
|
+
] });
|
|
63
|
+
}
|
|
64
|
+
var Dialog_default = Dialog;
|
|
65
|
+
export {
|
|
66
|
+
Dialog,
|
|
67
|
+
DialogClose,
|
|
68
|
+
DialogContent,
|
|
69
|
+
DialogTrigger,
|
|
70
|
+
Dialog_default as default
|
|
71
|
+
};
|
|
72
|
+
//# sourceMappingURL=Dialog.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../../src/components/Dialog/Dialog.tsx"],"sourcesContent":["'use client'\n\nimport * as DialogPrimitive from '@radix-ui/react-dialog'\nimport { X } from 'lucide-react'\nimport type { ComponentProps, ReactNode } from 'react'\nimport { cn } from '../../lib/cn'\n\n/** Radix Dialog root + trigger + close, re-exported as typed passthroughs. */\nexport const Dialog = DialogPrimitive.Root\nexport const DialogTrigger = DialogPrimitive.Trigger\nexport const DialogClose = DialogPrimitive.Close\n\n/** Title + description stack; renders nothing when both are omitted. */\nfunction DialogHeader({\n title,\n description,\n hidden,\n}: {\n title?: ReactNode\n description?: ReactNode\n hidden: boolean\n}) {\n if (title === undefined && description === undefined) return null\n return (\n <div className={cn('mb-4 flex flex-col gap-1 pe-8', hidden && 'sr-only')}>\n {title !== undefined && (\n <DialogPrimitive.Title className=\"m-0 font-heading text-[length:var(--fs-item)] font-normal text-(--ink)\">\n {title}\n </DialogPrimitive.Title>\n )}\n {description !== undefined && (\n <DialogPrimitive.Description className=\"m-0 text-sm leading-relaxed text-(--ink-3-aa)\">\n {description}\n </DialogPrimitive.Description>\n )}\n </div>\n )\n}\n\nexport interface DialogContentProps\n extends Omit<ComponentProps<typeof DialogPrimitive.Content>, 'title' | 'className'> {\n /** Heading text. When omitted, a visually-hidden title is rendered for a11y. */\n title?: ReactNode\n /** Sub-heading under the title. */\n description?: ReactNode\n className?: string\n /** Show the top-right close control (default true). */\n showClose?: boolean\n /**\n * Keeps the title for assistive tech and hides it visually.\n *\n * For a surface whose purpose is obvious to anyone who can see it — a command\n * palette, a media lightbox — where a printed heading would be furniture. The\n * title itself is never optional: Radix requires one, and a modal with no\n * accessible name drops a screen reader into an unnamed region.\n */\n hideTitle?: boolean\n}\n\n/**\n * A modal surface: portal → scrim → centred panel.\n *\n * Radix owns the focus trap, the escape key, the scroll lock and the\n * `aria-modal` wiring — all of which a hand-rolled dialog gets subtly wrong,\n * usually by leaving focus behind in the page underneath.\n *\n * Radix requires a `Dialog.Title` whether or not one is shown, so a dialog\n * without a visible heading still renders a hidden one rather than logging a\n * warning and shipping an unnamed modal.\n *\n * @example\n * <Dialog>\n * <DialogTrigger asChild><Button>Delete</Button></DialogTrigger>\n * <DialogContent title=\"Delete file\" description=\"This cannot be undone.\">\n * <DialogClose asChild><Button variant=\"secondary\">Cancel</Button></DialogClose>\n * </DialogContent>\n * </Dialog>\n */\nexport function DialogContent({\n title,\n description,\n children,\n className,\n showClose = true,\n hideTitle = false,\n ...rest\n}: DialogContentProps) {\n return (\n <DialogPrimitive.Portal>\n <DialogPrimitive.Overlay\n data-m22-animated\n className=\"fixed inset-0 z-(--z-overlay) bg-(--scrim) data-[state=open]:animate-[m22-fade-in_var(--duration-fast)_var(--ease)]\"\n />\n <DialogPrimitive.Content\n data-m22-animated\n className={cn(\n 'fixed left-1/2 top-1/2 z-(--z-modal) max-h-[85vh] w-[min(92vw,32rem)] -translate-x-1/2 -translate-y-1/2 overflow-auto rounded-(--radius-lg) border border-(--rule-2) bg-(--paper) p-6 scroll-slim',\n 'data-[state=open]:animate-[m22-panel-in_var(--duration-base)_var(--ease)]',\n className,\n )}\n {...rest}\n >\n <DialogHeader title={title} description={description} hidden={hideTitle} />\n\n {title === undefined && (\n <DialogPrimitive.Title className=\"sr-only\">Dialog</DialogPrimitive.Title>\n )}\n\n {showClose && (\n <DialogPrimitive.Close\n aria-label=\"Close\"\n className=\"absolute end-3 top-3 grid size-9 place-items-center rounded-(--radius-pill) text-(--ink-3-aa) transition-colors duration-(--duration-fast) hover:bg-(--stone) hover:text-(--ink)\"\n >\n <X size={16} strokeWidth={1.5} aria-hidden />\n </DialogPrimitive.Close>\n )}\n\n {children}\n </DialogPrimitive.Content>\n </DialogPrimitive.Portal>\n )\n}\n\nexport default Dialog\n"],"mappings":";AAwBI,SAEI,KAFJ;AAtBJ,YAAY,qBAAqB;AACjC,SAAS,SAAS;AAElB,SAAS,UAAU;AAGZ,MAAM,SAAS,gBAAgB;AAC/B,MAAM,gBAAgB,gBAAgB;AACtC,MAAM,cAAc,gBAAgB;AAG3C,SAAS,aAAa;AAAA,EACpB;AAAA,EACA;AAAA,EACA;AACF,GAIG;AACD,MAAI,UAAU,UAAa,gBAAgB,OAAW,QAAO;AAC7D,SACE,qBAAC,SAAI,WAAW,GAAG,iCAAiC,UAAU,SAAS,GACpE;AAAA,cAAU,UACT,oBAAC,gBAAgB,OAAhB,EAAsB,WAAU,0EAC9B,iBACH;AAAA,IAED,gBAAgB,UACf,oBAAC,gBAAgB,aAAhB,EAA4B,WAAU,iDACpC,uBACH;AAAA,KAEJ;AAEJ;AAyCO,SAAS,cAAc;AAAA,EAC5B;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA,YAAY;AAAA,EACZ,YAAY;AAAA,EACZ,GAAG;AACL,GAAuB;AACrB,SACE,qBAAC,gBAAgB,QAAhB,EACC;AAAA;AAAA,MAAC,gBAAgB;AAAA,MAAhB;AAAA,QACC,qBAAiB;AAAA,QACjB,WAAU;AAAA;AAAA,IACZ;AAAA,IACA;AAAA,MAAC,gBAAgB;AAAA,MAAhB;AAAA,QACC,qBAAiB;AAAA,QACjB,WAAW;AAAA,UACT;AAAA,UACA;AAAA,UACA;AAAA,QACF;AAAA,QACC,GAAG;AAAA,QAEJ;AAAA,8BAAC,gBAAa,OAAc,aAA0B,QAAQ,WAAW;AAAA,UAExE,UAAU,UACT,oBAAC,gBAAgB,OAAhB,EAAsB,WAAU,WAAU,oBAAM;AAAA,UAGlD,aACC;AAAA,YAAC,gBAAgB;AAAA,YAAhB;AAAA,cACC,cAAW;AAAA,cACX,WAAU;AAAA,cAEV,8BAAC,KAAE,MAAM,IAAI,aAAa,KAAK,eAAW,MAAC;AAAA;AAAA,UAC7C;AAAA,UAGD;AAAA;AAAA;AAAA,IACH;AAAA,KACF;AAEJ;AAEA,IAAO,iBAAQ;","names":[]}
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import * as react from 'react';
|
|
2
|
+
import { ComponentProps } from 'react';
|
|
3
|
+
import * as DropdownMenuPrimitive from '@radix-ui/react-dropdown-menu';
|
|
4
|
+
import { LucideIcon } from 'lucide-react';
|
|
5
|
+
|
|
6
|
+
/** Radix DropdownMenu root + trigger, re-exported as typed passthroughs. */
|
|
7
|
+
declare const DropdownMenu: react.FC<DropdownMenuPrimitive.DropdownMenuProps>;
|
|
8
|
+
declare const DropdownMenuTrigger: react.ForwardRefExoticComponent<DropdownMenuPrimitive.DropdownMenuTriggerProps & react.RefAttributes<HTMLButtonElement>>;
|
|
9
|
+
type DropdownMenuContentProps = ComponentProps<typeof DropdownMenuPrimitive.Content>;
|
|
10
|
+
/**
|
|
11
|
+
* A menu surface.
|
|
12
|
+
*
|
|
13
|
+
* A menu is a list of ACTIONS. If the items navigate somewhere, they belong in
|
|
14
|
+
* a nav; if they set a value, that is a `Select` or a `RadioGroup` — Radix has
|
|
15
|
+
* menu variants for both, and a plain item pretending to be a choice loses the
|
|
16
|
+
* checked state a screen reader needs.
|
|
17
|
+
*
|
|
18
|
+
* @example
|
|
19
|
+
* <DropdownMenu>
|
|
20
|
+
* <DropdownMenuTrigger asChild><Button variant="secondary">Menu</Button></DropdownMenuTrigger>
|
|
21
|
+
* <DropdownMenuContent>
|
|
22
|
+
* <DropdownMenuLabel>Account</DropdownMenuLabel>
|
|
23
|
+
* <DropdownMenuItem icon={Settings}>Settings</DropdownMenuItem>
|
|
24
|
+
* <DropdownMenuSeparator />
|
|
25
|
+
* <DropdownMenuItem icon={LogOut}>Sign out</DropdownMenuItem>
|
|
26
|
+
* </DropdownMenuContent>
|
|
27
|
+
* </DropdownMenu>
|
|
28
|
+
*/
|
|
29
|
+
declare function DropdownMenuContent({ className, sideOffset, children, ...rest }: DropdownMenuContentProps): react.JSX.Element;
|
|
30
|
+
interface DropdownMenuItemProps extends ComponentProps<typeof DropdownMenuPrimitive.Item> {
|
|
31
|
+
/** Optional leading icon, rendered before the label. */
|
|
32
|
+
icon?: LucideIcon;
|
|
33
|
+
/** Paints the row as destructive. Use for delete, revoke, disconnect. */
|
|
34
|
+
destructive?: boolean;
|
|
35
|
+
}
|
|
36
|
+
/**
|
|
37
|
+
* A menu row.
|
|
38
|
+
*
|
|
39
|
+
* Highlight is driven by Radix's `data-highlighted`, which covers both pointer
|
|
40
|
+
* hover and keyboard focus — styling `:hover` alone leaves the keyboard user
|
|
41
|
+
* unable to see where they are.
|
|
42
|
+
*/
|
|
43
|
+
declare function DropdownMenuItem({ icon: Icon, destructive, className, children, ...rest }: DropdownMenuItemProps): react.JSX.Element;
|
|
44
|
+
/** Hairline divider between menu groups. */
|
|
45
|
+
declare function DropdownMenuSeparator({ className, ...rest }: ComponentProps<typeof DropdownMenuPrimitive.Separator>): react.JSX.Element;
|
|
46
|
+
/** Mono eyebrow heading for a group of items. */
|
|
47
|
+
declare function DropdownMenuLabel({ className, ...rest }: ComponentProps<typeof DropdownMenuPrimitive.Label>): react.JSX.Element;
|
|
48
|
+
|
|
49
|
+
export { DropdownMenu, DropdownMenuContent, type DropdownMenuContentProps, DropdownMenuItem, type DropdownMenuItemProps, DropdownMenuLabel, DropdownMenuSeparator, DropdownMenuTrigger, DropdownMenu as default };
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { jsx, jsxs } from "react/jsx-runtime";
|
|
3
|
+
import * as DropdownMenuPrimitive from "@radix-ui/react-dropdown-menu";
|
|
4
|
+
import { cn } from "../../lib/cn.js";
|
|
5
|
+
import { useOverlayContainer } from "../../lib/overlay-container.js";
|
|
6
|
+
const DropdownMenu = DropdownMenuPrimitive.Root;
|
|
7
|
+
const DropdownMenuTrigger = DropdownMenuPrimitive.Trigger;
|
|
8
|
+
function DropdownMenuContent({
|
|
9
|
+
className,
|
|
10
|
+
sideOffset = 6,
|
|
11
|
+
children,
|
|
12
|
+
...rest
|
|
13
|
+
}) {
|
|
14
|
+
const container = useOverlayContainer();
|
|
15
|
+
return /* @__PURE__ */ jsx(DropdownMenuPrimitive.Portal, { container: container ?? void 0, children: /* @__PURE__ */ jsx(
|
|
16
|
+
DropdownMenuPrimitive.Content,
|
|
17
|
+
{
|
|
18
|
+
collisionBoundary: container ?? void 0,
|
|
19
|
+
collisionPadding: 8,
|
|
20
|
+
sideOffset,
|
|
21
|
+
"data-m22-animated": true,
|
|
22
|
+
className: cn(
|
|
23
|
+
"z-(--z-dropdown) min-w-44 rounded-(--radius) border border-(--rule-2) bg-(--paper) p-1.5",
|
|
24
|
+
"data-[state=open]:animate-[m22-pop-in_var(--duration-fast)_var(--ease-out-expo)] data-[state=closed]:animate-[m22-pop-out_var(--duration-fast)_var(--ease)] origin-(--radix-popper-transform-origin)",
|
|
25
|
+
className
|
|
26
|
+
),
|
|
27
|
+
...rest,
|
|
28
|
+
children
|
|
29
|
+
}
|
|
30
|
+
) });
|
|
31
|
+
}
|
|
32
|
+
function DropdownMenuItem({
|
|
33
|
+
icon: Icon,
|
|
34
|
+
destructive = false,
|
|
35
|
+
className,
|
|
36
|
+
children,
|
|
37
|
+
...rest
|
|
38
|
+
}) {
|
|
39
|
+
return /* @__PURE__ */ jsxs(
|
|
40
|
+
DropdownMenuPrimitive.Item,
|
|
41
|
+
{
|
|
42
|
+
className: cn(
|
|
43
|
+
"flex cursor-pointer items-center gap-2.5 rounded-(--radius-sm) px-2.5 py-2 text-sm outline-none transition-colors duration-(--duration-fast) data-[highlighted]:bg-(--stone) data-[disabled]:pointer-events-none data-[disabled]:opacity-(--disabled-opacity)",
|
|
44
|
+
destructive ? "text-(--danger)" : "text-(--ink-2) data-[highlighted]:text-(--ink)",
|
|
45
|
+
className
|
|
46
|
+
),
|
|
47
|
+
...rest,
|
|
48
|
+
children: [
|
|
49
|
+
Icon && /* @__PURE__ */ jsx(Icon, { size: 16, strokeWidth: 1.5, className: "shrink-0", "aria-hidden": true }),
|
|
50
|
+
children
|
|
51
|
+
]
|
|
52
|
+
}
|
|
53
|
+
);
|
|
54
|
+
}
|
|
55
|
+
function DropdownMenuSeparator({
|
|
56
|
+
className,
|
|
57
|
+
...rest
|
|
58
|
+
}) {
|
|
59
|
+
return /* @__PURE__ */ jsx(
|
|
60
|
+
DropdownMenuPrimitive.Separator,
|
|
61
|
+
{
|
|
62
|
+
className: cn("my-1 h-px bg-(--rule)", className),
|
|
63
|
+
...rest
|
|
64
|
+
}
|
|
65
|
+
);
|
|
66
|
+
}
|
|
67
|
+
function DropdownMenuLabel({
|
|
68
|
+
className,
|
|
69
|
+
...rest
|
|
70
|
+
}) {
|
|
71
|
+
return /* @__PURE__ */ jsx(
|
|
72
|
+
DropdownMenuPrimitive.Label,
|
|
73
|
+
{
|
|
74
|
+
className: cn("px-2.5 py-1.5 eyebrow text-(--ink-3-aa)", className),
|
|
75
|
+
...rest
|
|
76
|
+
}
|
|
77
|
+
);
|
|
78
|
+
}
|
|
79
|
+
var DropdownMenu_default = DropdownMenu;
|
|
80
|
+
export {
|
|
81
|
+
DropdownMenu,
|
|
82
|
+
DropdownMenuContent,
|
|
83
|
+
DropdownMenuItem,
|
|
84
|
+
DropdownMenuLabel,
|
|
85
|
+
DropdownMenuSeparator,
|
|
86
|
+
DropdownMenuTrigger,
|
|
87
|
+
DropdownMenu_default as default
|
|
88
|
+
};
|
|
89
|
+
//# sourceMappingURL=DropdownMenu.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../../src/components/DropdownMenu/DropdownMenu.tsx"],"sourcesContent":["'use client'\n\nimport * as DropdownMenuPrimitive from '@radix-ui/react-dropdown-menu'\nimport type { LucideIcon } from 'lucide-react'\nimport type { ComponentProps } from 'react'\nimport { cn } from '../../lib/cn'\nimport { useOverlayContainer } from '../../lib/overlay-container'\n\n/** Radix DropdownMenu root + trigger, re-exported as typed passthroughs. */\nexport const DropdownMenu = DropdownMenuPrimitive.Root\nexport const DropdownMenuTrigger = DropdownMenuPrimitive.Trigger\n\nexport type DropdownMenuContentProps = ComponentProps<typeof DropdownMenuPrimitive.Content>\n\n/**\n * A menu surface.\n *\n * A menu is a list of ACTIONS. If the items navigate somewhere, they belong in\n * a nav; if they set a value, that is a `Select` or a `RadioGroup` — Radix has\n * menu variants for both, and a plain item pretending to be a choice loses the\n * checked state a screen reader needs.\n *\n * @example\n * <DropdownMenu>\n * <DropdownMenuTrigger asChild><Button variant=\"secondary\">Menu</Button></DropdownMenuTrigger>\n * <DropdownMenuContent>\n * <DropdownMenuLabel>Account</DropdownMenuLabel>\n * <DropdownMenuItem icon={Settings}>Settings</DropdownMenuItem>\n * <DropdownMenuSeparator />\n * <DropdownMenuItem icon={LogOut}>Sign out</DropdownMenuItem>\n * </DropdownMenuContent>\n * </DropdownMenu>\n */\nexport function DropdownMenuContent({\n className,\n sideOffset = 6,\n children,\n ...rest\n}: DropdownMenuContentProps) {\n const container = useOverlayContainer()\n\n return (\n <DropdownMenuPrimitive.Portal container={container ?? undefined}>\n <DropdownMenuPrimitive.Content\n collisionBoundary={container ?? undefined}\n collisionPadding={8}\n sideOffset={sideOffset}\n data-m22-animated\n className={cn(\n 'z-(--z-dropdown) min-w-44 rounded-(--radius) border border-(--rule-2) bg-(--paper) p-1.5',\n 'data-[state=open]:animate-[m22-pop-in_var(--duration-fast)_var(--ease-out-expo)] data-[state=closed]:animate-[m22-pop-out_var(--duration-fast)_var(--ease)] origin-(--radix-popper-transform-origin)',\n className,\n )}\n {...rest}\n >\n {children}\n </DropdownMenuPrimitive.Content>\n </DropdownMenuPrimitive.Portal>\n )\n}\n\nexport interface DropdownMenuItemProps extends ComponentProps<typeof DropdownMenuPrimitive.Item> {\n /** Optional leading icon, rendered before the label. */\n icon?: LucideIcon\n /** Paints the row as destructive. Use for delete, revoke, disconnect. */\n destructive?: boolean\n}\n\n/**\n * A menu row.\n *\n * Highlight is driven by Radix's `data-highlighted`, which covers both pointer\n * hover and keyboard focus — styling `:hover` alone leaves the keyboard user\n * unable to see where they are.\n */\nexport function DropdownMenuItem({\n icon: Icon,\n destructive = false,\n className,\n children,\n ...rest\n}: DropdownMenuItemProps) {\n return (\n <DropdownMenuPrimitive.Item\n className={cn(\n 'flex cursor-pointer items-center gap-2.5 rounded-(--radius-sm) px-2.5 py-2 text-sm outline-none transition-colors duration-(--duration-fast) data-[highlighted]:bg-(--stone) data-[disabled]:pointer-events-none data-[disabled]:opacity-(--disabled-opacity)',\n destructive ? 'text-(--danger)' : 'text-(--ink-2) data-[highlighted]:text-(--ink)',\n className,\n )}\n {...rest}\n >\n {Icon && <Icon size={16} strokeWidth={1.5} className=\"shrink-0\" aria-hidden />}\n {children}\n </DropdownMenuPrimitive.Item>\n )\n}\n\n/** Hairline divider between menu groups. */\nexport function DropdownMenuSeparator({\n className,\n ...rest\n}: ComponentProps<typeof DropdownMenuPrimitive.Separator>) {\n return (\n <DropdownMenuPrimitive.Separator\n className={cn('my-1 h-px bg-(--rule)', className)}\n {...rest}\n />\n )\n}\n\n/** Mono eyebrow heading for a group of items. */\nexport function DropdownMenuLabel({\n className,\n ...rest\n}: ComponentProps<typeof DropdownMenuPrimitive.Label>) {\n return (\n <DropdownMenuPrimitive.Label\n className={cn('px-2.5 py-1.5 eyebrow text-(--ink-3-aa)', className)}\n {...rest}\n />\n )\n}\n\nexport default DropdownMenu\n"],"mappings":";AA2CM,cAwCF,YAxCE;AAzCN,YAAY,2BAA2B;AAGvC,SAAS,UAAU;AACnB,SAAS,2BAA2B;AAG7B,MAAM,eAAe,sBAAsB;AAC3C,MAAM,sBAAsB,sBAAsB;AAuBlD,SAAS,oBAAoB;AAAA,EAClC;AAAA,EACA,aAAa;AAAA,EACb;AAAA,EACA,GAAG;AACL,GAA6B;AAC3B,QAAM,YAAY,oBAAoB;AAEtC,SACE,oBAAC,sBAAsB,QAAtB,EAA6B,WAAW,aAAa,QACpD;AAAA,IAAC,sBAAsB;AAAA,IAAtB;AAAA,MACC,mBAAmB,aAAa;AAAA,MAChC,kBAAkB;AAAA,MAClB;AAAA,MACA,qBAAiB;AAAA,MACjB,WAAW;AAAA,QACT;AAAA,QACA;AAAA,QACA;AAAA,MACF;AAAA,MACC,GAAG;AAAA,MAEH;AAAA;AAAA,EACH,GACF;AAEJ;AAgBO,SAAS,iBAAiB;AAAA,EAC/B,MAAM;AAAA,EACN,cAAc;AAAA,EACd;AAAA,EACA;AAAA,EACA,GAAG;AACL,GAA0B;AACxB,SACE;AAAA,IAAC,sBAAsB;AAAA,IAAtB;AAAA,MACC,WAAW;AAAA,QACT;AAAA,QACA,cAAc,oBAAoB;AAAA,QAClC;AAAA,MACF;AAAA,MACC,GAAG;AAAA,MAEH;AAAA,gBAAQ,oBAAC,QAAK,MAAM,IAAI,aAAa,KAAK,WAAU,YAAW,eAAW,MAAC;AAAA,QAC3E;AAAA;AAAA;AAAA,EACH;AAEJ;AAGO,SAAS,sBAAsB;AAAA,EACpC;AAAA,EACA,GAAG;AACL,GAA2D;AACzD,SACE;AAAA,IAAC,sBAAsB;AAAA,IAAtB;AAAA,MACC,WAAW,GAAG,yBAAyB,SAAS;AAAA,MAC/C,GAAG;AAAA;AAAA,EACN;AAEJ;AAGO,SAAS,kBAAkB;AAAA,EAChC;AAAA,EACA,GAAG;AACL,GAAuD;AACrD,SACE;AAAA,IAAC,sBAAsB;AAAA,IAAtB;AAAA,MACC,WAAW,GAAG,2CAA2C,SAAS;AAAA,MACjE,GAAG;AAAA;AAAA,EACN;AAEJ;AAEA,IAAO,uBAAQ;","names":[]}
|