@l3mpire/ui 2.11.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
@@ -149,7 +149,7 @@ var buttonVariants = cva2(
149
149
  },
150
150
  size: {
151
151
  sm: [
152
- "h-6 p-xs gap-xs",
152
+ "h-6 py-xs gap-xs",
153
153
  "text-xs",
154
154
  "min-w-16 rounded-base"
155
155
  ],
@@ -244,13 +244,13 @@ var buttonVariants = cva2(
244
244
  appearance: "ghost",
245
245
  intent: "brand",
246
246
  class: [
247
- "bg-btn-ghost-neutral-bg-default",
248
- "text-btn-ghost-neutral-text-default",
249
- "border-btn-ghost-neutral-border-default",
250
- "hover:bg-btn-ghost-neutral-bg-hover",
251
- "hover:text-btn-ghost-neutral-text-hover",
252
- "active:bg-btn-ghost-neutral-bg-pressed",
253
- "active:text-btn-ghost-neutral-text-pressed"
247
+ "bg-btn-ghost-brand-bg-default",
248
+ "text-btn-ghost-brand-text-default",
249
+ "border-btn-ghost-brand-border-default",
250
+ "hover:bg-btn-ghost-brand-bg-hover",
251
+ "hover:text-btn-ghost-brand-text-hover",
252
+ "active:bg-btn-ghost-brand-bg-pressed",
253
+ "active:text-btn-ghost-brand-text-pressed"
254
254
  ]
255
255
  },
256
256
  // ── Ghost + Alert ──────────────────────────────────────────────────
@@ -308,13 +308,17 @@ var Button = React2.forwardRef(
308
308
  const isDisabled = disabled || loading;
309
309
  const isIconOnly = iconOnlyProp ?? !children;
310
310
  const iconSize = iconSizeMap[size ?? "md"];
311
+ const smPadding = size === "sm" && !isIconOnly ? cn(
312
+ leftIcon || loading ? "pl-xs" : "pl-sm",
313
+ rightIcon ? "pr-xs" : "pr-sm"
314
+ ) : "";
311
315
  const variantClasses = buttonVariants({
312
316
  appearance,
313
317
  intent,
314
318
  size,
315
319
  iconOnly: isIconOnly || void 0,
316
320
  fullWidth,
317
- className
321
+ className: cn(smPadding, className)
318
322
  });
319
323
  if (asChild) {
320
324
  return /* @__PURE__ */ jsx2(Slot, { ref, className: cn(variantClasses), ...props, children });
@@ -5012,7 +5016,6 @@ var OPERATORS_BY_TYPE = {
5012
5016
  "is on or before",
5013
5017
  "is on or after",
5014
5018
  "is between",
5015
- "is relative",
5016
5019
  "is empty",
5017
5020
  "is not empty"
5018
5021
  ],
@@ -5031,7 +5034,7 @@ var OPERATORS_BY_TYPE = {
5031
5034
  var DEFAULT_OPERATOR_BY_TYPE = {
5032
5035
  text: "contains",
5033
5036
  number: "=",
5034
- date: "is relative",
5037
+ date: "is between",
5035
5038
  enum: "is",
5036
5039
  tags: "contains",
5037
5040
  boolean: "is true",
@@ -5059,7 +5062,6 @@ function getValueInputType(type, operator) {
5059
5062
  return operator === "is between" ? "NumberRange" : "NumberInput";
5060
5063
  if (type === "date") {
5061
5064
  if (operator === "is between") return "DateRange";
5062
- if (operator === "is relative") return "PresetTags";
5063
5065
  return "DatePicker";
5064
5066
  }
5065
5067
  if (type === "enum")
@@ -5354,7 +5356,7 @@ import { jsx as jsx40, jsxs as jsxs35 } from "react/jsx-runtime";
5354
5356
  var SaveViewButton = React40.forwardRef(
5355
5357
  ({ className, label = "Save view", onSave, onDropdown, ...props }, ref) => {
5356
5358
  const sharedStyle = [
5357
- "flex items-center justify-center",
5359
+ "relative flex items-center justify-center",
5358
5360
  "min-h-[32px] max-h-[32px]",
5359
5361
  "bg-gradient-to-t from-[var(--color-btn-solid-brand-bg-default)] from-[10%] to-[var(--color-btn-solid-brand-bg-gradient-to-default)]",
5360
5362
  "border border-[var(--color-btn-solid-brand-border-default)]",
@@ -5504,2117 +5506,2537 @@ var OperatorList = ({
5504
5506
  };
5505
5507
  OperatorList.displayName = "OperatorList";
5506
5508
 
5507
- // src/components/ui/filter/value-input.tsx
5509
+ // src/components/ui/filter/value-inputs/shared.ts
5510
+ var inputClasses = [
5511
+ "w-full px-base py-sm rounded-base border border-[var(--color-input)]",
5512
+ "bg-[var(--color-background)] text-sm font-regular leading-sm text-[var(--color-foreground)]",
5513
+ "placeholder:text-[var(--color-muted-foreground)]",
5514
+ "focus:outline-none focus:ring-2 focus:ring-[var(--color-ring)] focus:ring-offset-0"
5515
+ ].join(" ");
5516
+ var halfInputClasses = [
5517
+ "flex-1 px-base py-sm rounded-base border border-[var(--color-input)]",
5518
+ "bg-[var(--color-background)] text-sm font-regular leading-sm text-[var(--color-foreground)]",
5519
+ "focus:outline-none focus:ring-2 focus:ring-[var(--color-ring)]"
5520
+ ].join(" ");
5521
+ var applyBtnClasses = "self-end px-md py-sm text-sm font-semibold leading-sm text-[var(--color-primary-foreground)] bg-[var(--color-primary)] rounded-base cursor-pointer hover:opacity-90 transition-opacity";
5522
+
5523
+ // src/components/ui/filter/value-inputs/text-value-input.tsx
5508
5524
  import { jsx as jsx42, jsxs as jsxs37 } from "react/jsx-runtime";
5509
- var RELATIVE_DATE_PRESETS = [
5510
- { group: "Past", options: ["Today", "Yesterday", "Last 7 days", "Last 14 days", "Last 30 days", "Last 90 days"] },
5511
- { group: "Current", options: ["This week", "This month", "This quarter", "This year"] },
5512
- { group: "Future", options: ["Tomorrow", "Next 7 days", "Next 14 days", "Next 30 days", "Next week", "Next month", "Next quarter"] }
5513
- ];
5514
- var ValueInput = ({
5515
- dataType,
5516
- operator,
5525
+ var TextValueInput = ({
5517
5526
  value,
5518
5527
  onChange,
5519
5528
  onSubmit,
5520
- options = [],
5521
5529
  className
5522
5530
  }) => {
5523
- const inputType = getValueInputType(dataType, operator);
5524
- if (!inputType) return null;
5525
5531
  const handleKeyDown = (e) => {
5526
5532
  if (e.key === "Enter") onSubmit?.();
5527
5533
  };
5528
- switch (inputType) {
5529
- case "TextInput":
5530
- return /* @__PURE__ */ jsxs37("div", { className: cn("flex flex-col gap-base p-base", className), children: [
5531
- /* @__PURE__ */ jsx42(
5532
- "input",
5533
- {
5534
- type: "text",
5535
- value: value ?? "",
5536
- onChange: (e) => onChange(e.target.value),
5537
- onKeyDown: handleKeyDown,
5538
- placeholder: "Enter value...",
5539
- autoFocus: true,
5540
- className: cn(
5541
- "w-full px-base py-sm rounded-base border border-[var(--color-input)]",
5542
- "bg-[var(--color-background)] text-sm font-regular leading-sm text-[var(--color-foreground)]",
5543
- "placeholder:text-[var(--color-muted-foreground)]",
5544
- "focus:outline-none focus:ring-2 focus:ring-[var(--color-ring)] focus:ring-offset-0"
5545
- )
5546
- }
5547
- ),
5548
- /* @__PURE__ */ jsx42(
5549
- "button",
5550
- {
5551
- type: "button",
5552
- onClick: onSubmit,
5553
- className: "self-end px-md py-sm text-sm font-semibold leading-sm text-[var(--color-primary-foreground)] bg-[var(--color-primary)] rounded-base cursor-pointer hover:opacity-90 transition-opacity",
5554
- children: "Apply"
5555
- }
5556
- )
5557
- ] });
5558
- case "NumberInput":
5559
- return /* @__PURE__ */ jsxs37("div", { className: cn("flex flex-col gap-base p-base", className), children: [
5560
- /* @__PURE__ */ jsx42(
5561
- "input",
5562
- {
5563
- type: "number",
5564
- value: value ?? "",
5565
- onChange: (e) => onChange(e.target.value ? Number(e.target.value) : null),
5566
- onKeyDown: handleKeyDown,
5567
- placeholder: "Enter number...",
5568
- autoFocus: true,
5569
- className: cn(
5570
- "w-full px-base py-sm rounded-base border border-[var(--color-input)]",
5571
- "bg-[var(--color-background)] text-sm font-regular leading-sm text-[var(--color-foreground)]",
5572
- "placeholder:text-[var(--color-muted-foreground)]",
5573
- "focus:outline-none focus:ring-2 focus:ring-[var(--color-ring)] focus:ring-offset-0"
5574
- )
5575
- }
5576
- ),
5577
- /* @__PURE__ */ jsx42(
5578
- "button",
5579
- {
5580
- type: "button",
5581
- onClick: onSubmit,
5582
- className: "self-end px-md py-sm text-sm font-semibold leading-sm text-[var(--color-primary-foreground)] bg-[var(--color-primary)] rounded-base cursor-pointer hover:opacity-90 transition-opacity",
5583
- children: "Apply"
5584
- }
5585
- )
5586
- ] });
5587
- case "NumberRange": {
5588
- const rangeVal = value ?? [0, 0];
5589
- return /* @__PURE__ */ jsxs37("div", { className: cn("flex flex-col gap-base p-base", className), children: [
5590
- /* @__PURE__ */ jsxs37("div", { className: "flex items-center gap-base", children: [
5591
- /* @__PURE__ */ jsx42(
5592
- "input",
5593
- {
5594
- type: "number",
5595
- value: rangeVal[0] ?? "",
5596
- onChange: (e) => onChange([Number(e.target.value), rangeVal[1]]),
5597
- placeholder: "Min",
5598
- autoFocus: true,
5599
- className: cn(
5600
- "flex-1 px-base py-sm rounded-base border border-[var(--color-input)]",
5601
- "bg-[var(--color-background)] text-sm font-regular leading-sm text-[var(--color-foreground)]",
5602
- "focus:outline-none focus:ring-2 focus:ring-[var(--color-ring)]"
5603
- )
5604
- }
5605
- ),
5606
- /* @__PURE__ */ jsx42("span", { className: "text-sm text-[var(--color-muted-foreground)]", children: "and" }),
5607
- /* @__PURE__ */ jsx42(
5608
- "input",
5609
- {
5610
- type: "number",
5611
- value: rangeVal[1] ?? "",
5612
- onChange: (e) => onChange([rangeVal[0], Number(e.target.value)]),
5613
- placeholder: "Max",
5614
- className: cn(
5615
- "flex-1 px-base py-sm rounded-base border border-[var(--color-input)]",
5616
- "bg-[var(--color-background)] text-sm font-regular leading-sm text-[var(--color-foreground)]",
5617
- "focus:outline-none focus:ring-2 focus:ring-[var(--color-ring)]"
5618
- )
5619
- }
5620
- )
5621
- ] }),
5622
- /* @__PURE__ */ jsx42(
5623
- "button",
5624
- {
5625
- type: "button",
5626
- onClick: onSubmit,
5627
- className: "self-end px-md py-sm text-sm font-semibold leading-sm text-[var(--color-primary-foreground)] bg-[var(--color-primary)] rounded-base cursor-pointer hover:opacity-90 transition-opacity",
5628
- children: "Apply"
5629
- }
5630
- )
5631
- ] });
5632
- }
5633
- case "PresetTags":
5634
- return /* @__PURE__ */ jsx42("div", { className: cn("flex flex-col gap-base p-base max-w-[280px]", className), children: RELATIVE_DATE_PRESETS.map((group) => /* @__PURE__ */ jsxs37("div", { className: "flex flex-col gap-xs", children: [
5635
- /* @__PURE__ */ jsx42("span", { className: "text-xs font-semibold leading-xs text-[var(--color-muted-foreground)] uppercase px-xs", children: group.group }),
5636
- /* @__PURE__ */ jsx42("div", { className: "flex flex-wrap gap-xs", children: group.options.map((preset) => /* @__PURE__ */ jsx42(
5637
- "button",
5638
- {
5639
- type: "button",
5640
- onClick: () => {
5641
- onChange(preset);
5642
- onSubmit?.();
5643
- },
5644
- className: cn(
5645
- "px-base py-2xs rounded-base border cursor-pointer transition-colors text-sm font-regular leading-sm",
5646
- 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)]"
5647
- ),
5648
- children: preset
5649
- },
5650
- preset
5651
- )) })
5652
- ] }, group.group)) });
5653
- case "SingleSelect":
5654
- return /* @__PURE__ */ jsx42("div", { className: cn("flex flex-col gap-xs p-base max-h-[250px] overflow-y-auto", className), children: options.map((opt) => /* @__PURE__ */ jsx42(
5655
- "button",
5656
- {
5657
- type: "button",
5658
- onClick: () => {
5659
- onChange(opt);
5660
- onSubmit?.();
5661
- },
5662
- className: cn(
5663
- "flex items-center gap-base p-base rounded-base cursor-pointer transition-colors text-left",
5664
- "hover:bg-[var(--color-dropdown-item-hover)]",
5665
- value === opt && "bg-[var(--color-dropdown-item-hover)]"
5666
- ),
5667
- children: /* @__PURE__ */ jsx42("span", { className: "text-sm font-regular leading-sm text-[var(--color-foreground)]", children: opt })
5668
- },
5669
- opt
5670
- )) });
5671
- case "MultiSelect": {
5672
- const selected = Array.isArray(value) ? value : [];
5673
- return /* @__PURE__ */ jsxs37("div", { className: cn("flex flex-col gap-xs p-base", className), children: [
5674
- /* @__PURE__ */ jsx42("div", { className: "flex flex-col max-h-[200px] overflow-y-auto", children: options.map((opt) => {
5675
- const isSelected = selected.includes(opt);
5676
- return /* @__PURE__ */ jsxs37(
5677
- "button",
5678
- {
5679
- type: "button",
5680
- onClick: () => {
5681
- const next = isSelected ? selected.filter((s) => s !== opt) : [...selected, opt];
5682
- onChange(next);
5683
- },
5684
- className: cn(
5685
- "flex items-center gap-base p-base rounded-base cursor-pointer transition-colors text-left",
5686
- "hover:bg-[var(--color-dropdown-item-hover)]"
5687
- ),
5688
- children: [
5689
- /* @__PURE__ */ jsx42(
5690
- "span",
5691
- {
5692
- className: cn(
5693
- "flex items-center justify-center size-4 rounded-xs border transition-colors",
5694
- isSelected ? "bg-[var(--color-primary)] border-[var(--color-primary)]" : "border-[var(--color-input)] bg-[var(--color-background)]"
5695
- ),
5696
- children: isSelected && /* @__PURE__ */ jsx42("svg", { width: "10", height: "10", viewBox: "0 0 10 10", fill: "none", children: /* @__PURE__ */ jsx42("path", { d: "M2 5L4 7L8 3", stroke: "white", strokeWidth: "1.5", strokeLinecap: "round", strokeLinejoin: "round" }) })
5697
- }
5698
- ),
5699
- /* @__PURE__ */ jsx42("span", { className: "text-sm font-regular leading-sm text-[var(--color-foreground)]", children: opt })
5700
- ]
5701
- },
5702
- opt
5703
- );
5704
- }) }),
5705
- /* @__PURE__ */ jsx42(
5706
- "button",
5707
- {
5708
- type: "button",
5709
- onClick: onSubmit,
5710
- className: "self-end px-md py-sm text-sm font-semibold leading-sm text-[var(--color-primary-foreground)] bg-[var(--color-primary)] rounded-base cursor-pointer hover:opacity-90 transition-opacity",
5711
- children: "Apply"
5712
- }
5713
- )
5714
- ] });
5715
- }
5716
- // DatePicker, DateRange, RelationPicker, MultiRelationPicker
5717
- // Stub as text inputs for now — will wire to actual DatePicker/relation components
5718
- case "DatePicker":
5719
- return /* @__PURE__ */ jsxs37("div", { className: cn("flex flex-col gap-base p-base", className), children: [
5720
- /* @__PURE__ */ jsx42(
5721
- "input",
5722
- {
5723
- type: "date",
5724
- value: value instanceof Date ? value.toISOString().split("T")[0] : value ?? "",
5725
- onChange: (e) => onChange(e.target.value ? new Date(e.target.value) : null),
5726
- autoFocus: true,
5727
- className: cn(
5728
- "w-full px-base py-sm rounded-base border border-[var(--color-input)]",
5729
- "bg-[var(--color-background)] text-sm font-regular leading-sm text-[var(--color-foreground)]",
5730
- "focus:outline-none focus:ring-2 focus:ring-[var(--color-ring)]"
5731
- )
5732
- }
5733
- ),
5734
- /* @__PURE__ */ jsx42(
5735
- "button",
5736
- {
5737
- type: "button",
5738
- onClick: onSubmit,
5739
- className: "self-end px-md py-sm text-sm font-semibold leading-sm text-[var(--color-primary-foreground)] bg-[var(--color-primary)] rounded-base cursor-pointer hover:opacity-90 transition-opacity",
5740
- children: "Apply"
5741
- }
5742
- )
5743
- ] });
5744
- case "DateRange":
5745
- return /* @__PURE__ */ jsxs37("div", { className: cn("flex flex-col gap-base p-base", className), children: [
5746
- /* @__PURE__ */ jsxs37("div", { className: "flex items-center gap-base", children: [
5747
- /* @__PURE__ */ jsx42(
5748
- "input",
5749
- {
5750
- type: "date",
5751
- autoFocus: true,
5752
- className: cn(
5753
- "flex-1 px-base py-sm rounded-base border border-[var(--color-input)]",
5754
- "bg-[var(--color-background)] text-sm font-regular leading-sm text-[var(--color-foreground)]",
5755
- "focus:outline-none focus:ring-2 focus:ring-[var(--color-ring)]"
5756
- )
5757
- }
5758
- ),
5759
- /* @__PURE__ */ jsx42("span", { className: "text-sm text-[var(--color-muted-foreground)]", children: "to" }),
5760
- /* @__PURE__ */ jsx42(
5761
- "input",
5762
- {
5763
- type: "date",
5764
- className: cn(
5765
- "flex-1 px-base py-sm rounded-base border border-[var(--color-input)]",
5766
- "bg-[var(--color-background)] text-sm font-regular leading-sm text-[var(--color-foreground)]",
5767
- "focus:outline-none focus:ring-2 focus:ring-[var(--color-ring)]"
5768
- )
5769
- }
5770
- )
5771
- ] }),
5772
- /* @__PURE__ */ jsx42(
5773
- "button",
5774
- {
5775
- type: "button",
5776
- onClick: onSubmit,
5777
- className: "self-end px-md py-sm text-sm font-semibold leading-sm text-[var(--color-primary-foreground)] bg-[var(--color-primary)] rounded-base cursor-pointer hover:opacity-90 transition-opacity",
5778
- children: "Apply"
5779
- }
5780
- )
5781
- ] });
5782
- case "RelationPicker":
5783
- case "MultiRelationPicker":
5784
- return /* @__PURE__ */ jsxs37("div", { className: cn("flex flex-col gap-base p-base", className), children: [
5785
- /* @__PURE__ */ jsx42(
5786
- "input",
5787
- {
5788
- type: "text",
5789
- value: value ?? "",
5790
- onChange: (e) => onChange(e.target.value),
5791
- onKeyDown: handleKeyDown,
5792
- placeholder: "Search...",
5793
- autoFocus: true,
5794
- className: cn(
5795
- "w-full px-base py-sm rounded-base border border-[var(--color-input)]",
5796
- "bg-[var(--color-background)] text-sm font-regular leading-sm text-[var(--color-foreground)]",
5797
- "placeholder:text-[var(--color-muted-foreground)]",
5798
- "focus:outline-none focus:ring-2 focus:ring-[var(--color-ring)]"
5799
- )
5800
- }
5801
- ),
5802
- /* @__PURE__ */ jsx42(
5803
- "button",
5804
- {
5805
- type: "button",
5806
- onClick: onSubmit,
5807
- className: "self-end px-md py-sm text-sm font-semibold leading-sm text-[var(--color-primary-foreground)] bg-[var(--color-primary)] rounded-base cursor-pointer hover:opacity-90 transition-opacity",
5808
- children: "Apply"
5809
- }
5810
- )
5811
- ] });
5812
- default:
5813
- return null;
5814
- }
5534
+ return /* @__PURE__ */ jsxs37("div", { className: cn("flex flex-col gap-base p-base", className), children: [
5535
+ /* @__PURE__ */ jsx42(
5536
+ "input",
5537
+ {
5538
+ type: "text",
5539
+ value: value ?? "",
5540
+ onChange: (e) => onChange(e.target.value),
5541
+ onKeyDown: handleKeyDown,
5542
+ placeholder: "Enter value...",
5543
+ autoFocus: true,
5544
+ className: inputClasses
5545
+ }
5546
+ ),
5547
+ /* @__PURE__ */ jsx42("button", { type: "button", onClick: onSubmit, className: applyBtnClasses, children: "Apply" })
5548
+ ] });
5815
5549
  };
5816
- ValueInput.displayName = "ValueInput";
5550
+ TextValueInput.displayName = "TextValueInput";
5817
5551
 
5818
- // src/components/ui/filter/property-selector.tsx
5819
- import * as React41 from "react";
5820
- import * as PopoverPrimitive5 from "@radix-ui/react-popover";
5821
- import { Icon as Icon26, faChevronLeftOutline as faChevronLeftOutline2, faChevronRightOutline as faChevronRightOutline2, faMagnifyingGlassOutline } from "@l3mpire/icons";
5552
+ // src/components/ui/filter/value-inputs/number-value-input.tsx
5822
5553
  import { jsx as jsx43, jsxs as jsxs38 } from "react/jsx-runtime";
5823
- var PropertySelector = ({
5824
- properties,
5825
- onSelect,
5826
- open,
5827
- onOpenChange,
5828
- children
5554
+ var NumberValueInput = ({
5555
+ value,
5556
+ onChange,
5557
+ onSubmit,
5558
+ className
5829
5559
  }) => {
5830
- const [activeGroup, setActiveGroup] = React41.useState(null);
5831
- const [search, setSearch] = React41.useState("");
5832
- React41.useEffect(() => {
5833
- if (!open) {
5834
- setActiveGroup(null);
5835
- setSearch("");
5836
- }
5837
- }, [open]);
5838
- const groups = React41.useMemo(() => {
5839
- const map = /* @__PURE__ */ new Map();
5840
- for (const prop of properties) {
5841
- const existing = map.get(prop.group);
5842
- if (existing) {
5843
- existing.count++;
5844
- } else {
5845
- map.set(prop.group, {
5846
- group: prop.group,
5847
- groupLabel: prop.groupLabel,
5848
- groupIcon: prop.icon,
5849
- count: 1
5850
- });
5851
- }
5852
- }
5853
- return Array.from(map.values());
5854
- }, [properties]);
5855
- const filteredProperties = React41.useMemo(() => {
5856
- if (!activeGroup) return [];
5857
- const groupProps = properties.filter((p) => p.group === activeGroup);
5858
- if (!search) return groupProps;
5859
- const lower = search.toLowerCase();
5860
- return groupProps.filter((p) => p.label.toLowerCase().includes(lower));
5861
- }, [properties, activeGroup, search]);
5862
- const activeGroupInfo = groups.find((g) => g.group === activeGroup);
5863
- return /* @__PURE__ */ jsxs38(PopoverPrimitive5.Root, { open, onOpenChange, children: [
5864
- /* @__PURE__ */ jsx43(PopoverPrimitive5.Trigger, { asChild: true, children }),
5865
- /* @__PURE__ */ jsx43(PopoverPrimitive5.Portal, { children: /* @__PURE__ */ jsx43(
5866
- PopoverPrimitive5.Content,
5560
+ const handleKeyDown = (e) => {
5561
+ if (e.key === "Enter") onSubmit?.();
5562
+ };
5563
+ return /* @__PURE__ */ jsxs38("div", { className: cn("flex flex-col gap-base p-base", className), children: [
5564
+ /* @__PURE__ */ jsx43(
5565
+ "input",
5867
5566
  {
5868
- sideOffset: 4,
5869
- align: "start",
5870
- className: cn(
5871
- "z-50 flex flex-col gap-xs overflow-clip p-xs",
5872
- "bg-[var(--color-dropdown-bg)] border border-[var(--color-dropdown-border)] rounded-md shadow-lg",
5873
- "data-[state=open]:animate-in data-[state=open]:fade-in-0 data-[state=open]:zoom-in-95",
5874
- "data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=closed]:zoom-out-95",
5875
- "data-[side=bottom]:slide-in-from-top-2",
5876
- "min-w-[230px]"
5877
- ),
5878
- children: activeGroup === null ? (
5879
- /* ── Level 1: Categories ─────────────────────────────────── */
5880
- /* @__PURE__ */ jsx43("div", { className: "flex flex-col", children: groups.map((g) => /* @__PURE__ */ jsxs38(
5881
- "button",
5882
- {
5883
- type: "button",
5884
- onClick: () => setActiveGroup(g.group),
5885
- className: "flex items-center gap-base p-base rounded-base cursor-pointer transition-colors hover:bg-[var(--color-dropdown-item-hover)]",
5886
- children: [
5887
- /* @__PURE__ */ jsx43(
5888
- Icon26,
5889
- {
5890
- icon: g.groupIcon,
5891
- size: "sm",
5892
- className: "shrink-0 text-[var(--color-dropdown-item-icon)]"
5893
- }
5894
- ),
5895
- /* @__PURE__ */ jsx43("span", { className: "flex-1 text-sm font-regular leading-sm text-[var(--color-dropdown-item-text)] text-left truncate", children: g.groupLabel }),
5896
- /* @__PURE__ */ jsx43("span", { className: "text-xs font-semibold leading-xs text-[var(--color-muted-foreground)]", children: g.count }),
5897
- /* @__PURE__ */ jsx43(
5898
- Icon26,
5899
- {
5900
- icon: faChevronRightOutline2,
5901
- size: "xs",
5902
- className: "shrink-0 text-[var(--color-dropdown-item-icon)]"
5903
- }
5904
- )
5905
- ]
5906
- },
5907
- g.group
5908
- )) })
5909
- ) : (
5910
- /* ── Level 2: Properties ─────────────────────────────────── */
5911
- /* @__PURE__ */ jsxs38("div", { className: "flex flex-col gap-xs", children: [
5912
- /* @__PURE__ */ jsxs38(
5913
- "button",
5914
- {
5915
- type: "button",
5916
- onClick: () => {
5917
- setActiveGroup(null);
5918
- setSearch("");
5919
- },
5920
- className: "flex items-center gap-base p-base rounded-base cursor-pointer transition-colors hover:bg-[var(--color-dropdown-item-hover)]",
5921
- children: [
5922
- /* @__PURE__ */ jsx43(
5923
- Icon26,
5924
- {
5925
- icon: faChevronLeftOutline2,
5926
- size: "sm",
5927
- className: "shrink-0 text-[var(--color-dropdown-item-icon)]"
5928
- }
5929
- ),
5930
- /* @__PURE__ */ jsx43("span", { className: "flex-1 text-xs font-semibold leading-xs text-[var(--color-muted-foreground)] text-left truncate", children: activeGroupInfo?.groupLabel })
5931
- ]
5932
- }
5933
- ),
5934
- /* @__PURE__ */ jsxs38("div", { className: "flex items-center gap-base px-md py-base border border-[var(--color-input)] rounded-md", children: [
5935
- /* @__PURE__ */ jsx43(
5936
- Icon26,
5937
- {
5938
- icon: faMagnifyingGlassOutline,
5939
- size: "sm",
5940
- className: "shrink-0 text-[var(--color-muted-foreground)]"
5941
- }
5942
- ),
5943
- /* @__PURE__ */ jsx43(
5944
- "input",
5945
- {
5946
- type: "text",
5947
- value: search,
5948
- onChange: (e) => setSearch(e.target.value),
5949
- placeholder: "Search...",
5950
- autoFocus: true,
5951
- className: "flex-1 text-sm font-regular leading-sm text-[var(--color-foreground)] bg-transparent outline-none placeholder:text-[var(--color-muted-foreground)]"
5952
- }
5953
- )
5954
- ] }),
5955
- /* @__PURE__ */ jsxs38("div", { className: "flex flex-col max-h-[300px] overflow-y-auto", children: [
5956
- filteredProperties.map((prop) => /* @__PURE__ */ jsxs38(
5957
- "button",
5958
- {
5959
- type: "button",
5960
- onClick: () => {
5961
- onSelect(prop);
5962
- onOpenChange?.(false);
5963
- },
5964
- className: "flex items-center gap-base p-base rounded-base cursor-pointer transition-colors hover:bg-[var(--color-dropdown-item-hover)]",
5965
- children: [
5966
- /* @__PURE__ */ jsx43(
5967
- Icon26,
5968
- {
5969
- icon: prop.icon,
5970
- size: "sm",
5971
- className: "shrink-0 text-[var(--color-dropdown-item-icon)]"
5972
- }
5973
- ),
5974
- /* @__PURE__ */ jsx43("span", { className: "flex-1 text-sm font-regular leading-sm text-[var(--color-dropdown-item-text)] text-left truncate", children: prop.label })
5975
- ]
5976
- },
5977
- prop.id
5978
- )),
5979
- filteredProperties.length === 0 && /* @__PURE__ */ jsx43("span", { className: "p-base text-sm text-[var(--color-muted-foreground)]", children: "No results" })
5980
- ] })
5981
- ] })
5982
- )
5567
+ type: "number",
5568
+ value: value ?? "",
5569
+ onChange: (e) => onChange(e.target.value ? Number(e.target.value) : null),
5570
+ onKeyDown: handleKeyDown,
5571
+ placeholder: "Enter number...",
5572
+ autoFocus: true,
5573
+ className: inputClasses
5983
5574
  }
5984
- ) })
5575
+ ),
5576
+ /* @__PURE__ */ jsx43("button", { type: "button", onClick: onSubmit, className: applyBtnClasses, children: "Apply" })
5985
5577
  ] });
5986
5578
  };
5987
- PropertySelector.displayName = "PropertySelector";
5579
+ NumberValueInput.displayName = "NumberValueInput";
5580
+ var NumberRangeValueInput = ({
5581
+ value,
5582
+ onChange,
5583
+ onSubmit,
5584
+ className
5585
+ }) => {
5586
+ const rangeVal = value ?? [0, 0];
5587
+ return /* @__PURE__ */ jsxs38("div", { className: cn("flex flex-col gap-base p-base", className), children: [
5588
+ /* @__PURE__ */ jsxs38("div", { className: "flex items-center gap-base", children: [
5589
+ /* @__PURE__ */ jsx43(
5590
+ "input",
5591
+ {
5592
+ type: "number",
5593
+ value: rangeVal[0] ?? "",
5594
+ onChange: (e) => onChange([Number(e.target.value), rangeVal[1]]),
5595
+ placeholder: "Min",
5596
+ autoFocus: true,
5597
+ className: halfInputClasses
5598
+ }
5599
+ ),
5600
+ /* @__PURE__ */ jsx43("span", { className: "text-sm text-[var(--color-muted-foreground)]", children: "and" }),
5601
+ /* @__PURE__ */ jsx43(
5602
+ "input",
5603
+ {
5604
+ type: "number",
5605
+ value: rangeVal[1] ?? "",
5606
+ onChange: (e) => onChange([rangeVal[0], Number(e.target.value)]),
5607
+ placeholder: "Max",
5608
+ className: halfInputClasses
5609
+ }
5610
+ )
5611
+ ] }),
5612
+ /* @__PURE__ */ jsx43("button", { type: "button", onClick: onSubmit, className: applyBtnClasses, children: "Apply" })
5613
+ ] });
5614
+ };
5615
+ NumberRangeValueInput.displayName = "NumberRangeValueInput";
5988
5616
 
5989
- // src/components/ui/filter/kebab-menu.tsx
5990
- import * as PopoverPrimitive6 from "@radix-ui/react-popover";
5991
- import { Icon as Icon27, faArrowRightOutline, faTrashOutline } from "@l3mpire/icons";
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";
5992
5630
  import { jsx as jsx44, jsxs as jsxs39 } from "react/jsx-runtime";
5993
- var KebabMenu = ({
5994
- onConvertToAdvanced,
5995
- onDelete,
5996
- open,
5997
- onOpenChange,
5998
- children
5999
- }) => /* @__PURE__ */ jsxs39(PopoverPrimitive6.Root, { open, onOpenChange, children: [
6000
- /* @__PURE__ */ jsx44(PopoverPrimitive6.Trigger, { asChild: true, children }),
6001
- /* @__PURE__ */ jsx44(PopoverPrimitive6.Portal, { children: /* @__PURE__ */ jsxs39(
6002
- PopoverPrimitive6.Content,
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"
5661
+ ];
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;
5670
+ }
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;
5702
+ }
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;
5711
+ }
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",
6003
5790
  {
6004
- sideOffset: 4,
6005
- align: "end",
6006
- className: cn(
6007
- "z-50 flex flex-col p-xs overflow-clip",
6008
- "bg-[var(--color-dropdown-bg)] border border-[var(--color-dropdown-border)] rounded-md shadow-lg",
6009
- "data-[state=open]:animate-in data-[state=open]:fade-in-0 data-[state=open]:zoom-in-95",
6010
- "data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=closed]:zoom-out-95",
6011
- "data-[side=bottom]:slide-in-from-top-2",
6012
- "min-w-[210px]"
6013
- ),
6014
- children: [
6015
- onConvertToAdvanced && /* @__PURE__ */ jsxs39(
6016
- "button",
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,
6017
5801
  {
6018
- type: "button",
6019
- onClick: () => {
6020
- onConvertToAdvanced();
6021
- onOpenChange?.(false);
6022
- },
6023
- className: "flex items-center gap-base p-base rounded-base cursor-pointer transition-colors hover:bg-[var(--color-dropdown-item-hover)]",
6024
- children: [
6025
- /* @__PURE__ */ jsx44(
6026
- Icon27,
6027
- {
6028
- icon: faArrowRightOutline,
6029
- size: "sm",
6030
- className: "shrink-0 text-[var(--color-dropdown-item-icon)]"
6031
- }
6032
- ),
6033
- /* @__PURE__ */ jsx44("span", { className: "text-sm font-regular leading-sm text-[var(--color-dropdown-item-text)]", children: "Convert to advanced" })
6034
- ]
5802
+ icon: faArrowRightOutline,
5803
+ size: "sm",
5804
+ className: "shrink-0 text-datepicker-header-weekday"
6035
5805
  }
6036
5806
  ),
6037
- onConvertToAdvanced && onDelete && /* @__PURE__ */ jsx44("div", { className: "h-px mx-base my-xs bg-[var(--color-border)]" }),
6038
- onDelete && /* @__PURE__ */ jsxs39(
6039
- "button",
6040
- {
6041
- type: "button",
6042
- onClick: () => {
6043
- onDelete();
6044
- onOpenChange?.(false);
6045
- },
6046
- className: "flex items-center gap-base p-base rounded-base cursor-pointer transition-colors hover:bg-[var(--color-dropdown-item-hover)]",
6047
- children: [
6048
- /* @__PURE__ */ jsx44(
6049
- Icon27,
6050
- {
6051
- icon: faTrashOutline,
6052
- size: "sm",
6053
- className: "shrink-0 text-[var(--color-destructive)]"
6054
- }
6055
- ),
6056
- /* @__PURE__ */ jsx44("span", { className: "text-sm font-regular leading-sm text-[var(--color-destructive)]", children: "Delete filter" })
6057
- ]
6058
- }
6059
- )
6060
- ]
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
+ ] })
6061
5812
  }
6062
- ) })
6063
- ] });
6064
- KebabMenu.displayName = "KebabMenu";
6065
-
6066
- // src/components/ui/filter/filter-editor.tsx
6067
- import * as React42 from "react";
6068
- import * as PopoverPrimitive7 from "@radix-ui/react-popover";
6069
- import { Icon as Icon28 } from "@l3mpire/icons";
6070
- import { jsx as jsx45, jsxs as jsxs40 } from "react/jsx-runtime";
6071
- var FilterEditor = ({
6072
- propertyDef,
6073
- condition,
6074
- mode,
6075
- onUpdate,
6076
- onClose,
6077
- open,
6078
- onOpenChange,
6079
- children
6080
- }) => {
6081
- const [view, setView] = React42.useState(
6082
- mode === "add" ? "value" : "operator"
6083
- );
6084
- const [localOperator, setLocalOperator] = React42.useState(
6085
- condition.operator
6086
5813
  );
6087
- const [localValue, setLocalValue] = React42.useState(
6088
- condition.value
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(
5826
+ "button",
5827
+ {
5828
+ type: "button",
5829
+ onClick: () => !isOutside && onSelect(date),
5830
+ onMouseEnter: () => mode === "range" && setHoveredDate(date),
5831
+ onMouseLeave: () => mode === "range" && setHoveredDate(void 0),
5832
+ disabled: isOutside,
5833
+ className: cn(
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"
5846
+ ),
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
+ }
6089
5852
  );
6090
- React42.useEffect(() => {
6091
- if (open) {
6092
- setView(mode === "add" ? "value" : "operator");
6093
- setLocalOperator(condition.operator);
6094
- setLocalValue(condition.value);
5853
+ };
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
+ });
6095
5875
  }
6096
- }, [open, mode, condition.operator, condition.value]);
6097
- const handleOperatorSelect = (op) => {
6098
- setLocalOperator(op);
6099
- if (isNoValueOperator(op)) {
6100
- onUpdate({ ...condition, operator: op, value: null });
6101
- onOpenChange?.(false);
6102
- onClose();
6103
- } else {
6104
- if (op !== localOperator) {
6105
- setLocalValue(null);
6106
- }
6107
- setView("value");
5876
+ for (let d = 1; d <= daysInMonth; d++) {
5877
+ days.push({ date: new Date(year, month, d), isOutside: false });
6108
5878
  }
6109
- };
6110
- const handleSubmit = () => {
6111
- onUpdate({ ...condition, operator: localOperator, value: localValue });
6112
- onOpenChange?.(false);
6113
- onClose();
6114
- };
6115
- return /* @__PURE__ */ jsxs40(PopoverPrimitive7.Root, { open, onOpenChange, children: [
6116
- /* @__PURE__ */ jsx45(PopoverPrimitive7.Trigger, { asChild: true, children }),
6117
- /* @__PURE__ */ jsx45(PopoverPrimitive7.Portal, { children: /* @__PURE__ */ jsxs40(
6118
- PopoverPrimitive7.Content,
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",
5898
+ {
5899
+ ref,
5900
+ className: cn("flex flex-col", className),
5901
+ ...props,
5902
+ children: [
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
+ ] })
5952
+ ] })
5953
+ ]
5954
+ }
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);
5967
+ } else {
5968
+ ctx.onSelect(val.from);
5969
+ if (val.to) {
5970
+ setTimeout(() => ctx.onSelect(val.to), 0);
5971
+ }
5972
+ }
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",
6119
5985
  {
6120
- sideOffset: 4,
6121
- align: "start",
5986
+ ref,
6122
5987
  className: cn(
6123
- "z-50 flex flex-col overflow-clip",
6124
- "bg-[var(--color-dropdown-bg)] border border-[var(--color-dropdown-border)] rounded-md shadow-lg",
6125
- "data-[state=open]:animate-in data-[state=open]:fade-in-0 data-[state=open]:zoom-in-95",
6126
- "data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=closed]:zoom-out-95",
6127
- "data-[side=bottom]:slide-in-from-top-2",
6128
- "min-w-[240px]"
5988
+ "flex flex-col border-l border-datepicker-border self-stretch shrink-0",
5989
+ className
6129
5990
  ),
5991
+ ...props,
6130
5992
  children: [
6131
- /* @__PURE__ */ jsxs40("div", { className: "flex items-center gap-base px-base pt-base pb-xs border-b border-[var(--color-border)]", children: [
6132
- /* @__PURE__ */ jsx45(
6133
- Icon28,
6134
- {
6135
- icon: propertyDef.icon,
6136
- size: "sm",
6137
- className: "shrink-0 text-[var(--color-dropdown-item-icon)]"
6138
- }
6139
- ),
6140
- /* @__PURE__ */ jsx45("span", { className: "text-sm font-semibold leading-sm text-[var(--color-foreground)]", children: propertyDef.label }),
6141
- localOperator && view === "value" && /* @__PURE__ */ jsxs40(
6142
- "button",
6143
- {
6144
- type: "button",
6145
- onClick: () => setView("operator"),
6146
- className: "ml-auto text-xs font-regular text-[var(--color-muted-foreground)] hover:text-[var(--color-foreground)] cursor-pointer transition-colors",
6147
- children: [
6148
- localOperator,
6149
- " \u25BE"
6150
- ]
6151
- }
6152
- )
6153
- ] }),
6154
- view === "operator" ? /* @__PURE__ */ jsx45("div", { className: "p-xs", children: /* @__PURE__ */ jsx45(
6155
- OperatorList,
6156
- {
6157
- dataType: propertyDef.type,
6158
- activeOperator: localOperator,
6159
- onSelect: handleOperatorSelect
6160
- }
6161
- ) }) : localOperator && /* @__PURE__ */ jsx45(
6162
- ValueInput,
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",
6163
5996
  {
6164
- dataType: propertyDef.type,
6165
- operator: localOperator,
6166
- value: localValue,
6167
- onChange: setLocalValue,
6168
- onSubmit: handleSubmit,
6169
- options: propertyDef.options
6170
- }
6171
- )
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
+ )) })
6172
6007
  ]
6173
6008
  }
6174
- ) })
6175
- ] });
6176
- };
6177
- FilterEditor.displayName = "FilterEditor";
6178
-
6179
- // src/components/ui/filter/interactive-filter-chip.tsx
6180
- import * as React43 from "react";
6181
- import * as PopoverPrimitive8 from "@radix-ui/react-popover";
6182
- import { jsx as jsx46, jsxs as jsxs41 } from "react/jsx-runtime";
6183
- function formatFilterValue(value) {
6184
- if (value == null) return void 0;
6185
- if (typeof value === "boolean") return value ? "Yes" : "No";
6186
- if (value instanceof Date) {
6187
- return value.toLocaleDateString("en-US", {
6188
- month: "short",
6189
- day: "numeric",
6190
- year: "numeric"
6191
- });
6192
- }
6193
- if (Array.isArray(value)) {
6194
- if (value.length === 0) return void 0;
6195
- if (value.length === 2 && typeof value[0] === "number") {
6196
- return `${value[0]} \u2013 ${value[1]}`;
6197
- }
6198
- return value[0];
6009
+ );
6199
6010
  }
