@l3mpire/ui 2.12.0 → 2.14.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.mjs CHANGED
@@ -5016,7 +5016,6 @@ var OPERATORS_BY_TYPE = {
5016
5016
  "is on or before",
5017
5017
  "is on or after",
5018
5018
  "is between",
5019
- "is relative",
5020
5019
  "is empty",
5021
5020
  "is not empty"
5022
5021
  ],
@@ -5035,7 +5034,7 @@ var OPERATORS_BY_TYPE = {
5035
5034
  var DEFAULT_OPERATOR_BY_TYPE = {
5036
5035
  text: "contains",
5037
5036
  number: "=",
5038
- date: "is relative",
5037
+ date: "is between",
5039
5038
  enum: "is",
5040
5039
  tags: "contains",
5041
5040
  boolean: "is true",
@@ -5063,7 +5062,6 @@ function getValueInputType(type, operator) {
5063
5062
  return operator === "is between" ? "NumberRange" : "NumberInput";
5064
5063
  if (type === "date") {
5065
5064
  if (operator === "is between") return "DateRange";
5066
- if (operator === "is relative") return "PresetTags";
5067
5065
  return "DatePicker";
5068
5066
  }
5069
5067
  if (type === "enum")
@@ -5074,6 +5072,130 @@ function getValueInputType(type, operator) {
5074
5072
  return ["is any of", "is none of"].includes(operator) ? "MultiRelationPicker" : "RelationPicker";
5075
5073
  return null;
5076
5074
  }
5075
+ function formatFilterValue(value) {
5076
+ if (value == null) return void 0;
5077
+ if (typeof value === "boolean") return value ? "Yes" : "No";
5078
+ if (value instanceof Date) {
5079
+ return value.toLocaleDateString("en-US", {
5080
+ month: "short",
5081
+ day: "numeric",
5082
+ year: "numeric"
5083
+ });
5084
+ }
5085
+ if (Array.isArray(value)) {
5086
+ if (value.length === 0) return void 0;
5087
+ if (value.length === 2 && typeof value[0] === "number") {
5088
+ return `${value[0]} \u2013 ${value[1]}`;
5089
+ }
5090
+ if (value.length === 2 && value[0] instanceof Date) {
5091
+ const fmt = (d) => d.toLocaleDateString("en-US", { month: "short", day: "numeric", year: "numeric" });
5092
+ return `${fmt(value[0])} \u2013 ${value[1] instanceof Date ? fmt(value[1]) : "\u2026"}`;
5093
+ }
5094
+ return String(value[0]);
5095
+ }
5096
+ return String(value);
5097
+ }
5098
+ function getBadgeCount(value) {
5099
+ if (Array.isArray(value) && value.length > 1 && typeof value[0] === "string") {
5100
+ return value.length;
5101
+ }
5102
+ return void 0;
5103
+ }
5104
+ function isFilterGroup(node) {
5105
+ return node.type === "group";
5106
+ }
5107
+ function createEmptyGroup() {
5108
+ return {
5109
+ id: crypto.randomUUID(),
5110
+ type: "group",
5111
+ children: []
5112
+ };
5113
+ }
5114
+ function duplicateNode(node) {
5115
+ if (isFilterGroup(node)) {
5116
+ return {
5117
+ ...node,
5118
+ id: crypto.randomUUID(),
5119
+ children: node.children.map(duplicateNode)
5120
+ };
5121
+ }
5122
+ return { ...node, id: crypto.randomUUID() };
5123
+ }
5124
+ function wrapInGroup(condition) {
5125
+ return {
5126
+ id: crypto.randomUUID(),
5127
+ type: "group",
5128
+ logicOperator: condition.logicOperator,
5129
+ children: [{ ...condition, logicOperator: void 0 }]
5130
+ };
5131
+ }
5132
+ function unwrapGroup(group) {
5133
+ const first = group.children.find((c) => !isFilterGroup(c));
5134
+ if (!first) return null;
5135
+ return { ...first, logicOperator: group.logicOperator };
5136
+ }
5137
+ function updateNodeInTree(nodes, id, updater) {
5138
+ return nodes.map((node) => {
5139
+ if (node.id === id) return updater(node);
5140
+ if (isFilterGroup(node)) {
5141
+ const updated = updateNodeInTree(node.children, id, updater);
5142
+ if (updated !== node.children) return { ...node, children: updated };
5143
+ }
5144
+ return node;
5145
+ });
5146
+ }
5147
+ function removeNodeFromTree(nodes, id) {
5148
+ const result = [];
5149
+ for (const node of nodes) {
5150
+ if (node.id === id) continue;
5151
+ if (isFilterGroup(node)) {
5152
+ const updated = removeNodeFromTree(node.children, id);
5153
+ result.push(updated !== node.children ? { ...node, children: updated } : node);
5154
+ } else {
5155
+ result.push(node);
5156
+ }
5157
+ }
5158
+ return result;
5159
+ }
5160
+ function insertAfterInTree(nodes, afterId, newNode) {
5161
+ const result = [];
5162
+ let inserted = false;
5163
+ for (const node of nodes) {
5164
+ result.push(node);
5165
+ if (node.id === afterId) {
5166
+ result.push(newNode);
5167
+ inserted = true;
5168
+ } else if (!inserted && isFilterGroup(node)) {
5169
+ const updated = insertAfterInTree(node.children, afterId, newNode);
5170
+ if (updated.length !== node.children.length) {
5171
+ result[result.length - 1] = { ...node, children: updated };
5172
+ inserted = true;
5173
+ }
5174
+ }
5175
+ }
5176
+ return result;
5177
+ }
5178
+ function replaceNodeInTree(nodes, id, replacement) {
5179
+ return nodes.map((node) => {
5180
+ if (node.id === id) return replacement;
5181
+ if (isFilterGroup(node)) {
5182
+ const updated = replaceNodeInTree(node.children, id, replacement);
5183
+ if (updated !== node.children) return { ...node, children: updated };
5184
+ }
5185
+ return node;
5186
+ });
5187
+ }
5188
+ function countConditions(nodes) {
5189
+ let count = 0;
5190
+ for (const node of nodes) {
5191
+ if (isFilterGroup(node)) {
5192
+ count += countConditions(node.children);
5193
+ } else {
5194
+ count++;
5195
+ }
5196
+ }
5197
+ return count;
5198
+ }
5077
5199
 
5078
5200
  // src/components/ui/filter/filter-bar.tsx
5079
5201
  import * as React37 from "react";
@@ -5617,304 +5739,924 @@ var NumberRangeValueInput = ({
5617
5739
  NumberRangeValueInput.displayName = "NumberRangeValueInput";
5618
5740
 
5619
5741
  // src/components/ui/filter/value-inputs/date-value-input.tsx
5620
- import { jsx as jsx44, jsxs as jsxs39 } from "react/jsx-runtime";
5621
- var RELATIVE_DATE_PRESETS = [
5622
- { group: "Past", options: ["Today", "Yesterday", "Last 7 days", "Last 14 days", "Last 30 days", "Last 90 days"] },
5623
- { group: "Current", options: ["This week", "This month", "This quarter", "This year"] },
5624
- { group: "Future", options: ["Tomorrow", "Next 7 days", "Next 14 days", "Next 30 days", "Next week", "Next month", "Next quarter"] }
5625
- ];
5626
- var DatePickerValueInput = ({
5627
- value,
5628
- onChange,
5629
- onSubmit,
5630
- className
5631
- }) => /* @__PURE__ */ jsxs39("div", { className: cn("flex flex-col gap-base p-base", className), children: [
5632
- /* @__PURE__ */ jsx44(
5633
- "input",
5634
- {
5635
- type: "date",
5636
- value: value instanceof Date ? value.toISOString().split("T")[0] : value ?? "",
5637
- onChange: (e) => onChange(e.target.value ? new Date(e.target.value) : null),
5638
- autoFocus: true,
5639
- className: inputClasses
5640
- }
5641
- ),
5642
- /* @__PURE__ */ jsx44("button", { type: "button", onClick: onSubmit, className: applyBtnClasses, children: "Apply" })
5643
- ] });
5644
- DatePickerValueInput.displayName = "DatePickerValueInput";
5645
- function toDateString(d) {
5646
- if (!d) return "";
5647
- if (d instanceof Date) return d.toISOString().split("T")[0];
5648
- return String(d);
5649
- }
5650
- var DateRangeValueInput = ({
5651
- value,
5652
- onChange,
5653
- onSubmit,
5654
- className
5655
- }) => {
5656
- const rangeVal = Array.isArray(value) ? value : [null, null];
5657
- return /* @__PURE__ */ jsxs39("div", { className: cn("flex flex-col gap-base p-base", className), children: [
5658
- /* @__PURE__ */ jsxs39("div", { className: "flex items-center gap-base", children: [
5659
- /* @__PURE__ */ jsx44(
5660
- "input",
5661
- {
5662
- type: "date",
5663
- value: toDateString(rangeVal[0]),
5664
- onChange: (e) => {
5665
- const from = e.target.value ? new Date(e.target.value) : null;
5666
- onChange([from, rangeVal[1]]);
5667
- },
5668
- autoFocus: true,
5669
- className: halfInputClasses
5670
- }
5671
- ),
5672
- /* @__PURE__ */ jsx44("span", { className: "text-sm text-[var(--color-muted-foreground)]", children: "to" }),
5673
- /* @__PURE__ */ jsx44(
5674
- "input",
5675
- {
5676
- type: "date",
5677
- value: toDateString(rangeVal[1]),
5678
- onChange: (e) => {
5679
- const to = e.target.value ? new Date(e.target.value) : null;
5680
- onChange([rangeVal[0], to]);
5681
- },
5682
- className: halfInputClasses
5683
- }
5684
- )
5685
- ] }),
5686
- /* @__PURE__ */ jsx44("button", { type: "button", onClick: onSubmit, className: applyBtnClasses, children: "Apply" })
5687
- ] });
5688
- };
5689
- DateRangeValueInput.displayName = "DateRangeValueInput";
5690
- var PresetTagsValueInput = ({
5691
- value,
5692
- onChange,
5693
- onSubmit,
5694
- className
5695
- }) => /* @__PURE__ */ jsx44("div", { className: cn("flex flex-col gap-base p-base max-w-[280px]", className), children: RELATIVE_DATE_PRESETS.map((group) => /* @__PURE__ */ jsxs39("div", { className: "flex flex-col gap-xs", children: [
5696
- /* @__PURE__ */ jsx44("span", { className: "text-xs font-semibold leading-xs text-[var(--color-muted-foreground)] uppercase px-xs", children: group.group }),
5697
- /* @__PURE__ */ jsx44("div", { className: "flex flex-wrap gap-xs", children: group.options.map((preset) => /* @__PURE__ */ jsx44(
5698
- "button",
5699
- {
5700
- type: "button",
5701
- onClick: () => {
5702
- onChange(preset);
5703
- onSubmit?.();
5704
- },
5705
- className: cn(
5706
- "px-base py-2xs rounded-base border cursor-pointer transition-colors text-sm font-regular leading-sm",
5707
- value === preset ? "border-[var(--color-ring)] bg-[var(--color-primary)] text-[var(--color-primary-foreground)]" : "border-[var(--color-input)] bg-[var(--color-background)] text-[var(--color-foreground)] hover:bg-[var(--color-accent)]"
5708
- ),
5709
- children: preset
5710
- },
5711
- preset
5712
- )) })
5713
- ] }, group.group)) });
5714
- PresetTagsValueInput.displayName = "PresetTagsValueInput";
5715
-
5716
- // src/components/ui/filter/value-inputs/select-value-input.tsx
5717
- import { jsx as jsx45, jsxs as jsxs40 } from "react/jsx-runtime";
5718
- var SingleSelectValueInput = ({
5719
- value,
5720
- onChange,
5721
- onSubmit,
5722
- options,
5723
- className
5724
- }) => /* @__PURE__ */ jsx45("div", { className: cn("flex flex-col gap-xs p-base max-h-[250px] overflow-y-auto", className), children: options.map((opt) => /* @__PURE__ */ jsx45(
5725
- "button",
5726
- {
5727
- type: "button",
5728
- onClick: () => {
5729
- onChange(opt);
5730
- onSubmit?.();
5731
- },
5732
- className: cn(
5733
- "flex items-center gap-base p-base rounded-base cursor-pointer transition-colors text-left",
5734
- "hover:bg-[var(--color-dropdown-item-hover)]",
5735
- value === opt && "bg-[var(--color-dropdown-item-hover)]"
5736
- ),
5737
- children: /* @__PURE__ */ jsx45("span", { className: "text-sm font-regular leading-sm text-[var(--color-foreground)]", children: opt })
5738
- },
5739
- opt
5740
- )) });
5741
- SingleSelectValueInput.displayName = "SingleSelectValueInput";
5742
- var MultiSelectValueInput = ({
5743
- value,
5744
- onChange,
5745
- onSubmit,
5746
- options,
5747
- className
5748
- }) => {
5749
- const selected = Array.isArray(value) ? value : [];
5750
- return /* @__PURE__ */ jsxs40("div", { className: cn("flex flex-col gap-xs p-base", className), children: [
5751
- /* @__PURE__ */ jsx45("div", { className: "flex flex-col max-h-[200px] overflow-y-auto", children: options.map((opt) => {
5752
- const isSelected = selected.includes(opt);
5753
- return /* @__PURE__ */ jsxs40(
5754
- "button",
5755
- {
5756
- type: "button",
5757
- onClick: () => {
5758
- const next = isSelected ? selected.filter((s) => s !== opt) : [...selected, opt];
5759
- onChange(next);
5760
- },
5761
- className: cn(
5762
- "flex items-center gap-base p-base rounded-base cursor-pointer transition-colors text-left",
5763
- "hover:bg-[var(--color-dropdown-item-hover)]"
5764
- ),
5765
- children: [
5766
- /* @__PURE__ */ jsx45(
5767
- "span",
5768
- {
5769
- className: cn(
5770
- "flex items-center justify-center size-4 rounded-xs border transition-colors",
5771
- isSelected ? "bg-[var(--color-primary)] border-[var(--color-primary)]" : "border-[var(--color-input)] bg-[var(--color-background)]"
5772
- ),
5773
- children: isSelected && /* @__PURE__ */ jsx45("svg", { width: "10", height: "10", viewBox: "0 0 10 10", fill: "none", children: /* @__PURE__ */ jsx45("path", { d: "M2 5L4 7L8 3", stroke: "white", strokeWidth: "1.5", strokeLinecap: "round", strokeLinejoin: "round" }) })
5774
- }
5775
- ),
5776
- /* @__PURE__ */ jsx45("span", { className: "text-sm font-regular leading-sm text-[var(--color-foreground)]", children: opt })
5777
- ]
5778
- },
5779
- opt
5780
- );
5781
- }) }),
5782
- /* @__PURE__ */ jsx45("button", { type: "button", onClick: onSubmit, className: applyBtnClasses, children: "Apply" })
5783
- ] });
5784
- };
5785
- MultiSelectValueInput.displayName = "MultiSelectValueInput";
5786
-
5787
- // src/components/ui/filter/value-inputs/relation-value-input.tsx
5788
- import { jsx as jsx46, jsxs as jsxs41 } from "react/jsx-runtime";
5789
- var RelationValueInput = ({
5790
- value,
5791
- onChange,
5792
- onSubmit,
5793
- className
5794
- }) => {
5795
- const handleKeyDown = (e) => {
5796
- if (e.key === "Enter") onSubmit?.();
5797
- };
5798
- return /* @__PURE__ */ jsxs41("div", { className: cn("flex flex-col gap-base p-base", className), children: [
5799
- /* @__PURE__ */ jsx46(
5800
- "input",
5801
- {
5802
- type: "text",
5803
- value: value ?? "",
5804
- onChange: (e) => onChange(e.target.value),
5805
- onKeyDown: handleKeyDown,
5806
- placeholder: "Search...",
5807
- autoFocus: true,
5808
- className: inputClasses
5809
- }
5810
- ),
5811
- /* @__PURE__ */ jsx46("button", { type: "button", onClick: onSubmit, className: applyBtnClasses, children: "Apply" })
5812
- ] });
5813
- };
5814
- RelationValueInput.displayName = "RelationValueInput";
5815
-
5816
- // src/components/ui/filter/value-input.tsx
5817
- import { jsx as jsx47 } from "react/jsx-runtime";
5818
- var ValueInput = ({
5819
- dataType,
5820
- operator,
5821
- value,
5822
- onChange,
5823
- onSubmit,
5824
- options = [],
5825
- className
5826
- }) => {
5827
- const inputType = getValueInputType(dataType, operator);
5828
- if (!inputType) return null;
5829
- switch (inputType) {
5830
- case "TextInput":
5831
- return /* @__PURE__ */ jsx47(TextValueInput, { value, onChange, onSubmit, className });
5832
- case "NumberInput":
5833
- return /* @__PURE__ */ jsx47(NumberValueInput, { value, onChange, onSubmit, className });
5834
- case "NumberRange":
5835
- return /* @__PURE__ */ jsx47(NumberRangeValueInput, { value, onChange, onSubmit, className });
5836
- case "PresetTags":
5837
- return /* @__PURE__ */ jsx47(PresetTagsValueInput, { value, onChange, onSubmit, className });
5838
- case "SingleSelect":
5839
- return /* @__PURE__ */ jsx47(SingleSelectValueInput, { value, onChange, onSubmit, options, className });
5840
- case "MultiSelect":
5841
- return /* @__PURE__ */ jsx47(MultiSelectValueInput, { value, onChange, onSubmit, options, className });
5842
- case "DatePicker":
5843
- return /* @__PURE__ */ jsx47(DatePickerValueInput, { value, onChange, onSubmit, className });
5844
- case "DateRange":
5845
- return /* @__PURE__ */ jsx47(DateRangeValueInput, { value, onChange, onSubmit, className });
5846
- case "RelationPicker":
5847
- case "MultiRelationPicker":
5848
- return /* @__PURE__ */ jsx47(RelationValueInput, { value, onChange, onSubmit, className });
5849
- default:
5850
- return null;
5851
- }
5852
- };
5853
- ValueInput.displayName = "ValueInput";
5742
+ import * as React42 from "react";
5854
5743
 
5855
- // src/components/ui/filter/property-selector.tsx
5744
+ // src/components/ui/date-picker.tsx
5856
5745
  import * as React41 from "react";
5857
5746
  import * as PopoverPrimitive5 from "@radix-ui/react-popover";
5858
5747
  import {
5859
5748
  Icon as Icon26,
5860
5749
  faChevronLeftOutline as faChevronLeftOutline2,
5861
5750
  faChevronRightOutline as faChevronRightOutline2,
5862
- faMagnifyingGlassOutline,
5863
- faFilterOutline as faFilterOutline2
5751
+ faArrowRightOutline,
5752
+ faCalendarOutline
5864
5753
  } from "@l3mpire/icons";
5865
- import { Fragment as Fragment4, jsx as jsx48, jsxs as jsxs42 } from "react/jsx-runtime";
5866
- var AdvancedFilterFooter = ({ onClick, count }) => /* @__PURE__ */ jsxs42(Fragment4, { children: [
5867
- /* @__PURE__ */ jsx48("div", { className: "h-px bg-[var(--color-dropdown-border)] mx-xs" }),
5868
- /* @__PURE__ */ jsxs42(
5869
- "button",
5870
- {
5871
- type: "button",
5872
- onPointerDown: (e) => e.preventDefault(),
5873
- onClick,
5874
- className: "flex items-center gap-base p-base rounded-base cursor-pointer transition-colors hover:bg-[var(--color-dropdown-item-hover)]",
5875
- children: [
5876
- /* @__PURE__ */ jsx48(
5877
- Icon26,
5878
- {
5879
- icon: faFilterOutline2,
5880
- size: "sm",
5881
- className: "shrink-0 text-[var(--color-dropdown-item-icon)]"
5882
- }
5883
- ),
5884
- /* @__PURE__ */ jsx48("span", { className: "flex-1 text-sm font-regular leading-sm text-[var(--color-dropdown-item-text)] text-left truncate", children: "Advanced filter" }),
5885
- count > 0 && /* @__PURE__ */ jsxs42("span", { className: "text-xs font-regular leading-xs text-[var(--color-muted-foreground)]", children: [
5886
- count,
5887
- " ",
5888
- count === 1 ? "rule" : "rules"
5889
- ] })
5890
- ]
5891
- }
5892
- )
5893
- ] });
5894
- var PropertySelector = ({
5895
- properties,
5896
- onSelect,
5897
- open,
5898
- onOpenChange,
5899
- children,
5900
- onAdvancedFilter,
5901
- advancedFilterCount = 0
5902
- }) => {
5903
- const handleAdvancedClick = (e) => {
5904
- e.stopPropagation();
5905
- e.preventDefault();
5906
- onAdvancedFilter?.();
5907
- };
5908
- const showAdvancedFooter = !!onAdvancedFilter;
5909
- const [activeGroup, setActiveGroup] = React41.useState(null);
5910
- const [search, setSearch] = React41.useState("");
5911
- React41.useEffect(() => {
5754
+ import { jsx as jsx44, jsxs as jsxs39 } from "react/jsx-runtime";
5755
+ function getDaysInMonth(year, month) {
5756
+ return new Date(year, month + 1, 0).getDate();
5757
+ }
5758
+ function getWeekdayIndex(date) {
5759
+ return (date.getDay() + 6) % 7;
5760
+ }
5761
+ function isSameDay(a, b) {
5762
+ return a.getFullYear() === b.getFullYear() && a.getMonth() === b.getMonth() && a.getDate() === b.getDate();
5763
+ }
5764
+ function isInRange(date, from, to) {
5765
+ const t = date.getTime();
5766
+ return t >= from.getTime() && t <= to.getTime();
5767
+ }
5768
+ function startOfDay(d) {
5769
+ return new Date(d.getFullYear(), d.getMonth(), d.getDate());
5770
+ }
5771
+ var WEEKDAYS = ["Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"];
5772
+ var MONTH_NAMES = [
5773
+ "January",
5774
+ "February",
5775
+ "March",
5776
+ "April",
5777
+ "May",
5778
+ "June",
5779
+ "July",
5780
+ "August",
5781
+ "September",
5782
+ "October",
5783
+ "November",
5784
+ "December"
5785
+ ];
5786
+ var DatePickerContext = React41.createContext(
5787
+ null
5788
+ );
5789
+ function useDatePickerContext() {
5790
+ const ctx = React41.useContext(DatePickerContext);
5791
+ if (!ctx)
5792
+ throw new Error("DatePicker compound components must be used within <DatePicker>");
5793
+ return ctx;
5794
+ }
5795
+ var DatePicker = React41.forwardRef(
5796
+ ({
5797
+ className,
5798
+ mode = "single",
5799
+ value,
5800
+ onValueChange,
5801
+ defaultMonth,
5802
+ defaultYear,
5803
+ children,
5804
+ ...props
5805
+ }, ref) => {
5806
+ const today = React41.useMemo(() => startOfDay(/* @__PURE__ */ new Date()), []);
5807
+ const initialDate = React41.useMemo(() => {
5808
+ if (value) {
5809
+ if (value instanceof Date) return value;
5810
+ return value.from;
5811
+ }
5812
+ return today;
5813
+ }, []);
5814
+ const [month, setMonth] = React41.useState(
5815
+ defaultMonth ?? initialDate.getMonth()
5816
+ );
5817
+ const [year, setYear] = React41.useState(
5818
+ defaultYear ?? initialDate.getFullYear()
5819
+ );
5820
+ const [hoveredDate, setHoveredDate] = React41.useState();
5821
+ const goToPrevMonth = React41.useCallback(() => {
5822
+ setMonth((m) => {
5823
+ if (m === 0) {
5824
+ setYear((y) => y - 1);
5825
+ return 11;
5826
+ }
5827
+ return m - 1;
5828
+ });
5829
+ }, []);
5830
+ const goToNextMonth = React41.useCallback(() => {
5831
+ setMonth((m) => {
5832
+ if (m === 11) {
5833
+ setYear((y) => y + 1);
5834
+ return 0;
5835
+ }
5836
+ return m + 1;
5837
+ });
5838
+ }, []);
5839
+ const onSelect = React41.useCallback(
5840
+ (date) => {
5841
+ if (mode === "single") {
5842
+ onValueChange?.(date);
5843
+ return;
5844
+ }
5845
+ if (!value || value instanceof Date) {
5846
+ onValueChange?.({ from: date });
5847
+ return;
5848
+ }
5849
+ const range = value;
5850
+ if (range.to || date.getTime() < range.from.getTime()) {
5851
+ onValueChange?.({ from: date });
5852
+ } else {
5853
+ onValueChange?.({ from: range.from, to: date });
5854
+ }
5855
+ },
5856
+ [mode, value, onValueChange]
5857
+ );
5858
+ const ctxValue = React41.useMemo(
5859
+ () => ({
5860
+ mode,
5861
+ selected: value,
5862
+ onSelect,
5863
+ month,
5864
+ year,
5865
+ setMonth,
5866
+ setYear,
5867
+ goToPrevMonth,
5868
+ goToNextMonth,
5869
+ today,
5870
+ hoveredDate,
5871
+ setHoveredDate
5872
+ }),
5873
+ [
5874
+ mode,
5875
+ value,
5876
+ onSelect,
5877
+ month,
5878
+ year,
5879
+ goToPrevMonth,
5880
+ goToNextMonth,
5881
+ today,
5882
+ hoveredDate
5883
+ ]
5884
+ );
5885
+ return /* @__PURE__ */ jsx44(DatePickerContext.Provider, { value: ctxValue, children: /* @__PURE__ */ jsx44(
5886
+ "div",
5887
+ {
5888
+ ref,
5889
+ className: cn(
5890
+ "flex flex-col overflow-clip",
5891
+ "bg-datepicker-bg border border-datepicker-border rounded-md shadow-lg",
5892
+ className
5893
+ ),
5894
+ ...props,
5895
+ children
5896
+ }
5897
+ ) });
5898
+ }
5899
+ );
5900
+ DatePicker.displayName = "DatePicker";
5901
+ function defaultFormatDate(date) {
5902
+ return date.toLocaleDateString("en-US", {
5903
+ month: "short",
5904
+ day: "numeric",
5905
+ year: "numeric"
5906
+ });
5907
+ }
5908
+ var DatePickerSelects = React41.forwardRef(({ className, formatDate = defaultFormatDate, ...props }, ref) => {
5909
+ const { selected } = useDatePickerContext();
5910
+ const fromDate = selected instanceof Date ? selected : selected?.from;
5911
+ const toDate = selected instanceof Date ? void 0 : selected?.to;
5912
+ return /* @__PURE__ */ jsx44(
5913
+ "div",
5914
+ {
5915
+ ref,
5916
+ className: cn("flex flex-col items-start pt-lg px-lg", className),
5917
+ ...props,
5918
+ children: /* @__PURE__ */ jsxs39("div", { className: "flex items-center gap-base w-full", children: [
5919
+ /* @__PURE__ */ jsxs39("div", { className: "flex-1 flex items-center gap-base min-w-0 px-base py-sm bg-gradient-to-t from-[var(--color-select-bg-default)] to-[var(--color-select-bg-gradient-to)] border border-[var(--color-select-border-default)] rounded-base shadow-sm", children: [
5920
+ /* @__PURE__ */ jsx44("span", { className: "flex-1 text-sm font-regular leading-sm text-datepicker-header-text truncate", children: fromDate ? formatDate(fromDate) : "Start date" }),
5921
+ /* @__PURE__ */ jsx44(Icon26, { icon: faCalendarOutline, size: "sm", className: "shrink-0 text-datepicker-header-text" })
5922
+ ] }),
5923
+ /* @__PURE__ */ jsx44(
5924
+ Icon26,
5925
+ {
5926
+ icon: faArrowRightOutline,
5927
+ size: "sm",
5928
+ className: "shrink-0 text-datepicker-header-weekday"
5929
+ }
5930
+ ),
5931
+ /* @__PURE__ */ jsxs39("div", { className: "flex-1 flex items-center gap-base min-w-0 px-base py-sm bg-gradient-to-t from-[var(--color-select-bg-default)] to-[var(--color-select-bg-gradient-to)] border border-[var(--color-select-border-default)] rounded-base shadow-sm", children: [
5932
+ /* @__PURE__ */ jsx44("span", { className: "flex-1 text-sm font-regular leading-sm text-datepicker-header-text truncate", children: toDate ? formatDate(toDate) : "End date" }),
5933
+ /* @__PURE__ */ jsx44(Icon26, { icon: faCalendarOutline, size: "sm", className: "shrink-0 text-datepicker-header-text" })
5934
+ ] })
5935
+ ] })
5936
+ }
5937
+ );
5938
+ });
5939
+ DatePickerSelects.displayName = "DatePickerSelects";
5940
+ var DatePickerDay = ({ date, isOutside }) => {
5941
+ const { mode, selected, onSelect, today, hoveredDate, setHoveredDate } = useDatePickerContext();
5942
+ const isToday = isSameDay(date, today);
5943
+ const isSelected = selected instanceof Date ? isSameDay(date, selected) : selected?.from ? isSameDay(date, selected.from) || (selected.to ? isSameDay(date, selected.to) : false) : false;
5944
+ const isRangeStart = mode === "range" && selected && !(selected instanceof Date) && selected.from && isSameDay(date, selected.from);
5945
+ const isRangeEnd = mode === "range" && selected && !(selected instanceof Date) && selected.to && isSameDay(date, selected.to);
5946
+ const inRange = mode === "range" && selected && !(selected instanceof Date) && selected.from && selected.to && !isSelected && isInRange(date, selected.from, selected.to);
5947
+ const inPreviewRange = mode === "range" && selected && !(selected instanceof Date) && selected.from && !selected.to && hoveredDate && !isSelected && hoveredDate.getTime() > selected.from.getTime() && isInRange(date, selected.from, hoveredDate);
5948
+ const isInRangeOrPreview = inRange || inPreviewRange;
5949
+ return /* @__PURE__ */ jsxs39(
5950
+ "button",
5951
+ {
5952
+ type: "button",
5953
+ onClick: () => !isOutside && onSelect(date),
5954
+ onMouseEnter: () => mode === "range" && setHoveredDate(date),
5955
+ onMouseLeave: () => mode === "range" && setHoveredDate(void 0),
5956
+ disabled: isOutside,
5957
+ className: cn(
5958
+ "relative flex flex-col items-center justify-center w-9 rounded-full p-2 cursor-pointer transition-colors",
5959
+ "text-sm font-semibold leading-sm text-center",
5960
+ // Default
5961
+ !isOutside && !isSelected && !isInRangeOrPreview && "text-datepicker-day-text-default hover:bg-datepicker-day-bg-hover",
5962
+ // Outside month (disabled)
5963
+ isOutside && "text-datepicker-day-text-disabled cursor-default",
5964
+ // Selected
5965
+ isSelected && "bg-datepicker-day-bg-selected text-datepicker-day-text-selected",
5966
+ // In range
5967
+ isInRangeOrPreview && "bg-datepicker-day-bg-range text-datepicker-day-text-range",
5968
+ // Range start/end get full rounded; in-range items could be less rounded
5969
+ (isRangeStart || isRangeEnd) && "rounded-full"
5970
+ ),
5971
+ children: [
5972
+ date.getDate(),
5973
+ isToday && !isOutside && /* @__PURE__ */ jsx44("span", { className: "absolute bottom-0.5 left-1/2 -translate-x-1/2 size-1.5 rounded-full bg-datepicker-day-today" })
5974
+ ]
5975
+ }
5976
+ );
5977
+ };
5978
+ var DatePickerCalendar = React41.forwardRef(({ className, header, ...props }, ref) => {
5979
+ const { month, year, goToPrevMonth, goToNextMonth } = useDatePickerContext();
5980
+ const weeks = React41.useMemo(() => {
5981
+ const firstDay = new Date(year, month, 1);
5982
+ const startOffset = getWeekdayIndex(firstDay);
5983
+ const daysInMonth = getDaysInMonth(year, month);
5984
+ const daysInPrevMonth = getDaysInMonth(
5985
+ month === 0 ? year - 1 : year,
5986
+ month === 0 ? 11 : month - 1
5987
+ );
5988
+ const days = [];
5989
+ for (let i = startOffset - 1; i >= 0; i--) {
5990
+ const d = daysInPrevMonth - i;
5991
+ days.push({
5992
+ date: new Date(
5993
+ month === 0 ? year - 1 : year,
5994
+ month === 0 ? 11 : month - 1,
5995
+ d
5996
+ ),
5997
+ isOutside: true
5998
+ });
5999
+ }
6000
+ for (let d = 1; d <= daysInMonth; d++) {
6001
+ days.push({ date: new Date(year, month, d), isOutside: false });
6002
+ }
6003
+ const remaining = 42 - days.length;
6004
+ for (let d = 1; d <= remaining; d++) {
6005
+ days.push({
6006
+ date: new Date(
6007
+ month === 11 ? year + 1 : year,
6008
+ month === 11 ? 0 : month + 1,
6009
+ d
6010
+ ),
6011
+ isOutside: true
6012
+ });
6013
+ }
6014
+ const result = [];
6015
+ for (let i = 0; i < days.length; i += 7) {
6016
+ result.push(days.slice(i, i + 7));
6017
+ }
6018
+ return result;
6019
+ }, [month, year]);
6020
+ return /* @__PURE__ */ jsxs39(
6021
+ "div",
6022
+ {
6023
+ ref,
6024
+ className: cn("flex flex-col", className),
6025
+ ...props,
6026
+ children: [
6027
+ header,
6028
+ /* @__PURE__ */ jsxs39("div", { className: "flex flex-col gap-lg p-lg", children: [
6029
+ /* @__PURE__ */ jsxs39("div", { className: "flex items-center justify-between", children: [
6030
+ /* @__PURE__ */ jsxs39("span", { className: "text-base font-semibold leading-base text-datepicker-header-text", children: [
6031
+ MONTH_NAMES[month],
6032
+ " ",
6033
+ year
6034
+ ] }),
6035
+ /* @__PURE__ */ jsxs39("div", { className: "flex items-center gap-xs", children: [
6036
+ /* @__PURE__ */ jsx44(
6037
+ "button",
6038
+ {
6039
+ type: "button",
6040
+ onClick: goToPrevMonth,
6041
+ className: "flex items-center justify-center p-xs rounded-base hover:bg-datepicker-day-bg-hover transition-colors cursor-pointer",
6042
+ "aria-label": "Previous month",
6043
+ children: /* @__PURE__ */ jsx44(Icon26, { icon: faChevronLeftOutline2, size: "xs", className: "text-datepicker-header-nav" })
6044
+ }
6045
+ ),
6046
+ /* @__PURE__ */ jsx44(
6047
+ "button",
6048
+ {
6049
+ type: "button",
6050
+ onClick: goToNextMonth,
6051
+ className: "flex items-center justify-center p-xs rounded-base hover:bg-datepicker-day-bg-hover transition-colors cursor-pointer",
6052
+ "aria-label": "Next month",
6053
+ children: /* @__PURE__ */ jsx44(Icon26, { icon: faChevronRightOutline2, size: "xs", className: "text-datepicker-header-nav" })
6054
+ }
6055
+ )
6056
+ ] })
6057
+ ] }),
6058
+ /* @__PURE__ */ jsxs39("div", { className: "flex flex-col", children: [
6059
+ /* @__PURE__ */ jsx44("div", { className: "grid grid-cols-7 gap-base py-sm", children: WEEKDAYS.map((day) => /* @__PURE__ */ jsx44(
6060
+ "span",
6061
+ {
6062
+ className: "w-9 text-center text-xs font-regular leading-xs text-datepicker-header-weekday",
6063
+ children: day
6064
+ },
6065
+ day
6066
+ )) }),
6067
+ /* @__PURE__ */ jsx44("div", { className: "flex flex-col", children: weeks.map((week, wi) => /* @__PURE__ */ jsx44("div", { className: "grid grid-cols-7 gap-base", children: week.map((day, di) => /* @__PURE__ */ jsx44(
6068
+ DatePickerDay,
6069
+ {
6070
+ date: day.date,
6071
+ isOutside: day.isOutside
6072
+ },
6073
+ di
6074
+ )) }, wi)) })
6075
+ ] })
6076
+ ] })
6077
+ ]
6078
+ }
6079
+ );
6080
+ });
6081
+ DatePickerCalendar.displayName = "DatePickerCalendar";
6082
+ var DatePickerSuggestions = React41.forwardRef(
6083
+ ({ className, suggestions, formatDate = defaultFormatDate, ...props }, ref) => {
6084
+ const { onSelect, mode } = useDatePickerContext();
6085
+ const onValueChange = React41.useContext(DatePickerContext) ? void 0 : void 0;
6086
+ const ctx = useDatePickerContext();
6087
+ const handleClick = (suggestion) => {
6088
+ const val = suggestion.getValue();
6089
+ if (val instanceof Date) {
6090
+ ctx.onSelect(val);
6091
+ } else {
6092
+ ctx.onSelect(val.from);
6093
+ if (val.to) {
6094
+ setTimeout(() => ctx.onSelect(val.to), 0);
6095
+ }
6096
+ }
6097
+ };
6098
+ const formatSuggestionDate = (suggestion) => {
6099
+ const val = suggestion.getValue();
6100
+ if (val instanceof Date) {
6101
+ return formatDate(val);
6102
+ }
6103
+ const from = formatDate(val.from);
6104
+ const to = val.to ? formatDate(val.to) : "";
6105
+ return to ? `${from} - ${to}` : from;
6106
+ };
6107
+ return /* @__PURE__ */ jsxs39(
6108
+ "div",
6109
+ {
6110
+ ref,
6111
+ className: cn(
6112
+ "flex flex-col border-l border-datepicker-border self-stretch shrink-0",
6113
+ className
6114
+ ),
6115
+ ...props,
6116
+ children: [
6117
+ /* @__PURE__ */ jsx44("div", { className: "pt-lg px-base", children: /* @__PURE__ */ jsx44("div", { className: "flex items-center p-base rounded-base", children: /* @__PURE__ */ jsx44("span", { className: "flex-1 text-xs font-semibold leading-xs text-datepicker-suggestion-heading uppercase truncate", children: "Suggestions" }) }) }),
6118
+ /* @__PURE__ */ jsx44("div", { className: "flex flex-1 flex-col p-base min-w-[222px]", children: suggestions.map((suggestion, i) => /* @__PURE__ */ jsxs39(
6119
+ "button",
6120
+ {
6121
+ type: "button",
6122
+ onClick: () => handleClick(suggestion),
6123
+ className: "flex items-center gap-sm p-base rounded-base hover:bg-datepicker-suggestion-hover transition-colors cursor-pointer text-left",
6124
+ children: [
6125
+ /* @__PURE__ */ jsx44("span", { className: "text-sm font-regular leading-sm text-datepicker-suggestion-text truncate shrink-0", children: suggestion.label }),
6126
+ /* @__PURE__ */ jsx44("span", { className: "text-xs font-regular leading-xs text-datepicker-suggestion-date truncate", children: formatSuggestionDate(suggestion) })
6127
+ ]
6128
+ },
6129
+ i
6130
+ )) })
6131
+ ]
6132
+ }
6133
+ );
6134
+ }
6135
+ );
6136
+ DatePickerSuggestions.displayName = "DatePickerSuggestions";
6137
+ var DatePickerFooter = React41.forwardRef(
6138
+ ({ className, children, ...props }, ref) => /* @__PURE__ */ jsx44(
6139
+ "div",
6140
+ {
6141
+ ref,
6142
+ className: cn(
6143
+ "flex items-center justify-between p-lg",
6144
+ "border-t border-datepicker-footer-border",
6145
+ "bg-datepicker-bg",
6146
+ className
6147
+ ),
6148
+ ...props,
6149
+ children
6150
+ }
6151
+ )
6152
+ );
6153
+ DatePickerFooter.displayName = "DatePickerFooter";
6154
+ var DatePickerPanel = React41.forwardRef(
6155
+ ({ className, children, ...props }, ref) => /* @__PURE__ */ jsx44(
6156
+ "div",
6157
+ {
6158
+ ref,
6159
+ className: cn("flex items-start", className),
6160
+ ...props,
6161
+ children
6162
+ }
6163
+ )
6164
+ );
6165
+ DatePickerPanel.displayName = "DatePickerPanel";
6166
+ var DatePickerRoot = PopoverPrimitive5.Root;
6167
+ var DatePickerTrigger = PopoverPrimitive5.Trigger;
6168
+ var DatePickerPopover = React41.forwardRef(({ className, sideOffset = 4, align = "start", children, ...props }, ref) => /* @__PURE__ */ jsx44(PopoverPrimitive5.Portal, { children: /* @__PURE__ */ jsx44(
6169
+ PopoverPrimitive5.Content,
6170
+ {
6171
+ ref,
6172
+ sideOffset,
6173
+ align,
6174
+ className: cn(
6175
+ "z-50",
6176
+ "data-[state=open]:animate-in data-[state=open]:fade-in-0 data-[state=open]:zoom-in-95",
6177
+ "data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=closed]:zoom-out-95",
6178
+ "data-[side=bottom]:slide-in-from-top-2 data-[side=top]:slide-in-from-bottom-2",
6179
+ className
6180
+ ),
6181
+ ...props,
6182
+ children
6183
+ }
6184
+ ) }));
6185
+ DatePickerPopover.displayName = "DatePickerPopover";
6186
+ function getDefaultSuggestions(referenceDate) {
6187
+ const now = referenceDate ?? /* @__PURE__ */ new Date();
6188
+ const today = startOfDay(now);
6189
+ const dayOfWeek = getWeekdayIndex(today);
6190
+ const startOfThisWeek = new Date(today);
6191
+ startOfThisWeek.setDate(today.getDate() - dayOfWeek);
6192
+ const endOfThisWeek = new Date(startOfThisWeek);
6193
+ endOfThisWeek.setDate(startOfThisWeek.getDate() + 6);
6194
+ const startOfThisMonth = new Date(today.getFullYear(), today.getMonth(), 1);
6195
+ const endOfThisMonth = new Date(
6196
+ today.getFullYear(),
6197
+ today.getMonth() + 1,
6198
+ 0
6199
+ );
6200
+ const startOfThisYear = new Date(today.getFullYear(), 0, 1);
6201
+ const endOfThisYear = new Date(today.getFullYear(), 11, 31);
6202
+ const startOfLastWeek = new Date(startOfThisWeek);
6203
+ startOfLastWeek.setDate(startOfThisWeek.getDate() - 7);
6204
+ const endOfLastWeek = new Date(startOfThisWeek);
6205
+ endOfLastWeek.setDate(startOfThisWeek.getDate() - 1);
6206
+ const startOfLastMonth = new Date(
6207
+ today.getFullYear(),
6208
+ today.getMonth() - 1,
6209
+ 1
6210
+ );
6211
+ const endOfLastMonth = new Date(today.getFullYear(), today.getMonth(), 0);
6212
+ const startOfLastYear = new Date(today.getFullYear() - 1, 0, 1);
6213
+ const endOfLastYear = new Date(today.getFullYear() - 1, 11, 31);
6214
+ return [
6215
+ { label: "Today", getValue: () => today },
6216
+ {
6217
+ label: "This week",
6218
+ getValue: () => ({ from: startOfThisWeek, to: endOfThisWeek })
6219
+ },
6220
+ {
6221
+ label: "This month",
6222
+ getValue: () => ({ from: startOfThisMonth, to: endOfThisMonth })
6223
+ },
6224
+ {
6225
+ label: "This year",
6226
+ getValue: () => ({ from: startOfThisYear, to: endOfThisYear })
6227
+ },
6228
+ {
6229
+ label: "Last week",
6230
+ getValue: () => ({ from: startOfLastWeek, to: endOfLastWeek })
6231
+ },
6232
+ {
6233
+ label: "Last month",
6234
+ getValue: () => ({ from: startOfLastMonth, to: endOfLastMonth })
6235
+ },
6236
+ {
6237
+ label: "Last year",
6238
+ getValue: () => ({ from: startOfLastYear, to: endOfLastYear })
6239
+ }
6240
+ ];
6241
+ }
6242
+
6243
+ // src/components/ui/filter/value-inputs/date-value-input.tsx
6244
+ import { jsx as jsx45, jsxs as jsxs40 } from "react/jsx-runtime";
6245
+ var RELATIVE_DATE_PRESETS = [
6246
+ { group: "Past", options: ["Today", "Yesterday", "Last 7 days", "Last 14 days", "Last 30 days", "Last 90 days"] },
6247
+ { group: "Current", options: ["This week", "This month", "This quarter", "This year"] },
6248
+ { group: "Future", options: ["Tomorrow", "Next 7 days", "Next 14 days", "Next 30 days", "Next week", "Next month", "Next quarter"] }
6249
+ ];
6250
+ var DateCalendarValueInput = ({
6251
+ operator,
6252
+ value,
6253
+ onChange,
6254
+ onSubmit,
6255
+ className
6256
+ }) => {
6257
+ const isRange = operator === "is between";
6258
+ const pickerValue = React42.useMemo(() => {
6259
+ if (isRange) {
6260
+ if (Array.isArray(value) && value.length === 2) {
6261
+ const [from, to] = value;
6262
+ return { from, to };
6263
+ }
6264
+ return void 0;
6265
+ }
6266
+ return value instanceof Date ? value : void 0;
6267
+ }, [value, isRange]);
6268
+ const handleValueChange = (v) => {
6269
+ if (v instanceof Date) {
6270
+ onChange(v);
6271
+ if (!isRange) onSubmit?.();
6272
+ } else {
6273
+ const range = v;
6274
+ if (range.from && range.to) {
6275
+ onChange([range.from, range.to]);
6276
+ } else if (range.from) {
6277
+ onChange([range.from, range.from]);
6278
+ }
6279
+ }
6280
+ };
6281
+ const suggestions = React42.useMemo(() => getDefaultSuggestions(), []);
6282
+ return /* @__PURE__ */ jsx45("div", { className: cn("flex flex-col", className), children: /* @__PURE__ */ jsxs40(
6283
+ DatePicker,
6284
+ {
6285
+ mode: isRange ? "range" : "single",
6286
+ value: pickerValue,
6287
+ onValueChange: handleValueChange,
6288
+ children: [
6289
+ isRange && /* @__PURE__ */ jsx45(DatePickerSelects, {}),
6290
+ isRange ? /* @__PURE__ */ jsxs40(DatePickerPanel, { children: [
6291
+ /* @__PURE__ */ jsx45(DatePickerCalendar, {}),
6292
+ /* @__PURE__ */ jsx45(DatePickerSuggestions, { suggestions })
6293
+ ] }) : /* @__PURE__ */ jsx45(DatePickerCalendar, {}),
6294
+ isRange && /* @__PURE__ */ jsxs40(DatePickerFooter, { children: [
6295
+ /* @__PURE__ */ jsx45("div", {}),
6296
+ /* @__PURE__ */ jsx45("button", { type: "button", onClick: onSubmit, className: applyBtnClasses, children: "Apply" })
6297
+ ] })
6298
+ ]
6299
+ }
6300
+ ) });
6301
+ };
6302
+ DateCalendarValueInput.displayName = "DateCalendarValueInput";
6303
+ var PresetTagsValueInput = ({
6304
+ value,
6305
+ onChange,
6306
+ onSubmit,
6307
+ className
6308
+ }) => /* @__PURE__ */ jsx45("div", { className: cn("flex flex-col gap-base p-base max-w-[280px]", className), children: RELATIVE_DATE_PRESETS.map((group) => /* @__PURE__ */ jsxs40("div", { className: "flex flex-col gap-xs", children: [
6309
+ /* @__PURE__ */ jsx45("span", { className: "text-xs font-semibold leading-xs text-[var(--color-muted-foreground)] uppercase px-xs", children: group.group }),
6310
+ /* @__PURE__ */ jsx45("div", { className: "flex flex-wrap gap-xs", children: group.options.map((preset) => /* @__PURE__ */ jsx45(
6311
+ "button",
6312
+ {
6313
+ type: "button",
6314
+ onClick: () => {
6315
+ onChange(preset);
6316
+ onSubmit?.();
6317
+ },
6318
+ className: cn(
6319
+ "px-base py-2xs rounded-base border cursor-pointer transition-colors text-sm font-regular leading-sm",
6320
+ value === preset ? "border-[var(--color-ring)] bg-[var(--color-primary)] text-[var(--color-primary-foreground)]" : "border-[var(--color-input)] bg-[var(--color-background)] text-[var(--color-foreground)] hover:bg-[var(--color-accent)]"
6321
+ ),
6322
+ children: preset
6323
+ },
6324
+ preset
6325
+ )) })
6326
+ ] }, group.group)) });
6327
+ PresetTagsValueInput.displayName = "PresetTagsValueInput";
6328
+
6329
+ // src/components/ui/filter/value-inputs/select-value-input.tsx
6330
+ import { Icon as Icon27 } from "@l3mpire/icons";
6331
+ import { jsx as jsx46, jsxs as jsxs41 } from "react/jsx-runtime";
6332
+ var DynamicOptionRow = ({
6333
+ option,
6334
+ selected,
6335
+ multi,
6336
+ onClick
6337
+ }) => /* @__PURE__ */ jsxs41(
6338
+ "button",
6339
+ {
6340
+ type: "button",
6341
+ onClick,
6342
+ className: cn(
6343
+ "flex items-start gap-base p-base rounded-base cursor-pointer transition-colors text-left",
6344
+ "hover:bg-[var(--color-dropdown-item-hover)]",
6345
+ selected && "bg-[var(--color-dropdown-item-hover)]"
6346
+ ),
6347
+ children: [
6348
+ multi && /* @__PURE__ */ jsx46(
6349
+ "span",
6350
+ {
6351
+ className: cn(
6352
+ "mt-[2px] flex items-center justify-center size-4 rounded-xs border transition-colors shrink-0",
6353
+ selected ? "bg-[var(--color-primary)] border-[var(--color-primary)]" : "border-[var(--color-input)] bg-[var(--color-background)]"
6354
+ ),
6355
+ children: selected && /* @__PURE__ */ jsx46("svg", { width: "10", height: "10", viewBox: "0 0 10 10", fill: "none", children: /* @__PURE__ */ jsx46(
6356
+ "path",
6357
+ {
6358
+ d: "M2 5L4 7L8 3",
6359
+ stroke: "white",
6360
+ strokeWidth: "1.5",
6361
+ strokeLinecap: "round",
6362
+ strokeLinejoin: "round"
6363
+ }
6364
+ ) })
6365
+ }
6366
+ ),
6367
+ option.icon && /* @__PURE__ */ jsx46(
6368
+ Icon27,
6369
+ {
6370
+ icon: option.icon,
6371
+ size: "sm",
6372
+ className: "shrink-0 mt-[1px] text-[var(--color-interactive-text-primary-dark-default,var(--color-primary))]"
6373
+ }
6374
+ ),
6375
+ /* @__PURE__ */ jsxs41("span", { className: "flex-1 flex flex-col gap-2xs min-w-0", children: [
6376
+ /* @__PURE__ */ jsx46("span", { className: "text-sm font-regular leading-sm text-[var(--color-foreground)] truncate", children: option.label }),
6377
+ option.description && /* @__PURE__ */ jsx46("span", { className: "text-xs font-regular leading-xs text-[var(--color-muted-foreground)]", children: option.description })
6378
+ ] })
6379
+ ]
6380
+ }
6381
+ );
6382
+ var DynamicOptionsDivider = () => /* @__PURE__ */ jsx46("div", { className: "h-px bg-[var(--color-dropdown-border)] mx-xs my-xs" });
6383
+ var SingleSelectValueInput = ({
6384
+ value,
6385
+ onChange,
6386
+ onSubmit,
6387
+ options,
6388
+ dynamicOptions,
6389
+ className
6390
+ }) => {
6391
+ const pick = (v) => {
6392
+ onChange(v);
6393
+ onSubmit?.();
6394
+ };
6395
+ return /* @__PURE__ */ jsxs41(
6396
+ "div",
6397
+ {
6398
+ className: cn(
6399
+ "flex flex-col gap-xs p-base max-h-[280px] overflow-y-auto",
6400
+ className
6401
+ ),
6402
+ children: [
6403
+ dynamicOptions?.map((opt) => /* @__PURE__ */ jsx46(
6404
+ DynamicOptionRow,
6405
+ {
6406
+ option: opt,
6407
+ selected: value === opt.value,
6408
+ multi: false,
6409
+ onClick: () => pick(opt.value)
6410
+ },
6411
+ opt.value
6412
+ )),
6413
+ dynamicOptions && dynamicOptions.length > 0 && options.length > 0 && /* @__PURE__ */ jsx46(DynamicOptionsDivider, {}),
6414
+ options.map((opt) => /* @__PURE__ */ jsx46(
6415
+ "button",
6416
+ {
6417
+ type: "button",
6418
+ onClick: () => pick(opt),
6419
+ className: cn(
6420
+ "flex items-center gap-base p-base rounded-base cursor-pointer transition-colors text-left",
6421
+ "hover:bg-[var(--color-dropdown-item-hover)]",
6422
+ value === opt && "bg-[var(--color-dropdown-item-hover)]"
6423
+ ),
6424
+ children: /* @__PURE__ */ jsx46("span", { className: "text-sm font-regular leading-sm text-[var(--color-foreground)]", children: opt })
6425
+ },
6426
+ opt
6427
+ ))
6428
+ ]
6429
+ }
6430
+ );
6431
+ };
6432
+ SingleSelectValueInput.displayName = "SingleSelectValueInput";
6433
+ var MultiSelectValueInput = ({
6434
+ value,
6435
+ onChange,
6436
+ onSubmit,
6437
+ options,
6438
+ dynamicOptions,
6439
+ className
6440
+ }) => {
6441
+ const selected = Array.isArray(value) ? value : [];
6442
+ const toggle = (v) => {
6443
+ const next = selected.includes(v) ? selected.filter((s) => s !== v) : [...selected, v];
6444
+ onChange(next);
6445
+ };
6446
+ return /* @__PURE__ */ jsxs41("div", { className: cn("flex flex-col gap-xs p-base", className), children: [
6447
+ /* @__PURE__ */ jsxs41("div", { className: "flex flex-col max-h-[240px] overflow-y-auto", children: [
6448
+ dynamicOptions?.map((opt) => /* @__PURE__ */ jsx46(
6449
+ DynamicOptionRow,
6450
+ {
6451
+ option: opt,
6452
+ selected: selected.includes(opt.value),
6453
+ multi: true,
6454
+ onClick: () => toggle(opt.value)
6455
+ },
6456
+ opt.value
6457
+ )),
6458
+ dynamicOptions && dynamicOptions.length > 0 && options.length > 0 && /* @__PURE__ */ jsx46(DynamicOptionsDivider, {}),
6459
+ options.map((opt) => {
6460
+ const isSelected = selected.includes(opt);
6461
+ return /* @__PURE__ */ jsxs41(
6462
+ "button",
6463
+ {
6464
+ type: "button",
6465
+ onClick: () => toggle(opt),
6466
+ className: cn(
6467
+ "flex items-center gap-base p-base rounded-base cursor-pointer transition-colors text-left",
6468
+ "hover:bg-[var(--color-dropdown-item-hover)]"
6469
+ ),
6470
+ children: [
6471
+ /* @__PURE__ */ jsx46(
6472
+ "span",
6473
+ {
6474
+ className: cn(
6475
+ "flex items-center justify-center size-4 rounded-xs border transition-colors",
6476
+ isSelected ? "bg-[var(--color-primary)] border-[var(--color-primary)]" : "border-[var(--color-input)] bg-[var(--color-background)]"
6477
+ ),
6478
+ children: isSelected && /* @__PURE__ */ jsx46("svg", { width: "10", height: "10", viewBox: "0 0 10 10", fill: "none", children: /* @__PURE__ */ jsx46(
6479
+ "path",
6480
+ {
6481
+ d: "M2 5L4 7L8 3",
6482
+ stroke: "white",
6483
+ strokeWidth: "1.5",
6484
+ strokeLinecap: "round",
6485
+ strokeLinejoin: "round"
6486
+ }
6487
+ ) })
6488
+ }
6489
+ ),
6490
+ /* @__PURE__ */ jsx46("span", { className: "text-sm font-regular leading-sm text-[var(--color-foreground)]", children: opt })
6491
+ ]
6492
+ },
6493
+ opt
6494
+ );
6495
+ })
6496
+ ] }),
6497
+ /* @__PURE__ */ jsx46("button", { type: "button", onClick: onSubmit, className: applyBtnClasses, children: "Apply" })
6498
+ ] });
6499
+ };
6500
+ MultiSelectValueInput.displayName = "MultiSelectValueInput";
6501
+
6502
+ // src/components/ui/filter/value-inputs/relation-value-input.tsx
6503
+ import { jsx as jsx47, jsxs as jsxs42 } from "react/jsx-runtime";
6504
+ var RelationValueInput = ({
6505
+ value,
6506
+ onChange,
6507
+ onSubmit,
6508
+ className
6509
+ }) => {
6510
+ const handleKeyDown = (e) => {
6511
+ if (e.key === "Enter") onSubmit?.();
6512
+ };
6513
+ return /* @__PURE__ */ jsxs42("div", { className: cn("flex flex-col gap-base p-base", className), children: [
6514
+ /* @__PURE__ */ jsx47(
6515
+ "input",
6516
+ {
6517
+ type: "text",
6518
+ value: value ?? "",
6519
+ onChange: (e) => onChange(e.target.value),
6520
+ onKeyDown: handleKeyDown,
6521
+ placeholder: "Search...",
6522
+ autoFocus: true,
6523
+ className: inputClasses
6524
+ }
6525
+ ),
6526
+ /* @__PURE__ */ jsx47("button", { type: "button", onClick: onSubmit, className: applyBtnClasses, children: "Apply" })
6527
+ ] });
6528
+ };
6529
+ RelationValueInput.displayName = "RelationValueInput";
6530
+
6531
+ // src/components/ui/filter/value-input.tsx
6532
+ import { jsx as jsx48 } from "react/jsx-runtime";
6533
+ var ValueInput = ({
6534
+ dataType,
6535
+ operator,
6536
+ value,
6537
+ onChange,
6538
+ onSubmit,
6539
+ options = [],
6540
+ dynamicOptions,
6541
+ className
6542
+ }) => {
6543
+ const inputType = getValueInputType(dataType, operator);
6544
+ if (!inputType) return null;
6545
+ switch (inputType) {
6546
+ case "TextInput":
6547
+ return /* @__PURE__ */ jsx48(TextValueInput, { value, onChange, onSubmit, className });
6548
+ case "NumberInput":
6549
+ return /* @__PURE__ */ jsx48(NumberValueInput, { value, onChange, onSubmit, className });
6550
+ case "NumberRange":
6551
+ return /* @__PURE__ */ jsx48(NumberRangeValueInput, { value, onChange, onSubmit, className });
6552
+ case "SingleSelect":
6553
+ return /* @__PURE__ */ jsx48(
6554
+ SingleSelectValueInput,
6555
+ {
6556
+ value,
6557
+ onChange,
6558
+ onSubmit,
6559
+ options,
6560
+ dynamicOptions,
6561
+ className
6562
+ }
6563
+ );
6564
+ case "MultiSelect":
6565
+ return /* @__PURE__ */ jsx48(
6566
+ MultiSelectValueInput,
6567
+ {
6568
+ value,
6569
+ onChange,
6570
+ onSubmit,
6571
+ options,
6572
+ dynamicOptions,
6573
+ className
6574
+ }
6575
+ );
6576
+ case "DatePicker":
6577
+ case "DateRange":
6578
+ return /* @__PURE__ */ jsx48(
6579
+ DateCalendarValueInput,
6580
+ {
6581
+ operator,
6582
+ value,
6583
+ onChange,
6584
+ onSubmit,
6585
+ className
6586
+ }
6587
+ );
6588
+ case "RelationPicker":
6589
+ case "MultiRelationPicker":
6590
+ return /* @__PURE__ */ jsx48(RelationValueInput, { value, onChange, onSubmit, className });
6591
+ default:
6592
+ return null;
6593
+ }
6594
+ };
6595
+ ValueInput.displayName = "ValueInput";
6596
+
6597
+ // src/components/ui/filter/property-selector.tsx
6598
+ import * as React43 from "react";
6599
+ import * as PopoverPrimitive6 from "@radix-ui/react-popover";
6600
+ import {
6601
+ Icon as Icon28,
6602
+ faChevronLeftOutline as faChevronLeftOutline3,
6603
+ faChevronRightOutline as faChevronRightOutline3,
6604
+ faMagnifyingGlassOutline,
6605
+ faFilterOutline as faFilterOutline2
6606
+ } from "@l3mpire/icons";
6607
+ import { Fragment as Fragment4, jsx as jsx49, jsxs as jsxs43 } from "react/jsx-runtime";
6608
+ var AdvancedFilterFooter = ({ onClick, count }) => /* @__PURE__ */ jsxs43(Fragment4, { children: [
6609
+ /* @__PURE__ */ jsx49("div", { className: "h-px bg-[var(--color-dropdown-border)] mx-xs" }),
6610
+ /* @__PURE__ */ jsxs43(
6611
+ "button",
6612
+ {
6613
+ type: "button",
6614
+ onPointerDown: (e) => e.preventDefault(),
6615
+ onClick,
6616
+ className: "flex items-center gap-base p-base rounded-base cursor-pointer transition-colors hover:bg-[var(--color-dropdown-item-hover)]",
6617
+ children: [
6618
+ /* @__PURE__ */ jsx49(
6619
+ Icon28,
6620
+ {
6621
+ icon: faFilterOutline2,
6622
+ size: "sm",
6623
+ className: "shrink-0 text-[var(--color-dropdown-item-icon)]"
6624
+ }
6625
+ ),
6626
+ /* @__PURE__ */ jsx49("span", { className: "flex-1 text-sm font-regular leading-sm text-[var(--color-dropdown-item-text)] text-left truncate", children: "Advanced filter" }),
6627
+ count > 0 && /* @__PURE__ */ jsxs43("span", { className: "text-xs font-regular leading-xs text-[var(--color-muted-foreground)]", children: [
6628
+ count,
6629
+ " ",
6630
+ count === 1 ? "rule" : "rules"
6631
+ ] })
6632
+ ]
6633
+ }
6634
+ )
6635
+ ] });
6636
+ var PropertySelector = ({
6637
+ properties,
6638
+ onSelect,
6639
+ open,
6640
+ onOpenChange,
6641
+ children,
6642
+ onAdvancedFilter,
6643
+ advancedFilterCount = 0
6644
+ }) => {
6645
+ const handleAdvancedClick = (e) => {
6646
+ e.stopPropagation();
6647
+ e.preventDefault();
6648
+ onAdvancedFilter?.();
6649
+ };
6650
+ const showAdvancedFooter = !!onAdvancedFilter;
6651
+ const [activeGroup, setActiveGroup] = React43.useState(null);
6652
+ const [search, setSearch] = React43.useState("");
6653
+ React43.useEffect(() => {
5912
6654
  if (!open) {
5913
6655
  setActiveGroup(null);
5914
6656
  setSearch("");
5915
6657
  }
5916
6658
  }, [open]);
5917
- const groups = React41.useMemo(() => {
6659
+ const groups = React43.useMemo(() => {
5918
6660
  const map = /* @__PURE__ */ new Map();
5919
6661
  for (const prop of properties) {
5920
6662
  const existing = map.get(prop.group);
@@ -5931,12 +6673,12 @@ var PropertySelector = ({
5931
6673
  }
5932
6674
  return Array.from(map.values());
5933
6675
  }, [properties]);
5934
- const globalSearchResults = React41.useMemo(() => {
6676
+ const globalSearchResults = React43.useMemo(() => {
5935
6677
  if (!search || activeGroup) return [];
5936
6678
  const lower = search.toLowerCase();
5937
6679
  return properties.filter((p) => p.label.toLowerCase().includes(lower));
5938
6680
  }, [properties, search, activeGroup]);
5939
- const filteredGroups = React41.useMemo(() => {
6681
+ const filteredGroups = React43.useMemo(() => {
5940
6682
  if (!search || activeGroup) return groups;
5941
6683
  const lower = search.toLowerCase();
5942
6684
  return groups.filter(
@@ -5945,7 +6687,7 @@ var PropertySelector = ({
5945
6687
  )
5946
6688
  );
5947
6689
  }, [groups, properties, search, activeGroup]);
5948
- const filteredProperties = React41.useMemo(() => {
6690
+ const filteredProperties = React43.useMemo(() => {
5949
6691
  if (!activeGroup) return [];
5950
6692
  const groupProps = properties.filter((p) => p.group === activeGroup);
5951
6693
  if (!search) return groupProps;
@@ -5954,10 +6696,10 @@ var PropertySelector = ({
5954
6696
  }, [properties, activeGroup, search]);
5955
6697
  const activeGroupInfo = groups.find((g) => g.group === activeGroup);
5956
6698
  const showGlobalResults = search.length > 0 && !activeGroup && globalSearchResults.length > 0;
5957
- return /* @__PURE__ */ jsxs42(PopoverPrimitive5.Root, { open, onOpenChange, children: [
5958
- /* @__PURE__ */ jsx48(PopoverPrimitive5.Trigger, { asChild: true, children }),
5959
- /* @__PURE__ */ jsx48(PopoverPrimitive5.Portal, { children: /* @__PURE__ */ jsxs42(
5960
- PopoverPrimitive5.Content,
6699
+ return /* @__PURE__ */ jsxs43(PopoverPrimitive6.Root, { open, onOpenChange, children: [
6700
+ /* @__PURE__ */ jsx49(PopoverPrimitive6.Trigger, { asChild: true, children }),
6701
+ /* @__PURE__ */ jsx49(PopoverPrimitive6.Portal, { children: /* @__PURE__ */ jsxs43(
6702
+ PopoverPrimitive6.Content,
5961
6703
  {
5962
6704
  sideOffset: 4,
5963
6705
  align: "start",
@@ -5973,17 +6715,17 @@ var PropertySelector = ({
5973
6715
  children: [
5974
6716
  activeGroup === null ? (
5975
6717
  /* ── Level 1: Search + Categories ───────────────────────── */
5976
- /* @__PURE__ */ jsxs42("div", { className: "flex flex-col gap-xs", children: [
5977
- /* @__PURE__ */ jsxs42("div", { className: "flex items-center gap-base px-md py-base border border-[var(--color-input)] rounded-md", children: [
5978
- /* @__PURE__ */ jsx48(
5979
- Icon26,
6718
+ /* @__PURE__ */ jsxs43("div", { className: "flex flex-col gap-xs", children: [
6719
+ /* @__PURE__ */ jsxs43("div", { className: "flex items-center gap-base px-md py-base border border-[var(--color-input)] rounded-md", children: [
6720
+ /* @__PURE__ */ jsx49(
6721
+ Icon28,
5980
6722
  {
5981
6723
  icon: faMagnifyingGlassOutline,
5982
6724
  size: "sm",
5983
6725
  className: "shrink-0 text-[var(--color-muted-foreground)]"
5984
6726
  }
5985
6727
  ),
5986
- /* @__PURE__ */ jsx48(
6728
+ /* @__PURE__ */ jsx49(
5987
6729
  "input",
5988
6730
  {
5989
6731
  type: "text",
@@ -5997,7 +6739,7 @@ var PropertySelector = ({
5997
6739
  ] }),
5998
6740
  showGlobalResults ? (
5999
6741
  /* ── Global search results (flat property list) ─────── */
6000
- /* @__PURE__ */ jsx48("div", { className: "flex flex-col max-h-[300px] overflow-y-auto", children: globalSearchResults.map((prop) => /* @__PURE__ */ jsxs42(
6742
+ /* @__PURE__ */ jsx49("div", { className: "flex flex-col max-h-[300px] overflow-y-auto", children: globalSearchResults.map((prop) => /* @__PURE__ */ jsxs43(
6001
6743
  "button",
6002
6744
  {
6003
6745
  type: "button",
@@ -6007,24 +6749,24 @@ var PropertySelector = ({
6007
6749
  },
6008
6750
  className: "flex items-center gap-base p-base rounded-base cursor-pointer transition-colors hover:bg-[var(--color-dropdown-item-hover)]",
6009
6751
  children: [
6010
- /* @__PURE__ */ jsx48(
6011
- Icon26,
6752
+ /* @__PURE__ */ jsx49(
6753
+ Icon28,
6012
6754
  {
6013
6755
  icon: prop.icon,
6014
6756
  size: "sm",
6015
6757
  className: "shrink-0 text-[var(--color-dropdown-item-icon)]"
6016
6758
  }
6017
6759
  ),
6018
- /* @__PURE__ */ jsx48("span", { className: "flex-1 text-sm font-regular leading-sm text-[var(--color-dropdown-item-text)] text-left truncate", children: prop.label }),
6019
- /* @__PURE__ */ jsx48("span", { className: "text-xs font-regular leading-xs text-[var(--color-muted-foreground)]", children: prop.groupLabel })
6760
+ /* @__PURE__ */ jsx49("span", { className: "flex-1 text-sm font-regular leading-sm text-[var(--color-dropdown-item-text)] text-left truncate", children: prop.label }),
6761
+ /* @__PURE__ */ jsx49("span", { className: "text-xs font-regular leading-xs text-[var(--color-muted-foreground)]", children: prop.groupLabel })
6020
6762
  ]
6021
6763
  },
6022
6764
  prop.id
6023
6765
  )) })
6024
6766
  ) : (
6025
6767
  /* ── Group list ─────────────────────────────────────── */
6026
- /* @__PURE__ */ jsxs42("div", { className: "flex flex-col", children: [
6027
- filteredGroups.map((g) => /* @__PURE__ */ jsxs42(
6768
+ /* @__PURE__ */ jsxs43("div", { className: "flex flex-col", children: [
6769
+ filteredGroups.map((g) => /* @__PURE__ */ jsxs43(
6028
6770
  "button",
6029
6771
  {
6030
6772
  type: "button",
@@ -6034,20 +6776,20 @@ var PropertySelector = ({
6034
6776
  },
6035
6777
  className: "flex items-center gap-base p-base rounded-base cursor-pointer transition-colors hover:bg-[var(--color-dropdown-item-hover)]",
6036
6778
  children: [
6037
- /* @__PURE__ */ jsx48(
6038
- Icon26,
6779
+ /* @__PURE__ */ jsx49(
6780
+ Icon28,
6039
6781
  {
6040
6782
  icon: g.groupIcon,
6041
6783
  size: "sm",
6042
6784
  className: "shrink-0 text-[var(--color-dropdown-item-icon)]"
6043
6785
  }
6044
6786
  ),
6045
- /* @__PURE__ */ jsx48("span", { className: "flex-1 text-sm font-regular leading-sm text-[var(--color-dropdown-item-text)] text-left truncate", children: g.groupLabel }),
6046
- /* @__PURE__ */ jsx48("span", { className: "text-xs font-semibold leading-xs text-[var(--color-muted-foreground)]", children: g.count }),
6047
- /* @__PURE__ */ jsx48(
6048
- Icon26,
6787
+ /* @__PURE__ */ jsx49("span", { className: "flex-1 text-sm font-regular leading-sm text-[var(--color-dropdown-item-text)] text-left truncate", children: g.groupLabel }),
6788
+ /* @__PURE__ */ jsx49("span", { className: "text-xs font-semibold leading-xs text-[var(--color-muted-foreground)]", children: g.count }),
6789
+ /* @__PURE__ */ jsx49(
6790
+ Icon28,
6049
6791
  {
6050
- icon: faChevronRightOutline2,
6792
+ icon: faChevronRightOutline3,
6051
6793
  size: "xs",
6052
6794
  className: "shrink-0 text-[var(--color-dropdown-item-icon)]"
6053
6795
  }
@@ -6056,14 +6798,14 @@ var PropertySelector = ({
6056
6798
  },
6057
6799
  g.group
6058
6800
  )),
6059
- filteredGroups.length === 0 && /* @__PURE__ */ jsx48("span", { className: "p-base text-sm text-[var(--color-muted-foreground)]", children: "No results" })
6801
+ filteredGroups.length === 0 && /* @__PURE__ */ jsx49("span", { className: "p-base text-sm text-[var(--color-muted-foreground)]", children: "No results" })
6060
6802
  ] })
6061
6803
  )
6062
6804
  ] })
6063
6805
  ) : (
6064
6806
  /* ── Level 2: Properties ─────────────────────────────────── */
6065
- /* @__PURE__ */ jsxs42("div", { className: "flex flex-col gap-xs", children: [
6066
- /* @__PURE__ */ jsxs42(
6807
+ /* @__PURE__ */ jsxs43("div", { className: "flex flex-col gap-xs", children: [
6808
+ /* @__PURE__ */ jsxs43(
6067
6809
  "button",
6068
6810
  {
6069
6811
  type: "button",
@@ -6073,28 +6815,28 @@ var PropertySelector = ({
6073
6815
  },
6074
6816
  className: "flex items-center gap-base p-base rounded-base cursor-pointer transition-colors hover:bg-[var(--color-dropdown-item-hover)]",
6075
6817
  children: [
6076
- /* @__PURE__ */ jsx48(
6077
- Icon26,
6818
+ /* @__PURE__ */ jsx49(
6819
+ Icon28,
6078
6820
  {
6079
- icon: faChevronLeftOutline2,
6821
+ icon: faChevronLeftOutline3,
6080
6822
  size: "sm",
6081
6823
  className: "shrink-0 text-[var(--color-dropdown-item-icon)]"
6082
6824
  }
6083
6825
  ),
6084
- /* @__PURE__ */ jsx48("span", { className: "flex-1 text-xs font-semibold leading-xs text-[var(--color-muted-foreground)] text-left truncate", children: activeGroupInfo?.groupLabel })
6826
+ /* @__PURE__ */ jsx49("span", { className: "flex-1 text-xs font-semibold leading-xs text-[var(--color-muted-foreground)] text-left truncate", children: activeGroupInfo?.groupLabel })
6085
6827
  ]
6086
6828
  }
6087
6829
  ),
6088
- /* @__PURE__ */ jsxs42("div", { className: "flex items-center gap-base px-md py-base border border-[var(--color-input)] rounded-md", children: [
6089
- /* @__PURE__ */ jsx48(
6090
- Icon26,
6830
+ /* @__PURE__ */ jsxs43("div", { className: "flex items-center gap-base px-md py-base border border-[var(--color-input)] rounded-md", children: [
6831
+ /* @__PURE__ */ jsx49(
6832
+ Icon28,
6091
6833
  {
6092
6834
  icon: faMagnifyingGlassOutline,
6093
6835
  size: "sm",
6094
6836
  className: "shrink-0 text-[var(--color-muted-foreground)]"
6095
6837
  }
6096
6838
  ),
6097
- /* @__PURE__ */ jsx48(
6839
+ /* @__PURE__ */ jsx49(
6098
6840
  "input",
6099
6841
  {
6100
6842
  type: "text",
@@ -6106,8 +6848,8 @@ var PropertySelector = ({
6106
6848
  }
6107
6849
  )
6108
6850
  ] }),
6109
- /* @__PURE__ */ jsxs42("div", { className: "flex flex-col max-h-[300px] overflow-y-auto", children: [
6110
- filteredProperties.map((prop) => /* @__PURE__ */ jsxs42(
6851
+ /* @__PURE__ */ jsxs43("div", { className: "flex flex-col max-h-[300px] overflow-y-auto", children: [
6852
+ filteredProperties.map((prop) => /* @__PURE__ */ jsxs43(
6111
6853
  "button",
6112
6854
  {
6113
6855
  type: "button",
@@ -6117,24 +6859,24 @@ var PropertySelector = ({
6117
6859
  },
6118
6860
  className: "flex items-center gap-base p-base rounded-base cursor-pointer transition-colors hover:bg-[var(--color-dropdown-item-hover)]",
6119
6861
  children: [
6120
- /* @__PURE__ */ jsx48(
6121
- Icon26,
6862
+ /* @__PURE__ */ jsx49(
6863
+ Icon28,
6122
6864
  {
6123
6865
  icon: prop.icon,
6124
6866
  size: "sm",
6125
6867
  className: "shrink-0 text-[var(--color-dropdown-item-icon)]"
6126
6868
  }
6127
6869
  ),
6128
- /* @__PURE__ */ jsx48("span", { className: "flex-1 text-sm font-regular leading-sm text-[var(--color-dropdown-item-text)] text-left truncate", children: prop.label })
6870
+ /* @__PURE__ */ jsx49("span", { className: "flex-1 text-sm font-regular leading-sm text-[var(--color-dropdown-item-text)] text-left truncate", children: prop.label })
6129
6871
  ]
6130
6872
  },
6131
6873
  prop.id
6132
6874
  )),
6133
- filteredProperties.length === 0 && /* @__PURE__ */ jsx48("span", { className: "p-base text-sm text-[var(--color-muted-foreground)]", children: "No results" })
6875
+ filteredProperties.length === 0 && /* @__PURE__ */ jsx49("span", { className: "p-base text-sm text-[var(--color-muted-foreground)]", children: "No results" })
6134
6876
  ] })
6135
6877
  ] })
6136
6878
  ),
6137
- showAdvancedFooter && /* @__PURE__ */ jsx48(
6879
+ showAdvancedFooter && /* @__PURE__ */ jsx49(
6138
6880
  AdvancedFilterFooter,
6139
6881
  {
6140
6882
  onClick: handleAdvancedClick,
@@ -6149,19 +6891,19 @@ var PropertySelector = ({
6149
6891
  PropertySelector.displayName = "PropertySelector";
6150
6892
 
6151
6893
  // src/components/ui/filter/kebab-menu.tsx
6152
- import * as PopoverPrimitive6 from "@radix-ui/react-popover";
6153
- import { Icon as Icon27, faArrowRightOutline, faTrashOutline } from "@l3mpire/icons";
6154
- import { jsx as jsx49, jsxs as jsxs43 } from "react/jsx-runtime";
6894
+ import * as PopoverPrimitive7 from "@radix-ui/react-popover";
6895
+ import { Icon as Icon29, faArrowRightOutline as faArrowRightOutline2, faTrashOutline } from "@l3mpire/icons";
6896
+ import { jsx as jsx50, jsxs as jsxs44 } from "react/jsx-runtime";
6155
6897
  var KebabMenu = ({
6156
6898
  onConvertToAdvanced,
6157
6899
  onDelete,
6158
6900
  open,
6159
6901
  onOpenChange,
6160
6902
  children
6161
- }) => /* @__PURE__ */ jsxs43(PopoverPrimitive6.Root, { open, onOpenChange, children: [
6162
- /* @__PURE__ */ jsx49(PopoverPrimitive6.Trigger, { asChild: true, children }),
6163
- /* @__PURE__ */ jsx49(PopoverPrimitive6.Portal, { children: /* @__PURE__ */ jsxs43(
6164
- PopoverPrimitive6.Content,
6903
+ }) => /* @__PURE__ */ jsxs44(PopoverPrimitive7.Root, { open, onOpenChange, children: [
6904
+ /* @__PURE__ */ jsx50(PopoverPrimitive7.Trigger, { asChild: true, children }),
6905
+ /* @__PURE__ */ jsx50(PopoverPrimitive7.Portal, { children: /* @__PURE__ */ jsxs44(
6906
+ PopoverPrimitive7.Content,
6165
6907
  {
6166
6908
  sideOffset: 4,
6167
6909
  align: "end",
@@ -6174,7 +6916,7 @@ var KebabMenu = ({
6174
6916
  "min-w-[210px]"
6175
6917
  ),
6176
6918
  children: [
6177
- onConvertToAdvanced && /* @__PURE__ */ jsxs43(
6919
+ onConvertToAdvanced && /* @__PURE__ */ jsxs44(
6178
6920
  "button",
6179
6921
  {
6180
6922
  type: "button",
@@ -6184,20 +6926,20 @@ var KebabMenu = ({
6184
6926
  },
6185
6927
  className: "flex items-center gap-base p-base rounded-base cursor-pointer transition-colors hover:bg-[var(--color-dropdown-item-hover)]",
6186
6928
  children: [
6187
- /* @__PURE__ */ jsx49(
6188
- Icon27,
6929
+ /* @__PURE__ */ jsx50(
6930
+ Icon29,
6189
6931
  {
6190
- icon: faArrowRightOutline,
6932
+ icon: faArrowRightOutline2,
6191
6933
  size: "sm",
6192
6934
  className: "shrink-0 text-[var(--color-dropdown-item-icon)]"
6193
6935
  }
6194
6936
  ),
6195
- /* @__PURE__ */ jsx49("span", { className: "text-sm font-regular leading-sm text-[var(--color-dropdown-item-text)]", children: "Convert to advanced" })
6937
+ /* @__PURE__ */ jsx50("span", { className: "text-sm font-regular leading-sm text-[var(--color-dropdown-item-text)]", children: "Convert to advanced" })
6196
6938
  ]
6197
6939
  }
6198
6940
  ),
6199
- onConvertToAdvanced && onDelete && /* @__PURE__ */ jsx49("div", { className: "h-px mx-base my-xs bg-[var(--color-border)]" }),
6200
- onDelete && /* @__PURE__ */ jsxs43(
6941
+ onConvertToAdvanced && onDelete && /* @__PURE__ */ jsx50("div", { className: "h-px mx-base my-xs bg-[var(--color-border)]" }),
6942
+ onDelete && /* @__PURE__ */ jsxs44(
6201
6943
  "button",
6202
6944
  {
6203
6945
  type: "button",
@@ -6207,15 +6949,15 @@ var KebabMenu = ({
6207
6949
  },
6208
6950
  className: "flex items-center gap-base p-base rounded-base cursor-pointer transition-colors hover:bg-[var(--color-dropdown-item-hover)]",
6209
6951
  children: [
6210
- /* @__PURE__ */ jsx49(
6211
- Icon27,
6952
+ /* @__PURE__ */ jsx50(
6953
+ Icon29,
6212
6954
  {
6213
6955
  icon: faTrashOutline,
6214
6956
  size: "sm",
6215
6957
  className: "shrink-0 text-[var(--color-destructive)]"
6216
6958
  }
6217
6959
  ),
6218
- /* @__PURE__ */ jsx49("span", { className: "text-sm font-regular leading-sm text-[var(--color-destructive)]", children: "Delete filter" })
6960
+ /* @__PURE__ */ jsx50("span", { className: "text-sm font-regular leading-sm text-[var(--color-destructive)]", children: "Delete filter" })
6219
6961
  ]
6220
6962
  }
6221
6963
  )
@@ -6226,10 +6968,10 @@ var KebabMenu = ({
6226
6968
  KebabMenu.displayName = "KebabMenu";
6227
6969
 
6228
6970
  // src/components/ui/filter/filter-editor.tsx
6229
- import * as React42 from "react";
6230
- import * as PopoverPrimitive7 from "@radix-ui/react-popover";
6231
- import { Icon as Icon28 } from "@l3mpire/icons";
6232
- import { jsx as jsx50, jsxs as jsxs44 } from "react/jsx-runtime";
6971
+ import * as React44 from "react";
6972
+ import * as PopoverPrimitive8 from "@radix-ui/react-popover";
6973
+ import { Icon as Icon30 } from "@l3mpire/icons";
6974
+ import { jsx as jsx51, jsxs as jsxs45 } from "react/jsx-runtime";
6233
6975
  var FilterEditor = ({
6234
6976
  propertyDef,
6235
6977
  condition,
@@ -6240,16 +6982,16 @@ var FilterEditor = ({
6240
6982
  onOpenChange,
6241
6983
  children
6242
6984
  }) => {
6243
- const [view, setView] = React42.useState(
6985
+ const [view, setView] = React44.useState(
6244
6986
  mode === "add" ? "value" : "operator"
6245
6987
  );
6246
- const [localOperator, setLocalOperator] = React42.useState(
6988
+ const [localOperator, setLocalOperator] = React44.useState(
6247
6989
  condition.operator
6248
6990
  );
6249
- const [localValue, setLocalValue] = React42.useState(
6991
+ const [localValue, setLocalValue] = React44.useState(
6250
6992
  condition.value
6251
6993
  );
6252
- React42.useEffect(() => {
6994
+ React44.useEffect(() => {
6253
6995
  if (open) {
6254
6996
  setView(mode === "add" ? "value" : "operator");
6255
6997
  setLocalOperator(condition.operator);
@@ -6274,10 +7016,10 @@ var FilterEditor = ({
6274
7016
  onOpenChange?.(false);
6275
7017
  onClose();
6276
7018
  };
6277
- return /* @__PURE__ */ jsxs44(PopoverPrimitive7.Root, { open, onOpenChange, children: [
6278
- /* @__PURE__ */ jsx50(PopoverPrimitive7.Trigger, { asChild: true, children }),
6279
- /* @__PURE__ */ jsx50(PopoverPrimitive7.Portal, { children: /* @__PURE__ */ jsxs44(
6280
- PopoverPrimitive7.Content,
7019
+ return /* @__PURE__ */ jsxs45(PopoverPrimitive8.Root, { open, onOpenChange, children: [
7020
+ /* @__PURE__ */ jsx51(PopoverPrimitive8.Trigger, { asChild: true, children }),
7021
+ /* @__PURE__ */ jsx51(PopoverPrimitive8.Portal, { children: /* @__PURE__ */ jsxs45(
7022
+ PopoverPrimitive8.Content,
6281
7023
  {
6282
7024
  sideOffset: 4,
6283
7025
  align: "start",
@@ -6290,17 +7032,17 @@ var FilterEditor = ({
6290
7032
  "min-w-[240px]"
6291
7033
  ),
6292
7034
  children: [
6293
- /* @__PURE__ */ jsxs44("div", { className: "flex items-center gap-base px-base pt-base pb-xs border-b border-[var(--color-border)]", children: [
6294
- /* @__PURE__ */ jsx50(
6295
- Icon28,
7035
+ /* @__PURE__ */ jsxs45("div", { className: "flex items-center gap-base px-base pt-base pb-xs border-b border-[var(--color-border)]", children: [
7036
+ /* @__PURE__ */ jsx51(
7037
+ Icon30,
6296
7038
  {
6297
7039
  icon: propertyDef.icon,
6298
7040
  size: "sm",
6299
7041
  className: "shrink-0 text-[var(--color-dropdown-item-icon)]"
6300
7042
  }
6301
7043
  ),
6302
- /* @__PURE__ */ jsx50("span", { className: "text-sm font-semibold leading-sm text-[var(--color-foreground)]", children: propertyDef.label }),
6303
- localOperator && view === "value" && /* @__PURE__ */ jsxs44(
7044
+ /* @__PURE__ */ jsx51("span", { className: "text-sm font-semibold leading-sm text-[var(--color-foreground)]", children: propertyDef.label }),
7045
+ localOperator && view === "value" && /* @__PURE__ */ jsxs45(
6304
7046
  "button",
6305
7047
  {
6306
7048
  type: "button",
@@ -6313,14 +7055,14 @@ var FilterEditor = ({
6313
7055
  }
6314
7056
  )
6315
7057
  ] }),
6316
- view === "operator" ? /* @__PURE__ */ jsx50("div", { className: "p-xs", children: /* @__PURE__ */ jsx50(
7058
+ view === "operator" ? /* @__PURE__ */ jsx51("div", { className: "p-xs", children: /* @__PURE__ */ jsx51(
6317
7059
  OperatorList,
6318
7060
  {
6319
7061
  dataType: propertyDef.type,
6320
7062
  activeOperator: localOperator,
6321
7063
  onSelect: handleOperatorSelect
6322
7064
  }
6323
- ) }) : localOperator && /* @__PURE__ */ jsx50(
7065
+ ) }) : localOperator && /* @__PURE__ */ jsx51(
6324
7066
  ValueInput,
6325
7067
  {
6326
7068
  dataType: propertyDef.type,
@@ -6328,7 +7070,8 @@ var FilterEditor = ({
6328
7070
  value: localValue,
6329
7071
  onChange: setLocalValue,
6330
7072
  onSubmit: handleSubmit,
6331
- options: propertyDef.options
7073
+ options: propertyDef.options,
7074
+ dynamicOptions: propertyDef.dynamicOptions
6332
7075
  }
6333
7076
  )
6334
7077
  ]
@@ -6339,34 +7082,9 @@ var FilterEditor = ({
6339
7082
  FilterEditor.displayName = "FilterEditor";
6340
7083
 
6341
7084
  // src/components/ui/filter/interactive-filter-chip.tsx
6342
- import * as React43 from "react";
6343
- import * as PopoverPrimitive8 from "@radix-ui/react-popover";
6344
- import { jsx as jsx51, jsxs as jsxs45 } from "react/jsx-runtime";
6345
- function formatFilterValue(value) {
6346
- if (value == null) return void 0;
6347
- if (typeof value === "boolean") return value ? "Yes" : "No";
6348
- if (value instanceof Date) {
6349
- return value.toLocaleDateString("en-US", {
6350
- month: "short",
6351
- day: "numeric",
6352
- year: "numeric"
6353
- });
6354
- }
6355
- if (Array.isArray(value)) {
6356
- if (value.length === 0) return void 0;
6357
- if (value.length === 2 && typeof value[0] === "number") {
6358
- return `${value[0]} \u2013 ${value[1]}`;
6359
- }
6360
- return value[0];
6361
- }
6362
- return String(value);
6363
- }
6364
- function getBadgeCount(value) {
6365
- if (Array.isArray(value) && value.length > 1 && typeof value[0] === "string") {
6366
- return value.length;
6367
- }
6368
- return void 0;
6369
- }
7085
+ import * as React45 from "react";
7086
+ import * as PopoverPrimitive9 from "@radix-ui/react-popover";
7087
+ import { jsx as jsx52, jsxs as jsxs46 } from "react/jsx-runtime";
6370
7088
  var SegmentPopover = ({
6371
7089
  open,
6372
7090
  onOpenChange,
@@ -6374,10 +7092,10 @@ var SegmentPopover = ({
6374
7092
  children,
6375
7093
  align = "start",
6376
7094
  minWidth = "240px"
6377
- }) => /* @__PURE__ */ jsxs45(PopoverPrimitive8.Root, { open, onOpenChange, children: [
6378
- /* @__PURE__ */ jsx51(PopoverPrimitive8.Trigger, { asChild: true, children: trigger }),
6379
- /* @__PURE__ */ jsx51(PopoverPrimitive8.Portal, { children: /* @__PURE__ */ jsx51(
6380
- PopoverPrimitive8.Content,
7095
+ }) => /* @__PURE__ */ jsxs46(PopoverPrimitive9.Root, { open, onOpenChange, children: [
7096
+ /* @__PURE__ */ jsx52(PopoverPrimitive9.Trigger, { asChild: true, children: trigger }),
7097
+ /* @__PURE__ */ jsx52(PopoverPrimitive9.Portal, { children: /* @__PURE__ */ jsx52(
7098
+ PopoverPrimitive9.Content,
6381
7099
  {
6382
7100
  sideOffset: 4,
6383
7101
  align,
@@ -6405,19 +7123,19 @@ var InteractiveFilterChip = ({
6405
7123
  onConvertToAdvanced,
6406
7124
  className
6407
7125
  }) => {
6408
- const [operatorOpen, setOperatorOpen] = React43.useState(false);
6409
- const [valueOpen, setValueOpen] = React43.useState(false);
6410
- const [propertyOpen, setPropertyOpen] = React43.useState(false);
6411
- const [kebabOpen, setKebabOpen] = React43.useState(false);
6412
- const [pendingValueOpen, setPendingValueOpen] = React43.useState(false);
6413
- const autoOpenHandled = React43.useRef(false);
6414
- React43.useEffect(() => {
7126
+ const [operatorOpen, setOperatorOpen] = React45.useState(false);
7127
+ const [valueOpen, setValueOpen] = React45.useState(false);
7128
+ const [propertyOpen, setPropertyOpen] = React45.useState(false);
7129
+ const [kebabOpen, setKebabOpen] = React45.useState(false);
7130
+ const [pendingValueOpen, setPendingValueOpen] = React45.useState(false);
7131
+ const autoOpenHandled = React45.useRef(false);
7132
+ React45.useEffect(() => {
6415
7133
  if (autoOpen && !autoOpenHandled.current && condition.operator && !isNoValueOperator(condition.operator)) {
6416
7134
  autoOpenHandled.current = true;
6417
7135
  setValueOpen(true);
6418
7136
  }
6419
7137
  }, [autoOpen, condition.operator]);
6420
- React43.useEffect(() => {
7138
+ React45.useEffect(() => {
6421
7139
  if (!operatorOpen && pendingValueOpen) {
6422
7140
  setPendingValueOpen(false);
6423
7141
  setValueOpen(true);
@@ -6446,7 +7164,7 @@ var InteractiveFilterChip = ({
6446
7164
  const displayValue = formatFilterValue(condition.value);
6447
7165
  const hasValue = hasOperator && displayValue != null;
6448
7166
  const badgeCount = getBadgeCount(condition.value);
6449
- return /* @__PURE__ */ jsxs45(
7167
+ return /* @__PURE__ */ jsxs46(
6450
7168
  "div",
6451
7169
  {
6452
7170
  className: cn(
@@ -6455,7 +7173,7 @@ var InteractiveFilterChip = ({
6455
7173
  className
6456
7174
  ),
6457
7175
  children: [
6458
- properties ? /* @__PURE__ */ jsx51(
7176
+ properties ? /* @__PURE__ */ jsx52(
6459
7177
  PropertySelector,
6460
7178
  {
6461
7179
  properties,
@@ -6465,7 +7183,7 @@ var InteractiveFilterChip = ({
6465
7183
  },
6466
7184
  open: propertyOpen,
6467
7185
  onOpenChange: setPropertyOpen,
6468
- children: /* @__PURE__ */ jsx51("div", { children: /* @__PURE__ */ jsx51(
7186
+ children: /* @__PURE__ */ jsx52("div", { children: /* @__PURE__ */ jsx52(
6469
7187
  FilterChipSegment,
6470
7188
  {
6471
7189
  segmentType: "property",
@@ -6476,7 +7194,7 @@ var InteractiveFilterChip = ({
6476
7194
  }
6477
7195
  ) })
6478
7196
  }
6479
- ) : /* @__PURE__ */ jsx51(
7197
+ ) : /* @__PURE__ */ jsx52(
6480
7198
  FilterChipSegment,
6481
7199
  {
6482
7200
  segmentType: "property",
@@ -6485,13 +7203,13 @@ var InteractiveFilterChip = ({
6485
7203
  label: propertyDef.label
6486
7204
  }
6487
7205
  ),
6488
- /* @__PURE__ */ jsx51(
7206
+ /* @__PURE__ */ jsx52(
6489
7207
  SegmentPopover,
6490
7208
  {
6491
7209
  open: operatorOpen,
6492
7210
  onOpenChange: setOperatorOpen,
6493
7211
  minWidth: "180px",
6494
- trigger: /* @__PURE__ */ jsx51("div", { children: /* @__PURE__ */ jsx51(
7212
+ trigger: /* @__PURE__ */ jsx52("div", { children: /* @__PURE__ */ jsx52(
6495
7213
  FilterChipSegment,
6496
7214
  {
6497
7215
  segmentType: hasOperator ? "operator" : "placeholder",
@@ -6500,7 +7218,7 @@ var InteractiveFilterChip = ({
6500
7218
  onClick: () => setOperatorOpen(true)
6501
7219
  }
6502
7220
  ) }),
6503
- children: /* @__PURE__ */ jsx51("div", { className: "p-xs", children: /* @__PURE__ */ jsx51(
7221
+ children: /* @__PURE__ */ jsx52("div", { className: "p-xs", children: /* @__PURE__ */ jsx52(
6504
7222
  OperatorList,
6505
7223
  {
6506
7224
  dataType: propertyDef.type,
@@ -6510,36 +7228,41 @@ var InteractiveFilterChip = ({
6510
7228
  ) })
6511
7229
  }
6512
7230
  ),
6513
- hasOperator && condition.operator && !isNoValueOperator(condition.operator) && /* @__PURE__ */ jsx51(
6514
- SegmentPopover,
6515
- {
6516
- open: valueOpen,
6517
- onOpenChange: setValueOpen,
6518
- minWidth: "240px",
6519
- trigger: /* @__PURE__ */ jsx51("div", { children: /* @__PURE__ */ jsx51(
6520
- FilterChipSegment,
6521
- {
6522
- segmentType: hasValue ? "value" : "placeholder",
6523
- hasBorder: true,
6524
- label: hasValue ? displayValue : "Enter value",
6525
- badgeCount,
6526
- onClick: () => setValueOpen(true)
6527
- }
6528
- ) }),
6529
- children: /* @__PURE__ */ jsx51(
6530
- ValueInput,
6531
- {
6532
- dataType: propertyDef.type,
6533
- operator: condition.operator,
6534
- value: condition.value,
6535
- onChange: handleValueChange,
6536
- onSubmit: handleValueSubmit,
6537
- options: propertyDef.options
6538
- }
6539
- )
6540
- }
6541
- ),
6542
- hasOperator && condition.operator && isNoValueOperator(condition.operator) && /* @__PURE__ */ jsx51(
7231
+ hasOperator && condition.operator && !isNoValueOperator(condition.operator) && (() => {
7232
+ const inputType = getValueInputType(propertyDef.type, condition.operator);
7233
+ const dateWide = inputType === "DatePicker" || inputType === "DateRange";
7234
+ return /* @__PURE__ */ jsx52(
7235
+ SegmentPopover,
7236
+ {
7237
+ open: valueOpen,
7238
+ onOpenChange: setValueOpen,
7239
+ minWidth: dateWide ? "auto" : "240px",
7240
+ trigger: /* @__PURE__ */ jsx52("div", { children: /* @__PURE__ */ jsx52(
7241
+ FilterChipSegment,
7242
+ {
7243
+ segmentType: hasValue ? "value" : "placeholder",
7244
+ hasBorder: true,
7245
+ label: hasValue ? displayValue : "Enter value",
7246
+ badgeCount,
7247
+ onClick: () => setValueOpen(true)
7248
+ }
7249
+ ) }),
7250
+ children: /* @__PURE__ */ jsx52(
7251
+ ValueInput,
7252
+ {
7253
+ dataType: propertyDef.type,
7254
+ operator: condition.operator,
7255
+ value: condition.value,
7256
+ onChange: handleValueChange,
7257
+ onSubmit: handleValueSubmit,
7258
+ options: propertyDef.options,
7259
+ dynamicOptions: propertyDef.dynamicOptions
7260
+ }
7261
+ )
7262
+ }
7263
+ );
7264
+ })(),
7265
+ hasOperator && condition.operator && isNoValueOperator(condition.operator) && /* @__PURE__ */ jsx52(
6543
7266
  FilterChipSegment,
6544
7267
  {
6545
7268
  segmentType: "value",
@@ -6547,14 +7270,14 @@ var InteractiveFilterChip = ({
6547
7270
  label: condition.operator
6548
7271
  }
6549
7272
  ),
6550
- hasOperator && /* @__PURE__ */ jsx51(
7273
+ hasOperator && /* @__PURE__ */ jsx52(
6551
7274
  KebabMenu,
6552
7275
  {
6553
7276
  open: kebabOpen,
6554
7277
  onOpenChange: setKebabOpen,
6555
7278
  onConvertToAdvanced,
6556
7279
  onDelete,
6557
- children: /* @__PURE__ */ jsx51("div", { children: /* @__PURE__ */ jsx51(
7280
+ children: /* @__PURE__ */ jsx52("div", { children: /* @__PURE__ */ jsx52(
6558
7281
  FilterChipSegment,
6559
7282
  {
6560
7283
  segmentType: "button",
@@ -6573,13 +7296,13 @@ var InteractiveFilterChip = ({
6573
7296
  InteractiveFilterChip.displayName = "InteractiveFilterChip";
6574
7297
 
6575
7298
  // src/components/ui/filter/filter-system.tsx
6576
- import * as React49 from "react";
6577
- import { Icon as Icon33, faXmarkOutline as faXmarkOutline4, faPlusOutline as faPlusOutline4 } from "@l3mpire/icons";
7299
+ import * as React53 from "react";
7300
+ import { Icon as Icon37, faXmarkOutline as faXmarkOutline5, faPlusOutline as faPlusOutline5 } from "@l3mpire/icons";
6578
7301
 
6579
7302
  // src/components/ui/filter/advanced-chip.tsx
6580
- import * as React44 from "react";
6581
- import { Icon as Icon29, faXmarkOutline as faXmarkOutline2 } from "@l3mpire/icons";
6582
- import { jsx as jsx52, jsxs as jsxs46 } from "react/jsx-runtime";
7303
+ import * as React46 from "react";
7304
+ import { Icon as Icon31, faXmarkOutline as faXmarkOutline2 } from "@l3mpire/icons";
7305
+ import { jsx as jsx53, jsxs as jsxs47 } from "react/jsx-runtime";
6583
7306
  var btnBase = [
6584
7307
  "flex items-center justify-center",
6585
7308
  "min-h-[32px] max-h-[32px]",
@@ -6588,9 +7311,9 @@ var btnBase = [
6588
7311
  "cursor-pointer transition-colors",
6589
7312
  "hover:from-[var(--color-btn-outlined-neutral-bg-hover)] hover:to-[var(--color-btn-outlined-neutral-bg-gradient-to-hover)]"
6590
7313
  ];
6591
- var AdvancedChip = React44.forwardRef(
6592
- ({ className, count, onClear, onClick, ...props }, ref) => /* @__PURE__ */ jsxs46("div", { className: cn("inline-flex items-center", className), children: [
6593
- /* @__PURE__ */ jsxs46(
7314
+ var AdvancedChip = React46.forwardRef(
7315
+ ({ className, count, onClear, onClick, ...props }, ref) => /* @__PURE__ */ jsxs47("div", { className: cn("inline-flex items-center", className), children: [
7316
+ /* @__PURE__ */ jsxs47(
6594
7317
  "button",
6595
7318
  {
6596
7319
  ref,
@@ -6603,12 +7326,12 @@ var AdvancedChip = React44.forwardRef(
6603
7326
  ),
6604
7327
  ...props,
6605
7328
  children: [
6606
- /* @__PURE__ */ jsx52("span", { className: "text-sm font-semibold leading-sm whitespace-nowrap text-[var(--color-foreground)]", children: "Advanced filters" }),
6607
- count > 0 && /* @__PURE__ */ jsx52("span", { className: "flex items-center p-2xs rounded-xs bg-filter-chip-badge-bg", children: /* @__PURE__ */ jsx52("span", { className: "text-[10px] font-semibold leading-2xs text-filter-chip-badge-text", children: count }) })
7329
+ /* @__PURE__ */ jsx53("span", { className: "text-sm font-semibold leading-sm whitespace-nowrap text-[var(--color-foreground)]", children: "Advanced filters" }),
7330
+ count > 0 && /* @__PURE__ */ jsx53("span", { className: "flex items-center p-2xs rounded-xs bg-filter-chip-badge-bg", children: /* @__PURE__ */ jsx53("span", { className: "text-[10px] font-semibold leading-2xs text-filter-chip-badge-text", children: count }) })
6608
7331
  ]
6609
7332
  }
6610
7333
  ),
6611
- onClear && /* @__PURE__ */ jsx52(
7334
+ onClear && /* @__PURE__ */ jsx53(
6612
7335
  "button",
6613
7336
  {
6614
7337
  type: "button",
@@ -6622,7 +7345,7 @@ var AdvancedChip = React44.forwardRef(
6622
7345
  "rounded-r-md -ml-px"
6623
7346
  ),
6624
7347
  "aria-label": "Clear all advanced filters",
6625
- children: /* @__PURE__ */ jsx52(Icon29, { icon: faXmarkOutline2, size: "sm", className: "text-[var(--color-foreground)]" })
7348
+ children: /* @__PURE__ */ jsx53(Icon31, { icon: faXmarkOutline2, size: "sm", className: "text-[var(--color-foreground)]" })
6626
7349
  }
6627
7350
  )
6628
7351
  ] })
@@ -6630,15 +7353,128 @@ var AdvancedChip = React44.forwardRef(
6630
7353
  AdvancedChip.displayName = "AdvancedChip";
6631
7354
 
6632
7355
  // src/components/ui/filter/advanced-popover.tsx
6633
- import * as React46 from "react";
7356
+ import * as React50 from "react";
7357
+ import * as PopoverPrimitive12 from "@radix-ui/react-popover";
7358
+ import { Icon as Icon35, faPlusOutline as faPlusOutline3, faChevronDownOutline as faChevronDownOutline3, faXmarkOutline as faXmarkOutline3 } from "@l3mpire/icons";
7359
+
7360
+ // src/components/ui/filter/advanced-row.tsx
7361
+ import * as React48 from "react";
7362
+ import * as PopoverPrimitive11 from "@radix-ui/react-popover";
7363
+ import { Icon as Icon33, faRefreshOutline, faChevronDownOutline as faChevronDownOutline2 } from "@l3mpire/icons";
7364
+
7365
+ // src/components/ui/filter/filter-node-actions.tsx
7366
+ import * as React47 from "react";
6634
7367
  import * as PopoverPrimitive10 from "@radix-ui/react-popover";
6635
- import { Icon as Icon31, faPlusOutline as faPlusOutline2, faChevronDownOutline as faChevronDownOutline3 } from "@l3mpire/icons";
7368
+ import {
7369
+ Icon as Icon32,
7370
+ faEllipsisOutline,
7371
+ faCopyOutline,
7372
+ faTrashOutline as faTrashOutline2,
7373
+ faFolderOutline,
7374
+ faFilterOutline as faFilterOutline3
7375
+ } from "@l3mpire/icons";
7376
+ import { jsx as jsx54, jsxs as jsxs48 } from "react/jsx-runtime";
7377
+ var FilterNodeActions = ({
7378
+ nodeType,
7379
+ onDuplicate,
7380
+ onConvert,
7381
+ onDelete
7382
+ }) => {
7383
+ const [open, setOpen] = React47.useState(false);
7384
+ const items = [
7385
+ {
7386
+ label: "Duplicate",
7387
+ icon: faCopyOutline,
7388
+ action: onDuplicate
7389
+ },
7390
+ {
7391
+ label: nodeType === "condition" ? "Turn into group" : "Turn into filter",
7392
+ icon: nodeType === "condition" ? faFolderOutline : faFilterOutline3,
7393
+ action: onConvert
7394
+ },
7395
+ {
7396
+ label: "Delete",
7397
+ icon: faTrashOutline2,
7398
+ action: onDelete,
7399
+ destructive: true
7400
+ }
7401
+ ];
7402
+ return /* @__PURE__ */ jsxs48(PopoverPrimitive10.Root, { open, onOpenChange: setOpen, children: [
7403
+ /* @__PURE__ */ jsx54(PopoverPrimitive10.Trigger, { asChild: true, children: /* @__PURE__ */ jsx54(
7404
+ "button",
7405
+ {
7406
+ type: "button",
7407
+ className: "shrink-0 flex items-center justify-center p-sm rounded-md cursor-pointer transition-colors hover:bg-[var(--color-accent)]",
7408
+ "aria-label": "More actions",
7409
+ children: /* @__PURE__ */ jsx54(
7410
+ Icon32,
7411
+ {
7412
+ icon: faEllipsisOutline,
7413
+ size: "sm",
7414
+ className: "text-[var(--color-foreground)]"
7415
+ }
7416
+ )
7417
+ }
7418
+ ) }),
7419
+ /* @__PURE__ */ jsx54(PopoverPrimitive10.Portal, { children: /* @__PURE__ */ jsx54(
7420
+ PopoverPrimitive10.Content,
7421
+ {
7422
+ sideOffset: 4,
7423
+ align: "end",
7424
+ className: cn(
7425
+ "z-50 flex flex-col p-xs overflow-clip",
7426
+ "bg-[var(--color-dropdown-bg)] border border-[var(--color-dropdown-border)] rounded-md shadow-lg",
7427
+ "data-[state=open]:animate-in data-[state=open]:fade-in-0 data-[state=open]:zoom-in-95",
7428
+ "data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=closed]:zoom-out-95",
7429
+ "min-w-[180px]"
7430
+ ),
7431
+ children: items.map((item) => /* @__PURE__ */ jsxs48(
7432
+ "button",
7433
+ {
7434
+ type: "button",
7435
+ onClick: () => {
7436
+ item.action();
7437
+ setOpen(false);
7438
+ },
7439
+ className: cn(
7440
+ "flex items-center gap-base p-base rounded-base cursor-pointer transition-colors text-left",
7441
+ "hover:bg-[var(--color-dropdown-item-hover)]",
7442
+ item.destructive && "text-[var(--color-destructive,#ef4444)]"
7443
+ ),
7444
+ children: [
7445
+ /* @__PURE__ */ jsx54(
7446
+ Icon32,
7447
+ {
7448
+ icon: item.icon,
7449
+ size: "sm",
7450
+ className: cn(
7451
+ "shrink-0",
7452
+ item.destructive ? "text-[var(--color-destructive,#ef4444)]" : "text-[var(--color-dropdown-item-icon)]"
7453
+ )
7454
+ }
7455
+ ),
7456
+ /* @__PURE__ */ jsx54(
7457
+ "span",
7458
+ {
7459
+ className: cn(
7460
+ "text-sm font-regular leading-sm",
7461
+ item.destructive ? "text-[var(--color-destructive,#ef4444)]" : "text-[var(--color-dropdown-item-text)]"
7462
+ ),
7463
+ children: item.label
7464
+ }
7465
+ )
7466
+ ]
7467
+ },
7468
+ item.label
7469
+ ))
7470
+ }
7471
+ ) })
7472
+ ] });
7473
+ };
7474
+ FilterNodeActions.displayName = "FilterNodeActions";
6636
7475
 
6637
7476
  // src/components/ui/filter/advanced-row.tsx
6638
- import * as React45 from "react";
6639
- import * as PopoverPrimitive9 from "@radix-ui/react-popover";
6640
- import { Icon as Icon30, faXmarkOutline as faXmarkOutline3, faRefreshOutline, faChevronDownOutline as faChevronDownOutline2 } from "@l3mpire/icons";
6641
- import { jsx as jsx53, jsxs as jsxs47 } from "react/jsx-runtime";
7477
+ import { jsx as jsx55, jsxs as jsxs49 } from "react/jsx-runtime";
6642
7478
  var selectBtnStyle = [
6643
7479
  "flex items-center gap-base",
6644
7480
  "px-base py-sm",
@@ -6655,10 +7491,13 @@ var AdvancedRow = ({
6655
7491
  properties,
6656
7492
  onUpdate,
6657
7493
  onPropertyChange,
6658
- onDelete
7494
+ onDelete,
7495
+ onDuplicate,
7496
+ onTurnIntoGroup
6659
7497
  }) => {
6660
- const [operatorOpen, setOperatorOpen] = React45.useState(false);
6661
- const [propertyOpen, setPropertyOpen] = React45.useState(false);
7498
+ const [operatorOpen, setOperatorOpen] = React48.useState(false);
7499
+ const [propertyOpen, setPropertyOpen] = React48.useState(false);
7500
+ const [valueOpen, setValueOpen] = React48.useState(false);
6662
7501
  const handleOperatorSelect = (op) => {
6663
7502
  if (isNoValueOperator(op)) {
6664
7503
  onUpdate({ ...condition, operator: op, value: null });
@@ -6671,16 +7510,18 @@ var AdvancedRow = ({
6671
7510
  const handleValueChange = (val) => {
6672
7511
  onUpdate({ ...condition, value: val });
6673
7512
  };
6674
- const displayValue = condition.value == null ? "" : typeof condition.value === "string" ? condition.value : String(condition.value);
6675
- return /* @__PURE__ */ jsxs47("div", { className: "flex items-center gap-base w-full min-w-0", children: [
6676
- connector === "Where" ? /* @__PURE__ */ jsx53("div", { className: "shrink-0 w-[64px] flex items-center justify-end", children: /* @__PURE__ */ jsx53("span", { className: "text-xs font-semibold leading-xs text-[var(--color-muted-foreground)]", children: "Where" }) }) : /* @__PURE__ */ jsxs47(
7513
+ const displayValue = formatFilterValue(condition.value);
7514
+ const badgeCount = getBadgeCount(condition.value);
7515
+ const hasValue = displayValue != null;
7516
+ return /* @__PURE__ */ jsxs49("div", { className: "flex items-center gap-base w-full min-w-0", children: [
7517
+ connector === "Where" ? /* @__PURE__ */ jsx55("div", { className: "shrink-0 w-[64px] flex items-center justify-end", children: /* @__PURE__ */ jsx55("span", { className: "text-xs font-semibold leading-xs text-[var(--color-muted-foreground)]", children: "Where" }) }) : /* @__PURE__ */ jsxs49(
6677
7518
  "button",
6678
7519
  {
6679
7520
  type: "button",
6680
7521
  onClick: onConnectorToggle,
6681
7522
  className: cn(
6682
7523
  "shrink-0 flex items-center justify-center gap-xs",
6683
- "min-w-[64px] min-h-[24px] max-h-[24px] p-xs",
7524
+ "min-w-[64px] min-h-[32px] max-h-[32px] px-base py-sm",
6684
7525
  "bg-gradient-to-t from-[var(--color-btn-outlined-neutral-bg-default)] from-[10%] to-[var(--color-btn-outlined-neutral-bg-gradient-to-default)]",
6685
7526
  "border border-[var(--color-btn-outlined-neutral-border-default)] rounded-base shadow-sm",
6686
7527
  "cursor-pointer transition-colors text-xs font-semibold leading-xs text-[var(--color-foreground)]",
@@ -6688,22 +7529,18 @@ var AdvancedRow = ({
6688
7529
  ),
6689
7530
  children: [
6690
7531
  connector,
6691
- /* @__PURE__ */ jsx53(Icon30, { icon: faRefreshOutline, size: "xs", className: "text-[var(--color-foreground)]" })
7532
+ /* @__PURE__ */ jsx55(Icon33, { icon: faRefreshOutline, size: "xs", className: "text-[var(--color-foreground)]" })
6692
7533
  ]
6693
7534
  }
6694
7535
  ),
6695
- /* @__PURE__ */ jsxs47(PopoverPrimitive9.Root, { open: propertyOpen, onOpenChange: setPropertyOpen, children: [
6696
- /* @__PURE__ */ jsx53(PopoverPrimitive9.Trigger, { asChild: true, children: /* @__PURE__ */ jsxs47("button", { type: "button", className: cn(selectBtnStyle, "min-w-0"), children: [
6697
- /* @__PURE__ */ jsx53(Icon30, { icon: propertyDef.icon, size: "sm", className: "shrink-0 text-[var(--color-muted-foreground)]" }),
6698
- /* @__PURE__ */ jsxs47("span", { className: "text-sm font-regular leading-sm text-[var(--color-foreground)] whitespace-nowrap truncate", children: [
6699
- propertyDef.groupLabel,
6700
- " > ",
6701
- propertyDef.label
6702
- ] }),
6703
- /* @__PURE__ */ jsx53(Icon30, { icon: faChevronDownOutline2, size: "xs", className: "shrink-0 text-[var(--color-foreground)]" })
7536
+ /* @__PURE__ */ jsxs49(PopoverPrimitive11.Root, { open: propertyOpen, onOpenChange: setPropertyOpen, children: [
7537
+ /* @__PURE__ */ jsx55(PopoverPrimitive11.Trigger, { asChild: true, children: /* @__PURE__ */ jsxs49("button", { type: "button", className: cn(selectBtnStyle, "min-w-0"), children: [
7538
+ /* @__PURE__ */ jsx55(Icon33, { icon: propertyDef.icon, size: "sm", className: "shrink-0 text-[var(--color-muted-foreground)]" }),
7539
+ /* @__PURE__ */ jsx55("span", { className: "text-sm font-regular leading-sm text-[var(--color-foreground)] whitespace-nowrap truncate", children: propertyDef.label }),
7540
+ /* @__PURE__ */ jsx55(Icon33, { icon: faChevronDownOutline2, size: "xs", className: "shrink-0 text-[var(--color-foreground)]" })
6704
7541
  ] }) }),
6705
- /* @__PURE__ */ jsx53(PopoverPrimitive9.Portal, { children: /* @__PURE__ */ jsx53(
6706
- PopoverPrimitive9.Content,
7542
+ /* @__PURE__ */ jsx55(PopoverPrimitive11.Portal, { children: /* @__PURE__ */ jsx55(
7543
+ PopoverPrimitive11.Content,
6707
7544
  {
6708
7545
  sideOffset: 4,
6709
7546
  align: "start",
@@ -6714,7 +7551,7 @@ var AdvancedRow = ({
6714
7551
  "data-[state=closed]:animate-out data-[state=closed]:fade-out-0",
6715
7552
  "min-w-[200px]"
6716
7553
  ),
6717
- children: properties.map((p) => /* @__PURE__ */ jsxs47(
7554
+ children: properties.map((p) => /* @__PURE__ */ jsxs49(
6718
7555
  "button",
6719
7556
  {
6720
7557
  type: "button",
@@ -6728,8 +7565,8 @@ var AdvancedRow = ({
6728
7565
  p.id === condition.propertyId && "bg-[var(--color-dropdown-item-hover)]"
6729
7566
  ),
6730
7567
  children: [
6731
- /* @__PURE__ */ jsx53(Icon30, { icon: p.icon, size: "sm", className: "shrink-0 text-[var(--color-dropdown-item-icon)]" }),
6732
- /* @__PURE__ */ jsx53("span", { className: "text-sm font-regular leading-sm text-[var(--color-dropdown-item-text)] truncate", children: p.label })
7568
+ /* @__PURE__ */ jsx55(Icon33, { icon: p.icon, size: "sm", className: "shrink-0 text-[var(--color-dropdown-item-icon)]" }),
7569
+ /* @__PURE__ */ jsx55("span", { className: "text-sm font-regular leading-sm text-[var(--color-dropdown-item-text)] truncate", children: p.label })
6733
7570
  ]
6734
7571
  },
6735
7572
  p.id
@@ -6737,1177 +7574,1021 @@ var AdvancedRow = ({
6737
7574
  }
6738
7575
  ) })
6739
7576
  ] }),
6740
- /* @__PURE__ */ jsxs47(PopoverPrimitive9.Root, { open: operatorOpen, onOpenChange: setOperatorOpen, children: [
6741
- /* @__PURE__ */ jsx53(PopoverPrimitive9.Trigger, { asChild: true, children: /* @__PURE__ */ jsxs47("button", { type: "button", className: cn(selectBtnStyle, "min-w-0"), children: [
6742
- /* @__PURE__ */ jsx53("span", { className: "text-sm font-regular leading-sm text-[var(--color-foreground)] whitespace-nowrap truncate text-left", children: condition.operator ?? "Select" }),
6743
- /* @__PURE__ */ jsx53(Icon30, { icon: faChevronDownOutline2, size: "xs", className: "shrink-0 text-[var(--color-foreground)]" })
7577
+ /* @__PURE__ */ jsxs49(PopoverPrimitive11.Root, { open: operatorOpen, onOpenChange: setOperatorOpen, children: [
7578
+ /* @__PURE__ */ jsx55(PopoverPrimitive11.Trigger, { asChild: true, children: /* @__PURE__ */ jsxs49("button", { type: "button", className: cn(selectBtnStyle, "min-w-0"), children: [
7579
+ /* @__PURE__ */ jsx55("span", { className: "text-sm font-regular leading-sm text-[var(--color-foreground)] whitespace-nowrap truncate text-left", children: condition.operator ?? "Select" }),
7580
+ /* @__PURE__ */ jsx55(Icon33, { icon: faChevronDownOutline2, size: "xs", className: "shrink-0 text-[var(--color-foreground)]" })
6744
7581
  ] }) }),
6745
- /* @__PURE__ */ jsx53(PopoverPrimitive9.Portal, { children: /* @__PURE__ */ jsx53(
6746
- PopoverPrimitive9.Content,
7582
+ /* @__PURE__ */ jsx55(PopoverPrimitive11.Portal, { children: /* @__PURE__ */ jsx55(
7583
+ PopoverPrimitive11.Content,
6747
7584
  {
6748
7585
  sideOffset: 4,
6749
7586
  align: "start",
6750
7587
  className: cn(
6751
7588
  "z-50 flex flex-col p-xs overflow-clip",
6752
7589
  "bg-[var(--color-dropdown-bg)] border border-[var(--color-dropdown-border)] rounded-md shadow-lg",
6753
- "data-[state=open]:animate-in data-[state=open]:fade-in-0 data-[state=open]:zoom-in-95",
6754
- "data-[state=closed]:animate-out data-[state=closed]:fade-out-0",
6755
- "min-w-[160px]"
6756
- ),
6757
- children: /* @__PURE__ */ jsx53(
6758
- OperatorList,
6759
- {
6760
- dataType: propertyDef.type,
6761
- activeOperator: condition.operator,
6762
- onSelect: handleOperatorSelect
6763
- }
6764
- )
6765
- }
6766
- ) })
6767
- ] }),
6768
- condition.operator && !isNoValueOperator(condition.operator) && /* @__PURE__ */ jsx53(
6769
- "input",
6770
- {
6771
- type: "text",
6772
- value: displayValue,
6773
- onChange: (e) => handleValueChange(e.target.value),
6774
- placeholder: "Placeholder",
6775
- className: cn(
6776
- "flex-1 min-w-[80px] px-base py-sm rounded-md",
6777
- "border border-[var(--color-input)]",
6778
- "bg-[var(--color-background)] text-sm font-regular leading-sm text-[var(--color-foreground)]",
6779
- "placeholder:text-[var(--color-muted-foreground)]",
6780
- "focus:outline-none focus:ring-2 focus:ring-[var(--color-ring)] focus:ring-offset-0"
6781
- )
6782
- }
6783
- ),
6784
- /* @__PURE__ */ jsx53(
6785
- "button",
6786
- {
6787
- type: "button",
6788
- onClick: onDelete,
6789
- className: "ml-auto shrink-0 flex items-center justify-center p-sm rounded-md cursor-pointer transition-colors hover:bg-[var(--color-accent)]",
6790
- "aria-label": "Remove filter",
6791
- children: /* @__PURE__ */ jsx53(Icon30, { icon: faXmarkOutline3, size: "sm", className: "text-[var(--color-foreground)]" })
6792
- }
6793
- )
6794
- ] });
6795
- };
6796
- AdvancedRow.displayName = "AdvancedRow";
6797
-
6798
- // src/components/ui/filter/advanced-popover.tsx
6799
- import { jsx as jsx54, jsxs as jsxs48 } from "react/jsx-runtime";
6800
- var outlinedBtn = [
6801
- "flex items-center gap-sm px-base py-sm",
6802
- "min-h-[32px] max-h-[32px] min-w-[80px]",
6803
- "bg-gradient-to-t from-[var(--color-btn-outlined-neutral-bg-default)] from-[10%] to-[var(--color-btn-outlined-neutral-bg-gradient-to-default)]",
6804
- "border border-[var(--color-btn-outlined-neutral-border-default)] rounded-md shadow-sm",
6805
- "cursor-pointer transition-colors text-sm font-semibold leading-sm text-[var(--color-foreground)]",
6806
- "hover:from-[var(--color-btn-outlined-neutral-bg-hover)] hover:to-[var(--color-btn-outlined-neutral-bg-gradient-to-hover)]"
6807
- ];
6808
- var AdvancedPopover = ({
6809
- filters,
6810
- properties,
6811
- onFiltersChange,
6812
- open,
6813
- onOpenChange,
6814
- children
6815
- }) => {
6816
- const [addSelectorOpen, setAddSelectorOpen] = React46.useState(false);
6817
- const [draftPickerOpen, setDraftPickerOpen] = React46.useState(false);
6818
- const getPropertyDef = (propertyId) => properties.find((p) => p.id === propertyId);
6819
- const handleUpdateFilter = (updated) => {
6820
- onFiltersChange(filters.map((f) => f.id === updated.id ? updated : f));
6821
- };
6822
- const handleDeleteFilter = (id) => {
6823
- onFiltersChange(filters.filter((f) => f.id !== id));
6824
- };
6825
- const handlePropertyChange = (filterId, newProp) => {
6826
- const newCondition = createFilterWithDefaults(newProp.id, newProp.type);
6827
- onFiltersChange(
6828
- filters.map((f) => f.id === filterId ? { ...newCondition, id: filterId } : f)
6829
- );
6830
- };
6831
- const handleAddFilter = (property) => {
6832
- const newFilter = createFilterWithDefaults(property.id, property.type);
6833
- onFiltersChange([...filters, newFilter]);
6834
- setAddSelectorOpen(false);
6835
- };
6836
- const handleClearAll = () => {
6837
- onFiltersChange([]);
6838
- onOpenChange?.(false);
6839
- };
6840
- const toggleLogicOp = (filterId) => {
6841
- onFiltersChange(
6842
- filters.map(
6843
- (f) => f.id === filterId ? { ...f, logicOperator: (f.logicOperator ?? "and") === "and" ? "or" : "and" } : f
6844
- )
6845
- );
6846
- };
6847
- return /* @__PURE__ */ jsxs48(PopoverPrimitive10.Root, { open, onOpenChange, children: [
6848
- /* @__PURE__ */ jsx54(PopoverPrimitive10.Trigger, { asChild: true, children }),
6849
- /* @__PURE__ */ jsx54(PopoverPrimitive10.Portal, { children: /* @__PURE__ */ jsxs48(
6850
- PopoverPrimitive10.Content,
6851
- {
6852
- sideOffset: 4,
6853
- align: "start",
6854
- collisionPadding: 16,
6855
- onOpenAutoFocus: (e) => e.preventDefault(),
6856
- className: cn(
6857
- "z-50 flex flex-col",
6858
- "bg-[var(--color-background)] rounded-md shadow-lg",
6859
- "data-[state=open]:animate-in data-[state=open]:fade-in-0 data-[state=open]:zoom-in-95",
6860
- "data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=closed]:zoom-out-95",
6861
- "data-[side=bottom]:slide-in-from-top-2",
6862
- "w-[min(520px,calc(100vw-32px))]"
6863
- ),
6864
- children: [
6865
- /* @__PURE__ */ jsxs48("div", { className: "flex flex-col gap-base p-base", children: [
6866
- filters.map((filter, i) => {
6867
- const propDef = getPropertyDef(filter.propertyId);
6868
- if (!propDef) return null;
6869
- return /* @__PURE__ */ jsx54(
6870
- AdvancedRow,
6871
- {
6872
- connector: i === 0 ? "Where" : (filter.logicOperator ?? "and") === "and" ? "And" : "Or",
6873
- onConnectorToggle: i > 0 ? () => toggleLogicOp(filter.id) : void 0,
6874
- propertyDef: propDef,
6875
- condition: filter,
6876
- properties,
6877
- onUpdate: handleUpdateFilter,
6878
- onPropertyChange: (p) => handlePropertyChange(filter.id, p),
6879
- onDelete: () => handleDeleteFilter(filter.id)
6880
- },
6881
- filter.id
6882
- );
6883
- }),
6884
- filters.length === 0 && /* ── Draft row: inline "Select property" placeholder ──── */
6885
- /* @__PURE__ */ jsxs48("div", { className: "flex items-center gap-base w-full min-w-0", children: [
6886
- /* @__PURE__ */ jsx54("div", { className: "shrink-0 w-[64px] flex items-center justify-end", children: /* @__PURE__ */ jsx54("span", { className: "text-xs font-semibold leading-xs text-[var(--color-muted-foreground)]", children: "Where" }) }),
6887
- /* @__PURE__ */ jsx54(
6888
- PropertySelector,
7590
+ "data-[state=open]:animate-in data-[state=open]:fade-in-0 data-[state=open]:zoom-in-95",
7591
+ "data-[state=closed]:animate-out data-[state=closed]:fade-out-0",
7592
+ "min-w-[160px]"
7593
+ ),
7594
+ children: /* @__PURE__ */ jsx55(
7595
+ OperatorList,
7596
+ {
7597
+ dataType: propertyDef.type,
7598
+ activeOperator: condition.operator,
7599
+ onSelect: handleOperatorSelect
7600
+ }
7601
+ )
7602
+ }
7603
+ ) })
7604
+ ] }),
7605
+ condition.operator && !isNoValueOperator(condition.operator) && (() => {
7606
+ const inputType = getValueInputType(propertyDef.type, condition.operator);
7607
+ const dateWide = inputType === "DatePicker" || inputType === "DateRange";
7608
+ return /* @__PURE__ */ jsxs49(PopoverPrimitive11.Root, { open: valueOpen, onOpenChange: setValueOpen, children: [
7609
+ /* @__PURE__ */ jsx55(PopoverPrimitive11.Trigger, { asChild: true, children: /* @__PURE__ */ jsxs49(
7610
+ "button",
7611
+ {
7612
+ type: "button",
7613
+ className: cn(selectBtnStyle, "flex-1 min-w-[80px] justify-between"),
7614
+ children: [
7615
+ /* @__PURE__ */ jsx55(
7616
+ "span",
6889
7617
  {
6890
- properties,
6891
- onSelect: handleAddFilter,
6892
- open: draftPickerOpen,
6893
- onOpenChange: setDraftPickerOpen,
6894
- children: /* @__PURE__ */ jsxs48(
6895
- "button",
6896
- {
6897
- type: "button",
6898
- className: cn(
6899
- "flex items-center gap-base px-base py-sm min-w-0",
6900
- "bg-gradient-to-t from-[var(--color-btn-outlined-neutral-bg-default)] to-[var(--color-btn-outlined-neutral-bg-gradient-to-default)]",
6901
- "border border-[var(--color-btn-outlined-neutral-border-default)] rounded-md shadow-sm",
6902
- "cursor-pointer transition-colors",
6903
- "hover:from-[var(--color-btn-outlined-neutral-bg-hover)] hover:to-[var(--color-btn-outlined-neutral-bg-gradient-to-hover)]"
6904
- ),
6905
- children: [
6906
- /* @__PURE__ */ jsx54("span", { className: "text-sm font-regular leading-sm text-[var(--color-muted-foreground)] whitespace-nowrap", children: "Select property" }),
6907
- /* @__PURE__ */ jsx54(
6908
- Icon31,
6909
- {
6910
- icon: faChevronDownOutline3,
6911
- size: "xs",
6912
- className: "shrink-0 text-[var(--color-foreground)]"
6913
- }
6914
- )
6915
- ]
6916
- }
6917
- )
7618
+ className: cn(
7619
+ "text-sm font-regular leading-sm whitespace-nowrap truncate text-left",
7620
+ hasValue ? "text-[var(--color-foreground)]" : "text-[var(--color-muted-foreground)]"
7621
+ ),
7622
+ children: hasValue ? displayValue : "Enter a value"
6918
7623
  }
6919
- )
6920
- ] })
6921
- ] }),
6922
- /* @__PURE__ */ jsxs48("div", { className: "flex items-center justify-between p-base border-t border-[var(--color-border)]", children: [
6923
- /* @__PURE__ */ jsx54(
6924
- PropertySelector,
6925
- {
6926
- properties,
6927
- onSelect: handleAddFilter,
6928
- open: addSelectorOpen,
6929
- onOpenChange: setAddSelectorOpen,
6930
- children: /* @__PURE__ */ jsxs48("button", { type: "button", className: cn(outlinedBtn), children: [
6931
- /* @__PURE__ */ jsx54(Icon31, { icon: faPlusOutline2, size: "sm", className: "text-[var(--color-foreground)]" }),
6932
- "Add filter"
6933
- ] })
6934
- }
7624
+ ),
7625
+ /* @__PURE__ */ jsxs49("span", { className: "flex items-center gap-xs shrink-0", children: [
7626
+ badgeCount != null && /* @__PURE__ */ jsxs49("span", { className: "text-xs font-semibold leading-xs text-[var(--color-muted-foreground)]", children: [
7627
+ "+",
7628
+ badgeCount - 1
7629
+ ] }),
7630
+ /* @__PURE__ */ jsx55(
7631
+ Icon33,
7632
+ {
7633
+ icon: faChevronDownOutline2,
7634
+ size: "xs",
7635
+ className: "text-[var(--color-foreground)]"
7636
+ }
7637
+ )
7638
+ ] })
7639
+ ]
7640
+ }
7641
+ ) }),
7642
+ /* @__PURE__ */ jsx55(PopoverPrimitive11.Portal, { children: /* @__PURE__ */ jsx55(
7643
+ PopoverPrimitive11.Content,
7644
+ {
7645
+ sideOffset: 4,
7646
+ align: "start",
7647
+ className: cn(
7648
+ "z-50 flex flex-col overflow-clip",
7649
+ "bg-[var(--color-dropdown-bg)] border border-[var(--color-dropdown-border)] rounded-md shadow-lg",
7650
+ "data-[state=open]:animate-in data-[state=open]:fade-in-0 data-[state=open]:zoom-in-95",
7651
+ "data-[state=closed]:animate-out data-[state=closed]:fade-out-0"
6935
7652
  ),
6936
- /* @__PURE__ */ jsx54(
6937
- "button",
7653
+ style: { minWidth: dateWide ? "auto" : "240px" },
7654
+ children: /* @__PURE__ */ jsx55(
7655
+ ValueInput,
6938
7656
  {
6939
- type: "button",
6940
- onClick: handleClearAll,
6941
- className: "text-sm font-semibold leading-sm text-[var(--color-foreground)] cursor-pointer transition-colors hover:opacity-70 px-base py-sm",
6942
- children: "Clear all filters"
7657
+ dataType: propertyDef.type,
7658
+ operator: condition.operator,
7659
+ value: condition.value,
7660
+ onChange: handleValueChange,
7661
+ onSubmit: () => setValueOpen(false),
7662
+ options: propertyDef.options,
7663
+ dynamicOptions: propertyDef.dynamicOptions
6943
7664
  }
6944
7665
  )
6945
- ] })
6946
- ]
7666
+ }
7667
+ ) })
7668
+ ] });
7669
+ })(),
7670
+ /* @__PURE__ */ jsx55(
7671
+ FilterNodeActions,
7672
+ {
7673
+ nodeType: "condition",
7674
+ onDuplicate: onDuplicate ?? (() => {
7675
+ }),
7676
+ onConvert: onTurnIntoGroup ?? (() => {
7677
+ }),
7678
+ onDelete
6947
7679
  }
6948
- ) })
7680
+ )
6949
7681
  ] });
6950
7682
  };
6951
- AdvancedPopover.displayName = "AdvancedPopover";
7683
+ AdvancedRow.displayName = "AdvancedRow";
6952
7684
 
6953
- // src/components/ui/filter/summary-chip.tsx
6954
- import * as React47 from "react";
6955
- import * as PopoverPrimitive11 from "@radix-ui/react-popover";
6956
- import { Icon as Icon32, faSlidersOutline as faSlidersOutline2, faPlusOutline as faPlusOutline3, faChevronDownOutline as faChevronDownOutline4 } from "@l3mpire/icons";
6957
- import { jsx as jsx55, jsxs as jsxs49 } from "react/jsx-runtime";
6958
- var SummaryChip = ({
6959
- count,
6960
- filters,
7685
+ // src/components/ui/filter/advanced-group.tsx
7686
+ import * as React49 from "react";
7687
+ import { Icon as Icon34, faRefreshOutline as faRefreshOutline2, faPlusOutline as faPlusOutline2 } from "@l3mpire/icons";
7688
+ import { jsx as jsx56, jsxs as jsxs50 } from "react/jsx-runtime";
7689
+ var AdvancedGroup = ({
7690
+ connector,
7691
+ onConnectorToggle,
7692
+ onDuplicate,
7693
+ onTurnIntoFilter,
7694
+ onDelete,
7695
+ onAddFilter,
6961
7696
  properties,
6962
- onFiltersChange,
6963
- onClearAll,
6964
- children,
6965
- className,
6966
- open: openProp,
6967
- onOpenChange
7697
+ children
6968
7698
  }) => {
6969
- const [uncontrolledOpen, setUncontrolledOpen] = React47.useState(false);
6970
- const isControlled = openProp !== void 0;
6971
- const open = isControlled ? openProp : uncontrolledOpen;
6972
- const setOpen = (v) => {
6973
- if (!isControlled) setUncontrolledOpen(v);
6974
- onOpenChange?.(v);
6975
- };
6976
- const [addSelectorOpen, setAddSelectorOpen] = React47.useState(false);
6977
- const [draftPickerOpen, setDraftPickerOpen] = React47.useState(false);
6978
- const getPropertyDef = (propertyId) => properties.find((p) => p.id === propertyId);
6979
- const handleUpdateFilter = (updated) => {
6980
- onFiltersChange(filters.map((f) => f.id === updated.id ? updated : f));
6981
- };
6982
- const handleDeleteFilter = (id) => {
6983
- const next = filters.filter((f) => f.id !== id);
6984
- onFiltersChange(next);
6985
- if (next.length === 0) setOpen(false);
6986
- };
6987
- const handlePropertyChange = (filterId, newProp) => {
6988
- const newCondition = createFilterWithDefaults(newProp.id, newProp.type);
6989
- onFiltersChange(
6990
- filters.map((f) => f.id === filterId ? { ...newCondition, id: filterId } : f)
6991
- );
6992
- };
6993
- const handleAddFilter = (property) => {
6994
- const newFilter = createFilterWithDefaults(property.id, property.type);
6995
- onFiltersChange([...filters, newFilter]);
6996
- setAddSelectorOpen(false);
6997
- };
6998
- const toggleLogicOp = (filterId) => {
6999
- onFiltersChange(
7000
- filters.map(
7001
- (f) => f.id === filterId ? { ...f, logicOperator: (f.logicOperator ?? "and") === "and" ? "or" : "and" } : f
7002
- )
7003
- );
7004
- };
7005
- return /* @__PURE__ */ jsxs49(PopoverPrimitive11.Root, { open, onOpenChange: setOpen, children: [
7006
- /* @__PURE__ */ jsx55(PopoverPrimitive11.Trigger, { asChild: true, children: children ?? /* @__PURE__ */ jsxs49(
7699
+ const [addOpen, setAddOpen] = React49.useState(false);
7700
+ return /* @__PURE__ */ jsxs50("div", { className: "flex items-start gap-base w-full min-w-0", children: [
7701
+ connector === "Where" ? /* @__PURE__ */ jsx56("div", { className: "shrink-0 w-[64px] flex items-center justify-end pt-base", children: /* @__PURE__ */ jsx56("span", { className: "text-xs font-semibold leading-xs text-[var(--color-muted-foreground)]", children: "Where" }) }) : /* @__PURE__ */ jsx56("div", { className: "shrink-0 w-[64px] flex items-center justify-end pt-base", children: /* @__PURE__ */ jsxs50(
7007
7702
  "button",
7008
7703
  {
7009
7704
  type: "button",
7705
+ onClick: onConnectorToggle,
7010
7706
  className: cn(
7011
- "inline-flex items-center gap-sm px-base py-sm",
7012
- "min-h-[32px] max-h-[32px]",
7707
+ "flex items-center justify-center gap-xs",
7708
+ "min-w-[64px] min-h-[32px] max-h-[32px] px-base py-sm",
7013
7709
  "bg-gradient-to-t from-[var(--color-btn-outlined-neutral-bg-default)] from-[10%] to-[var(--color-btn-outlined-neutral-bg-gradient-to-default)]",
7014
- "border border-[var(--color-btn-outlined-neutral-border-default)] rounded-md shadow-sm",
7015
- "cursor-pointer transition-colors",
7016
- "hover:from-[var(--color-btn-outlined-neutral-bg-hover)] hover:to-[var(--color-btn-outlined-neutral-bg-gradient-to-hover)]",
7017
- className
7710
+ "border border-[var(--color-btn-outlined-neutral-border-default)] rounded-base shadow-sm",
7711
+ "cursor-pointer transition-colors text-xs font-semibold leading-xs text-[var(--color-foreground)]",
7712
+ "hover:from-[var(--color-btn-outlined-neutral-bg-hover)] hover:to-[var(--color-btn-outlined-neutral-bg-gradient-to-hover)]"
7018
7713
  ),
7019
7714
  children: [
7020
- /* @__PURE__ */ jsx55(
7021
- Icon32,
7022
- {
7023
- icon: faSlidersOutline2,
7024
- size: "sm",
7025
- className: "shrink-0 text-[var(--color-foreground)]"
7026
- }
7027
- ),
7028
- /* @__PURE__ */ jsx55("span", { className: "text-sm font-semibold leading-sm whitespace-nowrap text-[var(--color-foreground)]", children: "Filters" }),
7029
- count > 0 && /* @__PURE__ */ jsx55("span", { className: "flex items-center p-2xs rounded-xs bg-filter-chip-badge-bg", children: /* @__PURE__ */ jsx55("span", { className: "text-[10px] font-semibold leading-2xs text-filter-chip-badge-text", children: count }) })
7715
+ connector,
7716
+ /* @__PURE__ */ jsx56(Icon34, { icon: faRefreshOutline2, size: "xs", className: "text-[var(--color-foreground)]" })
7030
7717
  ]
7031
7718
  }
7032
7719
  ) }),
7033
- /* @__PURE__ */ jsx55(PopoverPrimitive11.Portal, { children: /* @__PURE__ */ jsxs49(
7034
- PopoverPrimitive11.Content,
7720
+ /* @__PURE__ */ jsxs50("div", { className: "flex-1 min-w-0 flex flex-col gap-base p-base border border-[var(--color-border)] rounded-md bg-[var(--color-secondary,var(--color-accent))]", children: [
7721
+ children,
7722
+ onAddFilter && properties && /* @__PURE__ */ jsx56(
7723
+ PropertySelector,
7724
+ {
7725
+ properties,
7726
+ onSelect: (prop) => {
7727
+ onAddFilter(prop);
7728
+ setAddOpen(false);
7729
+ },
7730
+ open: addOpen,
7731
+ onOpenChange: setAddOpen,
7732
+ children: /* @__PURE__ */ jsxs50(
7733
+ "button",
7734
+ {
7735
+ type: "button",
7736
+ className: "flex items-center gap-sm px-base py-sm text-sm font-semibold leading-sm text-[var(--color-muted-foreground)] cursor-pointer transition-colors rounded-md hover:bg-[var(--color-accent)] hover:text-[var(--color-foreground)] w-fit",
7737
+ children: [
7738
+ /* @__PURE__ */ jsx56(Icon34, { icon: faPlusOutline2, size: "sm" }),
7739
+ "Add filter"
7740
+ ]
7741
+ }
7742
+ )
7743
+ }
7744
+ )
7745
+ ] }),
7746
+ /* @__PURE__ */ jsx56("div", { className: "shrink-0 pt-base", children: /* @__PURE__ */ jsx56(
7747
+ FilterNodeActions,
7035
7748
  {
7036
- sideOffset: 4,
7037
- align: "start",
7038
- collisionPadding: 16,
7039
- onOpenAutoFocus: (e) => e.preventDefault(),
7040
- className: cn(
7041
- "z-50 flex flex-col overflow-clip",
7042
- "bg-[var(--color-dropdown-bg)] border border-[var(--color-dropdown-border)] rounded-md shadow-lg",
7043
- "data-[state=open]:animate-in data-[state=open]:fade-in-0 data-[state=open]:zoom-in-95",
7044
- "data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=closed]:zoom-out-95",
7045
- "data-[side=bottom]:slide-in-from-top-2",
7046
- "w-[min(520px,calc(100vw-32px))]"
7047
- ),
7048
- children: [
7049
- /* @__PURE__ */ jsxs49("div", { className: "flex flex-col gap-base p-base", children: [
7050
- filters.map((filter, i) => {
7051
- const propDef = getPropertyDef(filter.propertyId);
7052
- if (!propDef) return null;
7053
- return /* @__PURE__ */ jsx55(
7054
- AdvancedRow,
7055
- {
7056
- connector: i === 0 ? "Where" : (filter.logicOperator ?? "and") === "and" ? "And" : "Or",
7057
- onConnectorToggle: i > 0 ? () => toggleLogicOp(filter.id) : void 0,
7058
- propertyDef: propDef,
7059
- condition: filter,
7060
- properties,
7061
- onUpdate: handleUpdateFilter,
7062
- onPropertyChange: (p) => handlePropertyChange(filter.id, p),
7063
- onDelete: () => handleDeleteFilter(filter.id)
7064
- },
7065
- filter.id
7066
- );
7067
- }),
7068
- filters.length === 0 && /* ── Draft row: inline "Select property" placeholder ──── */
7069
- /* @__PURE__ */ jsxs49("div", { className: "flex items-center gap-base w-full min-w-0", children: [
7070
- /* @__PURE__ */ jsx55("div", { className: "shrink-0 w-[64px] flex items-center justify-end", children: /* @__PURE__ */ jsx55("span", { className: "text-xs font-semibold leading-xs text-[var(--color-muted-foreground)]", children: "Where" }) }),
7071
- /* @__PURE__ */ jsx55(
7072
- PropertySelector,
7073
- {
7074
- properties,
7075
- onSelect: handleAddFilter,
7076
- open: draftPickerOpen,
7077
- onOpenChange: setDraftPickerOpen,
7078
- children: /* @__PURE__ */ jsxs49(
7079
- "button",
7080
- {
7081
- type: "button",
7082
- className: cn(
7083
- "flex items-center gap-base px-base py-sm min-w-0",
7084
- "bg-gradient-to-t from-[var(--color-btn-outlined-neutral-bg-default)] to-[var(--color-btn-outlined-neutral-bg-gradient-to-default)]",
7085
- "border border-[var(--color-btn-outlined-neutral-border-default)] rounded-md shadow-sm",
7086
- "cursor-pointer transition-colors",
7087
- "hover:from-[var(--color-btn-outlined-neutral-bg-hover)] hover:to-[var(--color-btn-outlined-neutral-bg-gradient-to-hover)]"
7088
- ),
7089
- children: [
7090
- /* @__PURE__ */ jsx55("span", { className: "text-sm font-regular leading-sm text-[var(--color-muted-foreground)] whitespace-nowrap", children: "Select property" }),
7091
- /* @__PURE__ */ jsx55(
7092
- Icon32,
7093
- {
7094
- icon: faChevronDownOutline4,
7095
- size: "xs",
7096
- className: "shrink-0 text-[var(--color-foreground)]"
7097
- }
7098
- )
7099
- ]
7100
- }
7101
- )
7102
- }
7103
- )
7104
- ] })
7105
- ] }),
7106
- /* @__PURE__ */ jsxs49("div", { className: "flex items-center justify-between p-base border-t border-[var(--color-border)]", children: [
7107
- /* @__PURE__ */ jsx55(
7108
- PropertySelector,
7109
- {
7110
- properties,
7111
- onSelect: handleAddFilter,
7112
- open: addSelectorOpen,
7113
- onOpenChange: setAddSelectorOpen,
7114
- children: /* @__PURE__ */ jsxs49(
7115
- "button",
7116
- {
7117
- type: "button",
7118
- className: cn(
7119
- "flex items-center gap-sm px-base py-sm",
7120
- "min-h-[32px] max-h-[32px] min-w-[80px]",
7121
- "bg-gradient-to-t from-[var(--color-btn-outlined-neutral-bg-default)] from-[10%] to-[var(--color-btn-outlined-neutral-bg-gradient-to-default)]",
7122
- "border border-[var(--color-btn-outlined-neutral-border-default)] rounded-md shadow-sm",
7123
- "cursor-pointer transition-colors text-sm font-semibold leading-sm text-[var(--color-foreground)]",
7124
- "hover:from-[var(--color-btn-outlined-neutral-bg-hover)] hover:to-[var(--color-btn-outlined-neutral-bg-gradient-to-hover)]"
7125
- ),
7126
- children: [
7127
- /* @__PURE__ */ jsx55(Icon32, { icon: faPlusOutline3, size: "sm", className: "text-[var(--color-foreground)]" }),
7128
- "Add filter"
7129
- ]
7130
- }
7131
- )
7132
- }
7133
- ),
7134
- filters.length > 0 && /* @__PURE__ */ jsx55(
7135
- "button",
7136
- {
7137
- type: "button",
7138
- onClick: () => {
7139
- onClearAll();
7140
- setOpen(false);
7141
- },
7142
- className: "text-sm font-semibold leading-sm text-[var(--color-foreground)] cursor-pointer transition-colors hover:opacity-70 px-base py-sm",
7143
- children: "Clear all filters"
7144
- }
7145
- )
7146
- ] })
7147
- ]
7749
+ nodeType: "group",
7750
+ onDuplicate,
7751
+ onConvert: onTurnIntoFilter,
7752
+ onDelete
7148
7753
  }
7149
7754
  ) })
7150
7755
  ] });
7151
7756
  };
7152
- SummaryChip.displayName = "SummaryChip";
7153
-
7154
- // src/components/ui/filter/use-filter-bar-mode.ts
7155
- import * as React48 from "react";
7156
- var DEFAULT_BREAKPOINT = 600;
7157
- function useFilterBarMode(ref, override, breakpoint = DEFAULT_BREAKPOINT) {
7158
- const [mode, setMode] = React48.useState("default");
7159
- React48.useEffect(() => {
7160
- if (override) return;
7161
- const el = ref.current;
7162
- if (!el) return;
7163
- const observer = new ResizeObserver((entries) => {
7164
- const width = entries[0]?.contentRect.width ?? 0;
7165
- setMode(width > breakpoint ? "default" : "minimal");
7166
- });
7167
- observer.observe(el);
7168
- return () => observer.disconnect();
7169
- }, [ref, override, breakpoint]);
7170
- return override ?? mode;
7171
- }
7757
+ AdvancedGroup.displayName = "AdvancedGroup";
7172
7758
 
7173
- // src/components/ui/filter/filter-system.tsx
7174
- import { Fragment as Fragment5, jsx as jsx56, jsxs as jsxs50 } from "react/jsx-runtime";
7175
- var FilterSystem = ({
7176
- properties,
7177
- filterState,
7178
- onFilterStateChange,
7179
- sortFields,
7180
- mode: modeOverride,
7181
- breakpoint,
7182
- children,
7183
- actions,
7184
- className
7185
- }) => {
7186
- const containerRef = React49.useRef(null);
7187
- const mode = useFilterBarMode(containerRef, modeOverride, breakpoint);
7188
- const [propertySelectorOpen, setPropertySelectorOpen] = React49.useState(false);
7189
- const [advancedOpen, setAdvancedOpen] = React49.useState(false);
7190
- const [summaryOpen, setSummaryOpen] = React49.useState(false);
7191
- const [pendingFilterId, setPendingFilterId] = React49.useState(null);
7192
- const allFilters = [...filterState.basicFilters, ...filterState.advancedFilters];
7193
- const totalCount = allFilters.length;
7194
- const handleAddFilter = (property) => {
7195
- const newFilter = createFilterWithDefaults(property.id, property.type);
7196
- if (newFilter.operator && isNoValueOperator(newFilter.operator)) {
7197
- onFilterStateChange({
7198
- ...filterState,
7199
- basicFilters: [...filterState.basicFilters, newFilter]
7200
- });
7201
- return;
7202
- }
7203
- setPendingFilterId(newFilter.id);
7204
- onFilterStateChange({
7205
- ...filterState,
7206
- basicFilters: [...filterState.basicFilters, newFilter]
7207
- });
7759
+ // src/components/ui/filter/advanced-popover.tsx
7760
+ import { jsx as jsx57, jsxs as jsxs51 } from "react/jsx-runtime";
7761
+ var ghostBtn = [
7762
+ "flex items-center gap-sm px-base py-sm",
7763
+ "min-h-[32px]",
7764
+ "cursor-pointer transition-colors text-sm font-semibold leading-sm",
7765
+ "rounded-md hover:bg-[var(--color-accent)]"
7766
+ ];
7767
+ var AdvancedPopover = ({
7768
+ filters,
7769
+ properties,
7770
+ onFiltersChange,
7771
+ open,
7772
+ onOpenChange,
7773
+ children
7774
+ }) => {
7775
+ const [addSelectorOpen, setAddSelectorOpen] = React50.useState(false);
7776
+ const [draftPickerOpen, setDraftPickerOpen] = React50.useState(false);
7777
+ const [groupSelectorOpen, setGroupSelectorOpen] = React50.useState(false);
7778
+ const getPropertyDef = (propertyId) => properties.find((p) => p.id === propertyId);
7779
+ const handleAddFilter = (property) => {
7780
+ const newFilter = createFilterWithDefaults(property.id, property.type);
7781
+ onFiltersChange([...filters, newFilter]);
7782
+ setAddSelectorOpen(false);
7208
7783
  };
7209
- const handleUpdateFilter = (updated) => {
7210
- onFilterStateChange({
7211
- ...filterState,
7212
- basicFilters: filterState.basicFilters.map(
7213
- (f) => f.id === updated.id ? updated : f
7214
- )
7215
- });
7216
- if (pendingFilterId === updated.id) {
7217
- setPendingFilterId(null);
7218
- }
7784
+ const handleAddGroup = () => {
7785
+ const group = createEmptyGroup();
7786
+ onFiltersChange([...filters, group]);
7787
+ setGroupSelectorOpen(false);
7219
7788
  };
7220
- const handleDeleteFilter = (id) => {
7221
- onFilterStateChange({
7222
- ...filterState,
7223
- basicFilters: filterState.basicFilters.filter((f) => f.id !== id)
7224
- });
7789
+ const handleClearAll = () => {
7790
+ onFiltersChange([]);
7791
+ onOpenChange?.(false);
7225
7792
  };
7226
- const handlePropertyChange = (filterId, newProp) => {
7227
- const newCondition = createFilterWithDefaults(newProp.id, newProp.type);
7228
- onFilterStateChange({
7229
- ...filterState,
7230
- basicFilters: filterState.basicFilters.map(
7231
- (f) => f.id === filterId ? { ...newCondition, id: filterId } : f
7232
- )
7233
- });
7234
- if (newCondition.operator && !isNoValueOperator(newCondition.operator)) {
7235
- setPendingFilterId(filterId);
7236
- }
7793
+ const handleUpdateNode = (id, updated) => {
7794
+ onFiltersChange(updateNodeInTree(filters, id, () => updated));
7237
7795
  };
7238
- const handleConvertToAdvanced = (id) => {
7239
- const filter = filterState.basicFilters.find((f) => f.id === id);
7240
- if (!filter) return;
7241
- onFilterStateChange({
7242
- ...filterState,
7243
- basicFilters: filterState.basicFilters.filter((f) => f.id !== id),
7244
- advancedFilters: [...filterState.advancedFilters, filter]
7245
- });
7796
+ const handleDeleteNode = (id) => {
7797
+ onFiltersChange(removeNodeFromTree(filters, id));
7246
7798
  };
7247
- const handleAdvancedFiltersChange = (filters) => {
7248
- onFilterStateChange({ ...filterState, advancedFilters: filters });
7799
+ const handleDuplicateNode = (id) => {
7800
+ const find = (nodes) => {
7801
+ for (const n of nodes) {
7802
+ if (n.id === id) return n;
7803
+ if (isFilterGroup(n)) {
7804
+ const found = find(n.children);
7805
+ if (found) return found;
7806
+ }
7807
+ }
7808
+ };
7809
+ const node = find(filters);
7810
+ if (!node) return;
7811
+ const clone = duplicateNode(node);
7812
+ clone.logicOperator = node.logicOperator ?? "and";
7813
+ onFiltersChange(insertAfterInTree(filters, id, clone));
7249
7814
  };
7250
- const handleClearAdvanced = () => {
7251
- onFilterStateChange({ ...filterState, advancedFilters: [] });
7815
+ const handleWrapInGroup = (id) => {
7816
+ const find = (nodes) => {
7817
+ for (const n of nodes) {
7818
+ if (n.id === id && !isFilterGroup(n)) return n;
7819
+ if (isFilterGroup(n)) {
7820
+ const found = find(n.children);
7821
+ if (found) return found;
7822
+ }
7823
+ }
7824
+ };
7825
+ const condition = find(filters);
7826
+ if (!condition) return;
7827
+ const group = wrapInGroup(condition);
7828
+ onFiltersChange(replaceNodeInTree(filters, id, group));
7252
7829
  };
7253
- const handleClearAll = () => {
7254
- onFilterStateChange({
7255
- ...filterState,
7256
- basicFilters: [],
7257
- advancedFilters: []
7258
- });
7830
+ const handleUnwrapGroup = (id) => {
7831
+ const find = (nodes) => {
7832
+ for (const n of nodes) {
7833
+ if (n.id === id && isFilterGroup(n)) return n;
7834
+ if (isFilterGroup(n)) {
7835
+ const found = find(n.children);
7836
+ if (found) return found;
7837
+ }
7838
+ }
7839
+ };
7840
+ const group = find(filters);
7841
+ if (!group) return;
7842
+ const replacement = unwrapGroup(group);
7843
+ if (replacement) {
7844
+ onFiltersChange(replaceNodeInTree(filters, id, replacement));
7845
+ } else {
7846
+ onFiltersChange(removeNodeFromTree(filters, id));
7847
+ }
7259
7848
  };
7260
- const handleSortChange = (field, direction) => {
7261
- onFilterStateChange({ ...filterState, sort: { field, direction } });
7849
+ const toggleLogicOp = (id) => {
7850
+ onFiltersChange(
7851
+ updateNodeInTree(filters, id, (n) => ({
7852
+ ...n,
7853
+ logicOperator: (n.logicOperator ?? "and") === "and" ? "or" : "and"
7854
+ }))
7855
+ );
7262
7856
  };
7263
- const getPropertyDef = (propertyId) => properties.find((p) => p.id === propertyId);
7264
- const hasAdvanced = filterState.advancedFilters.length > 0;
7265
- const isMinimal = mode === "minimal";
7266
- const handleOpenAdvanced = () => {
7267
- setPropertySelectorOpen(false);
7268
- requestAnimationFrame(() => {
7269
- if (isMinimal) {
7270
- setSummaryOpen(true);
7271
- } else {
7272
- setAdvancedOpen(true);
7273
- }
7274
- });
7857
+ const handleGroupChildrenChange = (groupId, children2) => {
7858
+ onFiltersChange(
7859
+ updateNodeInTree(
7860
+ filters,
7861
+ groupId,
7862
+ (n) => isFilterGroup(n) ? { ...n, children: children2 } : n
7863
+ )
7864
+ );
7275
7865
  };
7276
- const advancedFilterCount = filterState.advancedFilters.length;
7277
- const showAdvancedChip = hasAdvanced || advancedOpen;
7278
- const showSummaryChip = totalCount > 0 || summaryOpen;
7279
- return /* @__PURE__ */ jsxs50(FilterBar, { ref: containerRef, className, children: [
7280
- /* @__PURE__ */ jsxs50(FilterBarLeft, { className: "flex-nowrap flex-1 min-w-0 overflow-x-auto scrollbar-none outline-none [&>*]:shrink-0", children: [
7281
- children,
7282
- sortFields && filterState.sort && /* @__PURE__ */ jsx56(
7283
- SortButton,
7866
+ const renderNode = (node, index) => {
7867
+ const connector = index === 0 ? "Where" : (node.logicOperator ?? "and") === "and" ? "And" : "Or";
7868
+ if (isFilterGroup(node)) {
7869
+ return /* @__PURE__ */ jsx57(
7870
+ AdvancedGroup,
7284
7871
  {
7285
- fields: sortFields,
7286
- activeField: filterState.sort.field,
7287
- direction: filterState.sort.direction,
7288
- onChange: handleSortChange,
7289
- iconOnly: isMinimal
7290
- }
7291
- ),
7292
- isMinimal ? /* @__PURE__ */ jsxs50(Fragment5, { children: [
7293
- /* @__PURE__ */ jsx56(
7294
- "div",
7295
- {
7296
- className: showSummaryChip ? "inline-flex" : "inline-flex w-0 overflow-hidden opacity-0 pointer-events-none",
7297
- "aria-hidden": !showSummaryChip || void 0,
7298
- children: /* @__PURE__ */ jsx56(
7299
- SummaryChip,
7872
+ connector,
7873
+ onConnectorToggle: index > 0 ? () => toggleLogicOp(node.id) : void 0,
7874
+ onDuplicate: () => handleDuplicateNode(node.id),
7875
+ onTurnIntoFilter: () => handleUnwrapGroup(node.id),
7876
+ onDelete: () => handleDeleteNode(node.id),
7877
+ properties,
7878
+ onAddFilter: (prop) => {
7879
+ const newFilter = createFilterWithDefaults(prop.id, prop.type);
7880
+ handleGroupChildrenChange(node.id, [...node.children, newFilter]);
7881
+ },
7882
+ children: node.children.length === 0 ? (
7883
+ /* Draft row in empty group */
7884
+ /* @__PURE__ */ jsx57(
7885
+ DraftRow,
7300
7886
  {
7301
- count: totalCount,
7302
- filters: allFilters,
7303
7887
  properties,
7304
- onFiltersChange: (filters) => {
7305
- onFilterStateChange({
7306
- ...filterState,
7307
- basicFilters: filters,
7308
- advancedFilters: []
7309
- });
7310
- },
7311
- onClearAll: handleClearAll,
7312
- open: summaryOpen,
7313
- onOpenChange: setSummaryOpen
7888
+ onSelect: (prop) => {
7889
+ const newFilter = createFilterWithDefaults(prop.id, prop.type);
7890
+ handleGroupChildrenChange(node.id, [newFilter]);
7891
+ }
7314
7892
  }
7315
7893
  )
7316
- }
7894
+ ) : node.children.map((child, i) => renderNode(child, i))
7895
+ },
7896
+ node.id
7897
+ );
7898
+ }
7899
+ const propDef = getPropertyDef(node.propertyId);
7900
+ if (!propDef) return null;
7901
+ return /* @__PURE__ */ jsx57(
7902
+ AdvancedRow,
7903
+ {
7904
+ connector,
7905
+ onConnectorToggle: index > 0 ? () => toggleLogicOp(node.id) : void 0,
7906
+ propertyDef: propDef,
7907
+ condition: node,
7908
+ properties,
7909
+ onUpdate: (updated) => handleUpdateNode(node.id, updated),
7910
+ onPropertyChange: (p) => {
7911
+ const newCondition = createFilterWithDefaults(p.id, p.type);
7912
+ handleUpdateNode(node.id, { ...newCondition, id: node.id });
7913
+ },
7914
+ onDelete: () => handleDeleteNode(node.id),
7915
+ onDuplicate: () => handleDuplicateNode(node.id),
7916
+ onTurnIntoGroup: () => handleWrapInGroup(node.id)
7917
+ },
7918
+ node.id
7919
+ );
7920
+ };
7921
+ return /* @__PURE__ */ jsxs51(PopoverPrimitive12.Root, { open, onOpenChange, children: [
7922
+ /* @__PURE__ */ jsx57(PopoverPrimitive12.Trigger, { asChild: true, children }),
7923
+ /* @__PURE__ */ jsx57(PopoverPrimitive12.Portal, { children: /* @__PURE__ */ jsxs51(
7924
+ PopoverPrimitive12.Content,
7925
+ {
7926
+ sideOffset: 4,
7927
+ align: "start",
7928
+ collisionPadding: 16,
7929
+ onOpenAutoFocus: (e) => e.preventDefault(),
7930
+ className: cn(
7931
+ "z-50 flex flex-col",
7932
+ "bg-[var(--color-background)] rounded-md shadow-lg",
7933
+ "data-[state=open]:animate-in data-[state=open]:fade-in-0 data-[state=open]:zoom-in-95",
7934
+ "data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=closed]:zoom-out-95",
7935
+ "data-[side=bottom]:slide-in-from-top-2",
7936
+ "w-[min(640px,calc(100vw-32px))]"
7317
7937
  ),
7318
- !showSummaryChip && /* @__PURE__ */ jsx56(
7319
- PropertySelector,
7320
- {
7321
- properties,
7322
- onSelect: handleAddFilter,
7323
- open: propertySelectorOpen,
7324
- onOpenChange: setPropertySelectorOpen,
7325
- onAdvancedFilter: handleOpenAdvanced,
7326
- advancedFilterCount,
7327
- children: /* @__PURE__ */ jsx56(FilterBarButton, { iconOnly: true })
7328
- }
7329
- )
7330
- ] }) : (
7331
- /* ── DEFAULT MODE ────────────────────────────────────── */
7332
- /* @__PURE__ */ jsxs50(Fragment5, { children: [
7333
- /* @__PURE__ */ jsx56(
7334
- AdvancedPopover,
7938
+ children: [
7939
+ /* @__PURE__ */ jsx57("div", { className: "flex flex-col gap-base p-base", children: filters.length > 0 ? filters.map((node, i) => renderNode(node, i)) : /* @__PURE__ */ jsx57(
7940
+ DraftRow,
7335
7941
  {
7336
- filters: filterState.advancedFilters,
7337
7942
  properties,
7338
- onFiltersChange: handleAdvancedFiltersChange,
7339
- open: advancedOpen,
7340
- onOpenChange: setAdvancedOpen,
7341
- children: /* @__PURE__ */ jsx56(
7342
- "div",
7943
+ onSelect: handleAddFilter,
7944
+ open: draftPickerOpen,
7945
+ onOpenChange: setDraftPickerOpen
7946
+ }
7947
+ ) }),
7948
+ /* @__PURE__ */ jsxs51("div", { className: "flex items-center justify-between p-base border-t border-[var(--color-border)]", children: [
7949
+ /* @__PURE__ */ jsxs51("div", { className: "flex items-center gap-sm", children: [
7950
+ /* @__PURE__ */ jsx57(
7951
+ PropertySelector,
7343
7952
  {
7344
- className: showAdvancedChip ? "inline-flex" : "inline-flex w-0 overflow-hidden opacity-0 pointer-events-none",
7345
- "aria-hidden": !showAdvancedChip || void 0,
7346
- children: /* @__PURE__ */ jsx56(
7347
- AdvancedChip,
7348
- {
7349
- count: filterState.advancedFilters.length,
7350
- onClick: () => setAdvancedOpen(true),
7351
- onClear: handleClearAdvanced
7352
- }
7353
- )
7953
+ properties,
7954
+ onSelect: handleAddFilter,
7955
+ open: addSelectorOpen,
7956
+ onOpenChange: setAddSelectorOpen,
7957
+ children: /* @__PURE__ */ jsxs51("button", { type: "button", className: cn(ghostBtn, "text-[var(--color-foreground)]"), children: [
7958
+ /* @__PURE__ */ jsx57(Icon35, { icon: faPlusOutline3, size: "sm", className: "text-[var(--color-foreground)]" }),
7959
+ "Add filter"
7960
+ ] })
7354
7961
  }
7355
- )
7356
- }
7357
- ),
7358
- filterState.basicFilters.map((filter) => {
7359
- const propDef = getPropertyDef(filter.propertyId);
7360
- if (!propDef) return null;
7361
- return /* @__PURE__ */ jsx56(
7362
- InteractiveFilterChip,
7363
- {
7364
- propertyDef: propDef,
7365
- condition: filter,
7366
- properties,
7367
- mode: pendingFilterId === filter.id ? "add" : "edit",
7368
- autoOpen: pendingFilterId === filter.id,
7369
- onUpdate: handleUpdateFilter,
7370
- onPropertyChange: (newProp) => handlePropertyChange(filter.id, newProp),
7371
- onDelete: () => handleDeleteFilter(filter.id),
7372
- onConvertToAdvanced: () => handleConvertToAdvanced(filter.id)
7373
- },
7374
- filter.id
7375
- );
7376
- }),
7377
- /* @__PURE__ */ jsx56(
7378
- PropertySelector,
7379
- {
7380
- properties,
7381
- onSelect: handleAddFilter,
7382
- open: propertySelectorOpen,
7383
- onOpenChange: setPropertySelectorOpen,
7384
- onAdvancedFilter: handleOpenAdvanced,
7385
- advancedFilterCount,
7386
- children: totalCount > 0 ? /* @__PURE__ */ jsx56(
7962
+ ),
7963
+ /* @__PURE__ */ jsxs51(
7387
7964
  "button",
7388
7965
  {
7389
7966
  type: "button",
7390
- className: "shrink-0 inline-flex items-center justify-center size-8 rounded-md border border-[var(--color-btn-outlined-neutral-border-default)] bg-gradient-to-t from-[var(--color-btn-outlined-neutral-bg-default)] from-[10%] to-[var(--color-btn-outlined-neutral-bg-gradient-to-default)] shadow-sm cursor-pointer transition-colors hover:from-[var(--color-btn-outlined-neutral-bg-hover)] hover:to-[var(--color-btn-outlined-neutral-bg-gradient-to-hover)]",
7391
- children: /* @__PURE__ */ jsx56(Icon33, { icon: faPlusOutline4, size: "sm", className: "text-[var(--color-foreground)]" })
7967
+ onClick: handleAddGroup,
7968
+ className: cn(ghostBtn, "text-[var(--color-foreground)]"),
7969
+ children: [
7970
+ /* @__PURE__ */ jsx57(Icon35, { icon: faPlusOutline3, size: "sm", className: "text-[var(--color-foreground)]" }),
7971
+ "Add filters group"
7972
+ ]
7392
7973
  }
7393
- ) : /* @__PURE__ */ jsx56(FilterBarButton, {})
7394
- }
7395
- )
7396
- ] })
7397
- ),
7398
- totalCount > 0 && /* @__PURE__ */ jsx56(
7399
- "button",
7400
- {
7401
- type: "button",
7402
- onClick: handleClearAll,
7403
- className: "shrink-0 flex items-center gap-sm px-base py-sm min-h-[32px] max-h-[32px] rounded-md cursor-pointer transition-colors hover:bg-[var(--color-accent)]",
7404
- children: isMinimal ? /* @__PURE__ */ jsx56(Icon33, { icon: faXmarkOutline4, size: "sm", className: "text-[var(--color-foreground)]" }) : /* @__PURE__ */ jsx56("span", { className: "text-sm font-semibold leading-sm text-[var(--color-foreground)]", children: "Clear" })
7405
- }
7406
- )
7407
- ] }),
7408
- actions && /* @__PURE__ */ jsx56(FilterBarRight, { className: "shrink-0 -ml-2xl pl-2xl relative z-10 bg-[linear-gradient(to_right,transparent_0px,var(--filter-bar-bg,var(--color-background,#fff))_24px)]", children: actions })
7974
+ )
7975
+ ] }),
7976
+ filters.length > 0 && /* @__PURE__ */ jsxs51(
7977
+ "button",
7978
+ {
7979
+ type: "button",
7980
+ onClick: handleClearAll,
7981
+ className: cn(ghostBtn, "text-[var(--color-destructive,#ef4444)]"),
7982
+ children: [
7983
+ /* @__PURE__ */ jsx57(Icon35, { icon: faXmarkOutline3, size: "sm", className: "text-[var(--color-destructive,#ef4444)]" }),
7984
+ "Clear filters"
7985
+ ]
7986
+ }
7987
+ )
7988
+ ] })
7989
+ ]
7990
+ }
7991
+ ) })
7992
+ ] });
7993
+ };
7994
+ AdvancedPopover.displayName = "AdvancedPopover";
7995
+ var DraftRow = ({
7996
+ properties,
7997
+ onSelect,
7998
+ open: openProp,
7999
+ onOpenChange
8000
+ }) => {
8001
+ const [internalOpen, setInternalOpen] = React50.useState(false);
8002
+ const isControlled = openProp !== void 0;
8003
+ const open = isControlled ? openProp : internalOpen;
8004
+ const setOpen = (v) => {
8005
+ if (!isControlled) setInternalOpen(v);
8006
+ onOpenChange?.(v);
8007
+ };
8008
+ return /* @__PURE__ */ jsxs51("div", { className: "flex items-center gap-base w-full min-w-0", children: [
8009
+ /* @__PURE__ */ jsx57("div", { className: "shrink-0 w-[64px] flex items-center justify-end", children: /* @__PURE__ */ jsx57("span", { className: "text-xs font-semibold leading-xs text-[var(--color-muted-foreground)]", children: "Where" }) }),
8010
+ /* @__PURE__ */ jsx57(
8011
+ PropertySelector,
8012
+ {
8013
+ properties,
8014
+ onSelect: (prop) => {
8015
+ onSelect(prop);
8016
+ setOpen(false);
8017
+ },
8018
+ open,
8019
+ onOpenChange: setOpen,
8020
+ children: /* @__PURE__ */ jsxs51(
8021
+ "button",
8022
+ {
8023
+ type: "button",
8024
+ className: cn(
8025
+ "flex items-center gap-base px-base py-sm min-w-0",
8026
+ "bg-gradient-to-t from-[var(--color-btn-outlined-neutral-bg-default)] to-[var(--color-btn-outlined-neutral-bg-gradient-to-default)]",
8027
+ "border border-[var(--color-btn-outlined-neutral-border-default)] rounded-md shadow-sm",
8028
+ "cursor-pointer transition-colors",
8029
+ "hover:from-[var(--color-btn-outlined-neutral-bg-hover)] hover:to-[var(--color-btn-outlined-neutral-bg-gradient-to-hover)]"
8030
+ ),
8031
+ children: [
8032
+ /* @__PURE__ */ jsx57("span", { className: "text-sm font-regular leading-sm text-[var(--color-muted-foreground)] whitespace-nowrap", children: "Select property" }),
8033
+ /* @__PURE__ */ jsx57(
8034
+ Icon35,
8035
+ {
8036
+ icon: faChevronDownOutline3,
8037
+ size: "xs",
8038
+ className: "shrink-0 text-[var(--color-foreground)]"
8039
+ }
8040
+ )
8041
+ ]
8042
+ }
8043
+ )
8044
+ }
8045
+ )
7409
8046
  ] });
7410
8047
  };
7411
- FilterSystem.displayName = "FilterSystem";
7412
8048
 
7413
- // src/components/ui/date-picker.tsx
7414
- import * as React50 from "react";
7415
- import * as PopoverPrimitive12 from "@radix-ui/react-popover";
7416
- import {
7417
- Icon as Icon34,
7418
- faChevronLeftOutline as faChevronLeftOutline3,
7419
- faChevronRightOutline as faChevronRightOutline3,
7420
- faArrowRightOutline as faArrowRightOutline2,
7421
- faCalendarOutline
7422
- } from "@l3mpire/icons";
7423
- import { jsx as jsx57, jsxs as jsxs51 } from "react/jsx-runtime";
7424
- function getDaysInMonth(year, month) {
7425
- return new Date(year, month + 1, 0).getDate();
7426
- }
7427
- function getWeekdayIndex(date) {
7428
- return (date.getDay() + 6) % 7;
7429
- }
7430
- function isSameDay(a, b) {
7431
- return a.getFullYear() === b.getFullYear() && a.getMonth() === b.getMonth() && a.getDate() === b.getDate();
7432
- }
7433
- function isInRange(date, from, to) {
7434
- const t = date.getTime();
7435
- return t >= from.getTime() && t <= to.getTime();
7436
- }
7437
- function startOfDay(d) {
7438
- return new Date(d.getFullYear(), d.getMonth(), d.getDate());
7439
- }
7440
- var WEEKDAYS = ["Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"];
7441
- var MONTH_NAMES = [
7442
- "January",
7443
- "February",
7444
- "March",
7445
- "April",
7446
- "May",
7447
- "June",
7448
- "July",
7449
- "August",
7450
- "September",
7451
- "October",
7452
- "November",
7453
- "December"
8049
+ // src/components/ui/filter/summary-chip.tsx
8050
+ import * as React51 from "react";
8051
+ import * as PopoverPrimitive13 from "@radix-ui/react-popover";
8052
+ import { Icon as Icon36, faSlidersOutline as faSlidersOutline2, faPlusOutline as faPlusOutline4, faChevronDownOutline as faChevronDownOutline4, faXmarkOutline as faXmarkOutline4 } from "@l3mpire/icons";
8053
+ import { jsx as jsx58, jsxs as jsxs52 } from "react/jsx-runtime";
8054
+ var ghostBtn2 = [
8055
+ "flex items-center gap-sm px-base py-sm",
8056
+ "min-h-[32px]",
8057
+ "cursor-pointer transition-colors text-sm font-semibold leading-sm",
8058
+ "rounded-md hover:bg-[var(--color-accent)]"
7454
8059
  ];
7455
- var DatePickerContext = React50.createContext(
7456
- null
7457
- );
7458
- function useDatePickerContext() {
7459
- const ctx = React50.useContext(DatePickerContext);
7460
- if (!ctx)
7461
- throw new Error("DatePicker compound components must be used within <DatePicker>");
7462
- return ctx;
7463
- }
7464
- var DatePicker = React50.forwardRef(
7465
- ({
7466
- className,
7467
- mode = "single",
7468
- value,
7469
- onValueChange,
7470
- defaultMonth,
7471
- defaultYear,
7472
- children,
7473
- ...props
7474
- }, ref) => {
7475
- const today = React50.useMemo(() => startOfDay(/* @__PURE__ */ new Date()), []);
7476
- const initialDate = React50.useMemo(() => {
7477
- if (value) {
7478
- if (value instanceof Date) return value;
7479
- return value.from;
7480
- }
7481
- return today;
7482
- }, []);
7483
- const [month, setMonth] = React50.useState(
7484
- defaultMonth ?? initialDate.getMonth()
7485
- );
7486
- const [year, setYear] = React50.useState(
7487
- defaultYear ?? initialDate.getFullYear()
7488
- );
7489
- const [hoveredDate, setHoveredDate] = React50.useState();
7490
- const goToPrevMonth = React50.useCallback(() => {
7491
- setMonth((m) => {
7492
- if (m === 0) {
7493
- setYear((y) => y - 1);
7494
- return 11;
7495
- }
7496
- return m - 1;
7497
- });
7498
- }, []);
7499
- const goToNextMonth = React50.useCallback(() => {
7500
- setMonth((m) => {
7501
- if (m === 11) {
7502
- setYear((y) => y + 1);
7503
- return 0;
7504
- }
7505
- return m + 1;
7506
- });
7507
- }, []);
7508
- const onSelect = React50.useCallback(
7509
- (date) => {
7510
- if (mode === "single") {
7511
- onValueChange?.(date);
7512
- return;
8060
+ var SummaryChip = ({
8061
+ count,
8062
+ filters,
8063
+ properties,
8064
+ onFiltersChange,
8065
+ onClearAll,
8066
+ children,
8067
+ className,
8068
+ open: openProp,
8069
+ onOpenChange
8070
+ }) => {
8071
+ const [uncontrolledOpen, setUncontrolledOpen] = React51.useState(false);
8072
+ const isControlled = openProp !== void 0;
8073
+ const open = isControlled ? openProp : uncontrolledOpen;
8074
+ const setOpen = (v) => {
8075
+ if (!isControlled) setUncontrolledOpen(v);
8076
+ onOpenChange?.(v);
8077
+ };
8078
+ const [addSelectorOpen, setAddSelectorOpen] = React51.useState(false);
8079
+ const [draftPickerOpen, setDraftPickerOpen] = React51.useState(false);
8080
+ const getPropertyDef = (propertyId) => properties.find((p) => p.id === propertyId);
8081
+ const handleAddFilter = (property) => {
8082
+ const newFilter = createFilterWithDefaults(property.id, property.type);
8083
+ onFiltersChange([...filters, newFilter]);
8084
+ setAddSelectorOpen(false);
8085
+ };
8086
+ const handleAddGroup = () => {
8087
+ onFiltersChange([...filters, createEmptyGroup()]);
8088
+ };
8089
+ const handleUpdateNode = (id, updated) => {
8090
+ onFiltersChange(updateNodeInTree(filters, id, () => updated));
8091
+ };
8092
+ const handleDeleteNode = (id) => {
8093
+ const next = removeNodeFromTree(filters, id);
8094
+ onFiltersChange(next);
8095
+ if (next.length === 0) setOpen(false);
8096
+ };
8097
+ const handleDuplicateNode = (id) => {
8098
+ const find = (nodes) => {
8099
+ for (const n of nodes) {
8100
+ if (n.id === id) return n;
8101
+ if (isFilterGroup(n)) {
8102
+ const f = find(n.children);
8103
+ if (f) return f;
7513
8104
  }
7514
- if (!value || value instanceof Date) {
7515
- onValueChange?.({ from: date });
7516
- return;
8105
+ }
8106
+ };
8107
+ const node = find(filters);
8108
+ if (!node) return;
8109
+ const clone = duplicateNode(node);
8110
+ clone.logicOperator = node.logicOperator ?? "and";
8111
+ onFiltersChange(insertAfterInTree(filters, id, clone));
8112
+ };
8113
+ const handleWrapInGroup = (id) => {
8114
+ const find = (nodes) => {
8115
+ for (const n of nodes) {
8116
+ if (n.id === id && !isFilterGroup(n)) return n;
8117
+ if (isFilterGroup(n)) {
8118
+ const f = find(n.children);
8119
+ if (f) return f;
7517
8120
  }
7518
- const range = value;
7519
- if (range.to || date.getTime() < range.from.getTime()) {
7520
- onValueChange?.({ from: date });
7521
- } else {
7522
- onValueChange?.({ from: range.from, to: date });
8121
+ }
8122
+ };
8123
+ const condition = find(filters);
8124
+ if (!condition) return;
8125
+ onFiltersChange(replaceNodeInTree(filters, id, wrapInGroup(condition)));
8126
+ };
8127
+ const handleUnwrapGroup = (id) => {
8128
+ const find = (nodes) => {
8129
+ for (const n of nodes) {
8130
+ if (n.id === id && isFilterGroup(n)) return n;
8131
+ if (isFilterGroup(n)) {
8132
+ const f = find(n.children);
8133
+ if (f) return f;
7523
8134
  }
7524
- },
7525
- [mode, value, onValueChange]
8135
+ }
8136
+ };
8137
+ const group = find(filters);
8138
+ if (!group) return;
8139
+ const replacement = unwrapGroup(group);
8140
+ if (replacement) {
8141
+ onFiltersChange(replaceNodeInTree(filters, id, replacement));
8142
+ } else {
8143
+ onFiltersChange(removeNodeFromTree(filters, id));
8144
+ }
8145
+ };
8146
+ const toggleLogicOp = (id) => {
8147
+ onFiltersChange(
8148
+ updateNodeInTree(filters, id, (n) => ({
8149
+ ...n,
8150
+ logicOperator: (n.logicOperator ?? "and") === "and" ? "or" : "and"
8151
+ }))
7526
8152
  );
7527
- const ctxValue = React50.useMemo(
7528
- () => ({
7529
- mode,
7530
- selected: value,
7531
- onSelect,
7532
- month,
7533
- year,
7534
- setMonth,
7535
- setYear,
7536
- goToPrevMonth,
7537
- goToNextMonth,
7538
- today,
7539
- hoveredDate,
7540
- setHoveredDate
7541
- }),
7542
- [
7543
- mode,
7544
- value,
7545
- onSelect,
7546
- month,
7547
- year,
7548
- goToPrevMonth,
7549
- goToNextMonth,
7550
- today,
7551
- hoveredDate
7552
- ]
8153
+ };
8154
+ const handleGroupChildrenChange = (groupId, newChildren) => {
8155
+ onFiltersChange(
8156
+ updateNodeInTree(
8157
+ filters,
8158
+ groupId,
8159
+ (n) => isFilterGroup(n) ? { ...n, children: newChildren } : n
8160
+ )
7553
8161
  );
7554
- return /* @__PURE__ */ jsx57(DatePickerContext.Provider, { value: ctxValue, children: /* @__PURE__ */ jsx57(
7555
- "div",
8162
+ };
8163
+ const renderNode = (node, index) => {
8164
+ const connector = index === 0 ? "Where" : (node.logicOperator ?? "and") === "and" ? "And" : "Or";
8165
+ if (isFilterGroup(node)) {
8166
+ return /* @__PURE__ */ jsx58(
8167
+ AdvancedGroup,
8168
+ {
8169
+ connector,
8170
+ onConnectorToggle: index > 0 ? () => toggleLogicOp(node.id) : void 0,
8171
+ onDuplicate: () => handleDuplicateNode(node.id),
8172
+ onTurnIntoFilter: () => handleUnwrapGroup(node.id),
8173
+ onDelete: () => handleDeleteNode(node.id),
8174
+ properties,
8175
+ onAddFilter: (prop) => {
8176
+ const newFilter = createFilterWithDefaults(prop.id, prop.type);
8177
+ handleGroupChildrenChange(node.id, [...node.children, newFilter]);
8178
+ },
8179
+ children: node.children.length === 0 ? /* @__PURE__ */ jsx58(
8180
+ DraftRow2,
8181
+ {
8182
+ properties,
8183
+ onSelect: (prop) => {
8184
+ const newFilter = createFilterWithDefaults(prop.id, prop.type);
8185
+ handleGroupChildrenChange(node.id, [newFilter]);
8186
+ }
8187
+ }
8188
+ ) : node.children.map((child, i) => renderNode(child, i))
8189
+ },
8190
+ node.id
8191
+ );
8192
+ }
8193
+ const propDef = getPropertyDef(node.propertyId);
8194
+ if (!propDef) return null;
8195
+ return /* @__PURE__ */ jsx58(
8196
+ AdvancedRow,
7556
8197
  {
7557
- ref,
8198
+ connector,
8199
+ onConnectorToggle: index > 0 ? () => toggleLogicOp(node.id) : void 0,
8200
+ propertyDef: propDef,
8201
+ condition: node,
8202
+ properties,
8203
+ onUpdate: (updated) => handleUpdateNode(node.id, updated),
8204
+ onPropertyChange: (p) => {
8205
+ const newCondition = createFilterWithDefaults(p.id, p.type);
8206
+ handleUpdateNode(node.id, { ...newCondition, id: node.id });
8207
+ },
8208
+ onDelete: () => handleDeleteNode(node.id),
8209
+ onDuplicate: () => handleDuplicateNode(node.id),
8210
+ onTurnIntoGroup: () => handleWrapInGroup(node.id)
8211
+ },
8212
+ node.id
8213
+ );
8214
+ };
8215
+ return /* @__PURE__ */ jsxs52(PopoverPrimitive13.Root, { open, onOpenChange: setOpen, children: [
8216
+ /* @__PURE__ */ jsx58(PopoverPrimitive13.Trigger, { asChild: true, children: children ?? /* @__PURE__ */ jsxs52(
8217
+ "button",
8218
+ {
8219
+ type: "button",
7558
8220
  className: cn(
7559
- "flex flex-col overflow-clip",
7560
- "bg-datepicker-bg border border-datepicker-border rounded-md shadow-lg",
8221
+ "inline-flex items-center gap-sm px-base py-sm",
8222
+ "min-h-[32px] max-h-[32px]",
8223
+ "bg-gradient-to-t from-[var(--color-btn-outlined-neutral-bg-default)] from-[10%] to-[var(--color-btn-outlined-neutral-bg-gradient-to-default)]",
8224
+ "border border-[var(--color-btn-outlined-neutral-border-default)] rounded-md shadow-sm",
8225
+ "cursor-pointer transition-colors",
8226
+ "hover:from-[var(--color-btn-outlined-neutral-bg-hover)] hover:to-[var(--color-btn-outlined-neutral-bg-gradient-to-hover)]",
7561
8227
  className
7562
8228
  ),
7563
- ...props,
7564
- children
8229
+ children: [
8230
+ /* @__PURE__ */ jsx58(Icon36, { icon: faSlidersOutline2, size: "sm", className: "shrink-0 text-[var(--color-foreground)]" }),
8231
+ /* @__PURE__ */ jsx58("span", { className: "text-sm font-semibold leading-sm whitespace-nowrap text-[var(--color-foreground)]", children: "Filters" }),
8232
+ count > 0 && /* @__PURE__ */ jsx58("span", { className: "flex items-center p-2xs rounded-xs bg-filter-chip-badge-bg", children: /* @__PURE__ */ jsx58("span", { className: "text-[10px] font-semibold leading-2xs text-filter-chip-badge-text", children: count }) })
8233
+ ]
8234
+ }
8235
+ ) }),
8236
+ /* @__PURE__ */ jsx58(PopoverPrimitive13.Portal, { children: /* @__PURE__ */ jsxs52(
8237
+ PopoverPrimitive13.Content,
8238
+ {
8239
+ sideOffset: 4,
8240
+ align: "start",
8241
+ collisionPadding: 16,
8242
+ onOpenAutoFocus: (e) => e.preventDefault(),
8243
+ className: cn(
8244
+ "z-50 flex flex-col overflow-clip",
8245
+ "bg-[var(--color-dropdown-bg)] border border-[var(--color-dropdown-border)] rounded-md shadow-lg",
8246
+ "data-[state=open]:animate-in data-[state=open]:fade-in-0 data-[state=open]:zoom-in-95",
8247
+ "data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=closed]:zoom-out-95",
8248
+ "data-[side=bottom]:slide-in-from-top-2",
8249
+ "w-[min(640px,calc(100vw-32px))]"
8250
+ ),
8251
+ children: [
8252
+ /* @__PURE__ */ jsx58("div", { className: "flex flex-col gap-base p-base", children: filters.length > 0 ? filters.map((node, i) => renderNode(node, i)) : /* @__PURE__ */ jsx58(
8253
+ DraftRow2,
8254
+ {
8255
+ properties,
8256
+ onSelect: handleAddFilter,
8257
+ open: draftPickerOpen,
8258
+ onOpenChange: setDraftPickerOpen
8259
+ }
8260
+ ) }),
8261
+ /* @__PURE__ */ jsxs52("div", { className: "flex items-center justify-between p-base border-t border-[var(--color-border)]", children: [
8262
+ /* @__PURE__ */ jsxs52("div", { className: "flex items-center gap-sm", children: [
8263
+ /* @__PURE__ */ jsx58(
8264
+ PropertySelector,
8265
+ {
8266
+ properties,
8267
+ onSelect: handleAddFilter,
8268
+ open: addSelectorOpen,
8269
+ onOpenChange: setAddSelectorOpen,
8270
+ children: /* @__PURE__ */ jsxs52("button", { type: "button", className: cn(ghostBtn2, "text-[var(--color-foreground)]"), children: [
8271
+ /* @__PURE__ */ jsx58(Icon36, { icon: faPlusOutline4, size: "sm", className: "text-[var(--color-foreground)]" }),
8272
+ "Add filter"
8273
+ ] })
8274
+ }
8275
+ ),
8276
+ /* @__PURE__ */ jsxs52("button", { type: "button", onClick: handleAddGroup, className: cn(ghostBtn2, "text-[var(--color-foreground)]"), children: [
8277
+ /* @__PURE__ */ jsx58(Icon36, { icon: faPlusOutline4, size: "sm", className: "text-[var(--color-foreground)]" }),
8278
+ "Add filters group"
8279
+ ] })
8280
+ ] }),
8281
+ filters.length > 0 && /* @__PURE__ */ jsxs52(
8282
+ "button",
8283
+ {
8284
+ type: "button",
8285
+ onClick: () => {
8286
+ onClearAll();
8287
+ setOpen(false);
8288
+ },
8289
+ className: cn(ghostBtn2, "text-[var(--color-destructive,#ef4444)]"),
8290
+ children: [
8291
+ /* @__PURE__ */ jsx58(Icon36, { icon: faXmarkOutline4, size: "sm", className: "text-[var(--color-destructive,#ef4444)]" }),
8292
+ "Clear filters"
8293
+ ]
8294
+ }
8295
+ )
8296
+ ] })
8297
+ ]
8298
+ }
8299
+ ) })
8300
+ ] });
8301
+ };
8302
+ SummaryChip.displayName = "SummaryChip";
8303
+ var DraftRow2 = ({ properties, onSelect, open: openProp, onOpenChange }) => {
8304
+ const [internalOpen, setInternalOpen] = React51.useState(false);
8305
+ const isCtrl = openProp !== void 0;
8306
+ const open = isCtrl ? openProp : internalOpen;
8307
+ const setOpen = (v) => {
8308
+ if (!isCtrl) setInternalOpen(v);
8309
+ onOpenChange?.(v);
8310
+ };
8311
+ return /* @__PURE__ */ jsxs52("div", { className: "flex items-center gap-base w-full min-w-0", children: [
8312
+ /* @__PURE__ */ jsx58("div", { className: "shrink-0 w-[64px] flex items-center justify-end", children: /* @__PURE__ */ jsx58("span", { className: "text-xs font-semibold leading-xs text-[var(--color-muted-foreground)]", children: "Where" }) }),
8313
+ /* @__PURE__ */ jsx58(PropertySelector, { properties, onSelect: (p) => {
8314
+ onSelect(p);
8315
+ setOpen(false);
8316
+ }, open, onOpenChange: setOpen, children: /* @__PURE__ */ jsxs52(
8317
+ "button",
8318
+ {
8319
+ type: "button",
8320
+ className: cn(
8321
+ "flex items-center gap-base px-base py-sm min-w-0",
8322
+ "bg-gradient-to-t from-[var(--color-btn-outlined-neutral-bg-default)] to-[var(--color-btn-outlined-neutral-bg-gradient-to-default)]",
8323
+ "border border-[var(--color-btn-outlined-neutral-border-default)] rounded-md shadow-sm cursor-pointer transition-colors",
8324
+ "hover:from-[var(--color-btn-outlined-neutral-bg-hover)] hover:to-[var(--color-btn-outlined-neutral-bg-gradient-to-hover)]"
8325
+ ),
8326
+ children: [
8327
+ /* @__PURE__ */ jsx58("span", { className: "text-sm font-regular leading-sm text-[var(--color-muted-foreground)] whitespace-nowrap", children: "Select property" }),
8328
+ /* @__PURE__ */ jsx58(Icon36, { icon: faChevronDownOutline4, size: "xs", className: "shrink-0 text-[var(--color-foreground)]" })
8329
+ ]
7565
8330
  }
7566
- ) });
7567
- }
7568
- );
7569
- DatePicker.displayName = "DatePicker";
7570
- function defaultFormatDate(date) {
7571
- return date.toLocaleDateString("en-US", {
7572
- month: "short",
7573
- day: "numeric",
7574
- year: "numeric"
7575
- });
7576
- }
7577
- var DatePickerSelects = React50.forwardRef(({ className, formatDate = defaultFormatDate, ...props }, ref) => {
7578
- const { selected } = useDatePickerContext();
7579
- const fromDate = selected instanceof Date ? selected : selected?.from;
7580
- const toDate = selected instanceof Date ? void 0 : selected?.to;
7581
- return /* @__PURE__ */ jsx57(
7582
- "div",
7583
- {
7584
- ref,
7585
- className: cn("flex flex-col items-start pt-lg px-lg", className),
7586
- ...props,
7587
- children: /* @__PURE__ */ jsxs51("div", { className: "flex items-center gap-base w-full", children: [
7588
- /* @__PURE__ */ jsxs51("div", { className: "flex-1 flex items-center gap-base min-w-0 px-base py-sm bg-gradient-to-t from-[var(--color-select-bg-default)] to-[var(--color-select-bg-gradient-to)] border border-[var(--color-select-border-default)] rounded-base shadow-sm", children: [
7589
- /* @__PURE__ */ jsx57("span", { className: "flex-1 text-sm font-regular leading-sm text-datepicker-header-text truncate", children: fromDate ? formatDate(fromDate) : "Start date" }),
7590
- /* @__PURE__ */ jsx57(Icon34, { icon: faCalendarOutline, size: "sm", className: "shrink-0 text-datepicker-header-text" })
7591
- ] }),
7592
- /* @__PURE__ */ jsx57(
7593
- Icon34,
7594
- {
7595
- icon: faArrowRightOutline2,
7596
- size: "sm",
7597
- className: "shrink-0 text-datepicker-header-weekday"
7598
- }
7599
- ),
7600
- /* @__PURE__ */ jsxs51("div", { className: "flex-1 flex items-center gap-base min-w-0 px-base py-sm bg-gradient-to-t from-[var(--color-select-bg-default)] to-[var(--color-select-bg-gradient-to)] border border-[var(--color-select-border-default)] rounded-base shadow-sm", children: [
7601
- /* @__PURE__ */ jsx57("span", { className: "flex-1 text-sm font-regular leading-sm text-datepicker-header-text truncate", children: toDate ? formatDate(toDate) : "End date" }),
7602
- /* @__PURE__ */ jsx57(Icon34, { icon: faCalendarOutline, size: "sm", className: "shrink-0 text-datepicker-header-text" })
7603
- ] })
7604
- ] })
7605
- }
7606
- );
7607
- });
7608
- DatePickerSelects.displayName = "DatePickerSelects";
7609
- var DatePickerDay = ({ date, isOutside }) => {
7610
- const { mode, selected, onSelect, today, hoveredDate, setHoveredDate } = useDatePickerContext();
7611
- const isToday = isSameDay(date, today);
7612
- const isSelected = selected instanceof Date ? isSameDay(date, selected) : selected?.from ? isSameDay(date, selected.from) || (selected.to ? isSameDay(date, selected.to) : false) : false;
7613
- const isRangeStart = mode === "range" && selected && !(selected instanceof Date) && selected.from && isSameDay(date, selected.from);
7614
- const isRangeEnd = mode === "range" && selected && !(selected instanceof Date) && selected.to && isSameDay(date, selected.to);
7615
- const inRange = mode === "range" && selected && !(selected instanceof Date) && selected.from && selected.to && !isSelected && isInRange(date, selected.from, selected.to);
7616
- const inPreviewRange = mode === "range" && selected && !(selected instanceof Date) && selected.from && !selected.to && hoveredDate && !isSelected && hoveredDate.getTime() > selected.from.getTime() && isInRange(date, selected.from, hoveredDate);
7617
- const isInRangeOrPreview = inRange || inPreviewRange;
7618
- return /* @__PURE__ */ jsxs51(
7619
- "button",
7620
- {
7621
- type: "button",
7622
- onClick: () => !isOutside && onSelect(date),
7623
- onMouseEnter: () => mode === "range" && setHoveredDate(date),
7624
- onMouseLeave: () => mode === "range" && setHoveredDate(void 0),
7625
- disabled: isOutside,
7626
- className: cn(
7627
- "relative flex flex-col items-center justify-center w-9 rounded-full p-2 cursor-pointer transition-colors",
7628
- "text-sm font-semibold leading-sm text-center",
7629
- // Default
7630
- !isOutside && !isSelected && !isInRangeOrPreview && "text-datepicker-day-text-default hover:bg-datepicker-day-bg-hover",
7631
- // Outside month (disabled)
7632
- isOutside && "text-datepicker-day-text-disabled cursor-default",
7633
- // Selected
7634
- isSelected && "bg-datepicker-day-bg-selected text-datepicker-day-text-selected",
7635
- // In range
7636
- isInRangeOrPreview && "bg-datepicker-day-bg-range text-datepicker-day-text-range",
7637
- // Range start/end get full rounded; in-range items could be less rounded
7638
- (isRangeStart || isRangeEnd) && "rounded-full"
7639
- ),
7640
- children: [
7641
- date.getDate(),
7642
- isToday && !isOutside && /* @__PURE__ */ jsx57("span", { className: "absolute bottom-0.5 left-1/2 -translate-x-1/2 size-1.5 rounded-full bg-datepicker-day-today" })
7643
- ]
7644
- }
7645
- );
8331
+ ) })
8332
+ ] });
7646
8333
  };
7647
- var DatePickerCalendar = React50.forwardRef(({ className, header, ...props }, ref) => {
7648
- const { month, year, goToPrevMonth, goToNextMonth } = useDatePickerContext();
7649
- const weeks = React50.useMemo(() => {
7650
- const firstDay = new Date(year, month, 1);
7651
- const startOffset = getWeekdayIndex(firstDay);
7652
- const daysInMonth = getDaysInMonth(year, month);
7653
- const daysInPrevMonth = getDaysInMonth(
7654
- month === 0 ? year - 1 : year,
7655
- month === 0 ? 11 : month - 1
7656
- );
7657
- const days = [];
7658
- for (let i = startOffset - 1; i >= 0; i--) {
7659
- const d = daysInPrevMonth - i;
7660
- days.push({
7661
- date: new Date(
7662
- month === 0 ? year - 1 : year,
7663
- month === 0 ? 11 : month - 1,
7664
- d
7665
- ),
7666
- isOutside: true
8334
+
8335
+ // src/components/ui/filter/use-filter-bar-mode.ts
8336
+ import * as React52 from "react";
8337
+ var DEFAULT_BREAKPOINT = 600;
8338
+ function useFilterBarMode(ref, override, breakpoint = DEFAULT_BREAKPOINT) {
8339
+ const [mode, setMode] = React52.useState("default");
8340
+ React52.useEffect(() => {
8341
+ if (override) return;
8342
+ const el = ref.current;
8343
+ if (!el) return;
8344
+ const observer = new ResizeObserver((entries) => {
8345
+ const width = entries[0]?.contentRect.width ?? 0;
8346
+ setMode(width > breakpoint ? "default" : "minimal");
8347
+ });
8348
+ observer.observe(el);
8349
+ return () => observer.disconnect();
8350
+ }, [ref, override, breakpoint]);
8351
+ return override ?? mode;
8352
+ }
8353
+
8354
+ // src/components/ui/filter/filter-system.tsx
8355
+ import { Fragment as Fragment5, jsx as jsx59, jsxs as jsxs53 } from "react/jsx-runtime";
8356
+ var FilterSystem = ({
8357
+ properties,
8358
+ filterState,
8359
+ onFilterStateChange,
8360
+ sortFields,
8361
+ mode: modeOverride,
8362
+ breakpoint,
8363
+ children,
8364
+ actions,
8365
+ className
8366
+ }) => {
8367
+ const containerRef = React53.useRef(null);
8368
+ const mode = useFilterBarMode(containerRef, modeOverride, breakpoint);
8369
+ const [propertySelectorOpen, setPropertySelectorOpen] = React53.useState(false);
8370
+ const [advancedOpen, setAdvancedOpen] = React53.useState(false);
8371
+ const [summaryOpen, setSummaryOpen] = React53.useState(false);
8372
+ const [pendingFilterId, setPendingFilterId] = React53.useState(null);
8373
+ const totalCount = filterState.basicFilters.length + countConditions(filterState.advancedFilters);
8374
+ const handleAddFilter = (property) => {
8375
+ const newFilter = createFilterWithDefaults(property.id, property.type);
8376
+ if (newFilter.operator && isNoValueOperator(newFilter.operator)) {
8377
+ onFilterStateChange({
8378
+ ...filterState,
8379
+ basicFilters: [...filterState.basicFilters, newFilter]
7667
8380
  });
8381
+ return;
7668
8382
  }
7669
- for (let d = 1; d <= daysInMonth; d++) {
7670
- days.push({ date: new Date(year, month, d), isOutside: false });
7671
- }
7672
- const remaining = 42 - days.length;
7673
- for (let d = 1; d <= remaining; d++) {
7674
- days.push({
7675
- date: new Date(
7676
- month === 11 ? year + 1 : year,
7677
- month === 11 ? 0 : month + 1,
7678
- d
7679
- ),
7680
- isOutside: true
7681
- });
8383
+ setPendingFilterId(newFilter.id);
8384
+ onFilterStateChange({
8385
+ ...filterState,
8386
+ basicFilters: [...filterState.basicFilters, newFilter]
8387
+ });
8388
+ };
8389
+ const handleUpdateFilter = (updated) => {
8390
+ onFilterStateChange({
8391
+ ...filterState,
8392
+ basicFilters: filterState.basicFilters.map(
8393
+ (f) => f.id === updated.id ? updated : f
8394
+ )
8395
+ });
8396
+ if (pendingFilterId === updated.id) {
8397
+ setPendingFilterId(null);
7682
8398
  }
7683
- const result = [];
7684
- for (let i = 0; i < days.length; i += 7) {
7685
- result.push(days.slice(i, i + 7));
8399
+ };
8400
+ const handleDeleteFilter = (id) => {
8401
+ onFilterStateChange({
8402
+ ...filterState,
8403
+ basicFilters: filterState.basicFilters.filter((f) => f.id !== id)
8404
+ });
8405
+ };
8406
+ const handlePropertyChange = (filterId, newProp) => {
8407
+ const newCondition = createFilterWithDefaults(newProp.id, newProp.type);
8408
+ onFilterStateChange({
8409
+ ...filterState,
8410
+ basicFilters: filterState.basicFilters.map(
8411
+ (f) => f.id === filterId ? { ...newCondition, id: filterId } : f
8412
+ )
8413
+ });
8414
+ if (newCondition.operator && !isNoValueOperator(newCondition.operator)) {
8415
+ setPendingFilterId(filterId);
7686
8416
  }
7687
- return result;
7688
- }, [month, year]);
7689
- return /* @__PURE__ */ jsxs51(
7690
- "div",
7691
- {
7692
- ref,
7693
- className: cn("flex flex-col", className),
7694
- ...props,
7695
- children: [
7696
- header,
7697
- /* @__PURE__ */ jsxs51("div", { className: "flex flex-col gap-lg p-lg", children: [
7698
- /* @__PURE__ */ jsxs51("div", { className: "flex items-center justify-between", children: [
7699
- /* @__PURE__ */ jsxs51("span", { className: "text-base font-semibold leading-base text-datepicker-header-text", children: [
7700
- MONTH_NAMES[month],
7701
- " ",
7702
- year
7703
- ] }),
7704
- /* @__PURE__ */ jsxs51("div", { className: "flex items-center gap-xs", children: [
7705
- /* @__PURE__ */ jsx57(
7706
- "button",
8417
+ };
8418
+ const handleConvertToAdvanced = (id) => {
8419
+ const filter = filterState.basicFilters.find((f) => f.id === id);
8420
+ if (!filter) return;
8421
+ onFilterStateChange({
8422
+ ...filterState,
8423
+ basicFilters: filterState.basicFilters.filter((f) => f.id !== id),
8424
+ advancedFilters: [...filterState.advancedFilters, filter]
8425
+ });
8426
+ };
8427
+ const handleAdvancedFiltersChange = (filters) => {
8428
+ onFilterStateChange({ ...filterState, advancedFilters: filters });
8429
+ };
8430
+ const handleClearAdvanced = () => {
8431
+ onFilterStateChange({ ...filterState, advancedFilters: [] });
8432
+ };
8433
+ const handleClearAll = () => {
8434
+ onFilterStateChange({
8435
+ ...filterState,
8436
+ basicFilters: [],
8437
+ advancedFilters: []
8438
+ });
8439
+ };
8440
+ const handleSortChange = (field, direction) => {
8441
+ onFilterStateChange({ ...filterState, sort: { field, direction } });
8442
+ };
8443
+ const getPropertyDef = (propertyId) => properties.find((p) => p.id === propertyId);
8444
+ const hasAdvanced = filterState.advancedFilters.length > 0;
8445
+ const isMinimal = mode === "minimal";
8446
+ const handleOpenAdvanced = () => {
8447
+ setPropertySelectorOpen(false);
8448
+ requestAnimationFrame(() => {
8449
+ if (isMinimal) {
8450
+ setSummaryOpen(true);
8451
+ } else {
8452
+ setAdvancedOpen(true);
8453
+ }
8454
+ });
8455
+ };
8456
+ const advancedFilterCount = filterState.advancedFilters.length;
8457
+ const showAdvancedChip = hasAdvanced || advancedOpen;
8458
+ const showSummaryChip = totalCount > 0 || summaryOpen;
8459
+ return /* @__PURE__ */ jsxs53(FilterBar, { ref: containerRef, className, children: [
8460
+ /* @__PURE__ */ jsxs53(FilterBarLeft, { className: "flex-nowrap flex-1 min-w-0 overflow-x-auto scrollbar-none outline-none [&>*]:shrink-0", children: [
8461
+ children,
8462
+ sortFields && filterState.sort && /* @__PURE__ */ jsx59(
8463
+ SortButton,
8464
+ {
8465
+ fields: sortFields,
8466
+ activeField: filterState.sort.field,
8467
+ direction: filterState.sort.direction,
8468
+ onChange: handleSortChange,
8469
+ iconOnly: isMinimal
8470
+ }
8471
+ ),
8472
+ isMinimal ? /* @__PURE__ */ jsxs53(Fragment5, { children: [
8473
+ /* @__PURE__ */ jsx59(
8474
+ "div",
8475
+ {
8476
+ className: showSummaryChip ? "inline-flex" : "inline-flex w-0 overflow-hidden opacity-0 pointer-events-none",
8477
+ "aria-hidden": !showSummaryChip || void 0,
8478
+ children: /* @__PURE__ */ jsx59(
8479
+ SummaryChip,
8480
+ {
8481
+ count: totalCount,
8482
+ filters: [...filterState.basicFilters, ...filterState.advancedFilters],
8483
+ properties,
8484
+ onFiltersChange: (nodes) => {
8485
+ onFilterStateChange({
8486
+ ...filterState,
8487
+ basicFilters: [],
8488
+ advancedFilters: nodes
8489
+ });
8490
+ },
8491
+ onClearAll: handleClearAll,
8492
+ open: summaryOpen,
8493
+ onOpenChange: setSummaryOpen
8494
+ }
8495
+ )
8496
+ }
8497
+ ),
8498
+ !showSummaryChip && /* @__PURE__ */ jsx59(
8499
+ PropertySelector,
8500
+ {
8501
+ properties,
8502
+ onSelect: handleAddFilter,
8503
+ open: propertySelectorOpen,
8504
+ onOpenChange: setPropertySelectorOpen,
8505
+ onAdvancedFilter: handleOpenAdvanced,
8506
+ advancedFilterCount,
8507
+ children: /* @__PURE__ */ jsx59(FilterBarButton, { iconOnly: true })
8508
+ }
8509
+ )
8510
+ ] }) : (
8511
+ /* ── DEFAULT MODE ────────────────────────────────────── */
8512
+ /* @__PURE__ */ jsxs53(Fragment5, { children: [
8513
+ /* @__PURE__ */ jsx59(
8514
+ AdvancedPopover,
8515
+ {
8516
+ filters: filterState.advancedFilters,
8517
+ properties,
8518
+ onFiltersChange: handleAdvancedFiltersChange,
8519
+ open: advancedOpen,
8520
+ onOpenChange: setAdvancedOpen,
8521
+ children: /* @__PURE__ */ jsx59(
8522
+ "div",
7707
8523
  {
7708
- type: "button",
7709
- onClick: goToPrevMonth,
7710
- className: "flex items-center justify-center p-xs rounded-base hover:bg-datepicker-day-bg-hover transition-colors cursor-pointer",
7711
- "aria-label": "Previous month",
7712
- children: /* @__PURE__ */ jsx57(Icon34, { icon: faChevronLeftOutline3, size: "xs", className: "text-datepicker-header-nav" })
8524
+ className: showAdvancedChip ? "inline-flex" : "inline-flex w-0 overflow-hidden opacity-0 pointer-events-none",
8525
+ "aria-hidden": !showAdvancedChip || void 0,
8526
+ children: /* @__PURE__ */ jsx59(
8527
+ AdvancedChip,
8528
+ {
8529
+ count: filterState.advancedFilters.length,
8530
+ onClick: () => setAdvancedOpen(true),
8531
+ onClear: handleClearAdvanced
8532
+ }
8533
+ )
7713
8534
  }
7714
- ),
7715
- /* @__PURE__ */ jsx57(
8535
+ )
8536
+ }
8537
+ ),
8538
+ filterState.basicFilters.map((filter) => {
8539
+ const propDef = getPropertyDef(filter.propertyId);
8540
+ if (!propDef) return null;
8541
+ return /* @__PURE__ */ jsx59(
8542
+ InteractiveFilterChip,
8543
+ {
8544
+ propertyDef: propDef,
8545
+ condition: filter,
8546
+ properties,
8547
+ mode: pendingFilterId === filter.id ? "add" : "edit",
8548
+ autoOpen: pendingFilterId === filter.id,
8549
+ onUpdate: handleUpdateFilter,
8550
+ onPropertyChange: (newProp) => handlePropertyChange(filter.id, newProp),
8551
+ onDelete: () => handleDeleteFilter(filter.id),
8552
+ onConvertToAdvanced: () => handleConvertToAdvanced(filter.id)
8553
+ },
8554
+ filter.id
8555
+ );
8556
+ }),
8557
+ /* @__PURE__ */ jsx59(
8558
+ PropertySelector,
8559
+ {
8560
+ properties,
8561
+ onSelect: handleAddFilter,
8562
+ open: propertySelectorOpen,
8563
+ onOpenChange: setPropertySelectorOpen,
8564
+ onAdvancedFilter: handleOpenAdvanced,
8565
+ advancedFilterCount,
8566
+ children: totalCount > 0 ? /* @__PURE__ */ jsx59(
7716
8567
  "button",
7717
8568
  {
7718
8569
  type: "button",
7719
- onClick: goToNextMonth,
7720
- className: "flex items-center justify-center p-xs rounded-base hover:bg-datepicker-day-bg-hover transition-colors cursor-pointer",
7721
- "aria-label": "Next month",
7722
- children: /* @__PURE__ */ jsx57(Icon34, { icon: faChevronRightOutline3, size: "xs", className: "text-datepicker-header-nav" })
8570
+ className: "shrink-0 inline-flex items-center justify-center size-8 rounded-md border border-[var(--color-btn-outlined-neutral-border-default)] bg-gradient-to-t from-[var(--color-btn-outlined-neutral-bg-default)] from-[10%] to-[var(--color-btn-outlined-neutral-bg-gradient-to-default)] shadow-sm cursor-pointer transition-colors hover:from-[var(--color-btn-outlined-neutral-bg-hover)] hover:to-[var(--color-btn-outlined-neutral-bg-gradient-to-hover)]",
8571
+ children: /* @__PURE__ */ jsx59(Icon37, { icon: faPlusOutline5, size: "sm", className: "text-[var(--color-foreground)]" })
7723
8572
  }
7724
- )
7725
- ] })
7726
- ] }),
7727
- /* @__PURE__ */ jsxs51("div", { className: "flex flex-col", children: [
7728
- /* @__PURE__ */ jsx57("div", { className: "grid grid-cols-7 gap-base py-sm", children: WEEKDAYS.map((day) => /* @__PURE__ */ jsx57(
7729
- "span",
7730
- {
7731
- className: "w-9 text-center text-xs font-regular leading-xs text-datepicker-header-weekday",
7732
- children: day
7733
- },
7734
- day
7735
- )) }),
7736
- /* @__PURE__ */ jsx57("div", { className: "flex flex-col", children: weeks.map((week, wi) => /* @__PURE__ */ jsx57("div", { className: "grid grid-cols-7 gap-base", children: week.map((day, di) => /* @__PURE__ */ jsx57(
7737
- DatePickerDay,
7738
- {
7739
- date: day.date,
7740
- isOutside: day.isOutside
7741
- },
7742
- di
7743
- )) }, wi)) })
7744
- ] })
8573
+ ) : /* @__PURE__ */ jsx59(FilterBarButton, {})
8574
+ }
8575
+ )
7745
8576
  ] })
7746
- ]
7747
- }
7748
- );
7749
- });
7750
- DatePickerCalendar.displayName = "DatePickerCalendar";
7751
- var DatePickerSuggestions = React50.forwardRef(
7752
- ({ className, suggestions, formatDate = defaultFormatDate, ...props }, ref) => {
7753
- const { onSelect, mode } = useDatePickerContext();
7754
- const onValueChange = React50.useContext(DatePickerContext) ? void 0 : void 0;
7755
- const ctx = useDatePickerContext();
7756
- const handleClick = (suggestion) => {
7757
- const val = suggestion.getValue();
7758
- if (val instanceof Date) {
7759
- ctx.onSelect(val);
7760
- } else {
7761
- ctx.onSelect(val.from);
7762
- if (val.to) {
7763
- setTimeout(() => ctx.onSelect(val.to), 0);
7764
- }
7765
- }
7766
- };
7767
- const formatSuggestionDate = (suggestion) => {
7768
- const val = suggestion.getValue();
7769
- if (val instanceof Date) {
7770
- return formatDate(val);
7771
- }
7772
- const from = formatDate(val.from);
7773
- const to = val.to ? formatDate(val.to) : "";
7774
- return to ? `${from} - ${to}` : from;
7775
- };
7776
- return /* @__PURE__ */ jsxs51(
7777
- "div",
7778
- {
7779
- ref,
7780
- className: cn(
7781
- "flex flex-col border-l border-datepicker-border self-stretch shrink-0",
7782
- className
7783
- ),
7784
- ...props,
7785
- children: [
7786
- /* @__PURE__ */ jsx57("div", { className: "pt-lg px-base", children: /* @__PURE__ */ jsx57("div", { className: "flex items-center p-base rounded-base", children: /* @__PURE__ */ jsx57("span", { className: "flex-1 text-xs font-semibold leading-xs text-datepicker-suggestion-heading uppercase truncate", children: "Suggestions" }) }) }),
7787
- /* @__PURE__ */ jsx57("div", { className: "flex flex-1 flex-col p-base min-w-[222px]", children: suggestions.map((suggestion, i) => /* @__PURE__ */ jsxs51(
7788
- "button",
7789
- {
7790
- type: "button",
7791
- onClick: () => handleClick(suggestion),
7792
- className: "flex items-center gap-sm p-base rounded-base hover:bg-datepicker-suggestion-hover transition-colors cursor-pointer text-left",
7793
- children: [
7794
- /* @__PURE__ */ jsx57("span", { className: "text-sm font-regular leading-sm text-datepicker-suggestion-text truncate shrink-0", children: suggestion.label }),
7795
- /* @__PURE__ */ jsx57("span", { className: "text-xs font-regular leading-xs text-datepicker-suggestion-date truncate", children: formatSuggestionDate(suggestion) })
7796
- ]
7797
- },
7798
- i
7799
- )) })
7800
- ]
7801
- }
7802
- );
7803
- }
7804
- );
7805
- DatePickerSuggestions.displayName = "DatePickerSuggestions";
7806
- var DatePickerFooter = React50.forwardRef(
7807
- ({ className, children, ...props }, ref) => /* @__PURE__ */ jsx57(
7808
- "div",
7809
- {
7810
- ref,
7811
- className: cn(
7812
- "flex items-center justify-between p-lg",
7813
- "border-t border-datepicker-footer-border",
7814
- "bg-datepicker-bg",
7815
- className
7816
8577
  ),
7817
- ...props,
7818
- children
7819
- }
7820
- )
7821
- );
7822
- DatePickerFooter.displayName = "DatePickerFooter";
7823
- var DatePickerPanel = React50.forwardRef(
7824
- ({ className, children, ...props }, ref) => /* @__PURE__ */ jsx57(
7825
- "div",
7826
- {
7827
- ref,
7828
- className: cn("flex items-start", className),
7829
- ...props,
7830
- children
7831
- }
7832
- )
7833
- );
7834
- DatePickerPanel.displayName = "DatePickerPanel";
7835
- var DatePickerRoot = PopoverPrimitive12.Root;
7836
- var DatePickerTrigger = PopoverPrimitive12.Trigger;
7837
- var DatePickerPopover = React50.forwardRef(({ className, sideOffset = 4, align = "start", children, ...props }, ref) => /* @__PURE__ */ jsx57(PopoverPrimitive12.Portal, { children: /* @__PURE__ */ jsx57(
7838
- PopoverPrimitive12.Content,
7839
- {
7840
- ref,
7841
- sideOffset,
7842
- align,
7843
- className: cn(
7844
- "z-50",
7845
- "data-[state=open]:animate-in data-[state=open]:fade-in-0 data-[state=open]:zoom-in-95",
7846
- "data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=closed]:zoom-out-95",
7847
- "data-[side=bottom]:slide-in-from-top-2 data-[side=top]:slide-in-from-bottom-2",
7848
- className
7849
- ),
7850
- ...props,
7851
- children
7852
- }
7853
- ) }));
7854
- DatePickerPopover.displayName = "DatePickerPopover";
7855
- function getDefaultSuggestions(referenceDate) {
7856
- const now = referenceDate ?? /* @__PURE__ */ new Date();
7857
- const today = startOfDay(now);
7858
- const dayOfWeek = getWeekdayIndex(today);
7859
- const startOfThisWeek = new Date(today);
7860
- startOfThisWeek.setDate(today.getDate() - dayOfWeek);
7861
- const endOfThisWeek = new Date(startOfThisWeek);
7862
- endOfThisWeek.setDate(startOfThisWeek.getDate() + 6);
7863
- const startOfThisMonth = new Date(today.getFullYear(), today.getMonth(), 1);
7864
- const endOfThisMonth = new Date(
7865
- today.getFullYear(),
7866
- today.getMonth() + 1,
7867
- 0
7868
- );
7869
- const startOfThisYear = new Date(today.getFullYear(), 0, 1);
7870
- const endOfThisYear = new Date(today.getFullYear(), 11, 31);
7871
- const startOfLastWeek = new Date(startOfThisWeek);
7872
- startOfLastWeek.setDate(startOfThisWeek.getDate() - 7);
7873
- const endOfLastWeek = new Date(startOfThisWeek);
7874
- endOfLastWeek.setDate(startOfThisWeek.getDate() - 1);
7875
- const startOfLastMonth = new Date(
7876
- today.getFullYear(),
7877
- today.getMonth() - 1,
7878
- 1
7879
- );
7880
- const endOfLastMonth = new Date(today.getFullYear(), today.getMonth(), 0);
7881
- const startOfLastYear = new Date(today.getFullYear() - 1, 0, 1);
7882
- const endOfLastYear = new Date(today.getFullYear() - 1, 11, 31);
7883
- return [
7884
- { label: "Today", getValue: () => today },
7885
- {
7886
- label: "This week",
7887
- getValue: () => ({ from: startOfThisWeek, to: endOfThisWeek })
7888
- },
7889
- {
7890
- label: "This month",
7891
- getValue: () => ({ from: startOfThisMonth, to: endOfThisMonth })
7892
- },
7893
- {
7894
- label: "This year",
7895
- getValue: () => ({ from: startOfThisYear, to: endOfThisYear })
7896
- },
7897
- {
7898
- label: "Last week",
7899
- getValue: () => ({ from: startOfLastWeek, to: endOfLastWeek })
7900
- },
7901
- {
7902
- label: "Last month",
7903
- getValue: () => ({ from: startOfLastMonth, to: endOfLastMonth })
7904
- },
7905
- {
7906
- label: "Last year",
7907
- getValue: () => ({ from: startOfLastYear, to: endOfLastYear })
7908
- }
7909
- ];
7910
- }
8578
+ totalCount > 0 && /* @__PURE__ */ jsx59(
8579
+ "button",
8580
+ {
8581
+ type: "button",
8582
+ onClick: handleClearAll,
8583
+ className: "shrink-0 flex items-center gap-sm px-base py-sm min-h-[32px] max-h-[32px] rounded-md cursor-pointer transition-colors hover:bg-[var(--color-accent)]",
8584
+ children: isMinimal ? /* @__PURE__ */ jsx59(Icon37, { icon: faXmarkOutline5, size: "sm", className: "text-[var(--color-foreground)]" }) : /* @__PURE__ */ jsx59("span", { className: "text-sm font-semibold leading-sm text-[var(--color-foreground)]", children: "Clear" })
8585
+ }
8586
+ )
8587
+ ] }),
8588
+ actions && /* @__PURE__ */ jsx59(FilterBarRight, { className: "shrink-0 -ml-2xl pl-2xl relative z-10 bg-[linear-gradient(to_right,transparent_0px,var(--filter-bar-bg,var(--color-background,#fff))_24px)]", children: actions })
8589
+ ] });
8590
+ };
8591
+ FilterSystem.displayName = "FilterSystem";
7911
8592
  export {
7912
8593
  AdvancedChip,
7913
8594
  AdvancedPopover,