@dowel-ui/react 0.5.0 → 0.7.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/README.md +1 -1
- package/dist/blocks/admin-dashboard/meta.js +31 -0
- package/dist/blocks/admin-dashboard/meta.js.map +1 -0
- package/dist/blocks/agent-console/meta.js +27 -0
- package/dist/blocks/agent-console/meta.js.map +1 -0
- package/dist/blocks/ai-dashboard/meta.js +25 -0
- package/dist/blocks/ai-dashboard/meta.js.map +1 -0
- package/dist/blocks/ai-workspace/meta.js +33 -0
- package/dist/blocks/ai-workspace/meta.js.map +1 -0
- package/dist/blocks/analytics/meta.js +24 -0
- package/dist/blocks/analytics/meta.js.map +1 -0
- package/dist/blocks/billing/meta.js +25 -0
- package/dist/blocks/billing/meta.js.map +1 -0
- package/dist/blocks/command-center/meta.js +28 -0
- package/dist/blocks/command-center/meta.js.map +1 -0
- package/dist/blocks/crm/meta.js +32 -0
- package/dist/blocks/crm/meta.js.map +1 -0
- package/dist/blocks/onboarding/meta.js +23 -0
- package/dist/blocks/onboarding/meta.js.map +1 -0
- package/dist/components/accordion/accordion.js +1 -1
- package/dist/components/accordion/accordion.js.map +1 -1
- package/dist/components/activity-feed/activity-feed.js +1 -1
- package/dist/components/activity-feed/activity-feed.js.map +1 -1
- package/dist/components/ai-agent-plan/ai-agent-plan.js +1 -1
- package/dist/components/ai-agent-plan/ai-agent-plan.js.map +1 -1
- package/dist/components/ai-extraction-review/ai-extraction-review.js +1 -1
- package/dist/components/ai-extraction-review/ai-extraction-review.js.map +1 -1
- package/dist/components/ai-prompt-input/ai-prompt-input.js +1 -1
- package/dist/components/ai-prompt-input/ai-prompt-input.js.map +1 -1
- package/dist/components/ai-reasoning/ai-reasoning.js +1 -1
- package/dist/components/ai-reasoning/ai-reasoning.js.map +1 -1
- package/dist/components/ai-response/ai-response.js +2 -2
- package/dist/components/ai-response/ai-response.js.map +1 -1
- package/dist/components/ai-tool/ai-tool.js +2 -2
- package/dist/components/ai-tool/ai-tool.js.map +1 -1
- package/dist/components/alert/alert.d.ts +1 -1
- package/dist/components/avatar/avatar.d.ts +1 -1
- package/dist/components/badge/badge.d.ts +1 -1
- package/dist/components/breadcrumb/breadcrumb.d.ts +52 -0
- package/dist/components/breadcrumb/breadcrumb.d.ts.map +1 -0
- package/dist/components/breadcrumb/breadcrumb.js +141 -0
- package/dist/components/breadcrumb/breadcrumb.js.map +1 -0
- package/dist/components/breadcrumb/index.d.ts +2 -0
- package/dist/components/breadcrumb/index.js +2 -0
- package/dist/components/breadcrumb/meta.js +17 -0
- package/dist/components/breadcrumb/meta.js.map +1 -0
- package/dist/components/button/button.d.ts +1 -1
- package/dist/components/calendar/calendar.js +2 -2
- package/dist/components/calendar/calendar.js.map +1 -1
- package/dist/components/code-block/code-block.js +1 -1
- package/dist/components/code-block/code-block.js.map +1 -1
- package/dist/components/collapsible/collapsible.d.ts +30 -0
- package/dist/components/collapsible/collapsible.d.ts.map +1 -0
- package/dist/components/collapsible/collapsible.js +38 -0
- package/dist/components/collapsible/collapsible.js.map +1 -0
- package/dist/components/collapsible/index.d.ts +2 -0
- package/dist/components/collapsible/index.js +2 -0
- package/dist/components/collapsible/meta.js +17 -0
- package/dist/components/collapsible/meta.js.map +1 -0
- package/dist/components/combobox/combobox.js +2 -2
- package/dist/components/combobox/combobox.js.map +1 -1
- package/dist/components/command/command.js +1 -1
- package/dist/components/command/command.js.map +1 -1
- package/dist/components/data-table/data-table.d.ts.map +1 -1
- package/dist/components/data-table/data-table.js +4 -1
- package/dist/components/data-table/data-table.js.map +1 -1
- package/dist/components/dialog/dialog.js +2 -2
- package/dist/components/dialog/dialog.js.map +1 -1
- package/dist/components/diff-viewer/diff-viewer.js +4 -4
- package/dist/components/diff-viewer/diff-viewer.js.map +1 -1
- package/dist/components/direction/direction.d.ts +35 -0
- package/dist/components/direction/direction.d.ts.map +1 -0
- package/dist/components/direction/direction.js +14 -0
- package/dist/components/direction/direction.js.map +1 -0
- package/dist/components/direction/index.d.ts +2 -0
- package/dist/components/direction/index.js +2 -0
- package/dist/components/direction/meta.js +17 -0
- package/dist/components/direction/meta.js.map +1 -0
- package/dist/components/drawer/drawer.js +1 -1
- package/dist/components/drawer/drawer.js.map +1 -1
- package/dist/components/dropdown-menu/dropdown-menu.d.ts.map +1 -1
- package/dist/components/dropdown-menu/dropdown-menu.js +9 -8
- package/dist/components/dropdown-menu/dropdown-menu.js.map +1 -1
- package/dist/components/input/input.js +1 -1
- package/dist/components/input/input.js.map +1 -1
- package/dist/components/log-viewer/log-viewer.js +2 -2
- package/dist/components/log-viewer/log-viewer.js.map +1 -1
- package/dist/components/meter/meter.js +1 -1
- package/dist/components/meter/meter.js.map +1 -1
- package/dist/components/pagination/pagination.d.ts.map +1 -1
- package/dist/components/pagination/pagination.js +3 -2
- package/dist/components/pagination/pagination.js.map +1 -1
- package/dist/components/permission-matrix/permission-matrix.js +3 -3
- package/dist/components/permission-matrix/permission-matrix.js.map +1 -1
- package/dist/components/progress/progress.d.ts +1 -1
- package/dist/components/record-diff/record-diff.js +4 -4
- package/dist/components/record-diff/record-diff.js.map +1 -1
- package/dist/components/select/select.js +2 -2
- package/dist/components/select/select.js.map +1 -1
- package/dist/components/sheet/sheet.d.ts.map +1 -1
- package/dist/components/sheet/sheet.js +2 -2
- package/dist/components/sheet/sheet.js.map +1 -1
- package/dist/components/sidebar/index.d.ts +2 -0
- package/dist/components/sidebar/index.js +2 -0
- package/dist/components/sidebar/meta.js +17 -0
- package/dist/components/sidebar/meta.js.map +1 -0
- package/dist/components/sidebar/sidebar.d.ts +69 -0
- package/dist/components/sidebar/sidebar.d.ts.map +1 -0
- package/dist/components/sidebar/sidebar.js +256 -0
- package/dist/components/sidebar/sidebar.js.map +1 -0
- package/dist/components/spinner/spinner.d.ts +1 -1
- package/dist/components/table/table.js +2 -2
- package/dist/components/table/table.js.map +1 -1
- package/dist/components/tags-input/tags-input.js +1 -1
- package/dist/components/tags-input/tags-input.js.map +1 -1
- package/dist/components/textarea/index.d.ts +2 -0
- package/dist/components/textarea/index.js +2 -0
- package/dist/components/textarea/meta.js +17 -0
- package/dist/components/textarea/meta.js.map +1 -0
- package/dist/components/textarea/textarea.d.ts +43 -0
- package/dist/components/textarea/textarea.d.ts.map +1 -0
- package/dist/components/textarea/textarea.js +119 -0
- package/dist/components/textarea/textarea.js.map +1 -0
- package/dist/components/time-range-picker/time-range-picker.js +3 -3
- package/dist/components/time-range-picker/time-range-picker.js.map +1 -1
- package/dist/components/toast/toast.d.ts +1 -1
- package/dist/components/toast/toast.d.ts.map +1 -1
- package/dist/components/toast/toast.js +2 -2
- package/dist/components/toast/toast.js.map +1 -1
- package/dist/index.d.ts +12 -2
- package/dist/index.js +7 -2
- package/dist/lib/styles.d.ts +16 -1
- package/dist/lib/styles.d.ts.map +1 -1
- package/dist/lib/styles.js +16 -1
- package/dist/lib/styles.js.map +1 -1
- package/dist/registry/blocks.d.ts.map +1 -1
- package/dist/registry/blocks.js +27 -9
- package/dist/registry/blocks.js.map +1 -1
- package/dist/registry/components.d.ts.map +1 -1
- package/dist/registry/components.js +60 -50
- package/dist/registry/components.js.map +1 -1
- package/dist/registry/schema.d.ts +8 -0
- package/dist/registry/schema.d.ts.map +1 -1
- package/dist/registry/schema.js.map +1 -1
- package/package.json +5 -4
- package/src/components/accordion/accordion.tsx +1 -1
- package/src/components/activity-feed/activity-feed.tsx +1 -1
- package/src/components/ai-agent-plan/ai-agent-plan.tsx +0 -0
- package/src/components/ai-extraction-review/ai-extraction-review.tsx +1 -1
- package/src/components/ai-prompt-input/ai-prompt-input.tsx +1 -1
- package/src/components/ai-reasoning/ai-reasoning.tsx +1 -1
- package/src/components/ai-response/ai-response.tsx +2 -2
- package/src/components/ai-tool/ai-tool.tsx +2 -2
- package/src/components/breadcrumb/breadcrumb.tsx +157 -0
- package/src/components/breadcrumb/index.ts +10 -0
- package/src/components/breadcrumb/meta.ts +19 -0
- package/src/components/calendar/calendar.tsx +2 -2
- package/src/components/code-block/code-block.tsx +1 -1
- package/src/components/collapsible/collapsible.tsx +63 -0
- package/src/components/collapsible/index.ts +6 -0
- package/src/components/collapsible/meta.ts +16 -0
- package/src/components/combobox/combobox.tsx +2 -2
- package/src/components/command/command.tsx +1 -1
- package/src/components/data-table/data-table.tsx +14 -3
- package/src/components/dialog/dialog.tsx +2 -2
- package/src/components/diff-viewer/diff-viewer.tsx +4 -4
- package/src/components/direction/direction.tsx +38 -0
- package/src/components/direction/index.ts +1 -0
- package/src/components/direction/meta.ts +19 -0
- package/src/components/drawer/drawer.tsx +1 -1
- package/src/components/dropdown-menu/dropdown-menu.tsx +14 -8
- package/src/components/input/input.tsx +1 -1
- package/src/components/log-viewer/log-viewer.tsx +2 -2
- package/src/components/meter/meter.tsx +1 -1
- package/src/components/pagination/pagination.tsx +13 -2
- package/src/components/permission-matrix/permission-matrix.tsx +4 -4
- package/src/components/record-diff/record-diff.tsx +4 -4
- package/src/components/select/select.tsx +2 -2
- package/src/components/sheet/sheet.tsx +8 -4
- package/src/components/sidebar/index.ts +19 -0
- package/src/components/sidebar/meta.ts +25 -0
- package/src/components/sidebar/sidebar.tsx +374 -0
- package/src/components/table/table.tsx +3 -3
- package/src/components/tags-input/tags-input.tsx +1 -1
- package/src/components/textarea/index.ts +1 -0
- package/src/components/textarea/meta.ts +21 -0
- package/src/components/textarea/textarea.tsx +210 -0
- package/src/components/time-range-picker/time-range-picker.tsx +3 -3
- package/src/components/toast/toast.tsx +14 -6
- package/src/index.ts +5 -0
- package/src/lib/styles.ts +16 -0
- package/src/registry/blocks.ts +18 -0
- package/src/registry/components.ts +10 -0
- package/src/registry/schema.ts +8 -0
- package/src/blocks/admin-users/admin-users.tsx +0 -251
- package/src/blocks/admin-users/index.ts +0 -1
- package/src/blocks/admin-users/meta.ts +0 -27
- package/src/blocks/ai-chat/ai-chat.tsx +0 -280
- package/src/blocks/ai-chat/index.ts +0 -7
- package/src/blocks/ai-chat/meta.ts +0 -32
- package/src/blocks/dashboard/dashboard.tsx +0 -192
- package/src/blocks/dashboard/index.ts +0 -6
- package/src/blocks/dashboard/meta.ts +0 -18
- package/src/blocks/forgot-password/forgot-password.tsx +0 -158
- package/src/blocks/forgot-password/index.ts +0 -1
- package/src/blocks/forgot-password/meta.ts +0 -18
- package/src/blocks/login/index.ts +0 -1
- package/src/blocks/login/login.tsx +0 -178
- package/src/blocks/login/meta.ts +0 -18
- package/src/blocks/pricing/index.ts +0 -1
- package/src/blocks/pricing/meta.ts +0 -18
- package/src/blocks/pricing/pricing.tsx +0 -176
- package/src/blocks/settings/index.ts +0 -6
- package/src/blocks/settings/meta.ts +0 -29
- package/src/blocks/settings/settings.tsx +0 -317
- package/src/blocks/signup/index.ts +0 -1
- package/src/blocks/signup/meta.ts +0 -18
- package/src/blocks/signup/signup.tsx +0 -240
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { defineMeta } from "../../registry/schema.js";
|
|
2
|
+
//#region src/components/breadcrumb/meta.ts
|
|
3
|
+
const meta = defineMeta({
|
|
4
|
+
name: "breadcrumb",
|
|
5
|
+
title: "Breadcrumb",
|
|
6
|
+
description: "Where the current page sits in the hierarchy, and how to get back up it.",
|
|
7
|
+
category: "navigation",
|
|
8
|
+
status: "stable",
|
|
9
|
+
dependencies: ["radix-ui"],
|
|
10
|
+
registryDependencies: [],
|
|
11
|
+
files: ["breadcrumb.tsx"],
|
|
12
|
+
a11y: "The current page is a span carrying aria-current=\"page\", not a link: a link to the page you are already on does nothing, and in a list of links it is indistinguishable from the ones that go somewhere. Separators are hidden from assistive technology, because the list already conveys the sequence and reading \"slash\" between every item is the design's punctuation leaking into the content. The ellipsis is the exception and is named, because it is content: it says levels have been left out."
|
|
13
|
+
});
|
|
14
|
+
//#endregion
|
|
15
|
+
export { meta };
|
|
16
|
+
|
|
17
|
+
//# sourceMappingURL=meta.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"meta.js","names":[],"sources":["../../../src/components/breadcrumb/meta.ts"],"sourcesContent":["import { defineMeta } from \"@/registry/schema\";\n\nexport const meta = defineMeta({\n name: \"breadcrumb\",\n title: \"Breadcrumb\",\n description: \"Where the current page sits in the hierarchy, and how to get back up it.\",\n category: \"navigation\",\n status: \"stable\",\n dependencies: [\"radix-ui\"],\n registryDependencies: [],\n files: [\"breadcrumb.tsx\"],\n a11y:\n 'The current page is a span carrying aria-current=\"page\", not a link: a link to the page ' +\n \"you are already on does nothing, and in a list of links it is indistinguishable from the \" +\n \"ones that go somewhere. Separators are hidden from assistive technology, because the list \" +\n 'already conveys the sequence and reading \"slash\" between every item is the design\\'s ' +\n \"punctuation leaking into the content. The ellipsis is the exception and is named, because \" +\n \"it is content: it says levels have been left out.\",\n});\n"],"mappings":";;AAEA,MAAa,OAAO,WAAW;CAC7B,MAAM;CACN,OAAO;CACP,aAAa;CACb,UAAU;CACV,QAAQ;CACR,cAAc,CAAC,UAAU;CACzB,sBAAsB,CAAC;CACvB,OAAO,CAAC,gBAAgB;CACxB,MACE;AAMJ,CAAC"}
|
|
@@ -2,7 +2,7 @@ import { VariantProps } from "class-variance-authority";
|
|
|
2
2
|
import { ComponentPropsWithRef } from "react";
|
|
3
3
|
//#region src/components/button/button.d.ts
|
|
4
4
|
declare const buttonVariants: (props?: ({
|
|
5
|
-
variant?: "link" | "
|
|
5
|
+
variant?: "link" | "secondary" | "outline" | "destructive" | "primary" | "ghost" | null | undefined;
|
|
6
6
|
size?: "sm" | "md" | "lg" | "icon" | "icon-sm" | null | undefined;
|
|
7
7
|
} & import("class-variance-authority/types").ClassProp) | undefined) => string;
|
|
8
8
|
interface ButtonProps extends ComponentPropsWithRef<"button">, VariantProps<typeof buttonVariants> {
|
|
@@ -38,9 +38,9 @@ function Calendar({ className, classNames, showOutsideDays = true, ...props }) {
|
|
|
38
38
|
week_number: cn(defaults.week_number, "text-2xs text-muted-foreground"),
|
|
39
39
|
day: cn(defaults.day, "group/day size-9 p-0 text-center text-sm"),
|
|
40
40
|
day_button: cn(defaults.day_button, "size-9 rounded-md font-normal transition-colors duration-[var(--duration-instant)]", "hover:bg-accent hover:text-accent-foreground", "group-data-[selected=true]/day:bg-primary group-data-[selected=true]/day:text-primary-foreground", "group-data-[selected=true]/day:hover:bg-primary-hover", "disabled:pointer-events-none disabled:opacity-40", focusRing),
|
|
41
|
-
range_start: cn(defaults.range_start, "rounded-
|
|
41
|
+
range_start: cn(defaults.range_start, "rounded-s-md bg-accent"),
|
|
42
42
|
range_middle: cn(defaults.range_middle, "bg-accent [&>button]:bg-transparent [&>button]:text-accent-foreground"),
|
|
43
|
-
range_end: cn(defaults.range_end, "rounded-
|
|
43
|
+
range_end: cn(defaults.range_end, "rounded-e-md bg-accent"),
|
|
44
44
|
today: cn(defaults.today, "[&>button]:font-semibold [&>button]:text-primary"),
|
|
45
45
|
outside: cn(defaults.outside, "text-muted-foreground opacity-50"),
|
|
46
46
|
disabled: cn(defaults.disabled, "opacity-40"),
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"calendar.js","names":[],"sources":["../../../src/components/calendar/calendar.tsx"],"sourcesContent":["\"use client\";\n\nimport { DayPicker, getDefaultClassNames, type DayPickerProps } from \"react-day-picker\";\n\nimport { buttonVariants } from \"@/components/button\";\nimport { focusRing } from \"@/lib/styles\";\nimport { cn } from \"@/lib/utils\";\n\n/**\n * A date grid for selecting a day, several days or a range.\n *\n * Wraps `react-day-picker`, which supplies the parts that are genuinely hard —\n * locale-aware week layout, the roving-focus grid keyboard model, range\n * selection and out-of-month handling. This file is the design layer over it:\n * every class comes from our tokens, so the calendar re-skins with the rest of\n * the system rather than shipping its own visual language.\n */\nexport type CalendarProps = DayPickerProps;\n\nexport function Calendar({\n className,\n classNames,\n showOutsideDays = true,\n ...props\n}: CalendarProps) {\n const defaults = getDefaultClassNames();\n\n return (\n <DayPicker\n data-slot=\"calendar\"\n showOutsideDays={showOutsideDays}\n className={cn(\"p-3\", className)}\n classNames={{\n ...defaults,\n root: cn(defaults.root, \"w-fit\"),\n months: cn(defaults.months, \"flex flex-col gap-4 sm:flex-row\"),\n month: cn(defaults.month, \"flex flex-col gap-4\"),\n nav: cn(defaults.nav, \"absolute inset-x-3 top-3 flex items-center justify-between\"),\n button_previous: cn(\n buttonVariants({ variant: \"ghost\", size: \"icon-sm\" }),\n \"opacity-60 hover:opacity-100\",\n ),\n button_next: cn(\n buttonVariants({ variant: \"ghost\", size: \"icon-sm\" }),\n \"opacity-60 hover:opacity-100\",\n ),\n month_caption: cn(defaults.month_caption, \"flex h-8 items-center justify-center\"),\n caption_label: cn(defaults.caption_label, \"text-sm font-medium\"),\n dropdowns: cn(defaults.dropdowns, \"flex items-center gap-2 text-sm font-medium\"),\n dropdown_root: cn(defaults.dropdown_root, \"relative rounded-md border border-input\"),\n dropdown: cn(defaults.dropdown, \"absolute inset-0 opacity-0\"),\n month_grid: cn(defaults.month_grid, \"w-full border-collapse\"),\n weekdays: cn(defaults.weekdays, \"flex\"),\n weekday: cn(\n defaults.weekday,\n \"w-9 text-2xs font-normal text-muted-foreground select-none\",\n ),\n week: cn(defaults.week, \"mt-1 flex w-full\"),\n week_number_header: cn(defaults.week_number_header, \"w-9\"),\n week_number: cn(defaults.week_number, \"text-2xs text-muted-foreground\"),\n day: cn(defaults.day, \"group/day size-9 p-0 text-center text-sm\"),\n day_button: cn(\n defaults.day_button,\n \"size-9 rounded-md font-normal transition-colors duration-[var(--duration-instant)]\",\n \"hover:bg-accent hover:text-accent-foreground\",\n \"group-data-[selected=true]/day:bg-primary group-data-[selected=true]/day:text-primary-foreground\",\n \"group-data-[selected=true]/day:hover:bg-primary-hover\",\n \"disabled:pointer-events-none disabled:opacity-40\",\n focusRing,\n ),\n // Range middles keep the muted surface so the two ends stay legible as\n // the actual selection.\n range_start: cn(defaults.range_start, \"rounded-
|
|
1
|
+
{"version":3,"file":"calendar.js","names":[],"sources":["../../../src/components/calendar/calendar.tsx"],"sourcesContent":["\"use client\";\n\nimport { DayPicker, getDefaultClassNames, type DayPickerProps } from \"react-day-picker\";\n\nimport { buttonVariants } from \"@/components/button\";\nimport { focusRing } from \"@/lib/styles\";\nimport { cn } from \"@/lib/utils\";\n\n/**\n * A date grid for selecting a day, several days or a range.\n *\n * Wraps `react-day-picker`, which supplies the parts that are genuinely hard —\n * locale-aware week layout, the roving-focus grid keyboard model, range\n * selection and out-of-month handling. This file is the design layer over it:\n * every class comes from our tokens, so the calendar re-skins with the rest of\n * the system rather than shipping its own visual language.\n */\nexport type CalendarProps = DayPickerProps;\n\nexport function Calendar({\n className,\n classNames,\n showOutsideDays = true,\n ...props\n}: CalendarProps) {\n const defaults = getDefaultClassNames();\n\n return (\n <DayPicker\n data-slot=\"calendar\"\n showOutsideDays={showOutsideDays}\n className={cn(\"p-3\", className)}\n classNames={{\n ...defaults,\n root: cn(defaults.root, \"w-fit\"),\n months: cn(defaults.months, \"flex flex-col gap-4 sm:flex-row\"),\n month: cn(defaults.month, \"flex flex-col gap-4\"),\n nav: cn(defaults.nav, \"absolute inset-x-3 top-3 flex items-center justify-between\"),\n button_previous: cn(\n buttonVariants({ variant: \"ghost\", size: \"icon-sm\" }),\n \"opacity-60 hover:opacity-100\",\n ),\n button_next: cn(\n buttonVariants({ variant: \"ghost\", size: \"icon-sm\" }),\n \"opacity-60 hover:opacity-100\",\n ),\n month_caption: cn(defaults.month_caption, \"flex h-8 items-center justify-center\"),\n caption_label: cn(defaults.caption_label, \"text-sm font-medium\"),\n dropdowns: cn(defaults.dropdowns, \"flex items-center gap-2 text-sm font-medium\"),\n dropdown_root: cn(defaults.dropdown_root, \"relative rounded-md border border-input\"),\n dropdown: cn(defaults.dropdown, \"absolute inset-0 opacity-0\"),\n month_grid: cn(defaults.month_grid, \"w-full border-collapse\"),\n weekdays: cn(defaults.weekdays, \"flex\"),\n weekday: cn(\n defaults.weekday,\n \"w-9 text-2xs font-normal text-muted-foreground select-none\",\n ),\n week: cn(defaults.week, \"mt-1 flex w-full\"),\n week_number_header: cn(defaults.week_number_header, \"w-9\"),\n week_number: cn(defaults.week_number, \"text-2xs text-muted-foreground\"),\n day: cn(defaults.day, \"group/day size-9 p-0 text-center text-sm\"),\n day_button: cn(\n defaults.day_button,\n \"size-9 rounded-md font-normal transition-colors duration-[var(--duration-instant)]\",\n \"hover:bg-accent hover:text-accent-foreground\",\n \"group-data-[selected=true]/day:bg-primary group-data-[selected=true]/day:text-primary-foreground\",\n \"group-data-[selected=true]/day:hover:bg-primary-hover\",\n \"disabled:pointer-events-none disabled:opacity-40\",\n focusRing,\n ),\n // Range middles keep the muted surface so the two ends stay legible as\n // the actual selection.\n range_start: cn(defaults.range_start, \"rounded-s-md bg-accent\"),\n range_middle: cn(\n defaults.range_middle,\n \"bg-accent [&>button]:bg-transparent [&>button]:text-accent-foreground\",\n ),\n range_end: cn(defaults.range_end, \"rounded-e-md bg-accent\"),\n today: cn(defaults.today, \"[&>button]:font-semibold [&>button]:text-primary\"),\n outside: cn(defaults.outside, \"text-muted-foreground opacity-50\"),\n disabled: cn(defaults.disabled, \"opacity-40\"),\n hidden: cn(defaults.hidden, \"invisible\"),\n ...classNames,\n }}\n components={{\n Chevron: ({ orientation, className: chevronClassName, ...chevronProps }) => (\n <svg\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n aria-hidden=\"true\"\n className={cn(\"size-4\", chevronClassName)}\n {...chevronProps}\n >\n <path\n d={\n orientation === \"left\"\n ? \"m14 6-6 6 6 6\"\n : orientation === \"right\"\n ? \"m10 6 6 6-6 6\"\n : orientation === \"up\"\n ? \"m6 14 6-6 6 6\"\n : \"m6 10 6 6 6-6\"\n }\n stroke=\"currentColor\"\n strokeWidth=\"2\"\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n />\n </svg>\n ),\n }}\n {...props}\n />\n );\n}\n"],"mappings":";;;;;;;AAmBA,SAAgB,SAAS,EACvB,WACA,YACA,kBAAkB,MAClB,GAAG,SACa;CAChB,MAAM,WAAW,qBAAqB;CAEtC,OACE,oBAAC,WAAD;EACE,aAAU;EACO;EACjB,WAAW,GAAG,OAAO,SAAS;EAC9B,YAAY;GACV,GAAG;GACH,MAAM,GAAG,SAAS,MAAM,OAAO;GAC/B,QAAQ,GAAG,SAAS,QAAQ,iCAAiC;GAC7D,OAAO,GAAG,SAAS,OAAO,qBAAqB;GAC/C,KAAK,GAAG,SAAS,KAAK,4DAA4D;GAClF,iBAAiB,GACf,eAAe;IAAE,SAAS;IAAS,MAAM;GAAU,CAAC,GACpD,8BACF;GACA,aAAa,GACX,eAAe;IAAE,SAAS;IAAS,MAAM;GAAU,CAAC,GACpD,8BACF;GACA,eAAe,GAAG,SAAS,eAAe,sCAAsC;GAChF,eAAe,GAAG,SAAS,eAAe,qBAAqB;GAC/D,WAAW,GAAG,SAAS,WAAW,6CAA6C;GAC/E,eAAe,GAAG,SAAS,eAAe,yCAAyC;GACnF,UAAU,GAAG,SAAS,UAAU,4BAA4B;GAC5D,YAAY,GAAG,SAAS,YAAY,wBAAwB;GAC5D,UAAU,GAAG,SAAS,UAAU,MAAM;GACtC,SAAS,GACP,SAAS,SACT,4DACF;GACA,MAAM,GAAG,SAAS,MAAM,kBAAkB;GAC1C,oBAAoB,GAAG,SAAS,oBAAoB,KAAK;GACzD,aAAa,GAAG,SAAS,aAAa,gCAAgC;GACtE,KAAK,GAAG,SAAS,KAAK,0CAA0C;GAChE,YAAY,GACV,SAAS,YACT,sFACA,gDACA,oGACA,yDACA,oDACA,SACF;GAGA,aAAa,GAAG,SAAS,aAAa,wBAAwB;GAC9D,cAAc,GACZ,SAAS,cACT,uEACF;GACA,WAAW,GAAG,SAAS,WAAW,wBAAwB;GAC1D,OAAO,GAAG,SAAS,OAAO,kDAAkD;GAC5E,SAAS,GAAG,SAAS,SAAS,kCAAkC;GAChE,UAAU,GAAG,SAAS,UAAU,YAAY;GAC5C,QAAQ,GAAG,SAAS,QAAQ,WAAW;GACvC,GAAG;EACL;EACA,YAAY,EACV,UAAU,EAAE,aAAa,WAAW,kBAAkB,GAAG,mBACvD,oBAAC,OAAD;GACE,SAAQ;GACR,MAAK;GACL,eAAY;GACZ,WAAW,GAAG,UAAU,gBAAgB;GACxC,GAAI;GAEJ,UAAA,oBAAC,QAAD;IACE,GACE,gBAAgB,SACZ,kBACA,gBAAgB,UACd,kBACA,gBAAgB,OACd,kBACA;IAEV,QAAO;IACP,aAAY;IACZ,eAAc;IACd,gBAAe;GAChB,CAAA;EACE,CAAA,EAET;EACA,GAAI;CACL,CAAA;AAEL"}
|
|
@@ -63,7 +63,7 @@ function CopyButton({ className, getText, label = "Copy code", copiedLabel = "Co
|
|
|
63
63
|
"data-state": state,
|
|
64
64
|
onClick: copy,
|
|
65
65
|
"aria-label": label,
|
|
66
|
-
className: cn("
|
|
66
|
+
className: cn("ms-auto grid size-6 shrink-0 place-items-center rounded text-muted-foreground", "transition-colors duration-[var(--duration-fast)] hover:bg-accent hover:text-foreground", focusRing, className),
|
|
67
67
|
...props,
|
|
68
68
|
children: [state === "copied" ? /* @__PURE__ */ jsx("svg", {
|
|
69
69
|
viewBox: "0 0 24 24",
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"code-block.js","names":[],"sources":["../../../src/components/code-block/code-block.tsx"],"sourcesContent":["\"use client\";\n\nimport { useCallback, useEffect, useRef, useState, type ComponentPropsWithRef } from \"react\";\n\nimport { focusRing } from \"@/lib/styles\";\nimport { cn } from \"@/lib/utils\";\n\n/**\n * A block of code, with a copy control.\n *\n * Syntax highlighting is deliberately not built in. A highlighter is a large\n * dependency, a theme system of its own, and a choice between build-time and\n * runtime that belongs to the application. Pass already-highlighted markup as\n * children and the styling here applies to it; pass a plain string and it\n * renders as plain code.\n */\n\nexport interface CodeBlockProps extends ComponentPropsWithRef<\"div\"> {\n /** Shown in the header and used as the language hint. */\n language?: string;\n /** Filename or other caption for the header. */\n title?: string;\n /**\n * The text the copy button puts on the clipboard.\n *\n * Required when children are rendered markup, because reading text back out\n * of highlighted DOM loses whitespace in ways that break pasted code.\n */\n code?: string;\n /** Hides the copy control. */\n hideCopy?: boolean;\n}\n\nexport function CodeBlock({\n className,\n language,\n title,\n code,\n hideCopy,\n children,\n ...props\n}: CodeBlockProps) {\n const preRef = useRef<HTMLPreElement | null>(null);\n const showHeader = Boolean(title ?? language) || !hideCopy;\n\n return (\n <div\n data-slot=\"code-block\"\n data-language={language}\n className={cn(\"overflow-hidden rounded-lg border border-border bg-muted/40\", className)}\n {...props}\n >\n {showHeader ? (\n <div className=\"flex items-center gap-2 border-b border-border px-3 py-1.5\">\n <span className=\"truncate text-2xs font-medium text-muted-foreground\">\n {title ?? language}\n </span>\n {hideCopy ? null : (\n <CopyButton getText={() => code ?? preRef.current?.textContent ?? \"\"} />\n )}\n </div>\n ) : null}\n <pre\n ref={preRef}\n // Focusable named region: code overflows horizontally, and a scroll box\n // that cannot take focus is unreachable by keyboard.\n tabIndex={0}\n role=\"region\"\n aria-label={title ?? (language ? `${language} code` : \"Code\")}\n className={cn(\n \"overflow-x-auto p-3 font-mono text-xs leading-relaxed\",\n focusRing,\n \"focus-visible:ring-inset\",\n )}\n >\n <code>{children}</code>\n </pre>\n </div>\n );\n}\n\nexport interface CopyButtonProps extends Omit<ComponentPropsWithRef<\"button\">, \"onClick\"> {\n getText: () => string;\n label?: string;\n copiedLabel?: string;\n /** How long the confirmation stays, in milliseconds. */\n resetAfter?: number;\n}\n\n/**\n * Copies text and confirms it.\n *\n * The confirmation is announced politely as well as shown — a checkmark that\n * only appears visually leaves a screen reader user with no idea whether the\n * button did anything. Failure is surfaced too, rather than silently looking\n * like success, since the clipboard API can be refused outright.\n */\nexport function CopyButton({\n className,\n getText,\n label = \"Copy code\",\n copiedLabel = \"Copied\",\n resetAfter = 2000,\n ...props\n}: CopyButtonProps) {\n const [state, setState] = useState<\"idle\" | \"copied\" | \"error\">(\"idle\");\n const timer = useRef<ReturnType<typeof setTimeout> | null>(null);\n\n useEffect(\n () => () => {\n if (timer.current) clearTimeout(timer.current);\n },\n [],\n );\n\n const copy = useCallback(() => {\n const reset = () => {\n if (timer.current) clearTimeout(timer.current);\n timer.current = setTimeout(() => {\n setState(\"idle\");\n }, resetAfter);\n };\n\n navigator.clipboard.writeText(getText()).then(\n () => {\n setState(\"copied\");\n reset();\n },\n () => {\n // Refused by the browser or unavailable outside a secure context.\n // Saying so beats pretending it worked.\n setState(\"error\");\n reset();\n },\n );\n }, [getText, resetAfter]);\n\n return (\n <button\n type=\"button\"\n data-slot=\"copy-button\"\n data-state={state}\n onClick={copy}\n aria-label={label}\n className={cn(\n \"
|
|
1
|
+
{"version":3,"file":"code-block.js","names":[],"sources":["../../../src/components/code-block/code-block.tsx"],"sourcesContent":["\"use client\";\n\nimport { useCallback, useEffect, useRef, useState, type ComponentPropsWithRef } from \"react\";\n\nimport { focusRing } from \"@/lib/styles\";\nimport { cn } from \"@/lib/utils\";\n\n/**\n * A block of code, with a copy control.\n *\n * Syntax highlighting is deliberately not built in. A highlighter is a large\n * dependency, a theme system of its own, and a choice between build-time and\n * runtime that belongs to the application. Pass already-highlighted markup as\n * children and the styling here applies to it; pass a plain string and it\n * renders as plain code.\n */\n\nexport interface CodeBlockProps extends ComponentPropsWithRef<\"div\"> {\n /** Shown in the header and used as the language hint. */\n language?: string;\n /** Filename or other caption for the header. */\n title?: string;\n /**\n * The text the copy button puts on the clipboard.\n *\n * Required when children are rendered markup, because reading text back out\n * of highlighted DOM loses whitespace in ways that break pasted code.\n */\n code?: string;\n /** Hides the copy control. */\n hideCopy?: boolean;\n}\n\nexport function CodeBlock({\n className,\n language,\n title,\n code,\n hideCopy,\n children,\n ...props\n}: CodeBlockProps) {\n const preRef = useRef<HTMLPreElement | null>(null);\n const showHeader = Boolean(title ?? language) || !hideCopy;\n\n return (\n <div\n data-slot=\"code-block\"\n data-language={language}\n className={cn(\"overflow-hidden rounded-lg border border-border bg-muted/40\", className)}\n {...props}\n >\n {showHeader ? (\n <div className=\"flex items-center gap-2 border-b border-border px-3 py-1.5\">\n <span className=\"truncate text-2xs font-medium text-muted-foreground\">\n {title ?? language}\n </span>\n {hideCopy ? null : (\n <CopyButton getText={() => code ?? preRef.current?.textContent ?? \"\"} />\n )}\n </div>\n ) : null}\n <pre\n ref={preRef}\n // Focusable named region: code overflows horizontally, and a scroll box\n // that cannot take focus is unreachable by keyboard.\n tabIndex={0}\n role=\"region\"\n aria-label={title ?? (language ? `${language} code` : \"Code\")}\n className={cn(\n \"overflow-x-auto p-3 font-mono text-xs leading-relaxed\",\n focusRing,\n \"focus-visible:ring-inset\",\n )}\n >\n <code>{children}</code>\n </pre>\n </div>\n );\n}\n\nexport interface CopyButtonProps extends Omit<ComponentPropsWithRef<\"button\">, \"onClick\"> {\n getText: () => string;\n label?: string;\n copiedLabel?: string;\n /** How long the confirmation stays, in milliseconds. */\n resetAfter?: number;\n}\n\n/**\n * Copies text and confirms it.\n *\n * The confirmation is announced politely as well as shown — a checkmark that\n * only appears visually leaves a screen reader user with no idea whether the\n * button did anything. Failure is surfaced too, rather than silently looking\n * like success, since the clipboard API can be refused outright.\n */\nexport function CopyButton({\n className,\n getText,\n label = \"Copy code\",\n copiedLabel = \"Copied\",\n resetAfter = 2000,\n ...props\n}: CopyButtonProps) {\n const [state, setState] = useState<\"idle\" | \"copied\" | \"error\">(\"idle\");\n const timer = useRef<ReturnType<typeof setTimeout> | null>(null);\n\n useEffect(\n () => () => {\n if (timer.current) clearTimeout(timer.current);\n },\n [],\n );\n\n const copy = useCallback(() => {\n const reset = () => {\n if (timer.current) clearTimeout(timer.current);\n timer.current = setTimeout(() => {\n setState(\"idle\");\n }, resetAfter);\n };\n\n navigator.clipboard.writeText(getText()).then(\n () => {\n setState(\"copied\");\n reset();\n },\n () => {\n // Refused by the browser or unavailable outside a secure context.\n // Saying so beats pretending it worked.\n setState(\"error\");\n reset();\n },\n );\n }, [getText, resetAfter]);\n\n return (\n <button\n type=\"button\"\n data-slot=\"copy-button\"\n data-state={state}\n onClick={copy}\n aria-label={label}\n className={cn(\n \"ms-auto grid size-6 shrink-0 place-items-center rounded text-muted-foreground\",\n \"transition-colors duration-[var(--duration-fast)] hover:bg-accent hover:text-foreground\",\n focusRing,\n className,\n )}\n {...props}\n >\n {state === \"copied\" ? (\n <svg viewBox=\"0 0 24 24\" fill=\"none\" aria-hidden=\"true\" className=\"size-3.5\">\n <path\n d=\"m5 13 4 4L19 7\"\n stroke=\"currentColor\"\n strokeWidth=\"2\"\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n />\n </svg>\n ) : (\n <svg viewBox=\"0 0 24 24\" fill=\"none\" aria-hidden=\"true\" className=\"size-3.5\">\n <rect\n x=\"9\"\n y=\"9\"\n width=\"12\"\n height=\"12\"\n rx=\"2\"\n stroke=\"currentColor\"\n strokeWidth=\"2\"\n />\n <path\n d=\"M5 15H4a1 1 0 0 1-1-1V4a1 1 0 0 1 1-1h10a1 1 0 0 1 1 1v1\"\n stroke=\"currentColor\"\n strokeWidth=\"2\"\n strokeLinecap=\"round\"\n />\n </svg>\n )}\n {/* Announced, not just drawn. */}\n <span role=\"status\" aria-live=\"polite\" className=\"sr-only\">\n {state === \"copied\" ? copiedLabel : state === \"error\" ? \"Copy failed\" : \"\"}\n </span>\n </button>\n );\n}\n"],"mappings":";;;;;;AAiCA,SAAgB,UAAU,EACxB,WACA,UACA,OACA,MACA,UACA,UACA,GAAG,SACc;CACjB,MAAM,SAAS,OAA8B,IAAI;CACjD,MAAM,aAAa,QAAQ,SAAS,QAAQ,KAAK,CAAC;CAElD,OACE,qBAAC,OAAD;EACE,aAAU;EACV,iBAAe;EACf,WAAW,GAAG,+DAA+D,SAAS;EACtF,GAAI;EAJN,UAAA,CAMG,aACC,qBAAC,OAAD;GAAK,WAAU;GAAf,UAAA,CACE,oBAAC,QAAD;IAAM,WAAU;IACb,UAAA,SAAS;GACN,CAAA,GACL,WAAW,OACV,oBAAC,YAAD,EAAY,eAAe,QAAQ,OAAO,SAAS,eAAe,GAAK,CAAA,CAEtE;EACH,CAAA,IAAA,MACJ,oBAAC,OAAD;GACE,KAAK;GAGL,UAAU;GACV,MAAK;GACL,cAAY,UAAU,WAAW,GAAG,SAAS,SAAS;GACtD,WAAW,GACT,yDACA,WACA,0BACF;GAEA,UAAA,oBAAC,QAAD,EAAO,SAAe,CAAA;EACnB,CAAA,CACF;;AAET;;;;;;;;;AAkBA,SAAgB,WAAW,EACzB,WACA,SACA,QAAQ,aACR,cAAc,UACd,aAAa,KACb,GAAG,SACe;CAClB,MAAM,CAAC,OAAO,YAAY,SAAsC,MAAM;CACtE,MAAM,QAAQ,OAA6C,IAAI;CAE/D,sBACc;EACV,IAAI,MAAM,SAAS,aAAa,MAAM,OAAO;CAC/C,GACA,CAAC,CACH;CAEA,MAAM,OAAO,kBAAkB;EAC7B,MAAM,cAAc;GAClB,IAAI,MAAM,SAAS,aAAa,MAAM,OAAO;GAC7C,MAAM,UAAU,iBAAiB;IAC/B,SAAS,MAAM;GACjB,GAAG,UAAU;EACf;EAEA,UAAU,UAAU,UAAU,QAAQ,CAAC,CAAC,CAAC,WACjC;GACJ,SAAS,QAAQ;GACjB,MAAM;EACR,SACM;GAGJ,SAAS,OAAO;GAChB,MAAM;EACR,CACF;CACF,GAAG,CAAC,SAAS,UAAU,CAAC;CAExB,OACE,qBAAC,UAAD;EACE,MAAK;EACL,aAAU;EACV,cAAY;EACZ,SAAS;EACT,cAAY;EACZ,WAAW,GACT,iFACA,2FACA,WACA,SACF;EACA,GAAI;EAZN,UAAA,CAcG,UAAU,WACT,oBAAC,OAAD;GAAK,SAAQ;GAAY,MAAK;GAAO,eAAY;GAAO,WAAU;GAChE,UAAA,oBAAC,QAAD;IACE,GAAE;IACF,QAAO;IACP,aAAY;IACZ,eAAc;IACd,gBAAe;GAChB,CAAA;EACE,CAAA,IAEL,qBAAC,OAAD;GAAK,SAAQ;GAAY,MAAK;GAAO,eAAY;GAAO,WAAU;GAAlE,UAAA,CACE,oBAAC,QAAD;IACE,GAAE;IACF,GAAE;IACF,OAAM;IACN,QAAO;IACP,IAAG;IACH,QAAO;IACP,aAAY;GACb,CAAA,GACD,oBAAC,QAAD;IACE,GAAE;IACF,QAAO;IACP,aAAY;IACZ,eAAc;GACf,CAAA,CACE;EAGP,CAAA,GAAA,oBAAC,QAAD;GAAM,MAAK;GAAS,aAAU;GAAS,WAAU;GAC9C,UAAA,UAAU,WAAW,cAAc,UAAU,UAAU,gBAAgB;EACpE,CAAA,CACA;;AAEZ"}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import { Collapsible } from "radix-ui";
|
|
2
|
+
import { ComponentPropsWithRef } from "react";
|
|
3
|
+
//#region src/components/collapsible/collapsible.d.ts
|
|
4
|
+
/**
|
|
5
|
+
* A section that opens and closes.
|
|
6
|
+
*
|
|
7
|
+
* Unlike Accordion, there is no set: one region, one trigger, no notion of
|
|
8
|
+
* "only one open at a time". Reaching for an Accordion with a single item
|
|
9
|
+
* gives that item a `heading` role and a position in a list of one, both of
|
|
10
|
+
* which are noise.
|
|
11
|
+
*
|
|
12
|
+
* The height animation is driven by the primitive's own measured height rather
|
|
13
|
+
* than a guess, so content of any size opens smoothly, and it derives from
|
|
14
|
+
* `--duration-*` so the motion scale applies.
|
|
15
|
+
*/
|
|
16
|
+
type CollapsibleProps = ComponentPropsWithRef<typeof Collapsible.Root>;
|
|
17
|
+
/**
|
|
18
|
+
* Wrapped rather than re-exported.
|
|
19
|
+
*
|
|
20
|
+
* A bare `export const Collapsible = CollapsiblePrimitive.Root` leaves the
|
|
21
|
+
* inferred type pointing into the primitive's own package, which TypeScript
|
|
22
|
+
* cannot name in declaration output (TS2883). It also gives every other
|
|
23
|
+
* component's `data-slot` a hole where this one should be.
|
|
24
|
+
*/
|
|
25
|
+
declare function Collapsible$1({ className, ...props }: CollapsibleProps): import("react").JSX.Element;
|
|
26
|
+
declare function CollapsibleTrigger({ className, ...props }: ComponentPropsWithRef<typeof Collapsible.Trigger>): import("react").JSX.Element;
|
|
27
|
+
declare function CollapsibleContent({ className, ...props }: ComponentPropsWithRef<typeof Collapsible.Content>): import("react").JSX.Element;
|
|
28
|
+
//#endregion
|
|
29
|
+
export { Collapsible$1 as Collapsible, CollapsibleContent, CollapsibleProps, CollapsibleTrigger };
|
|
30
|
+
//# sourceMappingURL=collapsible.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"collapsible.d.ts","names":[],"sources":["../../../src/components/collapsible/collapsible.tsx"],"mappings":";;;;;;;;;;;;;;;KAoBY,mBAAmB,6BAA6B,YAAqB;;;;;;;;;iBAUjE,gBAAc,cAAc,SAAS,mCAAgB,IAAA;iBAIrD,qBACd,cACG,SACF,6BAA6B,YAAqB,2BAAQ,IAAA;iBAU7C,qBACd,cACG,SACF,6BAA6B,YAAqB,2BAAQ,IAAA"}
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { cn } from "../../lib/utils.js";
|
|
3
|
+
import { Collapsible } from "radix-ui";
|
|
4
|
+
import { jsx } from "react/jsx-runtime";
|
|
5
|
+
//#region src/components/collapsible/collapsible.tsx
|
|
6
|
+
/**
|
|
7
|
+
* Wrapped rather than re-exported.
|
|
8
|
+
*
|
|
9
|
+
* A bare `export const Collapsible = CollapsiblePrimitive.Root` leaves the
|
|
10
|
+
* inferred type pointing into the primitive's own package, which TypeScript
|
|
11
|
+
* cannot name in declaration output (TS2883). It also gives every other
|
|
12
|
+
* component's `data-slot` a hole where this one should be.
|
|
13
|
+
*/
|
|
14
|
+
function Collapsible$1({ className, ...props }) {
|
|
15
|
+
return /* @__PURE__ */ jsx(Collapsible.Root, {
|
|
16
|
+
"data-slot": "collapsible",
|
|
17
|
+
className,
|
|
18
|
+
...props
|
|
19
|
+
});
|
|
20
|
+
}
|
|
21
|
+
function CollapsibleTrigger({ className, ...props }) {
|
|
22
|
+
return /* @__PURE__ */ jsx(Collapsible.Trigger, {
|
|
23
|
+
"data-slot": "collapsible-trigger",
|
|
24
|
+
className: cn("outline-none", className),
|
|
25
|
+
...props
|
|
26
|
+
});
|
|
27
|
+
}
|
|
28
|
+
function CollapsibleContent({ className, ...props }) {
|
|
29
|
+
return /* @__PURE__ */ jsx(Collapsible.Content, {
|
|
30
|
+
"data-slot": "collapsible-content",
|
|
31
|
+
className: cn("overflow-hidden", "data-[state=closed]:animate-collapse-up data-[state=open]:animate-collapse-down", className),
|
|
32
|
+
...props
|
|
33
|
+
});
|
|
34
|
+
}
|
|
35
|
+
//#endregion
|
|
36
|
+
export { Collapsible$1 as Collapsible, CollapsibleContent, CollapsibleTrigger };
|
|
37
|
+
|
|
38
|
+
//# sourceMappingURL=collapsible.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"collapsible.js","names":["Collapsible","CollapsiblePrimitive"],"sources":["../../../src/components/collapsible/collapsible.tsx"],"sourcesContent":["\"use client\";\n\nimport { Collapsible as CollapsiblePrimitive } from \"radix-ui\";\nimport type { ComponentPropsWithRef } from \"react\";\n\nimport { cn } from \"@/lib/utils\";\n\n/**\n * A section that opens and closes.\n *\n * Unlike Accordion, there is no set: one region, one trigger, no notion of\n * \"only one open at a time\". Reaching for an Accordion with a single item\n * gives that item a `heading` role and a position in a list of one, both of\n * which are noise.\n *\n * The height animation is driven by the primitive's own measured height rather\n * than a guess, so content of any size opens smoothly, and it derives from\n * `--duration-*` so the motion scale applies.\n */\n\nexport type CollapsibleProps = ComponentPropsWithRef<typeof CollapsiblePrimitive.Root>;\n\n/**\n * Wrapped rather than re-exported.\n *\n * A bare `export const Collapsible = CollapsiblePrimitive.Root` leaves the\n * inferred type pointing into the primitive's own package, which TypeScript\n * cannot name in declaration output (TS2883). It also gives every other\n * component's `data-slot` a hole where this one should be.\n */\nexport function Collapsible({ className, ...props }: CollapsibleProps) {\n return <CollapsiblePrimitive.Root data-slot=\"collapsible\" className={className} {...props} />;\n}\n\nexport function CollapsibleTrigger({\n className,\n ...props\n}: ComponentPropsWithRef<typeof CollapsiblePrimitive.Trigger>) {\n return (\n <CollapsiblePrimitive.Trigger\n data-slot=\"collapsible-trigger\"\n className={cn(\"outline-none\", className)}\n {...props}\n />\n );\n}\n\nexport function CollapsibleContent({\n className,\n ...props\n}: ComponentPropsWithRef<typeof CollapsiblePrimitive.Content>) {\n return (\n <CollapsiblePrimitive.Content\n data-slot=\"collapsible-content\"\n className={cn(\n \"overflow-hidden\",\n \"data-[state=closed]:animate-collapse-up data-[state=open]:animate-collapse-down\",\n className,\n )}\n {...props}\n />\n );\n}\n"],"mappings":";;;;;;;;;;;;;AA8BA,SAAgBA,cAAY,EAAE,WAAW,GAAG,SAA2B;CACrE,OAAO,oBAACC,YAAqB,MAAtB;EAA2B,aAAU;EAAyB;EAAW,GAAI;CAAQ,CAAA;AAC9F;AAEA,SAAgB,mBAAmB,EACjC,WACA,GAAG,SAC0D;CAC7D,OACE,oBAACA,YAAqB,SAAtB;EACE,aAAU;EACV,WAAW,GAAG,gBAAgB,SAAS;EACvC,GAAI;CACL,CAAA;AAEL;AAEA,SAAgB,mBAAmB,EACjC,WACA,GAAG,SAC0D;CAC7D,OACE,oBAACA,YAAqB,SAAtB;EACE,aAAU;EACV,WAAW,GACT,mBACA,mFACA,SACF;EACA,GAAI;CACL,CAAA;AAEL"}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { defineMeta } from "../../registry/schema.js";
|
|
2
|
+
//#region src/components/collapsible/meta.ts
|
|
3
|
+
const meta = defineMeta({
|
|
4
|
+
name: "collapsible",
|
|
5
|
+
title: "Collapsible",
|
|
6
|
+
description: "A single section that opens and closes, without an accordion's set semantics.",
|
|
7
|
+
category: "layout",
|
|
8
|
+
status: "stable",
|
|
9
|
+
dependencies: ["radix-ui"],
|
|
10
|
+
registryDependencies: [],
|
|
11
|
+
files: ["collapsible.tsx"],
|
|
12
|
+
a11y: "The trigger carries aria-expanded and points at the region it controls, both from the primitive. Reach for this rather than an Accordion of one item: a single-item Accordion gives its trigger a heading role and a position in a list of one, neither of which is true."
|
|
13
|
+
});
|
|
14
|
+
//#endregion
|
|
15
|
+
export { meta };
|
|
16
|
+
|
|
17
|
+
//# sourceMappingURL=meta.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"meta.js","names":[],"sources":["../../../src/components/collapsible/meta.ts"],"sourcesContent":["import { defineMeta } from \"@/registry/schema\";\n\nexport const meta = defineMeta({\n name: \"collapsible\",\n title: \"Collapsible\",\n description: \"A single section that opens and closes, without an accordion's set semantics.\",\n category: \"layout\",\n status: \"stable\",\n dependencies: [\"radix-ui\"],\n registryDependencies: [],\n files: [\"collapsible.tsx\"],\n a11y:\n \"The trigger carries aria-expanded and points at the region it controls, both from the \" +\n \"primitive. Reach for this rather than an Accordion of one item: a single-item Accordion \" +\n \"gives its trigger a heading role and a position in a list of one, neither of which is true.\",\n});\n"],"mappings":";;AAEA,MAAa,OAAO,WAAW;CAC7B,MAAM;CACN,OAAO;CACP,aAAa;CACb,UAAU;CACV,QAAQ;CACR,cAAc,CAAC,UAAU;CACzB,sBAAsB,CAAC;CACvB,OAAO,CAAC,iBAAiB;CACzB,MACE;AAGJ,CAAC"}
|
|
@@ -308,10 +308,10 @@ function ComboboxItem({ className, value, keywords, disabled, children, ...props
|
|
|
308
308
|
select(value);
|
|
309
309
|
}
|
|
310
310
|
},
|
|
311
|
-
className: cn("relative flex cursor-default items-center gap-2 rounded-md py-1.5
|
|
311
|
+
className: cn("relative flex cursor-default items-center gap-2 rounded-md py-1.5 ps-2 pe-8 text-sm outline-none select-none", "transition-colors duration-[var(--duration-instant)]", "data-[active]:bg-accent data-[active]:text-accent-foreground", "data-[disabled]:pointer-events-none data-[disabled]:opacity-55", "[&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4", className),
|
|
312
312
|
...props,
|
|
313
313
|
children: [children ?? value, selected ? /* @__PURE__ */ jsx("span", {
|
|
314
|
-
className: "absolute
|
|
314
|
+
className: "absolute end-2 grid size-4 place-items-center",
|
|
315
315
|
children: /* @__PURE__ */ jsx("svg", {
|
|
316
316
|
viewBox: "0 0 24 24",
|
|
317
317
|
fill: "none",
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"combobox.js","names":["PopoverPrimitive"],"sources":["../../../src/components/combobox/combobox.tsx"],"sourcesContent":["\"use client\";\n\nimport { Popover as PopoverPrimitive } from \"radix-ui\";\nimport {\n createContext,\n useCallback,\n useContext,\n useEffect,\n useId,\n useMemo,\n useRef,\n useState,\n type ComponentPropsWithRef,\n type KeyboardEvent as ReactKeyboardEvent,\n type ReactNode,\n} from \"react\";\n\nimport { focusRing } from \"@/lib/styles\";\nimport { cn } from \"@/lib/utils\";\n\n/**\n * A searchable single-select.\n *\n * Implements the ARIA combobox pattern directly on a popover rather than\n * depending on a command-menu package: the input owns `role=\"combobox\"`, the\n * list owns `role=\"listbox\"`, and the active option is tracked with\n * `aria-activedescendant` so focus never leaves the input while typing.\n *\n * Navigation reads the rendered options from the DOM rather than a registry,\n * which keeps the active option correct as filtering adds and removes items —\n * a registry has to be kept in sync with what is actually on screen, and drifts.\n *\n * This version is single-select and flat. Multi-select and grouping can be\n * added without changing this API.\n */\n\n/** Default match: case-insensitive substring over the value and any keywords. */\nexport function defaultComboboxFilter(search: string, haystack: string[]): boolean {\n const needle = search.trim().toLowerCase();\n if (!needle) return true;\n return haystack.some((entry) => entry.toLowerCase().includes(needle));\n}\n\ninterface ComboboxContextValue {\n open: boolean;\n setOpen: (open: boolean) => void;\n search: string;\n setSearch: (search: string) => void;\n value: string | undefined;\n select: (value: string) => void;\n activeValue: string | undefined;\n setActiveValue: (value: string | undefined) => void;\n filter: (search: string, haystack: string[]) => boolean;\n listId: string;\n inputId: string;\n optionId: (value: string) => string;\n listRef: React.RefObject<HTMLDivElement | null>;\n registerVisible: (value: string, visible: boolean) => void;\n visibleCount: number;\n}\n\nconst ComboboxContext = createContext<ComboboxContextValue | null>(null);\n\nfunction useCombobox(component: string): ComboboxContextValue {\n const context = useContext(ComboboxContext);\n if (!context) {\n throw new Error(`${component} must be rendered inside <Combobox>.`);\n }\n return context;\n}\n\nexport interface ComboboxProps {\n value?: string;\n defaultValue?: string;\n onValueChange?: (value: string) => void;\n open?: boolean;\n defaultOpen?: boolean;\n onOpenChange?: (open: boolean) => void;\n /** Overrides how a search string is matched against an option. */\n filter?: (search: string, haystack: string[]) => boolean;\n children?: ReactNode;\n}\n\nexport function Combobox({\n value: valueProp,\n defaultValue,\n onValueChange,\n open: openProp,\n defaultOpen = false,\n onOpenChange,\n filter = defaultComboboxFilter,\n children,\n}: ComboboxProps) {\n const uid = useId();\n\n const [uncontrolledValue, setUncontrolledValue] = useState(defaultValue);\n const value = valueProp === undefined ? uncontrolledValue : valueProp;\n\n const [uncontrolledOpen, setUncontrolledOpen] = useState(defaultOpen);\n const open = openProp === undefined ? uncontrolledOpen : openProp;\n\n const [search, setSearch] = useState(\"\");\n const [activeValue, setActiveValue] = useState<string | undefined>(undefined);\n const listRef = useRef<HTMLDivElement | null>(null);\n\n // Counted rather than listed: the empty state only needs to know whether\n // anything survived the filter.\n const visibleValues = useRef(new Set<string>());\n const [visibleCount, setVisibleCount] = useState(0);\n\n const registerVisible = useCallback((optionValue: string, visible: boolean) => {\n const set = visibleValues.current;\n const had = set.has(optionValue);\n if (visible && !had) set.add(optionValue);\n else if (!visible && had) set.delete(optionValue);\n else return;\n setVisibleCount(set.size);\n }, []);\n\n const setOpen = useCallback(\n (next: boolean) => {\n if (openProp === undefined) setUncontrolledOpen(next);\n onOpenChange?.(next);\n // Reopening should start from a clean search rather than resuming a\n // half-typed query the user has forgotten about.\n if (!next) {\n setSearch(\"\");\n setActiveValue(undefined);\n }\n },\n [openProp, onOpenChange],\n );\n\n const select = useCallback(\n (next: string) => {\n if (valueProp === undefined) setUncontrolledValue(next);\n onValueChange?.(next);\n setOpen(false);\n },\n [valueProp, onValueChange, setOpen],\n );\n\n const context = useMemo<ComboboxContextValue>(\n () => ({\n open,\n setOpen,\n search,\n setSearch,\n value,\n select,\n activeValue,\n setActiveValue,\n filter,\n listId: `${uid}-list`,\n inputId: `${uid}-input`,\n optionId: (optionValue: string) =>\n `${uid}-option-${optionValue.replace(/\\s+/g, \"-\").toLowerCase()}`,\n listRef,\n registerVisible,\n visibleCount,\n }),\n [\n open,\n setOpen,\n search,\n value,\n select,\n activeValue,\n filter,\n uid,\n registerVisible,\n visibleCount,\n ],\n );\n\n return (\n <ComboboxContext.Provider value={context}>\n <PopoverPrimitive.Root open={open} onOpenChange={setOpen}>\n {children}\n </PopoverPrimitive.Root>\n </ComboboxContext.Provider>\n );\n}\n\nexport interface ComboboxTriggerProps extends ComponentPropsWithRef<\"button\"> {\n /** Shown when nothing is selected. */\n placeholder?: string;\n}\n\nexport function ComboboxTrigger({\n className,\n placeholder = \"Select…\",\n children,\n ...props\n}: ComboboxTriggerProps) {\n const { value, open } = useCombobox(\"ComboboxTrigger\");\n\n return (\n <PopoverPrimitive.Trigger asChild>\n <button\n type=\"button\"\n data-slot=\"combobox-trigger\"\n aria-expanded={open}\n className={cn(\n \"flex h-9 w-full items-center justify-between gap-2 rounded-md border border-input bg-background\",\n \"px-3 text-sm shadow-xs transition-[border-color,box-shadow] duration-[var(--duration-fast)]\",\n \"focus-visible:border-ring\",\n \"disabled:cursor-not-allowed disabled:opacity-55\",\n \"aria-invalid:border-destructive\",\n focusRing,\n className,\n )}\n {...props}\n >\n <span className={cn(\"truncate\", !value && \"text-muted-foreground\")}>\n {children ?? value ?? placeholder}\n </span>\n <svg\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n aria-hidden=\"true\"\n className=\"size-4 shrink-0 opacity-60\"\n >\n <path\n d=\"m7 10 5 5 5-5\"\n stroke=\"currentColor\"\n strokeWidth=\"2\"\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n />\n </svg>\n </button>\n </PopoverPrimitive.Trigger>\n );\n}\n\nexport interface ComboboxContentProps extends ComponentPropsWithRef<\n typeof PopoverPrimitive.Content\n> {\n /** Names the popover, which carries role=\"dialog\". */\n label?: string;\n}\n\nexport function ComboboxContent({\n className,\n align = \"start\",\n sideOffset = 6,\n label = \"Search options\",\n children,\n ...props\n}: ComboboxContentProps) {\n return (\n <PopoverPrimitive.Portal>\n <PopoverPrimitive.Content\n data-slot=\"combobox-content\"\n align={align}\n sideOffset={sideOffset}\n aria-label={label}\n // Focus belongs in the search input, which the input claims on mount.\n onOpenAutoFocus={(event) => {\n event.preventDefault();\n }}\n className={cn(\n \"z-[var(--z-popover)] w-[var(--radix-popover-trigger-width)] min-w-48 overflow-hidden\",\n \"rounded-lg border border-border bg-popover p-0 text-popover-foreground shadow-lg\",\n \"origin-[var(--radix-popover-content-transform-origin)]\",\n \"data-[state=closed]:animate-float-out data-[state=open]:animate-float-in\",\n className,\n )}\n {...props}\n >\n {children}\n </PopoverPrimitive.Content>\n </PopoverPrimitive.Portal>\n );\n}\n\n/** Options currently rendered, in DOM order and excluding disabled ones. */\nfunction visibleOptions(list: HTMLElement | null): HTMLElement[] {\n if (!list) return [];\n return Array.from(list.querySelectorAll<HTMLElement>('[role=\"option\"]:not([data-disabled])'));\n}\n\nexport type ComboboxInputProps = Omit<ComponentPropsWithRef<\"input\">, \"value\" | \"onChange\">;\n\nexport function ComboboxInput({ className, ...props }: ComboboxInputProps) {\n const {\n search,\n setSearch,\n activeValue,\n setActiveValue,\n select,\n setOpen,\n listId,\n inputId,\n optionId,\n listRef,\n } = useCombobox(\"ComboboxInput\");\n\n const inputRef = useRef<HTMLInputElement | null>(null);\n\n useEffect(() => {\n inputRef.current?.focus();\n }, []);\n\n const move = useCallback(\n (delta: number | \"first\" | \"last\") => {\n const options = visibleOptions(listRef.current);\n if (options.length === 0) return;\n\n const currentIndex = options.findIndex((option) => option.dataset.value === activeValue);\n\n let nextIndex: number;\n if (delta === \"first\") nextIndex = 0;\n else if (delta === \"last\") nextIndex = options.length - 1;\n else if (currentIndex === -1) nextIndex = delta > 0 ? 0 : options.length - 1;\n // Wraps, so holding an arrow key never dead-ends at the edge of the list.\n else nextIndex = (currentIndex + delta + options.length) % options.length;\n\n const next = options[nextIndex];\n if (!next) return;\n setActiveValue(next.dataset.value);\n next.scrollIntoView({ block: \"nearest\" });\n },\n [activeValue, listRef, setActiveValue],\n );\n\n function handleKeyDown(event: ReactKeyboardEvent<HTMLInputElement>) {\n switch (event.key) {\n case \"ArrowDown\":\n event.preventDefault();\n move(1);\n break;\n case \"ArrowUp\":\n event.preventDefault();\n move(-1);\n break;\n case \"Home\":\n event.preventDefault();\n move(\"first\");\n break;\n case \"End\":\n event.preventDefault();\n move(\"last\");\n break;\n case \"Enter\": {\n if (activeValue === undefined) return;\n event.preventDefault();\n select(activeValue);\n break;\n }\n case \"Escape\":\n event.preventDefault();\n setOpen(false);\n break;\n default:\n break;\n }\n }\n\n return (\n <div className=\"flex items-center gap-2 border-b border-border px-3\">\n <svg\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n aria-hidden=\"true\"\n className=\"size-4 shrink-0 opacity-55\"\n >\n <circle cx=\"11\" cy=\"11\" r=\"7\" stroke=\"currentColor\" strokeWidth=\"2\" />\n <path d=\"m20 20-3.5-3.5\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" />\n </svg>\n <input\n ref={inputRef}\n id={inputId}\n data-slot=\"combobox-input\"\n type=\"text\"\n role=\"combobox\"\n autoComplete=\"off\"\n aria-expanded=\"true\"\n aria-controls={listId}\n aria-autocomplete=\"list\"\n aria-activedescendant={activeValue ? optionId(activeValue) : undefined}\n value={search}\n onChange={(event) => {\n setSearch(event.target.value);\n // The previous active option may have just been filtered out.\n setActiveValue(undefined);\n }}\n onKeyDown={handleKeyDown}\n className={cn(\n \"h-10 w-full bg-transparent text-sm outline-none placeholder:text-muted-foreground\",\n className,\n )}\n {...props}\n />\n </div>\n );\n}\n\nexport function ComboboxList({ className, ...props }: ComponentPropsWithRef<\"div\">) {\n const { listId, listRef } = useCombobox(\"ComboboxList\");\n\n return (\n <div\n ref={listRef}\n id={listId}\n role=\"listbox\"\n data-slot=\"combobox-list\"\n className={cn(\"max-h-64 overflow-y-auto overscroll-contain p-1\", className)}\n {...props}\n />\n );\n}\n\nexport interface ComboboxItemProps extends Omit<\n ComponentPropsWithRef<\"div\">,\n \"onSelect\" | \"children\"\n> {\n /** The value reported by onValueChange, and the primary search term. */\n value: string;\n /** Extra search terms that are not shown, such as synonyms or an id. */\n keywords?: string[];\n disabled?: boolean;\n children?: ReactNode;\n}\n\nexport function ComboboxItem({\n className,\n value,\n keywords,\n disabled,\n children,\n ...props\n}: ComboboxItemProps) {\n const {\n search,\n filter,\n value: selectedValue,\n activeValue,\n setActiveValue,\n select,\n optionId,\n registerVisible,\n } = useCombobox(\"ComboboxItem\");\n\n // A string child is the visible label, so it is searchable for free. Richer\n // children cannot be read purely, so those pass `keywords` instead.\n const haystack = useMemo(\n () => [value, ...(keywords ?? []), typeof children === \"string\" ? children : \"\"],\n [value, keywords, children],\n );\n\n const visible = filter(search, haystack);\n const selected = selectedValue === value;\n const active = activeValue === value;\n\n useEffect(() => {\n registerVisible(value, visible && !disabled);\n return () => {\n registerVisible(value, false);\n };\n }, [registerVisible, value, visible, disabled]);\n\n if (!visible) return null;\n\n return (\n <div\n id={optionId(value)}\n role=\"option\"\n data-slot=\"combobox-item\"\n data-value={value}\n data-active={active || undefined}\n data-disabled={disabled || undefined}\n aria-selected={selected}\n aria-disabled={disabled || undefined}\n // Programmatically focusable but out of the tab order: in an\n // aria-activedescendant listbox the input keeps real focus and options are\n // only virtually focused, so they must never become tab stops.\n tabIndex={-1}\n onPointerMove={() => {\n if (!disabled) setActiveValue(value);\n }}\n onMouseDown={(event) => {\n // Without this, pressing on an option blurs the search input, which\n // breaks aria-activedescendant and can dismiss the popover before the\n // click ever lands.\n event.preventDefault();\n }}\n onClick={() => {\n if (!disabled) select(value);\n }}\n onKeyDown={(event) => {\n // Reachable only if a consumer focuses an option directly; the normal\n // path is Enter on the input, handled by ComboboxInput.\n if (disabled) return;\n if (event.key === \"Enter\" || event.key === \" \") {\n event.preventDefault();\n select(value);\n }\n }}\n className={cn(\n \"relative flex cursor-default items-center gap-2 rounded-md py-1.5 pr-8 pl-2 text-sm outline-none select-none\",\n \"transition-colors duration-[var(--duration-instant)]\",\n \"data-[active]:bg-accent data-[active]:text-accent-foreground\",\n \"data-[disabled]:pointer-events-none data-[disabled]:opacity-55\",\n \"[&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4\",\n className,\n )}\n {...props}\n >\n {children ?? value}\n {selected ? (\n <span className=\"absolute right-2 grid size-4 place-items-center\">\n <svg viewBox=\"0 0 24 24\" fill=\"none\" aria-hidden=\"true\" className=\"size-3.5\">\n <path\n d=\"m5 13 4 4L19 7\"\n stroke=\"currentColor\"\n strokeWidth=\"2.5\"\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n />\n </svg>\n </span>\n ) : null}\n </div>\n );\n}\n\n/** Shown only when the filter leaves nothing. */\nexport function ComboboxEmpty({ className, children, ...props }: ComponentPropsWithRef<\"div\">) {\n const { visibleCount } = useCombobox(\"ComboboxEmpty\");\n if (visibleCount > 0) return null;\n\n return (\n <div\n data-slot=\"combobox-empty\"\n role=\"presentation\"\n className={cn(\"px-3 py-6 text-center text-sm text-muted-foreground\", className)}\n {...props}\n >\n {children ?? \"No results found.\"}\n </div>\n );\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"combobox.js","names":["PopoverPrimitive"],"sources":["../../../src/components/combobox/combobox.tsx"],"sourcesContent":["\"use client\";\n\nimport { Popover as PopoverPrimitive } from \"radix-ui\";\nimport {\n createContext,\n useCallback,\n useContext,\n useEffect,\n useId,\n useMemo,\n useRef,\n useState,\n type ComponentPropsWithRef,\n type KeyboardEvent as ReactKeyboardEvent,\n type ReactNode,\n} from \"react\";\n\nimport { focusRing } from \"@/lib/styles\";\nimport { cn } from \"@/lib/utils\";\n\n/**\n * A searchable single-select.\n *\n * Implements the ARIA combobox pattern directly on a popover rather than\n * depending on a command-menu package: the input owns `role=\"combobox\"`, the\n * list owns `role=\"listbox\"`, and the active option is tracked with\n * `aria-activedescendant` so focus never leaves the input while typing.\n *\n * Navigation reads the rendered options from the DOM rather than a registry,\n * which keeps the active option correct as filtering adds and removes items —\n * a registry has to be kept in sync with what is actually on screen, and drifts.\n *\n * This version is single-select and flat. Multi-select and grouping can be\n * added without changing this API.\n */\n\n/** Default match: case-insensitive substring over the value and any keywords. */\nexport function defaultComboboxFilter(search: string, haystack: string[]): boolean {\n const needle = search.trim().toLowerCase();\n if (!needle) return true;\n return haystack.some((entry) => entry.toLowerCase().includes(needle));\n}\n\ninterface ComboboxContextValue {\n open: boolean;\n setOpen: (open: boolean) => void;\n search: string;\n setSearch: (search: string) => void;\n value: string | undefined;\n select: (value: string) => void;\n activeValue: string | undefined;\n setActiveValue: (value: string | undefined) => void;\n filter: (search: string, haystack: string[]) => boolean;\n listId: string;\n inputId: string;\n optionId: (value: string) => string;\n listRef: React.RefObject<HTMLDivElement | null>;\n registerVisible: (value: string, visible: boolean) => void;\n visibleCount: number;\n}\n\nconst ComboboxContext = createContext<ComboboxContextValue | null>(null);\n\nfunction useCombobox(component: string): ComboboxContextValue {\n const context = useContext(ComboboxContext);\n if (!context) {\n throw new Error(`${component} must be rendered inside <Combobox>.`);\n }\n return context;\n}\n\nexport interface ComboboxProps {\n value?: string;\n defaultValue?: string;\n onValueChange?: (value: string) => void;\n open?: boolean;\n defaultOpen?: boolean;\n onOpenChange?: (open: boolean) => void;\n /** Overrides how a search string is matched against an option. */\n filter?: (search: string, haystack: string[]) => boolean;\n children?: ReactNode;\n}\n\nexport function Combobox({\n value: valueProp,\n defaultValue,\n onValueChange,\n open: openProp,\n defaultOpen = false,\n onOpenChange,\n filter = defaultComboboxFilter,\n children,\n}: ComboboxProps) {\n const uid = useId();\n\n const [uncontrolledValue, setUncontrolledValue] = useState(defaultValue);\n const value = valueProp === undefined ? uncontrolledValue : valueProp;\n\n const [uncontrolledOpen, setUncontrolledOpen] = useState(defaultOpen);\n const open = openProp === undefined ? uncontrolledOpen : openProp;\n\n const [search, setSearch] = useState(\"\");\n const [activeValue, setActiveValue] = useState<string | undefined>(undefined);\n const listRef = useRef<HTMLDivElement | null>(null);\n\n // Counted rather than listed: the empty state only needs to know whether\n // anything survived the filter.\n const visibleValues = useRef(new Set<string>());\n const [visibleCount, setVisibleCount] = useState(0);\n\n const registerVisible = useCallback((optionValue: string, visible: boolean) => {\n const set = visibleValues.current;\n const had = set.has(optionValue);\n if (visible && !had) set.add(optionValue);\n else if (!visible && had) set.delete(optionValue);\n else return;\n setVisibleCount(set.size);\n }, []);\n\n const setOpen = useCallback(\n (next: boolean) => {\n if (openProp === undefined) setUncontrolledOpen(next);\n onOpenChange?.(next);\n // Reopening should start from a clean search rather than resuming a\n // half-typed query the user has forgotten about.\n if (!next) {\n setSearch(\"\");\n setActiveValue(undefined);\n }\n },\n [openProp, onOpenChange],\n );\n\n const select = useCallback(\n (next: string) => {\n if (valueProp === undefined) setUncontrolledValue(next);\n onValueChange?.(next);\n setOpen(false);\n },\n [valueProp, onValueChange, setOpen],\n );\n\n const context = useMemo<ComboboxContextValue>(\n () => ({\n open,\n setOpen,\n search,\n setSearch,\n value,\n select,\n activeValue,\n setActiveValue,\n filter,\n listId: `${uid}-list`,\n inputId: `${uid}-input`,\n optionId: (optionValue: string) =>\n `${uid}-option-${optionValue.replace(/\\s+/g, \"-\").toLowerCase()}`,\n listRef,\n registerVisible,\n visibleCount,\n }),\n [\n open,\n setOpen,\n search,\n value,\n select,\n activeValue,\n filter,\n uid,\n registerVisible,\n visibleCount,\n ],\n );\n\n return (\n <ComboboxContext.Provider value={context}>\n <PopoverPrimitive.Root open={open} onOpenChange={setOpen}>\n {children}\n </PopoverPrimitive.Root>\n </ComboboxContext.Provider>\n );\n}\n\nexport interface ComboboxTriggerProps extends ComponentPropsWithRef<\"button\"> {\n /** Shown when nothing is selected. */\n placeholder?: string;\n}\n\nexport function ComboboxTrigger({\n className,\n placeholder = \"Select…\",\n children,\n ...props\n}: ComboboxTriggerProps) {\n const { value, open } = useCombobox(\"ComboboxTrigger\");\n\n return (\n <PopoverPrimitive.Trigger asChild>\n <button\n type=\"button\"\n data-slot=\"combobox-trigger\"\n aria-expanded={open}\n className={cn(\n \"flex h-9 w-full items-center justify-between gap-2 rounded-md border border-input bg-background\",\n \"px-3 text-sm shadow-xs transition-[border-color,box-shadow] duration-[var(--duration-fast)]\",\n \"focus-visible:border-ring\",\n \"disabled:cursor-not-allowed disabled:opacity-55\",\n \"aria-invalid:border-destructive\",\n focusRing,\n className,\n )}\n {...props}\n >\n <span className={cn(\"truncate\", !value && \"text-muted-foreground\")}>\n {children ?? value ?? placeholder}\n </span>\n <svg\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n aria-hidden=\"true\"\n className=\"size-4 shrink-0 opacity-60\"\n >\n <path\n d=\"m7 10 5 5 5-5\"\n stroke=\"currentColor\"\n strokeWidth=\"2\"\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n />\n </svg>\n </button>\n </PopoverPrimitive.Trigger>\n );\n}\n\nexport interface ComboboxContentProps extends ComponentPropsWithRef<\n typeof PopoverPrimitive.Content\n> {\n /** Names the popover, which carries role=\"dialog\". */\n label?: string;\n}\n\nexport function ComboboxContent({\n className,\n align = \"start\",\n sideOffset = 6,\n label = \"Search options\",\n children,\n ...props\n}: ComboboxContentProps) {\n return (\n <PopoverPrimitive.Portal>\n <PopoverPrimitive.Content\n data-slot=\"combobox-content\"\n align={align}\n sideOffset={sideOffset}\n aria-label={label}\n // Focus belongs in the search input, which the input claims on mount.\n onOpenAutoFocus={(event) => {\n event.preventDefault();\n }}\n className={cn(\n \"z-[var(--z-popover)] w-[var(--radix-popover-trigger-width)] min-w-48 overflow-hidden\",\n \"rounded-lg border border-border bg-popover p-0 text-popover-foreground shadow-lg\",\n \"origin-[var(--radix-popover-content-transform-origin)]\",\n \"data-[state=closed]:animate-float-out data-[state=open]:animate-float-in\",\n className,\n )}\n {...props}\n >\n {children}\n </PopoverPrimitive.Content>\n </PopoverPrimitive.Portal>\n );\n}\n\n/** Options currently rendered, in DOM order and excluding disabled ones. */\nfunction visibleOptions(list: HTMLElement | null): HTMLElement[] {\n if (!list) return [];\n return Array.from(list.querySelectorAll<HTMLElement>('[role=\"option\"]:not([data-disabled])'));\n}\n\nexport type ComboboxInputProps = Omit<ComponentPropsWithRef<\"input\">, \"value\" | \"onChange\">;\n\nexport function ComboboxInput({ className, ...props }: ComboboxInputProps) {\n const {\n search,\n setSearch,\n activeValue,\n setActiveValue,\n select,\n setOpen,\n listId,\n inputId,\n optionId,\n listRef,\n } = useCombobox(\"ComboboxInput\");\n\n const inputRef = useRef<HTMLInputElement | null>(null);\n\n useEffect(() => {\n inputRef.current?.focus();\n }, []);\n\n const move = useCallback(\n (delta: number | \"first\" | \"last\") => {\n const options = visibleOptions(listRef.current);\n if (options.length === 0) return;\n\n const currentIndex = options.findIndex((option) => option.dataset.value === activeValue);\n\n let nextIndex: number;\n if (delta === \"first\") nextIndex = 0;\n else if (delta === \"last\") nextIndex = options.length - 1;\n else if (currentIndex === -1) nextIndex = delta > 0 ? 0 : options.length - 1;\n // Wraps, so holding an arrow key never dead-ends at the edge of the list.\n else nextIndex = (currentIndex + delta + options.length) % options.length;\n\n const next = options[nextIndex];\n if (!next) return;\n setActiveValue(next.dataset.value);\n next.scrollIntoView({ block: \"nearest\" });\n },\n [activeValue, listRef, setActiveValue],\n );\n\n function handleKeyDown(event: ReactKeyboardEvent<HTMLInputElement>) {\n switch (event.key) {\n case \"ArrowDown\":\n event.preventDefault();\n move(1);\n break;\n case \"ArrowUp\":\n event.preventDefault();\n move(-1);\n break;\n case \"Home\":\n event.preventDefault();\n move(\"first\");\n break;\n case \"End\":\n event.preventDefault();\n move(\"last\");\n break;\n case \"Enter\": {\n if (activeValue === undefined) return;\n event.preventDefault();\n select(activeValue);\n break;\n }\n case \"Escape\":\n event.preventDefault();\n setOpen(false);\n break;\n default:\n break;\n }\n }\n\n return (\n <div className=\"flex items-center gap-2 border-b border-border px-3\">\n <svg\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n aria-hidden=\"true\"\n className=\"size-4 shrink-0 opacity-55\"\n >\n <circle cx=\"11\" cy=\"11\" r=\"7\" stroke=\"currentColor\" strokeWidth=\"2\" />\n <path d=\"m20 20-3.5-3.5\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" />\n </svg>\n <input\n ref={inputRef}\n id={inputId}\n data-slot=\"combobox-input\"\n type=\"text\"\n role=\"combobox\"\n autoComplete=\"off\"\n aria-expanded=\"true\"\n aria-controls={listId}\n aria-autocomplete=\"list\"\n aria-activedescendant={activeValue ? optionId(activeValue) : undefined}\n value={search}\n onChange={(event) => {\n setSearch(event.target.value);\n // The previous active option may have just been filtered out.\n setActiveValue(undefined);\n }}\n onKeyDown={handleKeyDown}\n className={cn(\n \"h-10 w-full bg-transparent text-sm outline-none placeholder:text-muted-foreground\",\n className,\n )}\n {...props}\n />\n </div>\n );\n}\n\nexport function ComboboxList({ className, ...props }: ComponentPropsWithRef<\"div\">) {\n const { listId, listRef } = useCombobox(\"ComboboxList\");\n\n return (\n <div\n ref={listRef}\n id={listId}\n role=\"listbox\"\n data-slot=\"combobox-list\"\n className={cn(\"max-h-64 overflow-y-auto overscroll-contain p-1\", className)}\n {...props}\n />\n );\n}\n\nexport interface ComboboxItemProps extends Omit<\n ComponentPropsWithRef<\"div\">,\n \"onSelect\" | \"children\"\n> {\n /** The value reported by onValueChange, and the primary search term. */\n value: string;\n /** Extra search terms that are not shown, such as synonyms or an id. */\n keywords?: string[];\n disabled?: boolean;\n children?: ReactNode;\n}\n\nexport function ComboboxItem({\n className,\n value,\n keywords,\n disabled,\n children,\n ...props\n}: ComboboxItemProps) {\n const {\n search,\n filter,\n value: selectedValue,\n activeValue,\n setActiveValue,\n select,\n optionId,\n registerVisible,\n } = useCombobox(\"ComboboxItem\");\n\n // A string child is the visible label, so it is searchable for free. Richer\n // children cannot be read purely, so those pass `keywords` instead.\n const haystack = useMemo(\n () => [value, ...(keywords ?? []), typeof children === \"string\" ? children : \"\"],\n [value, keywords, children],\n );\n\n const visible = filter(search, haystack);\n const selected = selectedValue === value;\n const active = activeValue === value;\n\n useEffect(() => {\n registerVisible(value, visible && !disabled);\n return () => {\n registerVisible(value, false);\n };\n }, [registerVisible, value, visible, disabled]);\n\n if (!visible) return null;\n\n return (\n <div\n id={optionId(value)}\n role=\"option\"\n data-slot=\"combobox-item\"\n data-value={value}\n data-active={active || undefined}\n data-disabled={disabled || undefined}\n aria-selected={selected}\n aria-disabled={disabled || undefined}\n // Programmatically focusable but out of the tab order: in an\n // aria-activedescendant listbox the input keeps real focus and options are\n // only virtually focused, so they must never become tab stops.\n tabIndex={-1}\n onPointerMove={() => {\n if (!disabled) setActiveValue(value);\n }}\n onMouseDown={(event) => {\n // Without this, pressing on an option blurs the search input, which\n // breaks aria-activedescendant and can dismiss the popover before the\n // click ever lands.\n event.preventDefault();\n }}\n onClick={() => {\n if (!disabled) select(value);\n }}\n onKeyDown={(event) => {\n // Reachable only if a consumer focuses an option directly; the normal\n // path is Enter on the input, handled by ComboboxInput.\n if (disabled) return;\n if (event.key === \"Enter\" || event.key === \" \") {\n event.preventDefault();\n select(value);\n }\n }}\n className={cn(\n \"relative flex cursor-default items-center gap-2 rounded-md py-1.5 ps-2 pe-8 text-sm outline-none select-none\",\n \"transition-colors duration-[var(--duration-instant)]\",\n \"data-[active]:bg-accent data-[active]:text-accent-foreground\",\n \"data-[disabled]:pointer-events-none data-[disabled]:opacity-55\",\n \"[&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4\",\n className,\n )}\n {...props}\n >\n {children ?? value}\n {selected ? (\n <span className=\"absolute end-2 grid size-4 place-items-center\">\n <svg viewBox=\"0 0 24 24\" fill=\"none\" aria-hidden=\"true\" className=\"size-3.5\">\n <path\n d=\"m5 13 4 4L19 7\"\n stroke=\"currentColor\"\n strokeWidth=\"2.5\"\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n />\n </svg>\n </span>\n ) : null}\n </div>\n );\n}\n\n/** Shown only when the filter leaves nothing. */\nexport function ComboboxEmpty({ className, children, ...props }: ComponentPropsWithRef<\"div\">) {\n const { visibleCount } = useCombobox(\"ComboboxEmpty\");\n if (visibleCount > 0) return null;\n\n return (\n <div\n data-slot=\"combobox-empty\"\n role=\"presentation\"\n className={cn(\"px-3 py-6 text-center text-sm text-muted-foreground\", className)}\n {...props}\n >\n {children ?? \"No results found.\"}\n </div>\n );\n}\n"],"mappings":"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"}
|
|
@@ -297,7 +297,7 @@ function CommandShortcut({ className, ...props }) {
|
|
|
297
297
|
return /* @__PURE__ */ jsx("span", {
|
|
298
298
|
"data-slot": "command-shortcut",
|
|
299
299
|
"aria-hidden": "true",
|
|
300
|
-
className: cn("
|
|
300
|
+
className: cn("ms-auto text-2xs tracking-wide text-muted-foreground", className),
|
|
301
301
|
...props
|
|
302
302
|
});
|
|
303
303
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"command.js","names":[],"sources":["../../../src/components/command/command.tsx"],"sourcesContent":["\"use client\";\n\nimport {\n createContext,\n useCallback,\n useContext,\n useEffect,\n useId,\n useMemo,\n useRef,\n useState,\n type ComponentPropsWithRef,\n type KeyboardEvent as ReactKeyboardEvent,\n type ReactNode,\n} from \"react\";\n\nimport {\n Dialog,\n DialogContent,\n DialogDescription,\n DialogHeader,\n DialogTitle,\n} from \"@/components/dialog\";\nimport { cn } from \"@/lib/utils\";\n\n/**\n * A searchable list of commands.\n *\n * Shares its navigation model with Combobox — the input owns `role=\"combobox\"`,\n * the list owns `role=\"listbox\"`, and the active item is tracked with\n * `aria-activedescendant` so focus never leaves the input. Ordering is read\n * from the DOM rather than a registry, which stays correct as filtering adds\n * and removes items.\n *\n * Unlike Combobox this has no selected value: items run actions. It also\n * supports groups, and a group whose items have all been filtered out hides its\n * own heading rather than leaving a label over nothing.\n */\n\n/** Default match: case-insensitive substring over the value and any keywords. */\nexport function defaultCommandFilter(search: string, haystack: string[]): boolean {\n const needle = search.trim().toLowerCase();\n if (!needle) return true;\n return haystack.some((entry) => entry.toLowerCase().includes(needle));\n}\n\ninterface CommandContextValue {\n search: string;\n setSearch: (search: string) => void;\n activeValue: string | undefined;\n setActiveValue: (value: string | undefined) => void;\n filter: (search: string, haystack: string[]) => boolean;\n listId: string;\n inputId: string;\n optionId: (value: string) => string;\n listRef: React.RefObject<HTMLDivElement | null>;\n registerVisible: (value: string, visible: boolean) => void;\n visibleCount: number;\n}\n\nconst CommandContext = createContext<CommandContextValue | null>(null);\n\nfunction useCommand(component: string): CommandContextValue {\n const context = useContext(CommandContext);\n if (!context) {\n throw new Error(`${component} must be rendered inside <Command>.`);\n }\n return context;\n}\n\n/** Lets a group count how many of its own items survived the filter. */\nconst CommandGroupContext = createContext<((value: string, visible: boolean) => void) | null>(\n null,\n);\n\n/** Counts visible entries by name, so re-registration cannot double-count. */\nfunction useVisibilityCounter() {\n const visible = useRef(new Set<string>());\n const [count, setCount] = useState(0);\n\n const register = useCallback((value: string, isVisible: boolean) => {\n const set = visible.current;\n const had = set.has(value);\n if (isVisible && !had) set.add(value);\n else if (!isVisible && had) set.delete(value);\n else return;\n setCount(set.size);\n }, []);\n\n return { count, register };\n}\n\nexport interface CommandProps extends Omit<ComponentPropsWithRef<\"div\">, \"onSelect\"> {\n /** Overrides how a search string is matched against an item. */\n filter?: (search: string, haystack: string[]) => boolean;\n /** Controls the search text. */\n value?: string;\n onValueChange?: (search: string) => void;\n}\n\nexport function Command({\n className,\n filter = defaultCommandFilter,\n value,\n onValueChange,\n ...props\n}: CommandProps) {\n const uid = useId();\n const [uncontrolledSearch, setUncontrolledSearch] = useState(\"\");\n const search = value ?? uncontrolledSearch;\n const [activeValue, setActiveValue] = useState<string | undefined>(undefined);\n const listRef = useRef<HTMLDivElement | null>(null);\n const { count, register } = useVisibilityCounter();\n\n const setSearch = useCallback(\n (next: string) => {\n if (value === undefined) setUncontrolledSearch(next);\n onValueChange?.(next);\n },\n [value, onValueChange],\n );\n\n const context = useMemo<CommandContextValue>(\n () => ({\n search,\n setSearch,\n activeValue,\n setActiveValue,\n filter,\n listId: `${uid}-list`,\n inputId: `${uid}-input`,\n optionId: (itemValue: string) =>\n `${uid}-item-${itemValue.replace(/\\s+/g, \"-\").toLowerCase()}`,\n listRef,\n registerVisible: register,\n visibleCount: count,\n }),\n [search, setSearch, activeValue, filter, uid, register, count],\n );\n\n return (\n <CommandContext.Provider value={context}>\n <div\n data-slot=\"command\"\n className={cn(\n \"flex size-full flex-col overflow-hidden rounded-lg bg-popover text-popover-foreground\",\n className,\n )}\n {...props}\n />\n </CommandContext.Provider>\n );\n}\n\n/** Items currently rendered, in DOM order and excluding disabled ones. */\nfunction visibleItems(list: HTMLElement | null): HTMLElement[] {\n if (!list) return [];\n return Array.from(list.querySelectorAll<HTMLElement>('[role=\"option\"]:not([data-disabled])'));\n}\n\nexport type CommandInputProps = Omit<ComponentPropsWithRef<\"input\">, \"value\" | \"onChange\">;\n\nexport function CommandInput({ className, ...props }: CommandInputProps) {\n const { search, setSearch, activeValue, setActiveValue, listId, inputId, optionId, listRef } =\n useCommand(\"CommandInput\");\n\n const inputRef = useRef<HTMLInputElement | null>(null);\n\n useEffect(() => {\n inputRef.current?.focus();\n }, []);\n\n const move = useCallback(\n (delta: number | \"first\" | \"last\") => {\n const items = visibleItems(listRef.current);\n if (items.length === 0) return;\n\n const currentIndex = items.findIndex((item) => item.dataset.value === activeValue);\n\n let nextIndex: number;\n if (delta === \"first\") nextIndex = 0;\n else if (delta === \"last\") nextIndex = items.length - 1;\n else if (currentIndex === -1) nextIndex = delta > 0 ? 0 : items.length - 1;\n else nextIndex = (currentIndex + delta + items.length) % items.length;\n\n const next = items[nextIndex];\n if (!next) return;\n setActiveValue(next.dataset.value);\n next.scrollIntoView({ block: \"nearest\" });\n },\n [activeValue, listRef, setActiveValue],\n );\n\n function handleKeyDown(event: ReactKeyboardEvent<HTMLInputElement>) {\n switch (event.key) {\n case \"ArrowDown\":\n event.preventDefault();\n move(1);\n break;\n case \"ArrowUp\":\n event.preventDefault();\n move(-1);\n break;\n case \"Home\":\n event.preventDefault();\n move(\"first\");\n break;\n case \"End\":\n event.preventDefault();\n move(\"last\");\n break;\n case \"Enter\": {\n if (activeValue === undefined) return;\n event.preventDefault();\n // Running the item by clicking it keeps one code path for pointer and\n // keyboard, so the two can never drift apart.\n const item = visibleItems(listRef.current).find(\n (candidate) => candidate.dataset.value === activeValue,\n );\n item?.click();\n break;\n }\n default:\n break;\n }\n }\n\n return (\n <div className=\"flex items-center gap-2 border-b border-border px-3\">\n <svg\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n aria-hidden=\"true\"\n className=\"size-4 shrink-0 opacity-55\"\n >\n <circle cx=\"11\" cy=\"11\" r=\"7\" stroke=\"currentColor\" strokeWidth=\"2\" />\n <path d=\"m20 20-3.5-3.5\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" />\n </svg>\n <input\n ref={inputRef}\n id={inputId}\n data-slot=\"command-input\"\n type=\"text\"\n role=\"combobox\"\n autoComplete=\"off\"\n aria-expanded=\"true\"\n aria-controls={listId}\n aria-autocomplete=\"list\"\n aria-activedescendant={activeValue ? optionId(activeValue) : undefined}\n value={search}\n onChange={(event) => {\n setSearch(event.target.value);\n // The active item may have just been filtered away.\n setActiveValue(undefined);\n }}\n onKeyDown={handleKeyDown}\n className={cn(\n \"h-11 w-full bg-transparent text-sm outline-none placeholder:text-muted-foreground\",\n className,\n )}\n {...props}\n />\n </div>\n );\n}\n\nexport function CommandList({ className, ...props }: ComponentPropsWithRef<\"div\">) {\n const { listId, listRef } = useCommand(\"CommandList\");\n\n return (\n <div\n ref={listRef}\n id={listId}\n role=\"listbox\"\n data-slot=\"command-list\"\n className={cn(\"max-h-80 overflow-y-auto overscroll-contain p-1\", className)}\n {...props}\n />\n );\n}\n\nexport function CommandEmpty({ className, children, ...props }: ComponentPropsWithRef<\"div\">) {\n const { visibleCount } = useCommand(\"CommandEmpty\");\n if (visibleCount > 0) return null;\n\n return (\n <div\n data-slot=\"command-empty\"\n role=\"presentation\"\n className={cn(\"px-3 py-8 text-center text-sm text-muted-foreground\", className)}\n {...props}\n >\n {children ?? \"No results found.\"}\n </div>\n );\n}\n\nexport interface CommandGroupProps extends ComponentPropsWithRef<\"div\"> {\n heading?: ReactNode;\n}\n\nexport function CommandGroup({ className, heading, children, ...props }: CommandGroupProps) {\n const uid = useId();\n const { count, register } = useVisibilityCounter();\n const empty = count === 0;\n\n return (\n <div\n data-slot=\"command-group\"\n role=\"group\"\n aria-labelledby={heading && !empty ? `${uid}-heading` : undefined}\n // Hidden rather than unmounted: the items inside are what report whether\n // anything matched, and unmounting them would stop the reports and leave\n // the group permanently empty.\n hidden={empty || undefined}\n className={cn(\"py-1 first:pt-0\", className)}\n {...props}\n >\n {heading && !empty ? (\n <div\n id={`${uid}-heading`}\n className=\"px-2 py-1.5 text-xs font-medium text-muted-foreground\"\n >\n {heading}\n </div>\n ) : null}\n <CommandGroupContext.Provider value={register}>{children}</CommandGroupContext.Provider>\n </div>\n );\n}\n\nexport interface CommandItemProps extends Omit<\n ComponentPropsWithRef<\"div\">,\n \"onSelect\" | \"children\"\n> {\n /** Identifies the item, and is the primary search term. */\n value: string;\n /** Extra search terms that are not shown. */\n keywords?: string[];\n disabled?: boolean;\n onSelect?: (value: string) => void;\n children?: ReactNode;\n}\n\nexport function CommandItem({\n className,\n value,\n keywords,\n disabled,\n onSelect,\n children,\n ...props\n}: CommandItemProps) {\n const { search, filter, activeValue, setActiveValue, optionId, registerVisible } =\n useCommand(\"CommandItem\");\n const registerInGroup = useContext(CommandGroupContext);\n\n const haystack = useMemo(\n () => [value, ...(keywords ?? []), typeof children === \"string\" ? children : \"\"],\n [value, keywords, children],\n );\n\n const visible = filter(search, haystack);\n const active = activeValue === value;\n const counts = visible && !disabled;\n\n useEffect(() => {\n registerVisible(value, counts);\n registerInGroup?.(value, counts);\n return () => {\n registerVisible(value, false);\n registerInGroup?.(value, false);\n };\n }, [registerVisible, registerInGroup, value, counts]);\n\n if (!visible) return null;\n\n return (\n <div\n id={optionId(value)}\n role=\"option\"\n data-slot=\"command-item\"\n data-value={value}\n data-active={active || undefined}\n data-disabled={disabled || undefined}\n aria-selected={active}\n aria-disabled={disabled || undefined}\n // Programmatically focusable but never a tab stop: the input keeps focus\n // and items are only virtually focused via aria-activedescendant.\n tabIndex={-1}\n onPointerMove={() => {\n if (!disabled) setActiveValue(value);\n }}\n onMouseDown={(event) => {\n // Keeps focus in the input, so aria-activedescendant stays valid and a\n // hosting dialog does not close before the click lands.\n event.preventDefault();\n }}\n onClick={() => {\n if (!disabled) onSelect?.(value);\n }}\n onKeyDown={(event) => {\n if (disabled) return;\n if (event.key === \"Enter\" || event.key === \" \") {\n event.preventDefault();\n onSelect?.(value);\n }\n }}\n className={cn(\n \"relative flex cursor-default items-center gap-2 rounded-md px-2 py-2 text-sm outline-none select-none\",\n \"transition-colors duration-[var(--duration-instant)]\",\n \"data-[active]:bg-accent data-[active]:text-accent-foreground\",\n \"data-[disabled]:pointer-events-none data-[disabled]:opacity-55\",\n \"[&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4\",\n className,\n )}\n {...props}\n >\n {children ?? value}\n </div>\n );\n}\n\nexport function CommandSeparator({ className, ...props }: ComponentPropsWithRef<\"div\">) {\n return (\n <div\n data-slot=\"command-separator\"\n aria-hidden=\"true\"\n className={cn(\"-mx-1 my-1 h-px bg-border\", className)}\n {...props}\n />\n );\n}\n\n/** Keyboard hint. Decorative — bind the shortcut for real at the app level. */\nexport function CommandShortcut({ className, ...props }: ComponentPropsWithRef<\"span\">) {\n return (\n <span\n data-slot=\"command-shortcut\"\n aria-hidden=\"true\"\n className={cn(\"ml-auto text-2xs tracking-wide text-muted-foreground\", className)}\n {...props}\n />\n );\n}\n\nexport interface CommandDialogProps extends ComponentPropsWithRef<typeof Dialog> {\n /** Names the dialog for assistive technology. Visually hidden by default. */\n title?: string;\n description?: string;\n className?: string;\n}\n\n/**\n * The palette in a modal, for the ⌘K pattern.\n *\n * The title and description are rendered but visually hidden: a dialog needs an\n * accessible name whether or not the design shows one, and leaving it out is\n * the most common defect in hand-rolled command menus.\n */\nexport function CommandDialog({\n title = \"Command palette\",\n description = \"Search for a command to run.\",\n children,\n className,\n ...props\n}: CommandDialogProps) {\n return (\n <Dialog {...props}>\n <DialogContent\n showCloseButton={false}\n className={cn(\"max-w-lg overflow-hidden p-0\", className)}\n >\n <DialogHeader className=\"sr-only\">\n <DialogTitle>{title}</DialogTitle>\n <DialogDescription>{description}</DialogDescription>\n </DialogHeader>\n <Command className=\"rounded-none\">{children}</Command>\n </DialogContent>\n </Dialog>\n );\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"command.js","names":[],"sources":["../../../src/components/command/command.tsx"],"sourcesContent":["\"use client\";\n\nimport {\n createContext,\n useCallback,\n useContext,\n useEffect,\n useId,\n useMemo,\n useRef,\n useState,\n type ComponentPropsWithRef,\n type KeyboardEvent as ReactKeyboardEvent,\n type ReactNode,\n} from \"react\";\n\nimport {\n Dialog,\n DialogContent,\n DialogDescription,\n DialogHeader,\n DialogTitle,\n} from \"@/components/dialog\";\nimport { cn } from \"@/lib/utils\";\n\n/**\n * A searchable list of commands.\n *\n * Shares its navigation model with Combobox — the input owns `role=\"combobox\"`,\n * the list owns `role=\"listbox\"`, and the active item is tracked with\n * `aria-activedescendant` so focus never leaves the input. Ordering is read\n * from the DOM rather than a registry, which stays correct as filtering adds\n * and removes items.\n *\n * Unlike Combobox this has no selected value: items run actions. It also\n * supports groups, and a group whose items have all been filtered out hides its\n * own heading rather than leaving a label over nothing.\n */\n\n/** Default match: case-insensitive substring over the value and any keywords. */\nexport function defaultCommandFilter(search: string, haystack: string[]): boolean {\n const needle = search.trim().toLowerCase();\n if (!needle) return true;\n return haystack.some((entry) => entry.toLowerCase().includes(needle));\n}\n\ninterface CommandContextValue {\n search: string;\n setSearch: (search: string) => void;\n activeValue: string | undefined;\n setActiveValue: (value: string | undefined) => void;\n filter: (search: string, haystack: string[]) => boolean;\n listId: string;\n inputId: string;\n optionId: (value: string) => string;\n listRef: React.RefObject<HTMLDivElement | null>;\n registerVisible: (value: string, visible: boolean) => void;\n visibleCount: number;\n}\n\nconst CommandContext = createContext<CommandContextValue | null>(null);\n\nfunction useCommand(component: string): CommandContextValue {\n const context = useContext(CommandContext);\n if (!context) {\n throw new Error(`${component} must be rendered inside <Command>.`);\n }\n return context;\n}\n\n/** Lets a group count how many of its own items survived the filter. */\nconst CommandGroupContext = createContext<((value: string, visible: boolean) => void) | null>(\n null,\n);\n\n/** Counts visible entries by name, so re-registration cannot double-count. */\nfunction useVisibilityCounter() {\n const visible = useRef(new Set<string>());\n const [count, setCount] = useState(0);\n\n const register = useCallback((value: string, isVisible: boolean) => {\n const set = visible.current;\n const had = set.has(value);\n if (isVisible && !had) set.add(value);\n else if (!isVisible && had) set.delete(value);\n else return;\n setCount(set.size);\n }, []);\n\n return { count, register };\n}\n\nexport interface CommandProps extends Omit<ComponentPropsWithRef<\"div\">, \"onSelect\"> {\n /** Overrides how a search string is matched against an item. */\n filter?: (search: string, haystack: string[]) => boolean;\n /** Controls the search text. */\n value?: string;\n onValueChange?: (search: string) => void;\n}\n\nexport function Command({\n className,\n filter = defaultCommandFilter,\n value,\n onValueChange,\n ...props\n}: CommandProps) {\n const uid = useId();\n const [uncontrolledSearch, setUncontrolledSearch] = useState(\"\");\n const search = value ?? uncontrolledSearch;\n const [activeValue, setActiveValue] = useState<string | undefined>(undefined);\n const listRef = useRef<HTMLDivElement | null>(null);\n const { count, register } = useVisibilityCounter();\n\n const setSearch = useCallback(\n (next: string) => {\n if (value === undefined) setUncontrolledSearch(next);\n onValueChange?.(next);\n },\n [value, onValueChange],\n );\n\n const context = useMemo<CommandContextValue>(\n () => ({\n search,\n setSearch,\n activeValue,\n setActiveValue,\n filter,\n listId: `${uid}-list`,\n inputId: `${uid}-input`,\n optionId: (itemValue: string) =>\n `${uid}-item-${itemValue.replace(/\\s+/g, \"-\").toLowerCase()}`,\n listRef,\n registerVisible: register,\n visibleCount: count,\n }),\n [search, setSearch, activeValue, filter, uid, register, count],\n );\n\n return (\n <CommandContext.Provider value={context}>\n <div\n data-slot=\"command\"\n className={cn(\n \"flex size-full flex-col overflow-hidden rounded-lg bg-popover text-popover-foreground\",\n className,\n )}\n {...props}\n />\n </CommandContext.Provider>\n );\n}\n\n/** Items currently rendered, in DOM order and excluding disabled ones. */\nfunction visibleItems(list: HTMLElement | null): HTMLElement[] {\n if (!list) return [];\n return Array.from(list.querySelectorAll<HTMLElement>('[role=\"option\"]:not([data-disabled])'));\n}\n\nexport type CommandInputProps = Omit<ComponentPropsWithRef<\"input\">, \"value\" | \"onChange\">;\n\nexport function CommandInput({ className, ...props }: CommandInputProps) {\n const { search, setSearch, activeValue, setActiveValue, listId, inputId, optionId, listRef } =\n useCommand(\"CommandInput\");\n\n const inputRef = useRef<HTMLInputElement | null>(null);\n\n useEffect(() => {\n inputRef.current?.focus();\n }, []);\n\n const move = useCallback(\n (delta: number | \"first\" | \"last\") => {\n const items = visibleItems(listRef.current);\n if (items.length === 0) return;\n\n const currentIndex = items.findIndex((item) => item.dataset.value === activeValue);\n\n let nextIndex: number;\n if (delta === \"first\") nextIndex = 0;\n else if (delta === \"last\") nextIndex = items.length - 1;\n else if (currentIndex === -1) nextIndex = delta > 0 ? 0 : items.length - 1;\n else nextIndex = (currentIndex + delta + items.length) % items.length;\n\n const next = items[nextIndex];\n if (!next) return;\n setActiveValue(next.dataset.value);\n next.scrollIntoView({ block: \"nearest\" });\n },\n [activeValue, listRef, setActiveValue],\n );\n\n function handleKeyDown(event: ReactKeyboardEvent<HTMLInputElement>) {\n switch (event.key) {\n case \"ArrowDown\":\n event.preventDefault();\n move(1);\n break;\n case \"ArrowUp\":\n event.preventDefault();\n move(-1);\n break;\n case \"Home\":\n event.preventDefault();\n move(\"first\");\n break;\n case \"End\":\n event.preventDefault();\n move(\"last\");\n break;\n case \"Enter\": {\n if (activeValue === undefined) return;\n event.preventDefault();\n // Running the item by clicking it keeps one code path for pointer and\n // keyboard, so the two can never drift apart.\n const item = visibleItems(listRef.current).find(\n (candidate) => candidate.dataset.value === activeValue,\n );\n item?.click();\n break;\n }\n default:\n break;\n }\n }\n\n return (\n <div className=\"flex items-center gap-2 border-b border-border px-3\">\n <svg\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n aria-hidden=\"true\"\n className=\"size-4 shrink-0 opacity-55\"\n >\n <circle cx=\"11\" cy=\"11\" r=\"7\" stroke=\"currentColor\" strokeWidth=\"2\" />\n <path d=\"m20 20-3.5-3.5\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" />\n </svg>\n <input\n ref={inputRef}\n id={inputId}\n data-slot=\"command-input\"\n type=\"text\"\n role=\"combobox\"\n autoComplete=\"off\"\n aria-expanded=\"true\"\n aria-controls={listId}\n aria-autocomplete=\"list\"\n aria-activedescendant={activeValue ? optionId(activeValue) : undefined}\n value={search}\n onChange={(event) => {\n setSearch(event.target.value);\n // The active item may have just been filtered away.\n setActiveValue(undefined);\n }}\n onKeyDown={handleKeyDown}\n className={cn(\n \"h-11 w-full bg-transparent text-sm outline-none placeholder:text-muted-foreground\",\n className,\n )}\n {...props}\n />\n </div>\n );\n}\n\nexport function CommandList({ className, ...props }: ComponentPropsWithRef<\"div\">) {\n const { listId, listRef } = useCommand(\"CommandList\");\n\n return (\n <div\n ref={listRef}\n id={listId}\n role=\"listbox\"\n data-slot=\"command-list\"\n className={cn(\"max-h-80 overflow-y-auto overscroll-contain p-1\", className)}\n {...props}\n />\n );\n}\n\nexport function CommandEmpty({ className, children, ...props }: ComponentPropsWithRef<\"div\">) {\n const { visibleCount } = useCommand(\"CommandEmpty\");\n if (visibleCount > 0) return null;\n\n return (\n <div\n data-slot=\"command-empty\"\n role=\"presentation\"\n className={cn(\"px-3 py-8 text-center text-sm text-muted-foreground\", className)}\n {...props}\n >\n {children ?? \"No results found.\"}\n </div>\n );\n}\n\nexport interface CommandGroupProps extends ComponentPropsWithRef<\"div\"> {\n heading?: ReactNode;\n}\n\nexport function CommandGroup({ className, heading, children, ...props }: CommandGroupProps) {\n const uid = useId();\n const { count, register } = useVisibilityCounter();\n const empty = count === 0;\n\n return (\n <div\n data-slot=\"command-group\"\n role=\"group\"\n aria-labelledby={heading && !empty ? `${uid}-heading` : undefined}\n // Hidden rather than unmounted: the items inside are what report whether\n // anything matched, and unmounting them would stop the reports and leave\n // the group permanently empty.\n hidden={empty || undefined}\n className={cn(\"py-1 first:pt-0\", className)}\n {...props}\n >\n {heading && !empty ? (\n <div\n id={`${uid}-heading`}\n className=\"px-2 py-1.5 text-xs font-medium text-muted-foreground\"\n >\n {heading}\n </div>\n ) : null}\n <CommandGroupContext.Provider value={register}>{children}</CommandGroupContext.Provider>\n </div>\n );\n}\n\nexport interface CommandItemProps extends Omit<\n ComponentPropsWithRef<\"div\">,\n \"onSelect\" | \"children\"\n> {\n /** Identifies the item, and is the primary search term. */\n value: string;\n /** Extra search terms that are not shown. */\n keywords?: string[];\n disabled?: boolean;\n onSelect?: (value: string) => void;\n children?: ReactNode;\n}\n\nexport function CommandItem({\n className,\n value,\n keywords,\n disabled,\n onSelect,\n children,\n ...props\n}: CommandItemProps) {\n const { search, filter, activeValue, setActiveValue, optionId, registerVisible } =\n useCommand(\"CommandItem\");\n const registerInGroup = useContext(CommandGroupContext);\n\n const haystack = useMemo(\n () => [value, ...(keywords ?? []), typeof children === \"string\" ? children : \"\"],\n [value, keywords, children],\n );\n\n const visible = filter(search, haystack);\n const active = activeValue === value;\n const counts = visible && !disabled;\n\n useEffect(() => {\n registerVisible(value, counts);\n registerInGroup?.(value, counts);\n return () => {\n registerVisible(value, false);\n registerInGroup?.(value, false);\n };\n }, [registerVisible, registerInGroup, value, counts]);\n\n if (!visible) return null;\n\n return (\n <div\n id={optionId(value)}\n role=\"option\"\n data-slot=\"command-item\"\n data-value={value}\n data-active={active || undefined}\n data-disabled={disabled || undefined}\n aria-selected={active}\n aria-disabled={disabled || undefined}\n // Programmatically focusable but never a tab stop: the input keeps focus\n // and items are only virtually focused via aria-activedescendant.\n tabIndex={-1}\n onPointerMove={() => {\n if (!disabled) setActiveValue(value);\n }}\n onMouseDown={(event) => {\n // Keeps focus in the input, so aria-activedescendant stays valid and a\n // hosting dialog does not close before the click lands.\n event.preventDefault();\n }}\n onClick={() => {\n if (!disabled) onSelect?.(value);\n }}\n onKeyDown={(event) => {\n if (disabled) return;\n if (event.key === \"Enter\" || event.key === \" \") {\n event.preventDefault();\n onSelect?.(value);\n }\n }}\n className={cn(\n \"relative flex cursor-default items-center gap-2 rounded-md px-2 py-2 text-sm outline-none select-none\",\n \"transition-colors duration-[var(--duration-instant)]\",\n \"data-[active]:bg-accent data-[active]:text-accent-foreground\",\n \"data-[disabled]:pointer-events-none data-[disabled]:opacity-55\",\n \"[&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4\",\n className,\n )}\n {...props}\n >\n {children ?? value}\n </div>\n );\n}\n\nexport function CommandSeparator({ className, ...props }: ComponentPropsWithRef<\"div\">) {\n return (\n <div\n data-slot=\"command-separator\"\n aria-hidden=\"true\"\n className={cn(\"-mx-1 my-1 h-px bg-border\", className)}\n {...props}\n />\n );\n}\n\n/** Keyboard hint. Decorative — bind the shortcut for real at the app level. */\nexport function CommandShortcut({ className, ...props }: ComponentPropsWithRef<\"span\">) {\n return (\n <span\n data-slot=\"command-shortcut\"\n aria-hidden=\"true\"\n className={cn(\"ms-auto text-2xs tracking-wide text-muted-foreground\", className)}\n {...props}\n />\n );\n}\n\nexport interface CommandDialogProps extends ComponentPropsWithRef<typeof Dialog> {\n /** Names the dialog for assistive technology. Visually hidden by default. */\n title?: string;\n description?: string;\n className?: string;\n}\n\n/**\n * The palette in a modal, for the ⌘K pattern.\n *\n * The title and description are rendered but visually hidden: a dialog needs an\n * accessible name whether or not the design shows one, and leaving it out is\n * the most common defect in hand-rolled command menus.\n */\nexport function CommandDialog({\n title = \"Command palette\",\n description = \"Search for a command to run.\",\n children,\n className,\n ...props\n}: CommandDialogProps) {\n return (\n <Dialog {...props}>\n <DialogContent\n showCloseButton={false}\n className={cn(\"max-w-lg overflow-hidden p-0\", className)}\n >\n <DialogHeader className=\"sr-only\">\n <DialogTitle>{title}</DialogTitle>\n <DialogDescription>{description}</DialogDescription>\n </DialogHeader>\n <Command className=\"rounded-none\">{children}</Command>\n </DialogContent>\n </Dialog>\n );\n}\n"],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"data-table.d.ts","names":[],"sources":["../../../src/components/data-table/data-table.tsx"],"mappings":";;;
|
|
1
|
+
{"version":3,"file":"data-table.d.ts","names":[],"sources":["../../../src/components/data-table/data-table.tsx"],"mappings":";;;UAsIiB,eACf,kBAAkB,eAClB,cAAc,iBACN,KAAK;EACb,OAAO,MAAc,WAAW;;EAEhC,QAAQ;;iBAGM,UAAU,kBAAkB,eAAe,cAAc,WACvE,OACA,OACA,cACG,SACF,eAAe,WAAW,yBAAM,IAAA;;;;;;;UAmElB;EACf;EACA;EACA,gBAAgB;;UAGD,mCAAmC;EAClD,QAAQ;EACR;;;;;;;;;iBAUc,wBACd,QACA,OACA,cACG,SACF,6CAA0B,IAAA;;UA6EZ;EACf;IACE;IACA;IACA;IACA,mBAAmB;;;UAIN;EACf,OAAO;EACP;;;iBAIc,uBAAuB,OAAO,SAAqB,4CAAyB,IAAA;;;;;;;;UAwC3E;EACf;IAAS;MAAc;MAAmB;;;EAC1C;EACA,cAAc;EACd;EACA;EACA;EACA;;UAGe;EACf,OAAO;EACP;;;;;;;;EAQA,SAAS;;;;;;;;;iBAUK,sBACd,OACA,WACA,UACC,2CAAwB,IAAA"}
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
"use client";
|
|
2
|
+
import { mirrorForDirection } from "../../lib/styles.js";
|
|
2
3
|
import { cn } from "../../lib/utils.js";
|
|
3
4
|
import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from "../select/select.js";
|
|
4
5
|
import { Button } from "../button/button.js";
|
|
@@ -94,7 +95,7 @@ function DataTableColumnHeader({ column, title, className, ...props }) {
|
|
|
94
95
|
children: /* @__PURE__ */ jsxs(Button, {
|
|
95
96
|
variant: "ghost",
|
|
96
97
|
size: "sm",
|
|
97
|
-
className: "-
|
|
98
|
+
className: "-ms-2 h-7 gap-1 px-2 font-medium text-muted-foreground data-[state=open]:bg-accent",
|
|
98
99
|
children: [
|
|
99
100
|
title,
|
|
100
101
|
/* @__PURE__ */ jsx(SortIcon, { direction: sorted === false ? void 0 : sorted }),
|
|
@@ -224,6 +225,7 @@ function DataTablePagination({ table, pageSizes = [
|
|
|
224
225
|
viewBox: "0 0 24 24",
|
|
225
226
|
fill: "none",
|
|
226
227
|
"aria-hidden": "true",
|
|
228
|
+
className: mirrorForDirection,
|
|
227
229
|
children: /* @__PURE__ */ jsx("path", {
|
|
228
230
|
d: "m15 18-6-6 6-6",
|
|
229
231
|
stroke: "currentColor",
|
|
@@ -244,6 +246,7 @@ function DataTablePagination({ table, pageSizes = [
|
|
|
244
246
|
viewBox: "0 0 24 24",
|
|
245
247
|
fill: "none",
|
|
246
248
|
"aria-hidden": "true",
|
|
249
|
+
className: mirrorForDirection,
|
|
247
250
|
children: /* @__PURE__ */ jsx("path", {
|
|
248
251
|
d: "m9 18 6-6-6-6",
|
|
249
252
|
stroke: "currentColor",
|