6200
- return String(value);
6201
- }
6202
- function getBadgeCount(value) {
6203
- if (Array.isArray(value) && value.length > 1 && typeof value[0] === "string") {
6204
- return value.length;
6205
- }
6206
- return void 0;
6207
- }
6208
- var SegmentPopover = ({
6209
- open,
6210
- onOpenChange,
6211
- trigger,
6212
- children,
6213
- align = "start",
6214
- minWidth = "240px"
6215
- }) => /* @__PURE__ */ jsxs41(PopoverPrimitive8.Root, { open, onOpenChange, children: [
6216
- /* @__PURE__ */ jsx46(PopoverPrimitive8.Trigger, { asChild: true, children: trigger }),
6217
- /* @__PURE__ */ jsx46(PopoverPrimitive8.Portal, { children: /* @__PURE__ */ jsx46(
6218
- PopoverPrimitive8.Content,
6011
+ );
6012
+ DatePickerSuggestions.displayName = "DatePickerSuggestions";
6013
+ var DatePickerFooter = React41.forwardRef(
6014
+ ({ className, children, ...props }, ref) => /* @__PURE__ */ jsx44(
6015
+ "div",
6219
6016
  {
6220
- sideOffset: 4,
6221
- align,
6017
+ ref,
6222
6018
  className: cn(
6223
- "z-50 flex flex-col overflow-clip",
6224
- "bg-[var(--color-dropdown-bg)] border border-[var(--color-dropdown-border)] rounded-md shadow-lg",
6225
- "data-[state=open]:animate-in data-[state=open]:fade-in-0 data-[state=open]:zoom-in-95",
6226
- "data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=closed]:zoom-out-95",
6227
- "data-[side=bottom]:slide-in-from-top-2"
6019
+ "flex items-center justify-between p-lg",
6020
+ "border-t border-datepicker-footer-border",
6021
+ "bg-datepicker-bg",
6022
+ className
6228
6023
  ),
6229
- style: { minWidth },
6024
+ ...props,
6230
6025
  children
6231
6026
  }
6232
- ) })
6233
- ] });
6234
- var InteractiveFilterChip = ({
6235
- propertyDef,
6236
- condition,
6237
- properties,
6238
- mode = "edit",
6239
- autoOpen = false,
6240
- onUpdate,
6241
- onPropertyChange,
6242
- onDelete,
6243
- onConvertToAdvanced,
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
6075
+ );
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
6086
+ );
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 })
6115
+ }
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,
6244
6131
  className
