@nocoo/basalt 2.0.3 → 2.1.2
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 +134 -15
- package/ai/COMPATIBILITY.md +180 -0
- package/ai/INTEGRATION.md +1760 -0
- package/ai/RECIPES.md +161 -0
- package/ai/USAGE.md +99 -0
- package/ai/registry.json +38099 -0
- package/ai/sources.json +10 -0
- package/dist/assets/brand-mark.d.ts +1 -0
- package/dist/assets/brand-mark.js +7 -0
- package/dist/assets/brand-mark.js.map +1 -0
- package/dist/charts/area.d.ts +58 -5
- package/dist/charts/area.js +20 -12
- package/dist/charts/area.js.map +1 -1
- package/dist/charts/bar.d.ts +54 -5
- package/dist/charts/bar.js +16 -10
- package/dist/charts/bar.js.map +1 -1
- package/dist/charts/bullet.d.ts +18 -1
- package/dist/charts/bullet.js +6 -3
- package/dist/charts/bullet.js.map +1 -1
- package/dist/charts/charts.d.ts +58 -5
- package/dist/charts/charts.js +13 -2
- package/dist/charts/charts.js.map +1 -1
- package/dist/charts/config.d.ts +7 -0
- package/dist/charts/config.js +5 -1
- package/dist/charts/config.js.map +1 -1
- package/dist/charts/custom-chart.d.ts +58 -5
- package/dist/charts/custom-chart.js +13 -2
- package/dist/charts/custom-chart.js.map +1 -1
- package/dist/charts/donut.d.ts +18 -1
- package/dist/charts/donut.js +6 -3
- package/dist/charts/donut.js.map +1 -1
- package/dist/charts/frame.d.ts +40 -3
- package/dist/charts/frame.js +55 -28
- package/dist/charts/frame.js.map +1 -1
- package/dist/charts/funnel.d.ts +18 -1
- package/dist/charts/funnel.js +5 -1
- package/dist/charts/funnel.js.map +1 -1
- package/dist/charts/gauge.d.ts +18 -1
- package/dist/charts/gauge.js +38 -20
- package/dist/charts/gauge.js.map +1 -1
- package/dist/charts/grouped-bar.d.ts +54 -5
- package/dist/charts/grouped-bar.js +16 -10
- package/dist/charts/grouped-bar.js.map +1 -1
- package/dist/charts/heatmap-calendar.d.ts +61 -0
- package/dist/charts/heatmap-calendar.js +287 -96
- package/dist/charts/heatmap-calendar.js.map +1 -1
- package/dist/charts/heatmap-matrix.d.ts +99 -0
- package/dist/charts/heatmap-matrix.js +249 -0
- package/dist/charts/heatmap-matrix.js.map +1 -0
- package/dist/charts/line.d.ts +66 -5
- package/dist/charts/line.js +37 -30
- package/dist/charts/line.js.map +1 -1
- package/dist/charts/palette.d.ts +1 -0
- package/dist/charts/palette.js +7 -1
- package/dist/charts/palette.js.map +1 -1
- package/dist/charts/radar.d.ts +18 -1
- package/dist/charts/radar.js +26 -19
- package/dist/charts/radar.js.map +1 -1
- package/dist/charts/sankey.d.ts +18 -1
- package/dist/charts/sankey.js +4 -1
- package/dist/charts/sankey.js.map +1 -1
- package/dist/charts/series.d.ts +5 -7
- package/dist/charts/series.js.map +1 -1
- package/dist/charts/slot-bar.d.ts +38 -6
- package/dist/charts/slot-bar.js +5 -2
- package/dist/charts/slot-bar.js.map +1 -1
- package/dist/charts/sparkline.d.ts +35 -5
- package/dist/charts/sparkline.js +22 -18
- package/dist/charts/sparkline.js.map +1 -1
- package/dist/charts/stacked-bar.d.ts +58 -5
- package/dist/charts/stacked-bar.js +19 -12
- package/dist/charts/stacked-bar.js.map +1 -1
- package/dist/charts/stat-card.d.ts +51 -1
- package/dist/charts/stat-card.js +66 -39
- package/dist/charts/stat-card.js.map +1 -1
- package/dist/charts/timeline.d.ts +3 -0
- package/dist/charts/timeline.js +4 -3
- package/dist/charts/timeline.js.map +1 -1
- package/dist/charts/timeseries.d.ts +58 -5
- package/dist/charts/timeseries.js +13 -2
- package/dist/charts/timeseries.js.map +1 -1
- package/dist/charts/tooltip.d.ts +57 -0
- package/dist/charts/tooltip.js +119 -2
- package/dist/charts/tooltip.js.map +1 -1
- package/dist/components/accordion.d.ts +117 -2
- package/dist/components/accordion.js +20 -13
- package/dist/components/accordion.js.map +1 -1
- package/dist/components/alert-dialog.d.ts +131 -13
- package/dist/components/alert-dialog.js +12 -9
- package/dist/components/alert-dialog.js.map +1 -1
- package/dist/components/app-header.js +18 -17
- package/dist/components/app-header.js.map +1 -1
- package/dist/components/app-shell.js +15 -14
- package/dist/components/app-shell.js.map +1 -1
- package/dist/components/autocomplete.d.ts +4 -0
- package/dist/components/autocomplete.js.map +1 -1
- package/dist/components/avatar.d.ts +76 -3
- package/dist/components/avatar.js.map +1 -1
- package/dist/components/badge.d.ts +15 -1
- package/dist/components/badge.js +13 -12
- package/dist/components/badge.js.map +1 -1
- package/dist/components/banner.d.ts +88 -2
- package/dist/components/banner.js +41 -40
- package/dist/components/banner.js.map +1 -1
- package/dist/components/basalt-mark.js +14 -8
- package/dist/components/basalt-mark.js.map +1 -1
- package/dist/components/battery-meter.d.ts +10 -0
- package/dist/components/battery-meter.js +56 -0
- package/dist/components/battery-meter.js.map +1 -0
- package/dist/components/breadcrumbs.d.ts +27 -7
- package/dist/components/breadcrumbs.js +21 -20
- package/dist/components/breadcrumbs.js.map +1 -1
- package/dist/components/button.d.ts +48 -2
- package/dist/components/button.js +87 -36
- package/dist/components/button.js.map +1 -1
- package/dist/components/chat-bubble.d.ts +7 -0
- package/dist/components/chat-bubble.js +14 -13
- package/dist/components/chat-bubble.js.map +1 -1
- package/dist/components/chat-composer.d.ts +7 -3
- package/dist/components/chat-composer.js.map +1 -1
- package/dist/components/chat-header.d.ts +6 -1
- package/dist/components/chat-header.js +17 -16
- package/dist/components/chat-header.js.map +1 -1
- package/dist/components/chat-inbox.d.ts +7 -2
- package/dist/components/chat-inbox.js.map +1 -1
- package/dist/components/checkbox.js +84 -53
- package/dist/components/checkbox.js.map +1 -1
- package/dist/components/clipboard-text.d.ts +13 -2
- package/dist/components/clipboard-text.js +4 -4
- package/dist/components/clipboard-text.js.map +1 -1
- package/dist/components/collapsible.d.ts +58 -15
- package/dist/components/collapsible.js.map +1 -1
- package/dist/components/command-palette.d.ts +151 -61
- package/dist/components/command-palette.js.map +1 -1
- package/dist/components/confirm-dialog.d.ts +1 -1
- package/dist/components/confirm-dialog.js +6 -4
- package/dist/components/confirm-dialog.js.map +1 -1
- package/dist/components/context-menu.d.ts +210 -2
- package/dist/components/context-menu.js +7 -4
- package/dist/components/context-menu.js.map +1 -1
- package/dist/components/data-table.d.ts +40 -2
- package/dist/components/data-table.js +168 -120
- package/dist/components/data-table.js.map +1 -1
- package/dist/components/date-picker.d.ts +53 -2
- package/dist/components/date-picker.js +387 -219
- package/dist/components/date-picker.js.map +1 -1
- package/dist/components/delete-resource.d.ts +7 -1
- package/dist/components/delete-resource.js +22 -18
- package/dist/components/delete-resource.js.map +1 -1
- package/dist/components/description-list.js +16 -15
- package/dist/components/description-list.js.map +1 -1
- package/dist/components/dialog.d.ts +141 -12
- package/dist/components/dialog.js +42 -38
- package/dist/components/dialog.js.map +1 -1
- package/dist/components/dock.d.ts +1 -1
- package/dist/components/dock.js +39 -58
- package/dist/components/dock.js.map +1 -1
- package/dist/components/dropdown-menu.d.ts +229 -15
- package/dist/components/dropdown-menu.js +9 -6
- package/dist/components/dropdown-menu.js.map +1 -1
- package/dist/components/editable-nav-item.d.ts +33 -0
- package/dist/components/editable-nav-item.js +90 -0
- package/dist/components/editable-nav-item.js.map +1 -0
- package/dist/components/empty.d.ts +22 -2
- package/dist/components/empty.js +22 -13
- package/dist/components/empty.js.map +1 -1
- package/dist/components/field.js +31 -30
- package/dist/components/field.js.map +1 -1
- package/dist/components/file-dropzone.d.ts +37 -0
- package/dist/components/file-dropzone.js +103 -0
- package/dist/components/file-dropzone.js.map +1 -0
- package/dist/components/filter-bar.d.ts +34 -0
- package/dist/components/filter-bar.js +52 -0
- package/dist/components/filter-bar.js.map +1 -0
- package/dist/components/flow.js +19 -18
- package/dist/components/flow.js.map +1 -1
- package/dist/components/grid.d.ts +3 -1
- package/dist/components/grid.js.map +1 -1
- package/dist/components/hover-card.d.ts +111 -1
- package/dist/components/hover-card.js +9 -6
- package/dist/components/hover-card.js.map +1 -1
- package/dist/components/icon-picker.d.ts +34 -0
- package/dist/components/icon-picker.js +77 -0
- package/dist/components/icon-picker.js.map +1 -0
- package/dist/components/inline-editable.d.ts +46 -0
- package/dist/components/inline-editable.js +124 -0
- package/dist/components/inline-editable.js.map +1 -0
- package/dist/components/input-area.js +3 -3
- package/dist/components/input-group.js +7 -7
- package/dist/components/input.js +3 -3
- package/dist/components/label.js +18 -17
- package/dist/components/label.js.map +1 -1
- package/dist/components/layer-card.d.ts +10 -2
- package/dist/components/layer-card.js +71 -68
- package/dist/components/layer-card.js.map +1 -1
- package/dist/components/loader.d.ts +10 -2
- package/dist/components/loader.js.map +1 -1
- package/dist/components/menu-bar.d.ts +174 -6
- package/dist/components/menu-bar.js +33 -29
- package/dist/components/menu-bar.js.map +1 -1
- package/dist/components/meter.d.ts +27 -2
- package/dist/components/meter.js.map +1 -1
- package/dist/components/multi-select.d.ts +64 -0
- package/dist/components/multi-select.js +218 -0
- package/dist/components/multi-select.js.map +1 -0
- package/dist/components/navigation-menu.d.ts +88 -5
- package/dist/components/navigation-menu.js.map +1 -1
- package/dist/components/overlay.js +6 -5
- package/dist/components/overlay.js.map +1 -1
- package/dist/components/page-header.js +23 -21
- package/dist/components/page-header.js.map +1 -1
- package/dist/components/pagination.js +7 -7
- package/dist/components/popover.d.ts +136 -16
- package/dist/components/popover.js +32 -28
- package/dist/components/popover.js.map +1 -1
- package/dist/components/radio.js +38 -37
- package/dist/components/radio.js.map +1 -1
- package/dist/components/resource-list.d.ts +26 -1
- package/dist/components/resource-list.js +28 -15
- package/dist/components/resource-list.js.map +1 -1
- package/dist/components/responsive-master-detail.d.ts +27 -0
- package/dist/components/responsive-master-detail.js +85 -0
- package/dist/components/responsive-master-detail.js.map +1 -0
- package/dist/components/section-rule.js +23 -22
- package/dist/components/section-rule.js.map +1 -1
- package/dist/components/select.d.ts +27 -3
- package/dist/components/select.js +11 -11
- package/dist/components/select.js.map +1 -1
- package/dist/components/sheet.d.ts +115 -11
- package/dist/components/sheet.js +37 -30
- package/dist/components/sheet.js.map +1 -1
- package/dist/components/sidebar.d.ts +109 -17
- package/dist/components/sidebar.js +112 -111
- package/dist/components/sidebar.js.map +1 -1
- package/dist/components/skeleton-line.d.ts +22 -2
- package/dist/components/skeleton-line.js.map +1 -1
- package/dist/components/slider.d.ts +61 -1
- package/dist/components/slider.js +31 -15
- package/dist/components/slider.js.map +1 -1
- package/dist/components/stat-strip.js +16 -15
- package/dist/components/stat-strip.js.map +1 -1
- package/dist/components/switch.js +78 -47
- package/dist/components/switch.js.map +1 -1
- package/dist/components/table-of-contents.js +18 -17
- package/dist/components/table-of-contents.js.map +1 -1
- package/dist/components/table-pager.js +20 -19
- package/dist/components/table-pager.js.map +1 -1
- package/dist/components/table.d.ts +9 -3
- package/dist/components/table.js +19 -18
- package/dist/components/table.js.map +1 -1
- package/dist/components/tabs.js +29 -22
- package/dist/components/tabs.js.map +1 -1
- package/dist/components/tag-badge.d.ts +58 -0
- package/dist/components/tag-badge.js +72 -0
- package/dist/components/tag-badge.js.map +1 -0
- package/dist/components/tag-color-picker.d.ts +20 -0
- package/dist/components/tag-color-picker.js +42 -0
- package/dist/components/tag-color-picker.js.map +1 -0
- package/dist/components/text.js +17 -16
- package/dist/components/text.js.map +1 -1
- package/dist/components/toast.d.ts +173 -3
- package/dist/components/toast.js +1 -1
- package/dist/components/toast.js.map +1 -1
- package/dist/components/toggle-group.d.ts +88 -2
- package/dist/components/toggle-group.js +32 -31
- package/dist/components/toggle-group.js.map +1 -1
- package/dist/components/toggle.d.ts +35 -2
- package/dist/components/toggle.js +12 -11
- package/dist/components/toggle.js.map +1 -1
- package/dist/components/tooltip.d.ts +144 -6
- package/dist/components/tooltip.js +9 -6
- package/dist/components/tooltip.js.map +1 -1
- package/dist/components/typeahead-field.js +193 -132
- package/dist/components/typeahead-field.js.map +1 -1
- package/dist/components/upload-queue.d.ts +51 -0
- package/dist/components/upload-queue.js +116 -0
- package/dist/components/upload-queue.js.map +1 -0
- package/dist/providers/accent.d.ts +46 -2
- package/dist/providers/accent.js +358 -172
- package/dist/providers/accent.js.map +1 -1
- package/dist/providers/link.d.ts +14 -4
- package/dist/providers/link.js.map +1 -1
- package/dist/providers/theme.d.ts +38 -2
- package/dist/providers/theme.js +160 -27
- package/dist/providers/theme.js.map +1 -1
- package/dist/styles/base.css +83 -0
- package/dist/styles/standalone.css +699 -120
- package/dist/styles/tailwind.css +21 -7
- package/dist/styles/tokens.css +145 -91
- package/dist/utils/control-surface.d.ts +2 -1
- package/dist/utils/control-surface.js +4 -4
- package/dist/utils/control-surface.js.map +1 -1
- package/dist/utils/selection-indicator.js +2 -2
- package/dist/utils/selection-indicator.js.map +1 -1
- package/package.json +8 -4
|
@@ -5,12 +5,15 @@ import * as r from "react";
|
|
|
5
5
|
import { jsx as i } from "react/jsx-runtime";
|
|
6
6
|
import * as a from "@radix-ui/react-dropdown-menu";
|
|
7
7
|
//#region src/components/dropdown-menu.tsx
|
|
8
|
-
var o = a.Root, s = a.Trigger, c = a.Group, l = a.Portal, u = a.Sub, d = a.RadioGroup, f = r.forwardRef(({ className: t, sideOffset: r = 8, ...o }, s) => /* @__PURE__ */ i(a.Portal, {
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
8
|
+
var o = a.Root, s = a.Trigger, c = a.Group, l = a.Portal, u = a.Sub, d = a.RadioGroup, f = r.forwardRef(({ className: t, sideOffset: r = 8, ...o }, s) => /* @__PURE__ */ i(a.Portal, {
|
|
9
|
+
forceMount: o.forceMount,
|
|
10
|
+
children: /* @__PURE__ */ i(a.Content, {
|
|
11
|
+
ref: s,
|
|
12
|
+
sideOffset: r,
|
|
13
|
+
className: n(e("min-w-40", t)),
|
|
14
|
+
...o
|
|
15
|
+
})
|
|
16
|
+
}));
|
|
14
17
|
f.displayName = a.Content.displayName;
|
|
15
18
|
var p = r.forwardRef(({ className: n, ...r }, o) => /* @__PURE__ */ i(a.Item, {
|
|
16
19
|
ref: o,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"dropdown-menu.js","names":[],"sources":["../../src/components/dropdown-menu.tsx"],"sourcesContent":["import * as DropdownMenuPrimitive from \"@radix-ui/react-dropdown-menu\";\nimport * as React from \"react\";\nimport { cn } from \"../utils/cn\";\nimport { MENU_GAP, overlayItemClass, overlayPanelClass } from \"./overlay\";\n\nexport type DropdownMenuProps = Omit<\n\tReact.ComponentPropsWithoutRef<typeof DropdownMenuPrimitive.Root>,\n\t\"open\" | \"defaultOpen\" | \"onOpenChange\"\n> & {\n\t/**\n\t * The controlled open state.\n\t */\n\topen?: boolean;\n\t/**\n\t * The uncontrolled initial open state.\n\t * @default false\n\t */\n\tdefaultOpen?: boolean;\n\t/**\n\t * Called when the open state changes.\n\t */\n\tonOpenChange?: (open: boolean) => void;\n};\nexport const DropdownMenu: React.FC<DropdownMenuProps> = DropdownMenuPrimitive.Root;\nexport const DropdownMenuTrigger = DropdownMenuPrimitive.Trigger;\nexport const DropdownMenuGroup = DropdownMenuPrimitive.Group;\nexport const DropdownMenuPortal = DropdownMenuPrimitive.Portal;\nexport const DropdownMenuSub = DropdownMenuPrimitive.Sub;\nexport const DropdownMenuRadioGroup = DropdownMenuPrimitive.RadioGroup;\n\nexport const DropdownMenuContent = React.forwardRef<\n\tReact.ElementRef<typeof DropdownMenuPrimitive.Content>,\n\tReact.ComponentPropsWithoutRef<typeof DropdownMenuPrimitive.Content>\n>(({ className, sideOffset = MENU_GAP, ...props }, ref) => (\n\t<DropdownMenuPrimitive.Portal>\n\t\t<DropdownMenuPrimitive.Content\n\t\t\tref={ref}\n\t\t\tsideOffset={sideOffset}\n\t\t\tclassName={overlayPanelClass(cn(\"min-w-40\", className))}\n\t\t\t{...props}\n\t\t/>\n\t</DropdownMenuPrimitive.Portal>\n));\nDropdownMenuContent.displayName = DropdownMenuPrimitive.Content.displayName;\n\nexport type DropdownMenuItemProps = Omit<\n\tReact.ComponentPropsWithoutRef<typeof DropdownMenuPrimitive.Item>,\n\t\"disabled\"\n> & {\n\t/**\n\t * Disable the menu item.\n\t * @default false\n\t */\n\tdisabled?: boolean;\n};\n\nexport const DropdownMenuItem = React.forwardRef<\n\tReact.ElementRef<typeof DropdownMenuPrimitive.Item>,\n\tDropdownMenuItemProps\n>(({ className, ...props }, ref) => (\n\t<DropdownMenuPrimitive.Item\n\t\tref={ref}\n\t\tclassName={overlayItemClass(\n\t\t\tcn(\n\t\t\t\t\"relative outline-hidden focus:bg-basalt-accent data-disabled:pointer-events-none data-disabled:opacity-50\",\n\t\t\t\tclassName,\n\t\t\t),\n\t\t)}\n\t\t{...props}\n\t/>\n));\nDropdownMenuItem.displayName = DropdownMenuPrimitive.Item.displayName;\n"],"mappings":";;;;;;;AAuBA,IAAa,IAA4C,EAAsB,MAClE,IAAsB,EAAsB,SAC5C,IAAoB,EAAsB,OAC1C,IAAqB,EAAsB,QAC3C,IAAkB,EAAsB,KACxC,IAAyB,EAAsB,YAE/C,IAAsB,EAAM,YAGtC,EAAE,cAAW,gBAAA,GAAuB,GAAG,KAAS,MAClD,kBAAC,EAAsB,QAAvB,EAAA,UACC,kBAAC,EAAsB,SAAvB;CACM;CACO;CACZ,WAAW,EAAkB,EAAG,YAAY,CAAS,CAAC;CACtD,GAAI;AACJ,CAAA,EAC4B,CAAA,CAC9B;AACD,EAAoB,cAAc,EAAsB,QAAQ;AAahE,IAAa,IAAmB,EAAM,YAGnC,EAAE,cAAW,GAAG,KAAS,MAC3B,kBAAC,EAAsB,MAAvB;CACM;CACL,WAAW,EACV,EACC,6GACA,CACD,CACD;CACA,GAAI;AACJ,CAAA,CACD;AACD,EAAiB,cAAc,EAAsB,KAAK"}
|
|
1
|
+
{"version":3,"file":"dropdown-menu.js","names":[],"sources":["../../src/components/dropdown-menu.tsx"],"sourcesContent":["import * as DropdownMenuPrimitive from \"@radix-ui/react-dropdown-menu\";\nimport * as React from \"react\";\nimport { cn } from \"../utils/cn\";\nimport { MENU_GAP, overlayItemClass, overlayPanelClass } from \"./overlay\";\n\ntype RadixDropdownMenuProps = React.ComponentPropsWithoutRef<typeof DropdownMenuPrimitive.Root>;\ntype RadixDropdownMenuTriggerProps = React.ComponentPropsWithoutRef<\n\ttypeof DropdownMenuPrimitive.Trigger\n>;\ntype RadixDropdownMenuGroupProps = React.ComponentPropsWithoutRef<\n\ttypeof DropdownMenuPrimitive.Group\n>;\ntype RadixDropdownMenuPortalProps = React.ComponentPropsWithoutRef<\n\ttypeof DropdownMenuPrimitive.Portal\n>;\ntype RadixDropdownMenuSubProps = React.ComponentPropsWithoutRef<typeof DropdownMenuPrimitive.Sub>;\ntype RadixDropdownMenuRadioGroupProps = React.ComponentPropsWithoutRef<\n\ttypeof DropdownMenuPrimitive.RadioGroup\n>;\ntype RadixDropdownMenuContentProps = React.ComponentPropsWithoutRef<\n\ttypeof DropdownMenuPrimitive.Content\n>;\ntype RadixDropdownMenuItemProps = React.ComponentPropsWithoutRef<typeof DropdownMenuPrimitive.Item>;\n\nexport interface DropdownMenuProps\n\textends Omit<\n\t\tRadixDropdownMenuProps,\n\t\t\"open\" | \"defaultOpen\" | \"onOpenChange\" | \"dir\" | \"modal\" | \"children\"\n\t> {\n\t/**\n\t * Structure elements comprising the dropdown menu, typically trigger and content.\n\t */\n\tchildren?: React.ReactNode;\n\t/**\n\t * The controlled open state of the dropdown menu.\n\t */\n\topen?: RadixDropdownMenuProps[\"open\"];\n\t/**\n\t * The uncontrolled initial open state of the dropdown menu.\n\t * @default false\n\t */\n\tdefaultOpen?: RadixDropdownMenuProps[\"defaultOpen\"];\n\t/**\n\t * Called when the open state changes.\n\t */\n\tonOpenChange?: RadixDropdownMenuProps[\"onOpenChange\"];\n\t/**\n\t * The reading direction of the dropdown menu. Inherited from DirectionProvider if present,\n\t * or defaults to \"ltr\".\n\t * @default \"ltr\"\n\t */\n\tdir?: RadixDropdownMenuProps[\"dir\"];\n\t/**\n\t * The modality of the dropdown menu. When set to true, interaction with outside elements\n\t * will be disabled and only menu content will be visible to screen readers.\n\t * @default true\n\t */\n\tmodal?: RadixDropdownMenuProps[\"modal\"];\n}\n\nexport const DropdownMenu: React.FC<DropdownMenuProps> = DropdownMenuPrimitive.Root;\n\nexport interface DropdownMenuTriggerProps\n\textends Omit<RadixDropdownMenuTriggerProps, \"asChild\" | \"children\"> {\n\t/**\n\t * Trigger element content.\n\t */\n\tchildren?: React.ReactNode;\n\t/**\n\t * Change the default rendered button element to the child element, merging props and behavior.\n\t * DropdownMenuTrigger forwards ref to HTMLButtonElement and inherits native button attributes.\n\t * @default false\n\t */\n\tasChild?: RadixDropdownMenuTriggerProps[\"asChild\"];\n}\n\nexport const DropdownMenuTrigger = DropdownMenuPrimitive.Trigger;\n\nexport interface DropdownMenuGroupProps\n\textends Omit<RadixDropdownMenuGroupProps, \"asChild\" | \"children\"> {\n\t/**\n\t * Menu items or elements grouped together.\n\t */\n\tchildren?: React.ReactNode;\n\t/**\n\t * Change the default rendered div element to the child element, merging props and behavior.\n\t * DropdownMenuGroup forwards ref to HTMLDivElement and inherits native div attributes.\n\t * @default false\n\t */\n\tasChild?: RadixDropdownMenuGroupProps[\"asChild\"];\n}\n\nexport const DropdownMenuGroup = DropdownMenuPrimitive.Group;\n\nexport interface DropdownMenuPortalProps\n\textends Omit<RadixDropdownMenuPortalProps, \"container\" | \"forceMount\" | \"children\"> {\n\t/**\n\t * Content to render into the portal target.\n\t */\n\tchildren?: React.ReactNode;\n\t/**\n\t * Specify a container element to portal the content into.\n\t * Note: Only controls direct portal children; does not override the destination\n\t * container of the built-in portal inside DropdownMenuContent.\n\t */\n\tcontainer?: RadixDropdownMenuPortalProps[\"container\"];\n\t/**\n\t * Used to force mounting when more control is needed. Useful when\n\t * controlling animation with React animation libraries.\n\t */\n\tforceMount?: RadixDropdownMenuPortalProps[\"forceMount\"];\n}\n\nexport const DropdownMenuPortal = DropdownMenuPrimitive.Portal;\n\nexport interface DropdownMenuSubProps\n\textends Omit<RadixDropdownMenuSubProps, \"open\" | \"defaultOpen\" | \"onOpenChange\" | \"children\"> {\n\t/**\n\t * Submenu structure elements.\n\t * Note: Basalt does not export styled DropdownMenuSubTrigger or DropdownMenuSubContent components;\n\t * compose with underlying Radix primitives when building nested submenus.\n\t */\n\tchildren?: React.ReactNode;\n\t/**\n\t * The controlled open state of the submenu.\n\t */\n\topen?: RadixDropdownMenuSubProps[\"open\"];\n\t/**\n\t * The uncontrolled initial open state of the submenu.\n\t * @default false\n\t */\n\tdefaultOpen?: RadixDropdownMenuSubProps[\"defaultOpen\"];\n\t/**\n\t * Event handler called when the open state of the submenu changes.\n\t */\n\tonOpenChange?: RadixDropdownMenuSubProps[\"onOpenChange\"];\n}\n\nexport const DropdownMenuSub = DropdownMenuPrimitive.Sub;\n\nexport interface DropdownMenuRadioGroupProps\n\textends Omit<\n\t\tRadixDropdownMenuRadioGroupProps,\n\t\t\"value\" | \"onValueChange\" | \"asChild\" | \"children\"\n\t> {\n\t/**\n\t * Radio item elements grouped together.\n\t * Note: Basalt does not export styled DropdownMenuRadioItem or indicator components;\n\t * compose with underlying Radix primitives when building radio selection groups.\n\t */\n\tchildren?: React.ReactNode;\n\t/**\n\t * The value of the currently selected radio item.\n\t */\n\tvalue?: RadixDropdownMenuRadioGroupProps[\"value\"];\n\t/**\n\t * Event handler called when the value changes.\n\t */\n\tonValueChange?: RadixDropdownMenuRadioGroupProps[\"onValueChange\"];\n\t/**\n\t * Change the default rendered div element to the child element, merging props and behavior.\n\t * DropdownMenuRadioGroup forwards ref to HTMLDivElement and inherits native div attributes.\n\t * @default false\n\t */\n\tasChild?: RadixDropdownMenuRadioGroupProps[\"asChild\"];\n}\n\nexport const DropdownMenuRadioGroup = DropdownMenuPrimitive.RadioGroup;\n\nexport interface DropdownMenuContentProps\n\textends Omit<\n\t\tRadixDropdownMenuContentProps,\n\t\t| \"side\"\n\t\t| \"sideOffset\"\n\t\t| \"align\"\n\t\t| \"alignOffset\"\n\t\t| \"avoidCollisions\"\n\t\t| \"collisionBoundary\"\n\t\t| \"collisionPadding\"\n\t\t| \"arrowPadding\"\n\t\t| \"sticky\"\n\t\t| \"hideWhenDetached\"\n\t\t| \"updatePositionStrategy\"\n\t\t| \"loop\"\n\t\t| \"onCloseAutoFocus\"\n\t\t| \"onEscapeKeyDown\"\n\t\t| \"onPointerDownOutside\"\n\t\t| \"onFocusOutside\"\n\t\t| \"onInteractOutside\"\n\t\t| \"forceMount\"\n\t\t| \"asChild\"\n\t> {\n\t/**\n\t * Preferred placement side relative to trigger.\n\t * @default \"bottom\"\n\t */\n\tside?: RadixDropdownMenuContentProps[\"side\"];\n\t/**\n\t * Distance in pixels between trigger and floating content panel.\n\t * In Basalt, defaults to MENU_GAP (8).\n\t * @default 8\n\t */\n\tsideOffset?: RadixDropdownMenuContentProps[\"sideOffset\"];\n\t/**\n\t * Preferred alignment along the side axis.\n\t * @default \"center\"\n\t */\n\talign?: RadixDropdownMenuContentProps[\"align\"];\n\t/**\n\t * Offset in pixels from the start or end alignment position.\n\t * @default 0\n\t */\n\talignOffset?: RadixDropdownMenuContentProps[\"alignOffset\"];\n\t/**\n\t * Whether to reposition content to avoid viewport boundary collisions.\n\t * @default true\n\t */\n\tavoidCollisions?: RadixDropdownMenuContentProps[\"avoidCollisions\"];\n\t/**\n\t * Element or elements bounding boundary collision calculations.\n\t * @default []\n\t */\n\tcollisionBoundary?: RadixDropdownMenuContentProps[\"collisionBoundary\"];\n\t/**\n\t * Virtual padding from collision boundaries in pixels.\n\t * @default 0\n\t */\n\tcollisionPadding?: RadixDropdownMenuContentProps[\"collisionPadding\"];\n\t/**\n\t * Padding in pixels between popper arrow and floating panel edge.\n\t * @default 0\n\t */\n\tarrowPadding?: RadixDropdownMenuContentProps[\"arrowPadding\"];\n\t/**\n\t * Sticky positioning behavior along the align axis when overflowing.\n\t * @default \"partial\"\n\t */\n\tsticky?: RadixDropdownMenuContentProps[\"sticky\"];\n\t/**\n\t * Whether to hide content completely when trigger is fully occluded.\n\t * @default false\n\t */\n\thideWhenDetached?: RadixDropdownMenuContentProps[\"hideWhenDetached\"];\n\t/**\n\t * Strategy used to calculate and update popper position.\n\t * @default \"optimized\"\n\t */\n\tupdatePositionStrategy?: RadixDropdownMenuContentProps[\"updatePositionStrategy\"];\n\t/**\n\t * Whether keyboard navigation should loop around item boundaries.\n\t * @default false\n\t */\n\tloop?: RadixDropdownMenuContentProps[\"loop\"];\n\t/**\n\t * Callback fired when auto-focusing on close. Can be prevented.\n\t */\n\tonCloseAutoFocus?: RadixDropdownMenuContentProps[\"onCloseAutoFocus\"];\n\t/**\n\t * Callback fired when the Escape key is down on the content layer. Can be prevented.\n\t */\n\tonEscapeKeyDown?: RadixDropdownMenuContentProps[\"onEscapeKeyDown\"];\n\t/**\n\t * Callback fired when a pointerdown event happens outside the bounds of the content. Can be prevented.\n\t */\n\tonPointerDownOutside?: RadixDropdownMenuContentProps[\"onPointerDownOutside\"];\n\t/**\n\t * Callback fired when focus moves outside the bounds of the content. Can be prevented.\n\t */\n\tonFocusOutside?: RadixDropdownMenuContentProps[\"onFocusOutside\"];\n\t/**\n\t * Callback fired when an interaction (pointerdown or focus) happens outside the bounds of the content. Can be prevented.\n\t */\n\tonInteractOutside?: RadixDropdownMenuContentProps[\"onInteractOutside\"];\n\t/**\n\t * Force mounting content in DOM for external animation controls.\n\t * When forceMount is true, the content remains mounted even when closed.\n\t * The caller is responsible for visibility transitions and unmounting after animation completes.\n\t * Note: Keeping modal content forceMounted may isolate background interactions until unmounted.\n\t */\n\tforceMount?: true;\n\t/**\n\t * Change the default rendered div element to the child element, merging props and behavior.\n\t * DropdownMenuContent forwards ref to HTMLDivElement and inherits native div attributes.\n\t * @default false\n\t */\n\tasChild?: RadixDropdownMenuContentProps[\"asChild\"];\n}\n\nexport const DropdownMenuContent = React.forwardRef<\n\tReact.ElementRef<typeof DropdownMenuPrimitive.Content>,\n\tDropdownMenuContentProps\n>(({ className, sideOffset = MENU_GAP, ...props }, ref) => (\n\t<DropdownMenuPrimitive.Portal forceMount={props.forceMount}>\n\t\t<DropdownMenuPrimitive.Content\n\t\t\tref={ref}\n\t\t\tsideOffset={sideOffset}\n\t\t\tclassName={overlayPanelClass(cn(\"min-w-40\", className))}\n\t\t\t{...props}\n\t\t/>\n\t</DropdownMenuPrimitive.Portal>\n));\nDropdownMenuContent.displayName = DropdownMenuPrimitive.Content.displayName;\n\nexport interface DropdownMenuItemProps\n\textends Omit<RadixDropdownMenuItemProps, \"disabled\" | \"onSelect\" | \"textValue\" | \"asChild\"> {\n\t/**\n\t * Disable the menu item.\n\t * @default false\n\t */\n\tdisabled?: RadixDropdownMenuItemProps[\"disabled\"];\n\t/**\n\t * Event handler called when the menu item is selected (via click or keyboard).\n\t * Note that this is a Radix CustomEvent, not native DOM onSelect.\n\t */\n\tonSelect?: RadixDropdownMenuItemProps[\"onSelect\"];\n\t/**\n\t * Optional text used for typeahead navigation. By default typeahead uses item text content.\n\t */\n\ttextValue?: RadixDropdownMenuItemProps[\"textValue\"];\n\t/**\n\t * Change the default rendered div element to the child element, merging props and behavior.\n\t * DropdownMenuItem forwards ref to HTMLDivElement and inherits native div attributes.\n\t * @default false\n\t */\n\tasChild?: RadixDropdownMenuItemProps[\"asChild\"];\n}\n\nexport const DropdownMenuItem = React.forwardRef<\n\tReact.ElementRef<typeof DropdownMenuPrimitive.Item>,\n\tDropdownMenuItemProps\n>(({ className, ...props }, ref) => (\n\t<DropdownMenuPrimitive.Item\n\t\tref={ref}\n\t\tclassName={overlayItemClass(\n\t\t\tcn(\n\t\t\t\t\"relative outline-hidden focus:bg-basalt-accent data-disabled:pointer-events-none data-disabled:opacity-50\",\n\t\t\t\tclassName,\n\t\t\t),\n\t\t)}\n\t\t{...props}\n\t/>\n));\nDropdownMenuItem.displayName = DropdownMenuPrimitive.Item.displayName;\n"],"mappings":";;;;;;;AA4DA,IAAa,IAA4C,EAAsB,MAgBlE,IAAsB,EAAsB,SAgB5C,IAAoB,EAAsB,OAqB1C,IAAqB,EAAsB,QAyB3C,IAAkB,EAAsB,KA6BxC,IAAyB,EAAsB,YAyH/C,IAAsB,EAAM,YAGtC,EAAE,cAAW,gBAAA,GAAuB,GAAG,KAAS,MAClD,kBAAC,EAAsB,QAAvB;CAA8B,YAAY,EAAM;CAC/C,UAAA,kBAAC,EAAsB,SAAvB;EACM;EACO;EACZ,WAAW,EAAkB,EAAG,YAAY,CAAS,CAAC;EACtD,GAAI;CACJ,CAAA;AAC4B,CAAA,CAC9B;AACD,EAAoB,cAAc,EAAsB,QAAQ;AA0BhE,IAAa,IAAmB,EAAM,YAGnC,EAAE,cAAW,GAAG,KAAS,MAC3B,kBAAC,EAAsB,MAAvB;CACM;CACL,WAAW,EACV,EACC,6GACA,CACD,CACD;CACA,GAAI;AACJ,CAAA,CACD;AACD,EAAiB,cAAc,EAAsB,KAAK"}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import { type ReactNode } from "react";
|
|
2
|
+
export interface EditableNavItemProps {
|
|
3
|
+
/** Current display name. */
|
|
4
|
+
label: string;
|
|
5
|
+
/** Application route, interpreted by LinkProvider. */
|
|
6
|
+
href?: string;
|
|
7
|
+
/** Navigation/selection request. */
|
|
8
|
+
onSelect?: () => void;
|
|
9
|
+
/** Selected location. @default false */
|
|
10
|
+
selected?: boolean;
|
|
11
|
+
/** Caller-owned leading icon. */
|
|
12
|
+
icon?: ReactNode;
|
|
13
|
+
/** Caller-formatted count or status. */
|
|
14
|
+
count?: ReactNode;
|
|
15
|
+
/** Separate row actions, never nested inside the navigation button/link. */
|
|
16
|
+
actions?: ReactNode;
|
|
17
|
+
/** Enable renaming; rejected promises keep the editor and draft available. */
|
|
18
|
+
onRename?: (name: string) => void | Promise<void>;
|
|
19
|
+
/** Disable navigation and renaming. Application action slots retain their own permissions. @default false */
|
|
20
|
+
disabled?: boolean;
|
|
21
|
+
/** Rename action prefix. @default "Rename" */
|
|
22
|
+
renameLabel?: string;
|
|
23
|
+
/** Accessible save action. @default "Save" */
|
|
24
|
+
saveLabel?: string;
|
|
25
|
+
/** Accessible cancel action. @default "Cancel" */
|
|
26
|
+
cancelLabel?: string;
|
|
27
|
+
/** Additional root classes. */
|
|
28
|
+
className?: string;
|
|
29
|
+
}
|
|
30
|
+
export declare function EditableNavItem({ label, href, onSelect, selected, icon, count, actions, onRename, disabled, renameLabel, saveLabel, cancelLabel, className, }: EditableNavItemProps): import("react").JSX.Element;
|
|
31
|
+
export type FolderNavItemProps = EditableNavItemProps;
|
|
32
|
+
/** Folder presentation with an overridable icon; no tree, router or permission model. */
|
|
33
|
+
export declare function FolderNavItem({ icon, ...props }: FolderNavItemProps): import("react").JSX.Element;
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { cn as e } from "../utils/cn.js";
|
|
3
|
+
import { BASALT_UI_CLASS as t } from "../utils/control-surface.js";
|
|
4
|
+
import { Button as n } from "./button.js";
|
|
5
|
+
import { Link as r } from "./link.js";
|
|
6
|
+
import { InlineEditable as i } from "./inline-editable.js";
|
|
7
|
+
import { useId as a, useLayoutEffect as o, useRef as s, useState as c } from "react";
|
|
8
|
+
import { Folder as l, Pencil as u } from "lucide-react";
|
|
9
|
+
import { Fragment as d, jsx as f, jsxs as p } from "react/jsx-runtime";
|
|
10
|
+
//#region src/components/editable-nav-item.tsx
|
|
11
|
+
function m({ label: l, href: m, onSelect: h, selected: g = !1, icon: _, count: v, actions: y, onRename: b, disabled: x = !1, renameLabel: S = "Rename", saveLabel: C = "Save", cancelLabel: w = "Cancel", className: T }) {
|
|
12
|
+
let [E, D] = c(!1), O = a(), k = s(null), A = s(!1);
|
|
13
|
+
o(() => {
|
|
14
|
+
!E && A.current && (A.current = !1, k.current?.focus());
|
|
15
|
+
}, [E]);
|
|
16
|
+
let j = /* @__PURE__ */ p(d, { children: [
|
|
17
|
+
/* @__PURE__ */ f("span", {
|
|
18
|
+
className: "shrink-0",
|
|
19
|
+
"aria-hidden": "true",
|
|
20
|
+
children: _
|
|
21
|
+
}),
|
|
22
|
+
/* @__PURE__ */ f("span", {
|
|
23
|
+
className: "min-w-0 flex-1 truncate text-left",
|
|
24
|
+
children: l
|
|
25
|
+
}),
|
|
26
|
+
v != null && /* @__PURE__ */ p("span", {
|
|
27
|
+
id: O,
|
|
28
|
+
className: "shrink-0 text-xs tabular-nums text-basalt-muted-foreground",
|
|
29
|
+
children: [" ", v]
|
|
30
|
+
})
|
|
31
|
+
] });
|
|
32
|
+
return /* @__PURE__ */ f("div", {
|
|
33
|
+
className: e(t, "min-w-0 rounded-basalt-md", g && "bg-basalt-accent", T),
|
|
34
|
+
children: E && b ? /* @__PURE__ */ f(i, {
|
|
35
|
+
className: "p-2",
|
|
36
|
+
label: `${S} ${l}`,
|
|
37
|
+
value: l,
|
|
38
|
+
editing: !0,
|
|
39
|
+
onSave: b,
|
|
40
|
+
saveLabel: C,
|
|
41
|
+
cancelLabel: w,
|
|
42
|
+
disabled: x,
|
|
43
|
+
onEditingChange: (e, t) => {
|
|
44
|
+
A.current = !e && t !== "blur", D(e);
|
|
45
|
+
}
|
|
46
|
+
}) : /* @__PURE__ */ p("div", {
|
|
47
|
+
className: "flex min-w-0 items-center gap-1",
|
|
48
|
+
children: [
|
|
49
|
+
/* @__PURE__ */ f(n, {
|
|
50
|
+
asChild: !!m,
|
|
51
|
+
variant: "ghost",
|
|
52
|
+
disabled: x,
|
|
53
|
+
className: "min-w-0 flex-1 justify-start gap-2",
|
|
54
|
+
"aria-current": g ? "page" : void 0,
|
|
55
|
+
"aria-label": l,
|
|
56
|
+
"aria-describedby": v == null ? void 0 : O,
|
|
57
|
+
onClick: h,
|
|
58
|
+
children: m ? /* @__PURE__ */ f(r, {
|
|
59
|
+
href: m,
|
|
60
|
+
className: "text-inherit no-underline hover:no-underline",
|
|
61
|
+
children: j
|
|
62
|
+
}) : j
|
|
63
|
+
}),
|
|
64
|
+
b && /* @__PURE__ */ f(n, {
|
|
65
|
+
ref: k,
|
|
66
|
+
size: "icon",
|
|
67
|
+
variant: "ghost",
|
|
68
|
+
disabled: x,
|
|
69
|
+
"aria-label": `${S} ${l}`,
|
|
70
|
+
onClick: () => D(!0),
|
|
71
|
+
children: /* @__PURE__ */ f(u, {})
|
|
72
|
+
}),
|
|
73
|
+
y && /* @__PURE__ */ f("div", {
|
|
74
|
+
className: "flex shrink-0 items-center gap-1",
|
|
75
|
+
children: y
|
|
76
|
+
})
|
|
77
|
+
]
|
|
78
|
+
})
|
|
79
|
+
});
|
|
80
|
+
}
|
|
81
|
+
function h({ icon: e = /* @__PURE__ */ f(l, { className: "size-4" }), ...t }) {
|
|
82
|
+
return /* @__PURE__ */ f(m, {
|
|
83
|
+
icon: e,
|
|
84
|
+
...t
|
|
85
|
+
});
|
|
86
|
+
}
|
|
87
|
+
//#endregion
|
|
88
|
+
export { m as EditableNavItem, h as FolderNavItem };
|
|
89
|
+
|
|
90
|
+
//# sourceMappingURL=editable-nav-item.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"editable-nav-item.js","names":[],"sources":["../../src/components/editable-nav-item.tsx"],"sourcesContent":["import { Folder, Pencil } from \"lucide-react\";\nimport { type ReactNode, useId, useLayoutEffect, useRef, useState } from \"react\";\nimport { cn } from \"../utils/cn\";\nimport { BASALT_UI_CLASS } from \"../utils/control-surface\";\nimport { Button } from \"./button\";\nimport { InlineEditable } from \"./inline-editable\";\nimport { Link } from \"./link\";\n\nexport interface EditableNavItemProps {\n\t/** Current display name. */\n\tlabel: string;\n\t/** Application route, interpreted by LinkProvider. */\n\thref?: string;\n\t/** Navigation/selection request. */\n\tonSelect?: () => void;\n\t/** Selected location. @default false */\n\tselected?: boolean;\n\t/** Caller-owned leading icon. */\n\ticon?: ReactNode;\n\t/** Caller-formatted count or status. */\n\tcount?: ReactNode;\n\t/** Separate row actions, never nested inside the navigation button/link. */\n\tactions?: ReactNode;\n\t/** Enable renaming; rejected promises keep the editor and draft available. */\n\tonRename?: (name: string) => void | Promise<void>;\n\t/** Disable navigation and renaming. Application action slots retain their own permissions. @default false */\n\tdisabled?: boolean;\n\t/** Rename action prefix. @default \"Rename\" */\n\trenameLabel?: string;\n\t/** Accessible save action. @default \"Save\" */\n\tsaveLabel?: string;\n\t/** Accessible cancel action. @default \"Cancel\" */\n\tcancelLabel?: string;\n\t/** Additional root classes. */\n\tclassName?: string;\n}\nexport function EditableNavItem({\n\tlabel,\n\thref,\n\tonSelect,\n\tselected = false,\n\ticon,\n\tcount,\n\tactions,\n\tonRename,\n\tdisabled = false,\n\trenameLabel = \"Rename\",\n\tsaveLabel = \"Save\",\n\tcancelLabel = \"Cancel\",\n\tclassName,\n}: EditableNavItemProps) {\n\tconst [editing, setEditing] = useState(false);\n\tconst countId = useId();\n\tconst rename = useRef<HTMLButtonElement>(null);\n\tconst restore = useRef(false);\n\tuseLayoutEffect(() => {\n\t\tif (!editing && restore.current) {\n\t\t\trestore.current = false;\n\t\t\trename.current?.focus();\n\t\t}\n\t}, [editing]);\n\tconst content = (\n\t\t<>\n\t\t\t<span className=\"shrink-0\" aria-hidden=\"true\">\n\t\t\t\t{icon}\n\t\t\t</span>\n\t\t\t<span className=\"min-w-0 flex-1 truncate text-left\">{label}</span>\n\t\t\t{count != null && (\n\t\t\t\t<span id={countId} className=\"shrink-0 text-xs tabular-nums text-basalt-muted-foreground\">\n\t\t\t\t\t{\" \"}\n\t\t\t\t\t{count}\n\t\t\t\t</span>\n\t\t\t)}\n\t\t</>\n\t);\n\treturn (\n\t\t<div\n\t\t\tclassName={cn(\n\t\t\t\tBASALT_UI_CLASS,\n\t\t\t\t\"min-w-0 rounded-basalt-md\",\n\t\t\t\tselected && \"bg-basalt-accent\",\n\t\t\t\tclassName,\n\t\t\t)}\n\t\t>\n\t\t\t{editing && onRename ? (\n\t\t\t\t<InlineEditable\n\t\t\t\t\tclassName=\"p-2\"\n\t\t\t\t\tlabel={`${renameLabel} ${label}`}\n\t\t\t\t\tvalue={label}\n\t\t\t\t\tediting\n\t\t\t\t\tonSave={onRename}\n\t\t\t\t\tsaveLabel={saveLabel}\n\t\t\t\t\tcancelLabel={cancelLabel}\n\t\t\t\t\tdisabled={disabled}\n\t\t\t\t\tonEditingChange={(next, reason) => {\n\t\t\t\t\t\trestore.current = !next && reason !== \"blur\";\n\t\t\t\t\t\tsetEditing(next);\n\t\t\t\t\t}}\n\t\t\t\t/>\n\t\t\t) : (\n\t\t\t\t<div className=\"flex min-w-0 items-center gap-1\">\n\t\t\t\t\t<Button\n\t\t\t\t\t\tasChild={!!href}\n\t\t\t\t\t\tvariant=\"ghost\"\n\t\t\t\t\t\tdisabled={disabled}\n\t\t\t\t\t\tclassName=\"min-w-0 flex-1 justify-start gap-2\"\n\t\t\t\t\t\taria-current={selected ? \"page\" : undefined}\n\t\t\t\t\t\taria-label={label}\n\t\t\t\t\t\taria-describedby={count != null ? countId : undefined}\n\t\t\t\t\t\tonClick={onSelect}\n\t\t\t\t\t>\n\t\t\t\t\t\t{href ? (\n\t\t\t\t\t\t\t<Link href={href} className=\"text-inherit no-underline hover:no-underline\">\n\t\t\t\t\t\t\t\t{content}\n\t\t\t\t\t\t\t</Link>\n\t\t\t\t\t\t) : (\n\t\t\t\t\t\t\tcontent\n\t\t\t\t\t\t)}\n\t\t\t\t\t</Button>\n\t\t\t\t\t{onRename && (\n\t\t\t\t\t\t<Button\n\t\t\t\t\t\t\tref={rename}\n\t\t\t\t\t\t\tsize=\"icon\"\n\t\t\t\t\t\t\tvariant=\"ghost\"\n\t\t\t\t\t\t\tdisabled={disabled}\n\t\t\t\t\t\t\taria-label={`${renameLabel} ${label}`}\n\t\t\t\t\t\t\tonClick={() => setEditing(true)}\n\t\t\t\t\t\t>\n\t\t\t\t\t\t\t<Pencil />\n\t\t\t\t\t\t</Button>\n\t\t\t\t\t)}\n\t\t\t\t\t{actions && <div className=\"flex shrink-0 items-center gap-1\">{actions}</div>}\n\t\t\t\t</div>\n\t\t\t)}\n\t\t</div>\n\t);\n}\n\nexport type FolderNavItemProps = EditableNavItemProps;\n/** Folder presentation with an overridable icon; no tree, router or permission model. */\nexport function FolderNavItem({\n\ticon = <Folder className=\"size-4\" />,\n\t...props\n}: FolderNavItemProps) {\n\treturn <EditableNavItem icon={icon} {...props} />;\n}\n"],"mappings":";;;;;;;;;;AAoCA,SAAgB,EAAgB,EAC/B,UACA,SACA,aACA,cAAW,IACX,SACA,UACA,YACA,aACA,cAAW,IACX,iBAAc,UACd,eAAY,QACZ,iBAAc,UACd,gBACwB;CACxB,IAAM,CAAC,GAAS,KAAc,EAAS,EAAK,GACtC,IAAU,EAAM,GAChB,IAAS,EAA0B,IAAI,GACvC,IAAU,EAAO,EAAK;CAC5B,QAAsB;EACrB,AAAI,CAAC,KAAW,EAAQ,YACvB,EAAQ,UAAU,IAClB,EAAO,SAAS,MAAM;CAExB,GAAG,CAAC,CAAO,CAAC;CACZ,IAAM,IACL,kBAAA,GAAA,EAAA,UAAA;EACC,kBAAC,QAAD;GAAM,WAAU;GAAW,eAAY;GACrC,UAAA;EACI,CAAA;EACN,kBAAC,QAAD;GAAM,WAAU;GAAqC,UAAA;EAAY,CAAA;EAChE,KAAS,QACT,kBAAC,QAAD;GAAM,IAAI;GAAS,WAAU;GAA7B,UAAA,CACE,KACA,CACI;;CAEN,EAAA,CAAA;CAEH,OACC,kBAAC,OAAD;EACC,WAAW,EACV,GACA,6BACA,KAAY,oBACZ,CACD;EAEC,UAAA,KAAW,IACX,kBAAC,GAAD;GACC,WAAU;GACV,OAAO,GAAG,EAAY,GAAG;GACzB,OAAO;GACP,SAAA;GACA,QAAQ;GACG;GACE;GACH;GACV,kBAAkB,GAAM,MAAW;IAElC,AADA,EAAQ,UAAU,CAAC,KAAQ,MAAW,QACtC,EAAW,CAAI;GAChB;EACA,CAAA,IAED,kBAAC,OAAD;GAAK,WAAU;GAAf,UAAA;IACC,kBAAC,GAAD;KACC,SAAS,CAAC,CAAC;KACX,SAAQ;KACE;KACV,WAAU;KACV,gBAAc,IAAW,SAAS,KAAA;KAClC,cAAY;KACZ,oBAAkB,KAAS,OAAiB,KAAA,IAAV;KAClC,SAAS;KAER,UAAA,IACA,kBAAC,GAAD;MAAY;MAAM,WAAU;MAC1B,UAAA;KACI,CAAA,IAEN;IAEM,CAAA;IACP,KACA,kBAAC,GAAD;KACC,KAAK;KACL,MAAK;KACL,SAAQ;KACE;KACV,cAAY,GAAG,EAAY,GAAG;KAC9B,eAAe,EAAW,EAAI;KAE9B,UAAA,kBAAC,GAAD,CAAS,CAAA;IACF,CAAA;IAER,KAAW,kBAAC,OAAD;KAAK,WAAU;KAAoC,UAAA;IAAa,CAAA;GACxE;;CAEF,CAAA;AAEP;AAIA,SAAgB,EAAc,EAC7B,UAAO,kBAAC,GAAD,EAAQ,WAAU,SAAU,CAAA,GACnC,GAAG,KACmB;CACtB,OAAO,kBAAC,GAAD;EAAuB;EAAM,GAAI;CAAQ,CAAA;AACjD"}
|
|
@@ -1,6 +1,26 @@
|
|
|
1
1
|
import type { HTMLAttributes, ReactNode } from "react";
|
|
2
|
-
export
|
|
2
|
+
export interface EmptyProps extends Omit<HTMLAttributes<HTMLDivElement>, "title" | "children"> {
|
|
3
|
+
/**
|
|
4
|
+
* Primary title text displayed in the empty state.
|
|
5
|
+
*
|
|
6
|
+
* @default "No results"
|
|
7
|
+
*/
|
|
3
8
|
title?: string;
|
|
9
|
+
/**
|
|
10
|
+
* Secondary supporting description text rendered below the title.
|
|
11
|
+
*/
|
|
4
12
|
description?: string;
|
|
13
|
+
/**
|
|
14
|
+
* Visual icon element rendered above the title.
|
|
15
|
+
*/
|
|
5
16
|
icon?: ReactNode;
|
|
6
|
-
|
|
17
|
+
/**
|
|
18
|
+
* Interactive call-to-action element (e.g. Button or Link) rendered below content.
|
|
19
|
+
*/
|
|
20
|
+
action?: ReactNode;
|
|
21
|
+
/**
|
|
22
|
+
* Custom supporting content or custom layout rendered between description and action.
|
|
23
|
+
*/
|
|
24
|
+
children?: ReactNode;
|
|
25
|
+
}
|
|
26
|
+
export declare function Empty({ title, description, icon, action, children, className, ...props }: EmptyProps): import("react").JSX.Element;
|
package/dist/components/empty.js
CHANGED
|
@@ -1,28 +1,37 @@
|
|
|
1
1
|
"use client";
|
|
2
2
|
import { cn as e } from "../utils/cn.js";
|
|
3
|
-
import {
|
|
3
|
+
import { BASALT_UI_CLASS as t } from "../utils/control-surface.js";
|
|
4
|
+
import { jsx as n, jsxs as r } from "react/jsx-runtime";
|
|
4
5
|
//#region src/components/empty.tsx
|
|
5
|
-
function
|
|
6
|
-
return /* @__PURE__ */
|
|
7
|
-
className: e("flex flex-col items-center gap-2 text-center",
|
|
8
|
-
...
|
|
6
|
+
function i({ title: i = "No results", description: a, icon: o, action: s, children: c, className: l, ...u }) {
|
|
7
|
+
return /* @__PURE__ */ r("div", {
|
|
8
|
+
className: e(t, "flex flex-col items-center gap-2 text-center", l),
|
|
9
|
+
...u,
|
|
9
10
|
children: [
|
|
10
|
-
|
|
11
|
+
o ? /* @__PURE__ */ n("div", {
|
|
11
12
|
className: "text-basalt-muted-foreground [&_svg]:size-8",
|
|
12
|
-
children:
|
|
13
|
+
children: o
|
|
13
14
|
}) : null,
|
|
14
|
-
/* @__PURE__ */
|
|
15
|
+
/* @__PURE__ */ n("p", {
|
|
15
16
|
className: "text-sm font-medium text-basalt-foreground",
|
|
16
|
-
children:
|
|
17
|
+
children: i
|
|
17
18
|
}),
|
|
18
|
-
|
|
19
|
+
a ? /* @__PURE__ */ n("p", {
|
|
19
20
|
className: "text-xs text-basalt-muted-foreground",
|
|
20
|
-
children:
|
|
21
|
-
}) : null
|
|
21
|
+
children: a
|
|
22
|
+
}) : null,
|
|
23
|
+
c == null ? null : /* @__PURE__ */ n("div", {
|
|
24
|
+
className: "text-xs text-basalt-muted-foreground",
|
|
25
|
+
children: c
|
|
26
|
+
}),
|
|
27
|
+
s == null ? null : /* @__PURE__ */ n("div", {
|
|
28
|
+
className: "mt-2 flex items-center justify-center gap-2",
|
|
29
|
+
children: s
|
|
30
|
+
})
|
|
22
31
|
]
|
|
23
32
|
});
|
|
24
33
|
}
|
|
25
34
|
//#endregion
|
|
26
|
-
export {
|
|
35
|
+
export { i as Empty };
|
|
27
36
|
|
|
28
37
|
//# sourceMappingURL=empty.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"empty.js","names":[],"sources":["../../src/components/empty.tsx"],"sourcesContent":["import type { HTMLAttributes, ReactNode } from \"react\";\nimport { cn } from \"../utils/cn\";\n\nexport function Empty({\n\ttitle = \"No results\",\n\tdescription,\n\ticon,\n\tclassName,\n\t...props\n}:
|
|
1
|
+
{"version":3,"file":"empty.js","names":[],"sources":["../../src/components/empty.tsx"],"sourcesContent":["import type { HTMLAttributes, ReactNode } from \"react\";\nimport { cn } from \"../utils/cn\";\nimport { BASALT_UI_CLASS } from \"../utils/control-surface\";\n\nexport interface EmptyProps extends Omit<HTMLAttributes<HTMLDivElement>, \"title\" | \"children\"> {\n\t/**\n\t * Primary title text displayed in the empty state.\n\t *\n\t * @default \"No results\"\n\t */\n\ttitle?: string;\n\n\t/**\n\t * Secondary supporting description text rendered below the title.\n\t */\n\tdescription?: string;\n\n\t/**\n\t * Visual icon element rendered above the title.\n\t */\n\ticon?: ReactNode;\n\n\t/**\n\t * Interactive call-to-action element (e.g. Button or Link) rendered below content.\n\t */\n\taction?: ReactNode;\n\n\t/**\n\t * Custom supporting content or custom layout rendered between description and action.\n\t */\n\tchildren?: ReactNode;\n}\n\nexport function Empty({\n\ttitle = \"No results\",\n\tdescription,\n\ticon,\n\taction,\n\tchildren,\n\tclassName,\n\t...props\n}: EmptyProps) {\n\treturn (\n\t\t<div\n\t\t\tclassName={cn(BASALT_UI_CLASS, \"flex flex-col items-center gap-2 text-center\", className)}\n\t\t\t{...props}\n\t\t>\n\t\t\t{icon ? <div className=\"text-basalt-muted-foreground [&_svg]:size-8\">{icon}</div> : null}\n\t\t\t<p className=\"text-sm font-medium text-basalt-foreground\">{title}</p>\n\t\t\t{description ? <p className=\"text-xs text-basalt-muted-foreground\">{description}</p> : null}\n\t\t\t{children !== undefined && children !== null ? (\n\t\t\t\t<div className=\"text-xs text-basalt-muted-foreground\">{children}</div>\n\t\t\t) : null}\n\t\t\t{action !== undefined && action !== null ? (\n\t\t\t\t<div className=\"mt-2 flex items-center justify-center gap-2\">{action}</div>\n\t\t\t) : null}\n\t\t</div>\n\t);\n}\n"],"mappings":";;;;;AAiCA,SAAgB,EAAM,EACrB,WAAQ,cACR,gBACA,SACA,WACA,aACA,cACA,GAAG,KACW;CACd,OACC,kBAAC,OAAD;EACC,WAAW,EAAG,GAAiB,gDAAgD,CAAS;EACxF,GAAI;EAFL,UAAA;GAIE,IAAO,kBAAC,OAAD;IAAK,WAAU;IAA+C,UAAA;GAAU,CAAA,IAAI;GACpF,kBAAC,KAAD;IAAG,WAAU;IAA8C,UAAA;GAAS,CAAA;GACnE,IAAc,kBAAC,KAAD;IAAG,WAAU;IAAwC,UAAA;GAAe,CAAA,IAAI;GACtF,KAAuC,OAEpC,OADH,kBAAC,OAAD;IAAK,WAAU;IAAwC;GAAc,CAAA;GAErE,KAAmC,OAEhC,OADH,kBAAC,OAAD;IAAK,WAAU;IAA+C,UAAA;GAAY,CAAA;EAEvE;;AAEP"}
|
package/dist/components/field.js
CHANGED
|
@@ -1,52 +1,53 @@
|
|
|
1
1
|
"use client";
|
|
2
2
|
import { cn as e } from "../utils/cn.js";
|
|
3
|
-
import {
|
|
4
|
-
import
|
|
5
|
-
import
|
|
3
|
+
import { BASALT_UI_CLASS as t } from "../utils/control-surface.js";
|
|
4
|
+
import { Label as n } from "./label.js";
|
|
5
|
+
import * as r from "react";
|
|
6
|
+
import { jsx as i, jsxs as a } from "react/jsx-runtime";
|
|
6
7
|
//#region src/components/field.tsx
|
|
7
|
-
function a(e) {
|
|
8
|
-
return typeof e == "object" && !!e && !Array.isArray(e) && !n.isValidElement(e) && "message" in e;
|
|
9
|
-
}
|
|
10
8
|
function o(e) {
|
|
11
|
-
|
|
9
|
+
return typeof e == "object" && !!e && !Array.isArray(e) && !r.isValidElement(e) && "message" in e;
|
|
12
10
|
}
|
|
13
11
|
function s(e) {
|
|
12
|
+
if (e != null) return o(e) ? e.message : e;
|
|
13
|
+
}
|
|
14
|
+
function c(e) {
|
|
14
15
|
return !!e;
|
|
15
16
|
}
|
|
16
|
-
var
|
|
17
|
-
let
|
|
18
|
-
return /* @__PURE__ */
|
|
19
|
-
ref:
|
|
20
|
-
...
|
|
21
|
-
className: e("flex flex-col gap-1.5",
|
|
17
|
+
var l = r.forwardRef(({ label: o, htmlFor: l, hint: u, error: d, required: f, labelTooltip: p, className: m, children: h, ...g }, _) => {
|
|
18
|
+
let v = r.useId(), y = r.isValidElement(h) ? h : null, b = y ? l ?? y.props.id ?? v : l, x = b ? `${b}-hint` : void 0, S = b ? `${b}-error` : void 0, C = s(d), w = c(C), T = [[w ? S : null, !w && u ? x : null].filter(Boolean).join(" "), y?.props["aria-describedby"]].filter(Boolean).join(" ");
|
|
19
|
+
return /* @__PURE__ */ a("div", {
|
|
20
|
+
ref: _,
|
|
21
|
+
...g,
|
|
22
|
+
className: e(t, "flex flex-col gap-1.5", m),
|
|
22
23
|
children: [
|
|
23
|
-
/* @__PURE__ */
|
|
24
|
-
htmlFor:
|
|
25
|
-
showOptional:
|
|
26
|
-
tooltip:
|
|
27
|
-
children:
|
|
24
|
+
/* @__PURE__ */ i(n, {
|
|
25
|
+
htmlFor: b,
|
|
26
|
+
showOptional: f === !1,
|
|
27
|
+
tooltip: p,
|
|
28
|
+
children: o
|
|
28
29
|
}),
|
|
29
|
-
|
|
30
|
-
id: y,
|
|
31
|
-
"aria-invalid": C ? !0 : v.props["aria-invalid"],
|
|
32
|
-
"aria-describedby": w || void 0
|
|
33
|
-
}) : m,
|
|
34
|
-
l && !C ? /* @__PURE__ */ r("p", {
|
|
30
|
+
y ? r.cloneElement(y, {
|
|
35
31
|
id: b,
|
|
32
|
+
"aria-invalid": w ? !0 : y.props["aria-invalid"],
|
|
33
|
+
"aria-describedby": T || void 0
|
|
34
|
+
}) : h,
|
|
35
|
+
u && !w ? /* @__PURE__ */ i("p", {
|
|
36
|
+
id: x,
|
|
36
37
|
className: "text-xs text-basalt-muted-foreground",
|
|
37
|
-
children:
|
|
38
|
+
children: u
|
|
38
39
|
}) : null,
|
|
39
|
-
|
|
40
|
-
id:
|
|
40
|
+
w ? /* @__PURE__ */ i("p", {
|
|
41
|
+
id: S,
|
|
41
42
|
className: "text-xs text-basalt-destructive",
|
|
42
43
|
role: "alert",
|
|
43
|
-
children:
|
|
44
|
+
children: C
|
|
44
45
|
}) : null
|
|
45
46
|
]
|
|
46
47
|
});
|
|
47
48
|
});
|
|
48
|
-
|
|
49
|
+
l.displayName = "Field";
|
|
49
50
|
//#endregion
|
|
50
|
-
export {
|
|
51
|
+
export { l as Field };
|
|
51
52
|
|
|
52
53
|
//# sourceMappingURL=field.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"field.js","names":[],"sources":["../../src/components/field.tsx"],"sourcesContent":["import * as React from \"react\";\nimport { cn } from \"../utils/cn\";\nimport { Label } from \"./label\";\n\nexport type FieldError = Exclude<React.ReactNode, undefined> | { message: React.ReactNode };\n\ntype FieldControlProps = {\n\tid?: string;\n\t\"aria-describedby\"?: string;\n\t\"aria-invalid\"?: boolean | \"true\" | \"false\";\n};\n\nexport interface FieldProps\n\textends Omit<React.ComponentPropsWithoutRef<\"div\">, \"children\" | \"className\"> {\n\t/**\n\t * Visible label.\n\t */\n\tlabel: React.ReactNode;\n\t/**\n\t * Associates the label and described-by ids.\n\t */\n\thtmlFor?: string;\n\t/**\n\t * Supporting text when there is no error.\n\t */\n\thint?: React.ReactNode;\n\t/**\n\t * Replaces the hint and marks the control invalid.\n\t */\n\terror?: FieldError;\n\t/**\n\t * When false, show (optional) after the label.\n\t */\n\trequired?: boolean;\n\t/**\n\t * Info icon with hover text on the label.\n\t */\n\tlabelTooltip?: React.ReactNode;\n\t/**\n\t * Additional classes for the field root.\n\t */\n\tclassName?: string;\n\t/**\n\t * The control or content to render.\n\t */\n\tchildren: React.ReactNode;\n}\n\nfunction isStructuredError(error: FieldError): error is { message: React.ReactNode } {\n\treturn (\n\t\ttypeof error === \"object\" &&\n\t\terror !== null &&\n\t\t!Array.isArray(error) &&\n\t\t!React.isValidElement(error) &&\n\t\t\"message\" in error\n\t);\n}\n\nfunction fieldErrorMessage(error: FieldError | undefined): React.ReactNode | undefined {\n\tif (error == null) {\n\t\treturn undefined;\n\t}\n\treturn isStructuredError(error) ? error.message : error;\n}\n\nfunction hasFieldError(message: React.ReactNode | undefined): boolean {\n\treturn Boolean(message);\n}\n\nexport const Field = React.forwardRef<HTMLDivElement, FieldProps>(\n\t({ label, htmlFor, hint, error, required, labelTooltip, className, children, ...props }, ref) => {\n\t\tconst generatedId = React.useId();\n\t\tconst child = React.isValidElement(children)\n\t\t\t? (children as React.ReactElement<FieldControlProps>)\n\t\t\t: null;\n\t\tconst controlId = child ? (htmlFor ?? child.props.id ?? generatedId) : htmlFor;\n\t\tconst hintId = controlId ? `${controlId}-hint` : undefined;\n\t\tconst errorId = controlId ? `${controlId}-error` : undefined;\n\t\tconst errorMessage = fieldErrorMessage(error);\n\t\tconst hasError = hasFieldError(errorMessage);\n\t\tconst describedBy = [hasError ? errorId : null, !hasError && hint ? hintId : null]\n\t\t\t.filter(Boolean)\n\t\t\t.join(\" \");\n\t\tconst mergedDescribedBy = [describedBy, child?.props[\"aria-describedby\"]]\n\t\t\t.filter(Boolean)\n\t\t\t.join(\" \");\n\t\treturn (\n\t\t\t<div ref={ref} {...props} className={cn(\"flex flex-col gap-1.5\", className)}>\n\t\t\t\t<Label htmlFor={controlId} showOptional={required === false} tooltip={labelTooltip}>\n\t\t\t\t\t{label}\n\t\t\t\t</Label>\n\t\t\t\t{child\n\t\t\t\t\t? React.cloneElement(child, {\n\t\t\t\t\t\t\tid: controlId,\n\t\t\t\t\t\t\t\"aria-invalid\": hasError ? true : child.props[\"aria-invalid\"],\n\t\t\t\t\t\t\t\"aria-describedby\": mergedDescribedBy || undefined,\n\t\t\t\t\t\t})\n\t\t\t\t\t: children}\n\t\t\t\t{hint && !hasError ? (\n\t\t\t\t\t<p id={hintId} className=\"text-xs text-basalt-muted-foreground\">\n\t\t\t\t\t\t{hint}\n\t\t\t\t\t</p>\n\t\t\t\t) : null}\n\t\t\t\t{hasError ? (\n\t\t\t\t\t<p id={errorId} className=\"text-xs text-basalt-destructive\" role=\"alert\">\n\t\t\t\t\t\t{errorMessage}\n\t\t\t\t\t</p>\n\t\t\t\t) : null}\n\t\t\t</div>\n\t\t);\n\t},\n);\nField.displayName = \"Field\";\n"],"mappings":"
|
|
1
|
+
{"version":3,"file":"field.js","names":[],"sources":["../../src/components/field.tsx"],"sourcesContent":["import * as React from \"react\";\nimport { cn } from \"../utils/cn\";\nimport { BASALT_UI_CLASS } from \"../utils/control-surface\";\nimport { Label } from \"./label\";\n\nexport type FieldError = Exclude<React.ReactNode, undefined> | { message: React.ReactNode };\n\ntype FieldControlProps = {\n\tid?: string;\n\t\"aria-describedby\"?: string;\n\t\"aria-invalid\"?: boolean | \"true\" | \"false\";\n};\n\nexport interface FieldProps\n\textends Omit<React.ComponentPropsWithoutRef<\"div\">, \"children\" | \"className\"> {\n\t/**\n\t * Visible label.\n\t */\n\tlabel: React.ReactNode;\n\t/**\n\t * Associates the label and described-by ids.\n\t */\n\thtmlFor?: string;\n\t/**\n\t * Supporting text when there is no error.\n\t */\n\thint?: React.ReactNode;\n\t/**\n\t * Replaces the hint and marks the control invalid.\n\t */\n\terror?: FieldError;\n\t/**\n\t * When false, show (optional) after the label.\n\t */\n\trequired?: boolean;\n\t/**\n\t * Info icon with hover text on the label.\n\t */\n\tlabelTooltip?: React.ReactNode;\n\t/**\n\t * Additional classes for the field root.\n\t */\n\tclassName?: string;\n\t/**\n\t * The control or content to render.\n\t */\n\tchildren: React.ReactNode;\n}\n\nfunction isStructuredError(error: FieldError): error is { message: React.ReactNode } {\n\treturn (\n\t\ttypeof error === \"object\" &&\n\t\terror !== null &&\n\t\t!Array.isArray(error) &&\n\t\t!React.isValidElement(error) &&\n\t\t\"message\" in error\n\t);\n}\n\nfunction fieldErrorMessage(error: FieldError | undefined): React.ReactNode | undefined {\n\tif (error == null) {\n\t\treturn undefined;\n\t}\n\treturn isStructuredError(error) ? error.message : error;\n}\n\nfunction hasFieldError(message: React.ReactNode | undefined): boolean {\n\treturn Boolean(message);\n}\n\nexport const Field = React.forwardRef<HTMLDivElement, FieldProps>(\n\t({ label, htmlFor, hint, error, required, labelTooltip, className, children, ...props }, ref) => {\n\t\tconst generatedId = React.useId();\n\t\tconst child = React.isValidElement(children)\n\t\t\t? (children as React.ReactElement<FieldControlProps>)\n\t\t\t: null;\n\t\tconst controlId = child ? (htmlFor ?? child.props.id ?? generatedId) : htmlFor;\n\t\tconst hintId = controlId ? `${controlId}-hint` : undefined;\n\t\tconst errorId = controlId ? `${controlId}-error` : undefined;\n\t\tconst errorMessage = fieldErrorMessage(error);\n\t\tconst hasError = hasFieldError(errorMessage);\n\t\tconst describedBy = [hasError ? errorId : null, !hasError && hint ? hintId : null]\n\t\t\t.filter(Boolean)\n\t\t\t.join(\" \");\n\t\tconst mergedDescribedBy = [describedBy, child?.props[\"aria-describedby\"]]\n\t\t\t.filter(Boolean)\n\t\t\t.join(\" \");\n\t\treturn (\n\t\t\t<div ref={ref} {...props} className={cn(BASALT_UI_CLASS, \"flex flex-col gap-1.5\", className)}>\n\t\t\t\t<Label htmlFor={controlId} showOptional={required === false} tooltip={labelTooltip}>\n\t\t\t\t\t{label}\n\t\t\t\t</Label>\n\t\t\t\t{child\n\t\t\t\t\t? React.cloneElement(child, {\n\t\t\t\t\t\t\tid: controlId,\n\t\t\t\t\t\t\t\"aria-invalid\": hasError ? true : child.props[\"aria-invalid\"],\n\t\t\t\t\t\t\t\"aria-describedby\": mergedDescribedBy || undefined,\n\t\t\t\t\t\t})\n\t\t\t\t\t: children}\n\t\t\t\t{hint && !hasError ? (\n\t\t\t\t\t<p id={hintId} className=\"text-xs text-basalt-muted-foreground\">\n\t\t\t\t\t\t{hint}\n\t\t\t\t\t</p>\n\t\t\t\t) : null}\n\t\t\t\t{hasError ? (\n\t\t\t\t\t<p id={errorId} className=\"text-xs text-basalt-destructive\" role=\"alert\">\n\t\t\t\t\t\t{errorMessage}\n\t\t\t\t\t</p>\n\t\t\t\t) : null}\n\t\t\t</div>\n\t\t);\n\t},\n);\nField.displayName = \"Field\";\n"],"mappings":";;;;;;;AAiDA,SAAS,EAAkB,GAA0D;CACpF,OACC,OAAO,KAAU,cACjB,KACA,CAAC,MAAM,QAAQ,CAAK,KACpB,CAAC,EAAM,eAAe,CAAK,KAC3B,aAAa;AAEf;AAEA,SAAS,EAAkB,GAA4D;CAClF,SAAS,MAGb,OAAO,EAAkB,CAAK,IAAI,EAAM,UAAU;AACnD;AAEA,SAAS,EAAc,GAA+C;CACrE,OAAO,EAAQ;AAChB;AAEA,IAAa,IAAQ,EAAM,YACzB,EAAE,UAAO,YAAS,SAAM,UAAO,aAAU,iBAAc,cAAW,aAAU,GAAG,KAAS,MAAQ;CAChG,IAAM,IAAc,EAAM,MAAM,GAC1B,IAAQ,EAAM,eAAe,CAAQ,IACvC,IACD,MACG,IAAY,IAAS,KAAW,EAAM,MAAM,MAAM,IAAe,GACjE,IAAS,IAAY,GAAG,EAAU,SAAS,KAAA,GAC3C,IAAU,IAAY,GAAG,EAAU,UAAU,KAAA,GAC7C,IAAe,EAAkB,CAAK,GACtC,IAAW,EAAc,CAAY,GAIrC,IAAoB,CAHN,CAAC,IAAW,IAAU,MAAM,CAAC,KAAY,IAAO,IAAS,IAAI,CAAC,CAChF,OAAO,OAAO,CAAC,CACf,KAAK,GACoB,GAAa,GAAO,MAAM,mBAAmB,CAAC,CACvE,OAAO,OAAO,CAAC,CACf,KAAK,GAAG;CACV,OACC,kBAAC,OAAD;EAAU;EAAK,GAAI;EAAO,WAAW,EAAG,GAAiB,yBAAyB,CAAS;EAA3F,UAAA;GACC,kBAAC,GAAD;IAAO,SAAS;IAAW,cAAc,MAAa;IAAO,SAAS;IACpE,UAAA;GACK,CAAA;GACN,IACE,EAAM,aAAa,GAAO;IAC1B,IAAI;IACJ,gBAAgB,IAAW,KAAO,EAAM,MAAM;IAC9C,oBAAoB,KAAqB,KAAA;GAC1C,CAAC,IACA;GACF,KAAQ,CAAC,IACT,kBAAC,KAAD;IAAG,IAAI;IAAQ,WAAU;IACvB,UAAA;GACC,CAAA,IACA;GACH,IACA,kBAAC,KAAD;IAAG,IAAI;IAAS,WAAU;IAAkC,MAAK;IAC/D,UAAA;GACC,CAAA,IACA;EACA;;AAEP,CACD;AACA,EAAM,cAAc"}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
export interface FileRejection {
|
|
2
|
+
/** Original File; the component never creates preview URLs. */
|
|
3
|
+
file: File;
|
|
4
|
+
/** Machine-readable reason for application handling. */
|
|
5
|
+
code: "file-invalid-type" | "file-too-large" | "too-many-files";
|
|
6
|
+
}
|
|
7
|
+
export interface FileDropzoneProps {
|
|
8
|
+
/** Visible and accessible upload field name. */
|
|
9
|
+
label: string;
|
|
10
|
+
/** Optional file requirements shown under the label. */
|
|
11
|
+
description?: string;
|
|
12
|
+
/** Accepted extensions/MIME types using native accept syntax, e.g. .pdf,image/*. */
|
|
13
|
+
accept?: string;
|
|
14
|
+
/** Allow multiple files. @default true */
|
|
15
|
+
multiple?: boolean;
|
|
16
|
+
/** Maximum accepted file count including fileCount. @default Infinity */
|
|
17
|
+
maxFiles?: number;
|
|
18
|
+
/** Number already held by the application. @default 0 */
|
|
19
|
+
fileCount?: number;
|
|
20
|
+
/** Maximum size of an individual file in bytes. @default Infinity */
|
|
21
|
+
maxSize?: number;
|
|
22
|
+
/** Prevent both file browsing and drops. @default false */
|
|
23
|
+
disabled?: boolean;
|
|
24
|
+
/** Accepted files from this gesture; transport and queue ownership belong to the caller. */
|
|
25
|
+
onFilesAccepted: (files: File[]) => void;
|
|
26
|
+
/** Rejected files from this gesture, with one primary reason per file. */
|
|
27
|
+
onFilesRejected?: (rejections: FileRejection[]) => void;
|
|
28
|
+
/** Browse action text. @default "Browse files" */
|
|
29
|
+
browseLabel?: string;
|
|
30
|
+
/** Text while a file is dragged over the field. @default "Drop files here" */
|
|
31
|
+
dropLabel?: string;
|
|
32
|
+
/** Localized rejection message; defaults to a name and reason. */
|
|
33
|
+
formatRejection?: (rejection: FileRejection) => string;
|
|
34
|
+
/** Additional root classes. */
|
|
35
|
+
className?: string;
|
|
36
|
+
}
|
|
37
|
+
export declare function FileDropzone({ label, description, accept, multiple, maxFiles, fileCount, maxSize, disabled, onFilesAccepted, onFilesRejected, browseLabel, dropLabel, formatRejection, className, }: FileDropzoneProps): import("react").JSX.Element;
|
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { cn as e } from "../utils/cn.js";
|
|
3
|
+
import { BASALT_UI_CLASS as t } from "../utils/control-surface.js";
|
|
4
|
+
import { useId as n, useRef as r, useState as i } from "react";
|
|
5
|
+
import { Upload as a } from "lucide-react";
|
|
6
|
+
import { jsx as o, jsxs as s } from "react/jsx-runtime";
|
|
7
|
+
//#region src/components/file-dropzone.tsx
|
|
8
|
+
function c(e, t) {
|
|
9
|
+
let n = t.split(",").map((e) => e.trim().toLowerCase()).filter(Boolean);
|
|
10
|
+
return n.length === 0 || n.some((t) => t.startsWith(".") ? e.name.toLowerCase().endsWith(t) : t.endsWith("/*") ? e.type.toLowerCase().startsWith(t.slice(0, -1)) : e.type.toLowerCase() === t);
|
|
11
|
+
}
|
|
12
|
+
var l = {
|
|
13
|
+
"file-invalid-type": "File type is not accepted.",
|
|
14
|
+
"file-too-large": "File exceeds the size limit.",
|
|
15
|
+
"too-many-files": "File count limit reached."
|
|
16
|
+
};
|
|
17
|
+
function u({ label: u, description: d, accept: f = "", multiple: p = !0, maxFiles: m = Infinity, fileCount: h = 0, maxSize: g = Infinity, disabled: _ = !1, onFilesAccepted: v, onFilesRejected: y, browseLabel: b = "Browse files", dropLabel: x = "Drop files here", formatRejection: S, className: C }) {
|
|
18
|
+
let w = r(null), T = r(0), [E, D] = i(!1), [O, k] = i([]), A = n();
|
|
19
|
+
function j(e) {
|
|
20
|
+
if (_) return;
|
|
21
|
+
let t = [], n = [], r = Math.max(0, p ? m : Math.min(1, m));
|
|
22
|
+
for (let i of e) {
|
|
23
|
+
let e = c(i, f) ? i.size > g ? "file-too-large" : t.length + h >= r ? "too-many-files" : null : "file-invalid-type";
|
|
24
|
+
e ? n.push({
|
|
25
|
+
file: i,
|
|
26
|
+
code: e
|
|
27
|
+
}) : t.push(i);
|
|
28
|
+
}
|
|
29
|
+
k(n), t.length && v(t), n.length && y?.(n);
|
|
30
|
+
}
|
|
31
|
+
return /* @__PURE__ */ s("div", {
|
|
32
|
+
role: "group",
|
|
33
|
+
"aria-label": u,
|
|
34
|
+
className: e(t, "min-w-0 space-y-2", C),
|
|
35
|
+
children: [
|
|
36
|
+
/* @__PURE__ */ o("input", {
|
|
37
|
+
ref: w,
|
|
38
|
+
type: "file",
|
|
39
|
+
accept: f,
|
|
40
|
+
multiple: p,
|
|
41
|
+
disabled: _,
|
|
42
|
+
tabIndex: -1,
|
|
43
|
+
"aria-label": u,
|
|
44
|
+
className: "hidden",
|
|
45
|
+
onChange: (e) => {
|
|
46
|
+
j(Array.from(e.currentTarget.files ?? [])), e.currentTarget.value = "";
|
|
47
|
+
}
|
|
48
|
+
}),
|
|
49
|
+
/* @__PURE__ */ s("button", {
|
|
50
|
+
type: "button",
|
|
51
|
+
disabled: _,
|
|
52
|
+
"aria-label": `${b}: ${u}`,
|
|
53
|
+
"aria-describedby": d ? `${A}-description` : void 0,
|
|
54
|
+
"data-drag-active": E && !_,
|
|
55
|
+
onClick: () => w.current?.click(),
|
|
56
|
+
onDragEnter: (e) => {
|
|
57
|
+
e.preventDefault(), T.current += 1, _ || D(!0);
|
|
58
|
+
},
|
|
59
|
+
onDragOver: (e) => {
|
|
60
|
+
e.preventDefault(), _ || (e.dataTransfer.dropEffect = "copy");
|
|
61
|
+
},
|
|
62
|
+
onDragLeave: (e) => {
|
|
63
|
+
e.preventDefault(), T.current = Math.max(0, T.current - 1), T.current === 0 && D(!1);
|
|
64
|
+
},
|
|
65
|
+
onDrop: (e) => {
|
|
66
|
+
e.preventDefault(), e.stopPropagation(), T.current = 0, D(!1), j(Array.from(e.dataTransfer.files));
|
|
67
|
+
},
|
|
68
|
+
className: e("flex w-full min-w-0 flex-col items-center gap-2 rounded-basalt-lg border-2 border-dashed px-4 py-7 text-center transition-colors focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-basalt-ring disabled:cursor-not-allowed disabled:opacity-50", E && !_ ? "border-basalt-primary bg-basalt-accent" : "border-basalt-border bg-basalt-card hover:bg-basalt-accent"),
|
|
69
|
+
children: [
|
|
70
|
+
/* @__PURE__ */ o(a, {
|
|
71
|
+
className: "size-6 text-basalt-muted-foreground",
|
|
72
|
+
"aria-hidden": "true"
|
|
73
|
+
}),
|
|
74
|
+
/* @__PURE__ */ o("span", {
|
|
75
|
+
className: "text-sm font-medium",
|
|
76
|
+
children: E && !_ ? x : u
|
|
77
|
+
}),
|
|
78
|
+
d && /* @__PURE__ */ o("span", {
|
|
79
|
+
id: `${A}-description`,
|
|
80
|
+
className: "text-xs text-basalt-muted-foreground",
|
|
81
|
+
children: d
|
|
82
|
+
}),
|
|
83
|
+
/* @__PURE__ */ o("span", {
|
|
84
|
+
className: "rounded-basalt-md border border-basalt-border px-3 py-1 text-xs",
|
|
85
|
+
children: b
|
|
86
|
+
})
|
|
87
|
+
]
|
|
88
|
+
}),
|
|
89
|
+
O.length > 0 && /* @__PURE__ */ o("ul", {
|
|
90
|
+
role: "alert",
|
|
91
|
+
className: "space-y-1 text-xs text-basalt-destructive",
|
|
92
|
+
children: O.map((e, t) => /* @__PURE__ */ o("li", {
|
|
93
|
+
className: "break-words",
|
|
94
|
+
children: S ? S(e) : `${e.file.name}: ${l[e.code]}`
|
|
95
|
+
}, `${e.file.name}-${t}`))
|
|
96
|
+
})
|
|
97
|
+
]
|
|
98
|
+
});
|
|
99
|
+
}
|
|
100
|
+
//#endregion
|
|
101
|
+
export { u as FileDropzone };
|
|
102
|
+
|
|
103
|
+
//# sourceMappingURL=file-dropzone.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"file-dropzone.js","names":[],"sources":["../../src/components/file-dropzone.tsx"],"sourcesContent":["import { Upload } from \"lucide-react\";\nimport { useId, useRef, useState } from \"react\";\nimport { cn } from \"../utils/cn\";\nimport { BASALT_UI_CLASS } from \"../utils/control-surface\";\n\nexport interface FileRejection {\n\t/** Original File; the component never creates preview URLs. */\n\tfile: File;\n\t/** Machine-readable reason for application handling. */\n\tcode: \"file-invalid-type\" | \"file-too-large\" | \"too-many-files\";\n}\n\nexport interface FileDropzoneProps {\n\t/** Visible and accessible upload field name. */\n\tlabel: string;\n\t/** Optional file requirements shown under the label. */\n\tdescription?: string;\n\t/** Accepted extensions/MIME types using native accept syntax, e.g. .pdf,image/*. */\n\taccept?: string;\n\t/** Allow multiple files. @default true */\n\tmultiple?: boolean;\n\t/** Maximum accepted file count including fileCount. @default Infinity */\n\tmaxFiles?: number;\n\t/** Number already held by the application. @default 0 */\n\tfileCount?: number;\n\t/** Maximum size of an individual file in bytes. @default Infinity */\n\tmaxSize?: number;\n\t/** Prevent both file browsing and drops. @default false */\n\tdisabled?: boolean;\n\t/** Accepted files from this gesture; transport and queue ownership belong to the caller. */\n\tonFilesAccepted: (files: File[]) => void;\n\t/** Rejected files from this gesture, with one primary reason per file. */\n\tonFilesRejected?: (rejections: FileRejection[]) => void;\n\t/** Browse action text. @default \"Browse files\" */\n\tbrowseLabel?: string;\n\t/** Text while a file is dragged over the field. @default \"Drop files here\" */\n\tdropLabel?: string;\n\t/** Localized rejection message; defaults to a name and reason. */\n\tformatRejection?: (rejection: FileRejection) => string;\n\t/** Additional root classes. */\n\tclassName?: string;\n}\n\nfunction accepts(file: File, accept: string) {\n\tconst rules = accept\n\t\t.split(\",\")\n\t\t.map((rule) => rule.trim().toLowerCase())\n\t\t.filter(Boolean);\n\treturn (\n\t\trules.length === 0 ||\n\t\trules.some((rule) =>\n\t\t\trule.startsWith(\".\")\n\t\t\t\t? file.name.toLowerCase().endsWith(rule)\n\t\t\t\t: rule.endsWith(\"/*\")\n\t\t\t\t\t? file.type.toLowerCase().startsWith(rule.slice(0, -1))\n\t\t\t\t\t: file.type.toLowerCase() === rule,\n\t\t)\n\t);\n}\n\nconst REASONS = {\n\t\"file-invalid-type\": \"File type is not accepted.\",\n\t\"file-too-large\": \"File exceeds the size limit.\",\n\t\"too-many-files\": \"File count limit reached.\",\n};\n\nexport function FileDropzone({\n\tlabel,\n\tdescription,\n\taccept = \"\",\n\tmultiple = true,\n\tmaxFiles = Infinity,\n\tfileCount = 0,\n\tmaxSize = Infinity,\n\tdisabled = false,\n\tonFilesAccepted,\n\tonFilesRejected,\n\tbrowseLabel = \"Browse files\",\n\tdropLabel = \"Drop files here\",\n\tformatRejection,\n\tclassName,\n}: FileDropzoneProps) {\n\tconst input = useRef<HTMLInputElement>(null);\n\tconst depth = useRef(0);\n\tconst [dragging, setDragging] = useState(false);\n\tconst [rejections, setRejections] = useState<FileRejection[]>([]);\n\tconst id = useId();\n\tfunction receive(files: File[]) {\n\t\tif (disabled) return;\n\t\tconst accepted: File[] = [];\n\t\tconst rejected: FileRejection[] = [];\n\t\tconst limit = Math.max(0, multiple ? maxFiles : Math.min(1, maxFiles));\n\t\tfor (const file of files) {\n\t\t\tconst code = !accepts(file, accept)\n\t\t\t\t? \"file-invalid-type\"\n\t\t\t\t: file.size > maxSize\n\t\t\t\t\t? \"file-too-large\"\n\t\t\t\t\t: accepted.length + fileCount >= limit\n\t\t\t\t\t\t? \"too-many-files\"\n\t\t\t\t\t\t: null;\n\t\t\tif (code) rejected.push({ file, code });\n\t\t\telse accepted.push(file);\n\t\t}\n\t\tsetRejections(rejected);\n\t\tif (accepted.length) onFilesAccepted(accepted);\n\t\tif (rejected.length) onFilesRejected?.(rejected);\n\t}\n\treturn (\n\t\t<div\n\t\t\trole=\"group\"\n\t\t\taria-label={label}\n\t\t\tclassName={cn(BASALT_UI_CLASS, \"min-w-0 space-y-2\", className)}\n\t\t>\n\t\t\t<input\n\t\t\t\tref={input}\n\t\t\t\ttype=\"file\"\n\t\t\t\taccept={accept}\n\t\t\t\tmultiple={multiple}\n\t\t\t\tdisabled={disabled}\n\t\t\t\ttabIndex={-1}\n\t\t\t\taria-label={label}\n\t\t\t\tclassName=\"hidden\"\n\t\t\t\tonChange={(event) => {\n\t\t\t\t\treceive(Array.from(event.currentTarget.files ?? []));\n\t\t\t\t\tevent.currentTarget.value = \"\";\n\t\t\t\t}}\n\t\t\t/>\n\t\t\t<button\n\t\t\t\ttype=\"button\"\n\t\t\t\tdisabled={disabled}\n\t\t\t\taria-label={`${browseLabel}: ${label}`}\n\t\t\t\taria-describedby={description ? `${id}-description` : undefined}\n\t\t\t\tdata-drag-active={dragging && !disabled}\n\t\t\t\tonClick={() => input.current?.click()}\n\t\t\t\tonDragEnter={(event) => {\n\t\t\t\t\tevent.preventDefault();\n\t\t\t\t\tdepth.current += 1;\n\t\t\t\t\tif (!disabled) setDragging(true);\n\t\t\t\t}}\n\t\t\t\tonDragOver={(event) => {\n\t\t\t\t\tevent.preventDefault();\n\t\t\t\t\tif (!disabled) event.dataTransfer.dropEffect = \"copy\";\n\t\t\t\t}}\n\t\t\t\tonDragLeave={(event) => {\n\t\t\t\t\tevent.preventDefault();\n\t\t\t\t\tdepth.current = Math.max(0, depth.current - 1);\n\t\t\t\t\tif (depth.current === 0) setDragging(false);\n\t\t\t\t}}\n\t\t\t\tonDrop={(event) => {\n\t\t\t\t\tevent.preventDefault();\n\t\t\t\t\tevent.stopPropagation();\n\t\t\t\t\tdepth.current = 0;\n\t\t\t\t\tsetDragging(false);\n\t\t\t\t\treceive(Array.from(event.dataTransfer.files));\n\t\t\t\t}}\n\t\t\t\tclassName={cn(\n\t\t\t\t\t\"flex w-full min-w-0 flex-col items-center gap-2 rounded-basalt-lg border-2 border-dashed px-4 py-7 text-center transition-colors focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-basalt-ring disabled:cursor-not-allowed disabled:opacity-50\",\n\t\t\t\t\tdragging && !disabled\n\t\t\t\t\t\t? \"border-basalt-primary bg-basalt-accent\"\n\t\t\t\t\t\t: \"border-basalt-border bg-basalt-card hover:bg-basalt-accent\",\n\t\t\t\t)}\n\t\t\t>\n\t\t\t\t<Upload className=\"size-6 text-basalt-muted-foreground\" aria-hidden=\"true\" />\n\t\t\t\t<span className=\"text-sm font-medium\">{dragging && !disabled ? dropLabel : label}</span>\n\t\t\t\t{description && (\n\t\t\t\t\t<span id={`${id}-description`} className=\"text-xs text-basalt-muted-foreground\">\n\t\t\t\t\t\t{description}\n\t\t\t\t\t</span>\n\t\t\t\t)}\n\t\t\t\t<span className=\"rounded-basalt-md border border-basalt-border px-3 py-1 text-xs\">\n\t\t\t\t\t{browseLabel}\n\t\t\t\t</span>\n\t\t\t</button>\n\t\t\t{rejections.length > 0 && (\n\t\t\t\t<ul role=\"alert\" className=\"space-y-1 text-xs text-basalt-destructive\">\n\t\t\t\t\t{rejections.map((item, index) => (\n\t\t\t\t\t\t<li key={`${item.file.name}-${index}`} className=\"break-words\">\n\t\t\t\t\t\t\t{formatRejection ? formatRejection(item) : `${item.file.name}: ${REASONS[item.code]}`}\n\t\t\t\t\t\t</li>\n\t\t\t\t\t))}\n\t\t\t\t</ul>\n\t\t\t)}\n\t\t</div>\n\t);\n}\n"],"mappings":";;;;;;;AA2CA,SAAS,EAAQ,GAAY,GAAgB;CAC5C,IAAM,IAAQ,EACZ,MAAM,GAAG,CAAC,CACV,KAAK,MAAS,EAAK,KAAK,CAAC,CAAC,YAAY,CAAC,CAAC,CACxC,OAAO,OAAO;CAChB,OACC,EAAM,WAAW,KACjB,EAAM,MAAM,MACX,EAAK,WAAW,GAAG,IAChB,EAAK,KAAK,YAAY,CAAC,CAAC,SAAS,CAAI,IACrC,EAAK,SAAS,IAAI,IACjB,EAAK,KAAK,YAAY,CAAC,CAAC,WAAW,EAAK,MAAM,GAAG,EAAE,CAAC,IACpD,EAAK,KAAK,YAAY,MAAM,CACjC;AAEF;AAEA,IAAM,IAAU;CACf,qBAAqB;CACrB,kBAAkB;CAClB,kBAAkB;AACnB;AAEA,SAAgB,EAAa,EAC5B,UACA,gBACA,YAAS,IACT,cAAW,IACX,cAAW,UACX,eAAY,GACZ,aAAU,UACV,cAAW,IACX,oBACA,oBACA,iBAAc,gBACd,eAAY,mBACZ,oBACA,gBACqB;CACrB,IAAM,IAAQ,EAAyB,IAAI,GACrC,IAAQ,EAAO,CAAC,GAChB,CAAC,GAAU,KAAe,EAAS,EAAK,GACxC,CAAC,GAAY,KAAiB,EAA0B,CAAC,CAAC,GAC1D,IAAK,EAAM;CACjB,SAAS,EAAQ,GAAe;EAC/B,IAAI,GAAU;EACd,IAAM,IAAmB,CAAC,GACpB,IAA4B,CAAC,GAC7B,IAAQ,KAAK,IAAI,GAAG,IAAW,IAAW,KAAK,IAAI,GAAG,CAAQ,CAAC;EACrE,KAAK,IAAM,KAAQ,GAAO;GACzB,IAAM,IAAQ,EAAQ,GAAM,CAAM,IAE/B,EAAK,OAAO,IACX,mBACA,EAAS,SAAS,KAAa,IAC9B,mBACA,OALF;GAMH,AAAI,IAAM,EAAS,KAAK;IAAE;IAAM;GAAK,CAAC,IACjC,EAAS,KAAK,CAAI;EACxB;EAGA,AAFA,EAAc,CAAQ,GAClB,EAAS,UAAQ,EAAgB,CAAQ,GACzC,EAAS,UAAQ,IAAkB,CAAQ;CAChD;CACA,OACC,kBAAC,OAAD;EACC,MAAK;EACL,cAAY;EACZ,WAAW,EAAG,GAAiB,qBAAqB,CAAS;EAH9D,UAAA;GAKC,kBAAC,SAAD;IACC,KAAK;IACL,MAAK;IACG;IACE;IACA;IACV,UAAU;IACV,cAAY;IACZ,WAAU;IACV,WAAW,MAAU;KAEpB,AADA,EAAQ,MAAM,KAAK,EAAM,cAAc,SAAS,CAAC,CAAC,CAAC,GACnD,EAAM,cAAc,QAAQ;IAC7B;GACA,CAAA;GACD,kBAAC,UAAD;IACC,MAAK;IACK;IACV,cAAY,GAAG,EAAY,IAAI;IAC/B,oBAAkB,IAAc,GAAG,EAAG,gBAAgB,KAAA;IACtD,oBAAkB,KAAY,CAAC;IAC/B,eAAe,EAAM,SAAS,MAAM;IACpC,cAAc,MAAU;KAGvB,AAFA,EAAM,eAAe,GACrB,EAAM,WAAW,GACZ,KAAU,EAAY,EAAI;IAChC;IACA,aAAa,MAAU;KAEtB,AADA,EAAM,eAAe,GAChB,MAAU,EAAM,aAAa,aAAa;IAChD;IACA,cAAc,MAAU;KAGvB,AAFA,EAAM,eAAe,GACrB,EAAM,UAAU,KAAK,IAAI,GAAG,EAAM,UAAU,CAAC,GACzC,EAAM,YAAY,KAAG,EAAY,EAAK;IAC3C;IACA,SAAS,MAAU;KAKlB,AAJA,EAAM,eAAe,GACrB,EAAM,gBAAgB,GACtB,EAAM,UAAU,GAChB,EAAY,EAAK,GACjB,EAAQ,MAAM,KAAK,EAAM,aAAa,KAAK,CAAC;IAC7C;IACA,WAAW,EACV,6QACA,KAAY,CAAC,IACV,2CACA,4DACJ;IAjCD,UAAA;KAmCC,kBAAC,GAAD;MAAQ,WAAU;MAAsC,eAAY;KAAQ,CAAA;KAC5E,kBAAC,QAAD;MAAM,WAAU;MAAuB,UAAA,KAAY,CAAC,IAAW,IAAY;KAAY,CAAA;KACtF,KACA,kBAAC,QAAD;MAAM,IAAI,GAAG,EAAG;MAAe,WAAU;MACvC,UAAA;KACI,CAAA;KAEP,kBAAC,QAAD;MAAM,WAAU;MACd,UAAA;KACI,CAAA;IACC;;GACP,EAAW,SAAS,KACpB,kBAAC,MAAD;IAAI,MAAK;IAAQ,WAAU;IACzB,UAAA,EAAW,KAAK,GAAM,MACtB,kBAAC,MAAD;KAAuC,WAAU;KAC/C,UAAA,IAAkB,EAAgB,CAAI,IAAI,GAAG,EAAK,KAAK,KAAK,IAAI,EAAQ,EAAK;IAC3E,GAFK,GAAG,EAAK,KAAK,KAAK,GAAG,GAE1B,CACJ;GACE,CAAA;EAED;;AAEP"}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import type { ReactNode } from "react";
|
|
2
|
+
export interface FilterBarProps {
|
|
3
|
+
/** Accessible group name. */
|
|
4
|
+
label: string;
|
|
5
|
+
/** Application-owned search, select, and date controls. */
|
|
6
|
+
children: ReactNode;
|
|
7
|
+
/** Active chips, shown on their own wrapping row. */
|
|
8
|
+
chips?: ReactNode;
|
|
9
|
+
/** Whether the clear action is available. @default false */
|
|
10
|
+
active?: boolean;
|
|
11
|
+
/** Requests clearing application-owned filters. */
|
|
12
|
+
onClear?: () => void;
|
|
13
|
+
/** Clear action text. @default "Clear filters" */
|
|
14
|
+
clearLabel?: string;
|
|
15
|
+
/** Additional root classes. */
|
|
16
|
+
className?: string;
|
|
17
|
+
}
|
|
18
|
+
/** Layout only; URL serialization, query execution, and date presets belong to the caller. */
|
|
19
|
+
export declare function FilterBar({ label, children, chips, active, onClear, clearLabel, className, }: FilterBarProps): import("react").JSX.Element;
|
|
20
|
+
export interface FilterChipProps {
|
|
21
|
+
/** Filter dimension, e.g. Status. */
|
|
22
|
+
label: string;
|
|
23
|
+
/** Display value. */
|
|
24
|
+
value: ReactNode;
|
|
25
|
+
/** Requests removal from the application's filter state. */
|
|
26
|
+
onRemove: () => void;
|
|
27
|
+
/** Full accessible removal label; defaults to Remove plus the dimension label. */
|
|
28
|
+
removeLabel?: string;
|
|
29
|
+
/** Disable removal. @default false */
|
|
30
|
+
disabled?: boolean;
|
|
31
|
+
/** Additional root classes. */
|
|
32
|
+
className?: string;
|
|
33
|
+
}
|
|
34
|
+
export declare function FilterChip({ label, value, onRemove, removeLabel, disabled, className, }: FilterChipProps): import("react").JSX.Element;
|