azamat-ui-kit-cli 0.2.2 → 0.3.4
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 +11 -0
- package/dist/index.cjs +452 -0
- package/package.json +2 -2
- package/vendor/src/components/actions/action-menu.tsx +21 -18
- package/vendor/src/components/calendar/calendar.tsx +153 -102
- package/vendor/src/components/calendar/date-picker.tsx +24 -14
- package/vendor/src/components/calendar/date-range-picker.tsx +137 -58
- package/vendor/src/components/charts/charts.tsx +32 -21
- package/vendor/src/components/command/command-palette.tsx +68 -57
- package/vendor/src/components/data-table/data-table-bulk-actions.tsx +23 -20
- package/vendor/src/components/data-table/data-table-column-visibility-menu.tsx +21 -10
- package/vendor/src/components/data-table/data-table-pagination.tsx +6 -6
- package/vendor/src/components/data-table/data-table-toolbar.tsx +72 -44
- package/vendor/src/components/data-table/data-table.tsx +15 -11
- package/vendor/src/components/data-table/table-export-menu.tsx +1 -1
- package/vendor/src/components/data-table/table-import-button.tsx +1 -1
- package/vendor/src/components/display/data-state.tsx +20 -8
- package/vendor/src/components/display/index.ts +19 -15
- package/vendor/src/components/display/metric-card.tsx +35 -0
- package/vendor/src/components/display/progress-circle.tsx +24 -0
- package/vendor/src/components/display/smart-card.tsx +49 -27
- package/vendor/src/components/display/status-dot.tsx +45 -0
- package/vendor/src/components/display/user-card.tsx +30 -0
- package/vendor/src/components/feedback/alert.tsx +21 -11
- package/vendor/src/components/feedback/empty-state.tsx +2 -2
- package/vendor/src/components/feedback/loading-state.tsx +2 -2
- package/vendor/src/components/feedback/page-state.tsx +19 -15
- package/vendor/src/components/feedback/status-badge.tsx +43 -43
- package/vendor/src/components/form/form-app-input.tsx +147 -0
- package/vendor/src/components/form/form-date-input.tsx +16 -19
- package/vendor/src/components/form/form-field-shell.tsx +11 -8
- package/vendor/src/components/form/form-field-utils.ts +76 -0
- package/vendor/src/components/form/form-input.tsx +423 -44
- package/vendor/src/components/form/form-number-input.tsx +16 -15
- package/vendor/src/components/form/form-phone-input.tsx +15 -9
- package/vendor/src/components/form/form-search-input.tsx +16 -19
- package/vendor/src/components/form/form-select.tsx +4 -3
- package/vendor/src/components/form/public.ts +16 -14
- package/vendor/src/components/form/smart-form-shell.tsx +13 -12
- package/vendor/src/components/inputs/app-input.tsx +27 -0
- package/vendor/src/components/inputs/async-select.tsx +113 -84
- package/vendor/src/components/inputs/clearable-input.tsx +81 -61
- package/vendor/src/components/inputs/date-input.tsx +21 -17
- package/vendor/src/components/inputs/date-range-input.tsx +10 -10
- package/vendor/src/components/inputs/index.ts +1 -0
- package/vendor/src/components/inputs/input-decorator.tsx +101 -57
- package/vendor/src/components/inputs/masked-input.tsx +20 -20
- package/vendor/src/components/inputs/money-input.tsx +2 -2
- package/vendor/src/components/inputs/number-input.tsx +29 -19
- package/vendor/src/components/inputs/password-input.tsx +82 -45
- package/vendor/src/components/inputs/phone-input.tsx +24 -2
- package/vendor/src/components/inputs/quantity-input.tsx +2 -2
- package/vendor/src/components/inputs/search-input.tsx +54 -3
- package/vendor/src/components/inputs/simple-select.tsx +110 -22
- package/vendor/src/components/layout/app-shell.tsx +2 -2
- package/vendor/src/components/layout/index.ts +5 -4
- package/vendor/src/components/layout/page-header.tsx +79 -35
- package/vendor/src/components/layout/public.ts +12 -10
- package/vendor/src/components/layout/section-header.tsx +56 -0
- package/vendor/src/components/layout/stack.tsx +106 -0
- package/vendor/src/components/layout/stat-card.tsx +66 -29
- package/vendor/src/components/navigation/index.ts +1 -0
- package/vendor/src/components/navigation/nav-tabs.tsx +60 -0
- package/vendor/src/components/navigation/page-tabs.tsx +41 -26
- package/vendor/src/components/navigation/pagination.tsx +14 -10
- package/vendor/src/components/overlay/alert-dialog.tsx +65 -0
- package/vendor/src/components/overlay/drawer.tsx +71 -0
- package/vendor/src/components/overlay/index.ts +4 -2
- package/vendor/src/components/patterns/data-view.tsx +13 -8
- package/vendor/src/components/ui/badge.tsx +96 -52
- package/vendor/src/components/ui/button.tsx +99 -61
- package/vendor/src/components/ui/card.tsx +84 -25
- package/vendor/src/components/ui/checkbox.tsx +68 -68
- package/vendor/src/components/ui/command.tsx +32 -32
- package/vendor/src/components/ui/dialog.tsx +135 -138
- package/vendor/src/components/ui/dropdown-menu.tsx +21 -21
- package/vendor/src/components/ui/hover-card.tsx +49 -0
- package/vendor/src/components/ui/input-primitive.tsx +24 -0
- package/vendor/src/components/ui/input.tsx +191 -20
- package/vendor/src/components/ui/kbd.tsx +33 -0
- package/vendor/src/components/ui/popover.tsx +11 -11
- package/vendor/src/components/ui/radio-group.tsx +102 -0
- package/vendor/src/components/ui/right-click-menu.tsx +60 -0
- package/vendor/src/components/ui/scroll-box.tsx +27 -0
- package/vendor/src/components/ui/segmented-control.tsx +21 -17
- package/vendor/src/components/ui/select.tsx +187 -189
- package/vendor/src/components/ui/skeleton.tsx +2 -2
- package/vendor/src/components/ui/switch.tsx +60 -60
- package/vendor/src/components/ui/table.tsx +114 -114
- package/vendor/src/components/ui/tabs.tsx +2 -2
- package/vendor/src/components/ui/textarea.tsx +1 -1
- package/vendor/src/components/upload/file-dropzone.tsx +38 -0
- package/vendor/src/components/upload/file-upload.tsx +4 -4
- package/vendor/src/components/upload/image-upload.tsx +22 -19
- package/vendor/src/components/upload/index.ts +2 -0
- package/vendor/src/families/catalog.ts +1 -0
- package/vendor/src/families/docs-groups.ts +10 -1
- package/vendor/src/families/member-metadata.ts +24 -0
- package/vendor/src/families/member-snippets.ts +41 -2
- package/vendor/src/families/migration-map.ts +3 -0
- package/vendor/src/index.ts +23 -18
- package/vendor/templates/styles/globals.css +253 -0
- package/dist/index.js +0 -432
|
@@ -9,9 +9,11 @@ import { parseDateKey } from "./date-utils"
|
|
|
9
9
|
|
|
10
10
|
export type DateRangePickerValue = CalendarDateRange
|
|
11
11
|
|
|
12
|
-
export type DateRangePickerLabels = CalendarProps["labels"] & {
|
|
13
|
-
placeholder?: string
|
|
14
|
-
|
|
12
|
+
export type DateRangePickerLabels = CalendarProps["labels"] & {
|
|
13
|
+
placeholder?: string
|
|
14
|
+
apply?: React.ReactNode
|
|
15
|
+
clear?: React.ReactNode
|
|
16
|
+
}
|
|
15
17
|
|
|
16
18
|
export type DateRangePickerProps = Omit<
|
|
17
19
|
CalendarProps,
|
|
@@ -21,11 +23,13 @@ export type DateRangePickerProps = Omit<
|
|
|
21
23
|
onValueChange?: (value: DateRangePickerValue) => void
|
|
22
24
|
labels?: DateRangePickerLabels
|
|
23
25
|
placeholder?: string
|
|
24
|
-
disabled?: boolean
|
|
25
|
-
formatValue?: (value: string) => React.ReactNode
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
26
|
+
disabled?: boolean
|
|
27
|
+
formatValue?: (value: string) => React.ReactNode
|
|
28
|
+
closeOnSelect?: boolean
|
|
29
|
+
showFooter?: boolean
|
|
30
|
+
triggerClassName?: string
|
|
31
|
+
contentClassName?: string
|
|
32
|
+
}
|
|
29
33
|
|
|
30
34
|
function defaultFormatValue(value: string) {
|
|
31
35
|
const date = parseDateKey(value)
|
|
@@ -33,63 +37,138 @@ function defaultFormatValue(value: string) {
|
|
|
33
37
|
return new Intl.DateTimeFormat("en-US", { dateStyle: "medium" }).format(date)
|
|
34
38
|
}
|
|
35
39
|
|
|
36
|
-
function DateRangePicker({
|
|
37
|
-
className,
|
|
38
|
-
value,
|
|
40
|
+
function DateRangePicker({
|
|
41
|
+
className,
|
|
42
|
+
value,
|
|
39
43
|
onValueChange,
|
|
40
44
|
labels,
|
|
41
|
-
placeholder,
|
|
42
|
-
disabled = false,
|
|
43
|
-
formatValue = defaultFormatValue,
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
const
|
|
54
|
-
|
|
45
|
+
placeholder,
|
|
46
|
+
disabled = false,
|
|
47
|
+
formatValue = defaultFormatValue,
|
|
48
|
+
closeOnSelect = true,
|
|
49
|
+
showFooter = false,
|
|
50
|
+
triggerClassName,
|
|
51
|
+
contentClassName,
|
|
52
|
+
numberOfMonths = 2,
|
|
53
|
+
pagedNavigation = true,
|
|
54
|
+
...calendarProps
|
|
55
|
+
}: DateRangePickerProps) {
|
|
56
|
+
const [open, setOpen] = React.useState(false)
|
|
57
|
+
const [draftValue, setDraftValue] = React.useState<DateRangePickerValue>(value ?? {})
|
|
58
|
+
const from = value?.from ?? ""
|
|
59
|
+
const to = value?.to ?? ""
|
|
60
|
+
const hasValue = Boolean(from || to)
|
|
61
|
+
const activeValue = showFooter ? draftValue : value
|
|
62
|
+
const activeFrom = activeValue?.from ?? ""
|
|
63
|
+
const activeTo = activeValue?.to ?? ""
|
|
64
|
+
const hasDraftValue = Boolean(activeFrom || activeTo)
|
|
65
|
+
|
|
66
|
+
const label = from && to
|
|
67
|
+
? `${formatValue(from)} - ${formatValue(to)}`
|
|
55
68
|
: from
|
|
56
|
-
? `${formatValue(from)} - ...`
|
|
57
|
-
: placeholder ?? labels?.placeholder ?? "Select date range"
|
|
58
|
-
|
|
59
|
-
const
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
69
|
+
? `${formatValue(from)} - ...`
|
|
70
|
+
: placeholder ?? labels?.placeholder ?? "Select date range"
|
|
71
|
+
|
|
72
|
+
const draftLabel = activeFrom && activeTo
|
|
73
|
+
? `${formatValue(activeFrom)} - ${formatValue(activeTo)}`
|
|
74
|
+
: activeFrom
|
|
75
|
+
? `${formatValue(activeFrom)} - ...`
|
|
76
|
+
: labels?.placeholder ?? "Select date range"
|
|
77
|
+
|
|
78
|
+
React.useEffect(() => {
|
|
79
|
+
if (open && showFooter) {
|
|
80
|
+
setDraftValue(value ?? {})
|
|
81
|
+
}
|
|
82
|
+
}, [open, showFooter, value])
|
|
83
|
+
|
|
84
|
+
const handleRangeChange = (nextValue: DateRangePickerValue) => {
|
|
85
|
+
if (showFooter) {
|
|
86
|
+
setDraftValue(nextValue)
|
|
87
|
+
return
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
onValueChange?.(nextValue)
|
|
91
|
+
if (closeOnSelect && nextValue.from && nextValue.to) {
|
|
92
|
+
setOpen(false)
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
const applyDraftValue = () => {
|
|
97
|
+
onValueChange?.(draftValue)
|
|
98
|
+
setOpen(false)
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
const clearDraftValue = () => {
|
|
102
|
+
const nextValue = {}
|
|
103
|
+
|
|
104
|
+
if (showFooter) {
|
|
105
|
+
setDraftValue(nextValue)
|
|
106
|
+
return
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
onValueChange?.(nextValue)
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
return (
|
|
113
|
+
<div data-slot="date-range-picker" className={cn("w-full", className)}>
|
|
68
114
|
<Popover open={open} onOpenChange={setOpen}>
|
|
69
|
-
<PopoverTrigger
|
|
70
|
-
render={
|
|
71
|
-
<Button
|
|
72
|
-
type="button"
|
|
73
|
-
variant="outline"
|
|
74
|
-
disabled={disabled}
|
|
75
|
-
className={cn(
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
115
|
+
<PopoverTrigger
|
|
116
|
+
render={
|
|
117
|
+
<Button
|
|
118
|
+
type="button"
|
|
119
|
+
variant="outline"
|
|
120
|
+
disabled={disabled}
|
|
121
|
+
className={cn(
|
|
122
|
+
"min-h-11 w-full justify-start rounded-[min(var(--radius-xl),16px)] border-border/80 bg-background/96 text-left font-normal shadow-[0_1px_0_rgba(255,255,255,0.06)]",
|
|
123
|
+
!hasValue && "text-muted-foreground",
|
|
124
|
+
triggerClassName
|
|
125
|
+
)}
|
|
126
|
+
/>
|
|
127
|
+
}
|
|
128
|
+
>
|
|
79
129
|
<CalendarIcon data-icon="inline-start" />
|
|
80
130
|
<span className="min-w-0 flex-1 truncate">{label}</span>
|
|
81
131
|
</PopoverTrigger>
|
|
82
|
-
<PopoverContent
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
132
|
+
<PopoverContent
|
|
133
|
+
align="start"
|
|
134
|
+
className={cn(
|
|
135
|
+
"w-auto rounded-[var(--radius-2xl)] border-border/80 bg-popover/98 p-0 shadow-[0_24px_80px_rgba(15,23,42,0.18)] backdrop-blur",
|
|
136
|
+
contentClassName
|
|
137
|
+
)}
|
|
138
|
+
>
|
|
139
|
+
<Calendar
|
|
140
|
+
mode="range"
|
|
141
|
+
range={activeValue}
|
|
142
|
+
onRangeChange={handleRangeChange}
|
|
143
|
+
labels={labels}
|
|
144
|
+
numberOfMonths={numberOfMonths}
|
|
145
|
+
pagedNavigation={pagedNavigation}
|
|
146
|
+
{...calendarProps}
|
|
147
|
+
/>
|
|
148
|
+
{showFooter && (
|
|
149
|
+
<div className="flex flex-wrap items-center justify-between gap-3 border-t border-border/70 bg-muted/18 px-4 py-3">
|
|
150
|
+
<div className="min-w-0 text-sm text-muted-foreground">
|
|
151
|
+
<span className="block truncate">{draftLabel}</span>
|
|
152
|
+
</div>
|
|
153
|
+
<div className="flex items-center gap-2">
|
|
154
|
+
<Button type="button" variant="ghost" size="sm" className="rounded-full" onClick={clearDraftValue}>
|
|
155
|
+
{labels?.clear ?? "Clear"}
|
|
156
|
+
</Button>
|
|
157
|
+
<Button
|
|
158
|
+
type="button"
|
|
159
|
+
size="sm"
|
|
160
|
+
className="rounded-full"
|
|
161
|
+
disabled={!hasDraftValue}
|
|
162
|
+
onClick={applyDraftValue}
|
|
163
|
+
>
|
|
164
|
+
{labels?.apply ?? "Apply"}
|
|
165
|
+
</Button>
|
|
166
|
+
</div>
|
|
167
|
+
</div>
|
|
168
|
+
)}
|
|
169
|
+
</PopoverContent>
|
|
170
|
+
</Popover>
|
|
171
|
+
</div>
|
|
93
172
|
)
|
|
94
173
|
}
|
|
95
174
|
|
|
@@ -85,12 +85,16 @@ export type ChartFrameProps = React.ComponentProps<typeof Card> & {
|
|
|
85
85
|
action?: React.ReactNode
|
|
86
86
|
}
|
|
87
87
|
|
|
88
|
-
function ChartFrame({ title, description, action, className, children, ...props }: ChartFrameProps) {
|
|
89
|
-
return (
|
|
90
|
-
<Card
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
88
|
+
function ChartFrame({ title, description, action, className, children, ...props }: ChartFrameProps) {
|
|
89
|
+
return (
|
|
90
|
+
<Card
|
|
91
|
+
data-slot="chart-frame"
|
|
92
|
+
className={cn("border-border/75 bg-card/96 shadow-sm ring-1 ring-foreground/4", className)}
|
|
93
|
+
{...props}
|
|
94
|
+
>
|
|
95
|
+
{(title || description || action) && (
|
|
96
|
+
<CardHeader className="flex flex-row items-start justify-between gap-3">
|
|
97
|
+
<div className="grid gap-1">
|
|
94
98
|
{title && <CardTitle>{title}</CardTitle>}
|
|
95
99
|
{description && <CardDescription>{description}</CardDescription>}
|
|
96
100
|
</div>
|
|
@@ -115,20 +119,20 @@ function BarChart({ data, size = "md", max, showLabels = true, showValues = true
|
|
|
115
119
|
const resolvedMax = max ?? safeMax(data.map((item) => item.value))
|
|
116
120
|
const height = chartHeightBySize[size]
|
|
117
121
|
|
|
118
|
-
return (
|
|
119
|
-
<div data-slot="bar-chart" className={cn("grid gap-3", className)} {...props}>
|
|
120
|
-
<div className="flex items-end gap-2" style={{ height }}>
|
|
122
|
+
return (
|
|
123
|
+
<div data-slot="bar-chart" className={cn("grid gap-3", className)} {...props}>
|
|
124
|
+
<div className="flex items-end gap-2" style={{ height }}>
|
|
121
125
|
{data.map((item, index) => {
|
|
122
126
|
const ratio = normalizeValue(item.value, resolvedMax)
|
|
123
127
|
return (
|
|
124
128
|
<div key={index} className="flex min-w-0 flex-1 flex-col items-center gap-2">
|
|
125
129
|
{showValues && <div className="text-xs text-muted-foreground">{item.value}</div>}
|
|
126
|
-
<div className="flex w-full flex-1 items-end rounded-
|
|
127
|
-
<div
|
|
128
|
-
className={cn("w-full rounded-
|
|
129
|
-
style={{ height: `${Math.max(ratio * 100, item.value > 0 ? 3 : 0)}%`, background: item.color }}
|
|
130
|
-
/>
|
|
131
|
-
</div>
|
|
130
|
+
<div className="flex w-full flex-1 items-end rounded-[min(var(--radius-xl),16px)] border border-border/60 bg-muted/38 p-1">
|
|
131
|
+
<div
|
|
132
|
+
className={cn("w-full rounded-[min(var(--radius-lg),12px)] bg-primary transition-all", barClassName)}
|
|
133
|
+
style={{ height: `${Math.max(ratio * 100, item.value > 0 ? 3 : 0)}%`, background: item.color }}
|
|
134
|
+
/>
|
|
135
|
+
</div>
|
|
132
136
|
{showLabels && <div className="max-w-full truncate text-xs text-muted-foreground">{item.label}</div>}
|
|
133
137
|
</div>
|
|
134
138
|
)
|
|
@@ -253,12 +257,19 @@ export type MetricTrendProps = React.ComponentProps<"div"> & {
|
|
|
253
257
|
values?: number[]
|
|
254
258
|
}
|
|
255
259
|
|
|
256
|
-
function MetricTrend({ label, value, change, positive = true, values, className, ...props }: MetricTrendProps) {
|
|
257
|
-
return (
|
|
258
|
-
<div
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
260
|
+
function MetricTrend({ label, value, change, positive = true, values, className, ...props }: MetricTrendProps) {
|
|
261
|
+
return (
|
|
262
|
+
<div
|
|
263
|
+
data-slot="metric-trend"
|
|
264
|
+
className={cn(
|
|
265
|
+
"grid gap-3 rounded-[var(--radius-2xl)] border border-border/75 bg-card/96 p-4 shadow-sm ring-1 ring-foreground/4",
|
|
266
|
+
className
|
|
267
|
+
)}
|
|
268
|
+
{...props}
|
|
269
|
+
>
|
|
270
|
+
<div className="flex items-start justify-between gap-3">
|
|
271
|
+
<div className="grid gap-1">
|
|
272
|
+
<div className="text-sm text-muted-foreground">{label}</div>
|
|
262
273
|
<div className="text-2xl font-semibold tracking-tight">{value}</div>
|
|
263
274
|
</div>
|
|
264
275
|
{change && (
|
|
@@ -255,71 +255,82 @@ function CommandPalette({
|
|
|
255
255
|
}
|
|
256
256
|
}
|
|
257
257
|
|
|
258
|
-
return (
|
|
259
|
-
<Dialog open={open} onOpenChange={onOpenChange}>
|
|
260
|
-
<DialogContent
|
|
258
|
+
return (
|
|
259
|
+
<Dialog open={open} onOpenChange={onOpenChange}>
|
|
260
|
+
<DialogContent
|
|
261
|
+
className={cn(
|
|
262
|
+
"overflow-hidden rounded-[var(--radius-3xl)] border-border/80 bg-popover/98 p-0 shadow-[0_28px_90px_rgba(15,23,42,0.24)] backdrop-blur sm:max-w-xl",
|
|
263
|
+
contentClassName
|
|
264
|
+
)}
|
|
265
|
+
>
|
|
261
266
|
<DialogHeader className="sr-only">
|
|
262
267
|
<DialogTitle>{title}</DialogTitle>
|
|
263
268
|
<DialogDescription>{description}</DialogDescription>
|
|
264
269
|
</DialogHeader>
|
|
265
270
|
|
|
266
|
-
<div
|
|
267
|
-
data-slot="command-palette"
|
|
268
|
-
className={cn(
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
271
|
+
<div
|
|
272
|
+
data-slot="command-palette"
|
|
273
|
+
className={cn(
|
|
274
|
+
"flex max-h-[32rem] flex-col overflow-hidden rounded-[var(--radius-3xl)] bg-popover/98 text-popover-foreground",
|
|
275
|
+
className
|
|
276
|
+
)}
|
|
277
|
+
>
|
|
278
|
+
<div className="relative border-b border-border/70 bg-muted/20 p-3">
|
|
279
|
+
<SearchIcon className="pointer-events-none absolute left-4 top-1/2 size-4 -translate-y-1/2 text-muted-foreground" />
|
|
280
|
+
<Input
|
|
281
|
+
value={search}
|
|
282
|
+
onChange={(event) => setSearch(event.target.value)}
|
|
283
|
+
placeholder={placeholder}
|
|
284
|
+
className={cn(
|
|
285
|
+
"h-11 rounded-full border-border/75 bg-background/96 pl-10 shadow-[0_1px_0_rgba(255,255,255,0.05)] focus-visible:ring-2",
|
|
286
|
+
inputClassName
|
|
287
|
+
)}
|
|
288
|
+
autoFocus
|
|
289
|
+
/>
|
|
290
|
+
</div>
|
|
291
|
+
|
|
292
|
+
<div className={cn("overflow-y-auto p-3", listClassName)}>
|
|
293
|
+
{!hasResults && hasLoading && (
|
|
294
|
+
<div className="flex items-center justify-center gap-2 rounded-[min(var(--radius-xl),16px)] border border-border/70 bg-muted/30 py-8 text-sm text-muted-foreground">
|
|
295
|
+
{renderLoading?.(search) ?? (
|
|
296
|
+
<>
|
|
297
|
+
<Loader2Icon className="size-4 animate-spin" />
|
|
287
298
|
{loadingLabel}
|
|
288
299
|
</>
|
|
289
300
|
)}
|
|
290
301
|
</div>
|
|
291
302
|
)}
|
|
292
|
-
|
|
293
|
-
{!hasResults && !hasLoading && (
|
|
294
|
-
<div className="py-8 text-center text-sm text-muted-foreground">
|
|
295
|
-
{renderEmpty?.(search) ?? emptyLabel}
|
|
296
|
-
</div>
|
|
297
|
-
)}
|
|
298
|
-
|
|
299
|
-
{renderedGroups.map((group) => (
|
|
300
|
-
<div key={group.id} className="py-1">
|
|
301
|
-
{group.label && (
|
|
302
|
-
<div className="flex items-center justify-between px-2 py-
|
|
303
|
-
<span>{group.label}</span>
|
|
304
|
-
{group.loading && <Loader2Icon className="size-3.5 animate-spin" />}
|
|
305
|
-
</div>
|
|
306
|
-
)}
|
|
307
|
-
|
|
303
|
+
|
|
304
|
+
{!hasResults && !hasLoading && (
|
|
305
|
+
<div className="rounded-[min(var(--radius-xl),16px)] border border-border/70 bg-muted/30 py-8 text-center text-sm text-muted-foreground">
|
|
306
|
+
{renderEmpty?.(search) ?? emptyLabel}
|
|
307
|
+
</div>
|
|
308
|
+
)}
|
|
309
|
+
|
|
310
|
+
{renderedGroups.map((group) => (
|
|
311
|
+
<div key={group.id} className="py-1">
|
|
312
|
+
{group.label && (
|
|
313
|
+
<div className="flex items-center justify-between px-2 py-2 text-[11px] font-semibold uppercase tracking-[0.22em] text-muted-foreground">
|
|
314
|
+
<span>{group.label}</span>
|
|
315
|
+
{group.loading && <Loader2Icon className="size-3.5 animate-spin" />}
|
|
316
|
+
</div>
|
|
317
|
+
)}
|
|
318
|
+
|
|
308
319
|
{group.error ? (
|
|
309
|
-
<div className="rounded-
|
|
320
|
+
<div className="rounded-[min(var(--radius-xl),16px)] border border-destructive/20 bg-destructive/8 px-3 py-2 text-xs text-destructive">
|
|
310
321
|
Could not load commands.
|
|
311
322
|
</div>
|
|
312
323
|
) : null}
|
|
313
|
-
|
|
314
|
-
{group.loading && group.items.length === 0 && (
|
|
315
|
-
<div className="rounded-
|
|
316
|
-
{group.loadingLabel ?? loadingLabel}
|
|
317
|
-
</div>
|
|
318
|
-
)}
|
|
319
|
-
|
|
320
|
-
{group.items.length === 0 && !group.loading && !group.error && group.emptyLabel && (
|
|
321
|
-
<div className="rounded-
|
|
322
|
-
)}
|
|
324
|
+
|
|
325
|
+
{group.loading && group.items.length === 0 && (
|
|
326
|
+
<div className="rounded-[min(var(--radius-xl),16px)] border border-border/70 bg-muted/25 px-3 py-2 text-xs text-muted-foreground">
|
|
327
|
+
{group.loadingLabel ?? loadingLabel}
|
|
328
|
+
</div>
|
|
329
|
+
)}
|
|
330
|
+
|
|
331
|
+
{group.items.length === 0 && !group.loading && !group.error && group.emptyLabel && (
|
|
332
|
+
<div className="rounded-[min(var(--radius-xl),16px)] border border-border/70 bg-muted/25 px-3 py-2 text-xs text-muted-foreground">{group.emptyLabel}</div>
|
|
333
|
+
)}
|
|
323
334
|
|
|
324
335
|
{group.items.map((item) => {
|
|
325
336
|
const isLoading = loadingKey === item.id
|
|
@@ -327,12 +338,12 @@ function CommandPalette({
|
|
|
327
338
|
return (
|
|
328
339
|
<button
|
|
329
340
|
key={item.id}
|
|
330
|
-
type="button"
|
|
331
|
-
disabled={item.disabled || isLoading}
|
|
332
|
-
data-disabled={item.disabled || undefined}
|
|
333
|
-
className="flex w-full items-
|
|
334
|
-
onClick={() => void handleSelect(item, group)}
|
|
335
|
-
>
|
|
341
|
+
type="button"
|
|
342
|
+
disabled={item.disabled || isLoading}
|
|
343
|
+
data-disabled={item.disabled || undefined}
|
|
344
|
+
className="flex w-full items-start gap-3 rounded-[min(var(--radius-xl),16px)] border border-transparent px-3 py-2.5 text-left text-sm outline-none transition-colors hover:border-border/70 hover:bg-accent/60 hover:text-accent-foreground disabled:pointer-events-none disabled:opacity-50"
|
|
345
|
+
onClick={() => void handleSelect(item, group)}
|
|
346
|
+
>
|
|
336
347
|
{item.icon && <span className="shrink-0 text-muted-foreground [&_svg]:size-4">{item.icon}</span>}
|
|
337
348
|
<span className="min-w-0 flex-1">
|
|
338
349
|
<span className="block truncate">{item.label}</span>
|
|
@@ -51,32 +51,35 @@ function DataTableBulkActions<TData>({
|
|
|
51
51
|
onSelect: action.onSelect ? () => action.onSelect?.(rows) : undefined,
|
|
52
52
|
}))
|
|
53
53
|
|
|
54
|
-
return (
|
|
55
|
-
<div data-slot="data-table-bulk-actions" className="flex items-center gap-2">
|
|
56
|
-
<ActionMenu
|
|
57
|
-
label={label}
|
|
58
|
-
actions={resolvedActions}
|
|
54
|
+
return (
|
|
55
|
+
<div data-slot="data-table-bulk-actions" className="flex items-center gap-2">
|
|
56
|
+
<ActionMenu
|
|
57
|
+
label={label}
|
|
58
|
+
actions={resolvedActions}
|
|
59
59
|
disabled={disabled || count === 0}
|
|
60
60
|
trigger={
|
|
61
|
-
<Button
|
|
62
|
-
type="button"
|
|
63
|
-
variant="outline"
|
|
64
|
-
size="sm"
|
|
65
|
-
disabled={disabled || count === 0}
|
|
66
|
-
className={cn(
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
61
|
+
<Button
|
|
62
|
+
type="button"
|
|
63
|
+
variant="outline"
|
|
64
|
+
size="sm"
|
|
65
|
+
disabled={disabled || count === 0}
|
|
66
|
+
className={cn(
|
|
67
|
+
"gap-1.5 border-border/80 bg-background/94 shadow-[0_1px_0_rgba(255,255,255,0.06)]",
|
|
68
|
+
triggerClassName
|
|
69
|
+
)}
|
|
70
|
+
>
|
|
71
|
+
{selectedLabel(count)}
|
|
72
|
+
<ChevronDownIcon className="size-3.5" />
|
|
70
73
|
</Button>
|
|
71
74
|
}
|
|
72
75
|
{...props}
|
|
73
76
|
/>
|
|
74
|
-
|
|
75
|
-
{onClearSelection && count > 0 && (
|
|
76
|
-
<Button type="button" variant="ghost" size="sm" onClick={onClearSelection}>
|
|
77
|
-
{clearLabel}
|
|
78
|
-
</Button>
|
|
79
|
-
)}
|
|
77
|
+
|
|
78
|
+
{onClearSelection && count > 0 && (
|
|
79
|
+
<Button type="button" variant="ghost" size="sm" className="rounded-full" onClick={onClearSelection}>
|
|
80
|
+
{clearLabel}
|
|
81
|
+
</Button>
|
|
82
|
+
)}
|
|
80
83
|
</div>
|
|
81
84
|
)
|
|
82
85
|
}
|
|
@@ -47,19 +47,30 @@ function DataTableColumnVisibilityMenu<TData>({
|
|
|
47
47
|
|
|
48
48
|
return (
|
|
49
49
|
<DropdownMenu>
|
|
50
|
-
<DropdownMenuTrigger
|
|
51
|
-
render={
|
|
52
|
-
<Button
|
|
53
|
-
|
|
54
|
-
|
|
50
|
+
<DropdownMenuTrigger
|
|
51
|
+
render={
|
|
52
|
+
<Button
|
|
53
|
+
type="button"
|
|
54
|
+
variant="outline"
|
|
55
|
+
size="sm"
|
|
56
|
+
className={cn(
|
|
57
|
+
"border-border/80 bg-background/94 shadow-[0_1px_0_rgba(255,255,255,0.06)]",
|
|
58
|
+
triggerClassName
|
|
59
|
+
)}
|
|
60
|
+
/>
|
|
61
|
+
}
|
|
62
|
+
>
|
|
55
63
|
<Columns3Icon data-icon="inline-start" />
|
|
56
64
|
{triggerLabel ?? label}
|
|
57
65
|
</DropdownMenuTrigger>
|
|
58
|
-
<DropdownMenuContent
|
|
59
|
-
align={align}
|
|
60
|
-
side={side}
|
|
61
|
-
className={cn(
|
|
62
|
-
|
|
66
|
+
<DropdownMenuContent
|
|
67
|
+
align={align}
|
|
68
|
+
side={side}
|
|
69
|
+
className={cn(
|
|
70
|
+
"min-w-48 rounded-[var(--radius-2xl)] border-border/80 bg-popover/98 shadow-[0_24px_80px_rgba(15,23,42,0.18)] backdrop-blur",
|
|
71
|
+
contentClassName
|
|
72
|
+
)}
|
|
73
|
+
>
|
|
63
74
|
<DropdownMenuLabel>{label}</DropdownMenuLabel>
|
|
64
75
|
<DropdownMenuSeparator />
|
|
65
76
|
{columns.map((column) => (
|
|
@@ -66,12 +66,12 @@ function DataTablePagination({
|
|
|
66
66
|
<SimpleSelect
|
|
67
67
|
value={String(pageSize)}
|
|
68
68
|
onValueChange={(value) => onPageSizeChange(Number(value))}
|
|
69
|
-
options={pageSizeOptions.map((option) => ({
|
|
70
|
-
label: String(option),
|
|
71
|
-
value: String(option),
|
|
72
|
-
}))}
|
|
73
|
-
disabled={disabled}
|
|
74
|
-
triggerClassName="h-9 w-20 rounded-full border-border/
|
|
69
|
+
options={pageSizeOptions.map((option) => ({
|
|
70
|
+
label: String(option),
|
|
71
|
+
value: String(option),
|
|
72
|
+
}))}
|
|
73
|
+
disabled={disabled}
|
|
74
|
+
triggerClassName="h-9 w-20 rounded-full border-border/85 bg-background/94"
|
|
75
75
|
/>
|
|
76
76
|
</div>
|
|
77
77
|
)}
|