6245
6132
  }) => {
6246
- const [operatorOpen, setOperatorOpen] = React43.useState(false);
6247
- const [valueOpen, setValueOpen] = React43.useState(false);
6248
- const [propertyOpen, setPropertyOpen] = React43.useState(false);
6249
- const [kebabOpen, setKebabOpen] = React43.useState(false);
6250
- React43.useEffect(() => {
6251
- if (autoOpen && condition.operator && !isNoValueOperator(condition.operator)) {
6252
- const t = setTimeout(() => setValueOpen(true), 50);
6253
- return () => clearTimeout(t);
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;
6254
6141
  }
6255
- }, []);
6256
- const handleOperatorSelect = (op) => {
6257
- if (isNoValueOperator(op)) {
6258
- onUpdate({ ...condition, operator: op, value: null });
6259
- setOperatorOpen(false);
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?.();
6260
6148
  } else {
6261
- const resetValue = op !== condition.operator ? null : condition.value;
6262
- onUpdate({ ...condition, operator: op, value: resetValue });
6263
- setOperatorOpen(false);
6264
- if (resetValue == null) {
6265
- setTimeout(() => setValueOpen(true), 100);
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]);
6266
6154
  }
6267
6155
  }
6268
6156
  };
6269
- const handleValueChange = (val) => {
6270
- onUpdate({ ...condition, value: val });
6271
- };
6272
- const handleValueSubmit = () => {
6273
- setValueOpen(false);
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
+ ]
6175
+ }
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",
6188
+ {
6189
+ type: "button",
6190
+ onClick: () => {
6191
+ onChange(preset);
6192
+ onSubmit?.();
6193
+ },
6194
+ className: cn(
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)]"
6197
+ ),
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?.();
6274
6270
  };
