@l3mpire/ui 2.12.0 → 2.13.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")
@@ -5617,2297 +5615,2428 @@ var NumberRangeValueInput = ({
5617
5615
  NumberRangeValueInput.displayName = "NumberRangeValueInput";
5618
5616
 
5619
5617
  // src/components/ui/filter/value-inputs/date-value-input.tsx
5618
+ import * as React42 from "react";
5619
+
5620
+ // src/components/ui/date-picker.tsx
5621
+ import * as React41 from "react";
5622
+ import * as PopoverPrimitive5 from "@radix-ui/react-popover";
5623
+ import {
5624
+ Icon as Icon26,
5625
+ faChevronLeftOutline as faChevronLeftOutline2,
5626
+ faChevronRightOutline as faChevronRightOutline2,
5627
+ faArrowRightOutline,
5628
+ faCalendarOutline
5629
+ } from "@l3mpire/icons";
5620
5630
  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"] }
5631
+ function getDaysInMonth(year, month) {
5632
+ return new Date(year, month + 1, 0).getDate();
5633
+ }
5634
+ function getWeekdayIndex(date) {
5635
+ return (date.getDay() + 6) % 7;
5636
+ }
5637
+ function isSameDay(a, b) {
5638
+ return a.getFullYear() === b.getFullYear() && a.getMonth() === b.getMonth() && a.getDate() === b.getDate();
5639
+ }
5640
+ function isInRange(date, from, to) {
5641
+ const t = date.getTime();
5642
+ return t >= from.getTime() && t <= to.getTime();
5643
+ }
5644
+ function startOfDay(d) {
5645
+ return new Date(d.getFullYear(), d.getMonth(), d.getDate());
5646
+ }
5647
+ var WEEKDAYS = ["Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"];
5648
+ var MONTH_NAMES = [
5649
+ "January",
5650
+ "February",
5651
+ "March",
5652
+ "April",
5653
+ "May",
5654
+ "June",
5655
+ "July",
5656
+ "August",
5657
+ "September",
5658
+ "October",
5659
+ "November",
5660
+ "December"
5625
5661
  ];
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);
5662
+ var DatePickerContext = React41.createContext(
5663
+ null
5664
+ );
5665
+ function useDatePickerContext() {
5666
+ const ctx = React41.useContext(DatePickerContext);
5667
+ if (!ctx)
5668
+ throw new Error("DatePicker compound components must be used within <DatePicker>");
5669
+ return ctx;
5649
5670
  }
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
5671
+ var DatePicker = React41.forwardRef(
5672
+ ({
5673
+ className,
5674
+ mode = "single",
5675
+ value,
5676
+ onValueChange,
5677
+ defaultMonth,
5678
+ defaultYear,
5679
+ children,
5680
+ ...props
5681
+ }, ref) => {
5682
+ const today = React41.useMemo(() => startOfDay(/* @__PURE__ */ new Date()), []);
5683
+ const initialDate = React41.useMemo(() => {
5684
+ if (value) {
5685
+ if (value instanceof Date) return value;
5686
+ return value.from;
5687
+ }
5688
+ return today;
5689
+ }, []);
5690
+ const [month, setMonth] = React41.useState(
5691
+ defaultMonth ?? initialDate.getMonth()
5692
+ );
5693
+ const [year, setYear] = React41.useState(
5694
+ defaultYear ?? initialDate.getFullYear()
5695
+ );
5696
+ const [hoveredDate, setHoveredDate] = React41.useState();
5697
+ const goToPrevMonth = React41.useCallback(() => {
5698
+ setMonth((m) => {
5699
+ if (m === 0) {
5700
+ setYear((y) => y - 1);
5701
+ return 11;
5670
5702
  }
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
5703
+ return m - 1;
5704
+ });
5705
+ }, []);
5706
+ const goToNextMonth = React41.useCallback(() => {
5707
+ setMonth((m) => {
5708
+ if (m === 11) {
5709
+ setYear((y) => y + 1);
5710
+ return 0;
5683
5711
  }
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(
5712
+ return m + 1;
5713
+ });
5714
+ }, []);
5715
+ const onSelect = React41.useCallback(
5716
+ (date) => {
5717
+ if (mode === "single") {
5718
+ onValueChange?.(date);
5719
+ return;
5720
+ }
5721
+ if (!value || value instanceof Date) {
5722
+ onValueChange?.({ from: date });
5723
+ return;
5724
+ }
5725
+ const range = value;
5726
+ if (range.to || date.getTime() < range.from.getTime()) {
5727
+ onValueChange?.({ from: date });
5728
+ } else {
5729
+ onValueChange?.({ from: range.from, to: date });
5730
+ }
5731
+ },
5732
+ [mode, value, onValueChange]
5733
+ );
5734
+ const ctxValue = React41.useMemo(
5735
+ () => ({
5736
+ mode,
5737
+ selected: value,
5738
+ onSelect,
5739
+ month,
5740
+ year,
5741
+ setMonth,
5742
+ setYear,
5743
+ goToPrevMonth,
5744
+ goToNextMonth,
5745
+ today,
5746
+ hoveredDate,
5747
+ setHoveredDate
5748
+ }),
5749
+ [
5750
+ mode,
5751
+ value,
5752
+ onSelect,
5753
+ month,
5754
+ year,
5755
+ goToPrevMonth,
5756
+ goToNextMonth,
5757
+ today,
5758
+ hoveredDate
5759
+ ]
5760
+ );
5761
+ return /* @__PURE__ */ jsx44(DatePickerContext.Provider, { value: ctxValue, children: /* @__PURE__ */ jsx44(
5762
+ "div",
5763
+ {
5764
+ ref,
5765
+ className: cn(
5766
+ "flex flex-col overflow-clip",
5767
+ "bg-datepicker-bg border border-datepicker-border rounded-md shadow-lg",
5768
+ className
5769
+ ),
5770
+ ...props,
5771
+ children
5772
+ }
5773
+ ) });
5774
+ }
5775
+ );
5776
+ DatePicker.displayName = "DatePicker";
5777
+ function defaultFormatDate(date) {
5778
+ return date.toLocaleDateString("en-US", {
5779
+ month: "short",
5780
+ day: "numeric",
5781
+ year: "numeric"
5782
+ });
5783
+ }
5784
+ var DatePickerSelects = React41.forwardRef(({ className, formatDate = defaultFormatDate, ...props }, ref) => {
5785
+ const { selected } = useDatePickerContext();
5786
+ const fromDate = selected instanceof Date ? selected : selected?.from;
5787
+ const toDate = selected instanceof Date ? void 0 : selected?.to;
5788
+ return /* @__PURE__ */ jsx44(
5789
+ "div",
5790
+ {
5791
+ ref,
5792
+ className: cn("flex flex-col items-start pt-lg px-lg", className),
5793
+ ...props,
5794
+ children: /* @__PURE__ */ jsxs39("div", { className: "flex items-center gap-base w-full", children: [
5795
+ /* @__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: [
5796
+ /* @__PURE__ */ jsx44("span", { className: "flex-1 text-sm font-regular leading-sm text-datepicker-header-text truncate", children: fromDate ? formatDate(fromDate) : "Start date" }),
5797
+ /* @__PURE__ */ jsx44(Icon26, { icon: faCalendarOutline, size: "sm", className: "shrink-0 text-datepicker-header-text" })
5798
+ ] }),
5799
+ /* @__PURE__ */ jsx44(
5800
+ Icon26,
5801
+ {
5802
+ icon: faArrowRightOutline,
5803
+ size: "sm",
5804
+ className: "shrink-0 text-datepicker-header-weekday"
5805
+ }
5806
+ ),
5807
+ /* @__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: [
5808
+ /* @__PURE__ */ jsx44("span", { className: "flex-1 text-sm font-regular leading-sm text-datepicker-header-text truncate", children: toDate ? formatDate(toDate) : "End date" }),
5809
+ /* @__PURE__ */ jsx44(Icon26, { icon: faCalendarOutline, size: "sm", className: "shrink-0 text-datepicker-header-text" })
5810
+ ] })
5811
+ ] })
5812
+ }
5813
+ );
5814
+ });
5815
+ DatePickerSelects.displayName = "DatePickerSelects";
5816
+ var DatePickerDay = ({ date, isOutside }) => {
5817
+ const { mode, selected, onSelect, today, hoveredDate, setHoveredDate } = useDatePickerContext();
5818
+ const isToday = isSameDay(date, today);
5819
+ const isSelected = selected instanceof Date ? isSameDay(date, selected) : selected?.from ? isSameDay(date, selected.from) || (selected.to ? isSameDay(date, selected.to) : false) : false;
5820
+ const isRangeStart = mode === "range" && selected && !(selected instanceof Date) && selected.from && isSameDay(date, selected.from);
5821
+ const isRangeEnd = mode === "range" && selected && !(selected instanceof Date) && selected.to && isSameDay(date, selected.to);
5822
+ const inRange = mode === "range" && selected && !(selected instanceof Date) && selected.from && selected.to && !isSelected && isInRange(date, selected.from, selected.to);
5823
+ const inPreviewRange = mode === "range" && selected && !(selected instanceof Date) && selected.from && !selected.to && hoveredDate && !isSelected && hoveredDate.getTime() > selected.from.getTime() && isInRange(date, selected.from, hoveredDate);
5824
+ const isInRangeOrPreview = inRange || inPreviewRange;
5825
+ return /* @__PURE__ */ jsxs39(
5698
5826
  "button",
5699
5827
  {
5700
5828
  type: "button",
5701
- onClick: () => {
5702
- onChange(preset);
5703
- onSubmit?.();
5704
- },
5829
+ onClick: () => !isOutside && onSelect(date),
5830
+ onMouseEnter: () => mode === "range" && setHoveredDate(date),
5831
+ onMouseLeave: () => mode === "range" && setHoveredDate(void 0),
5832
+ disabled: isOutside,
5705
5833
  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)]"
5834
+ "relative flex flex-col items-center justify-center w-9 rounded-full p-2 cursor-pointer transition-colors",
5835
+ "text-sm font-semibold leading-sm text-center",
5836
+ // Default
5837
+ !isOutside && !isSelected && !isInRangeOrPreview && "text-datepicker-day-text-default hover:bg-datepicker-day-bg-hover",
5838
+ // Outside month (disabled)
5839
+ isOutside && "text-datepicker-day-text-disabled cursor-default",
5840
+ // Selected
5841
+ isSelected && "bg-datepicker-day-bg-selected text-datepicker-day-text-selected",
5842
+ // In range
5843
+ isInRangeOrPreview && "bg-datepicker-day-bg-range text-datepicker-day-text-range",
5844
+ // Range start/end get full rounded; in-range items could be less rounded
5845
+ (isRangeStart || isRangeEnd) && "rounded-full"
5708
5846
  ),
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
- }
5847
+ children: [
5848
+ date.getDate(),
5849
+ 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" })
5850
+ ]
5851
+ }
5852
+ );
5852
5853
  };
5853
- ValueInput.displayName = "ValueInput";
5854
-
5855
- // src/components/ui/filter/property-selector.tsx
5856
- import * as React41 from "react";
5857
- import * as PopoverPrimitive5 from "@radix-ui/react-popover";
5858
- import {
5859
- Icon as Icon26,
5860
- faChevronLeftOutline as faChevronLeftOutline2,
5861
- faChevronRightOutline as faChevronRightOutline2,
5862
- faMagnifyingGlassOutline,
5863
- faFilterOutline as faFilterOutline2
5864
- } 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",
5854
+ var DatePickerCalendar = React41.forwardRef(({ className, header, ...props }, ref) => {
5855
+ const { month, year, goToPrevMonth, goToNextMonth } = useDatePickerContext();
5856
+ const weeks = React41.useMemo(() => {
5857
+ const firstDay = new Date(year, month, 1);
5858
+ const startOffset = getWeekdayIndex(firstDay);
5859
+ const daysInMonth = getDaysInMonth(year, month);
5860
+ const daysInPrevMonth = getDaysInMonth(
5861
+ month === 0 ? year - 1 : year,
5862
+ month === 0 ? 11 : month - 1
5863
+ );
5864
+ const days = [];
5865
+ for (let i = startOffset - 1; i >= 0; i--) {
5866
+ const d = daysInPrevMonth - i;
5867
+ days.push({
5868
+ date: new Date(
5869
+ month === 0 ? year - 1 : year,
5870
+ month === 0 ? 11 : month - 1,
5871
+ d
5872
+ ),
5873
+ isOutside: true
5874
+ });
5875
+ }
5876
+ for (let d = 1; d <= daysInMonth; d++) {
5877
+ days.push({ date: new Date(year, month, d), isOutside: false });
5878
+ }
5879
+ const remaining = 42 - days.length;
5880
+ for (let d = 1; d <= remaining; d++) {
5881
+ days.push({
5882
+ date: new Date(
5883
+ month === 11 ? year + 1 : year,
5884
+ month === 11 ? 0 : month + 1,
5885
+ d
5886
+ ),
5887
+ isOutside: true
5888
+ });
5889
+ }
5890
+ const result = [];
5891
+ for (let i = 0; i < days.length; i += 7) {
5892
+ result.push(days.slice(i, i + 7));
5893
+ }
5894
+ return result;
5895
+ }, [month, year]);
5896
+ return /* @__PURE__ */ jsxs39(
5897
+ "div",
5870
5898
  {
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)]",
5899
+ ref,
5900
+ className: cn("flex flex-col", className),
5901
+ ...props,
5875
5902
  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"
5903
+ header,
5904
+ /* @__PURE__ */ jsxs39("div", { className: "flex flex-col gap-lg p-lg", children: [
5905
+ /* @__PURE__ */ jsxs39("div", { className: "flex items-center justify-between", children: [
5906
+ /* @__PURE__ */ jsxs39("span", { className: "text-base font-semibold leading-base text-datepicker-header-text", children: [
5907
+ MONTH_NAMES[month],
5908
+ " ",
5909
+ year
5910
+ ] }),
5911
+ /* @__PURE__ */ jsxs39("div", { className: "flex items-center gap-xs", children: [
5912
+ /* @__PURE__ */ jsx44(
5913
+ "button",
5914
+ {
5915
+ type: "button",
5916
+ onClick: goToPrevMonth,
5917
+ className: "flex items-center justify-center p-xs rounded-base hover:bg-datepicker-day-bg-hover transition-colors cursor-pointer",
5918
+ "aria-label": "Previous month",
5919
+ children: /* @__PURE__ */ jsx44(Icon26, { icon: faChevronLeftOutline2, size: "xs", className: "text-datepicker-header-nav" })
5920
+ }
5921
+ ),
5922
+ /* @__PURE__ */ jsx44(
5923
+ "button",
5924
+ {
5925
+ type: "button",
5926
+ onClick: goToNextMonth,
5927
+ className: "flex items-center justify-center p-xs rounded-base hover:bg-datepicker-day-bg-hover transition-colors cursor-pointer",
5928
+ "aria-label": "Next month",
5929
+ children: /* @__PURE__ */ jsx44(Icon26, { icon: faChevronRightOutline2, size: "xs", className: "text-datepicker-header-nav" })
5930
+ }
5931
+ )
5932
+ ] })
5933
+ ] }),
5934
+ /* @__PURE__ */ jsxs39("div", { className: "flex flex-col", children: [
5935
+ /* @__PURE__ */ jsx44("div", { className: "grid grid-cols-7 gap-base py-sm", children: WEEKDAYS.map((day) => /* @__PURE__ */ jsx44(
5936
+ "span",
5937
+ {
5938
+ className: "w-9 text-center text-xs font-regular leading-xs text-datepicker-header-weekday",
5939
+ children: day
5940
+ },
5941
+ day
5942
+ )) }),
5943
+ /* @__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(
5944
+ DatePickerDay,
5945
+ {
5946
+ date: day.date,
5947
+ isOutside: day.isOutside
5948
+ },
5949
+ di
5950
+ )) }, wi)) })
5951
+ ] })
5889
5952
  ] })
5890
5953
  ]
5891
5954
  }
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(() => {
5912
- if (!open) {
5913
- setActiveGroup(null);
5914
- setSearch("");
5915
- }
5916
- }, [open]);
5917
- const groups = React41.useMemo(() => {
5918
- const map = /* @__PURE__ */ new Map();
5919
- for (const prop of properties) {
5920
- const existing = map.get(prop.group);
5921
- if (existing) {
5922
- existing.count++;
5955
+ );
5956
+ });
5957
+ DatePickerCalendar.displayName = "DatePickerCalendar";
5958
+ var DatePickerSuggestions = React41.forwardRef(
5959
+ ({ className, suggestions, formatDate = defaultFormatDate, ...props }, ref) => {
5960
+ const { onSelect, mode } = useDatePickerContext();
5961
+ const onValueChange = React41.useContext(DatePickerContext) ? void 0 : void 0;
5962
+ const ctx = useDatePickerContext();
5963
+ const handleClick = (suggestion) => {
5964
+ const val = suggestion.getValue();
5965
+ if (val instanceof Date) {
5966
+ ctx.onSelect(val);
5923
5967
  } else {
5924
- map.set(prop.group, {
5925
- group: prop.group,
5926
- groupLabel: prop.groupLabel,
5927
- groupIcon: prop.icon,
5928
- count: 1
5929
- });
5968
+ ctx.onSelect(val.from);
5969
+ if (val.to) {
5970
+ setTimeout(() => ctx.onSelect(val.to), 0);
5971
+ }
5930
5972
  }
5931
- }
5932
- return Array.from(map.values());
5933
- }, [properties]);
5934
- const globalSearchResults = React41.useMemo(() => {
5935
- if (!search || activeGroup) return [];
5936
- const lower = search.toLowerCase();
5937
- return properties.filter((p) => p.label.toLowerCase().includes(lower));
5938
- }, [properties, search, activeGroup]);
5939
- const filteredGroups = React41.useMemo(() => {
5940
- if (!search || activeGroup) return groups;
5941
- const lower = search.toLowerCase();
5942
- return groups.filter(
5943
- (g) => g.groupLabel.toLowerCase().includes(lower) || properties.some(
5944
- (p) => p.group === g.group && p.label.toLowerCase().includes(lower)
5945
- )
5946
- );
5947
- }, [groups, properties, search, activeGroup]);
5948
- const filteredProperties = React41.useMemo(() => {
5949
- if (!activeGroup) return [];
5950
- const groupProps = properties.filter((p) => p.group === activeGroup);
5951
- if (!search) return groupProps;
5952
- const lower = search.toLowerCase();
5953
- return groupProps.filter((p) => p.label.toLowerCase().includes(lower));
5954
- }, [properties, activeGroup, search]);
5955
- const activeGroupInfo = groups.find((g) => g.group === activeGroup);
5956
- 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,
5973
+ };
5974
+ const formatSuggestionDate = (suggestion) => {
5975
+ const val = suggestion.getValue();
5976
+ if (val instanceof Date) {
5977
+ return formatDate(val);
5978
+ }
5979
+ const from = formatDate(val.from);
5980
+ const to = val.to ? formatDate(val.to) : "";
5981
+ return to ? `${from} - ${to}` : from;
5982
+ };
5983
+ return /* @__PURE__ */ jsxs39(
5984
+ "div",
5961
5985
  {
5962
- sideOffset: 4,
5963
- align: "start",
5964
- onCloseAutoFocus: (e) => e.preventDefault(),
5986
+ ref,
5965
5987
  className: cn(
5966
- "z-50 flex flex-col gap-xs overflow-clip p-xs",
5967
- "bg-[var(--color-dropdown-bg)] border border-[var(--color-dropdown-border)] rounded-md shadow-lg",
5968
- "data-[state=open]:animate-in data-[state=open]:fade-in-0 data-[state=open]:zoom-in-95",
5969
- "data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=closed]:zoom-out-95",
5970
- "data-[side=bottom]:slide-in-from-top-2",
5971
- "min-w-[230px]"
5988
+ "flex flex-col border-l border-datepicker-border self-stretch shrink-0",
5989
+ className
5972
5990
  ),
5991
+ ...props,
5973
5992
  children: [
5974
- activeGroup === null ? (
5975
- /* ── 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,
5980
- {
5981
- icon: faMagnifyingGlassOutline,
5982
- size: "sm",
5983
- className: "shrink-0 text-[var(--color-muted-foreground)]"
5984
- }
5985
- ),
5986
- /* @__PURE__ */ jsx48(
5987
- "input",
5988
- {
5989
- type: "text",
5990
- value: search,
5991
- onChange: (e) => setSearch(e.target.value),
5992
- placeholder: "Search...",
5993
- autoFocus: true,
5994
- className: "flex-1 text-sm font-regular leading-sm text-[var(--color-foreground)] bg-transparent outline-none placeholder:text-[var(--color-muted-foreground)]"
5995
- }
5996
- )
5997
- ] }),
5998
- showGlobalResults ? (
5999
- /* ── 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(
6001
- "button",
6002
- {
6003
- type: "button",
6004
- onClick: () => {
6005
- onSelect(prop);
6006
- onOpenChange?.(false);
6007
- },
6008
- className: "flex items-center gap-base p-base rounded-base cursor-pointer transition-colors hover:bg-[var(--color-dropdown-item-hover)]",
6009
- children: [
6010
- /* @__PURE__ */ jsx48(
6011
- Icon26,
6012
- {
6013
- icon: prop.icon,
6014
- size: "sm",
6015
- className: "shrink-0 text-[var(--color-dropdown-item-icon)]"
6016
- }
6017
- ),
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 })
6020
- ]
6021
- },
6022
- prop.id
6023
- )) })
6024
- ) : (
6025
- /* ── Group list ─────────────────────────────────────── */
6026
- /* @__PURE__ */ jsxs42("div", { className: "flex flex-col", children: [
6027
- filteredGroups.map((g) => /* @__PURE__ */ jsxs42(
6028
- "button",
6029
- {
6030
- type: "button",
6031
- onClick: () => {
6032
- setActiveGroup(g.group);
6033
- setSearch("");
6034
- },
6035
- className: "flex items-center gap-base p-base rounded-base cursor-pointer transition-colors hover:bg-[var(--color-dropdown-item-hover)]",
6036
- children: [
6037
- /* @__PURE__ */ jsx48(
6038
- Icon26,
6039
- {
6040
- icon: g.groupIcon,
6041
- size: "sm",
6042
- className: "shrink-0 text-[var(--color-dropdown-item-icon)]"
6043
- }
6044
- ),
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,
6049
- {
6050
- icon: faChevronRightOutline2,
6051
- size: "xs",
6052
- className: "shrink-0 text-[var(--color-dropdown-item-icon)]"
6053
- }
6054
- )
6055
- ]
6056
- },
6057
- g.group
6058
- )),
6059
- filteredGroups.length === 0 && /* @__PURE__ */ jsx48("span", { className: "p-base text-sm text-[var(--color-muted-foreground)]", children: "No results" })
6060
- ] })
6061
- )
6062
- ] })
6063
- ) : (
6064
- /* ── Level 2: Properties ─────────────────────────────────── */
6065
- /* @__PURE__ */ jsxs42("div", { className: "flex flex-col gap-xs", children: [
6066
- /* @__PURE__ */ jsxs42(
6067
- "button",
6068
- {
6069
- type: "button",
6070
- onClick: () => {
6071
- setActiveGroup(null);
6072
- setSearch("");
6073
- },
6074
- className: "flex items-center gap-base p-base rounded-base cursor-pointer transition-colors hover:bg-[var(--color-dropdown-item-hover)]",
6075
- children: [
6076
- /* @__PURE__ */ jsx48(
6077
- Icon26,
6078
- {
6079
- icon: faChevronLeftOutline2,
6080
- size: "sm",
6081
- className: "shrink-0 text-[var(--color-dropdown-item-icon)]"
6082
- }
6083
- ),
6084
- /* @__PURE__ */ jsx48("span", { className: "flex-1 text-xs font-semibold leading-xs text-[var(--color-muted-foreground)] text-left truncate", children: activeGroupInfo?.groupLabel })
6085
- ]
6086
- }
6087
- ),
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,
6091
- {
6092
- icon: faMagnifyingGlassOutline,
6093
- size: "sm",
6094
- className: "shrink-0 text-[var(--color-muted-foreground)]"
6095
- }
6096
- ),
6097
- /* @__PURE__ */ jsx48(
6098
- "input",
6099
- {
6100
- type: "text",
6101
- value: search,
6102
- onChange: (e) => setSearch(e.target.value),
6103
- placeholder: "Search...",
6104
- autoFocus: true,
6105
- className: "flex-1 text-sm font-regular leading-sm text-[var(--color-foreground)] bg-transparent outline-none placeholder:text-[var(--color-muted-foreground)]"
6106
- }
6107
- )
6108
- ] }),
6109
- /* @__PURE__ */ jsxs42("div", { className: "flex flex-col max-h-[300px] overflow-y-auto", children: [
6110
- filteredProperties.map((prop) => /* @__PURE__ */ jsxs42(
6111
- "button",
6112
- {
6113
- type: "button",
6114
- onClick: () => {
6115
- onSelect(prop);
6116
- onOpenChange?.(false);
6117
- },
6118
- className: "flex items-center gap-base p-base rounded-base cursor-pointer transition-colors hover:bg-[var(--color-dropdown-item-hover)]",
6119
- children: [
6120
- /* @__PURE__ */ jsx48(
6121
- Icon26,
6122
- {
6123
- icon: prop.icon,
6124
- size: "sm",
6125
- className: "shrink-0 text-[var(--color-dropdown-item-icon)]"
6126
- }
6127
- ),
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 })
6129
- ]
6130
- },
6131
- prop.id
6132
- )),
6133
- filteredProperties.length === 0 && /* @__PURE__ */ jsx48("span", { className: "p-base text-sm text-[var(--color-muted-foreground)]", children: "No results" })
6134
- ] })
6135
- ] })
6136
- ),
6137
- showAdvancedFooter && /* @__PURE__ */ jsx48(
6138
- AdvancedFilterFooter,
5993
+ /* @__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" }) }) }),
5994
+ /* @__PURE__ */ jsx44("div", { className: "flex flex-1 flex-col p-base min-w-[222px]", children: suggestions.map((suggestion, i) => /* @__PURE__ */ jsxs39(
5995
+ "button",
6139
5996
  {
6140
- onClick: handleAdvancedClick,
6141
- count: advancedFilterCount
6142
- }
6143
- )
5997
+ type: "button",
5998
+ onClick: () => handleClick(suggestion),
5999
+ className: "flex items-center gap-sm p-base rounded-base hover:bg-datepicker-suggestion-hover transition-colors cursor-pointer text-left",
6000
+ children: [
6001
+ /* @__PURE__ */ jsx44("span", { className: "text-sm font-regular leading-sm text-datepicker-suggestion-text truncate shrink-0", children: suggestion.label }),
6002
+ /* @__PURE__ */ jsx44("span", { className: "text-xs font-regular leading-xs text-datepicker-suggestion-date truncate", children: formatSuggestionDate(suggestion) })
6003
+ ]
6004
+ },
6005
+ i
6006
+ )) })
6144
6007
  ]
