@algodomain/smart-forms 0.1.3 → 0.1.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.
@@ -1,16 +1,19 @@
1
- import { useSmartForm, useFormField, useFieldDetection, Label, TooltipProvider, Tooltip, TooltipTrigger, TooltipContent, cn, Input } from './chunk-3L7TKJIB.js';
2
- import * as React4 from 'react';
3
- import { useRef, useEffect, useMemo, useState } from 'react';
1
+ import { useSmartForm, useFormField, useFieldDetection, Label, TooltipProvider, Tooltip, TooltipTrigger, TooltipContent, cn, SmartInput, Input } from './chunk-RHECLW3K.js';
2
+ import * as React6 from 'react';
3
+ import React6__default, { useRef, useEffect, useState } from 'react';
4
4
  import * as CheckboxPrimitive from '@radix-ui/react-checkbox';
5
- import { InfoIcon, Calendar as Calendar$1, X, CheckIcon, CircleIcon, ChevronDownIcon, ChevronLeftIcon, ChevronRightIcon, ChevronUpIcon } from 'lucide-react';
5
+ import { InfoIcon, SearchIcon, CalendarIcon, ChevronDownIcon, X, CheckIcon, CircleIcon, ChevronsUpDown, Check, Plus, ChevronLeftIcon, ChevronRightIcon, ChevronUpIcon } from 'lucide-react';
6
6
  import { jsxs, jsx } from 'react/jsx-runtime';
7
7
  import * as RadioGroupPrimitive from '@radix-ui/react-radio-group';
8
8
  import * as SelectPrimitive from '@radix-ui/react-select';
9
- import { format } from 'date-fns';
9
+ import * as PopoverPrimitive from '@radix-ui/react-popover';
10
10
  import { Slot } from '@radix-ui/react-slot';
11
11
  import { cva } from 'class-variance-authority';
12
+ import { Command as Command$1 } from 'cmdk';
13
+ import { eachYearOfInterval, endOfYear, startOfYear, eachMonthOfInterval, isBefore, isAfter, format } from 'date-fns';
12
14
  import { getDefaultClassNames, DayPicker } from 'react-day-picker';
13
- import * as PopoverPrimitive from '@radix-ui/react-popover';
15
+ import * as CollapsiblePrimitive from '@radix-ui/react-collapsible';
16
+ import * as ScrollAreaPrimitive from '@radix-ui/react-scroll-area';
14
17
 
15
18
  function Checkbox({
16
19
  className,
@@ -428,6 +431,36 @@ var SmartSelect = ({
428
431
  error && /* @__PURE__ */ jsx("p", { className: "text-destructive text-sm mt-1", children: error })
429
432
  ] });
430
433
  };