6275
- const hasOperator = !!condition.operator;
6276
- const displayValue = formatFilterValue(condition.value);
6277
- const hasValue = hasOperator && displayValue != null;
6278
- const badgeCount = getBadgeCount(condition.value);
6279
6271
  return /* @__PURE__ */ jsxs41(
6280
6272
  "div",
6281
6273
  {
6282
6274
  className: cn(
6283
- "inline-flex items-center overflow-clip",
6284
- "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",
6285
6276
  className
6286
6277
  ),
6287
6278
  children: [
6288
- properties ? /* @__PURE__ */ jsx46(
6289
- PropertySelector,
6290
- {
6291
- properties,
6292
- onSelect: (prop) => {
6293
- onPropertyChange?.(prop);
6294
- setPropertyOpen(false);
6295
- },
6296
- open: propertyOpen,
6297
- onOpenChange: setPropertyOpen,
6298
- children: /* @__PURE__ */ jsx46("div", { children: /* @__PURE__ */ jsx46(
6299
- FilterChipSegment,
6300
- {
6301
- segmentType: "property",
6302
- hasBorder: true,
6303
- icon: propertyDef.icon,
6304
- label: propertyDef.label,
6305
- onClick: () => setPropertyOpen(true)
6306
- }
6307
- ) })
6308
- }
6309
- ) : /* @__PURE__ */ jsx46(
6310
- FilterChipSegment,
6279
+ dynamicOptions?.map((opt) => /* @__PURE__ */ jsx46(
6280
+ DynamicOptionRow,
6311
6281
  {
6312
- segmentType: "property",
6313
- hasBorder: true,
6314
- icon: propertyDef.icon,
6315
- label: propertyDef.label
6316
- }
6317
- ),
6318
- /* @__PURE__ */ jsx46(
6319
- SegmentPopover,
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",
6320
6292
  {
6321
- open: operatorOpen,
6322
- onOpenChange: setOperatorOpen,
6323
- minWidth: "180px",
6324
- trigger: /* @__PURE__ */ jsx46("div", { children: /* @__PURE__ */ jsx46(
6325
- FilterChipSegment,
6326
- {
6327
- segmentType: hasOperator ? "operator" : "placeholder",
6328
- hasBorder: true,
6329
- label: hasOperator ? condition.operator : "Select condition",
6330
- onClick: () => setOperatorOpen(true)
6331
- }
6332
- ) }),
6333
- children: /* @__PURE__ */ jsx46("div", { className: "p-xs", children: /* @__PURE__ */ jsx46(
6334
- OperatorList,
6335
- {
6336
- dataType: propertyDef.type,
6337
- activeOperator: condition.operator,
6338
- onSelect: handleOperatorSelect
6339
- }
6340
- ) })
6341
- }
6342
- ),
6343
- hasOperator && condition.operator && !isNoValueOperator(condition.operator) && /* @__PURE__ */ jsx46(
6344
- SegmentPopover,
6345
- {
6346
- open: valueOpen,
6347
- onOpenChange: setValueOpen,
6348
- minWidth: "240px",
6349
- trigger: /* @__PURE__ */ jsx46("div", { children: /* @__PURE__ */ jsx46(
6350
- FilterChipSegment,
6351
- {
6352
- segmentType: hasValue ? "value" : "placeholder",
6353
- hasBorder: true,
6354
- label: hasValue ? displayValue : "Enter value",
6355
- badgeCount,
6356
- onClick: () => setValueOpen(true)
6357
- }
6358
- ) }),
6359
- children: /* @__PURE__ */ jsx46(
6360
- ValueInput,
6361
- {
6362
- dataType: propertyDef.type,
6363
- operator: condition.operator,
6364
- value: condition.value,
6365
- onChange: handleValueChange,
6366
- onSubmit: handleValueSubmit,
6367
- options: propertyDef.options
6368
- }
6369
- )
6370
- }
6371
- ),
6372
- hasOperator && condition.operator && isNoValueOperator(condition.operator) && /* @__PURE__ */ jsx46(
6373
- FilterChipSegment,
6374
- {
6375
- segmentType: "value",
6376
- hasBorder: true,
6377
- label: condition.operator
6378
- }
6379
- ),
6380
- hasOperator && /* @__PURE__ */ jsx46(
6381
- KebabMenu,
6382
- {
6383
- open: kebabOpen,
6384
- onOpenChange: setKebabOpen,
6385
- onConvertToAdvanced,
6386
- onDelete,
6387
- children: /* @__PURE__ */ jsx46("div", { children: /* @__PURE__ */ jsx46(
6388
- FilterChipSegment,
6389
- {
6390
- segmentType: "button",
6391
- onKebabClick: (e) => {
6392
- e.stopPropagation();
6393
- setKebabOpen(true);
6394
- }
6395
- }
6396
- ) })
6397
- }
6398
- )
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
+ ))
6399
6304
  ]
6400
6305
  }
6401
6306
  );
6402
6307
  };
6403
- InteractiveFilterChip.displayName = "InteractiveFilterChip";
6404
-
6405
- // src/components/ui/filter/filter-system.tsx
6406
- import * as React49 from "react";
6407
- import { Icon as Icon33, faXmarkOutline as faXmarkOutline4, faPlusOutline as faPlusOutline4 } from "@l3mpire/icons";
6408
-
6409
- // src/components/ui/filter/advanced-chip.tsx
6410
- import * as React44 from "react";
6411
- import { Icon as Icon29, faXmarkOutline as faXmarkOutline2 } from "@l3mpire/icons";
6412
- import { jsx as jsx47, jsxs as jsxs42 } from "react/jsx-runtime";
6413
- var btnBase = [
6414
- "flex items-center justify-center",
6415
- "min-h-[32px] max-h-[32px]",
6416
- "bg-gradient-to-t from-[var(--color-btn-outlined-neutral-bg-default)] from-[10%] to-[var(--color-btn-outlined-neutral-bg-gradient-to-default)]",
6417
- "border border-[var(--color-btn-outlined-neutral-border-default)] shadow-sm",
6418
- "cursor-pointer transition-colors",
6419
- "hover:from-[var(--color-btn-outlined-neutral-bg-hover)] hover:to-[var(--color-btn-outlined-neutral-bg-gradient-to-hover)]"
6420
- ];
6421
- var AdvancedChip = React44.forwardRef(
6422
- ({ className, count, onClear, onClick, ...props }, ref) => /* @__PURE__ */ jsxs42("div", { className: cn("inline-flex items-center", className), children: [
6423
- /* @__PURE__ */ jsxs42(
6424
- "button",
6425
- {
6426
- ref,
6427
- type: "button",
6428
- onClick,
6429
- className: cn(
6430
- btnBase,
6431
- "gap-sm px-base py-sm min-w-[80px]",
6432
- "rounded-l-md -mr-px"
6433
- ),
6434
- ...props,
6435
- children: [
6436
- /* @__PURE__ */ jsx47("span", { className: "text-sm font-semibold leading-sm whitespace-nowrap text-[var(--color-foreground)]", children: "Advanced filters" }),
6437
- /* @__PURE__ */ jsx47("span", { className: "flex items-center p-2xs rounded-xs bg-filter-chip-badge-bg", children: /* @__PURE__ */ jsx47("span", { className: "text-[10px] font-semibold leading-2xs text-filter-chip-badge-text", children: count }) })
6438
- ]
6439
- }
6440
- ),
6441
- onClear && /* @__PURE__ */ jsx47(
6442
- "button",
6443
- {
6444
- type: "button",
6445
- onClick: (e) => {
6446
- e.stopPropagation();
6447
- onClear();
6448
- },
6449
- className: cn(
6450
- btnBase,
6451
- "p-sm",
6452
- "rounded-r-md -ml-px"
6453
- ),
6454
- "aria-label": "Clear all advanced filters",
6455
- children: /* @__PURE__ */ jsx47(Icon29, { icon: faXmarkOutline2, size: "sm", className: "text-[var(--color-foreground)]" })
6456
- }
6457
- )
6458
- ] })
6459
- );
6460
- AdvancedChip.displayName = "AdvancedChip";
6461
-
6462
- // src/components/ui/filter/advanced-popover.tsx
6463
- import * as React46 from "react";
6464
- import * as PopoverPrimitive10 from "@radix-ui/react-popover";
6465
- import { Icon as Icon31, faPlusOutline as faPlusOutline2 } from "@l3mpire/icons";
6466
-
6467
- // src/components/ui/filter/advanced-row.tsx
6468
- import * as React45 from "react";
6469
- import * as PopoverPrimitive9 from "@radix-ui/react-popover";
6470
- import { Icon as Icon30, faXmarkOutline as faXmarkOutline3, faRefreshOutline, faChevronDownOutline as faChevronDownOutline2 } from "@l3mpire/icons";
6471
- import { jsx as jsx48, jsxs as jsxs43 } from "react/jsx-runtime";
6472
- var selectBtnStyle = [
6473
- "flex items-center gap-base",
6474
- "px-base py-sm",
6475
- "bg-gradient-to-t from-[var(--color-btn-outlined-neutral-bg-default)] to-[var(--color-btn-outlined-neutral-bg-gradient-to-default)]",
6476
- "border border-[var(--color-btn-outlined-neutral-border-default)] rounded-md shadow-sm",
6477
- "cursor-pointer transition-colors",
6478
- "hover:from-[var(--color-btn-outlined-neutral-bg-hover)] hover:to-[var(--color-btn-outlined-neutral-bg-gradient-to-hover)]"
6479
- ];
6480
- var AdvancedRow = ({
6481
- connector,
6482
- onConnectorToggle,
6483
- propertyDef,
6484
- condition,
6485
- properties,
6486
- onUpdate,
6487
- onPropertyChange,
6488
- onDelete
6308
+ SingleSelectValueInput.displayName = "SingleSelectValueInput";
6309
+ var MultiSelectValueInput = ({
6310
+ value,
6311
+ onChange,
6312
+ onSubmit,
6313
+ options,
6314
+ dynamicOptions,
6315
+ className
6489
6316
  }) => {
6490
- const [operatorOpen, setOperatorOpen] = React45.useState(false);
6491
- const [propertyOpen, setPropertyOpen] = React45.useState(false);
6492
- const handleOperatorSelect = (op) => {
6493
- if (isNoValueOperator(op)) {
6494
- onUpdate({ ...condition, operator: op, value: null });
6495
- } else {
6496
- const resetValue = op !== condition.operator ? null : condition.value;
6497
- onUpdate({ ...condition, operator: op, value: resetValue });
6498
- }
6499
- setOperatorOpen(false);
6500
- };
6501
- const handleValueChange = (val) => {
6502
- onUpdate({ ...condition, value: val });
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);
6503
6321
  };
6504
- const displayValue = condition.value == null ? "" : typeof condition.value === "string" ? condition.value : String(condition.value);
6505
- return /* @__PURE__ */ jsxs43("div", { className: "flex items-center gap-base w-full min-w-0", children: [
6506
- connector === "Where" ? /* @__PURE__ */ jsx48("div", { className: "shrink-0 w-[64px] flex items-center justify-end", children: /* @__PURE__ */ jsx48("span", { className: "text-xs font-semibold leading-xs text-[var(--color-muted-foreground)]", children: "Where" }) }) : /* @__PURE__ */ jsxs43(
6507
- "button",
6508
- {
6509
- type: "button",
6510
- onClick: onConnectorToggle,
6511
- className: cn(
6512
- "shrink-0 flex items-center justify-center gap-xs",
6513
- "min-w-[64px] min-h-[24px] max-h-[24px] p-xs",
6514
- "bg-gradient-to-t from-[var(--color-btn-outlined-neutral-bg-default)] from-[10%] to-[var(--color-btn-outlined-neutral-bg-gradient-to-default)]",
6515
- "border border-[var(--color-btn-outlined-neutral-border-default)] rounded-base shadow-sm",
6516
- "cursor-pointer transition-colors text-xs font-semibold leading-xs text-[var(--color-foreground)]",
6517
- "hover:from-[var(--color-btn-outlined-neutral-bg-hover)] hover:to-[var(--color-btn-outlined-neutral-bg-gradient-to-hover)]"
6518
- ),
6519
- children: [
6520
- connector,
6521
- /* @__PURE__ */ jsx48(Icon30, { icon: faRefreshOutline, size: "xs", className: "text-[var(--color-foreground)]" })
6522
- ]
6523
- }
6524
- ),
6525
- /* @__PURE__ */ jsxs43(PopoverPrimitive9.Root, { open: propertyOpen, onOpenChange: setPropertyOpen, children: [
6526
- /* @__PURE__ */ jsx48(PopoverPrimitive9.Trigger, { asChild: true, children: /* @__PURE__ */ jsxs43("button", { type: "button", className: cn(selectBtnStyle, "min-w-0"), children: [
6527
- /* @__PURE__ */ jsx48(Icon30, { icon: propertyDef.icon, size: "sm", className: "shrink-0 text-[var(--color-muted-foreground)]" }),
6528
- /* @__PURE__ */ jsxs43("span", { className: "text-sm font-regular leading-sm text-[var(--color-foreground)] whitespace-nowrap truncate", children: [
6529
- propertyDef.groupLabel,
6530
- " > ",
6531
- propertyDef.label
6532
- ] }),
6533
- /* @__PURE__ */ jsx48(Icon30, { icon: faChevronDownOutline2, size: "xs", className: "shrink-0 text-[var(--color-foreground)]" })
6534
- ] }) }),
6535
- /* @__PURE__ */ jsx48(PopoverPrimitive9.Portal, { children: /* @__PURE__ */ jsx48(
6536
- PopoverPrimitive9.Content,
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,
6537
6326
  {
6538
- sideOffset: 4,
6539
- align: "start",
6540
- className: cn(
6541
- "z-50 flex flex-col p-xs overflow-clip max-h-[300px] overflow-y-auto",
6542
- "bg-[var(--color-dropdown-bg)] border border-[var(--color-dropdown-border)] rounded-md shadow-lg",
6543
- "data-[state=open]:animate-in data-[state=open]:fade-in-0 data-[state=open]:zoom-in-95",
6544
- "data-[state=closed]:animate-out data-[state=closed]:fade-out-0",
6545
- "min-w-[200px]"
6546
- ),
6547
- children: properties.map((p) => /* @__PURE__ */ jsxs43(
6548
- "button",
6549
- {
6550
- type: "button",
6551
- onClick: () => {
6552
- onPropertyChange(p);
6553
- setPropertyOpen(false);
6554
- },
6555
- className: cn(
6556
- "flex items-center gap-base p-base rounded-base cursor-pointer transition-colors text-left",
6557
- "hover:bg-[var(--color-dropdown-item-hover)]",
6558
- p.id === condition.propertyId && "bg-[var(--color-dropdown-item-hover)]"
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
+ }
6559
6365
  ),
6560
- children: [
6561
- /* @__PURE__ */ jsx48(Icon30, { icon: p.icon, size: "sm", className: "shrink-0 text-[var(--color-dropdown-item-icon)]" }),
6562
- /* @__PURE__ */ jsx48("span", { className: "text-sm font-regular leading-sm text-[var(--color-dropdown-item-text)] truncate", children: p.label })
6563
- ]
6564
- },
6565
- p.id
6566
- ))
6567
- }
6568
- ) })
6569
- ] }),
6570
- /* @__PURE__ */ jsxs43(PopoverPrimitive9.Root, { open: operatorOpen, onOpenChange: setOperatorOpen, children: [
6571
- /* @__PURE__ */ jsx48(PopoverPrimitive9.Trigger, { asChild: true, children: /* @__PURE__ */ jsxs43("button", { type: "button", className: cn(selectBtnStyle, "min-w-0"), children: [
6572
- /* @__PURE__ */ jsx48("span", { className: "text-sm font-regular leading-sm text-[var(--color-foreground)] whitespace-nowrap truncate text-left", children: condition.operator ?? "Select" }),
6573
- /* @__PURE__ */ jsx48(Icon30, { icon: faChevronDownOutline2, size: "xs", className: "shrink-0 text-[var(--color-foreground)]" })
6574
- ] }) }),
6575
- /* @__PURE__ */ jsx48(PopoverPrimitive9.Portal, { children: /* @__PURE__ */ jsx48(
6576
- PopoverPrimitive9.Content,
6577
- {
6578
- sideOffset: 4,
6579
- align: "start",
6580
- className: cn(
6581
- "z-50 flex flex-col p-xs overflow-clip",
6582
- "bg-[var(--color-dropdown-bg)] border border-[var(--color-dropdown-border)] rounded-md shadow-lg",
6583
- "data-[state=open]:animate-in data-[state=open]:fade-in-0 data-[state=open]:zoom-in-95",
6584
- "data-[state=closed]:animate-out data-[state=closed]:fade-out-0",
6585
- "min-w-[160px]"
6586
- ),
6587
- children: /* @__PURE__ */ jsx48(
6588
- OperatorList,
6589
- {
6590
- dataType: propertyDef.type,
6591
- activeOperator: condition.operator,
6592
- onSelect: handleOperatorSelect
6593
- }
6594
- )
6595
- }
6596
- ) })
6366
+ /* @__PURE__ */ jsx46("span", { className: "text-sm font-regular leading-sm text-[var(--color-foreground)]", children: opt })
6367
+ ]
6368
+ },
6369
+ opt
6370
+ );
6371
+ })
6597
6372
  ] }),