6145
6008
  }
6146
- ) })
6147
- ] });
6148
- };
6149
- PropertySelector.displayName = "PropertySelector";
6150
-
6151
- // 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";
6155
- var KebabMenu = ({
6156
- onConvertToAdvanced,
6157
- onDelete,
6158
- open,
6159
- onOpenChange,
6160
- 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,
6009
+ );
6010
+ }
6011
+ );
6012
+ DatePickerSuggestions.displayName = "DatePickerSuggestions";
6013
+ var DatePickerFooter = React41.forwardRef(
6014
+ ({ className, children, ...props }, ref) => /* @__PURE__ */ jsx44(
6015
+ "div",
6165
6016
  {
6166
- sideOffset: 4,
6167
- align: "end",
6017
+ ref,
6168
6018
  className: cn(
6169
- "z-50 flex flex-col p-xs overflow-clip",
6170
- "bg-[var(--color-dropdown-bg)] border border-[var(--color-dropdown-border)] rounded-md shadow-lg",
6171
- "data-[state=open]:animate-in data-[state=open]:fade-in-0 data-[state=open]:zoom-in-95",
6172
- "data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=closed]:zoom-out-95",
6173
- "data-[side=bottom]:slide-in-from-top-2",
6174
- "min-w-[210px]"
6019
+ "flex items-center justify-between p-lg",
6020
+ "border-t border-datepicker-footer-border",
6021
+ "bg-datepicker-bg",
6022
+ className
6175
6023
  ),
6176
- children: [
6177
- onConvertToAdvanced && /* @__PURE__ */ jsxs43(
6178
- "button",
6179
- {
6180
- type: "button",
6181
- onClick: () => {
6182
- onConvertToAdvanced();
6183
- onOpenChange?.(false);
6184
- },
6185
- className: "flex items-center gap-base p-base rounded-base cursor-pointer transition-colors hover:bg-[var(--color-dropdown-item-hover)]",
6186
- children: [
6187
- /* @__PURE__ */ jsx49(
6188
- Icon27,
6189
- {
6190
- icon: faArrowRightOutline,
6191
- size: "sm",
6192
- className: "shrink-0 text-[var(--color-dropdown-item-icon)]"
6193
- }
6194
- ),
6195
- /* @__PURE__ */ jsx49("span", { className: "text-sm font-regular leading-sm text-[var(--color-dropdown-item-text)]", children: "Convert to advanced" })
6196
- ]
6197
- }
6198
- ),
6199
- onConvertToAdvanced && onDelete && /* @__PURE__ */ jsx49("div", { className: "h-px mx-base my-xs bg-[var(--color-border)]" }),
6200
- onDelete && /* @__PURE__ */ jsxs43(
6201
- "button",
6202
- {
6203
- type: "button",
6204
- onClick: () => {
6205
- onDelete();
6206
- onOpenChange?.(false);
6207
- },
6208
- className: "flex items-center gap-base p-base rounded-base cursor-pointer transition-colors hover:bg-[var(--color-dropdown-item-hover)]",
6209
- children: [
6210
- /* @__PURE__ */ jsx49(
6211
- Icon27,
6212
- {
6213
- icon: faTrashOutline,
6214
- size: "sm",
6215
- className: "shrink-0 text-[var(--color-destructive)]"
6216
- }
6217
- ),
6218
- /* @__PURE__ */ jsx49("span", { className: "text-sm font-regular leading-sm text-[var(--color-destructive)]", children: "Delete filter" })
6219
- ]
6220
- }
6221
- )
6222
- ]
6024
+ ...props,
6025
+ children
6223
6026
  }
6224
- ) })
6225
- ] });
6226
- KebabMenu.displayName = "KebabMenu";
6227
-
6228
- // 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";
6233
- var FilterEditor = ({
6234
- propertyDef,
6235
- condition,
6236
- mode,
6237
- onUpdate,
6238
- onClose,
6239
- open,
6240
- onOpenChange,
6241
- children
6242
- }) => {
6243
- const [view, setView] = React42.useState(
6244
- mode === "add" ? "value" : "operator"
6245
- );
6246
- const [localOperator, setLocalOperator] = React42.useState(
6247
- condition.operator
6027
+ )
6028
+ );
6029
+ DatePickerFooter.displayName = "DatePickerFooter";
6030
+ var DatePickerPanel = React41.forwardRef(
6031
+ ({ className, children, ...props }, ref) => /* @__PURE__ */ jsx44(
6032
+ "div",
6033
+ {
6034
+ ref,
6035
+ className: cn("flex items-start", className),
6036
+ ...props,
6037
+ children
6038
+ }
6039
+ )
6040
+ );
6041
+ DatePickerPanel.displayName = "DatePickerPanel";
6042
+ var DatePickerRoot = PopoverPrimitive5.Root;
6043
+ var DatePickerTrigger = PopoverPrimitive5.Trigger;
6044
+ var DatePickerPopover = React41.forwardRef(({ className, sideOffset = 4, align = "start", children, ...props }, ref) => /* @__PURE__ */ jsx44(PopoverPrimitive5.Portal, { children: /* @__PURE__ */ jsx44(
6045
+ PopoverPrimitive5.Content,
6046
+ {
6047
+ ref,
6048
+ sideOffset,
6049
+ align,
6050
+ className: cn(
6051
+ "z-50",
6052
+ "data-[state=open]:animate-in data-[state=open]:fade-in-0 data-[state=open]:zoom-in-95",
6053
+ "data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=closed]:zoom-out-95",
6054
+ "data-[side=bottom]:slide-in-from-top-2 data-[side=top]:slide-in-from-bottom-2",
6055
+ className
6056
+ ),
6057
+ ...props,
6058
+ children
6059
+ }
6060
+ ) }));
6061
+ DatePickerPopover.displayName = "DatePickerPopover";
6062
+ function getDefaultSuggestions(referenceDate) {
6063
+ const now = referenceDate ?? /* @__PURE__ */ new Date();
6064
+ const today = startOfDay(now);
6065
+ const dayOfWeek = getWeekdayIndex(today);
6066
+ const startOfThisWeek = new Date(today);
6067
+ startOfThisWeek.setDate(today.getDate() - dayOfWeek);
6068
+ const endOfThisWeek = new Date(startOfThisWeek);
6069
+ endOfThisWeek.setDate(startOfThisWeek.getDate() + 6);
6070
+ const startOfThisMonth = new Date(today.getFullYear(), today.getMonth(), 1);
6071
+ const endOfThisMonth = new Date(
6072
+ today.getFullYear(),
6073
+ today.getMonth() + 1,
6074
+ 0
6248
6075
  );
6249
- const [localValue, setLocalValue] = React42.useState(
6250
- condition.value
6076
+ const startOfThisYear = new Date(today.getFullYear(), 0, 1);
6077
+ const endOfThisYear = new Date(today.getFullYear(), 11, 31);
6078
+ const startOfLastWeek = new Date(startOfThisWeek);
6079
+ startOfLastWeek.setDate(startOfThisWeek.getDate() - 7);
6080
+ const endOfLastWeek = new Date(startOfThisWeek);
6081
+ endOfLastWeek.setDate(startOfThisWeek.getDate() - 1);
6082
+ const startOfLastMonth = new Date(
6083
+ today.getFullYear(),
6084
+ today.getMonth() - 1,
6085
+ 1
6251
6086
  );
6252
- React42.useEffect(() => {
6253
- if (open) {
6254
- setView(mode === "add" ? "value" : "operator");
6255
- setLocalOperator(condition.operator);
6256
- setLocalValue(condition.value);
6087
+ const endOfLastMonth = new Date(today.getFullYear(), today.getMonth(), 0);
6088
+ const startOfLastYear = new Date(today.getFullYear() - 1, 0, 1);
6089
+ const endOfLastYear = new Date(today.getFullYear() - 1, 11, 31);
6090
+ return [
6091
+ { label: "Today", getValue: () => today },
6092
+ {
6093
+ label: "This week",
6094
+ getValue: () => ({ from: startOfThisWeek, to: endOfThisWeek })
6095
+ },
6096
+ {
6097
+ label: "This month",
6098
+ getValue: () => ({ from: startOfThisMonth, to: endOfThisMonth })
6099
+ },
6100
+ {
6101
+ label: "This year",
6102
+ getValue: () => ({ from: startOfThisYear, to: endOfThisYear })
6103
+ },
6104
+ {
6105
+ label: "Last week",
6106
+ getValue: () => ({ from: startOfLastWeek, to: endOfLastWeek })
6107
+ },
6108
+ {
6109
+ label: "Last month",
6110
+ getValue: () => ({ from: startOfLastMonth, to: endOfLastMonth })
6111
+ },
6112
+ {
6113
+ label: "Last year",
6114
+ getValue: () => ({ from: startOfLastYear, to: endOfLastYear })
6257
6115
  }
6258
- }, [open, mode, condition.operator, condition.value]);
6259
- const handleOperatorSelect = (op) => {
6260
- setLocalOperator(op);
6261
- if (isNoValueOperator(op)) {
6262
- onUpdate({ ...condition, operator: op, value: null });
6263
- onOpenChange?.(false);
6264
- onClose();
6116
+ ];
6117
+ }
6118
+
6119
+ // src/components/ui/filter/value-inputs/date-value-input.tsx
6120
+ import { jsx as jsx45, jsxs as jsxs40 } from "react/jsx-runtime";
6121
+ var RELATIVE_DATE_PRESETS = [
6122
+ { group: "Past", options: ["Today", "Yesterday", "Last 7 days", "Last 14 days", "Last 30 days", "Last 90 days"] },
6123
+ { group: "Current", options: ["This week", "This month", "This quarter", "This year"] },
6124
+ { group: "Future", options: ["Tomorrow", "Next 7 days", "Next 14 days", "Next 30 days", "Next week", "Next month", "Next quarter"] }
6125
+ ];
6126
+ var DateCalendarValueInput = ({
6127
+ operator,
6128
+ value,
6129
+ onChange,
6130
+ onSubmit,
6131
+ className
6132
+ }) => {
6133
+ const isRange = operator === "is between";
6134
+ const pickerValue = React42.useMemo(() => {
6135
+ if (isRange) {
6136
+ if (Array.isArray(value) && value.length === 2) {
6137
+ const [from, to] = value;
6138
+ return { from, to };
6139
+ }
6140
+ return void 0;
6141
+ }
6142
+ return value instanceof Date ? value : void 0;
6143
+ }, [value, isRange]);
6144
+ const handleValueChange = (v) => {
6145
+ if (v instanceof Date) {
6146
+ onChange(v);
6147
+ if (!isRange) onSubmit?.();
6265
6148
  } else {
6266
- if (op !== localOperator) {
6267
- setLocalValue(null);
6149
+ const range = v;
6150
+ if (range.from && range.to) {
6151
+ onChange([range.from, range.to]);
6152
+ } else if (range.from) {
6153
+ onChange([range.from, range.from]);
6268
6154
  }
6269
- setView("value");
6270
6155
  }
6271
6156
  };
6272
- const handleSubmit = () => {
6273
- onUpdate({ ...condition, operator: localOperator, value: localValue });
6274
- onOpenChange?.(false);
6275
- onClose();
6276
- };
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,
6281
- {
6282
- sideOffset: 4,
6283
- align: "start",
6284
- className: cn(
6285
- "z-50 flex flex-col overflow-clip",
6286
- "bg-[var(--color-dropdown-bg)] border border-[var(--color-dropdown-border)] rounded-md shadow-lg",
6287
- "data-[state=open]:animate-in data-[state=open]:fade-in-0 data-[state=open]:zoom-in-95",
6288
- "data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=closed]:zoom-out-95",
6289
- "data-[side=bottom]:slide-in-from-top-2",
6290
- "min-w-[240px]"
6291
- ),
6292
- 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,
6296
- {
6297
- icon: propertyDef.icon,
6298
- size: "sm",
6299
- className: "shrink-0 text-[var(--color-dropdown-item-icon)]"
6300
- }
6301
- ),
6302
- /* @__PURE__ */ jsx50("span", { className: "text-sm font-semibold leading-sm text-[var(--color-foreground)]", children: propertyDef.label }),
6303
- localOperator && view === "value" && /* @__PURE__ */ jsxs44(
6304
- "button",
6305
- {
6306
- type: "button",
6307
- onClick: () => setView("operator"),
6308
- className: "ml-auto text-xs font-regular text-[var(--color-muted-foreground)] hover:text-[var(--color-foreground)] cursor-pointer transition-colors",
6309
- children: [
6310
- localOperator,
6311
- " \u25BE"
6312
- ]
6313
- }
6314
- )
6315
- ] }),
6316
- view === "operator" ? /* @__PURE__ */ jsx50("div", { className: "p-xs", children: /* @__PURE__ */ jsx50(
6317
- OperatorList,
6318
- {
6319
- dataType: propertyDef.type,
6320
- activeOperator: localOperator,
6321
- onSelect: handleOperatorSelect
6322
- }
6323
- ) }) : localOperator && /* @__PURE__ */ jsx50(
6324
- ValueInput,
6325
- {
6326
- dataType: propertyDef.type,
6327
- operator: localOperator,
6328
- value: localValue,
6329
- onChange: setLocalValue,
6330
- onSubmit: handleSubmit,
6331
- options: propertyDef.options
6332
- }
6333
- )
6334
- ]
6335
- }
6336
- ) })
6337
- ] });
6338
- };
6339
- FilterEditor.displayName = "FilterEditor";
6340
-
6341
- // 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]}`;
6157
+ const suggestions = React42.useMemo(() => getDefaultSuggestions(), []);
6158
+ return /* @__PURE__ */ jsx45("div", { className: cn("flex flex-col", className), children: /* @__PURE__ */ jsxs40(
6159
+ DatePicker,
6160
+ {
6161
+ mode: isRange ? "range" : "single",
6162
+ value: pickerValue,
6163
+ onValueChange: handleValueChange,
6164
+ children: [
6165
+ isRange && /* @__PURE__ */ jsx45(DatePickerSelects, {}),
6166
+ isRange ? /* @__PURE__ */ jsxs40(DatePickerPanel, { children: [
6167
+ /* @__PURE__ */ jsx45(DatePickerCalendar, {}),
6168
+ /* @__PURE__ */ jsx45(DatePickerSuggestions, { suggestions })
6169
+ ] }) : /* @__PURE__ */ jsx45(DatePickerCalendar, {}),
6170
+ isRange && /* @__PURE__ */ jsxs40(DatePickerFooter, { children: [
6171
+ /* @__PURE__ */ jsx45("div", {}),
6172
+ /* @__PURE__ */ jsx45("button", { type: "button", onClick: onSubmit, className: applyBtnClasses, children: "Apply" })
6173
+ ] })
6174
+ ]
6359
6175
  }
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
- }
6370
- var SegmentPopover = ({
6371
- open,
6372
- onOpenChange,
6373
- trigger,
6374
- children,
6375
- align = "start",
6376
- 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,
6176
+ ) });
6177
+ };
6178
+ DateCalendarValueInput.displayName = "DateCalendarValueInput";
6179
+ var PresetTagsValueInput = ({
6180
+ value,
6181
+ onChange,
6182
+ onSubmit,
6183
+ className
6184
+ }) => /* @__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: [
6185
+ /* @__PURE__ */ jsx45("span", { className: "text-xs font-semibold leading-xs text-[var(--color-muted-foreground)] uppercase px-xs", children: group.group }),
6186
+ /* @__PURE__ */ jsx45("div", { className: "flex flex-wrap gap-xs", children: group.options.map((preset) => /* @__PURE__ */ jsx45(
6187
+ "button",
6381
6188
  {
6382
- sideOffset: 4,
6383
- align,
6189
+ type: "button",
6190
+ onClick: () => {
6191
+ onChange(preset);
6192
+ onSubmit?.();
6193
+ },
6384
6194
  className: cn(
6385
- "z-50 flex flex-col overflow-clip",
6386
- "bg-[var(--color-dropdown-bg)] border border-[var(--color-dropdown-border)] rounded-md shadow-lg",
6387
- "data-[state=open]:animate-in data-[state=open]:fade-in-0 data-[state=open]:zoom-in-95",
6388
- "data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=closed]:zoom-out-95",
6389
- "data-[side=bottom]:slide-in-from-top-2"
6195
+ "px-base py-2xs rounded-base border cursor-pointer transition-colors text-sm font-regular leading-sm",
6196
+ 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)]"
6390
6197
  ),
6391
- style: { minWidth },
6392
- children
6393
- }
6394
- ) })
6395
- ] });
6396
- var InteractiveFilterChip = ({
6397
- propertyDef,
6398
- condition,
6399
- properties,
6400
- mode = "edit",
6401
- autoOpen = false,
6402
- onUpdate,
6403
- onPropertyChange,
6404
- onDelete,
6405
- onConvertToAdvanced,
6406
- className
6407
- }) => {
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(() => {
6415
- if (autoOpen && !autoOpenHandled.current && condition.operator && !isNoValueOperator(condition.operator)) {
6416
- autoOpenHandled.current = true;
6417
- setValueOpen(true);
6418
- }
6419
- }, [autoOpen, condition.operator]);
6420
- React43.useEffect(() => {
6421
- if (!operatorOpen && pendingValueOpen) {
6422
- setPendingValueOpen(false);
6423
- setValueOpen(true);
6424
- }
6425
- }, [operatorOpen, pendingValueOpen]);
6426
- const handleOperatorSelect = (op) => {
6427
- if (isNoValueOperator(op)) {
6428
- onUpdate({ ...condition, operator: op, value: null });
6429
- setOperatorOpen(false);
6430
- } else {
6431
- const resetValue = op !== condition.operator ? null : condition.value;
6432
- onUpdate({ ...condition, operator: op, value: resetValue });
6433
- setOperatorOpen(false);
6434
- if (resetValue == null) {
6435
- setPendingValueOpen(true);
6436
- }
6437
- }
6438
- };
6439
- const handleValueChange = (val) => {
6440
- onUpdate({ ...condition, value: val });
6441
- };
6442
- const handleValueSubmit = () => {
6443
- setValueOpen(false);
6198
+ children: preset
6199
+ },
6200
+ preset
6201
+ )) })
6202
+ ] }, group.group)) });
6203
+ PresetTagsValueInput.displayName = "PresetTagsValueInput";
6204
+
6205
+ // src/components/ui/filter/value-inputs/select-value-input.tsx
6206
+ import { Icon as Icon27 } from "@l3mpire/icons";
6207
+ import { jsx as jsx46, jsxs as jsxs41 } from "react/jsx-runtime";
6208
+ var DynamicOptionRow = ({
6209
+ option,
6210
+ selected,
6211
+ multi,
6212
+ onClick
6213
+ }) => /* @__PURE__ */ jsxs41(
6214
+ "button",
6215
+ {
6216
+ type: "button",
6217
+ onClick,
6218
+ className: cn(
6219
+ "flex items-start gap-base p-base rounded-base cursor-pointer transition-colors text-left",
6220
+ "hover:bg-[var(--color-dropdown-item-hover)]",
6221
+ selected && "bg-[var(--color-dropdown-item-hover)]"
6222
+ ),
6223
+ children: [
6224
+ multi && /* @__PURE__ */ jsx46(
6225
+ "span",
6226
+ {
6227
+ className: cn(
6228
+ "mt-[2px] flex items-center justify-center size-4 rounded-xs border transition-colors shrink-0",
6229
+ selected ? "bg-[var(--color-primary)] border-[var(--color-primary)]" : "border-[var(--color-input)] bg-[var(--color-background)]"
6230
+ ),
6231
+ children: selected && /* @__PURE__ */ jsx46("svg", { width: "10", height: "10", viewBox: "0 0 10 10", fill: "none", children: /* @__PURE__ */ jsx46(
6232
+ "path",
6233
+ {
6234
+ d: "M2 5L4 7L8 3",
6235
+ stroke: "white",
6236
+ strokeWidth: "1.5",
6237
+ strokeLinecap: "round",
6238
+ strokeLinejoin: "round"
6239
+ }
6240
+ ) })
6241
+ }
6242
+ ),
6243
+ option.icon && /* @__PURE__ */ jsx46(
6244
+ Icon27,
6245
+ {
6246
+ icon: option.icon,
6247
+ size: "sm",
6248
+ className: "shrink-0 mt-[1px] text-[var(--color-interactive-text-primary-dark-default,var(--color-primary))]"
6249
+ }
6250
+ ),
6251
+ /* @__PURE__ */ jsxs41("span", { className: "flex-1 flex flex-col gap-2xs min-w-0", children: [
6252
+ /* @__PURE__ */ jsx46("span", { className: "text-sm font-regular leading-sm text-[var(--color-foreground)] truncate", children: option.label }),
6253
+ option.description && /* @__PURE__ */ jsx46("span", { className: "text-xs font-regular leading-xs text-[var(--color-muted-foreground)]", children: option.description })
6254
+ ] })
6255
+ ]
6256
+ }
6257
+ );
6258
+ var DynamicOptionsDivider = () => /* @__PURE__ */ jsx46("div", { className: "h-px bg-[var(--color-dropdown-border)] mx-xs my-xs" });
6259
+ var SingleSelectValueInput = ({
6260
+ value,
6261
+ onChange,
6262
+ onSubmit,
6263
+ options,
6264
+ dynamicOptions,
6265
+ className
6266
+ }) => {
6267
+ const pick = (v) => {
6268
+ onChange(v);
6269
+ onSubmit?.();
6444
6270
  };
6445
- const hasOperator = !!condition.operator;
6446
- const displayValue = formatFilterValue(condition.value);
6447
- const hasValue = hasOperator && displayValue != null;
6448
- const badgeCount = getBadgeCount(condition.value);
6449
- return /* @__PURE__ */ jsxs45(
6271
+ return /* @__PURE__ */ jsxs41(
6450
6272
  "div",
6451
6273
  {
6452
6274
  className: cn(
6453
- "inline-flex items-center overflow-clip",
6454
- "bg-filter-chip-bg border border-filter-chip-border rounded-md shadow-sm",
6275
+ "flex flex-col gap-xs p-base max-h-[280px] overflow-y-auto",
6455
6276
  className
6456
6277
  ),
6457
6278
  children: [
6458
- properties ? /* @__PURE__ */ jsx51(
6459
- PropertySelector,
6460
- {
6461
- properties,
6462
- onSelect: (prop) => {
6463
- onPropertyChange?.(prop);
6464
- setPropertyOpen(false);
6465
- },
6466
- open: propertyOpen,
6467
- onOpenChange: setPropertyOpen,
6468
- children: /* @__PURE__ */ jsx51("div", { children: /* @__PURE__ */ jsx51(
6469
- FilterChipSegment,
6470
- {
6471
- segmentType: "property",
6472
- hasBorder: true,
6473
- icon: propertyDef.icon,
6474
- label: propertyDef.label,
6475
- onClick: () => setPropertyOpen(true)
6476
- }
6477
- ) })
6478
- }
6479
- ) : /* @__PURE__ */ jsx51(
6480
- FilterChipSegment,
6481
- {
6482
- segmentType: "property",
6483
- hasBorder: true,
6484
- icon: propertyDef.icon,
6485
- label: propertyDef.label
6486
- }
6487
- ),
6488
- /* @__PURE__ */ jsx51(
6489
- SegmentPopover,
6490
- {
6491
- open: operatorOpen,
6492
- onOpenChange: setOperatorOpen,
6493
- minWidth: "180px",
6494
- trigger: /* @__PURE__ */ jsx51("div", { children: /* @__PURE__ */ jsx51(
6495
- FilterChipSegment,
6496
- {
6497
- segmentType: hasOperator ? "operator" : "placeholder",
6498
- hasBorder: true,
6499
- label: hasOperator ? condition.operator : "Select condition",
6500
- onClick: () => setOperatorOpen(true)
6501
- }
6502
- ) }),
6503
- children: /* @__PURE__ */ jsx51("div", { className: "p-xs", children: /* @__PURE__ */ jsx51(
6504
- OperatorList,
6505
- {
6506
- dataType: propertyDef.type,
6507
- activeOperator: condition.operator,
6508
- onSelect: handleOperatorSelect
6509
- }
6510
- ) })
6511
- }
6512
- ),
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(
6543
- FilterChipSegment,
6279
+ dynamicOptions?.map((opt) => /* @__PURE__ */ jsx46(
6280
+ DynamicOptionRow,
6544
6281
  {
6545
- segmentType: "value",
6546
- hasBorder: true,
6547
- label: condition.operator
6548
- }
6549
- ),
6550
- hasOperator && /* @__PURE__ */ jsx51(
6551
- KebabMenu,
6282
+ option: opt,
6283
+ selected: value === opt.value,
6284
+ multi: false,
6285
+ onClick: () => pick(opt.value)
6286
+ },
6287
+ opt.value
6288
+ )),
6289
+ dynamicOptions && dynamicOptions.length > 0 && options.length > 0 && /* @__PURE__ */ jsx46(DynamicOptionsDivider, {}),
6290
+ options.map((opt) => /* @__PURE__ */ jsx46(
6291
+ "button",
6552
6292
  {
6553
- open: kebabOpen,
6554
- onOpenChange: setKebabOpen,
6555
- onConvertToAdvanced,
6556
- onDelete,
6557
- children: /* @__PURE__ */ jsx51("div", { children: /* @__PURE__ */ jsx51(
6558
- FilterChipSegment,
6559
- {
6560
- segmentType: "button",
6561
- onKebabClick: (e) => {
6562
- e.stopPropagation();
6563
- setKebabOpen(true);
6564
- }
6565
- }
6566
- ) })
6567
- }
6568
- )
6293
+ type: "button",
6294
+ onClick: () => pick(opt),
6295
+ className: cn(
6296
+ "flex items-center gap-base p-base rounded-base cursor-pointer transition-colors text-left",
6297
+ "hover:bg-[var(--color-dropdown-item-hover)]",
6298
+ value === opt && "bg-[var(--color-dropdown-item-hover)]"
6299
+ ),
6300
+ children: /* @__PURE__ */ jsx46("span", { className: "text-sm font-regular leading-sm text-[var(--color-foreground)]", children: opt })
6301
+ },
6302
+ opt
6303
+ ))
6569
6304
  ]
6570
6305
  }
6571
6306
  );