434
+ function Popover({
435
+ ...props
436
+ }) {
437
+ return /* @__PURE__ */ jsx(PopoverPrimitive.Root, { "data-slot": "popover", ...props });
438
+ }
439
+ function PopoverTrigger({
440
+ ...props
441
+ }) {
442
+ return /* @__PURE__ */ jsx(PopoverPrimitive.Trigger, { "data-slot": "popover-trigger", ...props });
443
+ }
444
+ function PopoverContent({
445
+ className,
446
+ align = "center",
447
+ sideOffset = 4,
448
+ ...props
449
+ }) {
450
+ return /* @__PURE__ */ jsx(PopoverPrimitive.Portal, { children: /* @__PURE__ */ jsx(
451
+ PopoverPrimitive.Content,
452
+ {
453
+ "data-slot": "popover-content",
454
+ align,
455
+ sideOffset,
456
+ className: cn(
457
+ "bg-popover text-popover-foreground 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 z-50 origin-(--radix-popover-content-transform-origin) rounded-md border p-4 shadow-md outline-hidden",
458
+ className
459
+ ),
460
+ ...props
461
+ }
462
+ ) });
463
+ }
431
464
  var buttonVariants = cva(
432
465
  "inline-flex items-center justify-center gap-2 whitespace-nowrap rounded-md text-sm font-medium transition-all disabled:pointer-events-none disabled:opacity-50 [&_svg]:pointer-events-none [&_svg:not([class*='size-'])]:size-4 shrink-0 [&_svg]:shrink-0 outline-none focus-visible:border-ring focus-visible:ring-ring/50 focus-visible:ring-[3px] aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 aria-invalid:border-destructive",
433
466
  {
@@ -470,6 +503,323 @@ function Button({
470
503
  }
471
504
  );
472
505
  }
506
+ function Command({
507
+ className,
508
+ ...props
509
+ }) {
510
+ return /* @__PURE__ */ jsx(
511
+ Command$1,
512
+ {
513
+ "data-slot": "command",
514
+ className: cn(
515
+ "bg-popover text-popover-foreground flex h-full w-full flex-col overflow-hidden rounded-md",
516
+ className
517
+ ),
518
+ ...props
519
+ }
520
+ );
521
+ }
522
+ function CommandInput({
523
+ className,
524
+ ...props
525
+ }) {
526
+ return /* @__PURE__ */ jsxs(
527
+ "div",
528
+ {
529
+ "data-slot": "command-input-wrapper",
530
+ className: "flex h-9 items-center gap-2 border-b px-3",
531
+ children: [
532
+ /* @__PURE__ */ jsx(SearchIcon, { className: "size-4 shrink-0 opacity-50" }),
533
+ /* @__PURE__ */ jsx(
534
+ Command$1.Input,
535
+ {
536
+ "data-slot": "command-input",
537
+ className: cn(
538
+ "placeholder:text-muted-foreground flex h-10 w-full rounded-md bg-transparent py-3 text-sm outline-hidden disabled:cursor-not-allowed disabled:opacity-50",
539
+ className
540
+ ),
541
+ ...props
542
+ }
543
+ )
544
+ ]
545
+ }
546
+ );
547
+ }
548
+ function CommandList({
549
+ className,
550
+ ...props
551
+ }) {
552
+ return /* @__PURE__ */ jsx(
553
+ Command$1.List,
554
+ {
555
+ "data-slot": "command-list",
556
+ className: cn(
557
+ "max-h-[300px] scroll-py-1 overflow-x-hidden overflow-y-auto",
558
+ className
559
+ ),
560
+ ...props
561
+ }
562
+ );
563
+ }
564
+ function CommandEmpty({
565
+ ...props
566
+ }) {
567
+ return /* @__PURE__ */ jsx(
568
+ Command$1.Empty,
569
+ {
570
+ "data-slot": "command-empty",
571
+ className: "py-6 text-center text-sm",
572
+ ...props
573
+ }
574
+ );
575
+ }
576
+ function CommandGroup({
577
+ className,
578
+ ...props
579
+ }) {
580
+ return /* @__PURE__ */ jsx(
581
+ Command$1.Group,
582
+ {
583
+ "data-slot": "command-group",
584
+ className: cn(
585
+ "text-foreground [&_[cmdk-group-heading]]:text-muted-foreground overflow-hidden p-1 [&_[cmdk-group-heading]]:px-2 [&_[cmdk-group-heading]]:py-1.5 [&_[cmdk-group-heading]]:text-xs [&_[cmdk-group-heading]]:font-medium",
586
+ className
587
+ ),
588
+ ...props
589
+ }
590
+ );
591
+ }
592
+ function CommandItem({
593
+ className,
594
+ ...props
595
+ }) {
596
+ return /* @__PURE__ */ jsx(
597
+ Command$1.Item,
598
+ {
599
+ "data-slot": "command-item",
600
+ className: cn(
601
+ "data-[selected=true]:bg-accent data-[selected=true]:text-accent-foreground [&_svg:not([class*='text-'])]:text-muted-foreground relative flex cursor-default items-center gap-2 rounded-sm px-2 py-1.5 text-sm outline-hidden select-none data-[disabled=true]:pointer-events-none data-[disabled=true]:opacity-50 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4",
602
+ className
603
+ ),
604
+ ...props
605
+ }
606
+ );
607
+ }
608
+ var badgeVariants = cva(
609
+ "inline-flex items-center justify-center rounded-md border px-2 py-0.5 text-xs font-medium w-fit whitespace-nowrap shrink-0 [&>svg]:size-3 gap-1 [&>svg]:pointer-events-none focus-visible:border-ring focus-visible:ring-ring/50 focus-visible:ring-[3px] aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 aria-invalid:border-destructive transition-[color,box-shadow] overflow-hidden",
610
+ {
611
+ variants: {
612
+ variant: {
613
+ default: "border-transparent bg-primary text-primary-foreground [a&]:hover:bg-primary/90",
614
+ secondary: "border-transparent bg-secondary text-secondary-foreground [a&]:hover:bg-secondary/90",
615
+ destructive: "border-transparent bg-destructive text-white [a&]:hover:bg-destructive/90 focus-visible:ring-destructive/20 dark:focus-visible:ring-destructive/40 dark:bg-destructive/60",
616
+ outline: "text-foreground [a&]:hover:bg-accent [a&]:hover:text-accent-foreground"
617
+ }
618
+ },
619
+ defaultVariants: {
620
+ variant: "default"
621
+ }
622
+ }
623
+ );
624
+ function Badge({
625
+ className,
626
+ variant,
627
+ asChild = false,
628
+ ...props
629
+ }) {
630
+ const Comp = asChild ? Slot : "span";
631
+ return /* @__PURE__ */ jsx(
632
+ Comp,
633
+ {
634
+ "data-slot": "badge",
635
+ className: cn(badgeVariants({ variant }), className),
636
+ ...props
637
+ }
638
+ );
639
+ }
640
+ function Combobox({
641
+ options,
642
+ value = "",
643
+ onChange,
644
+ placeholder = "Select option...",
645
+ searchPlaceholder = "Search...",
646
+ noResultsText = "No results found.",
647
+ width = "100%",
648
+ isDisabled = false,
649
+ allowCustom = false
650
+ }) {
651
+ const [open, setOpen] = React6__default.useState(false);
652
+ const [searchValue, setSearchValue] = useState("");
653
+ const containerStyles = {
654
+ width
655
+ };
656
+ const combinedOptions = allowCustom ? [
657
+ ...options,
658
+ ...searchValue && !options.some(
659
+ (opt) => opt.label.toLowerCase() === searchValue.toLowerCase()
660
+ ) ? [
661
+ {
662
+ value: searchValue.toLowerCase().replace(/\s+/g, "-"),
663
+ label: searchValue
664
+ }
665
+ ] : []
666
+ ] : options;
667
+ const filteredOptions = combinedOptions.filter(
668
+ (option) => option.label.toLowerCase().includes(searchValue.toLowerCase())
669
+ );
670
+ return /* @__PURE__ */ jsx("div", { style: containerStyles, children: /* @__PURE__ */ jsxs(Popover, { open, onOpenChange: setOpen, children: [
671
+ /* @__PURE__ */ jsx(PopoverTrigger, { asChild: true, children: /* @__PURE__ */ jsxs(
672
+ Button,
673
+ {
674
+ variant: "outline",
675
+ role: "combobox",
676
+ "aria-expanded": open,
677
+ style: containerStyles,
678
+ className: `flex items-center justify-between relative ${isDisabled ? "cursor-not-allowed opacity-50" : ""}`,
679
+ disabled: isDisabled,
680
+ children: [
681
+ /* @__PURE__ */ jsx("div", { className: "flex-1 min-w-0 text-left", children: /* @__PURE__ */ jsx("div", { className: "truncate", children: value ? combinedOptions.find((option) => option.value === value)?.label || value : placeholder }) }),
682
+ /* @__PURE__ */ jsx(ChevronsUpDown, { className: "ml-2 h-4 w-4 flex-shrink-0 opacity-50" })
683
+ ]
684
+ }
685
+ ) }),
686
+ /* @__PURE__ */ jsx(PopoverContent, { className: "w-[var(--radix-popover-trigger-width)] p-0", children: /* @__PURE__ */ jsxs(Command, { className: "w-full", children: [
687
+ /* @__PURE__ */ jsx(
688
+ CommandInput,
689
+ {
690
+ value: searchValue,
691
+ onValueChange: setSearchValue,
692
+ placeholder: searchPlaceholder,
693
+ className: "h-9"
694
+ }
695
+ ),
696
+ /* @__PURE__ */ jsx(CommandList, { children: filteredOptions.length > 0 ? /* @__PURE__ */ jsx(CommandGroup, { className: "max-h-[200px] overflow-y-auto", children: filteredOptions.map((option) => /* @__PURE__ */ jsxs(
697
+ CommandItem,
698
+ {
699
+ value: option.value,
700
+ onSelect: (currentValue) => {
701
+ onChange(currentValue === value ? "" : currentValue);
702
+ setOpen(false);
703
+ setSearchValue("");
704
+ },
705
+ className: "flex items-center",
706
+ style: { width: "100%" },
707
+ children: [
708
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center w-full min-w-0", children: [
709
+ /* @__PURE__ */ jsx(
710
+ Check,
711
+ {
712
+ className: `mr-2 h-4 w-4 flex-shrink-0 ${value === option.value ? "opacity-100" : "opacity-0"}`
713
+ }
714
+ ),
715
+ /* @__PURE__ */ jsx("span", { className: "truncate flex-1", children: option.label })
716
+ ] }),
717
+ option.badge && /* @__PURE__ */ jsx(
718
+ Badge,
719
+ {
720
+ variant: "outline",
721
+ className: "ml-2 text-[10px] px-2 py-0 h-5 font-normal",
722
+ children: option.badge
723
+ }
724
+ )
725
+ ]
726
+ },
727
+ option.value
728
+ )) }) : /* @__PURE__ */ jsxs(CommandEmpty, { children: [
729
+ allowCustom && searchValue && /* @__PURE__ */ jsxs(
730
+ Button,
731
+ {
732
+ variant: "ghost",
733
+ className: "w-full justify-start",
734
+ onClick: () => {
735
+ const newOption = {
736
+ value: searchValue.toLowerCase().replace(/\s+/g, "-")};
737
+ onChange(newOption.value);
738
+ setOpen(false);
739
+ setSearchValue("");
740
+ },
741
+ children: [
742
+ /* @__PURE__ */ jsx(Plus, { className: "mr-2 h-4 w-4" }),
743
+ 'Add "',
744
+ searchValue,
745
+ '" as a new option'
746
+ ]
747
+ }
748
+ ),
749
+ !searchValue && noResultsText
750
+ ] }) })
751
+ ] }) })
752
+ ] }) });
753
+ }
754
+ var SmartCombobox = ({
755
+ field,
756
+ label,
757
+ options,
758
+ className = "",
759
+ placeholder,
760
+ allowCustom = false,
761
+ validation,
762
+ required = false,
763
+ defaultValue,
764
+ info,
765
+ subLabel,
766
+ disabled,
767
+ hidden
768
+ }) => {
769
+ const { formData } = useSmartForm();
770
+ const { value, error, onChange, fieldRef, registerValidation } = useFormField(field);
771
+ const fieldDetection = useFieldDetection();
772
+ const hasRegistered = useRef(false);
773
+ const hasSetDefault = useRef(false);
774
+ const isDisabled = typeof disabled === "function" ? disabled(formData) : disabled || false;
775
+ const isHidden = typeof hidden === "function" ? hidden(formData) : hidden || false;
776
+ if (isHidden) return null;
777
+ useEffect(() => {
778
+ if (validation && !hasRegistered.current) {
779
+ hasRegistered.current = true;
780
+ registerValidation(field, validation);
781
+ }
782
+ }, [validation, field, registerValidation]);
783
+ useEffect(() => {
784
+ if (fieldDetection?.registerField) {
785
+ fieldDetection.registerField(field);
786
+ }
787
+ }, [field, fieldDetection]);
788
+ useEffect(() => {
789
+ if (defaultValue !== void 0 && !hasSetDefault.current && (value === void 0 || value === null || value === "")) {
790
+ onChange(defaultValue);
791
+ hasSetDefault.current = true;
792
+ }
793
+ }, [defaultValue, value, onChange]);
794
+ return /* @__PURE__ */ jsxs("div", { className: `flex-1 min-w-0 ${className}`, children: [
795
+ label && /* @__PURE__ */ jsxs("div", { className: "mb-2", children: [
796
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between gap-2", children: [
797
+ /* @__PURE__ */ jsxs(Label, { className: "text-sm font-medium text-foreground", children: [
798
+ label,
799
+ " ",
800
+ required && /* @__PURE__ */ jsx("span", { className: "text-destructive", children: "*" })
801
+ ] }),
802
+ info && /* @__PURE__ */ jsx(TooltipProvider, { children: /* @__PURE__ */ jsxs(Tooltip, { children: [
803
+ /* @__PURE__ */ jsx(TooltipTrigger, { asChild: true, children: /* @__PURE__ */ jsx(InfoIcon, { className: "h-4 w-4 text-muted-foreground cursor-pointer mr-2" }) }),
804
+ /* @__PURE__ */ jsx(TooltipContent, { children: /* @__PURE__ */ jsx("p", { className: "max-w-xs", children: info }) })
805
+ ] }) })
806
+ ] }),
807
+ subLabel && /* @__PURE__ */ jsx("p", { className: "text-xs text-muted-foreground mt-1", children: subLabel })
808
+ ] }),
809
+ /* @__PURE__ */ jsx("div", { ref: fieldRef, "data-field": field, children: /* @__PURE__ */ jsx(
810
+ Combobox,
811
+ {
812
+ options: (options || []).map((o) => ({ value: o.value, label: o.label })),
813
+ value: value || "",
814
+ onChange: (newValue) => onChange(newValue),
815
+ placeholder: placeholder || (label ? `Select ${label.toLowerCase()}` : `Select ${field}`),
816
+ allowCustom,
817
+ isDisabled
818
+ }
819
+ ) }),
820
+ error && /* @__PURE__ */ jsx("p", { className: "text-destructive text-sm mt-1", children: error })
821
+ ] });
822
+ };
473
823
  function Calendar({
474
824
  className,
475
825
  classNames,
@@ -622,8 +972,8 @@ function CalendarDayButton({
622
972
  ...props
623
973
  }) {
624
974
  const defaultClassNames = getDefaultClassNames();
625
- const ref = React4.useRef(null);
626
- React4.useEffect(() => {
975
+ const ref = React6.useRef(null);
976
+ React6.useEffect(() => {
627
977
  if (modifiers.focused) ref.current?.focus();
628
978
  }, [modifiers.focused]);
629
979
  return /* @__PURE__ */ jsx(
@@ -646,165 +996,295 @@ function CalendarDayButton({
646
996
  }
647
997
  );
648
998
  }
649
- function Popover({
999
+ function Collapsible({
650
1000
  ...props
651
1001
  }) {
652
- return /* @__PURE__ */ jsx(PopoverPrimitive.Root, { "data-slot": "popover", ...props });
1002
+ return /* @__PURE__ */ jsx(CollapsiblePrimitive.Root, { "data-slot": "collapsible", ...props });
653
1003
  }
654
- function PopoverTrigger({
1004
+ function CollapsibleTrigger2({
655
1005
  ...props
656
1006
  }) {
657
- return /* @__PURE__ */ jsx(PopoverPrimitive.Trigger, { "data-slot": "popover-trigger", ...props });
1007
+ return /* @__PURE__ */ jsx(
1008
+ CollapsiblePrimitive.CollapsibleTrigger,
1009
+ {
1010
+ "data-slot": "collapsible-trigger",
1011
+ ...props
1012
+ }
1013
+ );
658
1014
  }
659
- function PopoverContent({
1015
+ function CollapsibleContent2({
1016
+ ...props
1017
+ }) {
1018
+ return /* @__PURE__ */ jsx(
1019
+ CollapsiblePrimitive.CollapsibleContent,
1020
+ {
1021
+ "data-slot": "collapsible-content",
1022
+ ...props
1023
+ }
1024
+ );
1025
+ }
1026
+ function ScrollArea({
660
1027
  className,
661
- align = "center",
662
- sideOffset = 4,
1028
+ children,
663
1029
  ...props
664
1030
  }) {
665
- return /* @__PURE__ */ jsx(PopoverPrimitive.Portal, { children: /* @__PURE__ */ jsx(
666
- PopoverPrimitive.Content,
1031
+ return /* @__PURE__ */ jsxs(
1032
+ ScrollAreaPrimitive.Root,
667
1033
  {
668
- "data-slot": "popover-content",
669
- align,
670
- sideOffset,
1034
+ "data-slot": "scroll-area",
1035
+ className: cn("relative", className),
1036
+ ...props,
1037
+ children: [
1038
+ /* @__PURE__ */ jsx(
1039
+ ScrollAreaPrimitive.Viewport,
1040
+ {
1041
+ "data-slot": "scroll-area-viewport",
1042
+ className: "focus-visible:ring-ring/50 size-full rounded-[inherit] transition-[color,box-shadow] outline-none focus-visible:ring-[3px] focus-visible:outline-1",
1043
+ children
1044
+ }
1045
+ ),
1046
+ /* @__PURE__ */ jsx(ScrollBar, {}),
1047
+ /* @__PURE__ */ jsx(ScrollAreaPrimitive.Corner, {})
1048
+ ]
1049
+ }
1050
+ );
1051
+ }
1052
+ function ScrollBar({
1053
+ className,
1054
+ orientation = "vertical",
1055
+ ...props
1056
+ }) {
1057
+ return /* @__PURE__ */ jsx(
1058
+ ScrollAreaPrimitive.ScrollAreaScrollbar,
1059
+ {
1060
+ "data-slot": "scroll-area-scrollbar",
1061
+ orientation,
671
1062
  className: cn(
672
- "bg-popover text-popover-foreground 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 z-50 origin-(--radix-popover-content-transform-origin) rounded-md border p-4 shadow-md outline-hidden",
1063
+ "flex touch-none p-px transition-colors select-none",
1064
+ orientation === "vertical" && "h-full w-2.5 border-l border-l-transparent",
1065
+ orientation === "horizontal" && "h-2.5 flex-col border-t border-t-transparent",
673
1066
  className
674
1067
  ),
675
- ...props
1068
+ ...props,
1069
+ children: /* @__PURE__ */ jsx(
1070
+ ScrollAreaPrimitive.ScrollAreaThumb,
1071
+ {
1072
+ "data-slot": "scroll-area-thumb",
1073
+ className: "bg-border relative flex-1 rounded-full"
1074
+ }
1075
+ )
676
1076
  }
677
- ) });
1077
+ );
678
1078
  }
679
1079
  var SmartDatePicker = ({
680
1080
  field,
681
1081
  label,
682
- className = "",
683
- placeholder,
684
- validation,
685
- required = false,
686
- allowPast = true,
687
- allowFuture = true,
688
- valueAsString = true,
689
- minDate,
690
- maxDate,
691
- defaultValue,
692
- info,
693
- subLabel,
694
- disabled,
695
- hidden
1082
+ className,
1083
+ ...props
696
1084
  }) => {
697
- const { formData } = useSmartForm();
698
- const { value, error, onChange, fieldRef, registerValidation } = useFormField(field);
699
- const fieldDetection = useFieldDetection();
700
- const hasRegistered = useRef(false);
701
- const hasSetDefault = useRef(false);
702
- const isDisabled = typeof disabled === "function" ? disabled(formData) : disabled || false;
703
- const isHidden = typeof hidden === "function" ? hidden(formData) : hidden || false;
704
- if (isHidden) return null;
705
- const parsedValue = useMemo(() => {
706
- if (!value) return void 0;
707
- if (value instanceof Date) return value;
708
- const d = new Date(value);
709
- return isNaN(d.getTime()) ? void 0 : d;
710
- }, [value]);
711
- const [open, setOpen] = useState(false);
712
- useEffect(() => {
713
- if (validation && !hasRegistered.current) {
714
- hasRegistered.current = true;
715
- registerValidation(field, validation);
716
- }
717
- }, [validation, field, registerValidation]);
718
- useEffect(() => {
719
- if (fieldDetection?.registerField) {
720
- fieldDetection.registerField(field);
721
- }
722
- }, [field, fieldDetection]);
723
- useEffect(() => {
724
- if (defaultValue !== void 0 && !hasSetDefault.current && (value === void 0 || value === null || value === "")) {
725
- onChange(defaultValue);
726
- hasSetDefault.current = true;
727
- }
728
- }, [defaultValue, value, onChange]);
729
- const today = useMemo(() => /* @__PURE__ */ new Date(), []);
730
- const disabledMatcher = (date) => {
731
- if (!allowPast) {
732
- const startOfToday = new Date(today.getFullYear(), today.getMonth(), today.getDate());
733
- if (date < startOfToday) return true;
734
- }
735
- if (!allowFuture) {
736
- const startOfTomorrow = new Date(today.getFullYear(), today.getMonth(), today.getDate() + 1);
737
- if (date >= startOfTomorrow) return true;
738
- }
739
- if (minDate && date < new Date(minDate.getFullYear(), minDate.getMonth(), minDate.getDate())) return true;
740
- if (maxDate && date > new Date(maxDate.getFullYear(), maxDate.getMonth(), maxDate.getDate())) return true;
741
- return false;
742
- };
743
- const handleSelect = (selected) => {
744
- if (!selected) {
745
- onChange(void 0);
746
- return;
747
- }
748
- if (valueAsString) {
749
- const iso = format(selected, "yyyy-MM-dd");
750
- onChange(iso);
751
- } else {
752
- onChange(selected);
1085
+ const today = /* @__PURE__ */ new Date();
1086
+ const [month, setMonth] = useState(today);
1087
+ const [date, setDate] = useState(today);
1088
+ const [isYearView, setIsYearView] = useState(false);
1089
+ const [isOpen, setIsOpen] = useState(false);
1090
+ const startDate = new Date(1980, 6);
1091
+ const endDate = new Date(2030, 6);
1092
+ const years = eachYearOfInterval({
1093
+ start: startOfYear(startDate),
1094
+ end: endOfYear(endDate)
1095
+ });
1096
+ const handleDateSelect = (selectedDate) => {
1097
+ setDate(selectedDate);
1098
+ if (selectedDate) {
1099
+ setIsOpen(false);
1100
+ setIsYearView(false);
753
1101
  }
754
- setOpen(false);
755
1102
  };
756
- const buttonText = useMemo(() => {
757
- if (!parsedValue) return placeholder || `Select ${label || field}`;
758
- return format(parsedValue, "dd/MM/yyyy");
759
- }, [parsedValue, placeholder, label, field]);
760
- return /* @__PURE__ */ jsxs("div", { className: cn("flex-1 min-w-0", className), children: [
761
- label && /* @__PURE__ */ jsxs("div", { className: "mb-2", children: [
762
- /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between gap-2", children: [
763
- /* @__PURE__ */ jsxs(Label, { className: "text-sm font-medium text-foreground", children: [
764
- label,
765
- " ",
766
- required && /* @__PURE__ */ jsx("span", { className: "text-destructive", children: "*" })
767
- ] }),
768
- info && /* @__PURE__ */ jsx(TooltipProvider, { children: /* @__PURE__ */ jsxs(Tooltip, { children: [
769
- /* @__PURE__ */ jsx(TooltipTrigger, { asChild: true, children: /* @__PURE__ */ jsx(InfoIcon, { className: "h-4 w-4 text-muted-foreground cursor-pointer mr-2" }) }),
770
- /* @__PURE__ */ jsx(TooltipContent, { children: /* @__PURE__ */ jsx("p", { className: "max-w-xs", children: info }) })
771
- ] }) })
772
- ] }),
773
- subLabel && /* @__PURE__ */ jsx("p", { className: "text-xs text-muted-foreground mt-1", children: subLabel })
774
- ] }),
775
- /* @__PURE__ */ jsxs(Popover, { open, onOpenChange: setOpen, children: [
776
- /* @__PURE__ */ jsx(PopoverTrigger, { asChild: true, children: /* @__PURE__ */ jsxs(
777
- Button,
778
- {
779
- ref: fieldRef,
780
- variant: "outline",
781
- className: cn(
782
- "w-full justify-start text-left font-normal",
783
- !parsedValue && "text-muted-foreground",
784
- error && "border-destructive"
1103
+ return /* @__PURE__ */ jsx("div", { className: "w-[280px]", children: /* @__PURE__ */ jsxs(Popover, { open: isOpen, onOpenChange: setIsOpen, children: [
1104
+ /* @__PURE__ */ jsx(PopoverTrigger, { asChild: true, children: /* @__PURE__ */ jsx("div", { children: /* @__PURE__ */ jsx(
1105
+ SmartInput,
1106
+ {
1107
+ field,
1108
+ label,
1109
+ syncValue: date,
1110
+ type: "date",
1111
+ className: `${className ?? ""} cursor-pointer`,
1112
+ icon: /* @__PURE__ */ jsx(CalendarIcon, { className: "size-4" }),
1113
+ iconPosition: "right",
1114
+ ...props
1115
+ }
1116
+ ) }) }),
1117
+ /* @__PURE__ */ jsx(PopoverContent, { className: "w-auto p-0", align: "start", children: /* @__PURE__ */ jsx(
1118
+ Calendar,
1119
+ {
1120
+ mode: "single",
1121
+ selected: date,
1122
+ onSelect: handleDateSelect,
1123
+ month,
1124
+ onMonthChange: setMonth,
1125
+ defaultMonth: /* @__PURE__ */ new Date(),
1126
+ startMonth: startDate,
1127
+ endMonth: endDate,
1128
+ className: "overflow-hidden rounded-md p-2",
1129
+ classNames: {
1130
+ month_caption: "ml-2.5 mr-20 justify-start",
1131
+ nav: "flex absolute w-fit right-0 items-center"
1132
+ },
1133
+ components: {
1134
+ CaptionLabel: (props2) => /* @__PURE__ */ jsx(
1135
+ CaptionLabel,
1136
+ {
1137
+ isYearView,
1138
+ setIsYearView,
1139
+ ...props2
1140
+ }
785
1141
  ),
786
- "data-field": field,
787
- disabled: isDisabled,
788
- children: [
789
- /* @__PURE__ */ jsx(Calendar$1, { className: "mr-2 h-4 w-4" }),
790
- buttonText
791
- ]
1142
+ MonthGrid: (props2) => {
1143
+ return /* @__PURE__ */ jsx(
1144
+ MonthGrid,
1145
+ {
1146
+ className: props2.className,
1147
+ isYearView,
1148
+ setIsYearView,
1149
+ startDate,
1150
+ endDate,
1151
+ years,
1152
+ currentYear: month.getFullYear(),
1153
+ currentMonth: month.getMonth(),
1154
+ onMonthSelect: (selectedMonth) => {
1155
+ setMonth(selectedMonth);
1156
+ setIsYearView(false);
1157
+ },
1158
+ children: props2.children
1159
+ }
1160
+ );
1161
+ }
792
1162
  }
793
- ) }),
794
- /* @__PURE__ */ jsx(PopoverContent, { className: "w-auto p-0", align: "start", children: /* @__PURE__ */ jsx(
795
- Calendar,
1163
+ }
1164
+ ) })
1165
+ ] }) });
1166
+ };
1167
+ function MonthGrid({
1168
+ className,
1169
+ children,
1170
+ isYearView,
1171
+ startDate,
1172
+ endDate,
1173
+ years,
1174
+ currentYear,
1175
+ currentMonth,
1176
+ onMonthSelect
1177
+ }) {
1178
+ const currentYearRef = useRef(null);
1179
+ const currentMonthButtonRef = useRef(null);
1180
+ const scrollAreaRef = useRef(null);
1181
+ useEffect(() => {
1182
+ if (isYearView && currentYearRef.current && scrollAreaRef.current) {
1183
+ const viewport = scrollAreaRef.current.querySelector(
1184
+ "[data-radix-scroll-area-viewport]"
1185
+ );
1186
+ if (viewport) {
1187
+ const yearTop = currentYearRef.current.offsetTop;
1188
+ viewport.scrollTop = yearTop;
1189
+ }
1190
+ setTimeout(() => {
1191
+ currentMonthButtonRef.current?.focus();
1192
+ }, 100);
1193
+ }
1194
+ }, [isYearView]);
1195
+ return /* @__PURE__ */ jsxs("div", { className: "relative", children: [
1196
+ /* @__PURE__ */ jsx("table", { className, children }),
1197
+ isYearView && /* @__PURE__ */ jsx("div", { className: "bg-background absolute inset-0 z-20 -mx-2 -mb-2", children: /* @__PURE__ */ jsx(ScrollArea, { ref: scrollAreaRef, className: "h-full", children: years.map((year) => {
1198
+ const months = eachMonthOfInterval({
1199
+ start: startOfYear(year),
1200
+ end: endOfYear(year)
1201
+ });
1202
+ const isCurrentYear = year.getFullYear() === currentYear;
1203
+ return /* @__PURE__ */ jsx(
1204
+ "div",
796
1205
  {
797
- mode: "single",
798
- selected: parsedValue,
799
- onSelect: handleSelect,
800
- disabled: disabledMatcher,
801
- initialFocus: true
802
- }
803
- ) })
804
- ] }),
805
- error && /* @__PURE__ */ jsx("p", { className: "text-destructive text-sm mt-1", children: error })
1206
+ ref: isCurrentYear ? currentYearRef : void 0,
1207
+ children: /* @__PURE__ */ jsx(
1208
+ CollapsibleYear,
1209
+ {
1210
+ title: year.getFullYear().toString(),
1211
+ open: isCurrentYear,
1212
+ children: /* @__PURE__ */ jsx("div", { className: "grid grid-cols-3 gap-2", children: months.map((month) => {
1213
+ const isDisabled = isBefore(month, startDate) || isAfter(month, endDate);
1214
+ const isCurrentMonth = month.getMonth() === currentMonth && year.getFullYear() === currentYear;
1215
+ return /* @__PURE__ */ jsx(
1216
+ "button",
1217
+ {
1218
+ ref: isCurrentMonth ? currentMonthButtonRef : void 0,
1219
+ className: `inline-flex h-7 items-center justify-center rounded-md px-3 text-sm font-medium transition-all disabled:pointer-events-none disabled:opacity-50 ${isCurrentMonth ? "bg-primary text-primary-foreground hover:bg-primary/90" : "border bg-background shadow-xs hover:bg-accent hover:text-accent-foreground"}`,
1220
+ disabled: isDisabled,
1221
+ onClick: () => onMonthSelect(month),
1222
+ children: format(month, "MMM")
1223
+ },
1224
+ month.getTime()
1225
+ );
1226
+ }) })
1227
+ }
1228
+ )
1229
+ },
1230
+ year.getFullYear()
1231
+ );
1232
+ }) }) })
806
1233
  ] });
807
- };
1234
+ }
1235
+ function CaptionLabel({
1236
+ children,
1237
+ isYearView,
1238
+ setIsYearView
1239
+ }) {
1240
+ return /* @__PURE__ */ jsxs(
1241
+ Button,
1242
+ {
1243
+ className: "data-[state=open]:text-muted-foreground/80 -ms-2 flex items-center gap-2 text-sm font-medium hover:bg-transparent [&[data-state=open]>svg]:rotate-180",
1244
+ variant: "ghost",
1245
+ size: "sm",
1246
+ onClick: () => setIsYearView((prev) => !prev),
1247
+ "data-state": isYearView ? "open" : "closed",
1248
+ children: [
1249
+ children,
1250
+ /* @__PURE__ */ jsx(
1251
+ ChevronDownIcon,
1252
+ {
1253
+ className: "text-muted-foreground/80 shrink-0 transition-transform duration-200",
1254
+ "aria-hidden": "true"
1255
+ }
1256
+ )
1257
+ ]
1258
+ }
1259
+ );
1260
+ }
1261
+ function CollapsibleYear({
1262
+ title,
1263
+ children,
1264
+ open
1265
+ }) {
1266
+ return /* @__PURE__ */ jsxs(Collapsible, { className: "border-t px-2 py-1.5", defaultOpen: open, children: [
1267
+ /* @__PURE__ */ jsx(CollapsibleTrigger2, { asChild: true, children: /* @__PURE__ */ jsxs(
1268
+ Button,
1269
+ {
1270
+ className: "flex w-full justify-start gap-2 text-sm font-medium hover:bg-transparent [&[data-state=open]>svg]:rotate-180",
1271
+ variant: "ghost",
1272
+ size: "sm",
1273
+ children: [
1274
+ /* @__PURE__ */ jsx(
1275
+ ChevronDownIcon,
1276
+ {
1277
+ className: "text-muted-foreground/80 shrink-0 transition-transform duration-200",
1278
+ "aria-hidden": "true"
1279
+ }
1280
+ ),
1281
+ title
1282
+ ]
1283
+ }
1284
+ ) }),
1285
+ /* @__PURE__ */ jsx(CollapsibleContent2, { className: "data-[state=closed]:animate-collapsible-up data-[state=open]:animate-collapsible-down overflow-hidden px-3 py-1 text-sm transition-all", children })
1286
+ ] });
1287
+ }
808
1288
  var SmartTags = ({
809
1289
  field,
810
1290
  label,
@@ -977,6 +1457,6 @@ var SmartTags = ({
977
1457
  ] });
978
1458
  };
979
1459
 
980
- export { Button, Popover, PopoverContent, PopoverTrigger, SmartCheckbox, SmartDatePicker, SmartRadioGroup, SmartSelect, SmartTags };
981
- //# sourceMappingURL=chunk-CT6GW6PK.js.map
982
- //# sourceMappingURL=chunk-CT6GW6PK.js.map
1460
+ export { Badge, Button, Command, CommandEmpty, CommandGroup, CommandInput, CommandItem, CommandList, Popover, PopoverContent, PopoverTrigger, SmartCheckbox, SmartCombobox, SmartDatePicker, SmartRadioGroup, SmartSelect, SmartTags };
1461
+ //# sourceMappingURL=chunk-BNQNL7GF.js.map
1462
+ //# sourceMappingURL=chunk-BNQNL7GF.js.map