6598
- condition.operator && !isNoValueOperator(condition.operator) && /* @__PURE__ */ jsx48(
6373
+ /* @__PURE__ */ jsx46("button", { type: "button", onClick: onSubmit, className: applyBtnClasses, children: "Apply" })
6374
+ ] });
6375
+ };
6376
+ MultiSelectValueInput.displayName = "MultiSelectValueInput";
6377
+
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(
6599
6391
  "input",
6600
6392
  {
6601
6393
  type: "text",
6602
- value: displayValue,
6603
- onChange: (e) => handleValueChange(e.target.value),
6604
- placeholder: "Placeholder",
6605
- className: cn(
6606
- "flex-1 min-w-[80px] px-base py-sm rounded-md",
6607
- "border border-[var(--color-input)]",
6608
- "bg-[var(--color-background)] text-sm font-regular leading-sm text-[var(--color-foreground)]",
6609
- "placeholder:text-[var(--color-muted-foreground)]",
6610
- "focus:outline-none focus:ring-2 focus:ring-[var(--color-ring)] focus:ring-offset-0"
6611
- )
6394
+ value: value ?? "",
6395
+ onChange: (e) => onChange(e.target.value),
6396
+ onKeyDown: handleKeyDown,
6397
+ placeholder: "Search...",
6398
+ autoFocus: true,
6399
+ className: inputClasses
6612
6400
  }
6613
6401
  ),
6614
- /* @__PURE__ */ jsx48(
6615
- "button",
6616
- {
6617
- type: "button",
6618
- onClick: onDelete,
6619
- className: "ml-auto shrink-0 flex items-center justify-center p-sm rounded-md cursor-pointer transition-colors hover:bg-[var(--color-accent)]",
6620
- "aria-label": "Remove filter",
6621
- children: /* @__PURE__ */ jsx48(Icon30, { icon: faXmarkOutline3, size: "sm", className: "text-[var(--color-foreground)]" })
6622
- }
6623
- )
6402
+ /* @__PURE__ */ jsx47("button", { type: "button", onClick: onSubmit, className: applyBtnClasses, children: "Apply" })
6624
6403
  ] });
6625
6404
  };
6626
- AdvancedRow.displayName = "AdvancedRow";
6405
+ RelationValueInput.displayName = "RelationValueInput";
6627
6406
 
6628
- // src/components/ui/filter/advanced-popover.tsx
6629
- import { jsx as jsx49, jsxs as jsxs44 } from "react/jsx-runtime";
6630
- var outlinedBtn = [
6631
- "flex items-center gap-sm px-base py-sm",
6632
- "min-h-[32px] max-h-[32px] min-w-[80px]",
6633
- "bg-gradient-to-t from-[var(--color-btn-outlined-neutral-bg-default)] from-[10%] to-[var(--color-btn-outlined-neutral-bg-gradient-to-default)]",
6634
- "border border-[var(--color-btn-outlined-neutral-border-default)] rounded-md shadow-sm",
6635
- "cursor-pointer transition-colors text-sm font-semibold leading-sm text-[var(--color-foreground)]",
6636
- "hover:from-[var(--color-btn-outlined-neutral-bg-hover)] hover:to-[var(--color-btn-outlined-neutral-bg-gradient-to-hover)]"
6637
- ];
6638
- var AdvancedPopover = ({
6639
- filters,
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
6418
+ }) => {
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,
6431
+ {
6432
+ value,
6433
+ onChange,
6434
+ onSubmit,
6435
+ options,
6436
+ dynamicOptions,
6437
+ className
6438
+ }
6439
+ );
6440
+ case "MultiSelect":
6441
+ return /* @__PURE__ */ jsx48(
6442
+ MultiSelectValueInput,
6443
+ {
6444
+ value,
6445
+ onChange,
6446
+ onSubmit,
6447
+ options,
6448
+ dynamicOptions,
6449
+ className
6450
+ }
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
+ }
6470
+ };
6471
+ ValueInput.displayName = "ValueInput";
6472
+
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 = ({
6640
6513
  properties,
6641
- onFiltersChange,
6514
+ onSelect,
6642
6515
  open,
6643
6516
  onOpenChange,
6644
- children
6517
+ children,
6518
+ onAdvancedFilter,
6519
+ advancedFilterCount = 0
6645
6520
  }) => {
6646
- const [addSelectorOpen, setAddSelectorOpen] = React46.useState(false);
6647
- const [logicOps, setLogicOps] = React46.useState({});
6648
- const getPropertyDef = (propertyId) => properties.find((p) => p.id === propertyId);
6649
- const handleUpdateFilter = (updated) => {
6650
- onFiltersChange(filters.map((f) => f.id === updated.id ? updated : f));
6651
- };
6652
- const handleDeleteFilter = (id) => {
6653
- onFiltersChange(filters.filter((f) => f.id !== id));
6521
+ const handleAdvancedClick = (e) => {
6522
+ e.stopPropagation();
6523
+ e.preventDefault();
6524
+ onAdvancedFilter?.();
6654
6525
  };
6655
- const handlePropertyChange = (filterId, newProp) => {
6656
- const newCondition = createFilterWithDefaults(newProp.id, newProp.type);
6657
- onFiltersChange(
6658
- filters.map((f) => f.id === filterId ? { ...newCondition, id: filterId } : 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)
6563
+ )
6659
6564
  );
6660
- };
6661
- const handleAddFilter = (property) => {
6662
- const newFilter = createFilterWithDefaults(property.id, property.type);
6663
- onFiltersChange([...filters, newFilter]);
6664
- setAddSelectorOpen(false);
6665
- };
6666
- const handleClearAll = () => {
6667
- onFiltersChange([]);
6668
- onOpenChange?.(false);
6669
- };
6670
- const toggleLogicOp = (filterId) => {
6671
- setLogicOps((prev) => ({
6672
- ...prev,
6673
- [filterId]: (prev[filterId] ?? "and") === "and" ? "or" : "and"
6674
- }));
6675
- };
6676
- return /* @__PURE__ */ jsxs44(PopoverPrimitive10.Root, { open, onOpenChange, children: [
6677
- /* @__PURE__ */ jsx49(PopoverPrimitive10.Trigger, { asChild: true, children }),
6678
- /* @__PURE__ */ jsx49(PopoverPrimitive10.Portal, { children: /* @__PURE__ */ jsxs44(
6679
- 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,
6680
6579
  {
6681
6580
  sideOffset: 4,
6682
6581
  align: "start",
6683
- collisionPadding: 16,
6582
+ onCloseAutoFocus: (e) => e.preventDefault(),
6684
6583
  className: cn(
6685
- "z-50 flex flex-col",
6686
- "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",
6687
6586
  "data-[state=open]:animate-in data-[state=open]:fade-in-0 data-[state=open]:zoom-in-95",
6688
6587
  "data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=closed]:zoom-out-95",
6689
6588
  "data-[side=bottom]:slide-in-from-top-2",
6690
- "w-[min(520px,calc(100vw-32px))]"
6589
+ "min-w-[230px]"
6691
6590
  ),
6692
6591
  children: [
6693
- /* @__PURE__ */ jsxs44("div", { className: "flex flex-col gap-base p-base", children: [
6694
- filters.map((filter, i) => {
6695
- const propDef = getPropertyDef(filter.propertyId);
6696
- if (!propDef) return null;
6697
- return /* @__PURE__ */ jsx49(
6698
- AdvancedRow,
6699
- {
6700
- connector: i === 0 ? "Where" : (logicOps[filter.id] ?? "and") === "and" ? "And" : "Or",
6701
- onConnectorToggle: i > 0 ? () => toggleLogicOp(filter.id) : void 0,
6702
- propertyDef: propDef,
6703
- condition: filter,
6704
- properties,
6705
- onUpdate: handleUpdateFilter,
6706
- onPropertyChange: (p) => handlePropertyChange(filter.id, p),
6707
- onDelete: () => handleDeleteFilter(filter.id)
6708
- },
6709
- filter.id
6710
- );
6711
- }),
6712
- filters.length === 0 && /* @__PURE__ */ jsx49("p", { className: "py-base text-sm text-[var(--color-muted-foreground)]", children: "No advanced filters yet." })
6713
- ] }),
6714
- /* @__PURE__ */ jsxs44("div", { className: "flex items-center justify-between p-base border-t border-[var(--color-border)]", children: [
6715
- /* @__PURE__ */ jsx49(
6716
- PropertySelector,
6717
- {
6718
- properties,
6719
- onSelect: handleAddFilter,
6720
- open: addSelectorOpen,
6721
- onOpenChange: setAddSelectorOpen,
6722
- children: /* @__PURE__ */ jsxs44("button", { type: "button", className: cn(outlinedBtn), children: [
6723
- /* @__PURE__ */ jsx49(Icon31, { icon: faPlusOutline2, size: "sm", className: "text-[var(--color-foreground)]" }),
6724
- "Add filter"
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(
6646
+ "button",
6647
+ {
6648
+ type: "button",
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)]",
6654
+ children: [
6655
+ /* @__PURE__ */ jsx49(
6656
+ Icon28,
6657
+ {
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,
6669
+ size: "xs",
6670
+ className: "shrink-0 text-[var(--color-dropdown-item-icon)]"
6671
+ }
6672
+ )
6673
+ ]
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" })
6725
6678
  ] })
6726
- }
6727
- ),
6728
- /* @__PURE__ */ jsx49(
6729
- "button",
6730
- {
6731
- type: "button",
6732
- onClick: handleClearAll,
6733
- className: "text-sm font-semibold leading-sm text-[var(--color-foreground)] cursor-pointer transition-colors hover:opacity-70 px-base py-sm",
6734
- children: "Clear all filters"
6735
- }
6736
- )
6737
- ] })
6679
+ )
6680
+ ] })
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
+ )
6738
6762
  ]
6739
6763
  }
6740
6764
  ) })