6572
6307
  };
6573
- InteractiveFilterChip.displayName = "InteractiveFilterChip";
6574
-
6575
- // 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";
6308
+ SingleSelectValueInput.displayName = "SingleSelectValueInput";
6309
+ var MultiSelectValueInput = ({
6310
+ value,
6311
+ onChange,
6312
+ onSubmit,
6313
+ options,
6314
+ dynamicOptions,
6315
+ className
6316
+ }) => {
6317
+ const selected = Array.isArray(value) ? value : [];
6318
+ const toggle = (v) => {
6319
+ const next = selected.includes(v) ? selected.filter((s) => s !== v) : [...selected, v];
6320
+ onChange(next);
6321
+ };
6322
+ return /* @__PURE__ */ jsxs41("div", { className: cn("flex flex-col gap-xs p-base", className), children: [
6323
+ /* @__PURE__ */ jsxs41("div", { className: "flex flex-col max-h-[240px] overflow-y-auto", children: [
6324
+ dynamicOptions?.map((opt) => /* @__PURE__ */ jsx46(
6325
+ DynamicOptionRow,
6326
+ {
6327
+ option: opt,
6328
+ selected: selected.includes(opt.value),
6329
+ multi: true,
6330
+ onClick: () => toggle(opt.value)
6331
+ },
6332
+ opt.value
6333
+ )),
6334
+ dynamicOptions && dynamicOptions.length > 0 && options.length > 0 && /* @__PURE__ */ jsx46(DynamicOptionsDivider, {}),
6335
+ options.map((opt) => {
6336
+ const isSelected = selected.includes(opt);
6337
+ return /* @__PURE__ */ jsxs41(
6338
+ "button",
6339
+ {
6340
+ type: "button",
6341
+ onClick: () => toggle(opt),
6342
+ className: cn(
6343
+ "flex items-center gap-base p-base rounded-base cursor-pointer transition-colors text-left",
6344
+ "hover:bg-[var(--color-dropdown-item-hover)]"
6345
+ ),
6346
+ children: [
6347
+ /* @__PURE__ */ jsx46(
6348
+ "span",
6349
+ {
6350
+ className: cn(
6351
+ "flex items-center justify-center size-4 rounded-xs border transition-colors",
6352
+ isSelected ? "bg-[var(--color-primary)] border-[var(--color-primary)]" : "border-[var(--color-input)] bg-[var(--color-background)]"
6353
+ ),
6354
+ children: isSelected && /* @__PURE__ */ jsx46("svg", { width: "10", height: "10", viewBox: "0 0 10 10", fill: "none", children: /* @__PURE__ */ jsx46(
6355
+ "path",
6356
+ {
6357
+ d: "M2 5L4 7L8 3",
6358
+ stroke: "white",
6359
+ strokeWidth: "1.5",
6360
+ strokeLinecap: "round",
6361
+ strokeLinejoin: "round"
6362
+ }
6363
+ ) })
6364
+ }
6365
+ ),
6366
+ /* @__PURE__ */ jsx46("span", { className: "text-sm font-regular leading-sm text-[var(--color-foreground)]", children: opt })
6367
+ ]
6368
+ },
6369
+ opt
6370
+ );
6371
+ })
6372
+ ] }),
6373
+ /* @__PURE__ */ jsx46("button", { type: "button", onClick: onSubmit, className: applyBtnClasses, children: "Apply" })
6374
+ ] });
6375
+ };
6376
+ MultiSelectValueInput.displayName = "MultiSelectValueInput";
6578
6377
 
