@misoto22/folio 0.17.1 → 0.18.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/agent/Accordion.md +1 -1
- package/dist/agent/Actions.md +1 -1
- package/dist/agent/Alert.md +1 -1
- package/dist/agent/AppShell.md +1 -1
- package/dist/agent/ArchitectureFigure.md +1 -1
- package/dist/agent/AreaChart.md +1 -1
- package/dist/agent/Article.md +1 -1
- package/dist/agent/AspectRatio.md +1 -1
- package/dist/agent/Avatar.md +1 -1
- package/dist/agent/Badge.md +1 -1
- package/dist/agent/BarChart.md +1 -1
- package/dist/agent/BarList.md +1 -1
- package/dist/agent/BigNumber.md +1 -1
- package/dist/agent/BoxPlot.md +1 -1
- package/dist/agent/Breadcrumb.md +1 -1
- package/dist/agent/BulletChart.md +1 -1
- package/dist/agent/Button.md +1 -1
- package/dist/agent/Calendar.md +1 -1
- package/dist/agent/CalendarHeatmap.md +1 -1
- package/dist/agent/Card.md +1 -1
- package/dist/agent/Checkbox.md +1 -1
- package/dist/agent/Code.md +1 -1
- package/dist/agent/CodeBlock.md +1 -1
- package/dist/agent/Collapsible.md +1 -1
- package/dist/agent/Collection.md +1 -1
- package/dist/agent/ColorPicker.md +1 -1
- package/dist/agent/Combobox.md +1 -1
- package/dist/agent/Command.md +2 -1
- package/dist/agent/ComposedChart.md +1 -1
- package/dist/agent/Contact.md +1 -1
- package/dist/agent/Content.md +1 -1
- package/dist/agent/ContextMenu.md +1 -1
- package/dist/agent/Conversation.md +1 -1
- package/dist/agent/DataflowFigure.md +1 -1
- package/dist/agent/DatePicker.md +1 -1
- package/dist/agent/DescriptionList.md +1 -1
- package/dist/agent/Diagram.md +1 -1
- package/dist/agent/DiagramCanvas.md +1 -1
- package/dist/agent/DiagramExportMenu.md +1 -1
- package/dist/agent/DiagramInspector.md +1 -1
- package/dist/agent/DiagramLegend.md +1 -1
- package/dist/agent/DiagramMinimap.md +1 -1
- package/dist/agent/DiagramToolbar.md +1 -1
- package/dist/agent/Dialog.md +1 -1
- package/dist/agent/DropdownMenu.md +1 -1
- package/dist/agent/EmptyState.md +1 -1
- package/dist/agent/ErrorState.md +1 -1
- package/dist/agent/Evidence.md +1 -1
- package/dist/agent/Facet.md +1 -1
- package/dist/agent/Field.md +1 -1
- package/dist/agent/FigureBand.md +1 -1
- package/dist/agent/FloatingIconButton.md +1 -1
- package/dist/agent/FunnelChart.md +1 -1
- package/dist/agent/Heading.md +1 -1
- package/dist/agent/Heatmap.md +1 -1
- package/dist/agent/Histogram.md +1 -1
- package/dist/agent/Input.md +1 -1
- package/dist/agent/Kbd.md +1 -1
- package/dist/agent/LifecycleFigure.md +1 -1
- package/dist/agent/LineChart.md +1 -1
- package/dist/agent/LinkArrow.md +1 -1
- package/dist/agent/Markdown.md +1 -1
- package/dist/agent/Media.md +1 -1
- package/dist/agent/Metric.md +1 -1
- package/dist/agent/Metrics.md +1 -1
- package/dist/agent/Music.md +1 -1
- package/dist/agent/NativeSelect.md +1 -1
- package/dist/agent/NavItem.md +1 -1
- package/dist/agent/NumberField.md +1 -1
- package/dist/agent/PageHeader.md +1 -1
- package/dist/agent/Pagination.md +1 -1
- package/dist/agent/PieChart.md +1 -1
- package/dist/agent/Popover.md +1 -1
- package/dist/agent/Portfolio.md +1 -1
- package/dist/agent/PortfolioIndex.md +1 -1
- package/dist/agent/Progress.md +1 -1
- package/dist/agent/RadarChart.md +1 -1
- package/dist/agent/RadialChart.md +1 -1
- package/dist/agent/RadioGroup.md +1 -1
- package/dist/agent/Reading.md +10 -1
- package/dist/agent/Recovery.md +3 -3
- package/dist/agent/SankeyChart.md +1 -1
- package/dist/agent/ScatterChart.md +1 -1
- package/dist/agent/ScrollArea.md +1 -1
- package/dist/agent/SearchPalette.md +1 -1
- package/dist/agent/SearchableMenu.md +1 -1
- package/dist/agent/Select.md +1 -1
- package/dist/agent/Separator.md +1 -1
- package/dist/agent/SequenceFigure.md +1 -1
- package/dist/agent/Sheet.md +1 -1
- package/dist/agent/Sidebar.md +1 -1
- package/dist/agent/SiteNavigation.md +1 -1
- package/dist/agent/SiteShell.md +1 -1
- package/dist/agent/Skeleton.md +1 -1
- package/dist/agent/Slider.md +1 -1
- package/dist/agent/Sparkline.md +1 -1
- package/dist/agent/Spinner.md +1 -1
- package/dist/agent/StatusDot.md +1 -1
- package/dist/agent/StatusPill.md +1 -1
- package/dist/agent/Steps.md +1 -1
- package/dist/agent/Switch.md +1 -1
- package/dist/agent/Table.md +1 -1
- package/dist/agent/Tabs.md +1 -1
- package/dist/agent/Tag.md +1 -1
- package/dist/agent/Text.md +1 -1
- package/dist/agent/Textarea.md +1 -1
- package/dist/agent/Timeline.md +6 -2
- package/dist/agent/Timestamp.md +1 -1
- package/dist/agent/Toast.md +1 -1
- package/dist/agent/ToggleGroup.md +1 -1
- package/dist/agent/Toolbar.md +1 -1
- package/dist/agent/Tooltip.md +1 -1
- package/dist/agent/TreemapChart.md +1 -1
- package/dist/agent/WaterfallChart.md +1 -1
- package/dist/agent/Workbench.md +1 -1
- package/dist/agent/WorkflowFigure.md +1 -1
- package/dist/agent/catalog.json +10 -1
- package/dist/agent/index.md +2 -1
- package/dist/components/Button/Button.js +1 -1
- package/dist/components/Button/Button.js.map +1 -1
- package/dist/components/Command/Command.d.ts +3 -1
- package/dist/components/Command/Command.js +3 -2
- package/dist/components/Command/Command.js.map +1 -1
- package/dist/keyframes.css +22 -0
- package/dist/styles.css +1 -1
- package/dist/themes.css +11 -0
- package/dist/tokens.css +14 -0
- package/dist/tokens.d.ts +4 -0
- package/dist/tokens.js +21 -0
- package/dist/tokens.json +21 -0
- package/dist/website/Media/Media.js +2 -2
- package/dist/website/Media/Media.js.map +1 -1
- package/dist/website/Reading/Reading.d.ts +7 -1
- package/dist/website/Reading/Reading.js +4 -0
- package/dist/website/Reading/Reading.js.map +1 -1
- package/dist/website/Recovery/Recovery.d.ts +10 -2
- package/dist/website/Recovery/Recovery.js +36 -2
- package/dist/website/Recovery/Recovery.js.map +1 -1
- package/dist/website/SearchPalette/SearchPalette.js +2 -0
- package/dist/website/SearchPalette/SearchPalette.js.map +1 -1
- package/dist/website/Timeline/Timeline.d.ts +11 -2
- package/dist/website/Timeline/Timeline.js +7 -1
- package/dist/website/Timeline/Timeline.js.map +1 -1
- package/dist/website/Workbench/theme.d.ts +2 -1
- package/dist/website/Workbench/theme.js +2 -1
- package/dist/website/Workbench/theme.js.map +1 -1
- package/dist/website/index.d.ts +2 -2
- package/dist/website-media.css +10 -4
- package/dist/website-reading.css +15 -4
- package/dist/website-recovery.css +8 -0
- package/dist/website-search.css +28 -14
- package/dist/website-timeline.css +6 -0
- package/package.json +1 -1
- package/skills/folio-design/rules/tokens.md +1 -0
package/dist/agent/catalog.json
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
{
|
|
2
|
-
"version": "0.
|
|
2
|
+
"version": "0.18.0",
|
|
3
3
|
"groups": [
|
|
4
4
|
"Actions",
|
|
5
5
|
"Forms",
|
|
@@ -7880,6 +7880,7 @@
|
|
|
7880
7880
|
"ActionBand": "Reading",
|
|
7881
7881
|
"FeaturePairs": "Reading",
|
|
7882
7882
|
"DevicePreview": "Reading",
|
|
7883
|
+
"DeviceRow": "Reading",
|
|
7883
7884
|
"PreviewPair": "Reading",
|
|
7884
7885
|
"CommandTabs": "Reading",
|
|
7885
7886
|
"ReadingSurface": "Reading",
|
|
@@ -7912,6 +7913,7 @@
|
|
|
7912
7913
|
"ProfileFigure": "Timeline",
|
|
7913
7914
|
"Timeline": "Timeline",
|
|
7914
7915
|
"TimelineItem": "Timeline",
|
|
7916
|
+
"CareerRecordTag": "Timeline",
|
|
7915
7917
|
"WorkbenchSection": "Workbench",
|
|
7916
7918
|
"Chronology": "Workbench",
|
|
7917
7919
|
"ContactRow": "Workbench",
|
|
@@ -7955,6 +7957,13 @@
|
|
|
7955
7957
|
],
|
|
7956
7958
|
"unset": "the neutral series ramp"
|
|
7957
7959
|
},
|
|
7960
|
+
{
|
|
7961
|
+
"axis": "data-controls",
|
|
7962
|
+
"values": [
|
|
7963
|
+
"pill"
|
|
7964
|
+
],
|
|
7965
|
+
"unset": "the control step of the radius ladder"
|
|
7966
|
+
},
|
|
7958
7967
|
{
|
|
7959
7968
|
"axis": "data-density",
|
|
7960
7969
|
"values": [
|
package/dist/agent/index.md
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
# @misoto22/folio 0.
|
|
1
|
+
# @misoto22/folio 0.18.0
|
|
2
2
|
|
|
3
3
|
> Monochrome design system: portable CSS tokens and accessible React 19
|
|
4
4
|
> primitives. Components ship compiled — import them, do not copy them.
|
|
@@ -19,6 +19,7 @@ An unset axis is the default.
|
|
|
19
19
|
- `data-accent`: `clay` `cobalt` `ember` `forest` `ink` `moss` `plum` (unset = ink)
|
|
20
20
|
- `data-action`: `accent` `ink` (unset = accent)
|
|
21
21
|
- `data-chart-palette`: `accent` `chroma` (unset = the neutral series ramp)
|
|
22
|
+
- `data-controls`: `pill` (unset = the control step of the radius ladder)
|
|
22
23
|
- `data-density`: `comfortable` `compact` (unset = comfortable)
|
|
23
24
|
- `data-mode`: `dark` `light` (unset = follows the app)
|
|
24
25
|
- `data-motion`: `snappy` `still` (unset = calm)
|
|
@@ -3,7 +3,7 @@ import { Slot } from "@radix-ui/react-slot";
|
|
|
3
3
|
import { cn } from "../../lib/cn.js";
|
|
4
4
|
import { DEV, warn } from "../../lib/warn.js";
|
|
5
5
|
import { Spinner } from "../Spinner/Spinner.js";
|
|
6
|
-
const BASE = "inline-flex items-center justify-center gap-(--control-gap) rounded-(--radius) font-sans transition-[opacity,color,border-color,background-color] duration-(--duration-fast) ease-(--ease-out-expo) disabled:opacity-(--disabled-opacity) disabled:pointer-events-none aria-disabled:opacity-(--disabled-opacity) aria-disabled:pointer-events-none";
|
|
6
|
+
const BASE = "inline-flex items-center justify-center gap-(--control-gap) rounded-(--radius-control) font-sans transition-[opacity,color,border-color,background-color] duration-(--duration-fast) ease-(--ease-out-expo) disabled:opacity-(--disabled-opacity) disabled:pointer-events-none aria-disabled:opacity-(--disabled-opacity) aria-disabled:pointer-events-none";
|
|
7
7
|
const VARIANT = {
|
|
8
8
|
primary: "bg-(--action) text-(--action-foreground) border border-(--action) hover:opacity-85",
|
|
9
9
|
secondary: "border border-(--rule-2) text-(--ink) bg-transparent hover:border-(--ink)",
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../src/components/Button/Button.tsx"],"sourcesContent":["import { Slot } from '@radix-ui/react-slot'\nimport type { AnchorHTMLAttributes, ButtonHTMLAttributes, ReactNode } from 'react'\nimport { cn } from '../../lib/cn'\nimport { DEV, warn } from '../../lib/warn'\nimport { Spinner } from '../Spinner/Spinner'\n\nexport type ButtonVariant = 'primary' | 'secondary' | 'ghost' | 'danger'\nexport type ButtonSize = 'sm' | 'md' | 'lg'\n\n/**\n * The base every variant shares.\n *\n * It reads `--radius`, the CONTROL step, which is the same corner an `Input`,\n * a `Select` trigger and a `Textarea` draw. It used to be a pill, and a pill\n * beside an 8px field is two different ideas of what a control is — the one\n * inconsistency in the system that every reader noticed and none of the\n * component pages could explain. Everything on the control line now agrees,\n * and the capsule is kept for the things that genuinely are one: a badge, a\n * status pill, a segmented strip, a progress track.\n *\n * It does not move on hover. An earlier base lifted a pixel and asked for a\n * shadow the White Reset does not have — `--shadow` resolves to `none`, so that\n * hover state was invisible on every button in the system while still costing a\n * transition. Opacity carries the filled hover; the border carries the outlined\n * one.\n *\n * The transition names its properties rather than using `all`, so a layout\n * change (a width that grows when the label becomes \"Saving…\") is instant\n * instead of sliding.\n */\nconst BASE =\n 'inline-flex items-center justify-center gap-(--control-gap) rounded-(--radius) font-sans transition-[opacity,color,border-color,background-color] duration-(--duration-fast) ease-(--ease-out-expo) disabled:opacity-(--disabled-opacity) disabled:pointer-events-none aria-disabled:opacity-(--disabled-opacity) aria-disabled:pointer-events-none'\n\nconst VARIANT: Record<ButtonVariant, string> = {\n primary: 'bg-(--action) text-(--action-foreground) border border-(--action) hover:opacity-85',\n secondary: 'border border-(--rule-2) text-(--ink) bg-transparent hover:border-(--ink)',\n ghost: 'border border-transparent text-(--ink-2) hover:text-(--ink) hover:bg-(--stone)',\n /* The one place chroma is allowed on a control, and only because the action\n is destructive — that is a state, not a brand colour. */\n danger: 'bg-(--danger) text-(--paper) border border-(--danger) hover:opacity-85',\n}\n\n/**\n * `min-h` rather than `h`, so a button that wraps to two lines grows instead of\n * clipping.\n *\n * The heights come from the density tokens rather than from a literal, so a\n * subtree marked `data-density=\"compact\"` shrinks its controls without a single\n * call site being told. At the default density `md` is 44px — the pointer\n * target WCAG 2.5.5 asks for.\n *\n * `--control-lh` is what makes those numbers true rather than aspirational. A\n * floor only binds while the box is under it, and the box is the line plus the\n * padding plus the border — so a label inheriting the body's 1.6 leading put\n * `sm` at 39px against its own 36px token, `md` at 46 against 44 and `lg` at 50\n * against 48. Every size was two to three pixels taller than the number\n * documenting it, which is also how a masthead sized from `--control-h-sm`\n * ended up with a search field standing proud of every icon beside it.\n */\nconst SIZE: Record<ButtonSize, string> = {\n sm: 'min-h-(--control-h-sm) px-(--control-px-sm) py-(--control-py-sm) text-[13px] leading-(--control-lh)',\n md: 'min-h-(--control-h-md) px-(--control-px-md) py-(--control-py-md) text-sm leading-(--control-lh)',\n lg: 'min-h-(--control-h-lg) px-(--control-px-lg) py-(--control-py-lg) text-[15px] leading-(--control-lh)',\n}\n\n/** Square, because an icon has no label to give the box its width. */\nconst ICON_SIZE: Record<ButtonSize, string> = {\n sm: 'size-(--control-h-sm) p-0',\n md: 'size-(--control-h-md) p-0',\n lg: 'size-(--control-h-lg) p-0',\n}\n\nconst SPINNER_SIZE: Record<ButtonSize, 'sm' | 'md'> = { sm: 'sm', md: 'sm', lg: 'md' }\n\ninterface CommonProps {\n children?: ReactNode\n /**\n * Which action this is. `primary` is the one thing the screen wants you to\n * do, so there is at most one per view; `danger` is reserved for destructive\n * actions and is the only place chroma is allowed on a control.\n */\n variant?: ButtonVariant\n /** 36 / 44 / 48px tall. `md` meets the pointer-target floor on its own. */\n size?: ButtonSize\n /** Optional mono keycap glyph rendered after the label (e.g. \"P\"). */\n keycap?: string\n /**\n * Swaps the leading content for a spinner and blocks interaction. The label\n * stays put — a button that empties out while it works loses its width, and\n * the page reflows under the pointer that just clicked it.\n */\n loading?: boolean\n /**\n * Square control with no label. REQUIRES `aria-label`: an icon-only button\n * with no accessible name is invisible to a screen reader, and this is the\n * single most common way a design system ships an unusable control.\n */\n iconOnly?: boolean\n /**\n * Render the child element instead of a `<button>`, keeping these styles.\n * Use it to hand the styling to a router's `Link` — `asChild` is what keeps\n * this package free of any one router.\n *\n * The decoration slots (`keycap`, `loading`) are not injected into a slotted\n * child; compose them inside it yourself.\n *\n * @example\n * <Button asChild><Link href=\"/work\">Work</Link></Button>\n */\n asChild?: boolean\n className?: string\n}\n\ntype ButtonAsLink = CommonProps &\n Omit<AnchorHTMLAttributes<HTMLAnchorElement>, 'className' | 'children'> & { href: string }\n\ntype ButtonAsButton = CommonProps &\n Omit<ButtonHTMLAttributes<HTMLButtonElement>, 'className' | 'children'> & { href?: undefined }\n\nexport type ButtonProps = ButtonAsLink | ButtonAsButton\n\nfunction Keycap({ glyph }: { glyph: string }) {\n return (\n <span className=\"rounded-(--radius-sm) border border-current px-2 py-0.5 font-mono text-[11px] opacity-55\">\n {glyph}\n </span>\n )\n}\n\n/**\n * The system's action.\n *\n * Renders a `<button>`, or an `<a>` when given `href`, or whatever you hand it\n * via `asChild`. No router is imported, so the package stays framework-agnostic\n * and a Next or React Router app wires its own `Link` at the call site.\n *\n * Server-component friendly: there is no client boundary here, so it renders in\n * a static page as well as an interactive one.\n *\n * @example\n * <Button variant=\"secondary\" keycap=\"P\">View projects</Button>\n * @example\n * <Button loading disabled>Saving…</Button>\n * @example\n * <Button iconOnly aria-label=\"Close\"><X size={16} /></Button>\n */\nexport function Button(props: ButtonProps) {\n const {\n children,\n variant = 'primary',\n size = 'md',\n keycap,\n loading = false,\n iconOnly = false,\n asChild = false,\n className,\n } = props\n\n const cls = cn(BASE, VARIANT[variant], iconOnly ? ICON_SIZE[size] : SIZE[size], className)\n\n if (DEV && iconOnly) {\n // The control renders correctly and is announced as \"button\" and nothing\n // else. Nothing about the rendered page says so, which is why this is the\n // single most common way a design system ships an unusable control.\n const named =\n typeof props['aria-label'] === 'string' && props['aria-label'].trim() !== ''\n const described = typeof props['aria-labelledby'] === 'string'\n if (!named && !described) {\n warn({\n code: 'BUTTON_ICON_ONLY_UNNAMED',\n problem:\n 'An iconOnly Button has no text, so without an accessible name a screen reader announces it as \"button\" and nothing else.',\n field: 'aria-label',\n fix: 'Add aria-label with the action the button performs, e.g. aria-label=\"Delete invoice\".',\n component: 'Button',\n })\n }\n }\n\n // A filled ground needs a spinner in the inherited colour; an outlined one\n // reads better against the page's own rule scale.\n const spinnerTone = variant === 'primary' || variant === 'danger' ? 'current' : 'default'\n const decoration = (\n <>\n {loading && <Spinner size={SPINNER_SIZE[size]} tone={spinnerTone} label={null} />}\n {children}\n {keycap && <Keycap glyph={keycap} />}\n </>\n )\n\n if (asChild) {\n const { children: _c, variant: _v, size: _s, keycap: _k, loading: _l, iconOnly: _i, asChild: _a, className: _cn, ...rest } = props\n return (\n <Slot className={cls} {...rest}>\n {children}\n </Slot>\n )\n }\n\n if (props.href !== undefined) {\n const { children: _c, variant: _v, size: _s, keycap: _k, loading: _l, iconOnly: _i, asChild: _a, className: _cn, href, ...rest } = props\n return (\n <a\n href={href}\n className={cls}\n // A link cannot be `disabled`; `aria-disabled` plus the pointer-events\n // rule in BASE is the accessible equivalent.\n aria-disabled={loading || undefined}\n {...rest}\n >\n {decoration}\n </a>\n )\n }\n\n const { children: _c, variant: _v, size: _s, keycap: _k, loading: _l, iconOnly: _i, asChild: _a, className: _cn, ...rest } = props\n return (\n <button\n type={rest.type ?? 'button'}\n aria-busy={loading || undefined}\n disabled={rest.disabled || loading}\n className={cls}\n {...rest}\n >\n {decoration}\n </button>\n )\n}\n\nexport default Button\n"],"mappings":"AA2HI,SA4DA,UA5DA,KA4DA,YA5DA;AA3HJ,SAAS,YAAY;AAErB,SAAS,UAAU;AACnB,SAAS,KAAK,YAAY;AAC1B,SAAS,eAAe;AA0BxB,MAAM,OACJ;AAEF,MAAM,UAAyC;AAAA,EAC7C,SAAS;AAAA,EACT,WAAW;AAAA,EACX,OAAO;AAAA;AAAA;AAAA,EAGP,QAAQ;AACV;AAmBA,MAAM,OAAmC;AAAA,EACvC,IAAI;AAAA,EACJ,IAAI;AAAA,EACJ,IAAI;AACN;AAGA,MAAM,YAAwC;AAAA,EAC5C,IAAI;AAAA,EACJ,IAAI;AAAA,EACJ,IAAI;AACN;AAEA,MAAM,eAAgD,EAAE,IAAI,MAAM,IAAI,MAAM,IAAI,KAAK;AAiDrF,SAAS,OAAO,EAAE,MAAM,GAAsB;AAC5C,SACE,oBAAC,UAAK,WAAU,4FACb,iBACH;AAEJ;AAmBO,SAAS,OAAO,OAAoB;AACzC,QAAM;AAAA,IACJ;AAAA,IACA,UAAU;AAAA,IACV,OAAO;AAAA,IACP;AAAA,IACA,UAAU;AAAA,IACV,WAAW;AAAA,IACX,UAAU;AAAA,IACV;AAAA,EACF,IAAI;AAEJ,QAAM,MAAM,GAAG,MAAM,QAAQ,OAAO,GAAG,WAAW,UAAU,IAAI,IAAI,KAAK,IAAI,GAAG,SAAS;AAEzF,MAAI,OAAO,UAAU;AAInB,UAAM,QACJ,OAAO,MAAM,YAAY,MAAM,YAAY,MAAM,YAAY,EAAE,KAAK,MAAM;AAC5E,UAAM,YAAY,OAAO,MAAM,iBAAiB,MAAM;AACtD,QAAI,CAAC,SAAS,CAAC,WAAW;AACxB,WAAK;AAAA,QACH,MAAM;AAAA,QACN,SACE;AAAA,QACF,OAAO;AAAA,QACP,KAAK;AAAA,QACL,WAAW;AAAA,MACb,CAAC;AAAA,IACH;AAAA,EACF;AAIA,QAAM,cAAc,YAAY,aAAa,YAAY,WAAW,YAAY;AAChF,QAAM,aACJ,iCACG;AAAA,eAAW,oBAAC,WAAQ,MAAM,aAAa,IAAI,GAAG,MAAM,aAAa,OAAO,MAAM;AAAA,IAC9E;AAAA,IACA,UAAU,oBAAC,UAAO,OAAO,QAAQ;AAAA,KACpC;AAGF,MAAI,SAAS;AACX,UAAM,EAAE,UAAUA,KAAI,SAASC,KAAI,MAAMC,KAAI,QAAQC,KAAI,SAASC,KAAI,UAAUC,KAAI,SAASC,KAAI,WAAWC,MAAK,GAAGC,MAAK,IAAI;AAC7H,WACE,oBAAC,QAAK,WAAW,KAAM,GAAGA,OACvB,UACH;AAAA,EAEJ;AAEA,MAAI,MAAM,SAAS,QAAW;AAC5B,UAAM,EAAE,UAAUR,KAAI,SAASC,KAAI,MAAMC,KAAI,QAAQC,KAAI,SAASC,KAAI,UAAUC,KAAI,SAASC,KAAI,WAAWC,MAAK,MAAM,GAAGC,MAAK,IAAI;AACnI,WACE;AAAA,MAAC;AAAA;AAAA,QACC;AAAA,QACA,WAAW;AAAA,QAGX,iBAAe,WAAW;AAAA,QACzB,GAAGA;AAAA,QAEH;AAAA;AAAA,IACH;AAAA,EAEJ;AAEA,QAAM,EAAE,UAAU,IAAI,SAAS,IAAI,MAAM,IAAI,QAAQ,IAAI,SAAS,IAAI,UAAU,IAAI,SAAS,IAAI,WAAW,KAAK,GAAG,KAAK,IAAI;AAC7H,SACE;AAAA,IAAC;AAAA;AAAA,MACC,MAAM,KAAK,QAAQ;AAAA,MACnB,aAAW,WAAW;AAAA,MACtB,UAAU,KAAK,YAAY;AAAA,MAC3B,WAAW;AAAA,MACV,GAAG;AAAA,MAEH;AAAA;AAAA,EACH;AAEJ;AAEA,IAAO,iBAAQ;","names":["_c","_v","_s","_k","_l","_i","_a","_cn","rest"]}
|
|
1
|
+
{"version":3,"sources":["../../../src/components/Button/Button.tsx"],"sourcesContent":["import { Slot } from '@radix-ui/react-slot'\nimport type { AnchorHTMLAttributes, ButtonHTMLAttributes, ReactNode } from 'react'\nimport { cn } from '../../lib/cn'\nimport { DEV, warn } from '../../lib/warn'\nimport { Spinner } from '../Spinner/Spinner'\n\nexport type ButtonVariant = 'primary' | 'secondary' | 'ghost' | 'danger'\nexport type ButtonSize = 'sm' | 'md' | 'lg'\n\n/**\n * The base every variant shares.\n *\n * It reads `--radius-control`, which defaults to `--radius`, the same corner an\n * `Input`, a `Select` trigger and a `Textarea` draw. It used to be a hard-coded\n * pill, and a pill beside an 8px field that nobody chose is two different ideas\n * of what a control is. The shape is now a theme decision: the `data-controls`\n * axis sets it for every button at once (the Workbench preset makes them\n * capsules), so a host never re-rounds a single button by hand.\n *\n * It does not move on hover. An earlier base lifted a pixel and asked for a\n * shadow the White Reset does not have — `--shadow` resolves to `none`, so that\n * hover state was invisible on every button in the system while still costing a\n * transition. Opacity carries the filled hover; the border carries the outlined\n * one.\n *\n * The transition names its properties rather than using `all`, so a layout\n * change (a width that grows when the label becomes \"Saving…\") is instant\n * instead of sliding.\n */\nconst BASE =\n 'inline-flex items-center justify-center gap-(--control-gap) rounded-(--radius-control) font-sans transition-[opacity,color,border-color,background-color] duration-(--duration-fast) ease-(--ease-out-expo) disabled:opacity-(--disabled-opacity) disabled:pointer-events-none aria-disabled:opacity-(--disabled-opacity) aria-disabled:pointer-events-none'\n\nconst VARIANT: Record<ButtonVariant, string> = {\n primary: 'bg-(--action) text-(--action-foreground) border border-(--action) hover:opacity-85',\n secondary: 'border border-(--rule-2) text-(--ink) bg-transparent hover:border-(--ink)',\n ghost: 'border border-transparent text-(--ink-2) hover:text-(--ink) hover:bg-(--stone)',\n /* The one place chroma is allowed on a control, and only because the action\n is destructive — that is a state, not a brand colour. */\n danger: 'bg-(--danger) text-(--paper) border border-(--danger) hover:opacity-85',\n}\n\n/**\n * `min-h` rather than `h`, so a button that wraps to two lines grows instead of\n * clipping.\n *\n * The heights come from the density tokens rather than from a literal, so a\n * subtree marked `data-density=\"compact\"` shrinks its controls without a single\n * call site being told. At the default density `md` is 44px — the pointer\n * target WCAG 2.5.5 asks for.\n *\n * `--control-lh` is what makes those numbers true rather than aspirational. A\n * floor only binds while the box is under it, and the box is the line plus the\n * padding plus the border — so a label inheriting the body's 1.6 leading put\n * `sm` at 39px against its own 36px token, `md` at 46 against 44 and `lg` at 50\n * against 48. Every size was two to three pixels taller than the number\n * documenting it, which is also how a masthead sized from `--control-h-sm`\n * ended up with a search field standing proud of every icon beside it.\n */\nconst SIZE: Record<ButtonSize, string> = {\n sm: 'min-h-(--control-h-sm) px-(--control-px-sm) py-(--control-py-sm) text-[13px] leading-(--control-lh)',\n md: 'min-h-(--control-h-md) px-(--control-px-md) py-(--control-py-md) text-sm leading-(--control-lh)',\n lg: 'min-h-(--control-h-lg) px-(--control-px-lg) py-(--control-py-lg) text-[15px] leading-(--control-lh)',\n}\n\n/** Square, because an icon has no label to give the box its width. */\nconst ICON_SIZE: Record<ButtonSize, string> = {\n sm: 'size-(--control-h-sm) p-0',\n md: 'size-(--control-h-md) p-0',\n lg: 'size-(--control-h-lg) p-0',\n}\n\nconst SPINNER_SIZE: Record<ButtonSize, 'sm' | 'md'> = { sm: 'sm', md: 'sm', lg: 'md' }\n\ninterface CommonProps {\n children?: ReactNode\n /**\n * Which action this is. `primary` is the one thing the screen wants you to\n * do, so there is at most one per view; `danger` is reserved for destructive\n * actions and is the only place chroma is allowed on a control.\n */\n variant?: ButtonVariant\n /** 36 / 44 / 48px tall. `md` meets the pointer-target floor on its own. */\n size?: ButtonSize\n /** Optional mono keycap glyph rendered after the label (e.g. \"P\"). */\n keycap?: string\n /**\n * Swaps the leading content for a spinner and blocks interaction. The label\n * stays put — a button that empties out while it works loses its width, and\n * the page reflows under the pointer that just clicked it.\n */\n loading?: boolean\n /**\n * Square control with no label. REQUIRES `aria-label`: an icon-only button\n * with no accessible name is invisible to a screen reader, and this is the\n * single most common way a design system ships an unusable control.\n */\n iconOnly?: boolean\n /**\n * Render the child element instead of a `<button>`, keeping these styles.\n * Use it to hand the styling to a router's `Link` — `asChild` is what keeps\n * this package free of any one router.\n *\n * The decoration slots (`keycap`, `loading`) are not injected into a slotted\n * child; compose them inside it yourself.\n *\n * @example\n * <Button asChild><Link href=\"/work\">Work</Link></Button>\n */\n asChild?: boolean\n className?: string\n}\n\ntype ButtonAsLink = CommonProps &\n Omit<AnchorHTMLAttributes<HTMLAnchorElement>, 'className' | 'children'> & { href: string }\n\ntype ButtonAsButton = CommonProps &\n Omit<ButtonHTMLAttributes<HTMLButtonElement>, 'className' | 'children'> & { href?: undefined }\n\nexport type ButtonProps = ButtonAsLink | ButtonAsButton\n\nfunction Keycap({ glyph }: { glyph: string }) {\n return (\n <span className=\"rounded-(--radius-sm) border border-current px-2 py-0.5 font-mono text-[11px] opacity-55\">\n {glyph}\n </span>\n )\n}\n\n/**\n * The system's action.\n *\n * Renders a `<button>`, or an `<a>` when given `href`, or whatever you hand it\n * via `asChild`. No router is imported, so the package stays framework-agnostic\n * and a Next or React Router app wires its own `Link` at the call site.\n *\n * Server-component friendly: there is no client boundary here, so it renders in\n * a static page as well as an interactive one.\n *\n * @example\n * <Button variant=\"secondary\" keycap=\"P\">View projects</Button>\n * @example\n * <Button loading disabled>Saving…</Button>\n * @example\n * <Button iconOnly aria-label=\"Close\"><X size={16} /></Button>\n */\nexport function Button(props: ButtonProps) {\n const {\n children,\n variant = 'primary',\n size = 'md',\n keycap,\n loading = false,\n iconOnly = false,\n asChild = false,\n className,\n } = props\n\n const cls = cn(BASE, VARIANT[variant], iconOnly ? ICON_SIZE[size] : SIZE[size], className)\n\n if (DEV && iconOnly) {\n // The control renders correctly and is announced as \"button\" and nothing\n // else. Nothing about the rendered page says so, which is why this is the\n // single most common way a design system ships an unusable control.\n const named =\n typeof props['aria-label'] === 'string' && props['aria-label'].trim() !== ''\n const described = typeof props['aria-labelledby'] === 'string'\n if (!named && !described) {\n warn({\n code: 'BUTTON_ICON_ONLY_UNNAMED',\n problem:\n 'An iconOnly Button has no text, so without an accessible name a screen reader announces it as \"button\" and nothing else.',\n field: 'aria-label',\n fix: 'Add aria-label with the action the button performs, e.g. aria-label=\"Delete invoice\".',\n component: 'Button',\n })\n }\n }\n\n // A filled ground needs a spinner in the inherited colour; an outlined one\n // reads better against the page's own rule scale.\n const spinnerTone = variant === 'primary' || variant === 'danger' ? 'current' : 'default'\n const decoration = (\n <>\n {loading && <Spinner size={SPINNER_SIZE[size]} tone={spinnerTone} label={null} />}\n {children}\n {keycap && <Keycap glyph={keycap} />}\n </>\n )\n\n if (asChild) {\n const { children: _c, variant: _v, size: _s, keycap: _k, loading: _l, iconOnly: _i, asChild: _a, className: _cn, ...rest } = props\n return (\n <Slot className={cls} {...rest}>\n {children}\n </Slot>\n )\n }\n\n if (props.href !== undefined) {\n const { children: _c, variant: _v, size: _s, keycap: _k, loading: _l, iconOnly: _i, asChild: _a, className: _cn, href, ...rest } = props\n return (\n <a\n href={href}\n className={cls}\n // A link cannot be `disabled`; `aria-disabled` plus the pointer-events\n // rule in BASE is the accessible equivalent.\n aria-disabled={loading || undefined}\n {...rest}\n >\n {decoration}\n </a>\n )\n }\n\n const { children: _c, variant: _v, size: _s, keycap: _k, loading: _l, iconOnly: _i, asChild: _a, className: _cn, ...rest } = props\n return (\n <button\n type={rest.type ?? 'button'}\n aria-busy={loading || undefined}\n disabled={rest.disabled || loading}\n className={cls}\n {...rest}\n >\n {decoration}\n </button>\n )\n}\n\nexport default Button\n"],"mappings":"AA0HI,SA4DA,UA5DA,KA4DA,YA5DA;AA1HJ,SAAS,YAAY;AAErB,SAAS,UAAU;AACnB,SAAS,KAAK,YAAY;AAC1B,SAAS,eAAe;AAyBxB,MAAM,OACJ;AAEF,MAAM,UAAyC;AAAA,EAC7C,SAAS;AAAA,EACT,WAAW;AAAA,EACX,OAAO;AAAA;AAAA;AAAA,EAGP,QAAQ;AACV;AAmBA,MAAM,OAAmC;AAAA,EACvC,IAAI;AAAA,EACJ,IAAI;AAAA,EACJ,IAAI;AACN;AAGA,MAAM,YAAwC;AAAA,EAC5C,IAAI;AAAA,EACJ,IAAI;AAAA,EACJ,IAAI;AACN;AAEA,MAAM,eAAgD,EAAE,IAAI,MAAM,IAAI,MAAM,IAAI,KAAK;AAiDrF,SAAS,OAAO,EAAE,MAAM,GAAsB;AAC5C,SACE,oBAAC,UAAK,WAAU,4FACb,iBACH;AAEJ;AAmBO,SAAS,OAAO,OAAoB;AACzC,QAAM;AAAA,IACJ;AAAA,IACA,UAAU;AAAA,IACV,OAAO;AAAA,IACP;AAAA,IACA,UAAU;AAAA,IACV,WAAW;AAAA,IACX,UAAU;AAAA,IACV;AAAA,EACF,IAAI;AAEJ,QAAM,MAAM,GAAG,MAAM,QAAQ,OAAO,GAAG,WAAW,UAAU,IAAI,IAAI,KAAK,IAAI,GAAG,SAAS;AAEzF,MAAI,OAAO,UAAU;AAInB,UAAM,QACJ,OAAO,MAAM,YAAY,MAAM,YAAY,MAAM,YAAY,EAAE,KAAK,MAAM;AAC5E,UAAM,YAAY,OAAO,MAAM,iBAAiB,MAAM;AACtD,QAAI,CAAC,SAAS,CAAC,WAAW;AACxB,WAAK;AAAA,QACH,MAAM;AAAA,QACN,SACE;AAAA,QACF,OAAO;AAAA,QACP,KAAK;AAAA,QACL,WAAW;AAAA,MACb,CAAC;AAAA,IACH;AAAA,EACF;AAIA,QAAM,cAAc,YAAY,aAAa,YAAY,WAAW,YAAY;AAChF,QAAM,aACJ,iCACG;AAAA,eAAW,oBAAC,WAAQ,MAAM,aAAa,IAAI,GAAG,MAAM,aAAa,OAAO,MAAM;AAAA,IAC9E;AAAA,IACA,UAAU,oBAAC,UAAO,OAAO,QAAQ;AAAA,KACpC;AAGF,MAAI,SAAS;AACX,UAAM,EAAE,UAAUA,KAAI,SAASC,KAAI,MAAMC,KAAI,QAAQC,KAAI,SAASC,KAAI,UAAUC,KAAI,SAASC,KAAI,WAAWC,MAAK,GAAGC,MAAK,IAAI;AAC7H,WACE,oBAAC,QAAK,WAAW,KAAM,GAAGA,OACvB,UACH;AAAA,EAEJ;AAEA,MAAI,MAAM,SAAS,QAAW;AAC5B,UAAM,EAAE,UAAUR,KAAI,SAASC,KAAI,MAAMC,KAAI,QAAQC,KAAI,SAASC,KAAI,UAAUC,KAAI,SAASC,KAAI,WAAWC,MAAK,MAAM,GAAGC,MAAK,IAAI;AACnI,WACE;AAAA,MAAC;AAAA;AAAA,QACC;AAAA,QACA,WAAW;AAAA,QAGX,iBAAe,WAAW;AAAA,QACzB,GAAGA;AAAA,QAEH;AAAA;AAAA,IACH;AAAA,EAEJ;AAEA,QAAM,EAAE,UAAU,IAAI,SAAS,IAAI,MAAM,IAAI,QAAQ,IAAI,SAAS,IAAI,UAAU,IAAI,SAAS,IAAI,WAAW,KAAK,GAAG,KAAK,IAAI;AAC7H,SACE;AAAA,IAAC;AAAA;AAAA,MACC,MAAM,KAAK,QAAQ;AAAA,MACnB,aAAW,WAAW;AAAA,MACtB,UAAU,KAAK,YAAY;AAAA,MAC3B,WAAW;AAAA,MACV,GAAG;AAAA,MAEH;AAAA;AAAA,EACH;AAEJ;AAEA,IAAO,iBAAQ;","names":["_c","_v","_s","_k","_l","_i","_a","_cn","rest"]}
|
|
@@ -113,6 +113,8 @@ interface CommandDialogProps {
|
|
|
113
113
|
onCloseAutoFocus?: DialogContentProps['onCloseAutoFocus'];
|
|
114
114
|
/** Runs before Escape closes the dialog. Prevent the default to keep it open, as a nested view stepping back does. */
|
|
115
115
|
onEscapeKeyDown?: DialogContentProps['onEscapeKeyDown'];
|
|
116
|
+
/** Merged onto the panel after its defaults, so a composition can place and animate it. */
|
|
117
|
+
className?: string;
|
|
116
118
|
}
|
|
117
119
|
/**
|
|
118
120
|
* The palette in a modal, which is how it is nearly always used.
|
|
@@ -120,6 +122,6 @@ interface CommandDialogProps {
|
|
|
120
122
|
* The dialog's own padding is removed: a palette is edge-to-edge, and its input
|
|
121
123
|
* is the first thing focus lands on.
|
|
122
124
|
*/
|
|
123
|
-
declare function CommandDialog({ open, onOpenChange, label, inputLabel, children, shouldFilter, onOpenAutoFocus, onCloseAutoFocus, onEscapeKeyDown, }: CommandDialogProps): react.JSX.Element;
|
|
125
|
+
declare function CommandDialog({ open, onOpenChange, label, inputLabel, children, shouldFilter, onOpenAutoFocus, onCloseAutoFocus, onEscapeKeyDown, className, }: CommandDialogProps): react.JSX.Element;
|
|
124
126
|
|
|
125
127
|
export { Command, CommandDialog, type CommandDialogProps, CommandEmpty, CommandFooter, CommandGroup, CommandHint, type CommandHintProps, CommandInput, CommandItem, type CommandItemProps, CommandList, CommandSeparator, Command as default };
|
|
@@ -163,7 +163,8 @@ function CommandDialog({
|
|
|
163
163
|
shouldFilter,
|
|
164
164
|
onOpenAutoFocus,
|
|
165
165
|
onCloseAutoFocus,
|
|
166
|
-
onEscapeKeyDown
|
|
166
|
+
onEscapeKeyDown,
|
|
167
|
+
className
|
|
167
168
|
}) {
|
|
168
169
|
return /* @__PURE__ */ jsx(Dialog, { open, onOpenChange, children: /* @__PURE__ */ jsx(
|
|
169
170
|
DialogContent,
|
|
@@ -174,7 +175,7 @@ function CommandDialog({
|
|
|
174
175
|
onOpenAutoFocus,
|
|
175
176
|
onCloseAutoFocus,
|
|
176
177
|
onEscapeKeyDown,
|
|
177
|
-
className: "top-[10vh] w-[min(94vw,44rem)] translate-y-0 overflow-hidden p-0 [scrollbar-gutter:auto]",
|
|
178
|
+
className: cn("top-[10vh] w-[min(94vw,44rem)] translate-y-0 overflow-hidden p-0 [scrollbar-gutter:auto]", className),
|
|
178
179
|
children: /* @__PURE__ */ jsx(
|
|
179
180
|
Command,
|
|
180
181
|
{
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../src/components/Command/Command.tsx"],"sourcesContent":["'use client'\n\nimport { Command as CommandPrimitive } from 'cmdk'\nimport { RiSearchLine, type RemixiconComponentType } from '@remixicon/react'\nimport { isValidElement, type ComponentProps, type ReactNode } from 'react'\nimport { cn } from '../../lib/cn'\n\n/**\n * True for a component type — `icon={Settings}` — rather than a rendered element.\n *\n * Everything a `ReactNode` can be is an element, a primitive, an array, another\n * iterable or a promise; a Remix Icon glyph is none of those, it is a plain\n * function component. So both spellings are tellable apart at runtime, which is\n * what lets one prop take either — and it has to, because this prop meant the\n * opposite thing one import away and the wrong spelling failed at render, not\n * at the type.\n */\nfunction isIconComponent(icon: RemixiconComponentType | ReactNode): icon is RemixiconComponentType {\n if (isValidElement(icon)) return false\n if (typeof icon === 'function') return true\n if (typeof icon !== 'object' || icon === null) return false\n return !Array.isArray(icon) && !(Symbol.iterator in icon) && !('then' in icon)\n}\n\n/** The leading glyph, sized by this component when it was handed a component. */\nfunction iconNode(icon: RemixiconComponentType | ReactNode): ReactNode {\n if (!isIconComponent(icon)) return icon\n const Icon = icon\n return <Icon size={16} aria-hidden />\n}\nimport { Dialog, DialogContent, type DialogContentProps } from '../Dialog/Dialog'\nimport { Kbd } from '../Kbd/Kbd'\n\n/**\n * A filterable list of actions — the ⌘K surface.\n *\n * Built on cmdk rather than on a `Select` or a menu, because the interaction is\n * neither: the list is filtered as you type, the highlighted row moves with the\n * arrow keys while focus STAYS in the input, and Enter runs the highlighted\n * row. That is the ARIA combobox pattern, and it is the part nobody should\n * hand-roll — `aria-activedescendant` moving without focus moving is precisely\n * where a home-made palette stops working with a screen reader.\n *\n * @example\n * <Command label=\"Command palette\">\n * <CommandInput placeholder=\"Type a command…\" />\n * <CommandList>\n * <CommandEmpty>Nothing matches.</CommandEmpty>\n * <CommandGroup heading=\"Navigate\">\n * <CommandItem onSelect={go}>Components</CommandItem>\n * </CommandGroup>\n * </CommandList>\n * </Command>\n */\nexport function Command({\n className,\n ...props\n}: ComponentProps<typeof CommandPrimitive>) {\n return (\n <CommandPrimitive\n className={cn(\n 'flex w-full flex-col overflow-hidden rounded-(--radius-lg) border border-(--panel-border) bg-(--panel-bg) shadow-(--panel-lift) panel-blur',\n className,\n )}\n {...props}\n />\n )\n}\n\n/** The filter field. Carries the search icon and the combobox semantics. */\nexport function CommandInput({\n className,\n ...props\n}: ComponentProps<typeof CommandPrimitive.Input>) {\n return (\n <div className=\"flex items-center gap-3 border-b border-(--rule) px-4\">\n <RiSearchLine size={18} aria-hidden className=\"shrink-0 text-(--ink-3-aa)\" />\n <CommandPrimitive.Input\n className={cn(\n 'h-13 w-full bg-transparent text-base md:text-[15px] text-(--ink) outline-none placeholder:text-(--ink-3-aa)',\n className,\n )}\n {...props}\n />\n </div>\n )\n}\n\nexport function CommandList({\n className,\n ...props\n}: ComponentProps<typeof CommandPrimitive.List>) {\n return (\n <CommandPrimitive.List\n className={cn('max-h-72 overflow-y-auto overflow-x-hidden p-2 scroll-slim', className)}\n {...props}\n />\n )\n}\n\n/** Shown when the filter matches nothing. Say what would match, not \"no results\". */\nexport function CommandEmpty(props: ComponentProps<typeof CommandPrimitive.Empty>) {\n return (\n <CommandPrimitive.Empty\n className=\"px-3 py-10 text-center text-sm text-(--ink-3-aa)\"\n {...props}\n />\n )\n}\n\n/**\n * The key-hint strip along the bottom.\n *\n * A palette is a keyboard surface whose keys are invisible: nothing on screen\n * says the arrows move the row or that Enter runs it, and a reader who reaches\n * for the mouse has been failed by the design rather than by themselves.\n *\n * @example\n * <CommandFooter>\n * <CommandHint keys={['↑', '↓']}>navigate</CommandHint>\n * <CommandHint keys={['↵']}>open</CommandHint>\n * </CommandFooter>\n */\nexport function CommandFooter({ className, ...props }: ComponentProps<'div'>) {\n return (\n <div\n className={cn(\n 'flex items-center gap-4 border-t border-(--rule) bg-(--paper-2) px-3.5 py-2',\n className,\n )}\n {...props}\n />\n )\n}\n\nexport interface CommandHintProps extends Omit<ComponentProps<'span'>, 'children'> {\n /** The keys this hint describes, printed as `Kbd` chips. */\n keys: string[]\n /** What they do — a verb, lowercase, no sentence. */\n children: ReactNode\n}\n\n/** One key-and-verb pair inside a `CommandFooter`. */\nexport function CommandHint({ keys, children, className, ...props }: CommandHintProps) {\n return (\n <span className={cn('flex items-center gap-1.5 mono-meta text-(--ink-3-aa)', className)} {...props}>\n {keys.map((key) => (\n <Kbd key={key}>{key}</Kbd>\n ))}\n {children}\n </span>\n )\n}\n\nexport function CommandGroup({\n className,\n ...props\n}: ComponentProps<typeof CommandPrimitive.Group>) {\n return (\n <CommandPrimitive.Group\n className={cn(\n 'overflow-hidden [&_[cmdk-group-heading]]:px-2.5 [&_[cmdk-group-heading]]:py-1.5 [&_[cmdk-group-heading]]:eyebrow [&_[cmdk-group-heading]]:text-(--ink-3-aa)',\n className,\n )}\n {...props}\n />\n )\n}\n\n/**\n * A divider between groups.\n *\n * Marked presentational, because ARIA permits a `listbox` to contain only\n * `option` and `group` — and the library renders this as `role=\"separator\"`,\n * which puts a critical `aria-required-children` violation inside every palette\n * that uses one. The grouping is already announced by the groups themselves, so\n * removing the divider from the accessibility tree loses nothing.\n */\nexport function CommandSeparator({\n className,\n ...props\n}: ComponentProps<typeof CommandPrimitive.Separator>) {\n return (\n <CommandPrimitive.Separator\n role=\"presentation\"\n aria-hidden=\"true\"\n className={cn('my-1 h-px bg-(--rule)', className)}\n {...props}\n />\n )\n}\n\nexport interface CommandItemProps extends ComponentProps<typeof CommandPrimitive.Item> {\n /** A shortcut printed at the end of the row. */\n shortcut?: string\n /**\n * A leading glyph. Either spelling — `icon={<Settings size={16} />}` passes\n * the element, `icon={Settings}` passes the component and this sizes it.\n *\n * It is what makes a long list scannable — the eye sorts by shape before it\n * reads, and forty identical rows of text defeat that.\n */\n icon?: RemixiconComponentType | ReactNode\n /**\n * A quiet note at the end of the row — what kind of thing this is, or its\n * current state. Not a description: a palette that prints a sentence per row\n * stops being scannable at about six of them.\n */\n meta?: ReactNode\n}\n\nexport function CommandItem({ shortcut, icon, meta, className, children, ...props }: CommandItemProps) {\n return (\n <CommandPrimitive.Item\n className={cn(\n 'flex cursor-pointer items-center gap-3 overflow-hidden rounded-(--radius-row) px-3 py-2.5 text-[15px] text-(--ink-2) outline-none transition-colors duration-(--duration-fast)',\n // The highlighted row is a chosen state, and law 7 says a chosen state\n // reads --accent. The leading rule gives it an edge the eye catches\n // while scrolling, which a fill alone does not.\n //\n // `overflow-hidden` above clips the bar below to the row's own\n // `--radius-row` corner. Without it the bar is a straight-edged\n // absolutely-positioned box that ignores the rounded highlight behind\n // it — invisible at `sharp` (0px radius) and barely off at the\n // default, but at `round` the row's radius outgrows the bar's own\n // inset and the bar pokes past the curve by several pixels. The row\n // is never a clip boundary for anything but itself: padding keeps\n // every child (icon, label, meta, shortcut) inside it already, so\n // clipping to the row's shape costs nothing else. The focus ring\n // is unaffected too — `outline` paints outside the border box, which\n // an element's own `overflow` never clips.\n 'relative data-[selected=true]:bg-(--accent-muted) data-[selected=true]:text-(--ink)',\n 'before:absolute before:inset-y-1 before:start-0 before:w-0.5 before:rounded-(--radius-pill) before:bg-transparent data-[selected=true]:before:bg-(--accent)',\n 'data-[disabled=true]:pointer-events-none data-[disabled=true]:opacity-(--disabled-opacity)',\n className,\n )}\n {...props}\n >\n {icon && (\n <span className=\"grid size-4 shrink-0 place-items-center text-(--ink-3-aa) [&_svg]:size-4\">\n {iconNode(icon)}\n </span>\n )}\n {children}\n {meta && <span className=\"ms-auto ps-3 mono-meta text-(--ink-3-aa)\">{meta}</span>}\n {shortcut && <Kbd className={cn(meta ? '' : 'ms-auto')}>{shortcut}</Kbd>}\n </CommandPrimitive.Item>\n )\n}\n\nexport interface CommandDialogProps {\n open: boolean\n onOpenChange: (open: boolean) => void\n /** Names the palette for assistive tech. */\n label: string\n /**\n * Names the search field when it should read differently from the dialog —\n * a \"Search records\" field inside a \"Library search\" palette. Defaults to\n * `label`. An `aria-label` on `CommandInput` cannot do this: the field is\n * labelled by reference, and a reference outranks an `aria-label`.\n */\n inputLabel?: string\n children: ReactNode\n /**\n * Pass `false` when the host has already filtered the rows — a server search\n * or an index of its own. The palette would otherwise filter them a second\n * time against the input and hide results the host meant to show.\n */\n shouldFilter?: boolean\n /** Runs as the dialog moves focus in. Prevent the default to place focus yourself. */\n onOpenAutoFocus?: DialogContentProps['onOpenAutoFocus']\n /**\n * Runs as the dialog hands focus back on close. The default returns it to a\n * `DialogTrigger`, and a palette opened by a shortcut has none, so focus falls\n * to the page. Prevent the default and focus what opened it.\n */\n onCloseAutoFocus?: DialogContentProps['onCloseAutoFocus']\n /** Runs before Escape closes the dialog. Prevent the default to keep it open, as a nested view stepping back does. */\n onEscapeKeyDown?: DialogContentProps['onEscapeKeyDown']\n}\n\n/**\n * The palette in a modal, which is how it is nearly always used.\n *\n * The dialog's own padding is removed: a palette is edge-to-edge, and its input\n * is the first thing focus lands on.\n */\nexport function CommandDialog({\n open,\n onOpenChange,\n label,\n inputLabel,\n children,\n shouldFilter,\n onOpenAutoFocus,\n onCloseAutoFocus,\n onEscapeKeyDown,\n}: CommandDialogProps) {\n return (\n <Dialog open={open} onOpenChange={onOpenChange}>\n <DialogContent\n title={label}\n hideTitle\n showClose={false}\n onOpenAutoFocus={onOpenAutoFocus}\n onCloseAutoFocus={onCloseAutoFocus}\n onEscapeKeyDown={onEscapeKeyDown}\n // Above centre, not at it. A palette is read as a layer over the page\n // rather than as a message about it, and centring it puts the list\n // under the reader's own hands on a laptop.\n // `scrollbar-gutter: auto` undoes the `stable` that `Dialog`'s own\n // `scroll-slim` sets. The dialog never scrolls — the list inside it\n // does — but the reserved gutter was still there, so the list stopped\n // thirteen pixels short of the panel and drew its own hairline inside\n // an empty channel. Two bars, one of them permanently blank.\n className=\"top-[10vh] w-[min(94vw,44rem)] translate-y-0 overflow-hidden p-0 [scrollbar-gutter:auto]\"\n >\n {/* The modal has the whole screen, so its list may be taller than the\n default an inline menu should keep.\n\n `scroll-hairline` rather than `scroll-slim`: eleven pixels of grey\n down the side of a palette is the widest thing in it. */}\n <Command\n label={inputLabel ?? label}\n shouldFilter={shouldFilter}\n className=\"rounded-none border-0 [&_[cmdk-list]]:max-h-[26rem] [&_[cmdk-list]]:scroll-hairline\"\n >\n {children}\n </Command>\n </DialogContent>\n </Dialog>\n )\n}\n\nexport default Command\n"],"mappings":"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","names":[]}
|
|
1
|
+
{"version":3,"sources":["../../../src/components/Command/Command.tsx"],"sourcesContent":["'use client'\n\nimport { Command as CommandPrimitive } from 'cmdk'\nimport { RiSearchLine, type RemixiconComponentType } from '@remixicon/react'\nimport { isValidElement, type ComponentProps, type ReactNode } from 'react'\nimport { cn } from '../../lib/cn'\n\n/**\n * True for a component type — `icon={Settings}` — rather than a rendered element.\n *\n * Everything a `ReactNode` can be is an element, a primitive, an array, another\n * iterable or a promise; a Remix Icon glyph is none of those, it is a plain\n * function component. So both spellings are tellable apart at runtime, which is\n * what lets one prop take either — and it has to, because this prop meant the\n * opposite thing one import away and the wrong spelling failed at render, not\n * at the type.\n */\nfunction isIconComponent(icon: RemixiconComponentType | ReactNode): icon is RemixiconComponentType {\n if (isValidElement(icon)) return false\n if (typeof icon === 'function') return true\n if (typeof icon !== 'object' || icon === null) return false\n return !Array.isArray(icon) && !(Symbol.iterator in icon) && !('then' in icon)\n}\n\n/** The leading glyph, sized by this component when it was handed a component. */\nfunction iconNode(icon: RemixiconComponentType | ReactNode): ReactNode {\n if (!isIconComponent(icon)) return icon\n const Icon = icon\n return <Icon size={16} aria-hidden />\n}\nimport { Dialog, DialogContent, type DialogContentProps } from '../Dialog/Dialog'\nimport { Kbd } from '../Kbd/Kbd'\n\n/**\n * A filterable list of actions — the ⌘K surface.\n *\n * Built on cmdk rather than on a `Select` or a menu, because the interaction is\n * neither: the list is filtered as you type, the highlighted row moves with the\n * arrow keys while focus STAYS in the input, and Enter runs the highlighted\n * row. That is the ARIA combobox pattern, and it is the part nobody should\n * hand-roll — `aria-activedescendant` moving without focus moving is precisely\n * where a home-made palette stops working with a screen reader.\n *\n * @example\n * <Command label=\"Command palette\">\n * <CommandInput placeholder=\"Type a command…\" />\n * <CommandList>\n * <CommandEmpty>Nothing matches.</CommandEmpty>\n * <CommandGroup heading=\"Navigate\">\n * <CommandItem onSelect={go}>Components</CommandItem>\n * </CommandGroup>\n * </CommandList>\n * </Command>\n */\nexport function Command({\n className,\n ...props\n}: ComponentProps<typeof CommandPrimitive>) {\n return (\n <CommandPrimitive\n className={cn(\n 'flex w-full flex-col overflow-hidden rounded-(--radius-lg) border border-(--panel-border) bg-(--panel-bg) shadow-(--panel-lift) panel-blur',\n className,\n )}\n {...props}\n />\n )\n}\n\n/** The filter field. Carries the search icon and the combobox semantics. */\nexport function CommandInput({\n className,\n ...props\n}: ComponentProps<typeof CommandPrimitive.Input>) {\n return (\n <div className=\"flex items-center gap-3 border-b border-(--rule) px-4\">\n <RiSearchLine size={18} aria-hidden className=\"shrink-0 text-(--ink-3-aa)\" />\n <CommandPrimitive.Input\n className={cn(\n 'h-13 w-full bg-transparent text-base md:text-[15px] text-(--ink) outline-none placeholder:text-(--ink-3-aa)',\n className,\n )}\n {...props}\n />\n </div>\n )\n}\n\nexport function CommandList({\n className,\n ...props\n}: ComponentProps<typeof CommandPrimitive.List>) {\n return (\n <CommandPrimitive.List\n className={cn('max-h-72 overflow-y-auto overflow-x-hidden p-2 scroll-slim', className)}\n {...props}\n />\n )\n}\n\n/** Shown when the filter matches nothing. Say what would match, not \"no results\". */\nexport function CommandEmpty(props: ComponentProps<typeof CommandPrimitive.Empty>) {\n return (\n <CommandPrimitive.Empty\n className=\"px-3 py-10 text-center text-sm text-(--ink-3-aa)\"\n {...props}\n />\n )\n}\n\n/**\n * The key-hint strip along the bottom.\n *\n * A palette is a keyboard surface whose keys are invisible: nothing on screen\n * says the arrows move the row or that Enter runs it, and a reader who reaches\n * for the mouse has been failed by the design rather than by themselves.\n *\n * @example\n * <CommandFooter>\n * <CommandHint keys={['↑', '↓']}>navigate</CommandHint>\n * <CommandHint keys={['↵']}>open</CommandHint>\n * </CommandFooter>\n */\nexport function CommandFooter({ className, ...props }: ComponentProps<'div'>) {\n return (\n <div\n className={cn(\n 'flex items-center gap-4 border-t border-(--rule) bg-(--paper-2) px-3.5 py-2',\n className,\n )}\n {...props}\n />\n )\n}\n\nexport interface CommandHintProps extends Omit<ComponentProps<'span'>, 'children'> {\n /** The keys this hint describes, printed as `Kbd` chips. */\n keys: string[]\n /** What they do — a verb, lowercase, no sentence. */\n children: ReactNode\n}\n\n/** One key-and-verb pair inside a `CommandFooter`. */\nexport function CommandHint({ keys, children, className, ...props }: CommandHintProps) {\n return (\n <span className={cn('flex items-center gap-1.5 mono-meta text-(--ink-3-aa)', className)} {...props}>\n {keys.map((key) => (\n <Kbd key={key}>{key}</Kbd>\n ))}\n {children}\n </span>\n )\n}\n\nexport function CommandGroup({\n className,\n ...props\n}: ComponentProps<typeof CommandPrimitive.Group>) {\n return (\n <CommandPrimitive.Group\n className={cn(\n 'overflow-hidden [&_[cmdk-group-heading]]:px-2.5 [&_[cmdk-group-heading]]:py-1.5 [&_[cmdk-group-heading]]:eyebrow [&_[cmdk-group-heading]]:text-(--ink-3-aa)',\n className,\n )}\n {...props}\n />\n )\n}\n\n/**\n * A divider between groups.\n *\n * Marked presentational, because ARIA permits a `listbox` to contain only\n * `option` and `group` — and the library renders this as `role=\"separator\"`,\n * which puts a critical `aria-required-children` violation inside every palette\n * that uses one. The grouping is already announced by the groups themselves, so\n * removing the divider from the accessibility tree loses nothing.\n */\nexport function CommandSeparator({\n className,\n ...props\n}: ComponentProps<typeof CommandPrimitive.Separator>) {\n return (\n <CommandPrimitive.Separator\n role=\"presentation\"\n aria-hidden=\"true\"\n className={cn('my-1 h-px bg-(--rule)', className)}\n {...props}\n />\n )\n}\n\nexport interface CommandItemProps extends ComponentProps<typeof CommandPrimitive.Item> {\n /** A shortcut printed at the end of the row. */\n shortcut?: string\n /**\n * A leading glyph. Either spelling — `icon={<Settings size={16} />}` passes\n * the element, `icon={Settings}` passes the component and this sizes it.\n *\n * It is what makes a long list scannable — the eye sorts by shape before it\n * reads, and forty identical rows of text defeat that.\n */\n icon?: RemixiconComponentType | ReactNode\n /**\n * A quiet note at the end of the row — what kind of thing this is, or its\n * current state. Not a description: a palette that prints a sentence per row\n * stops being scannable at about six of them.\n */\n meta?: ReactNode\n}\n\nexport function CommandItem({ shortcut, icon, meta, className, children, ...props }: CommandItemProps) {\n return (\n <CommandPrimitive.Item\n className={cn(\n 'flex cursor-pointer items-center gap-3 overflow-hidden rounded-(--radius-row) px-3 py-2.5 text-[15px] text-(--ink-2) outline-none transition-colors duration-(--duration-fast)',\n // The highlighted row is a chosen state, and law 7 says a chosen state\n // reads --accent. The leading rule gives it an edge the eye catches\n // while scrolling, which a fill alone does not.\n //\n // `overflow-hidden` above clips the bar below to the row's own\n // `--radius-row` corner. Without it the bar is a straight-edged\n // absolutely-positioned box that ignores the rounded highlight behind\n // it — invisible at `sharp` (0px radius) and barely off at the\n // default, but at `round` the row's radius outgrows the bar's own\n // inset and the bar pokes past the curve by several pixels. The row\n // is never a clip boundary for anything but itself: padding keeps\n // every child (icon, label, meta, shortcut) inside it already, so\n // clipping to the row's shape costs nothing else. The focus ring\n // is unaffected too — `outline` paints outside the border box, which\n // an element's own `overflow` never clips.\n 'relative data-[selected=true]:bg-(--accent-muted) data-[selected=true]:text-(--ink)',\n 'before:absolute before:inset-y-1 before:start-0 before:w-0.5 before:rounded-(--radius-pill) before:bg-transparent data-[selected=true]:before:bg-(--accent)',\n 'data-[disabled=true]:pointer-events-none data-[disabled=true]:opacity-(--disabled-opacity)',\n className,\n )}\n {...props}\n >\n {icon && (\n <span className=\"grid size-4 shrink-0 place-items-center text-(--ink-3-aa) [&_svg]:size-4\">\n {iconNode(icon)}\n </span>\n )}\n {children}\n {meta && <span className=\"ms-auto ps-3 mono-meta text-(--ink-3-aa)\">{meta}</span>}\n {shortcut && <Kbd className={cn(meta ? '' : 'ms-auto')}>{shortcut}</Kbd>}\n </CommandPrimitive.Item>\n )\n}\n\nexport interface CommandDialogProps {\n open: boolean\n onOpenChange: (open: boolean) => void\n /** Names the palette for assistive tech. */\n label: string\n /**\n * Names the search field when it should read differently from the dialog —\n * a \"Search records\" field inside a \"Library search\" palette. Defaults to\n * `label`. An `aria-label` on `CommandInput` cannot do this: the field is\n * labelled by reference, and a reference outranks an `aria-label`.\n */\n inputLabel?: string\n children: ReactNode\n /**\n * Pass `false` when the host has already filtered the rows — a server search\n * or an index of its own. The palette would otherwise filter them a second\n * time against the input and hide results the host meant to show.\n */\n shouldFilter?: boolean\n /** Runs as the dialog moves focus in. Prevent the default to place focus yourself. */\n onOpenAutoFocus?: DialogContentProps['onOpenAutoFocus']\n /**\n * Runs as the dialog hands focus back on close. The default returns it to a\n * `DialogTrigger`, and a palette opened by a shortcut has none, so focus falls\n * to the page. Prevent the default and focus what opened it.\n */\n onCloseAutoFocus?: DialogContentProps['onCloseAutoFocus']\n /** Runs before Escape closes the dialog. Prevent the default to keep it open, as a nested view stepping back does. */\n onEscapeKeyDown?: DialogContentProps['onEscapeKeyDown']\n /** Merged onto the panel after its defaults, so a composition can place and animate it. */\n className?: string\n}\n\n/**\n * The palette in a modal, which is how it is nearly always used.\n *\n * The dialog's own padding is removed: a palette is edge-to-edge, and its input\n * is the first thing focus lands on.\n */\nexport function CommandDialog({\n open,\n onOpenChange,\n label,\n inputLabel,\n children,\n shouldFilter,\n onOpenAutoFocus,\n onCloseAutoFocus,\n onEscapeKeyDown,\n className,\n}: CommandDialogProps) {\n return (\n <Dialog open={open} onOpenChange={onOpenChange}>\n <DialogContent\n title={label}\n hideTitle\n showClose={false}\n onOpenAutoFocus={onOpenAutoFocus}\n onCloseAutoFocus={onCloseAutoFocus}\n onEscapeKeyDown={onEscapeKeyDown}\n // Above centre, not at it. A palette is read as a layer over the page\n // rather than as a message about it, and centring it puts the list\n // under the reader's own hands on a laptop.\n // `scrollbar-gutter: auto` undoes the `stable` that `Dialog`'s own\n // `scroll-slim` sets. The dialog never scrolls — the list inside it\n // does — but the reserved gutter was still there, so the list stopped\n // thirteen pixels short of the panel and drew its own hairline inside\n // an empty channel. Two bars, one of them permanently blank.\n className={cn('top-[10vh] w-[min(94vw,44rem)] translate-y-0 overflow-hidden p-0 [scrollbar-gutter:auto]', className)}\n >\n {/* The modal has the whole screen, so its list may be taller than the\n default an inline menu should keep.\n\n `scroll-hairline` rather than `scroll-slim`: eleven pixels of grey\n down the side of a palette is the widest thing in it. */}\n <Command\n label={inputLabel ?? label}\n shouldFilter={shouldFilter}\n className=\"rounded-none border-0 [&_[cmdk-list]]:max-h-[26rem] [&_[cmdk-list]]:scroll-hairline\"\n >\n {children}\n </Command>\n </DialogContent>\n </Dialog>\n )\n}\n\nexport default Command\n"],"mappings":"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","names":[]}
|
package/dist/keyframes.css
CHANGED
|
@@ -298,3 +298,25 @@
|
|
|
298
298
|
animation: none !important;
|
|
299
299
|
}
|
|
300
300
|
}
|
|
301
|
+
|
|
302
|
+
/* The search palette's arrival and exit. Opacity carries most of it; the lift
|
|
303
|
+
and the scale are small enough to read as settling, not as travel. Written
|
|
304
|
+
on `transform` so it never fights the panel's centring, which Tailwind
|
|
305
|
+
writes on `translate`. */
|
|
306
|
+
@keyframes folio-palette-in {
|
|
307
|
+
from {
|
|
308
|
+
opacity: 0;
|
|
309
|
+
transform: translateY(-6px) scale(0.985);
|
|
310
|
+
}
|
|
311
|
+
to {
|
|
312
|
+
opacity: 1;
|
|
313
|
+
transform: none;
|
|
314
|
+
}
|
|
315
|
+
}
|
|
316
|
+
|
|
317
|
+
@keyframes folio-palette-out {
|
|
318
|
+
to {
|
|
319
|
+
opacity: 0;
|
|
320
|
+
transform: translateY(-4px) scale(0.985);
|
|
321
|
+
}
|
|
322
|
+
}
|