6741
6765
  ] });
6742
6766
  };
6743
- AdvancedPopover.displayName = "AdvancedPopover";
6767
+ PropertySelector.displayName = "PropertySelector";
6744
6768
 
6745
- // src/components/ui/filter/summary-chip.tsx
6746
- import * as React47 from "react";
6747
- import * as PopoverPrimitive11 from "@radix-ui/react-popover";
6748
- import { Icon as Icon32, faSlidersOutline as faSlidersOutline2, faPlusOutline as faPlusOutline3 } from "@l3mpire/icons";
6749
- import { jsx as jsx50, jsxs as jsxs45 } from "react/jsx-runtime";
6750
- var SummaryChip = ({
6751
- count,
6752
- filters,
6753
- properties,
6754
- onFiltersChange,
6755
- onClearAll,
6756
- children,
6757
- className
6758
- }) => {
6759
- const [open, setOpen] = React47.useState(false);
6760
- const [addSelectorOpen, setAddSelectorOpen] = React47.useState(false);
6761
- const [logicOps, setLogicOps] = React47.useState({});
6762
- const getPropertyDef = (propertyId) => properties.find((p) => p.id === propertyId);
6763
- const handleUpdateFilter = (updated) => {
6764
- onFiltersChange(filters.map((f) => f.id === updated.id ? updated : f));
6765
- };
6766
- const handleDeleteFilter = (id) => {
6767
- const next = filters.filter((f) => f.id !== id);
6768
- onFiltersChange(next);
6769
- if (next.length === 0) setOpen(false);
6770
- };
6771
- const handlePropertyChange = (filterId, newProp) => {
6772
- const newCondition = createFilterWithDefaults(newProp.id, newProp.type);
6773
- onFiltersChange(
6774
- filters.map((f) => f.id === filterId ? { ...newCondition, id: filterId } : f)
6775
- );
6776
- };
6777
- const handleAddFilter = (property) => {
6778
- const newFilter = createFilterWithDefaults(property.id, property.type);
6779
- onFiltersChange([...filters, newFilter]);
6780
- setAddSelectorOpen(false);
6781
- };
6782
- return /* @__PURE__ */ jsxs45(PopoverPrimitive11.Root, { open, onOpenChange: setOpen, children: [
6783
- /* @__PURE__ */ jsx50(PopoverPrimitive11.Trigger, { asChild: true, children: children ?? /* @__PURE__ */ jsxs45(
6784
- "button",
6785
- {
6786
- type: "button",
6787
- className: cn(
6788
- "inline-flex items-center gap-sm px-base py-sm",
6789
- "min-h-[32px] max-h-[32px]",
6790
- "bg-gradient-to-t from-[var(--color-btn-outlined-neutral-bg-default)] from-[10%] to-[var(--color-btn-outlined-neutral-bg-gradient-to-default)]",
6791
- "border border-[var(--color-btn-outlined-neutral-border-default)] rounded-md shadow-sm",
6792
- "cursor-pointer transition-colors",
6793
- "hover:from-[var(--color-btn-outlined-neutral-bg-hover)] hover:to-[var(--color-btn-outlined-neutral-bg-gradient-to-hover)]",
6794
- 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
+ }
6795
6816
  ),
6796
- children: [
6797
- /* @__PURE__ */ jsx50(
6798
- Icon32,
6799
- {
6800
- icon: faSlidersOutline2,
6801
- size: "sm",
6802
- className: "shrink-0 text-[var(--color-foreground)]"
6803
- }
6804
- ),
6805
- /* @__PURE__ */ jsx50("span", { className: "text-sm font-semibold leading-sm whitespace-nowrap text-[var(--color-foreground)]", children: "Filters" }),
6806
- count > 0 && /* @__PURE__ */ jsx50("span", { className: "flex items-center p-2xs rounded-xs bg-filter-chip-badge-bg", children: /* @__PURE__ */ jsx50("span", { className: "text-[10px] font-semibold leading-2xs text-filter-chip-badge-text", children: count }) })
6807
- ]
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);
6808
6886
  }
6809
- ) }),
6810
- /* @__PURE__ */ jsx50(PopoverPrimitive11.Portal, { children: /* @__PURE__ */ jsxs45(
6811
- 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,
6812
6899
  {
6813
6900
  sideOffset: 4,
6814
6901
  align: "start",
6815
- collisionPadding: 16,
6816
6902
  className: cn(
6817
6903
  "z-50 flex flex-col overflow-clip",
6818
6904
  "bg-[var(--color-dropdown-bg)] border border-[var(--color-dropdown-border)] rounded-md shadow-lg",
6819
6905
  "data-[state=open]:animate-in data-[state=open]:fade-in-0 data-[state=open]:zoom-in-95",
6820
6906
  "data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=closed]:zoom-out-95",
6821
6907
  "data-[side=bottom]:slide-in-from-top-2",
6822
- "w-[min(520px,calc(100vw-32px))]"
6908
+ "min-w-[240px]"
6823
6909
  ),
6824
6910
  children: [
6825
- /* @__PURE__ */ jsxs45("div", { className: "flex flex-col gap-base p-base", children: [
6826
- filters.map((filter, i) => {
6827
- const propDef = getPropertyDef(filter.propertyId);
6828
- if (!propDef) return null;
6829
- return /* @__PURE__ */ jsx50(
6830
- AdvancedRow,
6831
- {
6832
- connector: i === 0 ? "Where" : (logicOps[filter.id] ?? "and") === "and" ? "And" : "Or",
6833
- onConnectorToggle: i > 0 ? () => setLogicOps((prev) => ({ ...prev, [filter.id]: (prev[filter.id] ?? "and") === "and" ? "or" : "and" })) : void 0,
6834
- propertyDef: propDef,
6835
- condition: filter,
6836
- properties,
6837
- onUpdate: handleUpdateFilter,
6838
- onPropertyChange: (p) => handlePropertyChange(filter.id, p),
6839
- onDelete: () => handleDeleteFilter(filter.id)
6840
- },
6841
- filter.id
6842
- );
6843
- }),
6844
- filters.length === 0 && /* @__PURE__ */ jsx50("p", { className: "py-base text-sm text-[var(--color-muted-foreground)]", children: "No active filters." })
6845
- ] }),
6846
- /* @__PURE__ */ jsxs45("div", { className: "flex items-center justify-between p-base border-t border-[var(--color-border)]", children: [
6847
- /* @__PURE__ */ jsx50(
6848
- 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,
6849
6914
  {
6850
- properties,
6851
- onSelect: handleAddFilter,
6852
- open: addSelectorOpen,
6853
- onOpenChange: setAddSelectorOpen,
6854
- children: /* @__PURE__ */ jsxs45(
6855
- "button",
6856
- {
6857
- type: "button",
6858
- className: cn(
6859
- "flex items-center gap-sm px-base py-sm",
6860
- "min-h-[32px] max-h-[32px] min-w-[80px]",
6861
- "bg-gradient-to-t from-[var(--color-btn-outlined-neutral-bg-default)] from-[10%] to-[var(--color-btn-outlined-neutral-bg-gradient-to-default)]",
6862
- "border border-[var(--color-btn-outlined-neutral-border-default)] rounded-md shadow-sm",
6863
- "cursor-pointer transition-colors text-sm font-semibold leading-sm text-[var(--color-foreground)]",
6864
- "hover:from-[var(--color-btn-outlined-neutral-bg-hover)] hover:to-[var(--color-btn-outlined-neutral-bg-gradient-to-hover)]"
6865
- ),
6866
- children: [
6867
- /* @__PURE__ */ jsx50(Icon32, { icon: faPlusOutline3, size: "sm", className: "text-[var(--color-foreground)]" }),
6868
- "Add filter"
6869
- ]
6870
- }
6871
- )
6915
+ icon: propertyDef.icon,
6916
+ size: "sm",
6917
+ className: "shrink-0 text-[var(--color-dropdown-item-icon)]"
6872
6918
  }
6873
6919
  ),
6874
- filters.length > 0 && /* @__PURE__ */ jsx50(
6920
+ /* @__PURE__ */ jsx51("span", { className: "text-sm font-semibold leading-sm text-[var(--color-foreground)]", children: propertyDef.label }),
6921
+ localOperator && view === "value" && /* @__PURE__ */ jsxs45(
6875
6922
  "button",
6876
6923
  {
6877
6924
  type: "button",
6878
- onClick: () => {
6879
- onClearAll();
6880
- setOpen(false);
6881
- },
6882
- className: "text-sm font-semibold leading-sm text-[var(--color-foreground)] cursor-pointer transition-colors hover:opacity-70 px-base py-sm",
6883
- 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
+ ]
6884
6931
  }
6885
6932
  )
6886
- ] })
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
+ )
6887
6953
  ]
6888
6954
  }
6889
6955
  ) })
6890
6956
  ] });
6891
6957
  };
6892
- SummaryChip.displayName = "SummaryChip";
6958
+ FilterEditor.displayName = "FilterEditor";
6893
6959
 
6894
- // src/components/ui/filter/use-filter-bar-mode.ts
6895
- import * as React48 from "react";
6896
- function useFilterBarMode(ref, override) {
6897
- const [mode, setMode] = React48.useState("default");
6898
- React48.useEffect(() => {
6899
- if (override) return;
6900
- const el = ref.current;
6901
- if (!el) return;
6902
- const observer = new ResizeObserver((entries) => {
6903
- const width = entries[0]?.contentRect.width ?? 0;
6904
- setMode(width > 600 ? "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"
6905
6972
  });
6906
- observer.observe(el);
6907
- return () => observer.disconnect();
6908
- }, [ref, override]);
6909
- 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);
6910
6986
  }
6911
-
6912
- // src/components/ui/filter/filter-system.tsx
6913
- import { Fragment as Fragment4, jsx as jsx51, jsxs as jsxs46 } from "react/jsx-runtime";
6914
- var FilterSystem = ({
6915
- properties,
6916
- filterState,
6917
- onFilterStateChange,
6918
- sortFields,
6919
- mode: modeOverride,
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,
6920
6997
  children,
6921
- actions,
6922
- className
6923
- }) => {
6924
- const containerRef = React49.useRef(null);
6925
- const mode = useFilterBarMode(containerRef, modeOverride);
6926
- const [propertySelectorOpen, setPropertySelectorOpen] = React49.useState(false);
6927
- const [advancedOpen, setAdvancedOpen] = React49.useState(false);
6928
- const [pendingFilterId, setPendingFilterId] = React49.useState(null);
6929
- const allFilters = [...filterState.basicFilters, ...filterState.advancedFilters];
6930
- const totalCount = allFilters.length;
6931
- const handleAddFilter = (property) => {
6932
- const newFilter = createFilterWithDefaults(property.id, property.type);
6933
- if (newFilter.operator && isNoValueOperator(newFilter.operator)) {
6934
- onFilterStateChange({
6935
- ...filterState,
6936
- basicFilters: [...filterState.basicFilters, newFilter]
6937
- });
6938
- return;
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
6939
7016
  }
6940
- setPendingFilterId(newFilter.id);
6941
- onFilterStateChange({
6942
- ...filterState,
6943
- basicFilters: [...filterState.basicFilters, newFilter]
6944
- });
6945
- };
6946
- const handleUpdateFilter = (updated) => {
6947
- onFilterStateChange({
6948
- ...filterState,
6949
- basicFilters: filterState.basicFilters.map(
6950
- (f) => f.id === updated.id ? updated : f
6951
- )
6952
- });
6953
- if (pendingFilterId === updated.id) {
6954
- setPendingFilterId(null);
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,
7029
+ className
7030
+ }) => {
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);
6955
7041
  }
6956
- };
6957
- const handleDeleteFilter = (id) => {
6958
- onFilterStateChange({
6959
- ...filterState,
6960
- basicFilters: filterState.basicFilters.filter((f) => f.id !== id)
6961
- });
6962
- };
6963
- const handlePropertyChange = (filterId, newProp) => {
6964
- const newCondition = createFilterWithDefaults(newProp.id, newProp.type);
6965
- onFilterStateChange({
6966
- ...filterState,
6967
- basicFilters: filterState.basicFilters.map(
6968
- (f) => f.id === filterId ? { ...newCondition, id: filterId } : f
6969
- )
6970
- });
6971
- if (newCondition.operator && !isNoValueOperator(newCondition.operator)) {
6972
- setPendingFilterId(filterId);
7042
+ }, [autoOpen, condition.operator]);
7043
+ React45.useEffect(() => {
7044
+ if (!operatorOpen && pendingValueOpen) {
7045
+ setPendingValueOpen(false);
7046
+ setValueOpen(true);
7047
+ }
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
+ }
6973
7060
  }
6974
7061
  };