6579
- // 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";
6583
- var btnBase = [
6584
- "flex items-center justify-center",
6585
- "min-h-[32px] max-h-[32px]",
6586
- "bg-gradient-to-t from-[var(--color-btn-outlined-neutral-bg-default)] from-[10%] to-[var(--color-btn-outlined-neutral-bg-gradient-to-default)]",
6587
- "border border-[var(--color-btn-outlined-neutral-border-default)] shadow-sm",
6588
- "cursor-pointer transition-colors",
6589
- "hover:from-[var(--color-btn-outlined-neutral-bg-hover)] hover:to-[var(--color-btn-outlined-neutral-bg-gradient-to-hover)]"
6590
- ];
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(
6594
- "button",
6378
+ // src/components/ui/filter/value-inputs/relation-value-input.tsx
6379
+ import { jsx as jsx47, jsxs as jsxs42 } from "react/jsx-runtime";
6380
+ var RelationValueInput = ({
6381
+ value,
6382
+ onChange,
6383
+ onSubmit,
6384
+ className
6385
+ }) => {
6386
+ const handleKeyDown = (e) => {
6387
+ if (e.key === "Enter") onSubmit?.();
6388
+ };
6389
+ return /* @__PURE__ */ jsxs42("div", { className: cn("flex flex-col gap-base p-base", className), children: [
6390
+ /* @__PURE__ */ jsx47(
6391
+ "input",
6595
6392
  {
6596
- ref,
6597
- type: "button",
6598
- onClick,
6599
- className: cn(
6600
- btnBase,
6601
- "gap-sm px-base py-sm min-w-[80px]",
6602
- "rounded-l-md -mr-px"
6603
- ),
6604
- ...props,
6605
- 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 }) })
6608
- ]
6393
+ type: "text",
6394
+ value: value ?? "",
6395
+ onChange: (e) => onChange(e.target.value),
6396
+ onKeyDown: handleKeyDown,
6397
+ placeholder: "Search...",
6398
+ autoFocus: true,
6399
+ className: inputClasses
6609
6400
  }
6610
6401
  ),
6611
- onClear && /* @__PURE__ */ jsx52(
6612
- "button",
6613
- {
6614
- type: "button",
6615
- onClick: (e) => {
6616
- e.stopPropagation();
6617
- onClear();
6618
- },
6619
- className: cn(
6620
- btnBase,
6621
- "p-sm",
6622
- "rounded-r-md -ml-px"
6623
- ),
6624
- "aria-label": "Clear all advanced filters",
6625
- children: /* @__PURE__ */ jsx52(Icon29, { icon: faXmarkOutline2, size: "sm", className: "text-[var(--color-foreground)]" })
6626
- }
6627
- )
6628
- ] })
6629
- );
6630
- AdvancedChip.displayName = "AdvancedChip";
6631
-
6632
- // src/components/ui/filter/advanced-popover.tsx
6633
- import * as React46 from "react";
6634
- import * as PopoverPrimitive10 from "@radix-ui/react-popover";
6635
- import { Icon as Icon31, faPlusOutline as faPlusOutline2, faChevronDownOutline as faChevronDownOutline3 } from "@l3mpire/icons";
6402
+ /* @__PURE__ */ jsx47("button", { type: "button", onClick: onSubmit, className: applyBtnClasses, children: "Apply" })
6403
+ ] });
6404
+ };
6405
+ RelationValueInput.displayName = "RelationValueInput";
6636
6406
 
6637
- // 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";
6642
- var selectBtnStyle = [
6643
- "flex items-center gap-base",
6644
- "px-base py-sm",
6645
- "bg-gradient-to-t from-[var(--color-btn-outlined-neutral-bg-default)] to-[var(--color-btn-outlined-neutral-bg-gradient-to-default)]",
6646
- "border border-[var(--color-btn-outlined-neutral-border-default)] rounded-md shadow-sm",
6647
- "cursor-pointer transition-colors",
6648
- "hover:from-[var(--color-btn-outlined-neutral-bg-hover)] hover:to-[var(--color-btn-outlined-neutral-bg-gradient-to-hover)]"
6649
- ];
6650
- var AdvancedRow = ({
6651
- connector,
6652
- onConnectorToggle,
6653
- propertyDef,
6654
- condition,
6655
- properties,
6656
- onUpdate,
6657
- onPropertyChange,
6658
- onDelete
6407
+ // src/components/ui/filter/value-input.tsx
6408
+ import { jsx as jsx48 } from "react/jsx-runtime";
6409
+ var ValueInput = ({
6410
+ dataType,
6411
+ operator,
6412
+ value,
6413
+ onChange,
6414
+ onSubmit,
6415
+ options = [],
6416
+ dynamicOptions,
6417
+ className
6659
6418
  }) => {
6660
- const [operatorOpen, setOperatorOpen] = React45.useState(false);
6661
- const [propertyOpen, setPropertyOpen] = React45.useState(false);
6662
- const handleOperatorSelect = (op) => {
6663
- if (isNoValueOperator(op)) {
6664
- onUpdate({ ...condition, operator: op, value: null });
6665
- } else {
6666
- const resetValue = op !== condition.operator ? null : condition.value;
6667
- onUpdate({ ...condition, operator: op, value: resetValue });
6668
- }
6669
- setOperatorOpen(false);
6670
- };
6671
- const handleValueChange = (val) => {
6672
- onUpdate({ ...condition, value: val });
6673
- };
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(
6677
- "button",
6678
- {
6679
- type: "button",
6680
- onClick: onConnectorToggle,
6681
- className: cn(
6682
- "shrink-0 flex items-center justify-center gap-xs",
6683
- "min-w-[64px] min-h-[24px] max-h-[24px] p-xs",
6684
- "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
- "border border-[var(--color-btn-outlined-neutral-border-default)] rounded-base shadow-sm",
6686
- "cursor-pointer transition-colors text-xs font-semibold leading-xs text-[var(--color-foreground)]",
6687
- "hover:from-[var(--color-btn-outlined-neutral-bg-hover)] hover:to-[var(--color-btn-outlined-neutral-bg-gradient-to-hover)]"
6688
- ),
6689
- children: [
6690
- connector,
6691
- /* @__PURE__ */ jsx53(Icon30, { icon: faRefreshOutline, size: "xs", className: "text-[var(--color-foreground)]" })
6692
- ]
6693
- }
6694
- ),
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)]" })
6704
- ] }) }),
6705
- /* @__PURE__ */ jsx53(PopoverPrimitive9.Portal, { children: /* @__PURE__ */ jsx53(
6706
- PopoverPrimitive9.Content,
6419
+ const inputType = getValueInputType(dataType, operator);
6420
+ if (!inputType) return null;
6421
+ switch (inputType) {
6422
+ case "TextInput":
6423
+ return /* @__PURE__ */ jsx48(TextValueInput, { value, onChange, onSubmit, className });
6424
+ case "NumberInput":
6425
+ return /* @__PURE__ */ jsx48(NumberValueInput, { value, onChange, onSubmit, className });
6426
+ case "NumberRange":
6427
+ return /* @__PURE__ */ jsx48(NumberRangeValueInput, { value, onChange, onSubmit, className });
6428
+ case "SingleSelect":
6429
+ return /* @__PURE__ */ jsx48(
6430
+ SingleSelectValueInput,
6707
6431
  {
6708
- sideOffset: 4,
6709
- align: "start",
6710
- className: cn(
6711
- "z-50 flex flex-col p-xs overflow-clip max-h-[300px] overflow-y-auto",
6712
- "bg-[var(--color-dropdown-bg)] border border-[var(--color-dropdown-border)] rounded-md shadow-lg",
6713
- "data-[state=open]:animate-in data-[state=open]:fade-in-0 data-[state=open]:zoom-in-95",
6714
- "data-[state=closed]:animate-out data-[state=closed]:fade-out-0",
6715
- "min-w-[200px]"
6716
- ),
6717
- children: properties.map((p) => /* @__PURE__ */ jsxs47(
6718
- "button",
6719
- {
6720
- type: "button",
6721
- onClick: () => {
6722
- onPropertyChange(p);
6723
- setPropertyOpen(false);
6724
- },
6725
- className: cn(
6726
- "flex items-center gap-base p-base rounded-base cursor-pointer transition-colors text-left",
6727
- "hover:bg-[var(--color-dropdown-item-hover)]",
6728
- p.id === condition.propertyId && "bg-[var(--color-dropdown-item-hover)]"
6729
- ),
6730
- 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 })
6733
- ]
6734
- },
6735
- p.id
6736
- ))
6432
+ value,
6433
+ onChange,
6434
+ onSubmit,
6435
+ options,
6436
+ dynamicOptions,
6437
+ className
6737
6438
  }
6738
- ) })
6739
- ] }),
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)]" })
6744
- ] }) }),
6745
- /* @__PURE__ */ jsx53(PopoverPrimitive9.Portal, { children: /* @__PURE__ */ jsx53(
6746
- PopoverPrimitive9.Content,
6439
+ );
6440
+ case "MultiSelect":
6441
+ return /* @__PURE__ */ jsx48(
6442
+ MultiSelectValueInput,
6747
6443
  {
6748
- sideOffset: 4,
6749
- align: "start",
6750
- className: cn(
6751
- "z-50 flex flex-col p-xs overflow-clip",
6752
- "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
- )
6444
+ value,
6445
+ onChange,
6446
+ onSubmit,
6447
+ options,
6448
+ dynamicOptions,
6449
+ className
6765
6450
  }
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
- ] });
6451
+ );
6452
+ case "DatePicker":
6453
+ case "DateRange":
6454
+ return /* @__PURE__ */ jsx48(
6455
+ DateCalendarValueInput,
6456
+ {
6457
+ operator,
6458
+ value,
6459
+ onChange,
6460
+ onSubmit,
6461
+ className
6462
+ }
6463
+ );
6464
+ case "RelationPicker":
6465
+ case "MultiRelationPicker":
6466
+ return /* @__PURE__ */ jsx48(RelationValueInput, { value, onChange, onSubmit, className });
6467
+ default:
6468
+ return null;
6469
+ }
6795
6470
  };
6796
- AdvancedRow.displayName = "AdvancedRow";
6471
+ ValueInput.displayName = "ValueInput";
6797
6472
 
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,
6473
+ // src/components/ui/filter/property-selector.tsx
6474
+ import * as React43 from "react";
6475
+ import * as PopoverPrimitive6 from "@radix-ui/react-popover";
6476
+ import {
6477
+ Icon as Icon28,
6478
+ faChevronLeftOutline as faChevronLeftOutline3,
6479
+ faChevronRightOutline as faChevronRightOutline3,
6480
+ faMagnifyingGlassOutline,
6481
+ faFilterOutline as faFilterOutline2
6482
+ } from "@l3mpire/icons";
6483
+ import { Fragment as Fragment4, jsx as jsx49, jsxs as jsxs43 } from "react/jsx-runtime";
6484
+ var AdvancedFilterFooter = ({ onClick, count }) => /* @__PURE__ */ jsxs43(Fragment4, { children: [
6485
+ /* @__PURE__ */ jsx49("div", { className: "h-px bg-[var(--color-dropdown-border)] mx-xs" }),
6486
+ /* @__PURE__ */ jsxs43(
6487
+ "button",
6488
+ {
6489
+ type: "button",
6490
+ onPointerDown: (e) => e.preventDefault(),
6491
+ onClick,
6492
+ className: "flex items-center gap-base p-base rounded-base cursor-pointer transition-colors hover:bg-[var(--color-dropdown-item-hover)]",
6493
+ children: [
6494
+ /* @__PURE__ */ jsx49(
6495
+ Icon28,
6496
+ {
6497
+ icon: faFilterOutline2,
6498
+ size: "sm",
6499
+ className: "shrink-0 text-[var(--color-dropdown-item-icon)]"
6500
+ }
6501
+ ),
6502
+ /* @__PURE__ */ jsx49("span", { className: "flex-1 text-sm font-regular leading-sm text-[var(--color-dropdown-item-text)] text-left truncate", children: "Advanced filter" }),
6503
+ count > 0 && /* @__PURE__ */ jsxs43("span", { className: "text-xs font-regular leading-xs text-[var(--color-muted-foreground)]", children: [
6504
+ count,
6505
+ " ",
6506
+ count === 1 ? "rule" : "rules"
6507
+ ] })
6508
+ ]
6509
+ }
6510
+ )
6511
+ ] });
6512
+ var PropertySelector = ({
6810
6513
  properties,
6811
- onFiltersChange,
6514
+ onSelect,
6812
6515
  open,
6813
6516
  onOpenChange,
6814
- children
6517
+ children,
6518
+ onAdvancedFilter,
6519
+ advancedFilterCount = 0
6815
6520
  }) => {
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);
6521
+ const handleAdvancedClick = (e) => {
6522
+ e.stopPropagation();
6523
+ e.preventDefault();
6524
+ onAdvancedFilter?.();
6839
6525
  };
6840
- const toggleLogicOp = (filterId) => {
6841
- onFiltersChange(
6842
- filters.map(
6843
- (f) => f.id === filterId ? { ...f, logicOperator: (f.logicOperator ?? "and") === "and" ? "or" : "and" } : f
6526
+ const showAdvancedFooter = !!onAdvancedFilter;
6527
+ const [activeGroup, setActiveGroup] = React43.useState(null);
6528
+ const [search, setSearch] = React43.useState("");
6529
+ React43.useEffect(() => {
6530
+ if (!open) {
6531
+ setActiveGroup(null);
6532
+ setSearch("");
6533
+ }
6534
+ }, [open]);
6535
+ const groups = React43.useMemo(() => {
6536
+ const map = /* @__PURE__ */ new Map();
6537
+ for (const prop of properties) {
6538
+ const existing = map.get(prop.group);
6539
+ if (existing) {
6540
+ existing.count++;
6541
+ } else {
6542
+ map.set(prop.group, {
6543
+ group: prop.group,
6544
+ groupLabel: prop.groupLabel,
6545
+ groupIcon: prop.icon,
6546
+ count: 1
6547
+ });
6548
+ }
6549
+ }
6550
+ return Array.from(map.values());
6551
+ }, [properties]);
6552
+ const globalSearchResults = React43.useMemo(() => {
6553
+ if (!search || activeGroup) return [];
6554
+ const lower = search.toLowerCase();
6555
+ return properties.filter((p) => p.label.toLowerCase().includes(lower));
6556
+ }, [properties, search, activeGroup]);
6557
+ const filteredGroups = React43.useMemo(() => {
6558
+ if (!search || activeGroup) return groups;
6559
+ const lower = search.toLowerCase();
6560
+ return groups.filter(
6561
+ (g) => g.groupLabel.toLowerCase().includes(lower) || properties.some(
6562
+ (p) => p.group === g.group && p.label.toLowerCase().includes(lower)
6844
6563
  )
6845
6564
  );
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,
6565
+ }, [groups, properties, search, activeGroup]);
6566
+ const filteredProperties = React43.useMemo(() => {
6567
+ if (!activeGroup) return [];
6568
+ const groupProps = properties.filter((p) => p.group === activeGroup);
6569
+ if (!search) return groupProps;
6570
+ const lower = search.toLowerCase();
6571
+ return groupProps.filter((p) => p.label.toLowerCase().includes(lower));
6572
+ }, [properties, activeGroup, search]);
6573
+ const activeGroupInfo = groups.find((g) => g.group === activeGroup);
6574
+ const showGlobalResults = search.length > 0 && !activeGroup && globalSearchResults.length > 0;
6575
+ return /* @__PURE__ */ jsxs43(PopoverPrimitive6.Root, { open, onOpenChange, children: [
6576
+ /* @__PURE__ */ jsx49(PopoverPrimitive6.Trigger, { asChild: true, children }),
6577
+ /* @__PURE__ */ jsx49(PopoverPrimitive6.Portal, { children: /* @__PURE__ */ jsxs43(
6578
+ PopoverPrimitive6.Content,
6851
6579
  {
6852
6580
  sideOffset: 4,
6853
6581
  align: "start",
6854
- collisionPadding: 16,
6855
- onOpenAutoFocus: (e) => e.preventDefault(),
6582
+ onCloseAutoFocus: (e) => e.preventDefault(),
6856
6583
  className: cn(
6857
- "z-50 flex flex-col",
6858
- "bg-[var(--color-background)] rounded-md shadow-lg",
6584
+ "z-50 flex flex-col gap-xs overflow-clip p-xs",
6585
+ "bg-[var(--color-dropdown-bg)] border border-[var(--color-dropdown-border)] rounded-md shadow-lg",
6859
6586
  "data-[state=open]:animate-in data-[state=open]:fade-in-0 data-[state=open]:zoom-in-95",
6860
6587
  "data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=closed]:zoom-out-95",
6861
6588
  "data-[side=bottom]:slide-in-from-top-2",
6862
- "w-[min(520px,calc(100vw-32px))]"
6589
+ "min-w-[230px]"
6863
6590
  ),
6864
6591
  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,
6889
- {
6890
- properties,
6891
- onSelect: handleAddFilter,
6892
- open: draftPickerOpen,
6893
- onOpenChange: setDraftPickerOpen,
6894
- children: /* @__PURE__ */ jsxs48(
6592
+ activeGroup === null ? (
6593
+ /* ── Level 1: Search + Categories ───────────────────────── */
6594
+ /* @__PURE__ */ jsxs43("div", { className: "flex flex-col gap-xs", children: [
6595
+ /* @__PURE__ */ jsxs43("div", { className: "flex items-center gap-base px-md py-base border border-[var(--color-input)] rounded-md", children: [
6596
+ /* @__PURE__ */ jsx49(
6597
+ Icon28,
6598
+ {
6599
+ icon: faMagnifyingGlassOutline,
6600
+ size: "sm",
6601
+ className: "shrink-0 text-[var(--color-muted-foreground)]"
6602
+ }
6603
+ ),
6604
+ /* @__PURE__ */ jsx49(
6605
+ "input",
6606
+ {
6607
+ type: "text",
6608
+ value: search,
6609
+ onChange: (e) => setSearch(e.target.value),
6610
+ placeholder: "Search...",
6611
+ autoFocus: true,
6612
+ className: "flex-1 text-sm font-regular leading-sm text-[var(--color-foreground)] bg-transparent outline-none placeholder:text-[var(--color-muted-foreground)]"
6613
+ }
6614
+ )
6615
+ ] }),
6616
+ showGlobalResults ? (
6617
+ /* ── Global search results (flat property list) ─────── */
6618
+ /* @__PURE__ */ jsx49("div", { className: "flex flex-col max-h-[300px] overflow-y-auto", children: globalSearchResults.map((prop) => /* @__PURE__ */ jsxs43(
6619
+ "button",
6620
+ {
6621
+ type: "button",
6622
+ onClick: () => {
6623
+ onSelect(prop);
6624
+ onOpenChange?.(false);
6625
+ },
6626
+ className: "flex items-center gap-base p-base rounded-base cursor-pointer transition-colors hover:bg-[var(--color-dropdown-item-hover)]",
6627
+ children: [
6628
+ /* @__PURE__ */ jsx49(
6629
+ Icon28,
6630
+ {
6631
+ icon: prop.icon,
6632
+ size: "sm",
6633
+ className: "shrink-0 text-[var(--color-dropdown-item-icon)]"
6634
+ }
6635
+ ),
6636
+ /* @__PURE__ */ jsx49("span", { className: "flex-1 text-sm font-regular leading-sm text-[var(--color-dropdown-item-text)] text-left truncate", children: prop.label }),
6637
+ /* @__PURE__ */ jsx49("span", { className: "text-xs font-regular leading-xs text-[var(--color-muted-foreground)]", children: prop.groupLabel })
6638
+ ]
6639
+ },
6640
+ prop.id
6641
+ )) })
6642
+ ) : (
6643
+ /* ── Group list ─────────────────────────────────────── */
6644
+ /* @__PURE__ */ jsxs43("div", { className: "flex flex-col", children: [
6645
+ filteredGroups.map((g) => /* @__PURE__ */ jsxs43(
6895
6646
  "button",
6896
6647
  {
6897
6648
  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
- ),
6649
+ onClick: () => {
6650
+ setActiveGroup(g.group);
6651
+ setSearch("");
6652
+ },
6653
+ className: "flex items-center gap-base p-base rounded-base cursor-pointer transition-colors hover:bg-[var(--color-dropdown-item-hover)]",
6905
6654
  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,
6655
+ /* @__PURE__ */ jsx49(
6656
+ Icon28,
6909
6657
  {
6910
- icon: faChevronDownOutline3,
6658
+ icon: g.groupIcon,
6659
+ size: "sm",
6660
+ className: "shrink-0 text-[var(--color-dropdown-item-icon)]"
6661
+ }
6662
+ ),
6663
+ /* @__PURE__ */ jsx49("span", { className: "flex-1 text-sm font-regular leading-sm text-[var(--color-dropdown-item-text)] text-left truncate", children: g.groupLabel }),
6664
+ /* @__PURE__ */ jsx49("span", { className: "text-xs font-semibold leading-xs text-[var(--color-muted-foreground)]", children: g.count }),
6665
+ /* @__PURE__ */ jsx49(
6666
+ Icon28,
6667
+ {
6668
+ icon: faChevronRightOutline3,
6911
6669
  size: "xs",
6912
- className: "shrink-0 text-[var(--color-foreground)]"
6670
+ className: "shrink-0 text-[var(--color-dropdown-item-icon)]"
6913
6671
  }
6914
6672
  )
6915
6673
  ]
6916
- }
6917
- )
6918
- }
6674
+ },
6675
+ g.group
6676
+ )),
6677
+ filteredGroups.length === 0 && /* @__PURE__ */ jsx49("span", { className: "p-base text-sm text-[var(--color-muted-foreground)]", children: "No results" })
6678
+ ] })
6919
6679
  )
6920
6680
  ] })
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
- }
6935
- ),
6936
- /* @__PURE__ */ jsx54(
6937
- "button",
6938
- {
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"
6943
- }
6944
- )
6945
- ] })
6681
+ ) : (
6682
+ /* ── Level 2: Properties ─────────────────────────────────── */
6683
+ /* @__PURE__ */ jsxs43("div", { className: "flex flex-col gap-xs", children: [
6684
+ /* @__PURE__ */ jsxs43(
6685
+ "button",
6686
+ {
6687
+ type: "button",
6688
+ onClick: () => {
6689
+ setActiveGroup(null);
6690
+ setSearch("");
6691
+ },
6692
+ className: "flex items-center gap-base p-base rounded-base cursor-pointer transition-colors hover:bg-[var(--color-dropdown-item-hover)]",
6693
+ children: [
6694
+ /* @__PURE__ */ jsx49(
6695
+ Icon28,
6696
+ {
6697
+ icon: faChevronLeftOutline3,
6698
+ size: "sm",
6699
+ className: "shrink-0 text-[var(--color-dropdown-item-icon)]"
6700
+ }
6701
+ ),
6702
+ /* @__PURE__ */ jsx49("span", { className: "flex-1 text-xs font-semibold leading-xs text-[var(--color-muted-foreground)] text-left truncate", children: activeGroupInfo?.groupLabel })
6703
+ ]
6704
+ }
6705
+ ),
6706
+ /* @__PURE__ */ jsxs43("div", { className: "flex items-center gap-base px-md py-base border border-[var(--color-input)] rounded-md", children: [
6707
+ /* @__PURE__ */ jsx49(
6708
+ Icon28,
6709
+ {
6710
+ icon: faMagnifyingGlassOutline,
6711
+ size: "sm",
6712
+ className: "shrink-0 text-[var(--color-muted-foreground)]"
6713
+ }
6714
+ ),
6715
+ /* @__PURE__ */ jsx49(
6716
+ "input",
6717
+ {
6718
+ type: "text",
6719
+ value: search,
6720
+ onChange: (e) => setSearch(e.target.value),
6721
+ placeholder: "Search...",
6722
+ autoFocus: true,
6723
+ className: "flex-1 text-sm font-regular leading-sm text-[var(--color-foreground)] bg-transparent outline-none placeholder:text-[var(--color-muted-foreground)]"
6724
+ }
6725
+ )
6726
+ ] }),
6727
+ /* @__PURE__ */ jsxs43("div", { className: "flex flex-col max-h-[300px] overflow-y-auto", children: [
6728
+ filteredProperties.map((prop) => /* @__PURE__ */ jsxs43(
6729
+ "button",
6730
+ {
6731
+ type: "button",
6732
+ onClick: () => {
6733
+ onSelect(prop);
6734
+ onOpenChange?.(false);
6735
+ },
6736
+ className: "flex items-center gap-base p-base rounded-base cursor-pointer transition-colors hover:bg-[var(--color-dropdown-item-hover)]",
6737
+ children: [
6738
+ /* @__PURE__ */ jsx49(
6739
+ Icon28,
6740
+ {
6741
+ icon: prop.icon,
6742
+ size: "sm",
6743
+ className: "shrink-0 text-[var(--color-dropdown-item-icon)]"
6744
+ }
6745
+ ),
6746
+ /* @__PURE__ */ jsx49("span", { className: "flex-1 text-sm font-regular leading-sm text-[var(--color-dropdown-item-text)] text-left truncate", children: prop.label })
6747
+ ]
6748
+ },
6749
+ prop.id
6750
+ )),
6751
+ filteredProperties.length === 0 && /* @__PURE__ */ jsx49("span", { className: "p-base text-sm text-[var(--color-muted-foreground)]", children: "No results" })
6752
+ ] })
6753
+ ] })
6754
+ ),
6755
+ showAdvancedFooter && /* @__PURE__ */ jsx49(
6756
+ AdvancedFilterFooter,
6757
+ {
6758
+ onClick: handleAdvancedClick,
6759
+ count: advancedFilterCount
6760
+ }
6761
+ )
6946
6762
  ]
6947
6763
  }
