hazo_ui 1.0.3 → 2.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 CHANGED
@@ -6,12 +6,16 @@ import { cva } from 'class-variance-authority';
6
6
  import { clsx } from 'clsx';
7
7
  import { twMerge } from 'tailwind-merge';
8
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';
9
+ import { X, ChevronDown, ChevronUp, Check, Filter, Plus, ChevronsUpDown, ArrowUpDown, Trash2, GripVertical, Calendar as Calendar$1, ChevronRight, ChevronLeft } from 'lucide-react';
10
10
  import * as PopoverPrimitive from '@radix-ui/react-popover';
11
11
  import * as SelectPrimitive from '@radix-ui/react-select';
12
12
  import * as TooltipPrimitive from '@radix-ui/react-tooltip';
13
13
  import { DayPicker } from 'react-day-picker';
14
14
  import { format } from 'date-fns';
15
+ import * as SwitchPrimitives from '@radix-ui/react-switch';
16
+ import { useSensors, useSensor, PointerSensor, KeyboardSensor, DndContext, closestCenter } from '@dnd-kit/core';
17
+ import { sortableKeyboardCoordinates, SortableContext, verticalListSortingStrategy, arrayMove, useSortable } from '@dnd-kit/sortable';
18
+ import { CSS } from '@dnd-kit/utilities';
15
19
 
