@franco_roura/module-01 0.0.0-stage → 1.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE-APACHE +202 -0
- package/LICENSE-MIT +21 -0
- package/README.md +64 -2
- package/dist/charts.d.ts +3 -0
- package/dist/charts.js +3 -0
- package/dist/components/alert-dialog.d.ts +19 -0
- package/dist/components/alert-dialog.js +101 -0
- package/dist/components/alert-dialog.js.map +1 -0
- package/dist/components/amount.d.ts +24 -0
- package/dist/components/amount.js +27 -0
- package/dist/components/amount.js.map +1 -0
- package/dist/components/appearance-pickers.d.ts +9 -0
- package/dist/components/appearance-pickers.js +65 -0
- package/dist/components/appearance-pickers.js.map +1 -0
- package/dist/components/badge.d.ts +10 -0
- package/dist/components/badge.js +28 -0
- package/dist/components/badge.js.map +1 -0
- package/dist/components/budget-meter.d.ts +18 -0
- package/dist/components/budget-meter.js +38 -0
- package/dist/components/budget-meter.js.map +1 -0
- package/dist/components/button.d.ts +13 -0
- package/dist/components/button.js +54 -0
- package/dist/components/button.js.map +1 -0
- package/dist/components/calendar.d.ts +7 -0
- package/dist/components/calendar.js +52 -0
- package/dist/components/calendar.js.map +1 -0
- package/dist/components/category-icon.d.ts +33 -0
- package/dist/components/category-icon.js +49 -0
- package/dist/components/category-icon.js.map +1 -0
- package/dist/components/chart.d.ts +44 -0
- package/dist/components/chart.js +147 -0
- package/dist/components/chart.js.map +1 -0
- package/dist/components/charts.d.ts +52 -0
- package/dist/components/charts.js +482 -0
- package/dist/components/charts.js.map +1 -0
- package/dist/components/checkbox.d.ts +5 -0
- package/dist/components/checkbox.js +21 -0
- package/dist/components/checkbox.js.map +1 -0
- package/dist/components/combobox.d.ts +32 -0
- package/dist/components/combobox.js +100 -0
- package/dist/components/combobox.js.map +1 -0
- package/dist/components/command.d.ts +19 -0
- package/dist/components/command.js +86 -0
- package/dist/components/command.js.map +1 -0
- package/dist/components/cta-banner.d.ts +14 -0
- package/dist/components/cta-banner.js +39 -0
- package/dist/components/cta-banner.js.map +1 -0
- package/dist/components/date-picker.d.ts +19 -0
- package/dist/components/date-picker.js +107 -0
- package/dist/components/date-picker.js.map +1 -0
- package/dist/components/dialog.d.ts +18 -0
- package/dist/components/dialog.js +99 -0
- package/dist/components/dialog.js.map +1 -0
- package/dist/components/dropdown-menu.d.ts +26 -0
- package/dist/components/dropdown-menu.js +123 -0
- package/dist/components/dropdown-menu.js.map +1 -0
- package/dist/components/field.d.ts +30 -0
- package/dist/components/field.js +53 -0
- package/dist/components/field.js.map +1 -0
- package/dist/components/footer.d.ts +18 -0
- package/dist/components/footer.js +40 -0
- package/dist/components/footer.js.map +1 -0
- package/dist/components/fx-converter.d.ts +22 -0
- package/dist/components/fx-converter.js +91 -0
- package/dist/components/fx-converter.js.map +1 -0
- package/dist/components/hero.d.ts +28 -0
- package/dist/components/hero.js +83 -0
- package/dist/components/hero.js.map +1 -0
- package/dist/components/hud.d.ts +41 -0
- package/dist/components/hud.js +108 -0
- package/dist/components/hud.js.map +1 -0
- package/dist/components/input.d.ts +4 -0
- package/dist/components/input.js +14 -0
- package/dist/components/input.js.map +1 -0
- package/dist/components/label.d.ts +5 -0
- package/dist/components/label.js +15 -0
- package/dist/components/label.js.map +1 -0
- package/dist/components/media-card.d.ts +29 -0
- package/dist/components/media-card.js +80 -0
- package/dist/components/media-card.js.map +1 -0
- package/dist/components/money-input.d.ts +10 -0
- package/dist/components/money-input.js +30 -0
- package/dist/components/money-input.js.map +1 -0
- package/dist/components/multi-combobox.d.ts +27 -0
- package/dist/components/multi-combobox.js +101 -0
- package/dist/components/multi-combobox.js.map +1 -0
- package/dist/components/nav-bar.d.ts +21 -0
- package/dist/components/nav-bar.js +44 -0
- package/dist/components/nav-bar.js.map +1 -0
- package/dist/components/panel.d.ts +27 -0
- package/dist/components/panel.js +49 -0
- package/dist/components/panel.js.map +1 -0
- package/dist/components/popover.d.ts +11 -0
- package/dist/components/popover.js +56 -0
- package/dist/components/popover.js.map +1 -0
- package/dist/components/select.d.ts +16 -0
- package/dist/components/select.js +128 -0
- package/dist/components/select.js.map +1 -0
- package/dist/components/separator.d.ts +5 -0
- package/dist/components/separator.js +17 -0
- package/dist/components/separator.js.map +1 -0
- package/dist/components/sheet.d.ts +15 -0
- package/dist/components/sheet.js +87 -0
- package/dist/components/sheet.js.map +1 -0
- package/dist/components/skeleton.d.ts +3 -0
- package/dist/components/skeleton.js +13 -0
- package/dist/components/skeleton.js.map +1 -0
- package/dist/components/sonner.d.ts +5 -0
- package/dist/components/sonner.js +44 -0
- package/dist/components/sonner.js.map +1 -0
- package/dist/components/spec-readout.d.ts +11 -0
- package/dist/components/spec-readout.js +25 -0
- package/dist/components/spec-readout.js.map +1 -0
- package/dist/components/split-flap.d.ts +12 -0
- package/dist/components/split-flap.js +77 -0
- package/dist/components/split-flap.js.map +1 -0
- package/dist/components/tabs.d.ts +12 -0
- package/dist/components/tabs.js +47 -0
- package/dist/components/tabs.js.map +1 -0
- package/dist/components/tag.d.ts +16 -0
- package/dist/components/tag.js +26 -0
- package/dist/components/tag.js.map +1 -0
- package/dist/components/terminal.d.ts +10 -0
- package/dist/components/terminal.js +20 -0
- package/dist/components/terminal.js.map +1 -0
- package/dist/components/textarea.d.ts +4 -0
- package/dist/components/textarea.js +13 -0
- package/dist/components/textarea.js.map +1 -0
- package/dist/components/timeline-entry.d.ts +26 -0
- package/dist/components/timeline-entry.js +63 -0
- package/dist/components/timeline-entry.js.map +1 -0
- package/dist/components/toggle-group.d.ts +10 -0
- package/dist/components/toggle-group.js +49 -0
- package/dist/components/toggle-group.js.map +1 -0
- package/dist/components/toggle.d.ts +10 -0
- package/dist/components/toggle.js +37 -0
- package/dist/components/toggle.js.map +1 -0
- package/dist/components/tooltip.d.ts +8 -0
- package/dist/components/tooltip.js +36 -0
- package/dist/components/tooltip.js.map +1 -0
- package/dist/finance.d.ts +10 -0
- package/dist/finance.js +10 -0
- package/dist/index.d.ts +33 -0
- package/dist/index.js +33 -0
- package/dist/lib/category-icons.d.ts +80 -0
- package/dist/lib/category-icons.js +102 -0
- package/dist/lib/category-icons.js.map +1 -0
- package/dist/lib/fault.d.ts +7 -0
- package/dist/lib/fault.js +28 -0
- package/dist/lib/fault.js.map +1 -0
- package/dist/lib/form-flow.d.ts +15 -0
- package/dist/lib/form-flow.js +50 -0
- package/dist/lib/form-flow.js.map +1 -0
- package/dist/lib/fx.d.ts +39 -0
- package/dist/lib/fx.js +98 -0
- package/dist/lib/fx.js.map +1 -0
- package/dist/lib/money.d.ts +19 -0
- package/dist/lib/money.js +55 -0
- package/dist/lib/money.js.map +1 -0
- package/dist/lib/use-media-query.d.ts +3 -0
- package/dist/lib/use-media-query.js +15 -0
- package/dist/lib/use-media-query.js.map +1 -0
- package/dist/lib/utils.d.ts +3 -0
- package/dist/lib/utils.js +26 -0
- package/dist/lib/utils.js.map +1 -0
- package/dist/site.d.ts +10 -0
- package/dist/site.js +10 -0
- package/dist/styles.css +2 -0
- package/dist/theme.css +391 -0
- package/dist/tokens.css +181 -0
- package/guidelines/AlertDialog.md +9 -0
- package/guidelines/Amount.md +10 -0
- package/guidelines/AppearancePickers.md +8 -0
- package/guidelines/Badge.md +11 -0
- package/guidelines/BudgetMeter.md +11 -0
- package/guidelines/Button.md +16 -0
- package/guidelines/Calendar.md +8 -0
- package/guidelines/CategoryIcon.md +10 -0
- package/guidelines/Charts.md +12 -0
- package/guidelines/Checkbox.md +8 -0
- package/guidelines/Combobox.md +18 -0
- package/guidelines/Command.md +8 -0
- package/guidelines/Crosshair.md +7 -0
- package/guidelines/CtaBanner.md +8 -0
- package/guidelines/DatePicker.md +11 -0
- package/guidelines/Dialog.md +9 -0
- package/guidelines/DropdownMenu.md +9 -0
- package/guidelines/Field.md +22 -0
- package/guidelines/Footer.md +7 -0
- package/guidelines/FxConverter.md +12 -0
- package/guidelines/GlassPanel.md +8 -0
- package/guidelines/Grill.md +7 -0
- package/guidelines/Hero.md +9 -0
- package/guidelines/HudLabel.md +8 -0
- package/guidelines/Input.md +9 -0
- package/guidelines/Label.md +7 -0
- package/guidelines/MediaCard.md +8 -0
- package/guidelines/MoneyInput.md +10 -0
- package/guidelines/MultiCombobox.md +11 -0
- package/guidelines/NavBar.md +10 -0
- package/guidelines/Panel.md +10 -0
- package/guidelines/Popover.md +8 -0
- package/guidelines/README.md +100 -0
- package/guidelines/SectionHeader.md +9 -0
- package/guidelines/Select.md +9 -0
- package/guidelines/Separator.md +8 -0
- package/guidelines/Sheet.md +9 -0
- package/guidelines/Skeleton.md +8 -0
- package/guidelines/SpecReadout.md +7 -0
- package/guidelines/SplitFlap.md +9 -0
- package/guidelines/StatusLed.md +8 -0
- package/guidelines/Tabs.md +9 -0
- package/guidelines/Tag.md +9 -0
- package/guidelines/Terminal.md +7 -0
- package/guidelines/Textarea.md +8 -0
- package/guidelines/TickRuler.md +8 -0
- package/guidelines/TimelineEntry.md +8 -0
- package/guidelines/Toaster.md +9 -0
- package/guidelines/Toggle.md +9 -0
- package/guidelines/Tooltip.md +8 -0
- package/package.json +103 -4
- package/tokens/tokens.json +739 -0
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { focusNextField } from "../lib/form-flow.js";
|
|
3
|
+
import { cn } from "../lib/utils.js";
|
|
4
|
+
import { Button } from "./button.js";
|
|
5
|
+
import { Command, CommandEmpty, CommandGroup, CommandInput, CommandItem, CommandList } from "./command.js";
|
|
6
|
+
import { Popover, PopoverContent, PopoverTrigger } from "./popover.js";
|
|
7
|
+
import { jsx, jsxs } from "react/jsx-runtime";
|
|
8
|
+
import { Check, ChevronsUpDown } from "lucide-react";
|
|
9
|
+
import { useRef, useState } from "react";
|
|
10
|
+
// src/components/combobox.tsx
|
|
11
|
+
/**
|
|
12
|
+
* Searchable single-choice picker. Part of the form flow: typing on the focused trigger opens it
|
|
13
|
+
* with that text as the search, and picking an option moves focus to the next field.
|
|
14
|
+
*/
|
|
15
|
+
function Combobox({ id, value, onChange, options, groups, getKey, getSearchText, renderOption, renderValue, placeholder = "Choose…", searchPlaceholder = "Search…", emptyText = "Nothing found.", footer, invalid, disabled, className, contentClassName }) {
|
|
16
|
+
const [open, setOpen] = useState(false);
|
|
17
|
+
const [query, setQuery] = useState("");
|
|
18
|
+
const trigger = useRef(null);
|
|
19
|
+
const committed = useRef(false);
|
|
20
|
+
const sections = groups ?? [{ options: options ?? [] }];
|
|
21
|
+
const current = sections.flatMap((g) => g.options).find((o) => getKey(o) === value);
|
|
22
|
+
const search = getSearchText ?? getKey;
|
|
23
|
+
function openWith(text) {
|
|
24
|
+
setQuery(text);
|
|
25
|
+
setOpen(true);
|
|
26
|
+
}
|
|
27
|
+
function pick(option) {
|
|
28
|
+
committed.current = true;
|
|
29
|
+
onChange(getKey(option));
|
|
30
|
+
setOpen(false);
|
|
31
|
+
}
|
|
32
|
+
return /* @__PURE__ */ jsxs(Popover, {
|
|
33
|
+
open,
|
|
34
|
+
onOpenChange: (next) => {
|
|
35
|
+
if (next) setQuery("");
|
|
36
|
+
setOpen(next);
|
|
37
|
+
},
|
|
38
|
+
children: [/* @__PURE__ */ jsx(PopoverTrigger, {
|
|
39
|
+
asChild: true,
|
|
40
|
+
children: /* @__PURE__ */ jsxs(Button, {
|
|
41
|
+
ref: trigger,
|
|
42
|
+
id,
|
|
43
|
+
type: "button",
|
|
44
|
+
variant: "outline",
|
|
45
|
+
role: "combobox",
|
|
46
|
+
"data-flow-autoopen": value ? void 0 : "",
|
|
47
|
+
"aria-expanded": open,
|
|
48
|
+
"aria-invalid": invalid || void 0,
|
|
49
|
+
disabled,
|
|
50
|
+
className: cn("w-full justify-between px-3", className),
|
|
51
|
+
onKeyDown: (e) => {
|
|
52
|
+
if (!open && e.key.length === 1 && !e.ctrlKey && !e.metaKey && !e.altKey && e.key !== " ") {
|
|
53
|
+
e.preventDefault();
|
|
54
|
+
openWith(e.key);
|
|
55
|
+
}
|
|
56
|
+
},
|
|
57
|
+
children: [current ? /* @__PURE__ */ jsx("span", {
|
|
58
|
+
className: "flex min-w-0 items-center gap-2",
|
|
59
|
+
children: (renderValue ?? renderOption)(current)
|
|
60
|
+
}) : /* @__PURE__ */ jsx("span", {
|
|
61
|
+
className: "text-ink-soft",
|
|
62
|
+
children: placeholder
|
|
63
|
+
}), /* @__PURE__ */ jsx(ChevronsUpDown, {
|
|
64
|
+
className: "size-4 shrink-0 text-ink-soft",
|
|
65
|
+
strokeWidth: 1.25
|
|
66
|
+
})]
|
|
67
|
+
})
|
|
68
|
+
}), /* @__PURE__ */ jsxs(PopoverContent, {
|
|
69
|
+
align: "start",
|
|
70
|
+
className: cn("w-(--radix-popover-trigger-width) min-w-64 p-0", contentClassName),
|
|
71
|
+
onCloseAutoFocus: (e) => {
|
|
72
|
+
if (!committed.current) return;
|
|
73
|
+
committed.current = false;
|
|
74
|
+
e.preventDefault();
|
|
75
|
+
focusNextField(trigger.current);
|
|
76
|
+
},
|
|
77
|
+
children: [/* @__PURE__ */ jsxs(Command, { children: [/* @__PURE__ */ jsx(CommandInput, {
|
|
78
|
+
placeholder: searchPlaceholder,
|
|
79
|
+
value: query,
|
|
80
|
+
onValueChange: setQuery
|
|
81
|
+
}), /* @__PURE__ */ jsxs(CommandList, { children: [/* @__PURE__ */ jsx(CommandEmpty, { children: emptyText }), sections.map((g, i) => /* @__PURE__ */ jsx(CommandGroup, {
|
|
82
|
+
heading: g.heading,
|
|
83
|
+
children: g.options.map((o) => /* @__PURE__ */ jsxs(CommandItem, {
|
|
84
|
+
value: `${search(o)} ${getKey(o)}`,
|
|
85
|
+
onSelect: () => pick(o),
|
|
86
|
+
children: [renderOption(o), getKey(o) === value && /* @__PURE__ */ jsx(Check, {
|
|
87
|
+
className: "ml-auto size-4",
|
|
88
|
+
strokeWidth: 1.25
|
|
89
|
+
})]
|
|
90
|
+
}, getKey(o)))
|
|
91
|
+
}, g.heading ?? i))] })] }), footer && /* @__PURE__ */ jsx("div", {
|
|
92
|
+
className: "border-t border-seam p-2",
|
|
93
|
+
children: footer
|
|
94
|
+
})]
|
|
95
|
+
})]
|
|
96
|
+
});
|
|
97
|
+
}
|
|
98
|
+
export { Combobox };
|
|
99
|
+
|
|
100
|
+
//# sourceMappingURL=combobox.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"combobox.js","names":[],"sources":["../../src/components/combobox.tsx"],"sourcesContent":["\"use client\";\n\nimport { focusNextField } from \"../lib/form-flow\";\nimport { cn } from \"../lib/utils\";\nimport { Check, ChevronsUpDown } from \"lucide-react\";\nimport { useRef, useState } from \"react\";\nimport { Button } from \"./button\";\nimport {\n Command,\n CommandEmpty,\n CommandGroup,\n CommandInput,\n CommandItem,\n CommandList,\n} from \"./command\";\nimport { Popover, PopoverContent, PopoverTrigger } from \"./popover\";\n\nexport type ComboboxGroup<T> = { heading?: string; options: T[] };\n\n/**\n * Searchable single-choice picker. Part of the form flow: typing on the focused trigger opens it\n * with that text as the search, and picking an option moves focus to the next field.\n */\nexport function Combobox<T>({\n id,\n value,\n onChange,\n options,\n groups,\n getKey,\n getSearchText,\n renderOption,\n renderValue,\n placeholder = \"Choose…\",\n searchPlaceholder = \"Search…\",\n emptyText = \"Nothing found.\",\n footer,\n invalid,\n disabled,\n className,\n contentClassName,\n}: {\n id?: string;\n value: string;\n onChange: (key: string) => void;\n /** Flat options; or pass `groups` for headed sections. */\n options?: T[];\n groups?: ComboboxGroup<T>[];\n getKey: (option: T) => string;\n /** Text the search matches against (defaults to the key). */\n getSearchText?: (option: T) => string;\n renderOption: (option: T) => React.ReactNode;\n /** The selected option on the trigger (defaults to renderOption). */\n renderValue?: (option: T) => React.ReactNode;\n placeholder?: React.ReactNode;\n searchPlaceholder?: string;\n emptyText?: React.ReactNode;\n /** Shown under the list, e.g. a link to manage the options. */\n footer?: React.ReactNode;\n invalid?: boolean;\n disabled?: boolean;\n className?: string;\n contentClassName?: string;\n}) {\n const [open, setOpen] = useState(false);\n const [query, setQuery] = useState(\"\");\n const trigger = useRef<HTMLButtonElement>(null);\n const committed = useRef(false);\n\n const sections: ComboboxGroup<T>[] = groups ?? [{ options: options ?? [] }];\n const current = sections.flatMap((g) => g.options).find((o) => getKey(o) === value);\n const search = getSearchText ?? getKey;\n\n function openWith(text: string) {\n setQuery(text);\n setOpen(true);\n }\n\n function pick(option: T) {\n committed.current = true;\n onChange(getKey(option));\n setOpen(false);\n }\n\n return (\n <Popover\n open={open}\n onOpenChange={(next) => {\n if (next) setQuery(\"\");\n setOpen(next);\n }}\n >\n <PopoverTrigger asChild>\n <Button\n ref={trigger}\n id={id}\n type=\"button\"\n variant=\"outline\"\n role=\"combobox\"\n data-flow-autoopen={value ? undefined : \"\"}\n aria-expanded={open}\n aria-invalid={invalid || undefined}\n disabled={disabled}\n className={cn(\"w-full justify-between px-3\", className)}\n onKeyDown={(e) => {\n // Type to search: a printable key on the closed trigger opens it with that letter.\n if (\n !open &&\n e.key.length === 1 &&\n !e.ctrlKey &&\n !e.metaKey &&\n !e.altKey &&\n e.key !== \" \"\n ) {\n e.preventDefault();\n openWith(e.key);\n }\n }}\n >\n {current ? (\n <span className=\"flex min-w-0 items-center gap-2\">\n {(renderValue ?? renderOption)(current)}\n </span>\n ) : (\n <span className=\"text-ink-soft\">{placeholder}</span>\n )}\n <ChevronsUpDown className=\"size-4 shrink-0 text-ink-soft\" strokeWidth={1.25} />\n </Button>\n </PopoverTrigger>\n <PopoverContent\n align=\"start\"\n className={cn(\"w-(--radix-popover-trigger-width) min-w-64 p-0\", contentClassName)}\n onCloseAutoFocus={(e) => {\n // Form flow: after a pick, move on to the next field (Escape returns to the trigger).\n if (!committed.current) return;\n committed.current = false;\n e.preventDefault();\n focusNextField(trigger.current);\n }}\n >\n <Command>\n <CommandInput placeholder={searchPlaceholder} value={query} onValueChange={setQuery} />\n <CommandList>\n <CommandEmpty>{emptyText}</CommandEmpty>\n {sections.map((g, i) => (\n <CommandGroup key={g.heading ?? i} heading={g.heading}>\n {g.options.map((o) => (\n <CommandItem\n key={getKey(o)}\n value={`${search(o)} ${getKey(o)}`}\n onSelect={() => pick(o)}\n >\n {renderOption(o)}\n {getKey(o) === value && <Check className=\"ml-auto size-4\" strokeWidth={1.25} />}\n </CommandItem>\n ))}\n </CommandGroup>\n ))}\n </CommandList>\n </Command>\n {footer && <div className=\"border-t border-seam p-2\">{footer}</div>}\n </PopoverContent>\n </Popover>\n );\n}\n"],"mappings":";;;;;;;;;;;;;;AAuBA,SAAgB,SAAY,EAC1B,IACA,OACA,UACA,SACA,QACA,QACA,eACA,cACA,aACA,cAAc,WACd,oBAAoB,WACpB,YAAY,kBACZ,QACA,SACA,UACA,WACA,oBAuBC;CACD,MAAM,CAAC,MAAM,WAAW,SAAS,KAAK;CACtC,MAAM,CAAC,OAAO,YAAY,SAAS,EAAE;CACrC,MAAM,UAAU,OAA0B,IAAI;CAC9C,MAAM,YAAY,OAAO,KAAK;CAE9B,MAAM,WAA+B,UAAU,CAAC,EAAE,SAAS,WAAW,CAAC,EAAE,CAAC;CAC1E,MAAM,UAAU,SAAS,SAAS,MAAM,EAAE,OAAO,CAAC,CAAC,MAAM,MAAM,OAAO,CAAC,MAAM,KAAK;CAClF,MAAM,SAAS,iBAAiB;CAEhC,SAAS,SAAS,MAAc;EAC9B,SAAS,IAAI;EACb,QAAQ,IAAI;CACd;CAEA,SAAS,KAAK,QAAW;EACvB,UAAU,UAAU;EACpB,SAAS,OAAO,MAAM,CAAC;EACvB,QAAQ,KAAK;CACf;CAEA,OACE,qBAAC,SAAD;EACQ;EACN,eAAe,SAAS;GACtB,IAAI,MAAM,SAAS,EAAE;GACrB,QAAQ,IAAI;EACd;EALF,UAAA,CAOE,oBAAC,gBAAD;GAAgB,SAAA;GACd,UAAA,qBAAC,QAAD;IACE,KAAK;IACD;IACJ,MAAK;IACL,SAAQ;IACR,MAAK;IACL,sBAAoB,QAAQ,KAAA,IAAY;IACxC,iBAAe;IACf,gBAAc,WAAW,KAAA;IACf;IACV,WAAW,GAAG,+BAA+B,SAAS;IACtD,YAAY,MAAM;KAEhB,IACE,CAAC,QACD,EAAE,IAAI,WAAW,KACjB,CAAC,EAAE,WACH,CAAC,EAAE,WACH,CAAC,EAAE,UACH,EAAE,QAAQ,KACV;MACA,EAAE,eAAe;MACjB,SAAS,EAAE,GAAG;KAChB;IACF;IAxBF,UAAA,CA0BG,UACC,oBAAC,QAAD;KAAM,WAAU;KACZ,WAAA,eAAe,aAAA,CAAc,OAAO;IAClC,CAAA,IAEN,oBAAC,QAAD;KAAM,WAAU;KAAiB,UAAA;IAAkB,CAAA,GAErD,oBAAC,gBAAD;KAAgB,WAAU;KAAgC,aAAa;IAAO,CAAA,CACxE;;EACM,CAAA,GAChB,qBAAC,gBAAD;GACE,OAAM;GACN,WAAW,GAAG,kDAAkD,gBAAgB;GAChF,mBAAmB,MAAM;IAEvB,IAAI,CAAC,UAAU,SAAS;IACxB,UAAU,UAAU;IACpB,EAAE,eAAe;IACjB,eAAe,QAAQ,OAAO;GAChC;GATF,UAAA,CAWE,qBAAC,SAAD,EAAA,UAAA,CACE,oBAAC,cAAD;IAAc,aAAa;IAAmB,OAAO;IAAO,eAAe;GAAW,CAAA,GACtF,qBAAC,aAAD,EAAA,UAAA,CACE,oBAAC,cAAD,EAAA,UAAe,UAAwB,CAAA,GACtC,SAAS,KAAK,GAAG,MAChB,oBAAC,cAAD;IAAmC,SAAS,EAAE;IAC3C,UAAA,EAAE,QAAQ,KAAK,MACd,qBAAC,aAAD;KAEE,OAAO,GAAG,OAAO,CAAC,EAAE,GAAG,OAAO,CAAC;KAC/B,gBAAgB,KAAK,CAAC;KAHxB,UAAA,CAKG,aAAa,CAAC,GACd,OAAO,CAAC,MAAM,SAAS,oBAAC,OAAD;MAAO,WAAU;MAAiB,aAAa;KAAO,CAAA,CACnE;IANN,GAAA,OAAO,CAAC,CAMF,CACd;GACW,GAXK,EAAE,WAAW,CAWlB,CACf,CACU,EAAA,CAAA,CACN,EAAA,CAAA,GACR,UAAU,oBAAC,OAAD;IAAK,WAAU;IAA4B,UAAA;GAAY,CAAA,CACpD;EACT,CAAA,CAAA;;AAEb"}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { Dialog } from "./dialog.js";
|
|
2
|
+
import * as React from "react";
|
|
3
|
+
import { Command } from "cmdk";
|
|
4
|
+
declare function Command$1({ className, ...props }: React.ComponentProps<typeof Command>): React.JSX.Element;
|
|
5
|
+
declare function CommandDialog({ title, description, children, className, showCloseButton, ...props }: React.ComponentProps<typeof Dialog> & {
|
|
6
|
+
title?: string;
|
|
7
|
+
description?: string;
|
|
8
|
+
className?: string;
|
|
9
|
+
showCloseButton?: boolean;
|
|
10
|
+
}): React.JSX.Element;
|
|
11
|
+
declare function CommandInput({ className, ...props }: React.ComponentProps<typeof Command.Input>): React.JSX.Element;
|
|
12
|
+
declare function CommandList({ className, ...props }: React.ComponentProps<typeof Command.List>): React.JSX.Element;
|
|
13
|
+
declare function CommandEmpty({ ...props }: React.ComponentProps<typeof Command.Empty>): React.JSX.Element;
|
|
14
|
+
declare function CommandGroup({ className, ...props }: React.ComponentProps<typeof Command.Group>): React.JSX.Element;
|
|
15
|
+
declare function CommandSeparator({ className, ...props }: React.ComponentProps<typeof Command.Separator>): React.JSX.Element;
|
|
16
|
+
declare function CommandItem({ className, ...props }: React.ComponentProps<typeof Command.Item>): React.JSX.Element;
|
|
17
|
+
declare function CommandShortcut({ className, ...props }: React.ComponentProps<"span">): React.JSX.Element;
|
|
18
|
+
export { Command$1 as Command, CommandDialog, CommandEmpty, CommandGroup, CommandInput, CommandItem, CommandList, CommandSeparator, CommandShortcut };
|
|
19
|
+
//# sourceMappingURL=command.d.ts.map
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { Dialog, DialogContent, DialogDescription, DialogHeader, DialogTitle } from "./dialog.js";
|
|
3
|
+
import { cn } from "../lib/utils.js";
|
|
4
|
+
import { jsx, jsxs } from "react/jsx-runtime";
|
|
5
|
+
import { SearchIcon } from "lucide-react";
|
|
6
|
+
import { Command } from "cmdk";
|
|
7
|
+
// src/components/command.tsx
|
|
8
|
+
function Command$1({ className, ...props }) {
|
|
9
|
+
return /* @__PURE__ */ jsx(Command, {
|
|
10
|
+
"data-slot": "command",
|
|
11
|
+
className: cn("flex h-full w-full flex-col overflow-hidden rounded-md bg-popover text-popover-foreground", className),
|
|
12
|
+
...props
|
|
13
|
+
});
|
|
14
|
+
}
|
|
15
|
+
function CommandDialog({ title = "Command Palette", description = "Search for a command to run...", children, className, showCloseButton = true, ...props }) {
|
|
16
|
+
return /* @__PURE__ */ jsxs(Dialog, {
|
|
17
|
+
...props,
|
|
18
|
+
children: [/* @__PURE__ */ jsxs(DialogHeader, {
|
|
19
|
+
className: "sr-only",
|
|
20
|
+
children: [/* @__PURE__ */ jsx(DialogTitle, { children: title }), /* @__PURE__ */ jsx(DialogDescription, { children: description })]
|
|
21
|
+
}), /* @__PURE__ */ jsx(DialogContent, {
|
|
22
|
+
className: cn("overflow-hidden p-0", className),
|
|
23
|
+
showCloseButton,
|
|
24
|
+
children: /* @__PURE__ */ jsx(Command$1, {
|
|
25
|
+
className: "**:data-[slot=command-input-wrapper]:h-12 [&_[cmdk-group-heading]]:px-2 [&_[cmdk-group-heading]]:font-medium [&_[cmdk-group-heading]]:text-muted-foreground [&_[cmdk-group]]:px-2 [&_[cmdk-group]:not([hidden])_~[cmdk-group]]:pt-0 [&_[cmdk-input-wrapper]_svg]:h-5 [&_[cmdk-input-wrapper]_svg]:w-5 [&_[cmdk-input]]:h-12 [&_[cmdk-item]]:px-2 [&_[cmdk-item]]:py-3 [&_[cmdk-item]_svg]:h-5 [&_[cmdk-item]_svg]:w-5",
|
|
26
|
+
children
|
|
27
|
+
})
|
|
28
|
+
})]
|
|
29
|
+
});
|
|
30
|
+
}
|
|
31
|
+
function CommandInput({ className, ...props }) {
|
|
32
|
+
return /* @__PURE__ */ jsxs("div", {
|
|
33
|
+
"data-slot": "command-input-wrapper",
|
|
34
|
+
className: "flex h-9 items-center gap-2 border-b px-3",
|
|
35
|
+
children: [/* @__PURE__ */ jsx(SearchIcon, { className: "size-4 shrink-0 opacity-50" }), /* @__PURE__ */ jsx(Command.Input, {
|
|
36
|
+
"data-slot": "command-input",
|
|
37
|
+
className: cn("flex h-10 w-full rounded-md bg-transparent py-3 text-body-md outline-hidden sm:text-body-sm placeholder:text-muted-foreground disabled:cursor-not-allowed disabled:opacity-50", className),
|
|
38
|
+
...props
|
|
39
|
+
})]
|
|
40
|
+
});
|
|
41
|
+
}
|
|
42
|
+
function CommandList({ className, ...props }) {
|
|
43
|
+
return /* @__PURE__ */ jsx(Command.List, {
|
|
44
|
+
"data-slot": "command-list",
|
|
45
|
+
className: cn("max-h-[300px] scroll-py-1 overflow-x-hidden overflow-y-auto", className),
|
|
46
|
+
...props
|
|
47
|
+
});
|
|
48
|
+
}
|
|
49
|
+
function CommandEmpty({ ...props }) {
|
|
50
|
+
return /* @__PURE__ */ jsx(Command.Empty, {
|
|
51
|
+
"data-slot": "command-empty",
|
|
52
|
+
className: "py-6 text-center text-sm",
|
|
53
|
+
...props
|
|
54
|
+
});
|
|
55
|
+
}
|
|
56
|
+
function CommandGroup({ className, ...props }) {
|
|
57
|
+
return /* @__PURE__ */ jsx(Command.Group, {
|
|
58
|
+
"data-slot": "command-group",
|
|
59
|
+
className: cn("overflow-hidden p-1 text-foreground [&_[cmdk-group-heading]]:px-2 [&_[cmdk-group-heading]]:py-1.5 [&_[cmdk-group-heading]]:text-xs [&_[cmdk-group-heading]]:font-medium [&_[cmdk-group-heading]]:text-muted-foreground", className),
|
|
60
|
+
...props
|
|
61
|
+
});
|
|
62
|
+
}
|
|
63
|
+
function CommandSeparator({ className, ...props }) {
|
|
64
|
+
return /* @__PURE__ */ jsx(Command.Separator, {
|
|
65
|
+
"data-slot": "command-separator",
|
|
66
|
+
className: cn("-mx-1 h-px bg-border", className),
|
|
67
|
+
...props
|
|
68
|
+
});
|
|
69
|
+
}
|
|
70
|
+
function CommandItem({ className, ...props }) {
|
|
71
|
+
return /* @__PURE__ */ jsx(Command.Item, {
|
|
72
|
+
"data-slot": "command-item",
|
|
73
|
+
className: cn("relative flex cursor-default items-center gap-2 rounded-sm px-2 py-1.5 text-sm outline-hidden select-none data-[disabled=true]:pointer-events-none data-[disabled=true]:opacity-50 data-[selected=true]:bg-accent data-[selected=true]:text-accent-foreground [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4 [&_svg:not([class*='text-'])]:text-muted-foreground", className),
|
|
74
|
+
...props
|
|
75
|
+
});
|
|
76
|
+
}
|
|
77
|
+
function CommandShortcut({ className, ...props }) {
|
|
78
|
+
return /* @__PURE__ */ jsx("span", {
|
|
79
|
+
"data-slot": "command-shortcut",
|
|
80
|
+
className: cn("ml-auto text-xs tracking-widest text-muted-foreground", className),
|
|
81
|
+
...props
|
|
82
|
+
});
|
|
83
|
+
}
|
|
84
|
+
export { Command$1 as Command, CommandDialog, CommandEmpty, CommandGroup, CommandInput, CommandItem, CommandList, CommandSeparator, CommandShortcut };
|
|
85
|
+
|
|
86
|
+
//# sourceMappingURL=command.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"command.js","names":["Command","CommandPrimitive"],"sources":["../../src/components/command.tsx"],"sourcesContent":["\"use client\";\n\nimport { Dialog, DialogContent, DialogDescription, DialogHeader, DialogTitle } from \"./dialog\";\nimport { cn } from \"../lib/utils\";\nimport { Command as CommandPrimitive } from \"cmdk\";\nimport { SearchIcon } from \"lucide-react\";\nimport type * as React from \"react\";\n\nfunction Command({ className, ...props }: React.ComponentProps<typeof CommandPrimitive>) {\n return (\n <CommandPrimitive\n data-slot=\"command\"\n className={cn(\n \"flex h-full w-full flex-col overflow-hidden rounded-md bg-popover text-popover-foreground\",\n className,\n )}\n {...props}\n />\n );\n}\n\nfunction CommandDialog({\n title = \"Command Palette\",\n description = \"Search for a command to run...\",\n children,\n className,\n showCloseButton = true,\n ...props\n}: React.ComponentProps<typeof Dialog> & {\n title?: string;\n description?: string;\n className?: string;\n showCloseButton?: boolean;\n}) {\n return (\n <Dialog {...props}>\n <DialogHeader className=\"sr-only\">\n <DialogTitle>{title}</DialogTitle>\n <DialogDescription>{description}</DialogDescription>\n </DialogHeader>\n <DialogContent\n className={cn(\"overflow-hidden p-0\", className)}\n showCloseButton={showCloseButton}\n >\n <Command className=\"**:data-[slot=command-input-wrapper]:h-12 [&_[cmdk-group-heading]]:px-2 [&_[cmdk-group-heading]]:font-medium [&_[cmdk-group-heading]]:text-muted-foreground [&_[cmdk-group]]:px-2 [&_[cmdk-group]:not([hidden])_~[cmdk-group]]:pt-0 [&_[cmdk-input-wrapper]_svg]:h-5 [&_[cmdk-input-wrapper]_svg]:w-5 [&_[cmdk-input]]:h-12 [&_[cmdk-item]]:px-2 [&_[cmdk-item]]:py-3 [&_[cmdk-item]_svg]:h-5 [&_[cmdk-item]_svg]:w-5\">\n {children}\n </Command>\n </DialogContent>\n </Dialog>\n );\n}\n\nfunction CommandInput({\n className,\n ...props\n}: React.ComponentProps<typeof CommandPrimitive.Input>) {\n return (\n <div data-slot=\"command-input-wrapper\" className=\"flex h-9 items-center gap-2 border-b px-3\">\n <SearchIcon className=\"size-4 shrink-0 opacity-50\" />\n <CommandPrimitive.Input\n data-slot=\"command-input\"\n className={cn(\n \"flex h-10 w-full rounded-md bg-transparent py-3 text-body-md outline-hidden sm:text-body-sm placeholder:text-muted-foreground disabled:cursor-not-allowed disabled:opacity-50\",\n className,\n )}\n {...props}\n />\n </div>\n );\n}\n\nfunction CommandList({ className, ...props }: React.ComponentProps<typeof CommandPrimitive.List>) {\n return (\n <CommandPrimitive.List\n data-slot=\"command-list\"\n className={cn(\"max-h-[300px] scroll-py-1 overflow-x-hidden overflow-y-auto\", className)}\n {...props}\n />\n );\n}\n\nfunction CommandEmpty({ ...props }: React.ComponentProps<typeof CommandPrimitive.Empty>) {\n return (\n <CommandPrimitive.Empty\n data-slot=\"command-empty\"\n className=\"py-6 text-center text-sm\"\n {...props}\n />\n );\n}\n\nfunction CommandGroup({\n className,\n ...props\n}: React.ComponentProps<typeof CommandPrimitive.Group>) {\n return (\n <CommandPrimitive.Group\n data-slot=\"command-group\"\n className={cn(\n \"overflow-hidden p-1 text-foreground [&_[cmdk-group-heading]]:px-2 [&_[cmdk-group-heading]]:py-1.5 [&_[cmdk-group-heading]]:text-xs [&_[cmdk-group-heading]]:font-medium [&_[cmdk-group-heading]]:text-muted-foreground\",\n className,\n )}\n {...props}\n />\n );\n}\n\nfunction CommandSeparator({\n className,\n ...props\n}: React.ComponentProps<typeof CommandPrimitive.Separator>) {\n return (\n <CommandPrimitive.Separator\n data-slot=\"command-separator\"\n className={cn(\"-mx-1 h-px bg-border\", className)}\n {...props}\n />\n );\n}\n\nfunction CommandItem({ className, ...props }: React.ComponentProps<typeof CommandPrimitive.Item>) {\n return (\n <CommandPrimitive.Item\n data-slot=\"command-item\"\n className={cn(\n \"relative flex cursor-default items-center gap-2 rounded-sm px-2 py-1.5 text-sm outline-hidden select-none data-[disabled=true]:pointer-events-none data-[disabled=true]:opacity-50 data-[selected=true]:bg-accent data-[selected=true]:text-accent-foreground [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4 [&_svg:not([class*='text-'])]:text-muted-foreground\",\n className,\n )}\n {...props}\n />\n );\n}\n\nfunction CommandShortcut({ className, ...props }: React.ComponentProps<\"span\">) {\n return (\n <span\n data-slot=\"command-shortcut\"\n className={cn(\"ml-auto text-xs tracking-widest text-muted-foreground\", className)}\n {...props}\n />\n );\n}\n\nexport {\n Command,\n CommandDialog,\n CommandEmpty,\n CommandGroup,\n CommandInput,\n CommandItem,\n CommandList,\n CommandSeparator,\n CommandShortcut,\n};\n"],"mappings":";;;;;;;AAQA,SAASA,UAAQ,EAAE,WAAW,GAAG,SAAwD;CACvF,OACE,oBAACC,SAAD;EACE,aAAU;EACV,WAAW,GACT,6FACA,SACF;EACA,GAAI;CACL,CAAA;AAEL;AAEA,SAAS,cAAc,EACrB,QAAQ,mBACR,cAAc,kCACd,UACA,WACA,kBAAkB,MAClB,GAAG,SAMF;CACD,OACE,qBAAC,QAAD;EAAQ,GAAI;EAAZ,UAAA,CACE,qBAAC,cAAD;GAAc,WAAU;GAAxB,UAAA,CACE,oBAAC,aAAD,EAAA,UAAc,MAAmB,CAAA,GACjC,oBAAC,mBAAD,EAAA,UAAoB,YAA+B,CAAA,CACvC;EACd,CAAA,GAAA,oBAAC,eAAD;GACE,WAAW,GAAG,uBAAuB,SAAS;GAC7B;GAEjB,UAAA,oBAACD,WAAD;IAAS,WAAU;IAChB;GACM,CAAA;EACI,CAAA,CACT;;AAEZ;AAEA,SAAS,aAAa,EACpB,WACA,GAAG,SACmD;CACtD,OACE,qBAAC,OAAD;EAAK,aAAU;EAAwB,WAAU;EAAjD,UAAA,CACE,oBAAC,YAAD,EAAY,WAAU,6BAA8B,CAAA,GACpD,oBAACC,QAAiB,OAAlB;GACE,aAAU;GACV,WAAW,GACT,iLACA,SACF;GACA,GAAI;EACL,CAAA,CACE;;AAET;AAEA,SAAS,YAAY,EAAE,WAAW,GAAG,SAA6D;CAChG,OACE,oBAACA,QAAiB,MAAlB;EACE,aAAU;EACV,WAAW,GAAG,+DAA+D,SAAS;EACtF,GAAI;CACL,CAAA;AAEL;AAEA,SAAS,aAAa,EAAE,GAAG,SAA8D;CACvF,OACE,oBAACA,QAAiB,OAAlB;EACE,aAAU;EACV,WAAU;EACV,GAAI;CACL,CAAA;AAEL;AAEA,SAAS,aAAa,EACpB,WACA,GAAG,SACmD;CACtD,OACE,oBAACA,QAAiB,OAAlB;EACE,aAAU;EACV,WAAW,GACT,0NACA,SACF;EACA,GAAI;CACL,CAAA;AAEL;AAEA,SAAS,iBAAiB,EACxB,WACA,GAAG,SACuD;CAC1D,OACE,oBAACA,QAAiB,WAAlB;EACE,aAAU;EACV,WAAW,GAAG,wBAAwB,SAAS;EAC/C,GAAI;CACL,CAAA;AAEL;AAEA,SAAS,YAAY,EAAE,WAAW,GAAG,SAA6D;CAChG,OACE,oBAACA,QAAiB,MAAlB;EACE,aAAU;EACV,WAAW,GACT,uYACA,SACF;EACA,GAAI;CACL,CAAA;AAEL;AAEA,SAAS,gBAAgB,EAAE,WAAW,GAAG,SAAuC;CAC9E,OACE,oBAAC,QAAD;EACE,aAAU;EACV,WAAW,GAAG,yDAAyD,SAAS;EAChF,GAAI;CACL,CAAA;AAEL"}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import * as React from "react";
|
|
2
|
+
export type CtaBannerProps = {
|
|
3
|
+
title: React.ReactNode;
|
|
4
|
+
id?: string;
|
|
5
|
+
text?: React.ReactNode;
|
|
6
|
+
/** Microprint above the title, e.g. "S-05 · START". */
|
|
7
|
+
code?: string;
|
|
8
|
+
/** The call to action, usually a secondary Button (shell on signal). */
|
|
9
|
+
action?: React.ReactNode;
|
|
10
|
+
className?: string;
|
|
11
|
+
};
|
|
12
|
+
/** The whole-signal call to action that closes a page. Text on it is ink, never white. */
|
|
13
|
+
export declare function CtaBanner({ title, id, text, code, action, className }: CtaBannerProps): React.JSX.Element;
|
|
14
|
+
//# sourceMappingURL=cta-banner.d.ts.map
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import { cn } from "../lib/utils.js";
|
|
2
|
+
import { Grill } from "./hud.js";
|
|
3
|
+
import { jsx, jsxs } from "react/jsx-runtime";
|
|
4
|
+
// src/components/cta-banner.tsx
|
|
5
|
+
/** The whole-signal call to action that closes a page. Text on it is ink, never white. */
|
|
6
|
+
function CtaBanner({ title, id, text, code, action, className }) {
|
|
7
|
+
return /* @__PURE__ */ jsx("section", {
|
|
8
|
+
id,
|
|
9
|
+
className: cn("relative drop-float", className),
|
|
10
|
+
children: /* @__PURE__ */ jsxs("div", {
|
|
11
|
+
className: "grid items-end gap-8 rounded-xl bg-signal notch-lg p-8 md:grid-cols-[1fr_auto] md:p-12",
|
|
12
|
+
children: [/* @__PURE__ */ jsxs("div", { children: [
|
|
13
|
+
code && /* @__PURE__ */ jsx("div", {
|
|
14
|
+
className: "hud-sm mb-4 text-ink",
|
|
15
|
+
children: code
|
|
16
|
+
}),
|
|
17
|
+
/* @__PURE__ */ jsx("h2", {
|
|
18
|
+
className: "font-display text-display-md text-ink",
|
|
19
|
+
children: title
|
|
20
|
+
}),
|
|
21
|
+
text && /* @__PURE__ */ jsx("p", {
|
|
22
|
+
className: "mt-3 max-w-[32em] text-body-md text-ink",
|
|
23
|
+
children: text
|
|
24
|
+
})
|
|
25
|
+
] }), /* @__PURE__ */ jsxs("div", {
|
|
26
|
+
className: "flex flex-col items-start gap-6 md:items-end",
|
|
27
|
+
children: [/* @__PURE__ */ jsx(Grill, {
|
|
28
|
+
count: 6,
|
|
29
|
+
tone: "on-signal",
|
|
30
|
+
slotWidth: 30,
|
|
31
|
+
gap: "8px"
|
|
32
|
+
}), action]
|
|
33
|
+
})]
|
|
34
|
+
})
|
|
35
|
+
});
|
|
36
|
+
}
|
|
37
|
+
export { CtaBanner };
|
|
38
|
+
|
|
39
|
+
//# sourceMappingURL=cta-banner.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cta-banner.js","names":[],"sources":["../../src/components/cta-banner.tsx"],"sourcesContent":["import type * as React from \"react\";\nimport { cn } from \"../lib/utils\";\nimport { Grill } from \"./hud\";\n\nexport type CtaBannerProps = {\n title: React.ReactNode;\n id?: string;\n text?: React.ReactNode;\n /** Microprint above the title, e.g. \"S-05 · START\". */\n code?: string;\n /** The call to action, usually a secondary Button (shell on signal). */\n action?: React.ReactNode;\n className?: string;\n};\n\n/** The whole-signal call to action that closes a page. Text on it is ink, never white. */\nexport function CtaBanner({ title, id, text, code, action, className }: CtaBannerProps) {\n return (\n <section id={id} className={cn(\"relative drop-float\", className)}>\n <div className=\"grid items-end gap-8 rounded-xl bg-signal notch-lg p-8 md:grid-cols-[1fr_auto] md:p-12\">\n <div>\n {code && <div className=\"hud-sm mb-4 text-ink\">{code}</div>}\n <h2 className=\"font-display text-display-md text-ink\">{title}</h2>\n {text && <p className=\"mt-3 max-w-[32em] text-body-md text-ink\">{text}</p>}\n </div>\n <div className=\"flex flex-col items-start gap-6 md:items-end\">\n <Grill count={6} tone=\"on-signal\" slotWidth={30} gap=\"8px\" />\n {action}\n </div>\n </div>\n </section>\n );\n}\n"],"mappings":";;;;;AAgBA,SAAgB,UAAU,EAAE,OAAO,IAAI,MAAM,MAAM,QAAQ,aAA6B;CACtF,OACE,oBAAC,WAAD;EAAa;EAAI,WAAW,GAAG,uBAAuB,SAAS;EAC7D,UAAA,qBAAC,OAAD;GAAK,WAAU;GAAf,UAAA,CACE,qBAAC,OAAD,EAAA,UAAA;IACG,QAAQ,oBAAC,OAAD;KAAK,WAAU;KAAwB,UAAA;IAAU,CAAA;IAC1D,oBAAC,MAAD;KAAI,WAAU;KAAyC,UAAA;IAAU,CAAA;IAChE,QAAQ,oBAAC,KAAD;KAAG,WAAU;KAA2C,UAAA;IAAQ,CAAA;GACtE,EAAA,CAAA,GACL,qBAAC,OAAD;IAAK,WAAU;IAAf,UAAA,CACE,oBAAC,OAAD;KAAO,OAAO;KAAG,MAAK;KAAY,WAAW;KAAI,KAAI;IAAO,CAAA,GAC3D,MACE;GACF,CAAA,CAAA;;CACE,CAAA;AAEb"}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
/** "YYYY-MM-DD" -> local Date (no time-zone shift). */
|
|
2
|
+
export declare function parseISODate(value: string): Date | undefined;
|
|
3
|
+
/** Local Date -> "YYYY-MM-DD". */
|
|
4
|
+
export declare function toISODate(date: Date): string;
|
|
5
|
+
/** Short field label: "Today, Oct 29", "Yesterday, Oct 28", "Tue, Oct 20", "Mon, Dec 1, 2025". */
|
|
6
|
+
export declare function dateLabel(date: Date, today: Date): string;
|
|
7
|
+
/**
|
|
8
|
+
* A calendar date in a sunken well, opening a Module/01 Calendar with Today and Yesterday
|
|
9
|
+
* shortcuts. Value and onChange use "YYYY-MM-DD" strings.
|
|
10
|
+
*/
|
|
11
|
+
export declare function DatePicker({ id, value, onChange, placeholder, disabled, className }: {
|
|
12
|
+
id?: string;
|
|
13
|
+
value: string;
|
|
14
|
+
onChange: (value: string) => void;
|
|
15
|
+
placeholder?: string;
|
|
16
|
+
disabled?: boolean;
|
|
17
|
+
className?: string;
|
|
18
|
+
}): import("react").JSX.Element;
|
|
19
|
+
//# sourceMappingURL=date-picker.d.ts.map
|
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { focusNextField } from "../lib/form-flow.js";
|
|
3
|
+
import { cn } from "../lib/utils.js";
|
|
4
|
+
import { Button } from "./button.js";
|
|
5
|
+
import { Calendar } from "./calendar.js";
|
|
6
|
+
import { Popover, PopoverContent, PopoverTrigger } from "./popover.js";
|
|
7
|
+
import { jsx, jsxs } from "react/jsx-runtime";
|
|
8
|
+
import { CalendarDays } from "lucide-react";
|
|
9
|
+
import { useRef, useState } from "react";
|
|
10
|
+
import { addDays, format, isSameDay } from "date-fns";
|
|
11
|
+
// src/components/date-picker.tsx
|
|
12
|
+
/** "YYYY-MM-DD" -> local Date (no time-zone shift). */
|
|
13
|
+
function parseISODate(value) {
|
|
14
|
+
const m = /^(\d{4})-(\d{2})-(\d{2})$/.exec(value);
|
|
15
|
+
if (!m) return void 0;
|
|
16
|
+
return new Date(Number(m[1]), Number(m[2]) - 1, Number(m[3]));
|
|
17
|
+
}
|
|
18
|
+
/** Local Date -> "YYYY-MM-DD". */
|
|
19
|
+
function toISODate(date) {
|
|
20
|
+
return format(date, "yyyy-MM-dd");
|
|
21
|
+
}
|
|
22
|
+
/** Short field label: "Today, Oct 29", "Yesterday, Oct 28", "Tue, Oct 20", "Mon, Dec 1, 2025". */
|
|
23
|
+
function dateLabel(date, today) {
|
|
24
|
+
if (isSameDay(date, today)) return `Today, ${format(date, "MMM d")}`;
|
|
25
|
+
if (isSameDay(date, addDays(today, -1))) return `Yesterday, ${format(date, "MMM d")}`;
|
|
26
|
+
return format(date, date.getFullYear() === today.getFullYear() ? "EEE, MMM d" : "EEE, MMM d, yyyy");
|
|
27
|
+
}
|
|
28
|
+
/**
|
|
29
|
+
* A calendar date in a sunken well, opening a Module/01 Calendar with Today and Yesterday
|
|
30
|
+
* shortcuts. Value and onChange use "YYYY-MM-DD" strings.
|
|
31
|
+
*/
|
|
32
|
+
function DatePicker({ id, value, onChange, placeholder = "Pick a date", disabled, className }) {
|
|
33
|
+
const [open, setOpen] = useState(false);
|
|
34
|
+
const selected = parseISODate(value);
|
|
35
|
+
const [month, setMonth] = useState(selected ?? /* @__PURE__ */ new Date());
|
|
36
|
+
const today = /* @__PURE__ */ new Date();
|
|
37
|
+
const trigger = useRef(null);
|
|
38
|
+
const committed = useRef(false);
|
|
39
|
+
function openChange(next) {
|
|
40
|
+
if (next) setMonth(selected ?? /* @__PURE__ */ new Date());
|
|
41
|
+
setOpen(next);
|
|
42
|
+
}
|
|
43
|
+
function pick(date) {
|
|
44
|
+
onChange(toISODate(date));
|
|
45
|
+
committed.current = true;
|
|
46
|
+
setOpen(false);
|
|
47
|
+
}
|
|
48
|
+
const label = selected ? dateLabel(selected, today) : placeholder;
|
|
49
|
+
return /* @__PURE__ */ jsxs(Popover, {
|
|
50
|
+
open,
|
|
51
|
+
onOpenChange: openChange,
|
|
52
|
+
children: [/* @__PURE__ */ jsx(PopoverTrigger, {
|
|
53
|
+
asChild: true,
|
|
54
|
+
children: /* @__PURE__ */ jsxs("button", {
|
|
55
|
+
ref: trigger,
|
|
56
|
+
"data-flow-field": true,
|
|
57
|
+
id,
|
|
58
|
+
type: "button",
|
|
59
|
+
disabled,
|
|
60
|
+
className: cn("flex h-control-height w-full min-w-0 cursor-pointer items-center gap-3 rounded-md border border-transparent bg-shell-recess px-4 text-left text-body-md text-ink shadow-press outline-none transition-[box-shadow,border-color] disabled:pointer-events-none disabled:opacity-50", "focus-visible:border-signal-ink focus-visible:ring-[3px] focus-visible:ring-ring/30 data-[state=open]:border-signal-ink", className),
|
|
61
|
+
children: [/* @__PURE__ */ jsx(CalendarDays, {
|
|
62
|
+
className: "size-4 shrink-0 text-ink-soft",
|
|
63
|
+
strokeWidth: 1.25
|
|
64
|
+
}), /* @__PURE__ */ jsx("span", {
|
|
65
|
+
className: cn("truncate", !selected && "text-ink-soft"),
|
|
66
|
+
children: label
|
|
67
|
+
})]
|
|
68
|
+
})
|
|
69
|
+
}), /* @__PURE__ */ jsxs(PopoverContent, {
|
|
70
|
+
align: "start",
|
|
71
|
+
className: "w-auto rounded-lg p-3",
|
|
72
|
+
onCloseAutoFocus: (e) => {
|
|
73
|
+
if (!committed.current) return;
|
|
74
|
+
committed.current = false;
|
|
75
|
+
e.preventDefault();
|
|
76
|
+
focusNextField(trigger.current);
|
|
77
|
+
},
|
|
78
|
+
children: [/* @__PURE__ */ jsx(Calendar, {
|
|
79
|
+
mode: "single",
|
|
80
|
+
required: true,
|
|
81
|
+
selected,
|
|
82
|
+
onSelect: pick,
|
|
83
|
+
month,
|
|
84
|
+
onMonthChange: setMonth,
|
|
85
|
+
autoFocus: true
|
|
86
|
+
}), /* @__PURE__ */ jsxs("div", {
|
|
87
|
+
className: "mt-3 flex gap-2 border-t border-seam pt-3",
|
|
88
|
+
children: [/* @__PURE__ */ jsx(Button, {
|
|
89
|
+
type: "button",
|
|
90
|
+
size: "xs",
|
|
91
|
+
variant: "secondary",
|
|
92
|
+
onClick: () => pick(today),
|
|
93
|
+
children: "Today"
|
|
94
|
+
}), /* @__PURE__ */ jsx(Button, {
|
|
95
|
+
type: "button",
|
|
96
|
+
size: "xs",
|
|
97
|
+
variant: "secondary",
|
|
98
|
+
onClick: () => pick(addDays(today, -1)),
|
|
99
|
+
children: "Yesterday"
|
|
100
|
+
})]
|
|
101
|
+
})]
|
|
102
|
+
})]
|
|
103
|
+
});
|
|
104
|
+
}
|
|
105
|
+
export { DatePicker, dateLabel, parseISODate, toISODate };
|
|
106
|
+
|
|
107
|
+
//# sourceMappingURL=date-picker.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"date-picker.js","names":[],"sources":["../../src/components/date-picker.tsx"],"sourcesContent":["\"use client\";\n\nimport { focusNextField } from \"../lib/form-flow\";\nimport { cn } from \"../lib/utils\";\nimport { addDays, format, isSameDay } from \"date-fns\";\nimport { CalendarDays } from \"lucide-react\";\nimport { useRef, useState } from \"react\";\nimport { Button } from \"./button\";\nimport { Calendar } from \"./calendar\";\nimport { Popover, PopoverContent, PopoverTrigger } from \"./popover\";\n\n/** \"YYYY-MM-DD\" -> local Date (no time-zone shift). */\nexport function parseISODate(value: string): Date | undefined {\n const m = /^(\\d{4})-(\\d{2})-(\\d{2})$/.exec(value);\n if (!m) return undefined;\n return new Date(Number(m[1]), Number(m[2]) - 1, Number(m[3]));\n}\n\n/** Local Date -> \"YYYY-MM-DD\". */\nexport function toISODate(date: Date): string {\n return format(date, \"yyyy-MM-dd\");\n}\n\n/** Short field label: \"Today, Oct 29\", \"Yesterday, Oct 28\", \"Tue, Oct 20\", \"Mon, Dec 1, 2025\". */\nexport function dateLabel(date: Date, today: Date): string {\n if (isSameDay(date, today)) return `Today, ${format(date, \"MMM d\")}`;\n if (isSameDay(date, addDays(today, -1))) return `Yesterday, ${format(date, \"MMM d\")}`;\n return format(\n date,\n date.getFullYear() === today.getFullYear() ? \"EEE, MMM d\" : \"EEE, MMM d, yyyy\",\n );\n}\n\n/**\n * A calendar date in a sunken well, opening a Module/01 Calendar with Today and Yesterday\n * shortcuts. Value and onChange use \"YYYY-MM-DD\" strings.\n */\nexport function DatePicker({\n id,\n value,\n onChange,\n placeholder = \"Pick a date\",\n disabled,\n className,\n}: {\n id?: string;\n value: string;\n onChange: (value: string) => void;\n placeholder?: string;\n disabled?: boolean;\n className?: string;\n}) {\n const [open, setOpen] = useState(false);\n const selected = parseISODate(value);\n const [month, setMonth] = useState<Date>(selected ?? new Date());\n const today = new Date();\n const trigger = useRef<HTMLButtonElement>(null);\n const committed = useRef(false);\n\n function openChange(next: boolean) {\n if (next) setMonth(selected ?? new Date());\n setOpen(next);\n }\n\n function pick(date: Date) {\n onChange(toISODate(date));\n committed.current = true;\n setOpen(false);\n }\n\n const label = selected ? dateLabel(selected, today) : placeholder;\n\n return (\n <Popover open={open} onOpenChange={openChange}>\n <PopoverTrigger asChild>\n <button\n ref={trigger}\n data-flow-field\n id={id}\n type=\"button\"\n disabled={disabled}\n className={cn(\n \"flex h-control-height w-full min-w-0 cursor-pointer items-center gap-3 rounded-md border border-transparent bg-shell-recess px-4 text-left text-body-md text-ink shadow-press outline-none transition-[box-shadow,border-color] disabled:pointer-events-none disabled:opacity-50\",\n \"focus-visible:border-signal-ink focus-visible:ring-[3px] focus-visible:ring-ring/30 data-[state=open]:border-signal-ink\",\n className,\n )}\n >\n <CalendarDays className=\"size-4 shrink-0 text-ink-soft\" strokeWidth={1.25} />\n <span className={cn(\"truncate\", !selected && \"text-ink-soft\")}>{label}</span>\n </button>\n </PopoverTrigger>\n <PopoverContent\n align=\"start\"\n className=\"w-auto rounded-lg p-3\"\n onCloseAutoFocus={(e) => {\n // Form flow: after picking a date, move on to the next field.\n if (!committed.current) return;\n committed.current = false;\n e.preventDefault();\n focusNextField(trigger.current);\n }}\n >\n <Calendar\n mode=\"single\"\n required\n selected={selected}\n onSelect={pick}\n month={month}\n onMonthChange={setMonth}\n autoFocus\n />\n <div className=\"mt-3 flex gap-2 border-t border-seam pt-3\">\n <Button type=\"button\" size=\"xs\" variant=\"secondary\" onClick={() => pick(today)}>\n Today\n </Button>\n <Button\n type=\"button\"\n size=\"xs\"\n variant=\"secondary\"\n onClick={() => pick(addDays(today, -1))}\n >\n Yesterday\n </Button>\n </div>\n </PopoverContent>\n </Popover>\n );\n}\n"],"mappings":";;;;;;;;;;;;AAYA,SAAgB,aAAa,OAAiC;CAC5D,MAAM,IAAI,4BAA4B,KAAK,KAAK;CAChD,IAAI,CAAC,GAAG,OAAO,KAAA;CACf,OAAO,IAAI,KAAK,OAAO,EAAE,EAAE,GAAG,OAAO,EAAE,EAAE,IAAI,GAAG,OAAO,EAAE,EAAE,CAAC;AAC9D;;AAGA,SAAgB,UAAU,MAAoB;CAC5C,OAAO,OAAO,MAAM,YAAY;AAClC;;AAGA,SAAgB,UAAU,MAAY,OAAqB;CACzD,IAAI,UAAU,MAAM,KAAK,GAAG,OAAO,UAAU,OAAO,MAAM,OAAO;CACjE,IAAI,UAAU,MAAM,QAAQ,OAAO,EAAE,CAAC,GAAG,OAAO,cAAc,OAAO,MAAM,OAAO;CAClF,OAAO,OACL,MACA,KAAK,YAAY,MAAM,MAAM,YAAY,IAAI,eAAe,kBAC9D;AACF;;;;;AAMA,SAAgB,WAAW,EACzB,IACA,OACA,UACA,cAAc,eACd,UACA,aAQC;CACD,MAAM,CAAC,MAAM,WAAW,SAAS,KAAK;CACtC,MAAM,WAAW,aAAa,KAAK;CACnC,MAAM,CAAC,OAAO,YAAY,SAAe,4BAAY,IAAI,KAAK,CAAC;CAC/D,MAAM,wBAAQ,IAAI,KAAK;CACvB,MAAM,UAAU,OAA0B,IAAI;CAC9C,MAAM,YAAY,OAAO,KAAK;CAE9B,SAAS,WAAW,MAAe;EACjC,IAAI,MAAM,SAAS,4BAAY,IAAI,KAAK,CAAC;EACzC,QAAQ,IAAI;CACd;CAEA,SAAS,KAAK,MAAY;EACxB,SAAS,UAAU,IAAI,CAAC;EACxB,UAAU,UAAU;EACpB,QAAQ,KAAK;CACf;CAEA,MAAM,QAAQ,WAAW,UAAU,UAAU,KAAK,IAAI;CAEtD,OACE,qBAAC,SAAD;EAAe;EAAM,cAAc;EAAnC,UAAA,CACE,oBAAC,gBAAD;GAAgB,SAAA;GACd,UAAA,qBAAC,UAAD;IACE,KAAK;IACL,mBAAA;IACI;IACJ,MAAK;IACK;IACV,WAAW,GACT,oRACA,2HACA,SACF;IAVF,UAAA,CAYE,oBAAC,cAAD;KAAc,WAAU;KAAgC,aAAa;IAAO,CAAA,GAC5E,oBAAC,QAAD;KAAM,WAAW,GAAG,YAAY,CAAC,YAAY,eAAe;KAAI,UAAA;IAAY,CAAA,CACtE;;EACM,CAAA,GAChB,qBAAC,gBAAD;GACE,OAAM;GACN,WAAU;GACV,mBAAmB,MAAM;IAEvB,IAAI,CAAC,UAAU,SAAS;IACxB,UAAU,UAAU;IACpB,EAAE,eAAe;IACjB,eAAe,QAAQ,OAAO;GAChC;GATF,UAAA,CAWE,oBAAC,UAAD;IACE,MAAK;IACL,UAAA;IACU;IACV,UAAU;IACH;IACP,eAAe;IACf,WAAA;GACD,CAAA,GACD,qBAAC,OAAD;IAAK,WAAU;IAAf,UAAA,CACE,oBAAC,QAAD;KAAQ,MAAK;KAAS,MAAK;KAAK,SAAQ;KAAY,eAAe,KAAK,KAAK;KAAG,UAAA;IAExE,CAAA,GACR,oBAAC,QAAD;KACE,MAAK;KACL,MAAK;KACL,SAAQ;KACR,eAAe,KAAK,QAAQ,OAAO,EAAE,CAAC;KACvC,UAAA;IAEO,CAAA,CACL;GACS,CAAA,CAAA;EACT,CAAA,CAAA;;AAEb"}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { Dialog } from "radix-ui";
|
|
2
|
+
import * as React from "react";
|
|
3
|
+
declare function Dialog$1({ ...props }: React.ComponentProps<typeof Dialog.Root>): React.JSX.Element;
|
|
4
|
+
declare function DialogTrigger({ ...props }: React.ComponentProps<typeof Dialog.Trigger>): React.JSX.Element;
|
|
5
|
+
declare function DialogPortal({ ...props }: React.ComponentProps<typeof Dialog.Portal>): React.JSX.Element;
|
|
6
|
+
declare function DialogClose({ ...props }: React.ComponentProps<typeof Dialog.Close>): React.JSX.Element;
|
|
7
|
+
declare function DialogOverlay({ className, ...props }: React.ComponentProps<typeof Dialog.Overlay>): React.JSX.Element;
|
|
8
|
+
declare function DialogContent({ className, children, showCloseButton, onOpenAutoFocus, ...props }: React.ComponentProps<typeof Dialog.Content> & {
|
|
9
|
+
showCloseButton?: boolean;
|
|
10
|
+
}): React.JSX.Element;
|
|
11
|
+
declare function DialogHeader({ className, ...props }: React.ComponentProps<"div">): React.JSX.Element;
|
|
12
|
+
declare function DialogFooter({ className, showCloseButton, children, ...props }: React.ComponentProps<"div"> & {
|
|
13
|
+
showCloseButton?: boolean;
|
|
14
|
+
}): React.JSX.Element;
|
|
15
|
+
declare function DialogTitle({ className, ...props }: React.ComponentProps<typeof Dialog.Title>): React.JSX.Element;
|
|
16
|
+
declare function DialogDescription({ className, ...props }: React.ComponentProps<typeof Dialog.Description>): React.JSX.Element;
|
|
17
|
+
export { Dialog$1 as Dialog, DialogClose, DialogContent, DialogDescription, DialogFooter, DialogHeader, DialogOverlay, DialogPortal, DialogTitle, DialogTrigger };
|
|
18
|
+
//# sourceMappingURL=dialog.d.ts.map
|
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { Button } from "./button.js";
|
|
3
|
+
import { focusFirstField } from "../lib/form-flow.js";
|
|
4
|
+
import { cn } from "../lib/utils.js";
|
|
5
|
+
import { Dialog } from "radix-ui";
|
|
6
|
+
import { jsx, jsxs } from "react/jsx-runtime";
|
|
7
|
+
import { XIcon } from "lucide-react";
|
|
8
|
+
// src/components/dialog.tsx
|
|
9
|
+
function Dialog$1({ ...props }) {
|
|
10
|
+
return /* @__PURE__ */ jsx(Dialog.Root, {
|
|
11
|
+
"data-slot": "dialog",
|
|
12
|
+
...props
|
|
13
|
+
});
|
|
14
|
+
}
|
|
15
|
+
function DialogTrigger({ ...props }) {
|
|
16
|
+
return /* @__PURE__ */ jsx(Dialog.Trigger, {
|
|
17
|
+
"data-slot": "dialog-trigger",
|
|
18
|
+
...props
|
|
19
|
+
});
|
|
20
|
+
}
|
|
21
|
+
function DialogPortal({ ...props }) {
|
|
22
|
+
return /* @__PURE__ */ jsx(Dialog.Portal, {
|
|
23
|
+
"data-slot": "dialog-portal",
|
|
24
|
+
...props
|
|
25
|
+
});
|
|
26
|
+
}
|
|
27
|
+
function DialogClose({ ...props }) {
|
|
28
|
+
return /* @__PURE__ */ jsx(Dialog.Close, {
|
|
29
|
+
"data-slot": "dialog-close",
|
|
30
|
+
...props
|
|
31
|
+
});
|
|
32
|
+
}
|
|
33
|
+
function DialogOverlay({ className, ...props }) {
|
|
34
|
+
return /* @__PURE__ */ jsx(Dialog.Overlay, {
|
|
35
|
+
"data-slot": "dialog-overlay",
|
|
36
|
+
className: cn("fixed inset-0 z-50 bg-overlay data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:animate-in data-[state=open]:fade-in-0", className),
|
|
37
|
+
...props
|
|
38
|
+
});
|
|
39
|
+
}
|
|
40
|
+
function DialogContent({ className, children, showCloseButton = true, onOpenAutoFocus, ...props }) {
|
|
41
|
+
return /* @__PURE__ */ jsxs(DialogPortal, {
|
|
42
|
+
"data-slot": "dialog-portal",
|
|
43
|
+
children: [/* @__PURE__ */ jsx(DialogOverlay, {}), /* @__PURE__ */ jsxs(Dialog.Content, {
|
|
44
|
+
"data-slot": "dialog-content",
|
|
45
|
+
className: cn("fixed top-[50%] left-[50%] z-50 grid w-full max-w-[calc(100%-2rem)] translate-x-[-50%] translate-y-[-50%] gap-4 rounded-lg border bg-background p-6 shadow-float duration-200 outline-none data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=closed]:zoom-out-95 data-[state=open]:animate-in data-[state=open]:fade-in-0 data-[state=open]:zoom-in-95 sm:max-w-lg", className),
|
|
46
|
+
...props,
|
|
47
|
+
onOpenAutoFocus: (e) => {
|
|
48
|
+
onOpenAutoFocus?.(e);
|
|
49
|
+
if (!e.defaultPrevented && focusFirstField(e.currentTarget)) e.preventDefault();
|
|
50
|
+
},
|
|
51
|
+
children: [children, showCloseButton && /* @__PURE__ */ jsxs(Dialog.Close, {
|
|
52
|
+
"data-slot": "dialog-close",
|
|
53
|
+
className: "absolute top-4 right-4 rounded-xs opacity-70 ring-offset-background transition-opacity hover:opacity-100 focus:ring-2 focus:ring-ring focus:ring-offset-2 focus:outline-hidden disabled:pointer-events-none data-[state=open]:bg-accent data-[state=open]:text-muted-foreground [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4",
|
|
54
|
+
children: [/* @__PURE__ */ jsx(XIcon, {}), /* @__PURE__ */ jsx("span", {
|
|
55
|
+
className: "sr-only",
|
|
56
|
+
children: "Close"
|
|
57
|
+
})]
|
|
58
|
+
})]
|
|
59
|
+
})]
|
|
60
|
+
});
|
|
61
|
+
}
|
|
62
|
+
function DialogHeader({ className, ...props }) {
|
|
63
|
+
return /* @__PURE__ */ jsx("div", {
|
|
64
|
+
"data-slot": "dialog-header",
|
|
65
|
+
className: cn("flex flex-col gap-2 text-center sm:text-left", className),
|
|
66
|
+
...props
|
|
67
|
+
});
|
|
68
|
+
}
|
|
69
|
+
function DialogFooter({ className, showCloseButton = false, children, ...props }) {
|
|
70
|
+
return /* @__PURE__ */ jsxs("div", {
|
|
71
|
+
"data-slot": "dialog-footer",
|
|
72
|
+
className: cn("flex flex-col-reverse gap-2 sm:flex-row sm:justify-end", className),
|
|
73
|
+
...props,
|
|
74
|
+
children: [children, showCloseButton && /* @__PURE__ */ jsx(Dialog.Close, {
|
|
75
|
+
asChild: true,
|
|
76
|
+
children: /* @__PURE__ */ jsx(Button, {
|
|
77
|
+
variant: "outline",
|
|
78
|
+
children: "Close"
|
|
79
|
+
})
|
|
80
|
+
})]
|
|
81
|
+
});
|
|
82
|
+
}
|
|
83
|
+
function DialogTitle({ className, ...props }) {
|
|
84
|
+
return /* @__PURE__ */ jsx(Dialog.Title, {
|
|
85
|
+
"data-slot": "dialog-title",
|
|
86
|
+
className: cn("text-lg leading-none font-semibold", className),
|
|
87
|
+
...props
|
|
88
|
+
});
|
|
89
|
+
}
|
|
90
|
+
function DialogDescription({ className, ...props }) {
|
|
91
|
+
return /* @__PURE__ */ jsx(Dialog.Description, {
|
|
92
|
+
"data-slot": "dialog-description",
|
|
93
|
+
className: cn("text-sm text-muted-foreground", className),
|
|
94
|
+
...props
|
|
95
|
+
});
|
|
96
|
+
}
|
|
97
|
+
export { Dialog$1 as Dialog, DialogClose, DialogContent, DialogDescription, DialogFooter, DialogHeader, DialogOverlay, DialogPortal, DialogTitle, DialogTrigger };
|
|
98
|
+
|
|
99
|
+
//# sourceMappingURL=dialog.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"dialog.js","names":["Dialog","DialogPrimitive"],"sources":["../../src/components/dialog.tsx"],"sourcesContent":["\"use client\";\n\nimport { Button } from \"./button\";\nimport { focusFirstField } from \"../lib/form-flow\";\nimport { cn } from \"../lib/utils\";\nimport { XIcon } from \"lucide-react\";\nimport { Dialog as DialogPrimitive } from \"radix-ui\";\nimport type * as React from \"react\";\n\nfunction Dialog({ ...props }: React.ComponentProps<typeof DialogPrimitive.Root>) {\n return <DialogPrimitive.Root data-slot=\"dialog\" {...props} />;\n}\n\nfunction DialogTrigger({ ...props }: React.ComponentProps<typeof DialogPrimitive.Trigger>) {\n return <DialogPrimitive.Trigger data-slot=\"dialog-trigger\" {...props} />;\n}\n\nfunction DialogPortal({ ...props }: React.ComponentProps<typeof DialogPrimitive.Portal>) {\n return <DialogPrimitive.Portal data-slot=\"dialog-portal\" {...props} />;\n}\n\nfunction DialogClose({ ...props }: React.ComponentProps<typeof DialogPrimitive.Close>) {\n return <DialogPrimitive.Close data-slot=\"dialog-close\" {...props} />;\n}\n\nfunction DialogOverlay({\n className,\n ...props\n}: React.ComponentProps<typeof DialogPrimitive.Overlay>) {\n return (\n <DialogPrimitive.Overlay\n data-slot=\"dialog-overlay\"\n className={cn(\n \"fixed inset-0 z-50 bg-overlay data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:animate-in data-[state=open]:fade-in-0\",\n className,\n )}\n {...props}\n />\n );\n}\n\nfunction DialogContent({\n className,\n children,\n showCloseButton = true,\n onOpenAutoFocus,\n ...props\n}: React.ComponentProps<typeof DialogPrimitive.Content> & {\n showCloseButton?: boolean;\n}) {\n return (\n <DialogPortal data-slot=\"dialog-portal\">\n <DialogOverlay />\n <DialogPrimitive.Content\n data-slot=\"dialog-content\"\n className={cn(\n \"fixed top-[50%] left-[50%] z-50 grid w-full max-w-[calc(100%-2rem)] translate-x-[-50%] translate-y-[-50%] gap-4 rounded-lg border bg-background p-6 shadow-float duration-200 outline-none data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=closed]:zoom-out-95 data-[state=open]:animate-in data-[state=open]:fade-in-0 data-[state=open]:zoom-in-95 sm:max-w-lg\",\n className,\n )}\n {...props}\n onOpenAutoFocus={(e) => {\n // Form flow: open on the first field rather than the close button or tabs.\n onOpenAutoFocus?.(e);\n if (!e.defaultPrevented && focusFirstField(e.currentTarget as HTMLElement)) {\n e.preventDefault();\n }\n }}\n >\n {children}\n {showCloseButton && (\n <DialogPrimitive.Close\n data-slot=\"dialog-close\"\n className=\"absolute top-4 right-4 rounded-xs opacity-70 ring-offset-background transition-opacity hover:opacity-100 focus:ring-2 focus:ring-ring focus:ring-offset-2 focus:outline-hidden disabled:pointer-events-none data-[state=open]:bg-accent data-[state=open]:text-muted-foreground [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4\"\n >\n <XIcon />\n <span className=\"sr-only\">Close</span>\n </DialogPrimitive.Close>\n )}\n </DialogPrimitive.Content>\n </DialogPortal>\n );\n}\n\nfunction DialogHeader({ className, ...props }: React.ComponentProps<\"div\">) {\n return (\n <div\n data-slot=\"dialog-header\"\n className={cn(\"flex flex-col gap-2 text-center sm:text-left\", className)}\n {...props}\n />\n );\n}\n\nfunction DialogFooter({\n className,\n showCloseButton = false,\n children,\n ...props\n}: React.ComponentProps<\"div\"> & {\n showCloseButton?: boolean;\n}) {\n return (\n <div\n data-slot=\"dialog-footer\"\n className={cn(\"flex flex-col-reverse gap-2 sm:flex-row sm:justify-end\", className)}\n {...props}\n >\n {children}\n {showCloseButton && (\n <DialogPrimitive.Close asChild>\n <Button variant=\"outline\">Close</Button>\n </DialogPrimitive.Close>\n )}\n </div>\n );\n}\n\nfunction DialogTitle({ className, ...props }: React.ComponentProps<typeof DialogPrimitive.Title>) {\n return (\n <DialogPrimitive.Title\n data-slot=\"dialog-title\"\n className={cn(\"text-lg leading-none font-semibold\", className)}\n {...props}\n />\n );\n}\n\nfunction DialogDescription({\n className,\n ...props\n}: React.ComponentProps<typeof DialogPrimitive.Description>) {\n return (\n <DialogPrimitive.Description\n data-slot=\"dialog-description\"\n className={cn(\"text-sm text-muted-foreground\", className)}\n {...props}\n />\n );\n}\n\nexport {\n Dialog,\n DialogClose,\n DialogContent,\n DialogDescription,\n DialogFooter,\n DialogHeader,\n DialogOverlay,\n DialogPortal,\n DialogTitle,\n DialogTrigger,\n};\n"],"mappings":";;;;;;;;AASA,SAASA,SAAO,EAAE,GAAG,SAA4D;CAC/E,OAAO,oBAACC,OAAgB,MAAjB;EAAsB,aAAU;EAAS,GAAI;CAAQ,CAAA;AAC9D;AAEA,SAAS,cAAc,EAAE,GAAG,SAA+D;CACzF,OAAO,oBAACA,OAAgB,SAAjB;EAAyB,aAAU;EAAiB,GAAI;CAAQ,CAAA;AACzE;AAEA,SAAS,aAAa,EAAE,GAAG,SAA8D;CACvF,OAAO,oBAACA,OAAgB,QAAjB;EAAwB,aAAU;EAAgB,GAAI;CAAQ,CAAA;AACvE;AAEA,SAAS,YAAY,EAAE,GAAG,SAA6D;CACrF,OAAO,oBAACA,OAAgB,OAAjB;EAAuB,aAAU;EAAe,GAAI;CAAQ,CAAA;AACrE;AAEA,SAAS,cAAc,EACrB,WACA,GAAG,SACoD;CACvD,OACE,oBAACA,OAAgB,SAAjB;EACE,aAAU;EACV,WAAW,GACT,yJACA,SACF;EACA,GAAI;CACL,CAAA;AAEL;AAEA,SAAS,cAAc,EACrB,WACA,UACA,kBAAkB,MAClB,iBACA,GAAG,SAGF;CACD,OACE,qBAAC,cAAD;EAAc,aAAU;EAAxB,UAAA,CACE,oBAAC,eAAD,CAAgB,CAAA,GAChB,qBAACA,OAAgB,SAAjB;GACE,aAAU;GACV,WAAW,GACT,+XACA,SACF;GACA,GAAI;GACJ,kBAAkB,MAAM;IAEtB,kBAAkB,CAAC;IACnB,IAAI,CAAC,EAAE,oBAAoB,gBAAgB,EAAE,aAA4B,GACvE,EAAE,eAAe;GAErB;GAbF,UAAA,CAeG,UACA,mBACC,qBAACA,OAAgB,OAAjB;IACE,aAAU;IACV,WAAU;IAFZ,UAAA,CAIE,oBAAC,OAAD,CAAQ,CAAA,GACR,oBAAC,QAAD;KAAM,WAAU;KAAU,UAAA;IAAW,CAAA,CAChB;GAEF,CAAA,CAAA;EACb,CAAA,CAAA;;AAElB;AAEA,SAAS,aAAa,EAAE,WAAW,GAAG,SAAsC;CAC1E,OACE,oBAAC,OAAD;EACE,aAAU;EACV,WAAW,GAAG,gDAAgD,SAAS;EACvE,GAAI;CACL,CAAA;AAEL;AAEA,SAAS,aAAa,EACpB,WACA,kBAAkB,OAClB,UACA,GAAG,SAGF;CACD,OACE,qBAAC,OAAD;EACE,aAAU;EACV,WAAW,GAAG,0DAA0D,SAAS;EACjF,GAAI;EAHN,UAAA,CAKG,UACA,mBACC,oBAACA,OAAgB,OAAjB;GAAuB,SAAA;GACrB,UAAA,oBAAC,QAAD;IAAQ,SAAQ;IAAU,UAAA;GAAa,CAAA;EAClB,CAAA,CAEtB;;AAET;AAEA,SAAS,YAAY,EAAE,WAAW,GAAG,SAA6D;CAChG,OACE,oBAACA,OAAgB,OAAjB;EACE,aAAU;EACV,WAAW,GAAG,sCAAsC,SAAS;EAC7D,GAAI;CACL,CAAA;AAEL;AAEA,SAAS,kBAAkB,EACzB,WACA,GAAG,SACwD;CAC3D,OACE,oBAACA,OAAgB,aAAjB;EACE,aAAU;EACV,WAAW,GAAG,iCAAiC,SAAS;EACxD,GAAI;CACL,CAAA;AAEL"}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import { DropdownMenu } from "radix-ui";
|
|
2
|
+
import * as React from "react";
|
|
3
|
+
declare function DropdownMenu$1({ ...props }: React.ComponentProps<typeof DropdownMenu.Root>): React.JSX.Element;
|
|
4
|
+
declare function DropdownMenuPortal({ ...props }: React.ComponentProps<typeof DropdownMenu.Portal>): React.JSX.Element;
|
|
5
|
+
declare function DropdownMenuTrigger({ ...props }: React.ComponentProps<typeof DropdownMenu.Trigger>): React.JSX.Element;
|
|
6
|
+
declare function DropdownMenuContent({ className, sideOffset, ...props }: React.ComponentProps<typeof DropdownMenu.Content>): React.JSX.Element;
|
|
7
|
+
declare function DropdownMenuGroup({ ...props }: React.ComponentProps<typeof DropdownMenu.Group>): React.JSX.Element;
|
|
8
|
+
declare function DropdownMenuItem({ className, inset, variant, ...props }: React.ComponentProps<typeof DropdownMenu.Item> & {
|
|
9
|
+
inset?: boolean;
|
|
10
|
+
variant?: "default" | "destructive";
|
|
11
|
+
}): React.JSX.Element;
|
|
12
|
+
declare function DropdownMenuCheckboxItem({ className, children, checked, ...props }: React.ComponentProps<typeof DropdownMenu.CheckboxItem>): React.JSX.Element;
|
|
13
|
+
declare function DropdownMenuRadioGroup({ ...props }: React.ComponentProps<typeof DropdownMenu.RadioGroup>): React.JSX.Element;
|
|
14
|
+
declare function DropdownMenuRadioItem({ className, children, ...props }: React.ComponentProps<typeof DropdownMenu.RadioItem>): React.JSX.Element;
|
|
15
|
+
declare function DropdownMenuLabel({ className, inset, ...props }: React.ComponentProps<typeof DropdownMenu.Label> & {
|
|
16
|
+
inset?: boolean;
|
|
17
|
+
}): React.JSX.Element;
|
|
18
|
+
declare function DropdownMenuSeparator({ className, ...props }: React.ComponentProps<typeof DropdownMenu.Separator>): React.JSX.Element;
|
|
19
|
+
declare function DropdownMenuShortcut({ className, ...props }: React.ComponentProps<"span">): React.JSX.Element;
|
|
20
|
+
declare function DropdownMenuSub({ ...props }: React.ComponentProps<typeof DropdownMenu.Sub>): React.JSX.Element;
|
|
21
|
+
declare function DropdownMenuSubTrigger({ className, inset, children, ...props }: React.ComponentProps<typeof DropdownMenu.SubTrigger> & {
|
|
22
|
+
inset?: boolean;
|
|
23
|
+
}): React.JSX.Element;
|
|
24
|
+
declare function DropdownMenuSubContent({ className, ...props }: React.ComponentProps<typeof DropdownMenu.SubContent>): React.JSX.Element;
|
|
25
|
+
export { DropdownMenu$1 as DropdownMenu, DropdownMenuCheckboxItem, DropdownMenuContent, DropdownMenuGroup, DropdownMenuItem, DropdownMenuLabel, DropdownMenuPortal, DropdownMenuRadioGroup, DropdownMenuRadioItem, DropdownMenuSeparator, DropdownMenuShortcut, DropdownMenuSub, DropdownMenuSubContent, DropdownMenuSubTrigger, DropdownMenuTrigger };
|
|
26
|
+
//# sourceMappingURL=dropdown-menu.d.ts.map
|