6948
6764
  ) })
6949
6765
  ] });
6950
6766
  };
6951
- AdvancedPopover.displayName = "AdvancedPopover";
6767
+ PropertySelector.displayName = "PropertySelector";
6952
6768
 
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,
6961
- properties,
6962
- onFiltersChange,
6963
- onClearAll,
6964
- children,
6965
- className,
6966
- open: openProp,
6967
- onOpenChange
6968
- }) => {
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(
7007
- "button",
7008
- {
7009
- type: "button",
7010
- className: cn(
7011
- "inline-flex items-center gap-sm px-base py-sm",
7012
- "min-h-[32px] max-h-[32px]",
7013
- "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
6769
+ // src/components/ui/filter/kebab-menu.tsx
6770
+ import * as PopoverPrimitive7 from "@radix-ui/react-popover";
6771
+ import { Icon as Icon29, faArrowRightOutline as faArrowRightOutline2, faTrashOutline } from "@l3mpire/icons";
6772
+ import { jsx as jsx50, jsxs as jsxs44 } from "react/jsx-runtime";
6773
+ var KebabMenu = ({
6774
+ onConvertToAdvanced,
6775
+ onDelete,
6776
+ open,
6777
+ onOpenChange,
6778
+ children
6779
+ }) => /* @__PURE__ */ jsxs44(PopoverPrimitive7.Root, { open, onOpenChange, children: [
6780
+ /* @__PURE__ */ jsx50(PopoverPrimitive7.Trigger, { asChild: true, children }),
6781
+ /* @__PURE__ */ jsx50(PopoverPrimitive7.Portal, { children: /* @__PURE__ */ jsxs44(
6782
+ PopoverPrimitive7.Content,
6783
+ {
6784
+ sideOffset: 4,
6785
+ align: "end",
6786
+ className: cn(
6787
+ "z-50 flex flex-col p-xs overflow-clip",
6788
+ "bg-[var(--color-dropdown-bg)] border border-[var(--color-dropdown-border)] rounded-md shadow-lg",
6789
+ "data-[state=open]:animate-in data-[state=open]:fade-in-0 data-[state=open]:zoom-in-95",
6790
+ "data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=closed]:zoom-out-95",
6791
+ "data-[side=bottom]:slide-in-from-top-2",
6792
+ "min-w-[210px]"
6793
+ ),
6794
+ children: [
6795
+ onConvertToAdvanced && /* @__PURE__ */ jsxs44(
6796
+ "button",
6797
+ {
6798
+ type: "button",
6799
+ onClick: () => {
6800
+ onConvertToAdvanced();
6801
+ onOpenChange?.(false);
6802
+ },
6803
+ className: "flex items-center gap-base p-base rounded-base cursor-pointer transition-colors hover:bg-[var(--color-dropdown-item-hover)]",
6804
+ children: [
6805
+ /* @__PURE__ */ jsx50(
6806
+ Icon29,
6807
+ {
6808
+ icon: faArrowRightOutline2,
6809
+ size: "sm",
6810
+ className: "shrink-0 text-[var(--color-dropdown-item-icon)]"
6811
+ }
6812
+ ),
6813
+ /* @__PURE__ */ jsx50("span", { className: "text-sm font-regular leading-sm text-[var(--color-dropdown-item-text)]", children: "Convert to advanced" })
6814
+ ]
6815
+ }
7018
6816
  ),
7019
- 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 }) })
7030
- ]
6817
+ onConvertToAdvanced && onDelete && /* @__PURE__ */ jsx50("div", { className: "h-px mx-base my-xs bg-[var(--color-border)]" }),
6818
+ onDelete && /* @__PURE__ */ jsxs44(
6819
+ "button",
6820
+ {
6821
+ type: "button",
6822
+ onClick: () => {
6823
+ onDelete();
6824
+ onOpenChange?.(false);
6825
+ },
6826
+ className: "flex items-center gap-base p-base rounded-base cursor-pointer transition-colors hover:bg-[var(--color-dropdown-item-hover)]",
6827
+ children: [
6828
+ /* @__PURE__ */ jsx50(
6829
+ Icon29,
6830
+ {
6831
+ icon: faTrashOutline,
6832
+ size: "sm",
6833
+ className: "shrink-0 text-[var(--color-destructive)]"
6834
+ }
6835
+ ),
6836
+ /* @__PURE__ */ jsx50("span", { className: "text-sm font-regular leading-sm text-[var(--color-destructive)]", children: "Delete filter" })
6837
+ ]
6838
+ }
6839
+ )
6840
+ ]
6841
+ }
6842
+ ) })
6843
+ ] });
6844
+ KebabMenu.displayName = "KebabMenu";
6845
+
6846
+ // src/components/ui/filter/filter-editor.tsx
6847
+ import * as React44 from "react";
6848
+ import * as PopoverPrimitive8 from "@radix-ui/react-popover";
6849
+ import { Icon as Icon30 } from "@l3mpire/icons";
6850
+ import { jsx as jsx51, jsxs as jsxs45 } from "react/jsx-runtime";
6851
+ var FilterEditor = ({
6852
+ propertyDef,
6853
+ condition,
6854
+ mode,
6855
+ onUpdate,
6856
+ onClose,
6857
+ open,
6858
+ onOpenChange,
6859
+ children
6860
+ }) => {
6861
+ const [view, setView] = React44.useState(
6862
+ mode === "add" ? "value" : "operator"
6863
+ );
6864
+ const [localOperator, setLocalOperator] = React44.useState(
6865
+ condition.operator
6866
+ );
6867
+ const [localValue, setLocalValue] = React44.useState(
6868
+ condition.value
6869
+ );
6870
+ React44.useEffect(() => {
6871
+ if (open) {
6872
+ setView(mode === "add" ? "value" : "operator");
6873
+ setLocalOperator(condition.operator);
6874
+ setLocalValue(condition.value);
6875
+ }
6876
+ }, [open, mode, condition.operator, condition.value]);
6877
+ const handleOperatorSelect = (op) => {
6878
+ setLocalOperator(op);
6879
+ if (isNoValueOperator(op)) {
6880
+ onUpdate({ ...condition, operator: op, value: null });
6881
+ onOpenChange?.(false);
6882
+ onClose();
6883
+ } else {
6884
+ if (op !== localOperator) {
6885
+ setLocalValue(null);
7031
6886
  }
7032
- ) }),
7033
- /* @__PURE__ */ jsx55(PopoverPrimitive11.Portal, { children: /* @__PURE__ */ jsxs49(
7034
- PopoverPrimitive11.Content,
6887
+ setView("value");
6888
+ }
6889
+ };
6890
+ const handleSubmit = () => {
6891
+ onUpdate({ ...condition, operator: localOperator, value: localValue });
6892
+ onOpenChange?.(false);
6893
+ onClose();
6894
+ };
6895
+ return /* @__PURE__ */ jsxs45(PopoverPrimitive8.Root, { open, onOpenChange, children: [
6896
+ /* @__PURE__ */ jsx51(PopoverPrimitive8.Trigger, { asChild: true, children }),
6897
+ /* @__PURE__ */ jsx51(PopoverPrimitive8.Portal, { children: /* @__PURE__ */ jsxs45(
6898
+ PopoverPrimitive8.Content,
7035
6899
  {
7036
6900
  sideOffset: 4,
7037
6901
  align: "start",
7038
- collisionPadding: 16,
7039
- onOpenAutoFocus: (e) => e.preventDefault(),
7040
6902
  className: cn(
7041
6903
  "z-50 flex flex-col overflow-clip",
7042
6904
  "bg-[var(--color-dropdown-bg)] border border-[var(--color-dropdown-border)] rounded-md shadow-lg",
7043
6905
  "data-[state=open]:animate-in data-[state=open]:fade-in-0 data-[state=open]:zoom-in-95",
7044
6906
  "data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=closed]:zoom-out-95",
7045
6907
  "data-[side=bottom]:slide-in-from-top-2",
7046
- "w-[min(520px,calc(100vw-32px))]"
6908
+ "min-w-[240px]"
7047
6909
  ),
7048
6910
  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,
6911
+ /* @__PURE__ */ jsxs45("div", { className: "flex items-center gap-base px-base pt-base pb-xs border-b border-[var(--color-border)]", children: [
6912
+ /* @__PURE__ */ jsx51(
6913
+ Icon30,
7109
6914
  {
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
- )
6915
+ icon: propertyDef.icon,
6916
+ size: "sm",
6917
+ className: "shrink-0 text-[var(--color-dropdown-item-icon)]"
7132
6918
  }
7133
6919
  ),
7134
- filters.length > 0 && /* @__PURE__ */ jsx55(
6920
+ /* @__PURE__ */ jsx51("span", { className: "text-sm font-semibold leading-sm text-[var(--color-foreground)]", children: propertyDef.label }),
6921
+ localOperator && view === "value" && /* @__PURE__ */ jsxs45(
7135
6922
  "button",
7136
6923
  {
7137
6924
  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"
6925
+ onClick: () => setView("operator"),
6926
+ className: "ml-auto text-xs font-regular text-[var(--color-muted-foreground)] hover:text-[var(--color-foreground)] cursor-pointer transition-colors",
6927
+ children: [
6928
+ localOperator,
6929
+ " \u25BE"
6930
+ ]
7144
6931
  }
7145
6932
  )
7146
- ] })
7147
- ]
7148
- }
7149
- ) })
7150
- ] });
6933
+ ] }),
6934
+ view === "operator" ? /* @__PURE__ */ jsx51("div", { className: "p-xs", children: /* @__PURE__ */ jsx51(
6935
+ OperatorList,
6936
+ {
6937
+ dataType: propertyDef.type,
6938
+ activeOperator: localOperator,
6939
+ onSelect: handleOperatorSelect
6940
+ }
6941
+ ) }) : localOperator && /* @__PURE__ */ jsx51(
6942
+ ValueInput,
6943
+ {
6944
+ dataType: propertyDef.type,
6945
+ operator: localOperator,
6946
+ value: localValue,
6947
+ onChange: setLocalValue,
6948
+ onSubmit: handleSubmit,
6949
+ options: propertyDef.options,
6950
+ dynamicOptions: propertyDef.dynamicOptions
6951
+ }
6952
+ )
6953
+ ]
6954
+ }
6955
+ ) })
6956
+ ] });
7151
6957
  };
7152
- SummaryChip.displayName = "SummaryChip";
6958
+ FilterEditor.displayName = "FilterEditor";
7153
6959
 
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");
6960
+ // src/components/ui/filter/interactive-filter-chip.tsx
6961
+ import * as React45 from "react";
6962
+ import * as PopoverPrimitive9 from "@radix-ui/react-popover";
6963
+ import { jsx as jsx52, jsxs as jsxs46 } from "react/jsx-runtime";
6964
+ function formatFilterValue(value) {
6965
+ if (value == null) return void 0;
6966
+ if (typeof value === "boolean") return value ? "Yes" : "No";
6967
+ if (value instanceof Date) {
6968
+ return value.toLocaleDateString("en-US", {
6969
+ month: "short",
6970
+ day: "numeric",
6971
+ year: "numeric"
7166
6972
  });
7167
- observer.observe(el);
7168
- return () => observer.disconnect();
7169
- }, [ref, override, breakpoint]);
7170
- return override ?? mode;
6973
+ }
6974
+ if (Array.isArray(value)) {
6975
+ if (value.length === 0) return void 0;
6976
+ if (value.length === 2 && typeof value[0] === "number") {
6977
+ return `${value[0]} \u2013 ${value[1]}`;
6978
+ }
6979
+ if (value.length === 2 && value[0] instanceof Date) {
6980
+ const fmt = (d) => d.toLocaleDateString("en-US", { month: "short", day: "numeric", year: "numeric" });
6981
+ return `${fmt(value[0])} \u2013 ${value[1] instanceof Date ? fmt(value[1]) : "\u2026"}`;
6982
+ }
6983
+ return String(value[0]);
6984
+ }
6985
+ return String(value);
7171
6986
  }