6975
- const handleConvertToAdvanced = (id) => {
6976
- const filter = filterState.basicFilters.find((f) => f.id === id);
6977
- if (!filter) return;
6978
- onFilterStateChange({
6979
- ...filterState,
6980
- basicFilters: filterState.basicFilters.filter((f) => f.id !== id),
6981
- advancedFilters: [...filterState.advancedFilters, filter]
6982
- });
6983
- };
6984
- const handleAdvancedFiltersChange = (filters) => {
6985
- onFilterStateChange({ ...filterState, advancedFilters: filters });
6986
- };
6987
- const handleClearAdvanced = () => {
6988
- onFilterStateChange({ ...filterState, advancedFilters: [] });
6989
- };
6990
- const handleClearAll = () => {
6991
- onFilterStateChange({
6992
- ...filterState,
6993
- basicFilters: [],
6994
- advancedFilters: []
6995
- });
7062
+ const handleValueChange = (val) => {
7063
+ onUpdate({ ...condition, value: val });
6996
7064
  };
6997
- const handleSortChange = (field, direction) => {
6998
- onFilterStateChange({ ...filterState, sort: { field, direction } });
7065
+ const handleValueSubmit = () => {
7066
+ setValueOpen(false);
6999
7067
  };
7000
- const getPropertyDef = (propertyId) => properties.find((p) => p.id === propertyId);
7001
- const hasAdvanced = filterState.advancedFilters.length > 0;
7002
- const isMinimal = mode === "minimal";
7003
- return /* @__PURE__ */ jsxs46(FilterBar, { ref: containerRef, className, children: [
7004
- /* @__PURE__ */ jsxs46(FilterBarLeft, { className: "flex-nowrap flex-1 min-w-0 overflow-x-auto scrollbar-none outline-none [&>*]:shrink-0", children: [
7005
- children,
7006
- sortFields && filterState.sort && /* @__PURE__ */ jsx51(
7007
- SortButton,
7008
- {
7009
- fields: sortFields,
7010
- activeField: filterState.sort.field,
7011
- direction: filterState.sort.direction,
7012
- onChange: handleSortChange,
7013
- iconOnly: isMinimal
7014
- }
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
7015
7079
  ),
7016
- isMinimal ? totalCount > 0 ? (
7017
- /* Has filters SummaryChip (interactive popover) */
7018
- /* @__PURE__ */ jsx51(
7019
- SummaryChip,
7080
+ children: [
7081
+ properties ? /* @__PURE__ */ jsx52(
7082
+ PropertySelector,
7020
7083
  {
7021
- count: totalCount,
7022
- filters: allFilters,
7023
7084
  properties,
7024
- onFiltersChange: (filters) => {
7025
- onFilterStateChange({
7026
- ...filterState,
7027
- basicFilters: filters,
7028
- advancedFilters: []
7029
- });
7085
+ onSelect: (prop) => {
7086
+ onPropertyChange?.(prop);
7087
+ setPropertyOpen(false);
7030
7088
  },
7031
- onClearAll: handleClearAll
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
+ ) })
7032
7101
  }
7033
- )
7034
- ) : (
7035
- /* No filters → same FilterBarButton as default, icon-only */
7036
- /* @__PURE__ */ jsx51(
7037
- PropertySelector,
7102
+ ) : /* @__PURE__ */ jsx52(
7103
+ FilterChipSegment,
7038
7104
  {
7039
- properties,
7040
- onSelect: handleAddFilter,
7041
- open: propertySelectorOpen,
7042
- onOpenChange: setPropertySelectorOpen,
7043
- children: /* @__PURE__ */ jsx51(FilterBarButton, { iconOnly: true })
7105
+ segmentType: "property",
7106
+ hasBorder: true,
7107
+ icon: propertyDef.icon,
7108
+ label: propertyDef.label
7044
7109
  }
7045
- )
7046
- ) : (
7047
- /* ── DEFAULT MODE ────────────────────────────────────── */
7048
- /* @__PURE__ */ jsxs46(Fragment4, { children: [
7049
- hasAdvanced && /* @__PURE__ */ jsx51(
7050
- AdvancedPopover,
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,
7051
7141
  {
7052
- filters: filterState.advancedFilters,
7053
- properties,
7054
- onFiltersChange: handleAdvancedFiltersChange,
7055
- open: advancedOpen,
7056
- onOpenChange: setAdvancedOpen,
7057
- children: /* @__PURE__ */ jsx51(
7058
- AdvancedChip,
7142
+ open: valueOpen,
7143
+ onOpenChange: setValueOpen,
7144
+ minWidth: dateWide ? "auto" : "240px",
7145
+ trigger: /* @__PURE__ */ jsx52("div", { children: /* @__PURE__ */ jsx52(
7146
+ FilterChipSegment,
7147
+ {
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,
7059
7157
  {
7060
- count: filterState.advancedFilters.length,
7061
- onClick: () => setAdvancedOpen(true),
7062
- onClear: handleClearAdvanced
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
7063
7165
  }
7064
7166
  )
7065
7167
  }
7066
- ),
7067
- filterState.basicFilters.map((filter) => {
7068
- const propDef = getPropertyDef(filter.propertyId);
7069
- if (!propDef) return null;
7070
- return /* @__PURE__ */ jsx51(
7071
- 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,
7072
7187
  {
7073
- propertyDef: propDef,
7074
- condition: filter,
7075
- properties,
7076
- mode: pendingFilterId === filter.id ? "add" : "edit",
7077
- autoOpen: pendingFilterId === filter.id,
7078
- onUpdate: handleUpdateFilter,
7079
- onPropertyChange: (newProp) => handlePropertyChange(filter.id, newProp),
7080
- onDelete: () => handleDeleteFilter(filter.id),
7081
- onConvertToAdvanced: () => handleConvertToAdvanced(filter.id)
7082
- },
7083
- filter.id
7084
- );
7085
- }),
7086
- /* @__PURE__ */ jsx51(
7087
- PropertySelector,
7088
- {
7089
- properties,
7090
- onSelect: handleAddFilter,
7091
- open: propertySelectorOpen,
7092
- onOpenChange: setPropertySelectorOpen,
7093
- children: totalCount > 0 ? /* @__PURE__ */ jsx51(
7094
- "button",
7095
- {
7096
- type: "button",
7097
- 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)]",
7098
- children: /* @__PURE__ */ jsx51(Icon33, { icon: faPlusOutline4, size: "sm", className: "text-[var(--color-foreground)]" })
7188
+ segmentType: "button",
7189
+ onKebabClick: (e) => {
7190
+ e.stopPropagation();
7191
+ setKebabOpen(true);
7099
7192
  }
7100
- ) : /* @__PURE__ */ jsx51(FilterBarButton, {})
7101
- }
7102
- )
7103
- ] })
7104
- ),
7105
- totalCount > 0 && /* @__PURE__ */ jsx51(
7106
- "button",
7107
- {
7108
- type: "button",
7109
- onClick: handleClearAll,
7110
- 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)]",
7111
- children: isMinimal ? /* @__PURE__ */ jsx51(Icon33, { icon: faXmarkOutline4, size: "sm", className: "text-[var(--color-foreground)]" }) : /* @__PURE__ */ jsx51("span", { className: "text-sm font-semibold leading-sm text-[var(--color-foreground)]", children: "Clear" })
7112
- }
7113
- )
7114
- ] }),
7115
- actions && /* @__PURE__ */ jsx51(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 })
7116
- ] });
7117
- };
7118
- FilterSystem.displayName = "FilterSystem";
7119
-
7120
- // src/components/ui/date-picker.tsx
7121
- import * as React50 from "react";
7122
- import * as PopoverPrimitive12 from "@radix-ui/react-popover";
7123
- import {
7124
- Icon as Icon34,
7125
- faChevronLeftOutline as faChevronLeftOutline3,
7126
- faChevronRightOutline as faChevronRightOutline3,
7127
- faArrowRightOutline as faArrowRightOutline2,
7128
- faCalendarOutline
7129
- } from "@l3mpire/icons";
7130
- import { jsx as jsx52, jsxs as jsxs47 } from "react/jsx-runtime";
7131
- function getDaysInMonth(year, month) {
7132
- return new Date(year, month + 1, 0).getDate();
7133
- }
7134
- function getWeekdayIndex(date) {
7135
- return (date.getDay() + 6) % 7;
7136
- }
7137
- function isSameDay(a, b) {
7138
- return a.getFullYear() === b.getFullYear() && a.getMonth() === b.getMonth() && a.getDate() === b.getDate();
7139
- }
7140
- function isInRange(date, from, to) {
7141
- const t = date.getTime();
7142
- return t >= from.getTime() && t <= to.getTime();
7143
- }
7144
- function startOfDay(d) {
7145
- return new Date(d.getFullYear(), d.getMonth(), d.getDate());
7146
- }
7147
- var WEEKDAYS = ["Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"];
7148
- var MONTH_NAMES = [
7149
- "January",
7150
- "February",
7151
- "March",
7152
- "April",
7153
- "May",
7154
- "June",
7155
- "July",
7156
- "August",
7157
- "September",
7158
- "October",
7159
- "November",
7160
- "December"
7161
- ];
7162
- var DatePickerContext = React50.createContext(
7163
- null
7164
- );
7165
- function useDatePickerContext() {
7166
- const ctx = React50.useContext(DatePickerContext);
7167
- if (!ctx)
7168
- throw new Error("DatePicker compound components must be used within <DatePicker>");
7169
- return ctx;
7170
- }
7171
- var DatePicker = React50.forwardRef(
7172
- ({
7173
- className,
7174
- mode = "single",
7175
- value,
7176
- onValueChange,
7177
- defaultMonth,
7178
- defaultYear,
7179
- children,
7180
- ...props
7181
- }, ref) => {
7182
- const today = React50.useMemo(() => startOfDay(/* @__PURE__ */ new Date()), []);
7183
- const initialDate = React50.useMemo(() => {
7184
- if (value) {
7185
- if (value instanceof Date) return value;
7186
- return value.from;
7187
- }
7188
- return today;
7189
- }, []);
7190
- const [month, setMonth] = React50.useState(
7191
- defaultMonth ?? initialDate.getMonth()
7192
- );
7193
- const [year, setYear] = React50.useState(
7194
- defaultYear ?? initialDate.getFullYear()
7195
- );
7196
- const [hoveredDate, setHoveredDate] = React50.useState();
7197
- const goToPrevMonth = React50.useCallback(() => {
7198
- setMonth((m) => {
7199
- if (m === 0) {
7200
- setYear((y) => y - 1);
7201
- return 11;
7202
- }
7203
- return m - 1;
7204
- });
7205
- }, []);
7206
- const goToNextMonth = React50.useCallback(() => {
7207
- setMonth((m) => {
7208
- if (m === 11) {
7209
- setYear((y) => y + 1);
7210
- return 0;
7211
- }
7212
- return m + 1;
7213
- });
7214
- }, []);
7215
- const onSelect = React50.useCallback(
7216
- (date) => {
7217
- if (mode === "single") {
7218
- onValueChange?.(date);
7219
- return;
7220
- }
7221
- if (!value || value instanceof Date) {
7222
- onValueChange?.({ from: date });
7223
- return;
7224
- }
7225
- const range = value;
7226
- if (range.to || date.getTime() < range.from.getTime()) {
7227
- onValueChange?.({ from: date });
7228
- } else {
7229
- onValueChange?.({ from: range.from, to: date });
7230
- }
7231
- },
7232
- [mode, value, onValueChange]
7233
- );
7234
- const ctxValue = React50.useMemo(
7235
- () => ({
7236
- mode,
7237
- selected: value,
7238
- onSelect,
7239
- month,
7240
- year,
7241
- setMonth,
7242
- setYear,
7243
- goToPrevMonth,
7244
- goToNextMonth,
7245
- today,
7246
- hoveredDate,
7247
- setHoveredDate
7248
- }),
7249
- [
7250
- mode,
7251
- value,
7252
- onSelect,
7253
- month,
7254
- year,
7255
- goToPrevMonth,
7256
- goToNextMonth,
7257
- today,
7258
- hoveredDate
7193
+ }
7194
+ ) })
7195
+ }
7196
+ )
7259
7197
  ]
7260
- );
7261
- return /* @__PURE__ */ jsx52(DatePickerContext.Provider, { value: ctxValue, children: /* @__PURE__ */ jsx52(
7262
- "div",
7198
+ }
7199
+ );
7200
+ };
7201
+ InteractiveFilterChip.displayName = "InteractiveFilterChip";
7202
+
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)]"
7218
+ ];
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",
7263
7223
  {
7264
7224
  ref,
7225
+ type: "button",
7226
+ onClick,
7265
7227
  className: cn(
7266
- "flex flex-col overflow-clip",
7267
- "bg-datepicker-bg border border-datepicker-border rounded-md shadow-lg",
7268
- className
7228
+ btnBase,
7229
+ "gap-sm px-base py-sm min-w-[80px]",
7230
+ "rounded-l-md -mr-px"
7269
7231
  ),
7270
7232
  ...props,
7271
- children
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
+ ]
7272
7237
  }
7273
- ) });
7274
- }
7275
- );
7276
- DatePicker.displayName = "DatePicker";
7277
- function defaultFormatDate(date) {
7278
- return date.toLocaleDateString("en-US", {
7279
- month: "short",
7280
- day: "numeric",
7281
- year: "numeric"
7282
- });
7283
- }
7284
- var DatePickerSelects = React50.forwardRef(({ className, formatDate = defaultFormatDate, ...props }, ref) => {
7285
- const { selected } = useDatePickerContext();
7286
- const fromDate = selected instanceof Date ? selected : selected?.from;
7287
- const toDate = selected instanceof Date ? void 0 : selected?.to;
7288
- return /* @__PURE__ */ jsx52(
7289
- "div",
7290
- {
7291
- ref,
7292
- className: cn("flex flex-col items-start pt-lg px-lg", className),
7293
- ...props,
7294
- children: /* @__PURE__ */ jsxs47("div", { className: "flex items-center gap-base w-full", children: [
7295
- /* @__PURE__ */ jsxs47("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: [
7296
- /* @__PURE__ */ jsx52("span", { className: "flex-1 text-sm font-regular leading-sm text-datepicker-header-text truncate", children: fromDate ? formatDate(fromDate) : "Start date" }),
7297
- /* @__PURE__ */ jsx52(Icon34, { icon: faCalendarOutline, size: "sm", className: "shrink-0 text-datepicker-header-text" })
7298
- ] }),
7299
- /* @__PURE__ */ jsx52(
7300
- Icon34,
7301
- {
7302
- icon: faArrowRightOutline2,
7303
- size: "sm",
7304
- className: "shrink-0 text-datepicker-header-weekday"
7305
- }
7238
+ ),
7239
+ onClear && /* @__PURE__ */ jsx53(
7240
+ "button",
7241
+ {
7242
+ type: "button",
7243
+ onClick: (e) => {
7244
+ e.stopPropagation();
7245
+ onClear();
7246
+ },
7247
+ className: cn(
7248
+ btnBase,
7249
+ "p-sm",
7250
+ "rounded-r-md -ml-px"
7306
7251
  ),
7307
- /* @__PURE__ */ jsxs47("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: [
7308
- /* @__PURE__ */ jsx52("span", { className: "flex-1 text-sm font-regular leading-sm text-datepicker-header-text truncate", children: toDate ? formatDate(toDate) : "End date" }),
7309
- /* @__PURE__ */ jsx52(Icon34, { icon: faCalendarOutline, size: "sm", className: "shrink-0 text-datepicker-header-text" })
7310
- ] })
7311
- ] })
7252
+ "aria-label": "Clear all advanced filters",
7253
+ children: /* @__PURE__ */ jsx53(Icon31, { icon: faXmarkOutline2, size: "sm", className: "text-[var(--color-foreground)]" })
7254
+ }
7255
+ )
7256
+ ] })
7257
+ );
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 });
7312
7296
  }
