hazo_ui 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js ADDED
@@ -0,0 +1,823 @@
1
+ import { jsx, jsxs } from 'react/jsx-runtime';
2
+ import * as React6 from 'react';
3
+ import { useState, useEffect } from 'react';
4
+ import { Slot } from '@radix-ui/react-slot';
5
+ import { cva } from 'class-variance-authority';
6
+ import { clsx } from 'clsx';
7
+ import { twMerge } from 'tailwind-merge';
8
+ import * as DialogPrimitive from '@radix-ui/react-dialog';
9
+ import { X, ChevronDown, ChevronUp, Check, Filter, Plus, ChevronsUpDown, Trash2, Calendar as Calendar$1, ChevronRight, ChevronLeft } from 'lucide-react';
10
+ import * as PopoverPrimitive from '@radix-ui/react-popover';
11
+ import * as SelectPrimitive from '@radix-ui/react-select';
12
+ import * as TooltipPrimitive from '@radix-ui/react-tooltip';
13
+ import { DayPicker } from 'react-day-picker';
14
+ import { format } from 'date-fns';
15
+
16
+ var ExampleComponent = ({ children, className = "" }) => {
17
+ return /* @__PURE__ */ jsx("div", { className: `cls_example_component ${className}`, children });
18
+ };
19
+ function cn(...inputs) {
20
+ return twMerge(clsx(inputs));
21
+ }
22
+ var buttonVariants = cva(
23
+ "inline-flex items-center justify-center whitespace-nowrap rounded-md text-sm font-medium ring-offset-background transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50",
24
+ {
25
+ variants: {
26
+ variant: {
27
+ default: "bg-primary text-primary-foreground hover:bg-primary/90",
28
+ destructive: "bg-destructive text-destructive-foreground hover:bg-destructive/90",
29
+ outline: "border border-input bg-background hover:bg-accent hover:text-accent-foreground",
30
+ secondary: "bg-secondary text-secondary-foreground hover:bg-secondary/80",
31
+ ghost: "hover:bg-accent hover:text-accent-foreground",
32
+ link: "text-primary underline-offset-4 hover:underline"
33
+ },
34
+ size: {
35
+ default: "h-10 px-4 py-2",
36
+ sm: "h-9 rounded-md px-3",
37
+ lg: "h-11 rounded-md px-8",
38
+ icon: "h-10 w-10"
39
+ }
40
+ },
41
+ defaultVariants: {
42
+ variant: "default",
43
+ size: "default"
44
+ }
45
+ }
46
+ );
47
+ var Button = React6.forwardRef(
48
+ ({ className, variant, size, asChild = false, ...props }, ref) => {
49
+ const Comp = asChild ? Slot : "button";
50
+ return /* @__PURE__ */ jsx(
51
+ Comp,
52
+ {
53
+ className: cn(buttonVariants({ variant, size, className })),
54
+ ref,
55
+ ...props
56
+ }
57
+ );
58
+ }
59
+ );
60
+ Button.displayName = "Button";
61
+ var Dialog = DialogPrimitive.Root;
62
+ var DialogTrigger = DialogPrimitive.Trigger;
63
+ var DialogPortal = DialogPrimitive.Portal;
64
+ var DialogOverlay = React6.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx(
65
+ DialogPrimitive.Overlay,
66
+ {
67
+ ref,
68
+ className: cn(
69
+ "fixed inset-0 z-50 bg-black/80 data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0",
70
+ className
71
+ ),
72
+ ...props
73
+ }
74
+ ));
75
+ DialogOverlay.displayName = DialogPrimitive.Overlay.displayName;
76
+ var DialogContent = React6.forwardRef(({ className, children, ...props }, ref) => /* @__PURE__ */ jsxs(DialogPortal, { children: [
77
+ /* @__PURE__ */ jsx(DialogOverlay, {}),
78
+ /* @__PURE__ */ jsxs(
79
+ DialogPrimitive.Content,
80
+ {
81
+ ref,
82
+ className: cn(
83
+ "fixed left-[50%] top-[50%] z-50 grid w-full max-w-lg translate-x-[-50%] translate-y-[-50%] gap-4 border bg-background p-6 shadow-lg duration-200 data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[state=closed]:slide-out-to-left-1/2 data-[state=closed]:slide-out-to-top-[48%] data-[state=open]:slide-in-from-left-1/2 data-[state=open]:slide-in-from-top-[48%] sm:rounded-lg",
84
+ className
85
+ ),
86
+ ...props,
87
+ children: [
88
+ children,
89
+ /* @__PURE__ */ jsxs(DialogPrimitive.Close, { className: "absolute right-4 top-4 rounded-sm opacity-70 ring-offset-background transition-opacity hover:opacity-100 focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2 disabled:pointer-events-none data-[state=open]:bg-accent data-[state=open]:text-muted-foreground", children: [
90
+ /* @__PURE__ */ jsx(X, { className: "h-4 w-4" }),
91
+ /* @__PURE__ */ jsx("span", { className: "sr-only", children: "Close" })
92
+ ] })
93
+ ]
94
+ }
95
+ )
96
+ ] }));
97
+ DialogContent.displayName = DialogPrimitive.Content.displayName;
98
+ var DialogHeader = ({
99
+ className,
100
+ ...props
101
+ }) => /* @__PURE__ */ jsx(
102
+ "div",
103
+ {
104
+ className: cn(
105
+ "flex flex-col space-y-1.5 text-center sm:text-left",
106
+ className
107
+ ),
108
+ ...props
109
+ }
110
+ );
111
+ DialogHeader.displayName = "DialogHeader";
112
+ var DialogFooter = ({
113
+ className,
114
+ ...props
115
+ }) => /* @__PURE__ */ jsx(
116
+ "div",
117
+ {
118
+ className: cn(
119
+ "flex flex-col-reverse sm:flex-row sm:justify-end sm:space-x-2",
120
+ className
121
+ ),
122
+ ...props
123
+ }
124
+ );
125
+ DialogFooter.displayName = "DialogFooter";
126
+ var DialogTitle = React6.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx(
127
+ DialogPrimitive.Title,
128
+ {
129
+ ref,
130
+ className: cn(
131
+ "text-lg font-semibold leading-none tracking-tight",
132
+ className
133
+ ),
134
+ ...props
135
+ }
136
+ ));
137
+ DialogTitle.displayName = DialogPrimitive.Title.displayName;
138
+ var DialogDescription = React6.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx(
139
+ DialogPrimitive.Description,
140
+ {
141
+ ref,
142
+ className: cn("text-sm text-muted-foreground", className),
143
+ ...props
144
+ }
145
+ ));
146
+ DialogDescription.displayName = DialogPrimitive.Description.displayName;
147
+ var Command = React6.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx(
148
+ "div",
149
+ {
150
+ ref,
151
+ className: cn(
152
+ "flex h-full w-full flex-col overflow-hidden rounded-md bg-popover text-popover-foreground",
153
+ className
154
+ ),
155
+ ...props
156
+ }
157
+ ));
158
+ Command.displayName = "Command";
159
+ var CommandInput = React6.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx(
160
+ "input",
161
+ {
162
+ ref,
163
+ className: cn(
164
+ "flex h-11 w-full rounded-md border border-input bg-transparent py-3 text-sm outline-none placeholder:text-muted-foreground disabled:cursor-not-allowed disabled:opacity-50 px-3",
165
+ className
166
+ ),
167
+ ...props
168
+ }
169
+ ));
170
+ CommandInput.displayName = "CommandInput";
171
+ var CommandList = React6.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx(
172
+ "div",
173
+ {
174
+ ref,
175
+ className: cn("max-h-[300px] overflow-y-auto overflow-x-hidden", className),
176
+ ...props
177
+ }
178
+ ));
179
+ CommandList.displayName = "CommandList";
180
+ var CommandEmpty = React6.forwardRef((props, ref) => /* @__PURE__ */ jsx(
181
+ "div",
182
+ {
183
+ ref,
184
+ className: "py-6 text-center text-sm",
185
+ ...props
186
+ }
187
+ ));
188
+ CommandEmpty.displayName = "CommandEmpty";
189
+ var CommandGroup = React6.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx(
190
+ "div",
191
+ {
192
+ ref,
193
+ className: cn(
194
+ "overflow-hidden p-1 text-foreground [&_[cmdk-group-heading]]:px-2 [&_[cmdk-group-heading]]:py-1.5 [&_[cmdk-group-heading]]:text-xs [&_[cmdk-group-heading]]:font-medium [&_[cmdk-group-heading]]:text-muted-foreground",
195
+ className
196
+ ),
197
+ ...props
198
+ }
199
+ ));
200
+ CommandGroup.displayName = "CommandGroup";
201
+ var CommandItem = React6.forwardRef(({ className, onSelect, value, ...props }, ref) => {
202
+ const handleClick = () => {
203
+ if (onSelect && value) {
204
+ onSelect(value);
205
+ }
206
+ };
207
+ return /* @__PURE__ */ jsx(
208
+ "div",
209
+ {
210
+ ref,
211
+ className: cn(
212
+ "relative flex cursor-default select-none items-center rounded-sm px-2 py-1.5 text-sm outline-none aria-selected:bg-accent aria-selected:text-accent-foreground data-[disabled]:pointer-events-none data-[disabled]:opacity-50",
213
+ className
214
+ ),
215
+ onClick: handleClick,
216
+ ...props
217
+ }
218
+ );
219
+ });
220
+ CommandItem.displayName = "CommandItem";
221
+ var Popover = PopoverPrimitive.Root;
222
+ var PopoverTrigger = PopoverPrimitive.Trigger;
223
+ var PopoverContent = React6.forwardRef(({ className, align = "center", sideOffset = 4, ...props }, ref) => /* @__PURE__ */ jsx(PopoverPrimitive.Portal, { children: /* @__PURE__ */ jsx(
224
+ PopoverPrimitive.Content,
225
+ {
226
+ ref,
227
+ align,
228
+ sideOffset,
229
+ className: cn(
230
+ "z-50 w-72 rounded-md border bg-popover p-4 text-popover-foreground shadow-md outline-none data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2",
231
+ className
232
+ ),
233
+ ...props
234
+ }
235
+ ) }));
236
+ PopoverContent.displayName = PopoverPrimitive.Content.displayName;
237
+ var Input = React6.forwardRef(
238
+ ({ className, type, ...props }, ref) => {
239
+ return /* @__PURE__ */ jsx(
240
+ "input",
241
+ {
242
+ type,
243
+ className: cn(
244
+ "flex h-10 w-full rounded-md border border-input bg-background px-3 py-2 text-sm ring-offset-background file:border-0 file:bg-transparent file:text-sm file:font-medium placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50",
245
+ className
246
+ ),
247
+ ref,
248
+ ...props
249
+ }
250
+ );
251
+ }
252
+ );
253
+ Input.displayName = "Input";
254
+ var Select = SelectPrimitive.Root;
255
+ var SelectValue = SelectPrimitive.Value;
256
+ var SelectTrigger = React6.forwardRef(({ className, children, ...props }, ref) => /* @__PURE__ */ jsxs(
257
+ SelectPrimitive.Trigger,
258
+ {
259
+ ref,
260
+ className: cn(
261
+ "flex h-10 w-full items-center justify-between rounded-md border border-input bg-background px-3 py-2 text-sm ring-offset-background placeholder:text-muted-foreground focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50 [&>span]:line-clamp-1",
262
+ className
263
+ ),
264
+ ...props,
265
+ children: [
266
+ children,
267
+ /* @__PURE__ */ jsx(SelectPrimitive.Icon, { asChild: true, children: /* @__PURE__ */ jsx(ChevronDown, { className: "h-4 w-4 opacity-50" }) })
268
+ ]
269
+ }
270
+ ));
271
+ SelectTrigger.displayName = SelectPrimitive.Trigger.displayName;
272
+ var SelectScrollUpButton = React6.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx(
273
+ SelectPrimitive.ScrollUpButton,
274
+ {
275
+ ref,
276
+ className: cn(
277
+ "flex cursor-default items-center justify-center py-1",
278
+ className
279
+ ),
280
+ ...props,
281
+ children: /* @__PURE__ */ jsx(ChevronUp, { className: "h-4 w-4" })
282
+ }
283
+ ));
284
+ SelectScrollUpButton.displayName = SelectPrimitive.ScrollUpButton.displayName;
285
+ var SelectScrollDownButton = React6.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx(
286
+ SelectPrimitive.ScrollDownButton,
287
+ {
288
+ ref,
289
+ className: cn(
290
+ "flex cursor-default items-center justify-center py-1",
291
+ className
292
+ ),
293
+ ...props,
294
+ children: /* @__PURE__ */ jsx(ChevronDown, { className: "h-4 w-4" })
295
+ }
296
+ ));
297
+ SelectScrollDownButton.displayName = SelectPrimitive.ScrollDownButton.displayName;
298
+ var SelectContent = React6.forwardRef(({ className, children, position = "popper", ...props }, ref) => /* @__PURE__ */ jsx(SelectPrimitive.Portal, { children: /* @__PURE__ */ jsxs(
299
+ SelectPrimitive.Content,
300
+ {
301
+ ref,
302
+ className: cn(
303
+ "relative z-50 max-h-96 min-w-[8rem] overflow-hidden rounded-md border bg-popover text-popover-foreground shadow-md data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2",
304
+ position === "popper" && "data-[side=bottom]:translate-y-1 data-[side=left]:-translate-x-1 data-[side=right]:translate-x-1 data-[side=top]:-translate-y-1",
305
+ className
306
+ ),
307
+ position,
308
+ ...props,
309
+ children: [
310
+ /* @__PURE__ */ jsx(SelectScrollUpButton, {}),
311
+ /* @__PURE__ */ jsx(
312
+ SelectPrimitive.Viewport,
313
+ {
314
+ className: cn(
315
+ "p-1",
316
+ position === "popper" && "h-[var(--radix-select-trigger-height)] w-full min-w-[var(--radix-select-trigger-width)]"
317
+ ),
318
+ children
319
+ }
320
+ ),
321
+ /* @__PURE__ */ jsx(SelectScrollDownButton, {})
322
+ ]
323
+ }
324
+ ) }));
325
+ SelectContent.displayName = SelectPrimitive.Content.displayName;
326
+ var SelectLabel = React6.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx(
327
+ SelectPrimitive.Label,
328
+ {
329
+ ref,
330
+ className: cn("py-1.5 pl-8 pr-2 text-sm font-semibold", className),
331
+ ...props
332
+ }
333
+ ));
334
+ SelectLabel.displayName = SelectPrimitive.Label.displayName;
335
+ var SelectItem = React6.forwardRef(({ className, children, ...props }, ref) => /* @__PURE__ */ jsxs(
336
+ SelectPrimitive.Item,
337
+ {
338
+ ref,
339
+ className: cn(
340
+ "relative flex w-full cursor-default select-none items-center rounded-sm py-1.5 pl-8 pr-2 text-sm outline-none focus:bg-accent focus:text-accent-foreground data-[disabled]:pointer-events-none data-[disabled]:opacity-50",
341
+ className
342
+ ),
343
+ ...props,
344
+ children: [
345
+ /* @__PURE__ */ jsx("span", { className: "absolute left-2 flex h-3.5 w-3.5 items-center justify-center", children: /* @__PURE__ */ jsx(SelectPrimitive.ItemIndicator, { children: /* @__PURE__ */ jsx(Check, { className: "h-4 w-4" }) }) }),
346
+ /* @__PURE__ */ jsx(SelectPrimitive.ItemText, { children })
347
+ ]
348
+ }
349
+ ));
350
+ SelectItem.displayName = SelectPrimitive.Item.displayName;
351
+ var SelectSeparator = React6.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx(
352
+ SelectPrimitive.Separator,
353
+ {
354
+ ref,
355
+ className: cn("-mx-1 my-1 h-px bg-muted", className),
356
+ ...props
357
+ }
358
+ ));
359
+ SelectSeparator.displayName = SelectPrimitive.Separator.displayName;
360
+ var TooltipProvider = TooltipPrimitive.Provider;
361
+ var Tooltip = TooltipPrimitive.Root;
362
+ var TooltipTrigger = TooltipPrimitive.Trigger;
363
+ var TooltipContent = React6.forwardRef(({ className, sideOffset = 4, ...props }, ref) => /* @__PURE__ */ jsx(
364
+ TooltipPrimitive.Content,
365
+ {
366
+ ref,
367
+ sideOffset,
368
+ className: cn(
369
+ "z-50 overflow-hidden rounded-md border bg-popover px-3 py-1.5 text-sm text-popover-foreground shadow-md animate-in fade-in-0 zoom-in-95 data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=closed]:zoom-out-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2",
370
+ className
371
+ ),
372
+ ...props
373
+ }
374
+ ));
375
+ TooltipContent.displayName = TooltipPrimitive.Content.displayName;
376
+ function Calendar({
377
+ className,
378
+ classNames,
379
+ showOutsideDays = true,
380
+ ...props
381
+ }) {
382
+ return /* @__PURE__ */ jsx(
383
+ DayPicker,
384
+ {
385
+ showOutsideDays,
386
+ className: cn("p-3", className),
387
+ classNames: {
388
+ months: "flex flex-col sm:flex-row space-y-4 sm:space-x-4 sm:space-y-0",
389
+ month: "space-y-4",
390
+ caption: "flex justify-center pt-1 relative items-center",
391
+ caption_label: "text-sm font-medium",
392
+ nav: "space-x-1 flex items-center",
393
+ nav_button: cn(
394
+ "h-7 w-7 bg-transparent p-0 opacity-50 hover:opacity-100"
395
+ ),
396
+ nav_button_previous: "absolute left-1",
397
+ nav_button_next: "absolute right-1",
398
+ table: "w-full border-collapse space-y-1",
399
+ head_row: "flex",
400
+ head_cell: "text-muted-foreground rounded-md w-9 font-normal text-[0.8rem]",
401
+ row: "flex w-full mt-2",
402
+ cell: "h-9 w-9 text-center text-sm p-0 relative [&:has([aria-selected].day-range-end)]:rounded-r-md [&:has([aria-selected].day-outside)]:bg-accent/50 [&:has([aria-selected])]:bg-accent first:[&:has([aria-selected])]:rounded-l-md last:[&:has([aria-selected])]:rounded-r-md focus-within:relative focus-within:z-20",
403
+ day: cn(
404
+ "h-9 w-9 p-0 font-normal aria-selected:opacity-100"
405
+ ),
406
+ day_range_end: "day-range-end",
407
+ day_selected: "bg-primary text-primary-foreground hover:bg-primary hover:text-primary-foreground focus:bg-primary focus:text-primary-foreground",
408
+ day_today: "bg-accent text-accent-foreground",
409
+ day_outside: "day-outside text-muted-foreground opacity-50 aria-selected:bg-accent/50 aria-selected:text-muted-foreground aria-selected:opacity-30",
410
+ day_disabled: "text-muted-foreground opacity-50",
411
+ day_range_middle: "aria-selected:bg-accent aria-selected:text-accent-foreground",
412
+ day_hidden: "invisible",
413
+ ...classNames
414
+ },
415
+ components: {
416
+ IconLeft: () => /* @__PURE__ */ jsx(ChevronLeft, { className: "h-4 w-4" }),
417
+ IconRight: () => /* @__PURE__ */ jsx(ChevronRight, { className: "h-4 w-4" })
418
+ },
419
+ ...props
420
+ }
421
+ );
422
+ }
423
+ Calendar.displayName = "Calendar";
424
+ function FilterFieldItem({
425
+ filterConfig,
426
+ fieldConfig,
427
+ onValueChange,
428
+ onOperatorChange,
429
+ onDelete
430
+ }) {
431
+ const [isCalendarOpen, setIsCalendarOpen] = useState(false);
432
+ const renderInput = () => {
433
+ switch (fieldConfig.type) {
434
+ case "text":
435
+ return /* @__PURE__ */ jsx(
436
+ Input,
437
+ {
438
+ type: "text",
439
+ value: filterConfig.value || "",
440
+ onChange: (e) => {
441
+ const value = e.target.value;
442
+ if (fieldConfig.textConfig?.maxLength && value.length > fieldConfig.textConfig.maxLength) {
443
+ return;
444
+ }
445
+ onValueChange(value);
446
+ },
447
+ placeholder: "Enter text...",
448
+ minLength: fieldConfig.textConfig?.minLength,
449
+ maxLength: fieldConfig.textConfig?.maxLength,
450
+ className: "cls_filter_text_input w-full min-w-0"
451
+ }
452
+ );
453
+ case "number":
454
+ const numberOperators = [
455
+ { value: "equals", label: "Equals" },
456
+ { value: "not_equals", label: "Not Equals" },
457
+ { value: "greater_than", label: "Greater Than" },
458
+ { value: "less_than", label: "Less Than" },
459
+ { value: "greater_equal", label: "Greater or Equal" },
460
+ { value: "less_equal", label: "Less or Equal" }
461
+ ];
462
+ return /* @__PURE__ */ jsxs("div", { className: "cls_number_filter_container flex flex-col sm:flex-row items-stretch sm:items-center gap-2 w-full", children: [
463
+ /* @__PURE__ */ jsxs(
464
+ Select,
465
+ {
466
+ value: filterConfig.operator || "equals",
467
+ onValueChange: (value) => onOperatorChange?.(value),
468
+ children: [
469
+ /* @__PURE__ */ jsx(SelectTrigger, { className: "cls_operator_select w-full sm:w-[140px] shrink-0", children: /* @__PURE__ */ jsx(SelectValue, {}) }),
470
+ /* @__PURE__ */ jsx(SelectContent, { children: numberOperators.map((op) => /* @__PURE__ */ jsx(SelectItem, { value: op.value, children: op.label }, op.value)) })
471
+ ]
472
+ }
473
+ ),
474
+ /* @__PURE__ */ jsx(
475
+ Input,
476
+ {
477
+ type: "number",
478
+ value: filterConfig.value !== void 0 && filterConfig.value !== null ? filterConfig.value : "",
479
+ onChange: (e) => {
480
+ const value = e.target.value;
481
+ if (value === "") {
482
+ onValueChange("");
483
+ return;
484
+ }
485
+ let numValue = fieldConfig.numberConfig?.allowDecimal ? parseFloat(value) : parseInt(value, 10);
486
+ if (isNaN(numValue)) {
487
+ return;
488
+ }
489
+ if (fieldConfig.numberConfig?.allowDecimal && fieldConfig.numberConfig?.decimalLength) {
490
+ const decimalPlaces = value.split(".")[1]?.length || 0;
491
+ if (decimalPlaces > fieldConfig.numberConfig.decimalLength) {
492
+ return;
493
+ }
494
+ }
495
+ if (fieldConfig.numberConfig?.min !== void 0 && numValue < fieldConfig.numberConfig.min) {
496
+ numValue = fieldConfig.numberConfig.min;
497
+ }
498
+ if (fieldConfig.numberConfig?.max !== void 0 && numValue > fieldConfig.numberConfig.max) {
499
+ numValue = fieldConfig.numberConfig.max;
500
+ }
501
+ onValueChange(numValue);
502
+ },
503
+ placeholder: "Enter number...",
504
+ min: fieldConfig.numberConfig?.min,
505
+ max: fieldConfig.numberConfig?.max,
506
+ step: fieldConfig.numberConfig?.allowDecimal ? 0.01 : 1,
507
+ className: "cls_filter_number_input flex-1 min-w-0"
508
+ }
509
+ )
510
+ ] });
511
+ case "combobox":
512
+ return /* @__PURE__ */ jsxs(
513
+ Select,
514
+ {
515
+ value: filterConfig.value || "",
516
+ onValueChange: (value) => onValueChange(value),
517
+ children: [
518
+ /* @__PURE__ */ jsx(SelectTrigger, { className: "cls_filter_combobox_select w-full min-w-0", children: /* @__PURE__ */ jsx(SelectValue, { placeholder: "Select option..." }) }),
519
+ /* @__PURE__ */ jsx(SelectContent, { children: fieldConfig.comboboxOptions?.map((option) => /* @__PURE__ */ jsx(SelectItem, { value: option.value, children: option.label }, option.value)) })
520
+ ]
521
+ }
522
+ );
523
+ case "boolean":
524
+ const trueLabel = fieldConfig.booleanLabels?.trueLabel || "On";
525
+ const falseLabel = fieldConfig.booleanLabels?.falseLabel || "Off";
526
+ return /* @__PURE__ */ jsxs(
527
+ Select,
528
+ {
529
+ value: filterConfig.value !== void 0 && filterConfig.value !== null ? String(filterConfig.value) : "",
530
+ onValueChange: (value) => onValueChange(value === "true"),
531
+ children: [
532
+ /* @__PURE__ */ jsx(SelectTrigger, { className: "cls_filter_boolean_select w-full min-w-0", children: /* @__PURE__ */ jsx(SelectValue, { placeholder: "Select..." }) }),
533
+ /* @__PURE__ */ jsxs(SelectContent, { children: [
534
+ /* @__PURE__ */ jsx(SelectItem, { value: "true", children: trueLabel }),
535
+ /* @__PURE__ */ jsx(SelectItem, { value: "false", children: falseLabel })
536
+ ] })
537
+ ]
538
+ }
539
+ );
540
+ case "date":
541
+ const dateOperators = [
542
+ { value: "equals", label: "Equals" },
543
+ { value: "not_equals", label: "Not Equals" },
544
+ { value: "greater_than", label: "Greater Than" },
545
+ { value: "less_than", label: "Less Than" },
546
+ { value: "greater_equal", label: "Greater or Equal" },
547
+ { value: "less_equal", label: "Less or Equal" }
548
+ ];
549
+ const selectedDate = filterConfig.value ? typeof filterConfig.value === "string" ? new Date(filterConfig.value) : filterConfig.value : void 0;
550
+ return /* @__PURE__ */ jsxs("div", { className: "cls_date_filter_container flex flex-col sm:flex-row items-stretch sm:items-center gap-2 w-full", children: [
551
+ /* @__PURE__ */ jsxs(
552
+ Select,
553
+ {
554
+ value: filterConfig.operator || "equals",
555
+ onValueChange: (value) => onOperatorChange?.(value),
556
+ children: [
557
+ /* @__PURE__ */ jsx(SelectTrigger, { className: "cls_operator_select w-full sm:w-[140px] shrink-0", children: /* @__PURE__ */ jsx(SelectValue, {}) }),
558
+ /* @__PURE__ */ jsx(SelectContent, { children: dateOperators.map((op) => /* @__PURE__ */ jsx(SelectItem, { value: op.value, children: op.label }, op.value)) })
559
+ ]
560
+ }
561
+ ),
562
+ /* @__PURE__ */ jsxs(Popover, { open: isCalendarOpen, onOpenChange: setIsCalendarOpen, children: [
563
+ /* @__PURE__ */ jsx(PopoverTrigger, { asChild: true, children: /* @__PURE__ */ jsxs(
564
+ Button,
565
+ {
566
+ variant: "outline",
567
+ className: cn(
568
+ "cls_date_picker_trigger w-full justify-start text-left font-normal min-w-0",
569
+ !selectedDate && "text-muted-foreground"
570
+ ),
571
+ children: [
572
+ /* @__PURE__ */ jsx(Calendar$1, { className: "cls_calendar_icon mr-2 h-4 w-4 shrink-0" }),
573
+ /* @__PURE__ */ jsx("span", { className: "cls_date_text truncate", children: selectedDate ? format(selectedDate, "MMM d, yyyy") : "Pick a date" })
574
+ ]
575
+ }
576
+ ) }),
577
+ /* @__PURE__ */ jsx(PopoverContent, { className: "cls_calendar_popover w-auto p-0", align: "start", children: /* @__PURE__ */ jsx(
578
+ Calendar,
579
+ {
580
+ mode: "single",
581
+ selected: selectedDate,
582
+ onSelect: (date) => {
583
+ onValueChange(date);
584
+ setIsCalendarOpen(false);
585
+ },
586
+ initialFocus: true
587
+ }
588
+ ) })
589
+ ] })
590
+ ] });
591
+ default:
592
+ return null;
593
+ }
594
+ };
595
+ return /* @__PURE__ */ jsxs("div", { className: "cls_filter_field_item flex flex-col sm:flex-row items-start sm:items-center gap-3 p-3 border rounded-md bg-card", children: [
596
+ /* @__PURE__ */ jsx("span", { className: "cls_field_label text-sm font-medium min-w-[120px] sm:min-w-[100px] truncate", children: fieldConfig.label }),
597
+ /* @__PURE__ */ jsx("div", { className: "cls_field_input_container flex-1 min-w-0 w-full sm:w-auto", children: renderInput() }),
598
+ /* @__PURE__ */ jsx(
599
+ Button,
600
+ {
601
+ variant: "ghost",
602
+ size: "sm",
603
+ onClick: onDelete,
604
+ className: "cls_delete_btn h-8 w-8 p-0 text-destructive hover:text-destructive shrink-0",
605
+ "aria-label": `Remove ${fieldConfig.label} filter`,
606
+ children: /* @__PURE__ */ jsx(Trash2, { className: "cls_delete_icon h-4 w-4" })
607
+ }
608
+ )
609
+ ] });
610
+ }
611
+ function MultiFilterDialog({
612
+ availableFields,
613
+ onFilterChange,
614
+ initialFilters = []
615
+ }) {
616
+ const [isOpen, setIsOpen] = useState(false);
617
+ const [filterFields, setFilterFields] = useState(initialFilters);
618
+ const [isComboboxOpen, setIsComboboxOpen] = useState(false);
619
+ useEffect(() => {
620
+ if (isOpen) {
621
+ setFilterFields(initialFilters);
622
+ }
623
+ }, [isOpen, initialFilters]);
624
+ const handleAddField = (fieldValue) => {
625
+ if (filterFields.some((ff) => ff.field === fieldValue)) {
626
+ return;
627
+ }
628
+ const fieldConfig = availableFields.find((af) => af.value === fieldValue);
629
+ if (!fieldConfig) {
630
+ return;
631
+ }
632
+ let defaultValue = "";
633
+ if (fieldConfig.type === "boolean") {
634
+ defaultValue = false;
635
+ } else if (fieldConfig.type === "number") {
636
+ defaultValue = fieldConfig.numberConfig?.min || 0;
637
+ } else if (fieldConfig.type === "date") {
638
+ defaultValue = /* @__PURE__ */ new Date();
639
+ }
640
+ const newFilter = {
641
+ field: fieldValue,
642
+ operator: fieldConfig.type === "number" || fieldConfig.type === "date" ? "equals" : void 0,
643
+ value: defaultValue
644
+ };
645
+ setFilterFields([...filterFields, newFilter]);
646
+ setIsComboboxOpen(false);
647
+ };
648
+ const handleDeleteField = (fieldValue) => {
649
+ setFilterFields(filterFields.filter((ff) => ff.field !== fieldValue));
650
+ };
651
+ const handleValueChange = (fieldValue, value) => {
652
+ setFilterFields(
653
+ filterFields.map(
654
+ (ff) => ff.field === fieldValue ? { ...ff, value } : ff
655
+ )
656
+ );
657
+ };
658
+ const handleOperatorChange = (fieldValue, operator) => {
659
+ setFilterFields(
660
+ filterFields.map(
661
+ (ff) => ff.field === fieldValue ? { ...ff, operator } : ff
662
+ )
663
+ );
664
+ };
665
+ const handleApply = () => {
666
+ onFilterChange([...filterFields]);
667
+ setIsOpen(false);
668
+ };
669
+ const handleCancel = () => {
670
+ setFilterFields(initialFilters);
671
+ setIsOpen(false);
672
+ };
673
+ const availableFieldsToAdd = availableFields.filter(
674
+ (af) => !filterFields.some((ff) => ff.field === af.value)
675
+ );
676
+ const getFieldConfig = (fieldValue) => {
677
+ return availableFields.find((af) => af.value === fieldValue);
678
+ };
679
+ const hasActiveFilters = initialFilters.length > 0;
680
+ const tooltipContent = hasActiveFilters ? /* @__PURE__ */ jsxs("div", { className: "cls_filter_tooltip_content space-y-1", children: [
681
+ /* @__PURE__ */ jsx("div", { className: "cls_tooltip_title text-xs font-semibold mb-1", children: "Active Filters:" }),
682
+ initialFilters.map((filterConfig) => {
683
+ const fieldConfig = getFieldConfig(filterConfig.field);
684
+ if (!fieldConfig) return null;
685
+ let displayValue = String(filterConfig.value);
686
+ if (fieldConfig.type === "boolean") {
687
+ displayValue = filterConfig.value ? fieldConfig.booleanLabels?.trueLabel || "On" : fieldConfig.booleanLabels?.falseLabel || "Off";
688
+ } else if (fieldConfig.type === "combobox") {
689
+ const option = fieldConfig.comboboxOptions?.find((opt) => opt.value === filterConfig.value);
690
+ displayValue = option?.label || displayValue;
691
+ } else if (fieldConfig.type === "date") {
692
+ const dateValue = filterConfig.value instanceof Date ? filterConfig.value : new Date(filterConfig.value);
693
+ if (!isNaN(dateValue.getTime())) {
694
+ displayValue = format(dateValue, "MMM d, yyyy");
695
+ }
696
+ }
697
+ const operatorLabel = filterConfig.operator ? filterConfig.operator.replace("_", " ").replace(/\b\w/g, (l) => l.toUpperCase()) + " " : "";
698
+ return /* @__PURE__ */ jsxs("div", { className: "cls_tooltip_item text-xs", children: [
699
+ fieldConfig.label,
700
+ ": ",
701
+ operatorLabel,
702
+ displayValue
703
+ ] }, filterConfig.field);
704
+ })
705
+ ] }) : /* @__PURE__ */ jsx("div", { className: "cls_filter_tooltip_content text-xs", children: "No active filters" });
706
+ return /* @__PURE__ */ jsxs(Dialog, { open: isOpen, onOpenChange: setIsOpen, children: [
707
+ /* @__PURE__ */ jsx(TooltipProvider, { children: /* @__PURE__ */ jsxs(Tooltip, { children: [
708
+ /* @__PURE__ */ jsx(TooltipTrigger, { asChild: true, children: /* @__PURE__ */ jsx(DialogTrigger, { asChild: true, children: /* @__PURE__ */ jsxs(
709
+ Button,
710
+ {
711
+ variant: "outline",
712
+ size: "sm",
713
+ className: "cls_filter_button",
714
+ "aria-label": "Open filter dialog",
715
+ children: [
716
+ /* @__PURE__ */ jsx(
717
+ Filter,
718
+ {
719
+ className: cn(
720
+ "cls_filter_icon h-4 w-4 mr-2",
721
+ hasActiveFilters && "text-blue-600"
722
+ )
723
+ }
724
+ ),
725
+ "Filter"
726
+ ]
727
+ }
728
+ ) }) }),
729
+ /* @__PURE__ */ jsx(TooltipContent, { children: tooltipContent })
730
+ ] }) }),
731
+ /* @__PURE__ */ jsxs(DialogContent, { className: "cls_filter_dialog_content max-w-lg w-full max-h-[90vh] overflow-y-auto", children: [
732
+ /* @__PURE__ */ jsxs(DialogHeader, { children: [
733
+ /* @__PURE__ */ jsx(DialogTitle, { children: "Filter Images" }),
734
+ /* @__PURE__ */ jsx(DialogDescription, { children: "Add multiple fields to filter by. Select a field and set its filter value." })
735
+ ] }),
736
+ /* @__PURE__ */ jsxs("div", { className: "cls_filter_dialog_body space-y-4 py-4", children: [
737
+ /* @__PURE__ */ jsx("div", { className: "cls_add_field_section", children: /* @__PURE__ */ jsxs(Popover, { open: isComboboxOpen, onOpenChange: setIsComboboxOpen, children: [
738
+ /* @__PURE__ */ jsx(PopoverTrigger, { asChild: true, children: /* @__PURE__ */ jsxs(
739
+ Button,
740
+ {
741
+ variant: "outline",
742
+ role: "combobox",
743
+ "aria-expanded": isComboboxOpen,
744
+ className: "cls_add_field_combobox w-full justify-between",
745
+ children: [
746
+ /* @__PURE__ */ jsxs("div", { className: "cls_combobox_content flex items-center", children: [
747
+ /* @__PURE__ */ jsx(Plus, { className: "cls_plus_icon h-4 w-4 mr-2" }),
748
+ /* @__PURE__ */ jsx("span", { children: "Add field" })
749
+ ] }),
750
+ /* @__PURE__ */ jsx(ChevronsUpDown, { className: "cls_chevron_icon ml-2 h-4 w-4 shrink-0 opacity-50" })
751
+ ]
752
+ }
753
+ ) }),
754
+ /* @__PURE__ */ jsx(PopoverContent, { className: "cls_combobox_popover w-full p-0", children: /* @__PURE__ */ jsxs(Command, { children: [
755
+ /* @__PURE__ */ jsx(CommandInput, { placeholder: "Search fields...", className: "cls_command_input" }),
756
+ /* @__PURE__ */ jsxs(CommandList, { children: [
757
+ /* @__PURE__ */ jsx(CommandEmpty, { children: "No fields found." }),
758
+ /* @__PURE__ */ jsx(CommandGroup, { children: availableFieldsToAdd.map((field) => /* @__PURE__ */ jsxs(
759
+ CommandItem,
760
+ {
761
+ value: field.value,
762
+ onSelect: () => handleAddField(field.value),
763
+ className: "cls_command_item",
764
+ children: [
765
+ /* @__PURE__ */ jsx(
766
+ Check,
767
+ {
768
+ className: cn(
769
+ "cls_check_icon mr-2 h-4 w-4",
770
+ "opacity-0"
771
+ )
772
+ }
773
+ ),
774
+ field.label
775
+ ]
776
+ },
777
+ field.value
778
+ )) })
779
+ ] })
780
+ ] }) })
781
+ ] }) }),
782
+ filterFields.length > 0 ? /* @__PURE__ */ jsx("div", { className: "cls_filter_fields_list space-y-2", children: filterFields.map((filterConfig) => {
783
+ const fieldConfig = getFieldConfig(filterConfig.field);
784
+ if (!fieldConfig) return null;
785
+ return /* @__PURE__ */ jsx(
786
+ FilterFieldItem,
787
+ {
788
+ filterConfig,
789
+ fieldConfig,
790
+ onValueChange: (value) => handleValueChange(filterConfig.field, value),
791
+ onOperatorChange: (operator) => handleOperatorChange(filterConfig.field, operator),
792
+ onDelete: () => handleDeleteField(filterConfig.field)
793
+ },
794
+ filterConfig.field
795
+ );
796
+ }) }) : /* @__PURE__ */ jsx("div", { className: "cls_empty_filter_fields text-center py-8 text-sm text-muted-foreground", children: 'No filter fields added. Click "Add field" to add filtering criteria.' })
797
+ ] }),
798
+ /* @__PURE__ */ jsxs(DialogFooter, { children: [
799
+ /* @__PURE__ */ jsx(
800
+ Button,
801
+ {
802
+ onClick: handleApply,
803
+ className: "cls_apply_btn",
804
+ children: "Apply"
805
+ }
806
+ ),
807
+ /* @__PURE__ */ jsx(
808
+ Button,
809
+ {
810
+ variant: "outline",
811
+ onClick: handleCancel,
812
+ className: "cls_cancel_btn",
813
+ children: "Cancel"
814
+ }
815
+ )
816
+ ] })
817
+ ] })
818
+ ] });
819
+ }
820
+
821
+ export { ExampleComponent, MultiFilterDialog };
822
+ //# sourceMappingURL=index.js.map
823
+ //# sourceMappingURL=index.js.map