7172
-
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,
6987
+ function getBadgeCount(value) {
6988
+ if (Array.isArray(value) && value.length > 1 && typeof value[0] === "string") {
6989
+ return value.length;
6990
+ }
6991
+ return void 0;
6992
+ }
6993
+ var SegmentPopover = ({
6994
+ open,
6995
+ onOpenChange,
6996
+ trigger,
7182
6997
  children,
7183
- actions,
6998
+ align = "start",
6999
+ minWidth = "240px"
7000
+ }) => /* @__PURE__ */ jsxs46(PopoverPrimitive9.Root, { open, onOpenChange, children: [
7001
+ /* @__PURE__ */ jsx52(PopoverPrimitive9.Trigger, { asChild: true, children: trigger }),
7002
+ /* @__PURE__ */ jsx52(PopoverPrimitive9.Portal, { children: /* @__PURE__ */ jsx52(
7003
+ PopoverPrimitive9.Content,
7004
+ {
7005
+ sideOffset: 4,
7006
+ align,
7007
+ className: cn(
7008
+ "z-50 flex flex-col overflow-clip",
7009
+ "bg-[var(--color-dropdown-bg)] border border-[var(--color-dropdown-border)] rounded-md shadow-lg",
7010
+ "data-[state=open]:animate-in data-[state=open]:fade-in-0 data-[state=open]:zoom-in-95",
7011
+ "data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=closed]:zoom-out-95",
7012
+ "data-[side=bottom]:slide-in-from-top-2"
7013
+ ),
7014
+ style: { minWidth },
7015
+ children
7016
+ }
7017
+ ) })
7018
+ ] });
7019
+ var InteractiveFilterChip = ({
7020
+ propertyDef,
7021
+ condition,
7022
+ properties,
7023
+ mode = "edit",
7024
+ autoOpen = false,
7025
+ onUpdate,
7026
+ onPropertyChange,
7027
+ onDelete,
7028
+ onConvertToAdvanced,
7184
7029
  className
7185
7030
  }) => {
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;
7031
+ const [operatorOpen, setOperatorOpen] = React45.useState(false);
7032
+ const [valueOpen, setValueOpen] = React45.useState(false);
7033
+ const [propertyOpen, setPropertyOpen] = React45.useState(false);
7034
+ const [kebabOpen, setKebabOpen] = React45.useState(false);
7035
+ const [pendingValueOpen, setPendingValueOpen] = React45.useState(false);
7036
+ const autoOpenHandled = React45.useRef(false);
7037
+ React45.useEffect(() => {
7038
+ if (autoOpen && !autoOpenHandled.current && condition.operator && !isNoValueOperator(condition.operator)) {
7039
+ autoOpenHandled.current = true;
7040
+ setValueOpen(true);
7202
7041
  }
7203
- setPendingFilterId(newFilter.id);
7204
- onFilterStateChange({
7205
- ...filterState,
7206
- basicFilters: [...filterState.basicFilters, newFilter]
7207
- });
7208
- };
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);
7042
+ }, [autoOpen, condition.operator]);
7043
+ React45.useEffect(() => {
7044
+ if (!operatorOpen && pendingValueOpen) {
7045
+ setPendingValueOpen(false);
7046
+ setValueOpen(true);
7218
7047
  }
7219
- };
7220
- const handleDeleteFilter = (id) => {
7221
- onFilterStateChange({
7222
- ...filterState,
7223
- basicFilters: filterState.basicFilters.filter((f) => f.id !== id)
7224
- });
7225
- };
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);
7048
+ }, [operatorOpen, pendingValueOpen]);
7049
+ const handleOperatorSelect = (op) => {
7050
+ if (isNoValueOperator(op)) {
7051
+ onUpdate({ ...condition, operator: op, value: null });
7052
+ setOperatorOpen(false);
7053
+ } else {
7054
+ const resetValue = op !== condition.operator ? null : condition.value;
7055
+ onUpdate({ ...condition, operator: op, value: resetValue });
7056
+ setOperatorOpen(false);
7057
+ if (resetValue == null) {
7058
+ setPendingValueOpen(true);
7059
+ }
7236
7060
  }
7237
7061
  };
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
- });
7246
- };
7247
- const handleAdvancedFiltersChange = (filters) => {
7248
- onFilterStateChange({ ...filterState, advancedFilters: filters });
7249
- };
7250
- const handleClearAdvanced = () => {
7251
- onFilterStateChange({ ...filterState, advancedFilters: [] });
7252
- };
7253
- const handleClearAll = () => {
7254
- onFilterStateChange({
7255
- ...filterState,
7256
- basicFilters: [],
7257
- advancedFilters: []
7258
- });
7259
- };
7260
- const handleSortChange = (field, direction) => {
7261
- onFilterStateChange({ ...filterState, sort: { field, direction } });
7062
+ const handleValueChange = (val) => {
7063
+ onUpdate({ ...condition, value: val });
7262
7064
  };
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
- });
7065
+ const handleValueSubmit = () => {
7066
+ setValueOpen(false);
7275
7067
  };
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,
7284
- {
7285
- fields: sortFields,
7286
- activeField: filterState.sort.field,
7287
- direction: filterState.sort.direction,
7288
- onChange: handleSortChange,
7289
- iconOnly: isMinimal
7290
- }
7068
+ const hasOperator = !!condition.operator;
7069
+ const displayValue = formatFilterValue(condition.value);
7070
+ const hasValue = hasOperator && displayValue != null;
7071
+ const badgeCount = getBadgeCount(condition.value);
7072
+ return /* @__PURE__ */ jsxs46(
7073
+ "div",
7074
+ {
7075
+ className: cn(
7076
+ "inline-flex items-center overflow-clip",
7077
+ "bg-filter-chip-bg border border-filter-chip-border rounded-md shadow-sm",
7078
+ className
7291
7079
  ),
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,
7300
- {
7301
- count: totalCount,
7302
- filters: allFilters,
7303
- properties,
7304
- onFiltersChange: (filters) => {
7305
- onFilterStateChange({
7306
- ...filterState,
7307
- basicFilters: filters,
7308
- advancedFilters: []
7309
- });
7310
- },
7311
- onClearAll: handleClearAll,
7312
- open: summaryOpen,
7313
- onOpenChange: setSummaryOpen
7314
- }
7315
- )
7316
- }
7317
- ),
7318
- !showSummaryChip && /* @__PURE__ */ jsx56(
7080
+ children: [
7081
+ properties ? /* @__PURE__ */ jsx52(
7319
7082
  PropertySelector,
7320
7083
  {
7321
7084
  properties,
7322
- onSelect: handleAddFilter,
7323
- open: propertySelectorOpen,
7324
- onOpenChange: setPropertySelectorOpen,
7325
- onAdvancedFilter: handleOpenAdvanced,
7326
- advancedFilterCount,
7327
- children: /* @__PURE__ */ jsx56(FilterBarButton, { iconOnly: true })
7085
+ onSelect: (prop) => {
7086
+ onPropertyChange?.(prop);
7087
+ setPropertyOpen(false);
7088
+ },
7089
+ open: propertyOpen,
7090
+ onOpenChange: setPropertyOpen,
7091
+ children: /* @__PURE__ */ jsx52("div", { children: /* @__PURE__ */ jsx52(
7092
+ FilterChipSegment,
7093
+ {
7094
+ segmentType: "property",
7095
+ hasBorder: true,
7096
+ icon: propertyDef.icon,
7097
+ label: propertyDef.label,
7098
+ onClick: () => setPropertyOpen(true)
7099
+ }
7100
+ ) })
7328
7101
  }
7329
- )
7330
- ] }) : (
7331
- /* ── DEFAULT MODE ────────────────────────────────────── */
7332
- /* @__PURE__ */ jsxs50(Fragment5, { children: [
7333
- /* @__PURE__ */ jsx56(
7334
- AdvancedPopover,
7102
+ ) : /* @__PURE__ */ jsx52(
7103
+ FilterChipSegment,
7104
+ {
7105
+ segmentType: "property",
7106
+ hasBorder: true,
7107
+ icon: propertyDef.icon,
7108
+ label: propertyDef.label
7109
+ }
7110
+ ),
7111
+ /* @__PURE__ */ jsx52(
7112
+ SegmentPopover,
7113
+ {
7114
+ open: operatorOpen,
7115
+ onOpenChange: setOperatorOpen,
7116
+ minWidth: "180px",
7117
+ trigger: /* @__PURE__ */ jsx52("div", { children: /* @__PURE__ */ jsx52(
7118
+ FilterChipSegment,
7119
+ {
7120
+ segmentType: hasOperator ? "operator" : "placeholder",
7121
+ hasBorder: true,
7122
+ label: hasOperator ? condition.operator : "Select condition",
7123
+ onClick: () => setOperatorOpen(true)
7124
+ }
7125
+ ) }),
7126
+ children: /* @__PURE__ */ jsx52("div", { className: "p-xs", children: /* @__PURE__ */ jsx52(
7127
+ OperatorList,
7128
+ {
7129
+ dataType: propertyDef.type,
7130
+ activeOperator: condition.operator,
7131
+ onSelect: handleOperatorSelect
7132
+ }
7133
+ ) })
7134
+ }
7135
+ ),
7136
+ hasOperator && condition.operator && !isNoValueOperator(condition.operator) && (() => {
7137
+ const inputType = getValueInputType(propertyDef.type, condition.operator);
7138
+ const dateWide = inputType === "DatePicker" || inputType === "DateRange";
7139
+ return /* @__PURE__ */ jsx52(
7140
+ SegmentPopover,
7335
7141
  {
7336
- filters: filterState.advancedFilters,
7337
- properties,
7338
- onFiltersChange: handleAdvancedFiltersChange,
7339
- open: advancedOpen,
7340
- onOpenChange: setAdvancedOpen,
7341
- children: /* @__PURE__ */ jsx56(
7342
- "div",
7142
+ open: valueOpen,
7143
+ onOpenChange: setValueOpen,
7144
+ minWidth: dateWide ? "auto" : "240px",
7145
+ trigger: /* @__PURE__ */ jsx52("div", { children: /* @__PURE__ */ jsx52(
7146
+ FilterChipSegment,
7343
7147
  {
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
- )
7148
+ segmentType: hasValue ? "value" : "placeholder",
7149
+ hasBorder: true,
7150
+ label: hasValue ? displayValue : "Enter value",
7151
+ badgeCount,
7152
+ onClick: () => setValueOpen(true)
7153
+ }
7154
+ ) }),
7155
+ children: /* @__PURE__ */ jsx52(
7156
+ ValueInput,
7157
+ {
7158
+ dataType: propertyDef.type,
7159
+ operator: condition.operator,
7160
+ value: condition.value,
7161
+ onChange: handleValueChange,
7162
+ onSubmit: handleValueSubmit,
7163
+ options: propertyDef.options,
7164
+ dynamicOptions: propertyDef.dynamicOptions
7354
7165
  }
7355
7166
  )
7356
7167
  }
7357
- ),
7358
- filterState.basicFilters.map((filter) => {
7359
- const propDef = getPropertyDef(filter.propertyId);
7360
- if (!propDef) return null;
7361
- return /* @__PURE__ */ jsx56(
7362
- InteractiveFilterChip,
7168
+ );
7169
+ })(),
7170
+ hasOperator && condition.operator && isNoValueOperator(condition.operator) && /* @__PURE__ */ jsx52(
7171
+ FilterChipSegment,
7172
+ {
7173
+ segmentType: "value",
7174
+ hasBorder: true,
7175
+ label: condition.operator
7176
+ }
7177
+ ),
7178
+ hasOperator && /* @__PURE__ */ jsx52(
7179
+ KebabMenu,
7180
+ {
7181
+ open: kebabOpen,
7182
+ onOpenChange: setKebabOpen,
7183
+ onConvertToAdvanced,
7184
+ onDelete,
7185
+ children: /* @__PURE__ */ jsx52("div", { children: /* @__PURE__ */ jsx52(
7186
+ FilterChipSegment,
7363
7187
  {
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(
7387
- "button",
7388
- {
7389
- 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)]" })
7188
+ segmentType: "button",
7189
+ onKebabClick: (e) => {
7190
+ e.stopPropagation();
7191
+ setKebabOpen(true);
7392
7192
  }
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 })
7409
- ] });
7193
+ }
7194
+ ) })
7195
+ }
7196
+ )
7197
+ ]
7198
+ }
7199
+ );
7410
7200
  };