7313
- );
7314
- });
7315
- DatePickerSelects.displayName = "DatePickerSelects";
7316
- var DatePickerDay = ({ date, isOutside }) => {
7317
- const { mode, selected, onSelect, today, hoveredDate, setHoveredDate } = useDatePickerContext();
7318
- const isToday = isSameDay(date, today);
7319
- const isSelected = selected instanceof Date ? isSameDay(date, selected) : selected?.from ? isSameDay(date, selected.from) || (selected.to ? isSameDay(date, selected.to) : false) : false;
7320
- const isRangeStart = mode === "range" && selected && !(selected instanceof Date) && selected.from && isSameDay(date, selected.from);
7321
- const isRangeEnd = mode === "range" && selected && !(selected instanceof Date) && selected.to && isSameDay(date, selected.to);
7322
- const inRange = mode === "range" && selected && !(selected instanceof Date) && selected.from && selected.to && !isSelected && isInRange(date, selected.from, selected.to);
7323
- const inPreviewRange = mode === "range" && selected && !(selected instanceof Date) && selected.from && !selected.to && hoveredDate && !isSelected && hoveredDate.getTime() > selected.from.getTime() && isInRange(date, selected.from, hoveredDate);
7324
- const isInRangeOrPreview = inRange || inPreviewRange;
7325
- return /* @__PURE__ */ jsxs47(
7326
- "button",
7327
- {
7328
- type: "button",
7329
- onClick: () => !isOutside && onSelect(date),
7330
- onMouseEnter: () => mode === "range" && setHoveredDate(date),
7331
- onMouseLeave: () => mode === "range" && setHoveredDate(void 0),
7332
- disabled: isOutside,
7333
- className: cn(
7334
- "relative flex flex-col items-center justify-center w-9 rounded-full p-2 cursor-pointer transition-colors",
7335
- "text-sm font-semibold leading-sm text-center",
7336
- // Default
7337
- !isOutside && !isSelected && !isInRangeOrPreview && "text-datepicker-day-text-default hover:bg-datepicker-day-bg-hover",
7338
- // Outside month (disabled)
7339
- isOutside && "text-datepicker-day-text-disabled cursor-default",
7340
- // Selected
7341
- isSelected && "bg-datepicker-day-bg-selected text-datepicker-day-text-selected",
7342
- // In range
7343
- isInRangeOrPreview && "bg-datepicker-day-bg-range text-datepicker-day-text-range",
7344
- // Range start/end get full rounded; in-range items could be less rounded
7345
- (isRangeStart || isRangeEnd) && "rounded-full"
7346
- ),
7347
- children: [
7348
- date.getDate(),
7349
- isToday && !isOutside && /* @__PURE__ */ jsx52("span", { className: "absolute bottom-0.5 left-1/2 -translate-x-1/2 size-1.5 rounded-full bg-datepicker-day-today" })
7350
- ]
7351
- }
7352
- );
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)]"
7316
+ ),
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
+ ] });
7353
7423
  };
7354
- var DatePickerCalendar = React50.forwardRef(({ className, header, ...props }, ref) => {
7355
- const { month, year, goToPrevMonth, goToNextMonth } = useDatePickerContext();
7356
- const weeks = React50.useMemo(() => {
7357
- const firstDay = new Date(year, month, 1);
7358
- const startOffset = getWeekdayIndex(firstDay);
7359
- const daysInMonth = getDaysInMonth(year, month);
7360
- const daysInPrevMonth = getDaysInMonth(
7361
- month === 0 ? year - 1 : year,
7362
- month === 0 ? 11 : month - 1
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)
7363
7619
  );
7364
- const days = [];
7365
- for (let i = startOffset - 1; i >= 0; i--) {
7366
- const d = daysInPrevMonth - i;
7367
- days.push({
7368
- date: new Date(
7369
- month === 0 ? year - 1 : year,
7370
- month === 0 ? 11 : month - 1,
7371
- d
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
7372
7646
  ),
7373
- isOutside: true
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]
7374
7828
  });
7829
+ return;
7375
7830
  }
7376
- for (let d = 1; d <= daysInMonth; d++) {
7377
- days.push({ date: new Date(year, month, d), isOutside: false });
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);
7378
7846
  }
7379
- const remaining = 42 - days.length;
7380
- for (let d = 1; d <= remaining; d++) {
7381
- days.push({
7382
- date: new Date(
7383
- month === 11 ? year + 1 : year,
7384
- month === 11 ? 0 : month + 1,
7385
- d
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
+ }
7386
7945
  ),
7387
- isOutside: true
7388
- });
7389
- }
7390
- const result = [];
7391
- for (let i = 0; i < days.length; i += 7) {
7392
- result.push(days.slice(i, i + 7));
7393
- }
7394
- return result;
7395
- }, [month, year]);
7396
- return /* @__PURE__ */ jsxs47(
7397
- "div",
7398
- {
7399
- ref,
7400
- className: cn("flex flex-col", className),
7401
- ...props,
7402
- children: [
7403
- header,
7404
- /* @__PURE__ */ jsxs47("div", { className: "flex flex-col gap-lg p-lg", children: [
7405
- /* @__PURE__ */ jsxs47("div", { className: "flex items-center justify-between", children: [
7406
- /* @__PURE__ */ jsxs47("span", { className: "text-base font-semibold leading-base text-datepicker-header-text", children: [
7407
- MONTH_NAMES[month],
7408
- " ",
7409
- year
7410
- ] }),
7411
- /* @__PURE__ */ jsxs47("div", { className: "flex items-center gap-xs", children: [
7412
- /* @__PURE__ */ jsx52(
7413
- "button",
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",
7414
7971
  {
7415
- type: "button",
7416
- onClick: goToPrevMonth,
7417
- className: "flex items-center justify-center p-xs rounded-base hover:bg-datepicker-day-bg-hover transition-colors cursor-pointer",
7418
- "aria-label": "Previous month",
7419
- children: /* @__PURE__ */ jsx52(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
+ )
7420
7982
  }
7421
- ),
7422
- /* @__PURE__ */ jsx52(
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(
7423
8015
  "button",
7424
8016
  {
7425
8017
  type: "button",
7426
- onClick: goToNextMonth,
7427
- className: "flex items-center justify-center p-xs rounded-base hover:bg-datepicker-day-bg-hover transition-colors cursor-pointer",
7428
- "aria-label": "Next month",
7429
- children: /* @__PURE__ */ jsx52(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)]" })
7430
8020
  }
7431
- )
7432
- ] })
7433
- ] }),
7434
- /* @__PURE__ */ jsxs47("div", { className: "flex flex-col", children: [
7435
- /* @__PURE__ */ jsx52("div", { className: "grid grid-cols-7 gap-base py-sm", children: WEEKDAYS.map((day) => /* @__PURE__ */ jsx52(
7436
- "span",
7437
- {
7438
- className: "w-9 text-center text-xs font-regular leading-xs text-datepicker-header-weekday",
7439
- children: day
7440
- },
7441
- day
7442
- )) }),
7443
- /* @__PURE__ */ jsx52("div", { className: "flex flex-col", children: weeks.map((week, wi) => /* @__PURE__ */ jsx52("div", { className: "grid grid-cols-7 gap-base", children: week.map((day, di) => /* @__PURE__ */ jsx52(
7444
- DatePickerDay,
7445
- {
7446
- date: day.date,
7447
- isOutside: day.isOutside
7448
- },
7449
- di
7450
- )) }, wi)) })
7451
- ] })
8021
+ ) : /* @__PURE__ */ jsx57(FilterBarButton, {})
8022
+ }
8023
+ )
7452
8024
  ] })
7453
- ]
7454
- }
7455
- );
7456
- });
7457
- DatePickerCalendar.displayName = "DatePickerCalendar";
7458
- var DatePickerSuggestions = React50.forwardRef(
7459
- ({ className, suggestions, formatDate = defaultFormatDate, ...props }, ref) => {
7460
- const { onSelect, mode } = useDatePickerContext();
7461
- const onValueChange = React50.useContext(DatePickerContext) ? void 0 : void 0;
7462
- const ctx = useDatePickerContext();
7463
- const handleClick = (suggestion) => {
7464
- const val = suggestion.getValue();
7465
- if (val instanceof Date) {
7466
- ctx.onSelect(val);
7467
- } else {
7468
- ctx.onSelect(val.from);
7469
- if (val.to) {
7470
- setTimeout(() => ctx.onSelect(val.to), 0);
7471
- }
7472
- }
7473
- };
7474
- const formatSuggestionDate = (suggestion) => {
7475
- const val = suggestion.getValue();
7476
- if (val instanceof Date) {
7477
- return formatDate(val);
7478
- }
7479
- const from = formatDate(val.from);
7480
- const to = val.to ? formatDate(val.to) : "";
7481
- return to ? `${from} - ${to}` : from;
7482
- };
7483
- return /* @__PURE__ */ jsxs47(
7484
- "div",
7485
- {
7486
- ref,
7487
- className: cn(
7488
- "flex flex-col border-l border-datepicker-border self-stretch shrink-0",
7489
- className
7490
- ),
7491
- ...props,
7492
- children: [
7493
- /* @__PURE__ */ jsx52("div", { className: "pt-lg px-base", children: /* @__PURE__ */ jsx52("div", { className: "flex items-center p-base rounded-base", children: /* @__PURE__ */ jsx52("span", { className: "flex-1 text-xs font-semibold leading-xs text-datepicker-suggestion-heading uppercase truncate", children: "Suggestions" }) }) }),
7494
- /* @__PURE__ */ jsx52("div", { className: "flex flex-1 flex-col p-base min-w-[222px]", children: suggestions.map((suggestion, i) => /* @__PURE__ */ jsxs47(
7495
- "button",
7496
- {
7497
- type: "button",
7498
- onClick: () => handleClick(suggestion),
7499
- className: "flex items-center gap-sm p-base rounded-base hover:bg-datepicker-suggestion-hover transition-colors cursor-pointer text-left",
7500
- children: [
7501
- /* @__PURE__ */ jsx52("span", { className: "text-sm font-regular leading-sm text-datepicker-suggestion-text truncate shrink-0", children: suggestion.label }),
7502
- /* @__PURE__ */ jsx52("span", { className: "text-xs font-regular leading-xs text-datepicker-suggestion-date truncate", children: formatSuggestionDate(suggestion) })
7503
- ]
7504
- },
7505
- i
7506
- )) })
7507
- ]
7508
- }
7509
- );
7510
- }
7511
- );
7512
- DatePickerSuggestions.displayName = "DatePickerSuggestions";
7513
- var DatePickerFooter = React50.forwardRef(
7514
- ({ className, children, ...props }, ref) => /* @__PURE__ */ jsx52(
7515
- "div",
7516
- {
7517
- ref,
7518
- className: cn(
7519
- "flex items-center justify-between p-lg",
7520
- "border-t border-datepicker-footer-border",
7521
- "bg-datepicker-bg",
7522
- className
7523
8025
  ),
7524
- ...props,
7525
- children
7526
- }
7527
- )
7528
- );
7529
- DatePickerFooter.displayName = "DatePickerFooter";
7530
- var DatePickerPanel = React50.forwardRef(
7531
- ({ className, children, ...props }, ref) => /* @__PURE__ */ jsx52(
7532
- "div",
7533
- {
7534
- ref,
7535
- className: cn("flex items-start", className),
7536
- ...props,
7537
- children
7538
- }
7539
- )
7540
- );
7541
- DatePickerPanel.displayName = "DatePickerPanel";
7542
- var DatePickerRoot = PopoverPrimitive12.Root;
7543
- var DatePickerTrigger = PopoverPrimitive12.Trigger;
7544
- var DatePickerPopover = React50.forwardRef(({ className, sideOffset = 4, align = "start", children, ...props }, ref) => /* @__PURE__ */ jsx52(PopoverPrimitive12.Portal, { children: /* @__PURE__ */ jsx52(
7545
- PopoverPrimitive12.Content,
7546
- {
7547
- ref,
7548
- sideOffset,
7549
- align,
7550
- className: cn(
7551
- "z-50",
7552
- "data-[state=open]:animate-in data-[state=open]:fade-in-0 data-[state=open]:zoom-in-95",
7553
- "data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=closed]:zoom-out-95",
7554
- "data-[side=bottom]:slide-in-from-top-2 data-[side=top]:slide-in-from-bottom-2",
7555
- className
7556
- ),
7557
- ...props,
7558
- children
7559
- }
7560
- ) }));
7561
- DatePickerPopover.displayName = "DatePickerPopover";
7562
- function getDefaultSuggestions(referenceDate) {
7563
- const now = referenceDate ?? /* @__PURE__ */ new Date();
7564
- const today = startOfDay(now);
7565
- const dayOfWeek = getWeekdayIndex(today);
7566
- const startOfThisWeek = new Date(today);
7567
- startOfThisWeek.setDate(today.getDate() - dayOfWeek);
7568
- const endOfThisWeek = new Date(startOfThisWeek);
7569
- endOfThisWeek.setDate(startOfThisWeek.getDate() + 6);
7570
- const startOfThisMonth = new Date(today.getFullYear(), today.getMonth(), 1);
7571
- const endOfThisMonth = new Date(
7572
- today.getFullYear(),
7573
- today.getMonth() + 1,
7574
- 0
7575
- );
7576
- const startOfThisYear = new Date(today.getFullYear(), 0, 1);
7577
- const endOfThisYear = new Date(today.getFullYear(), 11, 31);
7578
- const startOfLastWeek = new Date(startOfThisWeek);
7579
- startOfLastWeek.setDate(startOfThisWeek.getDate() - 7);
7580
- const endOfLastWeek = new Date(startOfThisWeek);
7581
- endOfLastWeek.setDate(startOfThisWeek.getDate() - 1);
7582
- const startOfLastMonth = new Date(
7583
- today.getFullYear(),
7584
- today.getMonth() - 1,
7585
- 1
7586
- );
7587
- const endOfLastMonth = new Date(today.getFullYear(), today.getMonth(), 0);
7588
- const startOfLastYear = new Date(today.getFullYear() - 1, 0, 1);
7589
- const endOfLastYear = new Date(today.getFullYear() - 1, 11, 31);
7590
- return [
7591
- { label: "Today", getValue: () => today },
7592
- {
7593
- label: "This week",
7594
- getValue: () => ({ from: startOfThisWeek, to: endOfThisWeek })
7595
- },
7596
- {
7597
- label: "This month",
7598
- getValue: () => ({ from: startOfThisMonth, to: endOfThisMonth })
7599
- },
7600
- {
7601
- label: "This year",
7602
- getValue: () => ({ from: startOfThisYear, to: endOfThisYear })
7603
- },
7604
- {
7605
- label: "Last week",
7606
- getValue: () => ({ from: startOfLastWeek, to: endOfLastWeek })
7607
- },
7608
- {
7609
- label: "Last month",
7610
- getValue: () => ({ from: startOfLastMonth, to: endOfLastMonth })
7611
- },
7612
- {
7613
- label: "Last year",
7614
- getValue: () => ({ from: startOfLastYear, to: endOfLastYear })
7615
- }
7616
- ];
7617
- }
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";
7618
8040
  export {
7619
8041
  AdvancedChip,
7620
8042
  AdvancedPopover,