16
20
  var ExampleComponent = ({ children, className = "" }) => {
17
21
  return /* @__PURE__ */ jsx("div", { className: `cls_example_component ${className}`, children });
@@ -670,6 +674,9 @@ function MultiFilterDialog({
670
674
  setFilterFields(initialFilters);
671
675
  setIsOpen(false);
672
676
  };
677
+ const handleClearAll = () => {
678
+ setFilterFields([]);
679
+ };
673
680
  const availableFieldsToAdd = availableFields.filter(
674
681
  (af) => !filterFields.some((ff) => ff.field === af.value)
675
682
  );
@@ -796,6 +803,333 @@ function MultiFilterDialog({
796
803
  }) }) : /* @__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
804
  ] }),
798
805
  /* @__PURE__ */ jsxs(DialogFooter, { children: [
806
+ filterFields.length > 0 && /* @__PURE__ */ jsxs(
807
+ Button,
808
+ {
809
+ variant: "outline",
810
+ onClick: handleClearAll,
811
+ className: "cls_clear_all_btn",
812
+ children: [
813
+ /* @__PURE__ */ jsx(X, { className: "cls_clear_all_icon h-4 w-4 mr-2" }),
814
+ "Clear All"
815
+ ]
816
+ }
817
+ ),
818
+ /* @__PURE__ */ jsx(
819
+ Button,
820
+ {
821
+ onClick: handleApply,
822
+ className: "cls_apply_btn",
823
+ children: "Apply"
824
+ }
825
+ ),
826
+ /* @__PURE__ */ jsx(
827
+ Button,
828
+ {
829
+ variant: "outline",
830
+ onClick: handleCancel,
831
+ className: "cls_cancel_btn",
832
+ children: "Cancel"
833
+ }
834
+ )
835
+ ] })
836
+ ] })
837
+ ] });
838
+ }
839
+ var Switch = React6.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx(
840
+ SwitchPrimitives.Root,
841
+ {
842
+ className: cn(
843
+ "peer inline-flex h-6 w-11 shrink-0 cursor-pointer items-center rounded-full border-2 border-transparent transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 focus-visible:ring-offset-background disabled:cursor-not-allowed disabled:opacity-50 data-[state=checked]:bg-primary data-[state=unchecked]:bg-input",
844
+ className
845
+ ),
846
+ ...props,
847
+ ref,
848
+ children: /* @__PURE__ */ jsx(
849
+ SwitchPrimitives.Thumb,
850
+ {
851
+ className: cn(
852
+ "pointer-events-none block h-5 w-5 rounded-full bg-background shadow-lg ring-0 transition-transform data-[state=checked]:translate-x-5 data-[state=unchecked]:translate-x-0"
853
+ )
854
+ }
855
+ )
856
+ }
857
+ ));
858
+ Switch.displayName = SwitchPrimitives.Root.displayName;
859
+ var Label2 = React6.forwardRef(
860
+ ({ className, ...props }, ref) => {
861
+ return /* @__PURE__ */ jsx(
862
+ "label",
863
+ {
864
+ ref,
865
+ className: cn(
866
+ "text-sm font-medium leading-none peer-disabled:cursor-not-allowed peer-disabled:opacity-70",
867
+ className
868
+ ),
869
+ ...props
870
+ }
871
+ );
872
+ }
873
+ );
874
+ Label2.displayName = "Label";
875
+ function SortableSortFieldItem({
876
+ sortConfig,
877
+ fieldLabel,
878
+ onDirectionChange,
879
+ onDelete
880
+ }) {
881
+ const {
882
+ attributes,
883
+ listeners,
884
+ setNodeRef,
885
+ transform,
886
+ transition,
887
+ isDragging
888
+ } = useSortable({ id: sortConfig.field });
889
+ const style = {
890
+ transform: CSS.Transform.toString(transform),
891
+ transition,
892
+ opacity: isDragging ? 0.5 : 1
893
+ };
894
+ return /* @__PURE__ */ jsxs(
895
+ "div",
896
+ {
897
+ ref: setNodeRef,
898
+ style,
899
+ className: "cls_sortable_sort_field_item flex items-center gap-3 p-3 border rounded-md bg-card",
900
+ children: [
901
+ /* @__PURE__ */ jsx(
902
+ "div",
903
+ {
904
+ ...attributes,
905
+ ...listeners,
906
+ className: "cls_drag_handle cursor-grab active:cursor-grabbing text-muted-foreground hover:text-foreground",
907
+ children: /* @__PURE__ */ jsx(GripVertical, { className: "cls_drag_icon h-4 w-4" })
908
+ }
909
+ ),
910
+ /* @__PURE__ */ jsx("span", { className: "cls_field_label flex-1 text-sm font-medium", children: fieldLabel }),
911
+ /* @__PURE__ */ jsxs("div", { className: "cls_direction_control flex items-center gap-2", children: [
912
+ /* @__PURE__ */ jsx(Label2, { htmlFor: `switch-${sortConfig.field}`, className: "cls_direction_label text-xs text-muted-foreground", children: sortConfig.direction === "asc" ? "Ascending" : "Descending" }),
913
+ /* @__PURE__ */ jsx(
914
+ Switch,
915
+ {
916
+ id: `switch-${sortConfig.field}`,
917
+ checked: sortConfig.direction === "desc",
918
+ onCheckedChange: (checked) => onDirectionChange(checked ? "desc" : "asc"),
919
+ "aria-label": `Toggle sort direction for ${fieldLabel}`
920
+ }
921
+ )
922
+ ] }),
923
+ /* @__PURE__ */ jsx(
924
+ Button,
925
+ {
926
+ variant: "ghost",
927
+ size: "sm",
928
+ onClick: onDelete,
929
+ className: "cls_delete_btn h-8 w-8 p-0 text-destructive hover:text-destructive",
930
+ "aria-label": `Remove ${fieldLabel} from sort`,
931
+ children: /* @__PURE__ */ jsx(Trash2, { className: "cls_delete_icon h-4 w-4" })
932
+ }
933
+ )
934
+ ]
935
+ }
936
+ );
937
+ }
938
+ function MultiSortDialog({
939
+ availableFields,
940
+ onSortChange,
941
+ initialSortFields = []
942
+ }) {
943
+ const [isOpen, setIsOpen] = useState(false);
944
+ const [sortFields, setSortFields] = useState(initialSortFields);
945
+ const [isComboboxOpen, setIsComboboxOpen] = useState(false);
946
+ const sensors = useSensors(
947
+ useSensor(PointerSensor),
948
+ useSensor(KeyboardSensor, {
949
+ coordinateGetter: sortableKeyboardCoordinates
950
+ })
951
+ );
952
+ useEffect(() => {
953
+ if (isOpen) {
954
+ setSortFields(initialSortFields);
955
+ }
956
+ }, [isOpen, initialSortFields]);
957
+ const handleAddField = (fieldValue) => {
958
+ if (sortFields.some((sf) => sf.field === fieldValue)) {
959
+ return;
960
+ }
961
+ const newField = {
962
+ field: fieldValue,
963
+ direction: "asc"
964
+ };
965
+ setSortFields([...sortFields, newField]);
966
+ setIsComboboxOpen(false);
967
+ };
968
+ const handleDeleteField = (fieldValue) => {
969
+ setSortFields(sortFields.filter((sf) => sf.field !== fieldValue));
970
+ };
971
+ const handleDirectionChange = (fieldValue, direction) => {
972
+ setSortFields(
973
+ sortFields.map(
974
+ (sf) => sf.field === fieldValue ? { ...sf, direction } : sf
975
+ )
976
+ );
977
+ };
978
+ const handleDragEnd = (event) => {
979
+ const { active, over } = event;
980
+ if (!over || active.id === over.id) {
981
+ return;
982
+ }
983
+ const oldIndex = sortFields.findIndex((sf) => sf.field === active.id);
984
+ const newIndex = sortFields.findIndex((sf) => sf.field === over.id);
985
+ if (oldIndex !== -1 && newIndex !== -1) {
986
+ setSortFields(arrayMove(sortFields, oldIndex, newIndex));
987
+ }
988
+ };
989
+ const handleApply = () => {
990
+ onSortChange([...sortFields]);
991
+ setIsOpen(false);
992
+ };
993
+ const handleCancel = () => {
994
+ setSortFields(initialSortFields);
995
+ setIsOpen(false);
996
+ };
997
+ const handleClearAll = () => {
998
+ setSortFields([]);
999
+ };
1000
+ const availableFieldsToAdd = availableFields.filter(
1001
+ (af) => !sortFields.some((sf) => sf.field === af.value)
1002
+ );
1003
+ const getFieldLabel = (fieldValue) => {
1004
+ return availableFields.find((af) => af.value === fieldValue)?.label || fieldValue;
1005
+ };
1006
+ const hasActiveSorts = initialSortFields.length > 0;
1007
+ const tooltipContent = hasActiveSorts ? /* @__PURE__ */ jsxs("div", { className: "cls_sort_tooltip_content space-y-1", children: [
1008
+ /* @__PURE__ */ jsx("div", { className: "cls_tooltip_title text-xs font-semibold mb-1", children: "Active Sorts:" }),
1009
+ initialSortFields.map((sortConfig, index) => /* @__PURE__ */ jsxs("div", { className: "cls_tooltip_item text-xs", children: [
1010
+ index + 1,
1011
+ ". ",
1012
+ getFieldLabel(sortConfig.field),
1013
+ " (",
1014
+ sortConfig.direction === "asc" ? "Asc" : "Desc",
1015
+ ")"
1016
+ ] }, sortConfig.field))
1017
+ ] }) : /* @__PURE__ */ jsx("div", { className: "cls_sort_tooltip_content text-xs", children: "No active sorts" });
1018
+ return /* @__PURE__ */ jsxs(Dialog, { open: isOpen, onOpenChange: setIsOpen, children: [
1019
+ /* @__PURE__ */ jsx(TooltipProvider, { children: /* @__PURE__ */ jsxs(Tooltip, { children: [
1020
+ /* @__PURE__ */ jsx(TooltipTrigger, { asChild: true, children: /* @__PURE__ */ jsx(DialogTrigger, { asChild: true, children: /* @__PURE__ */ jsxs(
1021
+ Button,
1022
+ {
1023
+ variant: "outline",
1024
+ size: "sm",
1025
+ className: "cls_sort_button",
1026
+ "aria-label": "Open sort dialog",
1027
+ children: [
1028
+ /* @__PURE__ */ jsx(
1029
+ ArrowUpDown,
1030
+ {
1031
+ className: cn(
1032
+ "cls_sort_icon h-4 w-4 mr-2",
1033
+ hasActiveSorts && "text-blue-600"
1034
+ )
1035
+ }
1036
+ ),
1037
+ "Sort"
1038
+ ]
1039
+ }
1040
+ ) }) }),
1041
+ /* @__PURE__ */ jsx(TooltipContent, { children: tooltipContent })
1042
+ ] }) }),
1043
+ /* @__PURE__ */ jsxs(DialogContent, { className: "cls_sort_dialog_content max-w-lg", children: [
1044
+ /* @__PURE__ */ jsxs(DialogHeader, { children: [
1045
+ /* @__PURE__ */ jsx(DialogTitle, { children: "Sort Images" }),
1046
+ /* @__PURE__ */ jsx(DialogDescription, { children: "Add multiple fields to sort by and reorder them. Use the switch to toggle between ascending and descending." })
1047
+ ] }),
1048
+ /* @__PURE__ */ jsxs("div", { className: "cls_sort_dialog_body space-y-4 py-4", children: [
1049
+ /* @__PURE__ */ jsx("div", { className: "cls_add_field_section", children: /* @__PURE__ */ jsxs(Popover, { open: isComboboxOpen, onOpenChange: setIsComboboxOpen, children: [
1050
+ /* @__PURE__ */ jsx(PopoverTrigger, { asChild: true, children: /* @__PURE__ */ jsxs(
1051
+ Button,
1052
+ {
1053
+ variant: "outline",
1054
+ role: "combobox",
1055
+ "aria-expanded": isComboboxOpen,
1056
+ className: "cls_add_field_combobox w-full justify-between",
1057
+ children: [
1058
+ /* @__PURE__ */ jsxs("div", { className: "cls_combobox_content flex items-center", children: [
1059
+ /* @__PURE__ */ jsx(Plus, { className: "cls_plus_icon h-4 w-4 mr-2" }),
1060
+ /* @__PURE__ */ jsx("span", { children: "Add field" })
1061
+ ] }),
1062
+ /* @__PURE__ */ jsx(ChevronsUpDown, { className: "cls_chevron_icon ml-2 h-4 w-4 shrink-0 opacity-50" })
1063
+ ]
1064
+ }
1065
+ ) }),
1066
+ /* @__PURE__ */ jsx(PopoverContent, { className: "cls_combobox_popover w-full p-0", children: /* @__PURE__ */ jsxs(Command, { children: [
1067
+ /* @__PURE__ */ jsx(CommandInput, { placeholder: "Search fields...", className: "cls_command_input" }),
1068
+ /* @__PURE__ */ jsxs(CommandList, { children: [
1069
+ /* @__PURE__ */ jsx(CommandEmpty, { children: "No fields found." }),
1070
+ /* @__PURE__ */ jsx(CommandGroup, { children: availableFieldsToAdd.map((field) => /* @__PURE__ */ jsxs(
1071
+ CommandItem,
1072
+ {
1073
+ value: field.value,
1074
+ onSelect: () => handleAddField(field.value),
1075
+ className: "cls_command_item",
1076
+ children: [
1077
+ /* @__PURE__ */ jsx(
1078
+ Check,
1079
+ {
1080
+ className: cn(
1081
+ "cls_check_icon mr-2 h-4 w-4",
1082
+ "opacity-0"
1083
+ )
1084
+ }
1085
+ ),
1086
+ field.label
1087
+ ]
1088
+ },
1089
+ field.value
1090
+ )) })
1091
+ ] })
1092
+ ] }) })
1093
+ ] }) }),
1094
+ sortFields.length > 0 ? /* @__PURE__ */ jsx("div", { className: "cls_sort_fields_list space-y-2", children: /* @__PURE__ */ jsx(
1095
+ DndContext,
1096
+ {
1097
+ sensors,
1098
+ collisionDetection: closestCenter,
1099
+ onDragEnd: handleDragEnd,
1100
+ children: /* @__PURE__ */ jsx(
1101
+ SortableContext,
1102
+ {
1103
+ items: sortFields.map((sf) => sf.field),
1104
+ strategy: verticalListSortingStrategy,
1105
+ children: sortFields.map((sortConfig) => /* @__PURE__ */ jsx(
1106
+ SortableSortFieldItem,
1107
+ {
1108
+ sortConfig,
1109
+ fieldLabel: getFieldLabel(sortConfig.field),
1110
+ onDirectionChange: (direction) => handleDirectionChange(sortConfig.field, direction),
1111
+ onDelete: () => handleDeleteField(sortConfig.field)
1112
+ },
1113
+ sortConfig.field
1114
+ ))
1115
+ }
1116
+ )
1117
+ }
1118
+ ) }) : /* @__PURE__ */ jsx("div", { className: "cls_empty_sort_fields text-center py-8 text-sm text-muted-foreground", children: 'No sort fields added. Click "Add field" to add sorting criteria.' })
1119
+ ] }),
1120
+ /* @__PURE__ */ jsxs(DialogFooter, { children: [
1121
+ sortFields.length > 0 && /* @__PURE__ */ jsxs(
1122
+ Button,
1123
+ {
1124
+ variant: "outline",
1125
+ onClick: handleClearAll,
1126
+ className: "cls_clear_all_btn",
1127
+ children: [
1128
+ /* @__PURE__ */ jsx(Trash2, { className: "cls_clear_all_icon h-4 w-4 mr-2" }),
1129
+ "Clear All"
1130
+ ]
1131
+ }
1132
+ ),
799
1133
  /* @__PURE__ */ jsx(
800
1134
  Button,
801
1135
  {
@@ -818,6 +1152,6 @@ function MultiFilterDialog({
818
1152
  ] });
819
1153
  }
820
1154
 
821
- export { ExampleComponent, MultiFilterDialog };
1155
+ export { ExampleComponent, MultiFilterDialog, MultiSortDialog };
822
1156
  //# sourceMappingURL=index.js.map
823
1157
  //# sourceMappingURL=index.js.map