7411
- FilterSystem.displayName = "FilterSystem";
7201
+ InteractiveFilterChip.displayName = "InteractiveFilterChip";
7412
7202
 
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"
7203
+ // src/components/ui/filter/filter-system.tsx
7204
+ import * as React51 from "react";
7205
+ import { Icon as Icon35, faXmarkOutline as faXmarkOutline4, faPlusOutline as faPlusOutline4 } from "@l3mpire/icons";
7206
+
7207
+ // src/components/ui/filter/advanced-chip.tsx
7208
+ import * as React46 from "react";
7209
+ import { Icon as Icon31, faXmarkOutline as faXmarkOutline2 } from "@l3mpire/icons";
7210
+ import { jsx as jsx53, jsxs as jsxs47 } from "react/jsx-runtime";
7211
+ var btnBase = [
7212
+ "flex items-center justify-center",
7213
+ "min-h-[32px] max-h-[32px]",
7214
+ "bg-gradient-to-t from-[var(--color-btn-outlined-neutral-bg-default)] from-[10%] to-[var(--color-btn-outlined-neutral-bg-gradient-to-default)]",
7215
+ "border border-[var(--color-btn-outlined-neutral-border-default)] shadow-sm",
7216
+ "cursor-pointer transition-colors",
7217
+ "hover:from-[var(--color-btn-outlined-neutral-bg-hover)] hover:to-[var(--color-btn-outlined-neutral-bg-gradient-to-hover)]"
7454
7218
  ];
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;
7219
+ var AdvancedChip = React46.forwardRef(
7220
+ ({ className, count, onClear, onClick, ...props }, ref) => /* @__PURE__ */ jsxs47("div", { className: cn("inline-flex items-center", className), children: [
7221
+ /* @__PURE__ */ jsxs47(
7222
+ "button",
7223
+ {
7224
+ ref,
7225
+ type: "button",
7226
+ onClick,
7227
+ className: cn(
7228
+ btnBase,
7229
+ "gap-sm px-base py-sm min-w-[80px]",
7230
+ "rounded-l-md -mr-px"
7231
+ ),
7232
+ ...props,
7233
+ children: [
7234
+ /* @__PURE__ */ jsx53("span", { className: "text-sm font-semibold leading-sm whitespace-nowrap text-[var(--color-foreground)]", children: "Advanced filters" }),
7235
+ 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 }) })
7236
+ ]
7480
7237
  }
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;
7513
- }
7514
- if (!value || value instanceof Date) {
7515
- onValueChange?.({ from: date });
7516
- return;
7517
- }
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 });
7523
- }
7524
- },
7525
- [mode, value, onValueChange]
7526
- );
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
- ]
7553
- );
7554
- return /* @__PURE__ */ jsx57(DatePickerContext.Provider, { value: ctxValue, children: /* @__PURE__ */ jsx57(
7555
- "div",
7238
+ ),
7239
+ onClear && /* @__PURE__ */ jsx53(
7240
+ "button",
7556
7241
  {
7557
- ref,
7242
+ type: "button",
7243
+ onClick: (e) => {
7244
+ e.stopPropagation();
7245
+ onClear();
7246
+ },
7558
7247
  className: cn(
7559
- "flex flex-col overflow-clip",
7560
- "bg-datepicker-bg border border-datepicker-border rounded-md shadow-lg",
7561
- className
7248
+ btnBase,
7249
+ "p-sm",
7250
+ "rounded-r-md -ml-px"
7562
7251
  ),
7563
- ...props,
7564
- children
7252
+ "aria-label": "Clear all advanced filters",
7253
+ children: /* @__PURE__ */ jsx53(Icon31, { icon: faXmarkOutline2, size: "sm", className: "text-[var(--color-foreground)]" })
7565
7254
  }
7566
- ) });
7567
- }
7255
+ )
7256
+ ] })
7568
7257
  );
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
- );
7646
- };
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
7667
- });
7668
- }
7669
- for (let d = 1; d <= daysInMonth; d++) {
7670
- days.push({ date: new Date(year, month, d), isOutside: false });
7258
+ AdvancedChip.displayName = "AdvancedChip";
7259
+
7260
+ // src/components/ui/filter/advanced-popover.tsx
7261
+ import * as React48 from "react";
7262
+ import * as PopoverPrimitive11 from "@radix-ui/react-popover";
7263
+ import { Icon as Icon33, faPlusOutline as faPlusOutline2, faChevronDownOutline as faChevronDownOutline3 } from "@l3mpire/icons";
7264
+
7265
+ // src/components/ui/filter/advanced-row.tsx
7266
+ import * as React47 from "react";
7267
+ import * as PopoverPrimitive10 from "@radix-ui/react-popover";
7268
+ import { Icon as Icon32, faXmarkOutline as faXmarkOutline3, faRefreshOutline, faChevronDownOutline as faChevronDownOutline2 } from "@l3mpire/icons";
7269
+ import { jsx as jsx54, jsxs as jsxs48 } from "react/jsx-runtime";
7270
+ var selectBtnStyle = [
7271
+ "flex items-center gap-base",
7272
+ "px-base py-sm",
7273
+ "bg-gradient-to-t from-[var(--color-btn-outlined-neutral-bg-default)] to-[var(--color-btn-outlined-neutral-bg-gradient-to-default)]",
7274
+ "border border-[var(--color-btn-outlined-neutral-border-default)] rounded-md shadow-sm",
7275
+ "cursor-pointer transition-colors",
7276
+ "hover:from-[var(--color-btn-outlined-neutral-bg-hover)] hover:to-[var(--color-btn-outlined-neutral-bg-gradient-to-hover)]"
7277
+ ];
7278
+ var AdvancedRow = ({
7279
+ connector,
7280
+ onConnectorToggle,
7281
+ propertyDef,
7282
+ condition,
7283
+ properties,
7284
+ onUpdate,
7285
+ onPropertyChange,
7286
+ onDelete
7287
+ }) => {
7288
+ const [operatorOpen, setOperatorOpen] = React47.useState(false);
7289
+ const [propertyOpen, setPropertyOpen] = React47.useState(false);
7290
+ const handleOperatorSelect = (op) => {
7291
+ if (isNoValueOperator(op)) {
7292
+ onUpdate({ ...condition, operator: op, value: null });
7293
+ } else {
7294
+ const resetValue = op !== condition.operator ? null : condition.value;
7295
+ onUpdate({ ...condition, operator: op, value: resetValue });
7671
7296
  }
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
7297
+ setOperatorOpen(false);
7298
+ };
7299
+ const handleValueChange = (val) => {
7300
+ onUpdate({ ...condition, value: val });
7301
+ };
7302
+ const displayValue = condition.value == null ? "" : typeof condition.value === "string" ? condition.value : String(condition.value);
7303
+ return /* @__PURE__ */ jsxs48("div", { className: "flex items-center gap-base w-full min-w-0", children: [
7304
+ connector === "Where" ? /* @__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" }) }) : /* @__PURE__ */ jsxs48(
7305
+ "button",
7306
+ {
7307
+ type: "button",
7308
+ onClick: onConnectorToggle,
7309
+ className: cn(
7310
+ "shrink-0 flex items-center justify-center gap-xs",
7311
+ "min-w-[64px] min-h-[24px] max-h-[24px] p-xs",
7312
+ "bg-gradient-to-t from-[var(--color-btn-outlined-neutral-bg-default)] from-[10%] to-[var(--color-btn-outlined-neutral-bg-gradient-to-default)]",
7313
+ "border border-[var(--color-btn-outlined-neutral-border-default)] rounded-base shadow-sm",
7314
+ "cursor-pointer transition-colors text-xs font-semibold leading-xs text-[var(--color-foreground)]",
7315
+ "hover:from-[var(--color-btn-outlined-neutral-bg-hover)] hover:to-[var(--color-btn-outlined-neutral-bg-gradient-to-hover)]"
7679
7316
  ),
7680
- isOutside: true
7681
- });
7682
- }
7683
- const result = [];
7684
- for (let i = 0; i < days.length; i += 7) {
7685
- result.push(days.slice(i, i + 7));
7686
- }
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",
7317
+ children: [
7318
+ connector,
7319
+ /* @__PURE__ */ jsx54(Icon32, { icon: faRefreshOutline, size: "xs", className: "text-[var(--color-foreground)]" })
7320
+ ]
7321
+ }
7322
+ ),
7323
+ /* @__PURE__ */ jsxs48(PopoverPrimitive10.Root, { open: propertyOpen, onOpenChange: setPropertyOpen, children: [
7324
+ /* @__PURE__ */ jsx54(PopoverPrimitive10.Trigger, { asChild: true, children: /* @__PURE__ */ jsxs48("button", { type: "button", className: cn(selectBtnStyle, "min-w-0"), children: [
7325
+ /* @__PURE__ */ jsx54(Icon32, { icon: propertyDef.icon, size: "sm", className: "shrink-0 text-[var(--color-muted-foreground)]" }),
7326
+ /* @__PURE__ */ jsxs48("span", { className: "text-sm font-regular leading-sm text-[var(--color-foreground)] whitespace-nowrap truncate", children: [
7327
+ propertyDef.groupLabel,
7328
+ " > ",
7329
+ propertyDef.label
7330
+ ] }),
7331
+ /* @__PURE__ */ jsx54(Icon32, { icon: faChevronDownOutline2, size: "xs", className: "shrink-0 text-[var(--color-foreground)]" })
7332
+ ] }) }),
7333
+ /* @__PURE__ */ jsx54(PopoverPrimitive10.Portal, { children: /* @__PURE__ */ jsx54(
7334
+ PopoverPrimitive10.Content,
7335
+ {
7336
+ sideOffset: 4,
7337
+ align: "start",
7338
+ className: cn(
7339
+ "z-50 flex flex-col p-xs overflow-clip max-h-[300px] overflow-y-auto",
7340
+ "bg-[var(--color-dropdown-bg)] border border-[var(--color-dropdown-border)] rounded-md shadow-lg",
7341
+ "data-[state=open]:animate-in data-[state=open]:fade-in-0 data-[state=open]:zoom-in-95",
7342
+ "data-[state=closed]:animate-out data-[state=closed]:fade-out-0",
7343
+ "min-w-[200px]"
7344
+ ),
7345
+ children: properties.map((p) => /* @__PURE__ */ jsxs48(
7346
+ "button",
7347
+ {
7348
+ type: "button",
7349
+ onClick: () => {
7350
+ onPropertyChange(p);
7351
+ setPropertyOpen(false);
7352
+ },
7353
+ className: cn(
7354
+ "flex items-center gap-base p-base rounded-base cursor-pointer transition-colors text-left",
7355
+ "hover:bg-[var(--color-dropdown-item-hover)]",
7356
+ p.id === condition.propertyId && "bg-[var(--color-dropdown-item-hover)]"
7357
+ ),
7358
+ children: [
7359
+ /* @__PURE__ */ jsx54(Icon32, { icon: p.icon, size: "sm", className: "shrink-0 text-[var(--color-dropdown-item-icon)]" }),
7360
+ /* @__PURE__ */ jsx54("span", { className: "text-sm font-regular leading-sm text-[var(--color-dropdown-item-text)] truncate", children: p.label })
7361
+ ]
7362
+ },
7363
+ p.id
7364
+ ))
7365
+ }
7366
+ ) })
7367
+ ] }),
7368
+ /* @__PURE__ */ jsxs48(PopoverPrimitive10.Root, { open: operatorOpen, onOpenChange: setOperatorOpen, children: [
7369
+ /* @__PURE__ */ jsx54(PopoverPrimitive10.Trigger, { asChild: true, children: /* @__PURE__ */ jsxs48("button", { type: "button", className: cn(selectBtnStyle, "min-w-0"), children: [
7370
+ /* @__PURE__ */ jsx54("span", { className: "text-sm font-regular leading-sm text-[var(--color-foreground)] whitespace-nowrap truncate text-left", children: condition.operator ?? "Select" }),
7371
+ /* @__PURE__ */ jsx54(Icon32, { icon: faChevronDownOutline2, size: "xs", className: "shrink-0 text-[var(--color-foreground)]" })
7372
+ ] }) }),
7373
+ /* @__PURE__ */ jsx54(PopoverPrimitive10.Portal, { children: /* @__PURE__ */ jsx54(
7374
+ PopoverPrimitive10.Content,
7375
+ {
7376
+ sideOffset: 4,
7377
+ align: "start",
7378
+ className: cn(
7379
+ "z-50 flex flex-col p-xs overflow-clip",
7380
+ "bg-[var(--color-dropdown-bg)] border border-[var(--color-dropdown-border)] rounded-md shadow-lg",
7381
+ "data-[state=open]:animate-in data-[state=open]:fade-in-0 data-[state=open]:zoom-in-95",
7382
+ "data-[state=closed]:animate-out data-[state=closed]:fade-out-0",
7383
+ "min-w-[160px]"
7384
+ ),
7385
+ children: /* @__PURE__ */ jsx54(
7386
+ OperatorList,
7387
+ {
7388
+ dataType: propertyDef.type,
7389
+ activeOperator: condition.operator,
7390
+ onSelect: handleOperatorSelect
7391
+ }
7392
+ )
7393
+ }
7394
+ ) })
7395
+ ] }),
7396
+ condition.operator && !isNoValueOperator(condition.operator) && /* @__PURE__ */ jsx54(
7397
+ "input",
7398
+ {
7399
+ type: "text",
7400
+ value: displayValue,
7401
+ onChange: (e) => handleValueChange(e.target.value),
7402
+ placeholder: "Placeholder",
7403
+ className: cn(
7404
+ "flex-1 min-w-[80px] px-base py-sm rounded-md",
7405
+ "border border-[var(--color-input)]",
7406
+ "bg-[var(--color-background)] text-sm font-regular leading-sm text-[var(--color-foreground)]",
7407
+ "placeholder:text-[var(--color-muted-foreground)]",
7408
+ "focus:outline-none focus:ring-2 focus:ring-[var(--color-ring)] focus:ring-offset-0"
7409
+ )
7410
+ }
7411
+ ),
7412
+ /* @__PURE__ */ jsx54(
7413
+ "button",
7414
+ {
7415
+ type: "button",
7416
+ onClick: onDelete,
7417
+ className: "ml-auto shrink-0 flex items-center justify-center p-sm rounded-md cursor-pointer transition-colors hover:bg-[var(--color-accent)]",
7418
+ "aria-label": "Remove filter",
7419
+ children: /* @__PURE__ */ jsx54(Icon32, { icon: faXmarkOutline3, size: "sm", className: "text-[var(--color-foreground)]" })
7420
+ }
7421
+ )
7422
+ ] });
7423
+ };
7424
+ AdvancedRow.displayName = "AdvancedRow";
7425
+
7426
+ // src/components/ui/filter/advanced-popover.tsx
7427
+ import { jsx as jsx55, jsxs as jsxs49 } from "react/jsx-runtime";
7428
+ var outlinedBtn = [
7429
+ "flex items-center gap-sm px-base py-sm",
7430
+ "min-h-[32px] max-h-[32px] min-w-[80px]",
7431
+ "bg-gradient-to-t from-[var(--color-btn-outlined-neutral-bg-default)] from-[10%] to-[var(--color-btn-outlined-neutral-bg-gradient-to-default)]",
7432
+ "border border-[var(--color-btn-outlined-neutral-border-default)] rounded-md shadow-sm",
7433
+ "cursor-pointer transition-colors text-sm font-semibold leading-sm text-[var(--color-foreground)]",
7434
+ "hover:from-[var(--color-btn-outlined-neutral-bg-hover)] hover:to-[var(--color-btn-outlined-neutral-bg-gradient-to-hover)]"
7435
+ ];
7436
+ var AdvancedPopover = ({
7437
+ filters,
7438
+ properties,
7439
+ onFiltersChange,
7440
+ open,
7441
+ onOpenChange,
7442
+ children
7443
+ }) => {
7444
+ const [addSelectorOpen, setAddSelectorOpen] = React48.useState(false);
7445
+ const [draftPickerOpen, setDraftPickerOpen] = React48.useState(false);
7446
+ const getPropertyDef = (propertyId) => properties.find((p) => p.id === propertyId);
7447
+ const handleUpdateFilter = (updated) => {
7448
+ onFiltersChange(filters.map((f) => f.id === updated.id ? updated : f));
7449
+ };
7450
+ const handleDeleteFilter = (id) => {
7451
+ onFiltersChange(filters.filter((f) => f.id !== id));
7452
+ };
7453
+ const handlePropertyChange = (filterId, newProp) => {
7454
+ const newCondition = createFilterWithDefaults(newProp.id, newProp.type);
7455
+ onFiltersChange(
7456
+ filters.map((f) => f.id === filterId ? { ...newCondition, id: filterId } : f)
7457
+ );
7458
+ };
7459
+ const handleAddFilter = (property) => {
7460
+ const newFilter = createFilterWithDefaults(property.id, property.type);
7461
+ onFiltersChange([...filters, newFilter]);
7462
+ setAddSelectorOpen(false);
7463
+ };
7464
+ const handleClearAll = () => {
7465
+ onFiltersChange([]);
7466
+ onOpenChange?.(false);
7467
+ };
7468
+ const toggleLogicOp = (filterId) => {
7469
+ onFiltersChange(
7470
+ filters.map(
7471
+ (f) => f.id === filterId ? { ...f, logicOperator: (f.logicOperator ?? "and") === "and" ? "or" : "and" } : f
7472
+ )
7473
+ );
7474
+ };
7475
+ return /* @__PURE__ */ jsxs49(PopoverPrimitive11.Root, { open, onOpenChange, children: [
7476
+ /* @__PURE__ */ jsx55(PopoverPrimitive11.Trigger, { asChild: true, children }),
7477
+ /* @__PURE__ */ jsx55(PopoverPrimitive11.Portal, { children: /* @__PURE__ */ jsxs49(
7478
+ PopoverPrimitive11.Content,
7479
+ {
7480
+ sideOffset: 4,
7481
+ align: "start",
7482
+ collisionPadding: 16,
7483
+ onOpenAutoFocus: (e) => e.preventDefault(),
7484
+ className: cn(
7485
+ "z-50 flex flex-col",
7486
+ "bg-[var(--color-background)] rounded-md shadow-lg",
7487
+ "data-[state=open]:animate-in data-[state=open]:fade-in-0 data-[state=open]:zoom-in-95",
7488
+ "data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=closed]:zoom-out-95",
7489
+ "data-[side=bottom]:slide-in-from-top-2",
7490
+ "w-[min(520px,calc(100vw-32px))]"
7491
+ ),
7492
+ children: [
7493
+ /* @__PURE__ */ jsxs49("div", { className: "flex flex-col gap-base p-base", children: [
7494
+ filters.map((filter, i) => {
7495
+ const propDef = getPropertyDef(filter.propertyId);
7496
+ if (!propDef) return null;
7497
+ return /* @__PURE__ */ jsx55(
7498
+ AdvancedRow,
7499
+ {
7500
+ connector: i === 0 ? "Where" : (filter.logicOperator ?? "and") === "and" ? "And" : "Or",
7501
+ onConnectorToggle: i > 0 ? () => toggleLogicOp(filter.id) : void 0,
7502
+ propertyDef: propDef,
7503
+ condition: filter,
7504
+ properties,
7505
+ onUpdate: handleUpdateFilter,
7506
+ onPropertyChange: (p) => handlePropertyChange(filter.id, p),
7507
+ onDelete: () => handleDeleteFilter(filter.id)
7508
+ },
7509
+ filter.id
7510
+ );
7511
+ }),
7512
+ filters.length === 0 && /* ── Draft row: inline "Select property" placeholder ──── */
7513
+ /* @__PURE__ */ jsxs49("div", { className: "flex items-center gap-base w-full min-w-0", children: [
7514
+ /* @__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" }) }),
7515
+ /* @__PURE__ */ jsx55(
7516
+ PropertySelector,
7517
+ {
7518
+ properties,
7519
+ onSelect: handleAddFilter,
7520
+ open: draftPickerOpen,
7521
+ onOpenChange: setDraftPickerOpen,
7522
+ children: /* @__PURE__ */ jsxs49(
7523
+ "button",
7524
+ {
7525
+ type: "button",
7526
+ className: cn(
7527
+ "flex items-center gap-base px-base py-sm min-w-0",
7528
+ "bg-gradient-to-t from-[var(--color-btn-outlined-neutral-bg-default)] to-[var(--color-btn-outlined-neutral-bg-gradient-to-default)]",
7529
+ "border border-[var(--color-btn-outlined-neutral-border-default)] rounded-md shadow-sm",
7530
+ "cursor-pointer transition-colors",
7531
+ "hover:from-[var(--color-btn-outlined-neutral-bg-hover)] hover:to-[var(--color-btn-outlined-neutral-bg-gradient-to-hover)]"
7532
+ ),
7533
+ children: [
7534
+ /* @__PURE__ */ jsx55("span", { className: "text-sm font-regular leading-sm text-[var(--color-muted-foreground)] whitespace-nowrap", children: "Select property" }),
7535
+ /* @__PURE__ */ jsx55(
7536
+ Icon33,
7537
+ {
7538
+ icon: faChevronDownOutline3,
7539
+ size: "xs",
7540
+ className: "shrink-0 text-[var(--color-foreground)]"
7541
+ }
7542
+ )
7543
+ ]
7544
+ }
7545
+ )
7546
+ }
7547
+ )
7548
+ ] })
7549
+ ] }),
7550
+ /* @__PURE__ */ jsxs49("div", { className: "flex items-center justify-between p-base border-t border-[var(--color-border)]", children: [
7551
+ /* @__PURE__ */ jsx55(
7552
+ PropertySelector,
7553
+ {
7554
+ properties,
7555
+ onSelect: handleAddFilter,
7556
+ open: addSelectorOpen,
7557
+ onOpenChange: setAddSelectorOpen,
7558
+ children: /* @__PURE__ */ jsxs49("button", { type: "button", className: cn(outlinedBtn), children: [
7559
+ /* @__PURE__ */ jsx55(Icon33, { icon: faPlusOutline2, size: "sm", className: "text-[var(--color-foreground)]" }),
7560
+ "Add filter"
7561
+ ] })
7562
+ }
7563
+ ),
7564
+ /* @__PURE__ */ jsx55(
7565
+ "button",
7566
+ {
7567
+ type: "button",
7568
+ onClick: handleClearAll,
7569
+ className: "text-sm font-semibold leading-sm text-[var(--color-foreground)] cursor-pointer transition-colors hover:opacity-70 px-base py-sm",
7570
+ children: "Clear all filters"
7571
+ }
7572
+ )
7573
+ ] })
7574
+ ]
7575
+ }
7576
+ ) })
7577
+ ] });
7578
+ };
7579
+ AdvancedPopover.displayName = "AdvancedPopover";
7580
+
7581
+ // src/components/ui/filter/summary-chip.tsx
7582
+ import * as React49 from "react";
7583
+ import * as PopoverPrimitive12 from "@radix-ui/react-popover";
7584
+ import { Icon as Icon34, faSlidersOutline as faSlidersOutline2, faPlusOutline as faPlusOutline3, faChevronDownOutline as faChevronDownOutline4 } from "@l3mpire/icons";
7585
+ import { jsx as jsx56, jsxs as jsxs50 } from "react/jsx-runtime";
7586
+ var SummaryChip = ({
7587
+ count,
7588
+ filters,
7589
+ properties,
7590
+ onFiltersChange,
7591
+ onClearAll,
7592
+ children,
7593
+ className,
7594
+ open: openProp,
7595
+ onOpenChange
7596
+ }) => {
7597
+ const [uncontrolledOpen, setUncontrolledOpen] = React49.useState(false);
7598
+ const isControlled = openProp !== void 0;
7599
+ const open = isControlled ? openProp : uncontrolledOpen;
7600
+ const setOpen = (v) => {
7601
+ if (!isControlled) setUncontrolledOpen(v);
7602
+ onOpenChange?.(v);
7603
+ };
7604
+ const [addSelectorOpen, setAddSelectorOpen] = React49.useState(false);
7605
+ const [draftPickerOpen, setDraftPickerOpen] = React49.useState(false);
7606
+ const getPropertyDef = (propertyId) => properties.find((p) => p.id === propertyId);
7607
+ const handleUpdateFilter = (updated) => {
7608
+ onFiltersChange(filters.map((f) => f.id === updated.id ? updated : f));
7609
+ };
7610
+ const handleDeleteFilter = (id) => {
7611
+ const next = filters.filter((f) => f.id !== id);
7612
+ onFiltersChange(next);
7613
+ if (next.length === 0) setOpen(false);
7614
+ };
7615
+ const handlePropertyChange = (filterId, newProp) => {
7616
+ const newCondition = createFilterWithDefaults(newProp.id, newProp.type);
7617
+ onFiltersChange(
7618
+ filters.map((f) => f.id === filterId ? { ...newCondition, id: filterId } : f)
7619
+ );
7620
+ };
7621
+ const handleAddFilter = (property) => {
7622
+ const newFilter = createFilterWithDefaults(property.id, property.type);
7623
+ onFiltersChange([...filters, newFilter]);
7624
+ setAddSelectorOpen(false);
7625
+ };
7626
+ const toggleLogicOp = (filterId) => {
7627
+ onFiltersChange(
7628
+ filters.map(
7629
+ (f) => f.id === filterId ? { ...f, logicOperator: (f.logicOperator ?? "and") === "and" ? "or" : "and" } : f
7630
+ )
7631
+ );
7632
+ };
7633
+ return /* @__PURE__ */ jsxs50(PopoverPrimitive12.Root, { open, onOpenChange: setOpen, children: [
7634
+ /* @__PURE__ */ jsx56(PopoverPrimitive12.Trigger, { asChild: true, children: children ?? /* @__PURE__ */ jsxs50(
7635
+ "button",
7636
+ {
7637
+ type: "button",
7638
+ className: cn(
7639
+ "inline-flex items-center gap-sm px-base py-sm",
7640
+ "min-h-[32px] max-h-[32px]",
7641
+ "bg-gradient-to-t from-[var(--color-btn-outlined-neutral-bg-default)] from-[10%] to-[var(--color-btn-outlined-neutral-bg-gradient-to-default)]",
7642
+ "border border-[var(--color-btn-outlined-neutral-border-default)] rounded-md shadow-sm",
7643
+ "cursor-pointer transition-colors",
7644
+ "hover:from-[var(--color-btn-outlined-neutral-bg-hover)] hover:to-[var(--color-btn-outlined-neutral-bg-gradient-to-hover)]",
7645
+ className
7646
+ ),
7647
+ children: [
7648
+ /* @__PURE__ */ jsx56(
7649
+ Icon34,
7650
+ {
7651
+ icon: faSlidersOutline2,
7652
+ size: "sm",
7653
+ className: "shrink-0 text-[var(--color-foreground)]"
7654
+ }
7655
+ ),
7656
+ /* @__PURE__ */ jsx56("span", { className: "text-sm font-semibold leading-sm whitespace-nowrap text-[var(--color-foreground)]", children: "Filters" }),
7657
+ count > 0 && /* @__PURE__ */ jsx56("span", { className: "flex items-center p-2xs rounded-xs bg-filter-chip-badge-bg", children: /* @__PURE__ */ jsx56("span", { className: "text-[10px] font-semibold leading-2xs text-filter-chip-badge-text", children: count }) })
7658
+ ]
7659
+ }
7660
+ ) }),
7661
+ /* @__PURE__ */ jsx56(PopoverPrimitive12.Portal, { children: /* @__PURE__ */ jsxs50(
7662
+ PopoverPrimitive12.Content,
7663
+ {
7664
+ sideOffset: 4,
7665
+ align: "start",
7666
+ collisionPadding: 16,
7667
+ onOpenAutoFocus: (e) => e.preventDefault(),
7668
+ className: cn(
7669
+ "z-50 flex flex-col overflow-clip",
7670
+ "bg-[var(--color-dropdown-bg)] border border-[var(--color-dropdown-border)] rounded-md shadow-lg",
7671
+ "data-[state=open]:animate-in data-[state=open]:fade-in-0 data-[state=open]:zoom-in-95",
7672
+ "data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=closed]:zoom-out-95",
7673
+ "data-[side=bottom]:slide-in-from-top-2",
7674
+ "w-[min(520px,calc(100vw-32px))]"
7675
+ ),
7676
+ children: [
7677
+ /* @__PURE__ */ jsxs50("div", { className: "flex flex-col gap-base p-base", children: [
7678
+ filters.map((filter, i) => {
7679
+ const propDef = getPropertyDef(filter.propertyId);
7680
+ if (!propDef) return null;
7681
+ return /* @__PURE__ */ jsx56(
7682
+ AdvancedRow,
7683
+ {
7684
+ connector: i === 0 ? "Where" : (filter.logicOperator ?? "and") === "and" ? "And" : "Or",
7685
+ onConnectorToggle: i > 0 ? () => toggleLogicOp(filter.id) : void 0,
7686
+ propertyDef: propDef,
7687
+ condition: filter,
7688
+ properties,
7689
+ onUpdate: handleUpdateFilter,
7690
+ onPropertyChange: (p) => handlePropertyChange(filter.id, p),
7691
+ onDelete: () => handleDeleteFilter(filter.id)
7692
+ },
7693
+ filter.id
7694
+ );
7695
+ }),
7696
+ filters.length === 0 && /* ── Draft row: inline "Select property" placeholder ──── */
7697
+ /* @__PURE__ */ jsxs50("div", { className: "flex items-center gap-base w-full min-w-0", children: [
7698
+ /* @__PURE__ */ jsx56("div", { className: "shrink-0 w-[64px] flex items-center justify-end", children: /* @__PURE__ */ jsx56("span", { className: "text-xs font-semibold leading-xs text-[var(--color-muted-foreground)]", children: "Where" }) }),
7699
+ /* @__PURE__ */ jsx56(
7700
+ PropertySelector,
7701
+ {
7702
+ properties,
7703
+ onSelect: handleAddFilter,
7704
+ open: draftPickerOpen,
7705
+ onOpenChange: setDraftPickerOpen,
7706
+ children: /* @__PURE__ */ jsxs50(
7707
+ "button",
7708
+ {
7709
+ type: "button",
7710
+ className: cn(
7711
+ "flex items-center gap-base px-base py-sm min-w-0",
7712
+ "bg-gradient-to-t from-[var(--color-btn-outlined-neutral-bg-default)] to-[var(--color-btn-outlined-neutral-bg-gradient-to-default)]",
7713
+ "border border-[var(--color-btn-outlined-neutral-border-default)] rounded-md shadow-sm",
7714
+ "cursor-pointer transition-colors",
7715
+ "hover:from-[var(--color-btn-outlined-neutral-bg-hover)] hover:to-[var(--color-btn-outlined-neutral-bg-gradient-to-hover)]"
7716
+ ),
7717
+ children: [
7718
+ /* @__PURE__ */ jsx56("span", { className: "text-sm font-regular leading-sm text-[var(--color-muted-foreground)] whitespace-nowrap", children: "Select property" }),
7719
+ /* @__PURE__ */ jsx56(
7720
+ Icon34,
7721
+ {
7722
+ icon: faChevronDownOutline4,
7723
+ size: "xs",
7724
+ className: "shrink-0 text-[var(--color-foreground)]"
7725
+ }
7726
+ )
7727
+ ]
7728
+ }
7729
+ )
7730
+ }
7731
+ )
7732
+ ] })
7733
+ ] }),
7734
+ /* @__PURE__ */ jsxs50("div", { className: "flex items-center justify-between p-base border-t border-[var(--color-border)]", children: [
7735
+ /* @__PURE__ */ jsx56(
7736
+ PropertySelector,
7737
+ {
7738
+ properties,
7739
+ onSelect: handleAddFilter,
7740
+ open: addSelectorOpen,
7741
+ onOpenChange: setAddSelectorOpen,
7742
+ children: /* @__PURE__ */ jsxs50(
7743
+ "button",
7744
+ {
7745
+ type: "button",
7746
+ className: cn(
7747
+ "flex items-center gap-sm px-base py-sm",
7748
+ "min-h-[32px] max-h-[32px] min-w-[80px]",
7749
+ "bg-gradient-to-t from-[var(--color-btn-outlined-neutral-bg-default)] from-[10%] to-[var(--color-btn-outlined-neutral-bg-gradient-to-default)]",
7750
+ "border border-[var(--color-btn-outlined-neutral-border-default)] rounded-md shadow-sm",
7751
+ "cursor-pointer transition-colors text-sm font-semibold leading-sm text-[var(--color-foreground)]",
7752
+ "hover:from-[var(--color-btn-outlined-neutral-bg-hover)] hover:to-[var(--color-btn-outlined-neutral-bg-gradient-to-hover)]"
7753
+ ),
7754
+ children: [
7755
+ /* @__PURE__ */ jsx56(Icon34, { icon: faPlusOutline3, size: "sm", className: "text-[var(--color-foreground)]" }),
7756
+ "Add filter"
7757
+ ]
7758
+ }
7759
+ )
7760
+ }
7761
+ ),
7762
+ filters.length > 0 && /* @__PURE__ */ jsx56(
7763
+ "button",
7764
+ {
7765
+ type: "button",
7766
+ onClick: () => {
7767
+ onClearAll();
7768
+ setOpen(false);
7769
+ },
7770
+ className: "text-sm font-semibold leading-sm text-[var(--color-foreground)] cursor-pointer transition-colors hover:opacity-70 px-base py-sm",
7771
+ children: "Clear all filters"
7772
+ }
7773
+ )
7774
+ ] })
7775
+ ]
7776
+ }
7777
+ ) })
7778
+ ] });
7779
+ };
7780
+ SummaryChip.displayName = "SummaryChip";
7781
+
7782
+ // src/components/ui/filter/use-filter-bar-mode.ts
7783
+ import * as React50 from "react";
7784
+ var DEFAULT_BREAKPOINT = 600;
7785
+ function useFilterBarMode(ref, override, breakpoint = DEFAULT_BREAKPOINT) {
7786
+ const [mode, setMode] = React50.useState("default");
7787
+ React50.useEffect(() => {
7788
+ if (override) return;
7789
+ const el = ref.current;
7790
+ if (!el) return;
7791
+ const observer = new ResizeObserver((entries) => {
7792
+ const width = entries[0]?.contentRect.width ?? 0;
7793
+ setMode(width > breakpoint ? "default" : "minimal");
7794
+ });
7795
+ observer.observe(el);
7796
+ return () => observer.disconnect();
7797
+ }, [ref, override, breakpoint]);
7798
+ return override ?? mode;
7799
+ }
7800
+
7801
+ // src/components/ui/filter/filter-system.tsx
7802
+ import { Fragment as Fragment5, jsx as jsx57, jsxs as jsxs51 } from "react/jsx-runtime";
7803
+ var FilterSystem = ({
7804
+ properties,
7805
+ filterState,
7806
+ onFilterStateChange,
7807
+ sortFields,
7808
+ mode: modeOverride,
7809
+ breakpoint,
7810
+ children,
7811
+ actions,
7812
+ className
7813
+ }) => {
7814
+ const containerRef = React51.useRef(null);
7815
+ const mode = useFilterBarMode(containerRef, modeOverride, breakpoint);
7816
+ const [propertySelectorOpen, setPropertySelectorOpen] = React51.useState(false);
7817
+ const [advancedOpen, setAdvancedOpen] = React51.useState(false);
7818
+ const [summaryOpen, setSummaryOpen] = React51.useState(false);
7819
+ const [pendingFilterId, setPendingFilterId] = React51.useState(null);
7820
+ const allFilters = [...filterState.basicFilters, ...filterState.advancedFilters];
7821
+ const totalCount = allFilters.length;
7822
+ const handleAddFilter = (property) => {
7823
+ const newFilter = createFilterWithDefaults(property.id, property.type);
7824
+ if (newFilter.operator && isNoValueOperator(newFilter.operator)) {
7825
+ onFilterStateChange({
7826
+ ...filterState,
7827
+ basicFilters: [...filterState.basicFilters, newFilter]
7828
+ });
7829
+ return;
7830
+ }
7831
+ setPendingFilterId(newFilter.id);
7832
+ onFilterStateChange({
7833
+ ...filterState,
7834
+ basicFilters: [...filterState.basicFilters, newFilter]
7835
+ });
7836
+ };
7837
+ const handleUpdateFilter = (updated) => {
7838
+ onFilterStateChange({
7839
+ ...filterState,
7840
+ basicFilters: filterState.basicFilters.map(
7841
+ (f) => f.id === updated.id ? updated : f
7842
+ )
7843
+ });
7844
+ if (pendingFilterId === updated.id) {
7845
+ setPendingFilterId(null);
7846
+ }
7847
+ };
7848
+ const handleDeleteFilter = (id) => {
7849
+ onFilterStateChange({
7850
+ ...filterState,
7851
+ basicFilters: filterState.basicFilters.filter((f) => f.id !== id)
7852
+ });
7853
+ };
7854
+ const handlePropertyChange = (filterId, newProp) => {
7855
+ const newCondition = createFilterWithDefaults(newProp.id, newProp.type);
7856
+ onFilterStateChange({
7857
+ ...filterState,
7858
+ basicFilters: filterState.basicFilters.map(
7859
+ (f) => f.id === filterId ? { ...newCondition, id: filterId } : f
7860
+ )
7861
+ });
7862
+ if (newCondition.operator && !isNoValueOperator(newCondition.operator)) {
7863
+ setPendingFilterId(filterId);
7864
+ }
7865
+ };
7866
+ const handleConvertToAdvanced = (id) => {
7867
+ const filter = filterState.basicFilters.find((f) => f.id === id);
7868
+ if (!filter) return;
7869
+ onFilterStateChange({
7870
+ ...filterState,
7871
+ basicFilters: filterState.basicFilters.filter((f) => f.id !== id),
7872
+ advancedFilters: [...filterState.advancedFilters, filter]
7873
+ });
7874
+ };
7875
+ const handleAdvancedFiltersChange = (filters) => {
7876
+ onFilterStateChange({ ...filterState, advancedFilters: filters });
7877
+ };
7878
+ const handleClearAdvanced = () => {
7879
+ onFilterStateChange({ ...filterState, advancedFilters: [] });
7880
+ };
7881
+ const handleClearAll = () => {
7882
+ onFilterStateChange({
7883
+ ...filterState,
7884
+ basicFilters: [],
7885
+ advancedFilters: []
7886
+ });
7887
+ };
7888
+ const handleSortChange = (field, direction) => {
7889
+ onFilterStateChange({ ...filterState, sort: { field, direction } });
7890
+ };
7891
+ const getPropertyDef = (propertyId) => properties.find((p) => p.id === propertyId);
7892
+ const hasAdvanced = filterState.advancedFilters.length > 0;
7893
+ const isMinimal = mode === "minimal";
7894
+ const handleOpenAdvanced = () => {
7895
+ setPropertySelectorOpen(false);
7896
+ requestAnimationFrame(() => {
7897
+ if (isMinimal) {
7898
+ setSummaryOpen(true);
7899
+ } else {
7900
+ setAdvancedOpen(true);
7901
+ }
7902
+ });
7903
+ };
7904
+ const advancedFilterCount = filterState.advancedFilters.length;
7905
+ const showAdvancedChip = hasAdvanced || advancedOpen;
7906
+ const showSummaryChip = totalCount > 0 || summaryOpen;
7907
+ return /* @__PURE__ */ jsxs51(FilterBar, { ref: containerRef, className, children: [
7908
+ /* @__PURE__ */ jsxs51(FilterBarLeft, { className: "flex-nowrap flex-1 min-w-0 overflow-x-auto scrollbar-none outline-none [&>*]:shrink-0", children: [
7909
+ children,
7910
+ sortFields && filterState.sort && /* @__PURE__ */ jsx57(
7911
+ SortButton,
7912
+ {
7913
+ fields: sortFields,
7914
+ activeField: filterState.sort.field,
7915
+ direction: filterState.sort.direction,
7916
+ onChange: handleSortChange,
7917
+ iconOnly: isMinimal
7918
+ }
7919
+ ),
7920
+ isMinimal ? /* @__PURE__ */ jsxs51(Fragment5, { children: [
7921
+ /* @__PURE__ */ jsx57(
7922
+ "div",
7923
+ {
7924
+ className: showSummaryChip ? "inline-flex" : "inline-flex w-0 overflow-hidden opacity-0 pointer-events-none",
7925
+ "aria-hidden": !showSummaryChip || void 0,
7926
+ children: /* @__PURE__ */ jsx57(
7927
+ SummaryChip,
7928
+ {
7929
+ count: totalCount,
7930
+ filters: allFilters,
7931
+ properties,
7932
+ onFiltersChange: (filters) => {
7933
+ onFilterStateChange({
7934
+ ...filterState,
7935
+ basicFilters: filters,
7936
+ advancedFilters: []
7937
+ });
7938
+ },
7939
+ onClearAll: handleClearAll,
7940
+ open: summaryOpen,
7941
+ onOpenChange: setSummaryOpen
7942
+ }
7943
+ )
7944
+ }
7945
+ ),
7946
+ !showSummaryChip && /* @__PURE__ */ jsx57(
7947
+ PropertySelector,
7948
+ {
7949
+ properties,
7950
+ onSelect: handleAddFilter,
7951
+ open: propertySelectorOpen,
7952
+ onOpenChange: setPropertySelectorOpen,
7953
+ onAdvancedFilter: handleOpenAdvanced,
7954
+ advancedFilterCount,
7955
+ children: /* @__PURE__ */ jsx57(FilterBarButton, { iconOnly: true })
7956
+ }
7957
+ )
7958
+ ] }) : (
7959
+ /* ── DEFAULT MODE ────────────────────────────────────── */
7960
+ /* @__PURE__ */ jsxs51(Fragment5, { children: [
7961
+ /* @__PURE__ */ jsx57(
7962
+ AdvancedPopover,
7963
+ {
7964
+ filters: filterState.advancedFilters,
7965
+ properties,
7966
+ onFiltersChange: handleAdvancedFiltersChange,
7967
+ open: advancedOpen,
7968
+ onOpenChange: setAdvancedOpen,
7969
+ children: /* @__PURE__ */ jsx57(
7970
+ "div",
7707
7971
  {
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" })
7972
+ className: showAdvancedChip ? "inline-flex" : "inline-flex w-0 overflow-hidden opacity-0 pointer-events-none",
7973
+ "aria-hidden": !showAdvancedChip || void 0,
7974
+ children: /* @__PURE__ */ jsx57(
7975
+ AdvancedChip,
7976
+ {
7977
+ count: filterState.advancedFilters.length,
7978
+ onClick: () => setAdvancedOpen(true),
7979
+ onClear: handleClearAdvanced
7980
+ }
7981
+ )
7713
7982
  }
7714
- ),
7715
- /* @__PURE__ */ jsx57(
7983
+ )
7984
+ }
7985
+ ),
7986
+ filterState.basicFilters.map((filter) => {
7987
+ const propDef = getPropertyDef(filter.propertyId);
7988
+ if (!propDef) return null;
7989
+ return /* @__PURE__ */ jsx57(
7990
+ InteractiveFilterChip,
7991
+ {
7992
+ propertyDef: propDef,
7993
+ condition: filter,
7994
+ properties,
7995
+ mode: pendingFilterId === filter.id ? "add" : "edit",
7996
+ autoOpen: pendingFilterId === filter.id,
7997
+ onUpdate: handleUpdateFilter,
7998
+ onPropertyChange: (newProp) => handlePropertyChange(filter.id, newProp),
7999
+ onDelete: () => handleDeleteFilter(filter.id),
8000
+ onConvertToAdvanced: () => handleConvertToAdvanced(filter.id)
8001
+ },
8002
+ filter.id
8003
+ );
8004
+ }),
8005
+ /* @__PURE__ */ jsx57(
8006
+ PropertySelector,
8007
+ {
8008
+ properties,
8009
+ onSelect: handleAddFilter,
8010
+ open: propertySelectorOpen,
8011
+ onOpenChange: setPropertySelectorOpen,
8012
+ onAdvancedFilter: handleOpenAdvanced,
8013
+ advancedFilterCount,
8014
+ children: totalCount > 0 ? /* @__PURE__ */ jsx57(
7716
8015
  "button",
7717
8016
  {
7718
8017
  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" })
8018
+ 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)]",
8019
+ children: /* @__PURE__ */ jsx57(Icon35, { icon: faPlusOutline4, size: "sm", className: "text-[var(--color-foreground)]" })
7723
8020
  }
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
- ] })
8021
+ ) : /* @__PURE__ */ jsx57(FilterBarButton, {})
8022
+ }
8023
+ )
7745
8024
  ] })
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
8025
  ),
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
- }
8026
+ totalCount > 0 && /* @__PURE__ */ jsx57(
8027
+ "button",
8028
+ {
8029
+ type: "button",
8030
+ onClick: handleClearAll,
8031
+ 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)]",
8032
+ children: isMinimal ? /* @__PURE__ */ jsx57(Icon35, { icon: faXmarkOutline4, size: "sm", className: "text-[var(--color-foreground)]" }) : /* @__PURE__ */ jsx57("span", { className: "text-sm font-semibold leading-sm text-[var(--color-foreground)]", children: "Clear" })
8033
+ }
8034
+ )
8035
+ ] }),
8036
+ actions && /* @__PURE__ */ jsx57(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 })
8037
+ ] });
8038
+ };
8039
+ FilterSystem.displayName = "FilterSystem";
7911
8040
  export {
7912
8041
  AdvancedChip,
7913
8042
  AdvancedPopover,