@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,54 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { jsx, jsxs } from "react/jsx-runtime";
|
|
3
|
+
import * as ScrollAreaPrimitive from "@radix-ui/react-scroll-area";
|
|
4
|
+
import { cn } from "../../lib/cn.js";
|
|
5
|
+
function ScrollArea({
|
|
6
|
+
label,
|
|
7
|
+
orientation = "vertical",
|
|
8
|
+
className,
|
|
9
|
+
children,
|
|
10
|
+
...props
|
|
11
|
+
}) {
|
|
12
|
+
return /* @__PURE__ */ jsxs(
|
|
13
|
+
ScrollAreaPrimitive.Root,
|
|
14
|
+
{
|
|
15
|
+
type: "hover",
|
|
16
|
+
className: cn("relative overflow-hidden", className),
|
|
17
|
+
...props,
|
|
18
|
+
children: [
|
|
19
|
+
/* @__PURE__ */ jsx(
|
|
20
|
+
ScrollAreaPrimitive.Viewport,
|
|
21
|
+
{
|
|
22
|
+
tabIndex: 0,
|
|
23
|
+
role: "region",
|
|
24
|
+
"aria-label": label,
|
|
25
|
+
className: "size-full rounded-[inherit]",
|
|
26
|
+
children
|
|
27
|
+
}
|
|
28
|
+
),
|
|
29
|
+
(orientation === "vertical" || orientation === "both") && /* @__PURE__ */ jsx(Bar, { orientation: "vertical" }),
|
|
30
|
+
(orientation === "horizontal" || orientation === "both") && /* @__PURE__ */ jsx(Bar, { orientation: "horizontal" }),
|
|
31
|
+
/* @__PURE__ */ jsx(ScrollAreaPrimitive.Corner, {})
|
|
32
|
+
]
|
|
33
|
+
}
|
|
34
|
+
);
|
|
35
|
+
}
|
|
36
|
+
function Bar({ orientation }) {
|
|
37
|
+
return /* @__PURE__ */ jsx(
|
|
38
|
+
ScrollAreaPrimitive.Scrollbar,
|
|
39
|
+
{
|
|
40
|
+
orientation,
|
|
41
|
+
className: cn(
|
|
42
|
+
"flex touch-none select-none p-0.5 transition-colors duration-(--duration-fast)",
|
|
43
|
+
orientation === "vertical" ? "h-full w-2" : "h-2 flex-col"
|
|
44
|
+
),
|
|
45
|
+
children: /* @__PURE__ */ jsx(ScrollAreaPrimitive.Thumb, { className: "relative flex-1 rounded-(--radius-pill) bg-(--rule-2)" })
|
|
46
|
+
}
|
|
47
|
+
);
|
|
48
|
+
}
|
|
49
|
+
var ScrollArea_default = ScrollArea;
|
|
50
|
+
export {
|
|
51
|
+
ScrollArea,
|
|
52
|
+
ScrollArea_default as default
|
|
53
|
+
};
|
|
54
|
+
//# sourceMappingURL=ScrollArea.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../../src/components/ScrollArea/ScrollArea.tsx"],"sourcesContent":["'use client'\n\nimport * as ScrollAreaPrimitive from '@radix-ui/react-scroll-area'\nimport type { ComponentProps } from 'react'\nimport { cn } from '../../lib/cn'\n\nexport interface ScrollAreaProps extends ComponentProps<typeof ScrollAreaPrimitive.Root> {\n /**\n * Names the region. Required, and not decoration: a scroll container is a\n * keyboard stop, and an unnamed stop announces \"group\" and nothing else.\n */\n label: string\n orientation?: 'vertical' | 'horizontal' | 'both'\n}\n\n/**\n * A box that scrolls, with a scrollbar that looks the same on every platform.\n *\n * The reason to reach for this over `overflow-auto` is not the scrollbar — it\n * is that Radix keeps the viewport focusable and the bar operable, which a bare\n * overflow container does not. A scrollable region whose contents are not\n * themselves focusable is unreachable by keyboard: there is nothing to Tab to,\n * so everything past the fold does not exist without a mouse.\n *\n * For a page-level or prose scroll, the `scroll-slim` utility is lighter and\n * needs no component. This is for a bounded panel: a long option list, a log,\n * a sidebar that outgrows its column.\n *\n * @example\n * <ScrollArea label=\"Deploy log\" className=\"h-48\">…</ScrollArea>\n */\nexport function ScrollArea({\n label,\n orientation = 'vertical',\n className,\n children,\n ...props\n}: ScrollAreaProps) {\n return (\n <ScrollAreaPrimitive.Root\n type=\"hover\"\n className={cn('relative overflow-hidden', className)}\n {...props}\n >\n <ScrollAreaPrimitive.Viewport\n tabIndex={0}\n role=\"region\"\n aria-label={label}\n className=\"size-full rounded-[inherit]\"\n >\n {children}\n </ScrollAreaPrimitive.Viewport>\n {(orientation === 'vertical' || orientation === 'both') && <Bar orientation=\"vertical\" />}\n {(orientation === 'horizontal' || orientation === 'both') && <Bar orientation=\"horizontal\" />}\n <ScrollAreaPrimitive.Corner />\n </ScrollAreaPrimitive.Root>\n )\n}\n\nfunction Bar({ orientation }: { orientation: 'vertical' | 'horizontal' }) {\n return (\n <ScrollAreaPrimitive.Scrollbar\n orientation={orientation}\n className={cn(\n 'flex touch-none select-none p-0.5 transition-colors duration-(--duration-fast)',\n orientation === 'vertical' ? 'h-full w-2' : 'h-2 flex-col',\n )}\n >\n <ScrollAreaPrimitive.Thumb className=\"relative flex-1 rounded-(--radius-pill) bg-(--rule-2)\" />\n </ScrollAreaPrimitive.Scrollbar>\n )\n}\n\nexport default ScrollArea\n"],"mappings":";AAuCI,SAKE,KALF;AArCJ,YAAY,yBAAyB;AAErC,SAAS,UAAU;AA2BZ,SAAS,WAAW;AAAA,EACzB;AAAA,EACA,cAAc;AAAA,EACd;AAAA,EACA;AAAA,EACA,GAAG;AACL,GAAoB;AAClB,SACE;AAAA,IAAC,oBAAoB;AAAA,IAApB;AAAA,MACC,MAAK;AAAA,MACL,WAAW,GAAG,4BAA4B,SAAS;AAAA,MAClD,GAAG;AAAA,MAEJ;AAAA;AAAA,UAAC,oBAAoB;AAAA,UAApB;AAAA,YACC,UAAU;AAAA,YACV,MAAK;AAAA,YACL,cAAY;AAAA,YACZ,WAAU;AAAA,YAET;AAAA;AAAA,QACH;AAAA,SACE,gBAAgB,cAAc,gBAAgB,WAAW,oBAAC,OAAI,aAAY,YAAW;AAAA,SACrF,gBAAgB,gBAAgB,gBAAgB,WAAW,oBAAC,OAAI,aAAY,cAAa;AAAA,QAC3F,oBAAC,oBAAoB,QAApB,EAA2B;AAAA;AAAA;AAAA,EAC9B;AAEJ;AAEA,SAAS,IAAI,EAAE,YAAY,GAA+C;AACxE,SACE;AAAA,IAAC,oBAAoB;AAAA,IAApB;AAAA,MACC;AAAA,MACA,WAAW;AAAA,QACT;AAAA,QACA,gBAAgB,aAAa,eAAe;AAAA,MAC9C;AAAA,MAEA,8BAAC,oBAAoB,OAApB,EAA0B,WAAU,yDAAwD;AAAA;AAAA,EAC/F;AAEJ;AAEA,IAAO,qBAAQ;","names":[]}
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
import * as react from 'react';
|
|
2
|
+
import { ReactNode } from 'react';
|
|
3
|
+
|
|
4
|
+
interface MenuAction {
|
|
5
|
+
/** Stable id, and what the filter matches on. */
|
|
6
|
+
id: string;
|
|
7
|
+
label: ReactNode;
|
|
8
|
+
/** Plain text the filter should match beyond the label. */
|
|
9
|
+
keywords?: string[];
|
|
10
|
+
/** Printed at the end of the row. */
|
|
11
|
+
shortcut?: string;
|
|
12
|
+
/** Optional group heading. Rows with the same value are shown together. */
|
|
13
|
+
group?: string;
|
|
14
|
+
disabled?: boolean;
|
|
15
|
+
destructive?: boolean;
|
|
16
|
+
onSelect: () => void;
|
|
17
|
+
}
|
|
18
|
+
interface SearchableMenuProps {
|
|
19
|
+
actions: MenuAction[];
|
|
20
|
+
/** The trigger's text. */
|
|
21
|
+
children: ReactNode;
|
|
22
|
+
/** Names the menu for assistive tech. */
|
|
23
|
+
label: string;
|
|
24
|
+
searchPlaceholder?: string;
|
|
25
|
+
emptyMessage?: string;
|
|
26
|
+
align?: 'start' | 'center' | 'end';
|
|
27
|
+
className?: string;
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* A menu of actions you can type into.
|
|
31
|
+
*
|
|
32
|
+
* The fourth corner of a square the system otherwise had three of, and the
|
|
33
|
+
* distinction is worth stating because reaching for the wrong one is easy:
|
|
34
|
+
*
|
|
35
|
+
* | | few options | many options |
|
|
36
|
+
* |---|---|---|
|
|
37
|
+
* | **sets a value** | `Select` | `Combobox` |
|
|
38
|
+
* | **runs an action** | `DropdownMenu` | `SearchableMenu` |
|
|
39
|
+
*
|
|
40
|
+
* A `DropdownMenu` past about a dozen rows stops being scannable, and the
|
|
41
|
+
* usual response — nesting submenus — makes it worse. This is the same list
|
|
42
|
+
* with a filter over it.
|
|
43
|
+
*
|
|
44
|
+
* Not the same thing as `Command`: that is a page-level palette, usually modal
|
|
45
|
+
* and usually bound to ⌘K. This is anchored to a control, like the menu it
|
|
46
|
+
* replaces.
|
|
47
|
+
*
|
|
48
|
+
* The rows are `option`s inside a listbox rather than `menuitem`s, because that
|
|
49
|
+
* is what the filtering pattern requires — the highlight moves through
|
|
50
|
+
* `aria-activedescendant` while focus stays in the input, and a menu cannot do
|
|
51
|
+
* that. The trade is deliberate: a menu that cannot be filtered is worse for
|
|
52
|
+
* the reader than a listbox that runs actions.
|
|
53
|
+
*
|
|
54
|
+
* @example
|
|
55
|
+
* <SearchableMenu label="Actions" actions={ACTIONS}>Actions</SearchableMenu>
|
|
56
|
+
*/
|
|
57
|
+
declare function SearchableMenu({ actions, children, label, searchPlaceholder, emptyMessage, align, className, }: SearchableMenuProps): react.JSX.Element;
|
|
58
|
+
|
|
59
|
+
export { type MenuAction, SearchableMenu, type SearchableMenuProps, SearchableMenu as default };
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { jsx, jsxs } from "react/jsx-runtime";
|
|
3
|
+
import { ChevronDown } from "lucide-react";
|
|
4
|
+
import { useState } from "react";
|
|
5
|
+
import { cn } from "../../lib/cn.js";
|
|
6
|
+
import {
|
|
7
|
+
Command,
|
|
8
|
+
CommandEmpty,
|
|
9
|
+
CommandGroup,
|
|
10
|
+
CommandInput,
|
|
11
|
+
CommandItem,
|
|
12
|
+
CommandList,
|
|
13
|
+
CommandSeparator
|
|
14
|
+
} from "../Command/Command.js";
|
|
15
|
+
import { Popover, PopoverContent, PopoverTrigger } from "../Popover/Popover.js";
|
|
16
|
+
function SearchableMenu({
|
|
17
|
+
actions,
|
|
18
|
+
children,
|
|
19
|
+
label,
|
|
20
|
+
searchPlaceholder = "Filter\u2026",
|
|
21
|
+
emptyMessage = "Nothing matches.",
|
|
22
|
+
align = "start",
|
|
23
|
+
className
|
|
24
|
+
}) {
|
|
25
|
+
const [open, setOpen] = useState(false);
|
|
26
|
+
const groups = [];
|
|
27
|
+
for (const action of actions) {
|
|
28
|
+
const last = groups.at(-1);
|
|
29
|
+
if (last && last.name === action.group) last.items.push(action);
|
|
30
|
+
else groups.push({ name: action.group, items: [action] });
|
|
31
|
+
}
|
|
32
|
+
return /* @__PURE__ */ jsxs(Popover, { open, onOpenChange: setOpen, children: [
|
|
33
|
+
/* @__PURE__ */ jsxs(
|
|
34
|
+
PopoverTrigger,
|
|
35
|
+
{
|
|
36
|
+
"aria-label": label,
|
|
37
|
+
className: cn(
|
|
38
|
+
"inline-flex min-h-(--control-h-sm) items-center gap-2 rounded-(--radius-pill) border border-(--rule-2) px-4 text-sm text-(--ink) transition-colors duration-(--duration-fast) hover:border-(--ink)",
|
|
39
|
+
className
|
|
40
|
+
),
|
|
41
|
+
children: [
|
|
42
|
+
children,
|
|
43
|
+
/* @__PURE__ */ jsx(ChevronDown, { size: 14, strokeWidth: 1.5, "aria-hidden": true, className: "shrink-0 text-(--ink-3-aa)" })
|
|
44
|
+
]
|
|
45
|
+
}
|
|
46
|
+
),
|
|
47
|
+
/* @__PURE__ */ jsx(PopoverContent, { label, align, className: "w-64 overflow-hidden p-0", children: /* @__PURE__ */ jsxs(Command, { label: `${label}: ${searchPlaceholder}`, className: "rounded-none border-0", children: [
|
|
48
|
+
/* @__PURE__ */ jsx(CommandInput, { placeholder: searchPlaceholder }),
|
|
49
|
+
/* @__PURE__ */ jsxs(CommandList, { children: [
|
|
50
|
+
/* @__PURE__ */ jsx(CommandEmpty, { children: emptyMessage }),
|
|
51
|
+
groups.map((group, index) => /* @__PURE__ */ jsxs("div", { children: [
|
|
52
|
+
index > 0 && /* @__PURE__ */ jsx(CommandSeparator, {}),
|
|
53
|
+
/* @__PURE__ */ jsx(CommandGroup, { heading: group.name, children: group.items.map((action) => /* @__PURE__ */ jsx(
|
|
54
|
+
CommandItem,
|
|
55
|
+
{
|
|
56
|
+
value: action.id,
|
|
57
|
+
keywords: action.keywords,
|
|
58
|
+
disabled: action.disabled,
|
|
59
|
+
shortcut: action.shortcut,
|
|
60
|
+
onSelect: () => {
|
|
61
|
+
setOpen(false);
|
|
62
|
+
action.onSelect();
|
|
63
|
+
},
|
|
64
|
+
className: action.destructive ? "text-(--danger)" : void 0,
|
|
65
|
+
children: action.label
|
|
66
|
+
},
|
|
67
|
+
action.id
|
|
68
|
+
)) })
|
|
69
|
+
] }, group.name ?? index))
|
|
70
|
+
] })
|
|
71
|
+
] }) })
|
|
72
|
+
] });
|
|
73
|
+
}
|
|
74
|
+
var SearchableMenu_default = SearchableMenu;
|
|
75
|
+
export {
|
|
76
|
+
SearchableMenu,
|
|
77
|
+
SearchableMenu_default as default
|
|
78
|
+
};
|
|
79
|
+
//# sourceMappingURL=SearchableMenu.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../../src/components/SearchableMenu/SearchableMenu.tsx"],"sourcesContent":["'use client'\n\nimport { ChevronDown } from 'lucide-react'\nimport { useState, type ReactNode } from 'react'\nimport { cn } from '../../lib/cn'\nimport {\n Command,\n CommandEmpty,\n CommandGroup,\n CommandInput,\n CommandItem,\n CommandList,\n CommandSeparator,\n} from '../Command/Command'\nimport { Popover, PopoverContent, PopoverTrigger } from '../Popover/Popover'\n\nexport interface MenuAction {\n /** Stable id, and what the filter matches on. */\n id: string\n label: ReactNode\n /** Plain text the filter should match beyond the label. */\n keywords?: string[]\n /** Printed at the end of the row. */\n shortcut?: string\n /** Optional group heading. Rows with the same value are shown together. */\n group?: string\n disabled?: boolean\n destructive?: boolean\n onSelect: () => void\n}\n\nexport interface SearchableMenuProps {\n actions: MenuAction[]\n /** The trigger's text. */\n children: ReactNode\n /** Names the menu for assistive tech. */\n label: string\n searchPlaceholder?: string\n emptyMessage?: string\n align?: 'start' | 'center' | 'end'\n className?: string\n}\n\n/**\n * A menu of actions you can type into.\n *\n * The fourth corner of a square the system otherwise had three of, and the\n * distinction is worth stating because reaching for the wrong one is easy:\n *\n * | | few options | many options |\n * |---|---|---|\n * | **sets a value** | `Select` | `Combobox` |\n * | **runs an action** | `DropdownMenu` | `SearchableMenu` |\n *\n * A `DropdownMenu` past about a dozen rows stops being scannable, and the\n * usual response — nesting submenus — makes it worse. This is the same list\n * with a filter over it.\n *\n * Not the same thing as `Command`: that is a page-level palette, usually modal\n * and usually bound to ⌘K. This is anchored to a control, like the menu it\n * replaces.\n *\n * The rows are `option`s inside a listbox rather than `menuitem`s, because that\n * is what the filtering pattern requires — the highlight moves through\n * `aria-activedescendant` while focus stays in the input, and a menu cannot do\n * that. The trade is deliberate: a menu that cannot be filtered is worse for\n * the reader than a listbox that runs actions.\n *\n * @example\n * <SearchableMenu label=\"Actions\" actions={ACTIONS}>Actions</SearchableMenu>\n */\nexport function SearchableMenu({\n actions,\n children,\n label,\n searchPlaceholder = 'Filter…',\n emptyMessage = 'Nothing matches.',\n align = 'start',\n className,\n}: SearchableMenuProps) {\n const [open, setOpen] = useState(false)\n\n // Grouped in declaration order, so a caller controls the arrangement by the\n // order they list actions rather than by an extra prop.\n const groups: { name: string | undefined; items: MenuAction[] }[] = []\n for (const action of actions) {\n const last = groups.at(-1)\n if (last && last.name === action.group) last.items.push(action)\n else groups.push({ name: action.group, items: [action] })\n }\n\n return (\n <Popover open={open} onOpenChange={setOpen}>\n <PopoverTrigger\n aria-label={label}\n className={cn(\n 'inline-flex min-h-(--control-h-sm) items-center gap-2 rounded-(--radius-pill) border border-(--rule-2) px-4 text-sm text-(--ink) transition-colors duration-(--duration-fast) hover:border-(--ink)',\n className,\n )}\n >\n {children}\n <ChevronDown size={14} strokeWidth={1.5} aria-hidden className=\"shrink-0 text-(--ink-3-aa)\" />\n </PopoverTrigger>\n <PopoverContent label={label} align={align} className=\"w-64 overflow-hidden p-0\">\n <Command label={`${label}: ${searchPlaceholder}`} className=\"rounded-none border-0\">\n <CommandInput placeholder={searchPlaceholder} />\n <CommandList>\n <CommandEmpty>{emptyMessage}</CommandEmpty>\n {groups.map((group, index) => (\n <div key={group.name ?? index}>\n {index > 0 && <CommandSeparator />}\n <CommandGroup heading={group.name}>\n {group.items.map((action) => (\n <CommandItem\n key={action.id}\n value={action.id}\n keywords={action.keywords}\n disabled={action.disabled}\n shortcut={action.shortcut}\n onSelect={() => {\n setOpen(false)\n action.onSelect()\n }}\n className={action.destructive ? 'text-(--danger)' : undefined}\n >\n {action.label}\n </CommandItem>\n ))}\n </CommandGroup>\n </div>\n ))}\n </CommandList>\n </Command>\n </PopoverContent>\n </Popover>\n )\n}\n\nexport default SearchableMenu\n"],"mappings":";AA6FM,SAQE,KARF;AA3FN,SAAS,mBAAmB;AAC5B,SAAS,gBAAgC;AACzC,SAAS,UAAU;AACnB;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,OACK;AACP,SAAS,SAAS,gBAAgB,sBAAsB;AAyDjD,SAAS,eAAe;AAAA,EAC7B;AAAA,EACA;AAAA,EACA;AAAA,EACA,oBAAoB;AAAA,EACpB,eAAe;AAAA,EACf,QAAQ;AAAA,EACR;AACF,GAAwB;AACtB,QAAM,CAAC,MAAM,OAAO,IAAI,SAAS,KAAK;AAItC,QAAM,SAA8D,CAAC;AACrE,aAAW,UAAU,SAAS;AAC5B,UAAM,OAAO,OAAO,GAAG,EAAE;AACzB,QAAI,QAAQ,KAAK,SAAS,OAAO,MAAO,MAAK,MAAM,KAAK,MAAM;AAAA,QACzD,QAAO,KAAK,EAAE,MAAM,OAAO,OAAO,OAAO,CAAC,MAAM,EAAE,CAAC;AAAA,EAC1D;AAEA,SACE,qBAAC,WAAQ,MAAY,cAAc,SACjC;AAAA;AAAA,MAAC;AAAA;AAAA,QACC,cAAY;AAAA,QACZ,WAAW;AAAA,UACT;AAAA,UACA;AAAA,QACF;AAAA,QAEC;AAAA;AAAA,UACD,oBAAC,eAAY,MAAM,IAAI,aAAa,KAAK,eAAW,MAAC,WAAU,8BAA6B;AAAA;AAAA;AAAA,IAC9F;AAAA,IACA,oBAAC,kBAAe,OAAc,OAAc,WAAU,4BACpD,+BAAC,WAAQ,OAAO,GAAG,KAAK,KAAK,iBAAiB,IAAI,WAAU,yBAC1D;AAAA,0BAAC,gBAAa,aAAa,mBAAmB;AAAA,MAC9C,qBAAC,eACC;AAAA,4BAAC,gBAAc,wBAAa;AAAA,QAC3B,OAAO,IAAI,CAAC,OAAO,UAClB,qBAAC,SACE;AAAA,kBAAQ,KAAK,oBAAC,oBAAiB;AAAA,UAChC,oBAAC,gBAAa,SAAS,MAAM,MAC1B,gBAAM,MAAM,IAAI,CAAC,WAChB;AAAA,YAAC;AAAA;AAAA,cAEC,OAAO,OAAO;AAAA,cACd,UAAU,OAAO;AAAA,cACjB,UAAU,OAAO;AAAA,cACjB,UAAU,OAAO;AAAA,cACjB,UAAU,MAAM;AACd,wBAAQ,KAAK;AACb,uBAAO,SAAS;AAAA,cAClB;AAAA,cACA,WAAW,OAAO,cAAc,oBAAoB;AAAA,cAEnD,iBAAO;AAAA;AAAA,YAXH,OAAO;AAAA,UAYd,CACD,GACH;AAAA,aAnBQ,MAAM,QAAQ,KAoBxB,CACD;AAAA,SACH;AAAA,OACF,GACF;AAAA,KACF;AAEJ;AAEA,IAAO,yBAAQ;","names":[]}
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
import * as react from 'react';
|
|
2
|
+
import { ComponentProps, ReactNode } from 'react';
|
|
3
|
+
import * as SelectPrimitive from '@radix-ui/react-select';
|
|
4
|
+
|
|
5
|
+
/** Radix Select root, group and label, as typed passthroughs. */
|
|
6
|
+
declare const SelectRoot: react.FC<SelectPrimitive.SelectProps>;
|
|
7
|
+
declare const SelectGroup: react.ForwardRefExoticComponent<SelectPrimitive.SelectGroupProps & react.RefAttributes<HTMLDivElement>>;
|
|
8
|
+
interface SelectProps extends ComponentProps<typeof SelectPrimitive.Root> {
|
|
9
|
+
/**
|
|
10
|
+
* Classes for the option PANEL, not the trigger.
|
|
11
|
+
*
|
|
12
|
+
* `className` styles the trigger, which is the common case. This exists for
|
|
13
|
+
* the uncommon one: a select inside a bounded surface, where the default
|
|
14
|
+
* 18rem of list would cover the thing the reader is choosing for — a year
|
|
15
|
+
* picker over its own calendar, say.
|
|
16
|
+
*/
|
|
17
|
+
contentClassName?: string;
|
|
18
|
+
/** Names the control. Required — the trigger shows a value, and a value is not a name. */
|
|
19
|
+
label: string;
|
|
20
|
+
placeholder?: string;
|
|
21
|
+
/** Paints the resting border with `--danger` and reflects `aria-invalid`. */
|
|
22
|
+
invalid?: boolean;
|
|
23
|
+
disabled?: boolean;
|
|
24
|
+
className?: string;
|
|
25
|
+
/** `SelectItem`s, optionally wrapped in `SelectGroup` with a `SelectLabel`. */
|
|
26
|
+
children: ReactNode;
|
|
27
|
+
}
|
|
28
|
+
/**
|
|
29
|
+
* A choice from a list, styled the whole way down.
|
|
30
|
+
*
|
|
31
|
+
* The option list is ours — drawn from the same tokens as everything else, so
|
|
32
|
+
* it does not change typeface, spacing and selection colour the moment it
|
|
33
|
+
* opens. That is the whole reason this replaced the native control as the
|
|
34
|
+
* default: a design system whose most common form control stops being part of
|
|
35
|
+
* the system on click is not a design system, it is a stylesheet for closed
|
|
36
|
+
* states.
|
|
37
|
+
*
|
|
38
|
+
* The keyboard contract is Radix's, which means it is the platform's: typeahead
|
|
39
|
+
* works, the arrows move, Home and End reach the ends, and Escape closes
|
|
40
|
+
* without choosing. That was the one genuine argument for staying native, and
|
|
41
|
+
* it is answered.
|
|
42
|
+
*
|
|
43
|
+
* Past roughly a dozen options, reach for `Combobox` — a list nobody can filter
|
|
44
|
+
* is worse than one they can type into. Where the platform picker is genuinely
|
|
45
|
+
* better — a phone, or a form that must survive without JavaScript — reach for
|
|
46
|
+
* `NativeSelect`.
|
|
47
|
+
*
|
|
48
|
+
* @example
|
|
49
|
+
* <Field label="Region">
|
|
50
|
+
* <Select label="Region" defaultValue="au">
|
|
51
|
+
* <SelectItem value="au">Australia</SelectItem>
|
|
52
|
+
* <SelectItem value="nz">New Zealand</SelectItem>
|
|
53
|
+
* </Select>
|
|
54
|
+
* </Field>
|
|
55
|
+
*/
|
|
56
|
+
declare function Select({ label, placeholder, invalid, disabled, className, contentClassName, children, ...props }: SelectProps): react.JSX.Element;
|
|
57
|
+
type SelectItemProps = ComponentProps<typeof SelectPrimitive.Item>;
|
|
58
|
+
/** One option. The tick marks the chosen one; the fill marks the highlighted one. */
|
|
59
|
+
declare function SelectItem({ className, children, ...props }: SelectItemProps): react.JSX.Element;
|
|
60
|
+
/**
|
|
61
|
+
* Mono eyebrow heading for a group of options.
|
|
62
|
+
*
|
|
63
|
+
* Must sit inside a `SelectGroup` — Radix throws otherwise, because a heading
|
|
64
|
+
* with no group is a heading for nothing, and assistive tech would announce it
|
|
65
|
+
* as an option.
|
|
66
|
+
*/
|
|
67
|
+
declare function SelectLabel({ className, ...props }: ComponentProps<typeof SelectPrimitive.Label>): react.JSX.Element;
|
|
68
|
+
/** Hairline divider between groups. */
|
|
69
|
+
declare function SelectSeparator({ className, ...props }: ComponentProps<typeof SelectPrimitive.Separator>): react.JSX.Element;
|
|
70
|
+
|
|
71
|
+
export { Select, SelectGroup, SelectItem, type SelectItemProps, SelectLabel, type SelectProps, SelectRoot, SelectSeparator, Select as default };
|
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { jsx, jsxs } from "react/jsx-runtime";
|
|
3
|
+
import * as SelectPrimitive from "@radix-ui/react-select";
|
|
4
|
+
import { Check, ChevronDown, ChevronUp } from "lucide-react";
|
|
5
|
+
import { cn } from "../../lib/cn.js";
|
|
6
|
+
import { useOverlayContainer } from "../../lib/overlay-container.js";
|
|
7
|
+
import { CONTROL_BASE, CONTROL_BORDER, isInvalid } from "../../lib/control.js";
|
|
8
|
+
const SelectRoot = SelectPrimitive.Root;
|
|
9
|
+
const SelectGroup = SelectPrimitive.Group;
|
|
10
|
+
function Select({
|
|
11
|
+
label,
|
|
12
|
+
placeholder = "Select\u2026",
|
|
13
|
+
invalid,
|
|
14
|
+
disabled,
|
|
15
|
+
className,
|
|
16
|
+
contentClassName,
|
|
17
|
+
children,
|
|
18
|
+
...props
|
|
19
|
+
}) {
|
|
20
|
+
const bad = isInvalid(invalid);
|
|
21
|
+
const container = useOverlayContainer();
|
|
22
|
+
return /* @__PURE__ */ jsxs(SelectPrimitive.Root, { disabled, ...props, children: [
|
|
23
|
+
/* @__PURE__ */ jsxs(
|
|
24
|
+
SelectPrimitive.Trigger,
|
|
25
|
+
{
|
|
26
|
+
"aria-label": label,
|
|
27
|
+
"aria-invalid": bad || void 0,
|
|
28
|
+
className: cn(
|
|
29
|
+
CONTROL_BASE,
|
|
30
|
+
"group flex cursor-pointer items-center justify-between gap-2 text-start data-[placeholder]:text-(--ink-3-aa)",
|
|
31
|
+
bad ? CONTROL_BORDER.invalid : CONTROL_BORDER.resting,
|
|
32
|
+
className
|
|
33
|
+
),
|
|
34
|
+
children: [
|
|
35
|
+
/* @__PURE__ */ jsx(SelectPrimitive.Value, { placeholder }),
|
|
36
|
+
/* @__PURE__ */ jsx(SelectPrimitive.Icon, { asChild: true, children: /* @__PURE__ */ jsx(
|
|
37
|
+
ChevronDown,
|
|
38
|
+
{
|
|
39
|
+
size: 16,
|
|
40
|
+
strokeWidth: 1.5,
|
|
41
|
+
"aria-hidden": true,
|
|
42
|
+
className: "shrink-0 text-(--ink-3-aa) transition-transform duration-(--duration-fast) group-data-[state=open]:rotate-180"
|
|
43
|
+
}
|
|
44
|
+
) })
|
|
45
|
+
]
|
|
46
|
+
}
|
|
47
|
+
),
|
|
48
|
+
/* @__PURE__ */ jsx(SelectPrimitive.Portal, { container: container ?? void 0, children: /* @__PURE__ */ jsxs(
|
|
49
|
+
SelectPrimitive.Content,
|
|
50
|
+
{
|
|
51
|
+
collisionBoundary: container ?? void 0,
|
|
52
|
+
collisionPadding: 8,
|
|
53
|
+
position: "popper",
|
|
54
|
+
sideOffset: 6,
|
|
55
|
+
"data-m22-animated": true,
|
|
56
|
+
className: cn(
|
|
57
|
+
"z-(--z-dropdown) max-h-72 min-w-(--radix-select-trigger-width) overflow-hidden rounded-(--radius) border border-(--rule-2) bg-(--paper)",
|
|
58
|
+
contentClassName,
|
|
59
|
+
"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)"
|
|
60
|
+
),
|
|
61
|
+
children: [
|
|
62
|
+
/* @__PURE__ */ jsx(SelectPrimitive.ScrollUpButton, { className: "flex h-6 items-center justify-center text-(--ink-3-aa)", children: /* @__PURE__ */ jsx(ChevronUp, { size: 14, strokeWidth: 1.5, "aria-hidden": true }) }),
|
|
63
|
+
/* @__PURE__ */ jsx(SelectPrimitive.Viewport, { className: "p-1.5", children }),
|
|
64
|
+
/* @__PURE__ */ jsx(SelectPrimitive.ScrollDownButton, { className: "flex h-6 items-center justify-center text-(--ink-3-aa)", children: /* @__PURE__ */ jsx(ChevronDown, { size: 14, strokeWidth: 1.5, "aria-hidden": true }) })
|
|
65
|
+
]
|
|
66
|
+
}
|
|
67
|
+
) })
|
|
68
|
+
] });
|
|
69
|
+
}
|
|
70
|
+
function SelectItem({ className, children, ...props }) {
|
|
71
|
+
return /* @__PURE__ */ jsxs(
|
|
72
|
+
SelectPrimitive.Item,
|
|
73
|
+
{
|
|
74
|
+
className: cn(
|
|
75
|
+
"flex cursor-pointer select-none items-center gap-2.5 rounded-(--radius-sm) px-2.5 py-2 text-sm text-(--ink-2) outline-none transition-colors duration-(--duration-fast) data-[highlighted]:bg-(--stone) data-[highlighted]:text-(--ink) data-[disabled]:pointer-events-none data-[disabled]:opacity-(--disabled-opacity)",
|
|
76
|
+
className
|
|
77
|
+
),
|
|
78
|
+
...props,
|
|
79
|
+
children: [
|
|
80
|
+
/* @__PURE__ */ jsx("span", { className: "grid size-3.5 shrink-0 place-items-center", children: /* @__PURE__ */ jsx(SelectPrimitive.ItemIndicator, { asChild: true, children: /* @__PURE__ */ jsx(Check, { size: 14, strokeWidth: 2, "aria-hidden": true }) }) }),
|
|
81
|
+
/* @__PURE__ */ jsx(SelectPrimitive.ItemText, { children })
|
|
82
|
+
]
|
|
83
|
+
}
|
|
84
|
+
);
|
|
85
|
+
}
|
|
86
|
+
function SelectLabel({
|
|
87
|
+
className,
|
|
88
|
+
...props
|
|
89
|
+
}) {
|
|
90
|
+
return /* @__PURE__ */ jsx(
|
|
91
|
+
SelectPrimitive.Label,
|
|
92
|
+
{
|
|
93
|
+
className: cn("px-2.5 py-1.5 eyebrow text-(--ink-3-aa)", className),
|
|
94
|
+
...props
|
|
95
|
+
}
|
|
96
|
+
);
|
|
97
|
+
}
|
|
98
|
+
function SelectSeparator({
|
|
99
|
+
className,
|
|
100
|
+
...props
|
|
101
|
+
}) {
|
|
102
|
+
return /* @__PURE__ */ jsx(SelectPrimitive.Separator, { className: cn("my-1 h-px bg-(--rule)", className), ...props });
|
|
103
|
+
}
|
|
104
|
+
var Select_default = Select;
|
|
105
|
+
export {
|
|
106
|
+
Select,
|
|
107
|
+
SelectGroup,
|
|
108
|
+
SelectItem,
|
|
109
|
+
SelectLabel,
|
|
110
|
+
SelectRoot,
|
|
111
|
+
SelectSeparator,
|
|
112
|
+
Select_default as default
|
|
113
|
+
};
|
|
114
|
+
//# sourceMappingURL=Select.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../../src/components/Select/Select.tsx"],"sourcesContent":["'use client'\n\nimport * as SelectPrimitive from '@radix-ui/react-select'\nimport { Check, ChevronDown, ChevronUp } from 'lucide-react'\nimport type { ComponentProps, ReactNode } from 'react'\nimport { cn } from '../../lib/cn'\nimport { useOverlayContainer } from '../../lib/overlay-container'\nimport { CONTROL_BASE, CONTROL_BORDER, isInvalid } from '../../lib/control'\n\n/** Radix Select root, group and label, as typed passthroughs. */\nexport const SelectRoot = SelectPrimitive.Root\nexport const SelectGroup = SelectPrimitive.Group\n\nexport interface SelectProps extends ComponentProps<typeof SelectPrimitive.Root> {\n /**\n * Classes for the option PANEL, not the trigger.\n *\n * `className` styles the trigger, which is the common case. This exists for\n * the uncommon one: a select inside a bounded surface, where the default\n * 18rem of list would cover the thing the reader is choosing for — a year\n * picker over its own calendar, say.\n */\n contentClassName?: string\n /** Names the control. Required — the trigger shows a value, and a value is not a name. */\n label: string\n placeholder?: string\n /** Paints the resting border with `--danger` and reflects `aria-invalid`. */\n invalid?: boolean\n disabled?: boolean\n className?: string\n /** `SelectItem`s, optionally wrapped in `SelectGroup` with a `SelectLabel`. */\n children: ReactNode\n}\n\n/**\n * A choice from a list, styled the whole way down.\n *\n * The option list is ours — drawn from the same tokens as everything else, so\n * it does not change typeface, spacing and selection colour the moment it\n * opens. That is the whole reason this replaced the native control as the\n * default: a design system whose most common form control stops being part of\n * the system on click is not a design system, it is a stylesheet for closed\n * states.\n *\n * The keyboard contract is Radix's, which means it is the platform's: typeahead\n * works, the arrows move, Home and End reach the ends, and Escape closes\n * without choosing. That was the one genuine argument for staying native, and\n * it is answered.\n *\n * Past roughly a dozen options, reach for `Combobox` — a list nobody can filter\n * is worse than one they can type into. Where the platform picker is genuinely\n * better — a phone, or a form that must survive without JavaScript — reach for\n * `NativeSelect`.\n *\n * @example\n * <Field label=\"Region\">\n * <Select label=\"Region\" defaultValue=\"au\">\n * <SelectItem value=\"au\">Australia</SelectItem>\n * <SelectItem value=\"nz\">New Zealand</SelectItem>\n * </Select>\n * </Field>\n */\nexport function Select({\n label,\n placeholder = 'Select…',\n invalid,\n disabled,\n className,\n contentClassName,\n children,\n ...props\n}: SelectProps) {\n const bad = isInvalid(invalid)\n const container = useOverlayContainer()\n\n return (\n <SelectPrimitive.Root disabled={disabled} {...props}>\n <SelectPrimitive.Trigger\n aria-label={label}\n aria-invalid={bad || undefined}\n className={cn(\n CONTROL_BASE,\n 'group flex cursor-pointer items-center justify-between gap-2 text-start data-[placeholder]:text-(--ink-3-aa)',\n bad ? CONTROL_BORDER.invalid : CONTROL_BORDER.resting,\n className,\n )}\n >\n <SelectPrimitive.Value placeholder={placeholder} />\n <SelectPrimitive.Icon asChild>\n <ChevronDown\n size={16}\n strokeWidth={1.5}\n aria-hidden\n className=\"shrink-0 text-(--ink-3-aa) transition-transform duration-(--duration-fast) group-data-[state=open]:rotate-180\"\n />\n </SelectPrimitive.Icon>\n </SelectPrimitive.Trigger>\n\n <SelectPrimitive.Portal container={container ?? undefined}>\n <SelectPrimitive.Content\n collisionBoundary={container ?? undefined}\n collisionPadding={8}\n position=\"popper\"\n sideOffset={6}\n data-m22-animated\n className={cn(\n 'z-(--z-dropdown) max-h-72 min-w-(--radix-select-trigger-width) overflow-hidden rounded-(--radius) border border-(--rule-2) bg-(--paper)',\n contentClassName,\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 )}\n >\n <SelectPrimitive.ScrollUpButton className=\"flex h-6 items-center justify-center text-(--ink-3-aa)\">\n <ChevronUp size={14} strokeWidth={1.5} aria-hidden />\n </SelectPrimitive.ScrollUpButton>\n <SelectPrimitive.Viewport className=\"p-1.5\">{children}</SelectPrimitive.Viewport>\n <SelectPrimitive.ScrollDownButton className=\"flex h-6 items-center justify-center text-(--ink-3-aa)\">\n <ChevronDown size={14} strokeWidth={1.5} aria-hidden />\n </SelectPrimitive.ScrollDownButton>\n </SelectPrimitive.Content>\n </SelectPrimitive.Portal>\n </SelectPrimitive.Root>\n )\n}\n\nexport type SelectItemProps = ComponentProps<typeof SelectPrimitive.Item>\n\n/** One option. The tick marks the chosen one; the fill marks the highlighted one. */\nexport function SelectItem({ className, children, ...props }: SelectItemProps) {\n return (\n <SelectPrimitive.Item\n className={cn(\n 'flex cursor-pointer select-none items-center gap-2.5 rounded-(--radius-sm) px-2.5 py-2 text-sm text-(--ink-2) outline-none transition-colors duration-(--duration-fast) data-[highlighted]:bg-(--stone) data-[highlighted]:text-(--ink) data-[disabled]:pointer-events-none data-[disabled]:opacity-(--disabled-opacity)',\n className,\n )}\n {...props}\n >\n {/* The box is always there and only the tick inside it appears, so\n choosing an option does not shunt every label sideways. */}\n <span className=\"grid size-3.5 shrink-0 place-items-center\">\n <SelectPrimitive.ItemIndicator asChild>\n <Check size={14} strokeWidth={2} aria-hidden />\n </SelectPrimitive.ItemIndicator>\n </span>\n <SelectPrimitive.ItemText>{children}</SelectPrimitive.ItemText>\n </SelectPrimitive.Item>\n )\n}\n\n/**\n * Mono eyebrow heading for a group of options.\n *\n * Must sit inside a `SelectGroup` — Radix throws otherwise, because a heading\n * with no group is a heading for nothing, and assistive tech would announce it\n * as an option.\n */\nexport function SelectLabel({\n className,\n ...props\n}: ComponentProps<typeof SelectPrimitive.Label>) {\n return (\n <SelectPrimitive.Label\n className={cn('px-2.5 py-1.5 eyebrow text-(--ink-3-aa)', className)}\n {...props}\n />\n )\n}\n\n/** Hairline divider between groups. */\nexport function SelectSeparator({\n className,\n ...props\n}: ComponentProps<typeof SelectPrimitive.Separator>) {\n return (\n <SelectPrimitive.Separator className={cn('my-1 h-px bg-(--rule)', className)} {...props} />\n )\n}\n\nexport default Select\n"],"mappings":";AA6EM,SAUE,KAVF;AA3EN,YAAY,qBAAqB;AACjC,SAAS,OAAO,aAAa,iBAAiB;AAE9C,SAAS,UAAU;AACnB,SAAS,2BAA2B;AACpC,SAAS,cAAc,gBAAgB,iBAAiB;AAGjD,MAAM,aAAa,gBAAgB;AACnC,MAAM,cAAc,gBAAgB;AAmDpC,SAAS,OAAO;AAAA,EACrB;AAAA,EACA,cAAc;AAAA,EACd;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA,GAAG;AACL,GAAgB;AACd,QAAM,MAAM,UAAU,OAAO;AAC7B,QAAM,YAAY,oBAAoB;AAEtC,SACE,qBAAC,gBAAgB,MAAhB,EAAqB,UAAqB,GAAG,OAC5C;AAAA;AAAA,MAAC,gBAAgB;AAAA,MAAhB;AAAA,QACC,cAAY;AAAA,QACZ,gBAAc,OAAO;AAAA,QACrB,WAAW;AAAA,UACT;AAAA,UACA;AAAA,UACA,MAAM,eAAe,UAAU,eAAe;AAAA,UAC9C;AAAA,QACF;AAAA,QAEA;AAAA,8BAAC,gBAAgB,OAAhB,EAAsB,aAA0B;AAAA,UACjD,oBAAC,gBAAgB,MAAhB,EAAqB,SAAO,MAC3B;AAAA,YAAC;AAAA;AAAA,cACC,MAAM;AAAA,cACN,aAAa;AAAA,cACb,eAAW;AAAA,cACX,WAAU;AAAA;AAAA,UACZ,GACF;AAAA;AAAA;AAAA,IACF;AAAA,IAEA,oBAAC,gBAAgB,QAAhB,EAAuB,WAAW,aAAa,QAC9C;AAAA,MAAC,gBAAgB;AAAA,MAAhB;AAAA,QACD,mBAAmB,aAAa;AAAA,QAChC,kBAAkB;AAAA,QAChB,UAAS;AAAA,QACT,YAAY;AAAA,QACZ,qBAAiB;AAAA,QACjB,WAAW;AAAA,UACT;AAAA,UACA;AAAA,UACA;AAAA,QACF;AAAA,QAEA;AAAA,8BAAC,gBAAgB,gBAAhB,EAA+B,WAAU,0DACxC,8BAAC,aAAU,MAAM,IAAI,aAAa,KAAK,eAAW,MAAC,GACrD;AAAA,UACA,oBAAC,gBAAgB,UAAhB,EAAyB,WAAU,SAAS,UAAS;AAAA,UACtD,oBAAC,gBAAgB,kBAAhB,EAAiC,WAAU,0DAC1C,8BAAC,eAAY,MAAM,IAAI,aAAa,KAAK,eAAW,MAAC,GACvD;AAAA;AAAA;AAAA,IACF,GACF;AAAA,KACF;AAEJ;AAKO,SAAS,WAAW,EAAE,WAAW,UAAU,GAAG,MAAM,GAAoB;AAC7E,SACE;AAAA,IAAC,gBAAgB;AAAA,IAAhB;AAAA,MACC,WAAW;AAAA,QACT;AAAA,QACA;AAAA,MACF;AAAA,MACC,GAAG;AAAA,MAIJ;AAAA,4BAAC,UAAK,WAAU,6CACd,8BAAC,gBAAgB,eAAhB,EAA8B,SAAO,MACpC,8BAAC,SAAM,MAAM,IAAI,aAAa,GAAG,eAAW,MAAC,GAC/C,GACF;AAAA,QACA,oBAAC,gBAAgB,UAAhB,EAA0B,UAAS;AAAA;AAAA;AAAA,EACtC;AAEJ;AASO,SAAS,YAAY;AAAA,EAC1B;AAAA,EACA,GAAG;AACL,GAAiD;AAC/C,SACE;AAAA,IAAC,gBAAgB;AAAA,IAAhB;AAAA,MACC,WAAW,GAAG,2CAA2C,SAAS;AAAA,MACjE,GAAG;AAAA;AAAA,EACN;AAEJ;AAGO,SAAS,gBAAgB;AAAA,EAC9B;AAAA,EACA,GAAG;AACL,GAAqD;AACnD,SACE,oBAAC,gBAAgB,WAAhB,EAA0B,WAAW,GAAG,yBAAyB,SAAS,GAAI,GAAG,OAAO;AAE7F;AAEA,IAAO,iBAAQ;","names":[]}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import * as react from 'react';
|
|
2
|
+
import { HTMLAttributes } from 'react';
|
|
3
|
+
|
|
4
|
+
interface SeparatorProps extends HTMLAttributes<HTMLDivElement> {
|
|
5
|
+
orientation?: 'horizontal' | 'vertical';
|
|
6
|
+
/** `hairline` divides rows inside one block; `edge` divides one block from the next. */
|
|
7
|
+
weight?: 'hairline' | 'edge' | 'hard';
|
|
8
|
+
/**
|
|
9
|
+
* A rule that only groups things visually is decoration and must not be
|
|
10
|
+
* announced. Set `false` when the rule genuinely separates two sections a
|
|
11
|
+
* screen reader should hear as distinct.
|
|
12
|
+
*/
|
|
13
|
+
decorative?: boolean;
|
|
14
|
+
}
|
|
15
|
+
/**
|
|
16
|
+
* A rule.
|
|
17
|
+
*
|
|
18
|
+
* In a monochrome system the rule does the work colour would otherwise do, so
|
|
19
|
+
* it has three weights rather than one: hairline between rows, edge between
|
|
20
|
+
* blocks, hard under a masthead. Picking by name keeps a page from drifting
|
|
21
|
+
* into five hand-tuned greys.
|
|
22
|
+
*
|
|
23
|
+
* @example
|
|
24
|
+
* <Separator weight="hard" />
|
|
25
|
+
* @example
|
|
26
|
+
* <Separator orientation="vertical" className="h-4" />
|
|
27
|
+
*/
|
|
28
|
+
declare function Separator({ orientation, weight, decorative, className, ...rest }: SeparatorProps): react.JSX.Element;
|
|
29
|
+
|
|
30
|
+
export { Separator, type SeparatorProps, Separator as default };
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import { jsx } from "react/jsx-runtime";
|
|
2
|
+
import { cn } from "../../lib/cn.js";
|
|
3
|
+
const WEIGHT = {
|
|
4
|
+
hairline: "bg-(--rule)",
|
|
5
|
+
edge: "bg-(--rule-2)",
|
|
6
|
+
hard: "bg-(--rule-hard)"
|
|
7
|
+
};
|
|
8
|
+
function Separator({
|
|
9
|
+
orientation = "horizontal",
|
|
10
|
+
weight = "hairline",
|
|
11
|
+
decorative = true,
|
|
12
|
+
className,
|
|
13
|
+
...rest
|
|
14
|
+
}) {
|
|
15
|
+
return /* @__PURE__ */ jsx(
|
|
16
|
+
"div",
|
|
17
|
+
{
|
|
18
|
+
role: decorative ? "none" : "separator",
|
|
19
|
+
"aria-orientation": decorative ? void 0 : orientation,
|
|
20
|
+
className: cn(
|
|
21
|
+
"shrink-0",
|
|
22
|
+
orientation === "horizontal" ? "h-px w-full" : "h-full w-px",
|
|
23
|
+
WEIGHT[weight],
|
|
24
|
+
className
|
|
25
|
+
),
|
|
26
|
+
...rest
|
|
27
|
+
}
|
|
28
|
+
);
|
|
29
|
+
}
|
|
30
|
+
var Separator_default = Separator;
|
|
31
|
+
export {
|
|
32
|
+
Separator,
|
|
33
|
+
Separator_default as default
|
|
34
|
+
};
|
|
35
|
+
//# sourceMappingURL=Separator.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../../src/components/Separator/Separator.tsx"],"sourcesContent":["import type { HTMLAttributes } from 'react'\nimport { cn } from '../../lib/cn'\n\nexport interface SeparatorProps extends HTMLAttributes<HTMLDivElement> {\n orientation?: 'horizontal' | 'vertical'\n /** `hairline` divides rows inside one block; `edge` divides one block from the next. */\n weight?: 'hairline' | 'edge' | 'hard'\n /**\n * A rule that only groups things visually is decoration and must not be\n * announced. Set `false` when the rule genuinely separates two sections a\n * screen reader should hear as distinct.\n */\n decorative?: boolean\n}\n\nconst WEIGHT = {\n hairline: 'bg-(--rule)',\n edge: 'bg-(--rule-2)',\n hard: 'bg-(--rule-hard)',\n} as const\n\n/**\n * A rule.\n *\n * In a monochrome system the rule does the work colour would otherwise do, so\n * it has three weights rather than one: hairline between rows, edge between\n * blocks, hard under a masthead. Picking by name keeps a page from drifting\n * into five hand-tuned greys.\n *\n * @example\n * <Separator weight=\"hard\" />\n * @example\n * <Separator orientation=\"vertical\" className=\"h-4\" />\n */\nexport function Separator({\n orientation = 'horizontal',\n weight = 'hairline',\n decorative = true,\n className,\n ...rest\n}: SeparatorProps) {\n return (\n <div\n role={decorative ? 'none' : 'separator'}\n aria-orientation={decorative ? undefined : orientation}\n className={cn(\n 'shrink-0',\n orientation === 'horizontal' ? 'h-px w-full' : 'h-full w-px',\n WEIGHT[weight],\n className,\n )}\n {...rest}\n />\n )\n}\n\nexport default Separator\n"],"mappings":"AA0CI;AAzCJ,SAAS,UAAU;AAcnB,MAAM,SAAS;AAAA,EACb,UAAU;AAAA,EACV,MAAM;AAAA,EACN,MAAM;AACR;AAeO,SAAS,UAAU;AAAA,EACxB,cAAc;AAAA,EACd,SAAS;AAAA,EACT,aAAa;AAAA,EACb;AAAA,EACA,GAAG;AACL,GAAmB;AACjB,SACE;AAAA,IAAC;AAAA;AAAA,MACC,MAAM,aAAa,SAAS;AAAA,MAC5B,oBAAkB,aAAa,SAAY;AAAA,MAC3C,WAAW;AAAA,QACT;AAAA,QACA,gBAAgB,eAAe,gBAAgB;AAAA,QAC/C,OAAO,MAAM;AAAA,QACb;AAAA,MACF;AAAA,MACC,GAAG;AAAA;AAAA,EACN;AAEJ;AAEA,IAAO,oBAAQ;","names":[]}
|
|
@@ -0,0 +1,38 @@
|
|
|
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 and close — a sheet IS a dialog, docked. */
|
|
6
|
+
declare const Sheet: react.FC<DialogPrimitive.DialogProps>;
|
|
7
|
+
declare const SheetTrigger: react.ForwardRefExoticComponent<DialogPrimitive.DialogTriggerProps & react.RefAttributes<HTMLButtonElement>>;
|
|
8
|
+
declare const SheetClose: react.ForwardRefExoticComponent<DialogPrimitive.DialogCloseProps & react.RefAttributes<HTMLButtonElement>>;
|
|
9
|
+
type SheetSide = 'start' | 'end' | 'top' | 'bottom';
|
|
10
|
+
interface SheetContentProps extends Omit<ComponentProps<typeof DialogPrimitive.Content>, 'title'> {
|
|
11
|
+
/** Which edge it is docked to. `end` by default. */
|
|
12
|
+
side?: SheetSide;
|
|
13
|
+
title: ReactNode;
|
|
14
|
+
description?: ReactNode;
|
|
15
|
+
/** Hide the title visually while keeping it for assistive tech. */
|
|
16
|
+
hideTitle?: boolean;
|
|
17
|
+
}
|
|
18
|
+
/**
|
|
19
|
+
* A panel docked to an edge of the viewport.
|
|
20
|
+
*
|
|
21
|
+
* It is a modal dialog — Radix's, so the focus trap, the escape key, the scroll
|
|
22
|
+
* lock and the `aria-modal` wiring are the same ones `Dialog` gets. The only
|
|
23
|
+
* differences are where it sits and which way it arrives, which is why this
|
|
24
|
+
* shares that implementation rather than reproducing it: a second focus trap is
|
|
25
|
+
* a second focus trap to get wrong.
|
|
26
|
+
*
|
|
27
|
+
* The title is required, visible or not. A modal with no accessible name drops
|
|
28
|
+
* a screen reader into an unnamed region with no way back out.
|
|
29
|
+
*
|
|
30
|
+
* @example
|
|
31
|
+
* <Sheet>
|
|
32
|
+
* <SheetTrigger asChild><Button variant="secondary">Filters</Button></SheetTrigger>
|
|
33
|
+
* <SheetContent title="Filters" description="Narrow the list.">…</SheetContent>
|
|
34
|
+
* </Sheet>
|
|
35
|
+
*/
|
|
36
|
+
declare function SheetContent({ side, title, description, hideTitle, className, children, ...rest }: SheetContentProps): react.JSX.Element;
|
|
37
|
+
|
|
38
|
+
export { Sheet, SheetClose, SheetContent, type SheetContentProps, type SheetSide, SheetTrigger, Sheet as default };
|
|
@@ -0,0 +1,68 @@
|
|
|
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 Sheet = DialogPrimitive.Root;
|
|
7
|
+
const SheetTrigger = DialogPrimitive.Trigger;
|
|
8
|
+
const SheetClose = DialogPrimitive.Close;
|
|
9
|
+
const SIDE = {
|
|
10
|
+
start: "inset-y-0 start-0 h-full w-[min(24rem,92vw)] border-e data-[state=closed]:-translate-x-full rtl:data-[state=closed]:translate-x-full",
|
|
11
|
+
end: "inset-y-0 end-0 h-full w-[min(24rem,92vw)] border-s data-[state=closed]:translate-x-full rtl:data-[state=closed]:-translate-x-full",
|
|
12
|
+
top: "inset-x-0 top-0 w-full max-h-[85vh] border-b data-[state=closed]:-translate-y-full",
|
|
13
|
+
bottom: "inset-x-0 bottom-0 w-full max-h-[85vh] border-t data-[state=closed]:translate-y-full"
|
|
14
|
+
};
|
|
15
|
+
function SheetContent({
|
|
16
|
+
side = "end",
|
|
17
|
+
title,
|
|
18
|
+
description,
|
|
19
|
+
hideTitle = false,
|
|
20
|
+
className,
|
|
21
|
+
children,
|
|
22
|
+
...rest
|
|
23
|
+
}) {
|
|
24
|
+
return /* @__PURE__ */ jsxs(DialogPrimitive.Portal, { children: [
|
|
25
|
+
/* @__PURE__ */ jsx(
|
|
26
|
+
DialogPrimitive.Overlay,
|
|
27
|
+
{
|
|
28
|
+
"data-m22-animated": true,
|
|
29
|
+
className: "fixed inset-0 z-(--z-overlay) bg-(--scrim) data-[state=open]:animate-[m22-fade-in_var(--duration-fast)_var(--ease)]"
|
|
30
|
+
}
|
|
31
|
+
),
|
|
32
|
+
/* @__PURE__ */ jsxs(
|
|
33
|
+
DialogPrimitive.Content,
|
|
34
|
+
{
|
|
35
|
+
className: cn(
|
|
36
|
+
"fixed z-(--z-modal) flex flex-col overflow-y-auto border-(--rule-2) bg-(--paper) p-6 transition-transform duration-(--duration-slow) ease-(--ease-out-expo) scroll-slim",
|
|
37
|
+
SIDE[side],
|
|
38
|
+
className
|
|
39
|
+
),
|
|
40
|
+
...rest,
|
|
41
|
+
children: [
|
|
42
|
+
/* @__PURE__ */ jsxs("div", { className: cn("mb-4 flex flex-col gap-1 pe-8", hideTitle && "sr-only"), children: [
|
|
43
|
+
/* @__PURE__ */ jsx(DialogPrimitive.Title, { className: "m-0 font-heading text-[length:var(--fs-item)] font-normal text-(--ink)", children: title }),
|
|
44
|
+
description !== void 0 && /* @__PURE__ */ jsx(DialogPrimitive.Description, { className: "m-0 text-sm leading-relaxed text-(--ink-3-aa)", children: description })
|
|
45
|
+
] }),
|
|
46
|
+
/* @__PURE__ */ jsx(
|
|
47
|
+
DialogPrimitive.Close,
|
|
48
|
+
{
|
|
49
|
+
"aria-label": "Close",
|
|
50
|
+
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)",
|
|
51
|
+
children: /* @__PURE__ */ jsx(X, { size: 16, strokeWidth: 1.5, "aria-hidden": true })
|
|
52
|
+
}
|
|
53
|
+
),
|
|
54
|
+
children
|
|
55
|
+
]
|
|
56
|
+
}
|
|
57
|
+
)
|
|
58
|
+
] });
|
|
59
|
+
}
|
|
60
|
+
var Sheet_default = Sheet;
|
|
61
|
+
export {
|
|
62
|
+
Sheet,
|
|
63
|
+
SheetClose,
|
|
64
|
+
SheetContent,
|
|
65
|
+
SheetTrigger,
|
|
66
|
+
Sheet_default as default
|
|
67
|
+
};
|
|
68
|
+
//# sourceMappingURL=Sheet.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../../src/components/Sheet/Sheet.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 and close — a sheet IS a dialog, docked. */\nexport const Sheet = DialogPrimitive.Root\nexport const SheetTrigger = DialogPrimitive.Trigger\nexport const SheetClose = DialogPrimitive.Close\n\nexport type SheetSide = 'start' | 'end' | 'top' | 'bottom'\n\n/**\n * Full literal class strings per edge, because Tailwind only generates what it\n * can see verbatim. The inline sides are named in READING order, so a sheet\n * docked to `end` comes from the right in English and the left in Arabic.\n */\nconst SIDE: Record<SheetSide, string> = {\n start:\n 'inset-y-0 start-0 h-full w-[min(24rem,92vw)] border-e data-[state=closed]:-translate-x-full rtl:data-[state=closed]:translate-x-full',\n end: 'inset-y-0 end-0 h-full w-[min(24rem,92vw)] border-s data-[state=closed]:translate-x-full rtl:data-[state=closed]:-translate-x-full',\n top: 'inset-x-0 top-0 w-full max-h-[85vh] border-b data-[state=closed]:-translate-y-full',\n bottom:\n 'inset-x-0 bottom-0 w-full max-h-[85vh] border-t data-[state=closed]:translate-y-full',\n}\n\nexport interface SheetContentProps\n extends Omit<ComponentProps<typeof DialogPrimitive.Content>, 'title'> {\n /** Which edge it is docked to. `end` by default. */\n side?: SheetSide\n title: ReactNode\n description?: ReactNode\n /** Hide the title visually while keeping it for assistive tech. */\n hideTitle?: boolean\n}\n\n/**\n * A panel docked to an edge of the viewport.\n *\n * It is a modal dialog — Radix's, so the focus trap, the escape key, the scroll\n * lock and the `aria-modal` wiring are the same ones `Dialog` gets. The only\n * differences are where it sits and which way it arrives, which is why this\n * shares that implementation rather than reproducing it: a second focus trap is\n * a second focus trap to get wrong.\n *\n * The title is required, visible or not. A modal with no accessible name drops\n * a screen reader into an unnamed region with no way back out.\n *\n * @example\n * <Sheet>\n * <SheetTrigger asChild><Button variant=\"secondary\">Filters</Button></SheetTrigger>\n * <SheetContent title=\"Filters\" description=\"Narrow the list.\">…</SheetContent>\n * </Sheet>\n */\nexport function SheetContent({\n side = 'end',\n title,\n description,\n hideTitle = false,\n className,\n children,\n ...rest\n}: SheetContentProps) {\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 className={cn(\n 'fixed z-(--z-modal) flex flex-col overflow-y-auto border-(--rule-2) bg-(--paper) p-6 transition-transform duration-(--duration-slow) ease-(--ease-out-expo) scroll-slim',\n SIDE[side],\n className,\n )}\n {...rest}\n >\n <div className={cn('mb-4 flex flex-col gap-1 pe-8', hideTitle && 'sr-only')}>\n <DialogPrimitive.Title className=\"m-0 font-heading text-[length:var(--fs-item)] font-normal text-(--ink)\">\n {title}\n </DialogPrimitive.Title>\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 <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 {children}\n </DialogPrimitive.Content>\n </DialogPrimitive.Portal>\n )\n}\n\nexport default Sheet\n"],"mappings":";AAmEM,cAYE,YAZF;AAjEN,YAAY,qBAAqB;AACjC,SAAS,SAAS;AAElB,SAAS,UAAU;AAGZ,MAAM,QAAQ,gBAAgB;AAC9B,MAAM,eAAe,gBAAgB;AACrC,MAAM,aAAa,gBAAgB;AAS1C,MAAM,OAAkC;AAAA,EACtC,OACE;AAAA,EACF,KAAK;AAAA,EACL,KAAK;AAAA,EACL,QACE;AACJ;AA8BO,SAAS,aAAa;AAAA,EAC3B,OAAO;AAAA,EACP;AAAA,EACA;AAAA,EACA,YAAY;AAAA,EACZ;AAAA,EACA;AAAA,EACA,GAAG;AACL,GAAsB;AACpB,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,WAAW;AAAA,UACT;AAAA,UACA,KAAK,IAAI;AAAA,UACT;AAAA,QACF;AAAA,QACC,GAAG;AAAA,QAEJ;AAAA,+BAAC,SAAI,WAAW,GAAG,iCAAiC,aAAa,SAAS,GACxE;AAAA,gCAAC,gBAAgB,OAAhB,EAAsB,WAAU,0EAC9B,iBACH;AAAA,YACC,gBAAgB,UACf,oBAAC,gBAAgB,aAAhB,EAA4B,WAAU,iDACpC,uBACH;AAAA,aAEJ;AAAA,UAEA;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,UAEC;AAAA;AAAA;AAAA,IACH;AAAA,KACF;AAEJ;AAEA,IAAO,gBAAQ;","names":[]}
|