@l3mpire/ui 2.13.0 → 2.14.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.mjs CHANGED
@@ -5072,6 +5072,130 @@ function getValueInputType(type, operator) {
5072
5072
  return ["is any of", "is none of"].includes(operator) ? "MultiRelationPicker" : "RelationPicker";
5073
5073
  return null;
5074
5074
  }
5075
+ function formatFilterValue(value) {
5076
+ if (value == null) return void 0;
5077
+ if (typeof value === "boolean") return value ? "Yes" : "No";
5078
+ if (value instanceof Date) {
5079
+ return value.toLocaleDateString("en-US", {
5080
+ month: "short",
5081
+ day: "numeric",
5082
+ year: "numeric"
5083
+ });
5084
+ }
5085
+ if (Array.isArray(value)) {
5086
+ if (value.length === 0) return void 0;
5087
+ if (value.length === 2 && typeof value[0] === "number") {
5088
+ return `${value[0]} \u2013 ${value[1]}`;
5089
+ }
5090
+ if (value.length === 2 && value[0] instanceof Date) {
5091
+ const fmt = (d) => d.toLocaleDateString("en-US", { month: "short", day: "numeric", year: "numeric" });
5092
+ return `${fmt(value[0])} \u2013 ${value[1] instanceof Date ? fmt(value[1]) : "\u2026"}`;
5093
+ }
5094
+ return String(value[0]);
5095
+ }
5096
+ return String(value);
5097
+ }
5098
+ function getBadgeCount(value) {
5099
+ if (Array.isArray(value) && value.length > 1 && typeof value[0] === "string") {
5100
+ return value.length;
5101
+ }
5102
+ return void 0;
5103
+ }
5104
+ function isFilterGroup(node) {
5105
+ return node.type === "group";
5106
+ }
5107
+ function createEmptyGroup() {
5108
+ return {
5109
+ id: crypto.randomUUID(),
5110
+ type: "group",
5111
+ children: []
5112
+ };
5113
+ }
5114
+ function duplicateNode(node) {
5115
+ if (isFilterGroup(node)) {
5116
+ return {
5117
+ ...node,
5118
+ id: crypto.randomUUID(),
5119
+ children: node.children.map(duplicateNode)
5120
+ };
5121
+ }
5122
+ return { ...node, id: crypto.randomUUID() };
5123
+ }
5124
+ function wrapInGroup(condition) {
5125
+ return {
5126
+ id: crypto.randomUUID(),
5127
+ type: "group",
5128
+ logicOperator: condition.logicOperator,
5129
+ children: [{ ...condition, logicOperator: void 0 }]
5130
+ };
5131
+ }
5132
+ function unwrapGroup(group) {
5133
+ const first = group.children.find((c) => !isFilterGroup(c));
5134
+ if (!first) return null;
5135
+ return { ...first, logicOperator: group.logicOperator };
5136
+ }
5137
+ function updateNodeInTree(nodes, id, updater) {
5138
+ return nodes.map((node) => {
5139
+ if (node.id === id) return updater(node);
5140
+ if (isFilterGroup(node)) {
5141
+ const updated = updateNodeInTree(node.children, id, updater);
5142
+ if (updated !== node.children) return { ...node, children: updated };
5143
+ }
5144
+ return node;
5145
+ });
5146
+ }
5147
+ function removeNodeFromTree(nodes, id) {
5148
+ const result = [];
5149
+ for (const node of nodes) {
5150
+ if (node.id === id) continue;
5151
+ if (isFilterGroup(node)) {
5152
+ const updated = removeNodeFromTree(node.children, id);
5153
+ result.push(updated !== node.children ? { ...node, children: updated } : node);
5154
+ } else {
5155
+ result.push(node);
5156
+ }
5157
+ }
5158
+ return result;
5159
+ }
5160
+ function insertAfterInTree(nodes, afterId, newNode) {
5161
+ const result = [];
5162
+ let inserted = false;
5163
+ for (const node of nodes) {
5164
+ result.push(node);
5165
+ if (node.id === afterId) {
5166
+ result.push(newNode);
5167
+ inserted = true;
5168
+ } else if (!inserted && isFilterGroup(node)) {
5169
+ const updated = insertAfterInTree(node.children, afterId, newNode);
5170
+ if (updated.length !== node.children.length) {
5171
+ result[result.length - 1] = { ...node, children: updated };
5172
+ inserted = true;
5173
+ }
5174
+ }
5175
+ }
5176
+ return result;
5177
+ }
5178
+ function replaceNodeInTree(nodes, id, replacement) {
5179
+ return nodes.map((node) => {
5180
+ if (node.id === id) return replacement;
5181
+ if (isFilterGroup(node)) {
5182
+ const updated = replaceNodeInTree(node.children, id, replacement);
5183
+ if (updated !== node.children) return { ...node, children: updated };
5184
+ }
5185
+ return node;
5186
+ });
5187
+ }
5188
+ function countConditions(nodes) {
5189
+ let count = 0;
5190
+ for (const node of nodes) {
5191
+ if (isFilterGroup(node)) {
5192
+ count += countConditions(node.children);
5193
+ } else {
5194
+ count++;
5195
+ }
5196
+ }
5197
+ return count;
5198
+ }
5075
5199
 
5076
5200
  // src/components/ui/filter/filter-bar.tsx
5077
5201
  import * as React37 from "react";
@@ -6961,35 +7085,6 @@ FilterEditor.displayName = "FilterEditor";
6961
7085
  import * as React45 from "react";
6962
7086
  import * as PopoverPrimitive9 from "@radix-ui/react-popover";
6963
7087
  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"
6972
- });
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);
6986
- }
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
7088
  var SegmentPopover = ({
6994
7089
  open,
6995
7090
  onOpenChange,
@@ -7201,8 +7296,8 @@ var InteractiveFilterChip = ({
7201
7296
  InteractiveFilterChip.displayName = "InteractiveFilterChip";
7202
7297
 
7203
7298
  // 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";
7299
+ import * as React53 from "react";
7300
+ import { Icon as Icon37, faXmarkOutline as faXmarkOutline5, faPlusOutline as faPlusOutline5 } from "@l3mpire/icons";
7206
7301
 
7207
7302
  // src/components/ui/filter/advanced-chip.tsx
7208
7303
  import * as React46 from "react";
@@ -7258,15 +7353,128 @@ var AdvancedChip = React46.forwardRef(
7258
7353
  AdvancedChip.displayName = "AdvancedChip";
7259
7354
 
7260
7355
  // src/components/ui/filter/advanced-popover.tsx
7356
+ import * as React50 from "react";
7357
+ import * as PopoverPrimitive12 from "@radix-ui/react-popover";
7358
+ import { Icon as Icon35, faPlusOutline as faPlusOutline3, faChevronDownOutline as faChevronDownOutline3, faXmarkOutline as faXmarkOutline3 } from "@l3mpire/icons";
7359
+
7360
+ // src/components/ui/filter/advanced-row.tsx
7261
7361
  import * as React48 from "react";
7262
7362
  import * as PopoverPrimitive11 from "@radix-ui/react-popover";
7263
- import { Icon as Icon33, faPlusOutline as faPlusOutline2, faChevronDownOutline as faChevronDownOutline3 } from "@l3mpire/icons";
7363
+ import { Icon as Icon33, faRefreshOutline, faChevronDownOutline as faChevronDownOutline2 } from "@l3mpire/icons";
7264
7364
 
7265
- // src/components/ui/filter/advanced-row.tsx
7365
+ // src/components/ui/filter/filter-node-actions.tsx
7266
7366
  import * as React47 from "react";
7267
7367
  import * as PopoverPrimitive10 from "@radix-ui/react-popover";
7268
- import { Icon as Icon32, faXmarkOutline as faXmarkOutline3, faRefreshOutline, faChevronDownOutline as faChevronDownOutline2 } from "@l3mpire/icons";
7368
+ import {
7369
+ Icon as Icon32,
7370
+ faEllipsisOutline,
7371
+ faCopyOutline,
7372
+ faTrashOutline as faTrashOutline2,
7373
+ faFolderOutline,
7374
+ faFilterOutline as faFilterOutline3
7375
+ } from "@l3mpire/icons";
7269
7376
  import { jsx as jsx54, jsxs as jsxs48 } from "react/jsx-runtime";
7377
+ var FilterNodeActions = ({
7378
+ nodeType,
7379
+ onDuplicate,
7380
+ onConvert,
7381
+ onDelete
7382
+ }) => {
7383
+ const [open, setOpen] = React47.useState(false);
7384
+ const items = [
7385
+ {
7386
+ label: "Duplicate",
7387
+ icon: faCopyOutline,
7388
+ action: onDuplicate
7389
+ },
7390
+ {
7391
+ label: nodeType === "condition" ? "Turn into group" : "Turn into filter",
7392
+ icon: nodeType === "condition" ? faFolderOutline : faFilterOutline3,
7393
+ action: onConvert
7394
+ },
7395
+ {
7396
+ label: "Delete",
7397
+ icon: faTrashOutline2,
7398
+ action: onDelete,
7399
+ destructive: true
7400
+ }
7401
+ ];
7402
+ return /* @__PURE__ */ jsxs48(PopoverPrimitive10.Root, { open, onOpenChange: setOpen, children: [
7403
+ /* @__PURE__ */ jsx54(PopoverPrimitive10.Trigger, { asChild: true, children: /* @__PURE__ */ jsx54(
7404
+ "button",
7405
+ {
7406
+ type: "button",
7407
+ className: "shrink-0 flex items-center justify-center p-sm rounded-md cursor-pointer transition-colors hover:bg-[var(--color-accent)]",
7408
+ "aria-label": "More actions",
7409
+ children: /* @__PURE__ */ jsx54(
7410
+ Icon32,
7411
+ {
7412
+ icon: faEllipsisOutline,
7413
+ size: "sm",
7414
+ className: "text-[var(--color-foreground)]"
7415
+ }
7416
+ )
7417
+ }
7418
+ ) }),
7419
+ /* @__PURE__ */ jsx54(PopoverPrimitive10.Portal, { children: /* @__PURE__ */ jsx54(
7420
+ PopoverPrimitive10.Content,
7421
+ {
7422
+ sideOffset: 4,
7423
+ align: "end",
7424
+ className: cn(
7425
+ "z-50 flex flex-col p-xs overflow-clip",
7426
+ "bg-[var(--color-dropdown-bg)] border border-[var(--color-dropdown-border)] rounded-md shadow-lg",
7427
+ "data-[state=open]:animate-in data-[state=open]:fade-in-0 data-[state=open]:zoom-in-95",
7428
+ "data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=closed]:zoom-out-95",
7429
+ "min-w-[180px]"
7430
+ ),
7431
+ children: items.map((item) => /* @__PURE__ */ jsxs48(
7432
+ "button",
7433
+ {
7434
+ type: "button",
7435
+ onClick: () => {
7436
+ item.action();
7437
+ setOpen(false);
7438
+ },
7439
+ className: cn(
7440
+ "flex items-center gap-base p-base rounded-base cursor-pointer transition-colors text-left",
7441
+ "hover:bg-[var(--color-dropdown-item-hover)]",
7442
+ item.destructive && "text-[var(--color-destructive,#ef4444)]"
7443
+ ),
7444
+ children: [
7445
+ /* @__PURE__ */ jsx54(
7446
+ Icon32,
7447
+ {
7448
+ icon: item.icon,
7449
+ size: "sm",
7450
+ className: cn(
7451
+ "shrink-0",
7452
+ item.destructive ? "text-[var(--color-destructive,#ef4444)]" : "text-[var(--color-dropdown-item-icon)]"
7453
+ )
7454
+ }
7455
+ ),
7456
+ /* @__PURE__ */ jsx54(
7457
+ "span",
7458
+ {
7459
+ className: cn(
7460
+ "text-sm font-regular leading-sm",
7461
+ item.destructive ? "text-[var(--color-destructive,#ef4444)]" : "text-[var(--color-dropdown-item-text)]"
7462
+ ),
7463
+ children: item.label
7464
+ }
7465
+ )
7466
+ ]
7467
+ },
7468
+ item.label
7469
+ ))
7470
+ }
7471
+ ) })
7472
+ ] });
7473
+ };
7474
+ FilterNodeActions.displayName = "FilterNodeActions";
7475
+
7476
+ // src/components/ui/filter/advanced-row.tsx
7477
+ import { jsx as jsx55, jsxs as jsxs49 } from "react/jsx-runtime";
7270
7478
  var selectBtnStyle = [
7271
7479
  "flex items-center gap-base",
7272
7480
  "px-base py-sm",
@@ -7283,10 +7491,13 @@ var AdvancedRow = ({
7283
7491
  properties,
7284
7492
  onUpdate,
7285
7493
  onPropertyChange,
7286
- onDelete
7494
+ onDelete,
7495
+ onDuplicate,
7496
+ onTurnIntoGroup
7287
7497
  }) => {
7288
- const [operatorOpen, setOperatorOpen] = React47.useState(false);
7289
- const [propertyOpen, setPropertyOpen] = React47.useState(false);
7498
+ const [operatorOpen, setOperatorOpen] = React48.useState(false);
7499
+ const [propertyOpen, setPropertyOpen] = React48.useState(false);
7500
+ const [valueOpen, setValueOpen] = React48.useState(false);
7290
7501
  const handleOperatorSelect = (op) => {
7291
7502
  if (isNoValueOperator(op)) {
7292
7503
  onUpdate({ ...condition, operator: op, value: null });
@@ -7299,16 +7510,18 @@ var AdvancedRow = ({
7299
7510
  const handleValueChange = (val) => {
7300
7511
  onUpdate({ ...condition, value: val });
7301
7512
  };
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(
7513
+ const displayValue = formatFilterValue(condition.value);
7514
+ const badgeCount = getBadgeCount(condition.value);
7515
+ const hasValue = displayValue != null;
7516
+ return /* @__PURE__ */ jsxs49("div", { className: "flex items-center gap-base w-full min-w-0", children: [
7517
+ connector === "Where" ? /* @__PURE__ */ jsx55("div", { className: "shrink-0 w-[64px] flex items-center justify-end", children: /* @__PURE__ */ jsx55("span", { className: "text-xs font-semibold leading-xs text-[var(--color-muted-foreground)]", children: "Where" }) }) : /* @__PURE__ */ jsxs49(
7305
7518
  "button",
7306
7519
  {
7307
7520
  type: "button",
7308
7521
  onClick: onConnectorToggle,
7309
7522
  className: cn(
7310
7523
  "shrink-0 flex items-center justify-center gap-xs",
7311
- "min-w-[64px] min-h-[24px] max-h-[24px] p-xs",
7524
+ "min-w-[64px] min-h-[32px] max-h-[32px] px-base py-sm",
7312
7525
  "bg-gradient-to-t from-[var(--color-btn-outlined-neutral-bg-default)] from-[10%] to-[var(--color-btn-outlined-neutral-bg-gradient-to-default)]",
7313
7526
  "border border-[var(--color-btn-outlined-neutral-border-default)] rounded-base shadow-sm",
7314
7527
  "cursor-pointer transition-colors text-xs font-semibold leading-xs text-[var(--color-foreground)]",
@@ -7316,22 +7529,18 @@ var AdvancedRow = ({
7316
7529
  ),
7317
7530
  children: [
7318
7531
  connector,
7319
- /* @__PURE__ */ jsx54(Icon32, { icon: faRefreshOutline, size: "xs", className: "text-[var(--color-foreground)]" })
7532
+ /* @__PURE__ */ jsx55(Icon33, { icon: faRefreshOutline, size: "xs", className: "text-[var(--color-foreground)]" })
7320
7533
  ]
7321
7534
  }
7322
7535
  ),
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)]" })
7536
+ /* @__PURE__ */ jsxs49(PopoverPrimitive11.Root, { open: propertyOpen, onOpenChange: setPropertyOpen, children: [
7537
+ /* @__PURE__ */ jsx55(PopoverPrimitive11.Trigger, { asChild: true, children: /* @__PURE__ */ jsxs49("button", { type: "button", className: cn(selectBtnStyle, "min-w-0"), children: [
7538
+ /* @__PURE__ */ jsx55(Icon33, { icon: propertyDef.icon, size: "sm", className: "shrink-0 text-[var(--color-muted-foreground)]" }),
7539
+ /* @__PURE__ */ jsx55("span", { className: "text-sm font-regular leading-sm text-[var(--color-foreground)] whitespace-nowrap truncate", children: propertyDef.label }),
7540
+ /* @__PURE__ */ jsx55(Icon33, { icon: faChevronDownOutline2, size: "xs", className: "shrink-0 text-[var(--color-foreground)]" })
7332
7541
  ] }) }),
7333
- /* @__PURE__ */ jsx54(PopoverPrimitive10.Portal, { children: /* @__PURE__ */ jsx54(
7334
- PopoverPrimitive10.Content,
7542
+ /* @__PURE__ */ jsx55(PopoverPrimitive11.Portal, { children: /* @__PURE__ */ jsx55(
7543
+ PopoverPrimitive11.Content,
7335
7544
  {
7336
7545
  sideOffset: 4,
7337
7546
  align: "start",
@@ -7342,7 +7551,7 @@ var AdvancedRow = ({
7342
7551
  "data-[state=closed]:animate-out data-[state=closed]:fade-out-0",
7343
7552
  "min-w-[200px]"
7344
7553
  ),
7345
- children: properties.map((p) => /* @__PURE__ */ jsxs48(
7554
+ children: properties.map((p) => /* @__PURE__ */ jsxs49(
7346
7555
  "button",
7347
7556
  {
7348
7557
  type: "button",
@@ -7356,8 +7565,8 @@ var AdvancedRow = ({
7356
7565
  p.id === condition.propertyId && "bg-[var(--color-dropdown-item-hover)]"
7357
7566
  ),
7358
7567
  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 })
7568
+ /* @__PURE__ */ jsx55(Icon33, { icon: p.icon, size: "sm", className: "shrink-0 text-[var(--color-dropdown-item-icon)]" }),
7569
+ /* @__PURE__ */ jsx55("span", { className: "text-sm font-regular leading-sm text-[var(--color-dropdown-item-text)] truncate", children: p.label })
7361
7570
  ]
7362
7571
  },
7363
7572
  p.id
@@ -7365,13 +7574,13 @@ var AdvancedRow = ({
7365
7574
  }
7366
7575
  ) })
7367
7576
  ] }),
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)]" })
7577
+ /* @__PURE__ */ jsxs49(PopoverPrimitive11.Root, { open: operatorOpen, onOpenChange: setOperatorOpen, children: [
7578
+ /* @__PURE__ */ jsx55(PopoverPrimitive11.Trigger, { asChild: true, children: /* @__PURE__ */ jsxs49("button", { type: "button", className: cn(selectBtnStyle, "min-w-0"), children: [
7579
+ /* @__PURE__ */ jsx55("span", { className: "text-sm font-regular leading-sm text-[var(--color-foreground)] whitespace-nowrap truncate text-left", children: condition.operator ?? "Select" }),
7580
+ /* @__PURE__ */ jsx55(Icon33, { icon: faChevronDownOutline2, size: "xs", className: "shrink-0 text-[var(--color-foreground)]" })
7372
7581
  ] }) }),
7373
- /* @__PURE__ */ jsx54(PopoverPrimitive10.Portal, { children: /* @__PURE__ */ jsx54(
7374
- PopoverPrimitive10.Content,
7582
+ /* @__PURE__ */ jsx55(PopoverPrimitive11.Portal, { children: /* @__PURE__ */ jsx55(
7583
+ PopoverPrimitive11.Content,
7375
7584
  {
7376
7585
  sideOffset: 4,
7377
7586
  align: "start",
@@ -7382,7 +7591,7 @@ var AdvancedRow = ({
7382
7591
  "data-[state=closed]:animate-out data-[state=closed]:fade-out-0",
7383
7592
  "min-w-[160px]"
7384
7593
  ),
7385
- children: /* @__PURE__ */ jsx54(
7594
+ children: /* @__PURE__ */ jsx55(
7386
7595
  OperatorList,
7387
7596
  {
7388
7597
  dataType: propertyDef.type,
@@ -7393,45 +7602,167 @@ var AdvancedRow = ({
7393
7602
  }
7394
7603
  ) })
7395
7604
  ] }),
7396
- condition.operator && !isNoValueOperator(condition.operator) && /* @__PURE__ */ jsx54(
7397
- "input",
7605
+ condition.operator && !isNoValueOperator(condition.operator) && (() => {
7606
+ const inputType = getValueInputType(propertyDef.type, condition.operator);
7607
+ const dateWide = inputType === "DatePicker" || inputType === "DateRange";
7608
+ return /* @__PURE__ */ jsxs49(PopoverPrimitive11.Root, { open: valueOpen, onOpenChange: setValueOpen, children: [
7609
+ /* @__PURE__ */ jsx55(PopoverPrimitive11.Trigger, { asChild: true, children: /* @__PURE__ */ jsxs49(
7610
+ "button",
7611
+ {
7612
+ type: "button",
7613
+ className: cn(selectBtnStyle, "flex-1 min-w-[80px] justify-between"),
7614
+ children: [
7615
+ /* @__PURE__ */ jsx55(
7616
+ "span",
7617
+ {
7618
+ className: cn(
7619
+ "text-sm font-regular leading-sm whitespace-nowrap truncate text-left",
7620
+ hasValue ? "text-[var(--color-foreground)]" : "text-[var(--color-muted-foreground)]"
7621
+ ),
7622
+ children: hasValue ? displayValue : "Enter a value"
7623
+ }
7624
+ ),
7625
+ /* @__PURE__ */ jsxs49("span", { className: "flex items-center gap-xs shrink-0", children: [
7626
+ badgeCount != null && /* @__PURE__ */ jsxs49("span", { className: "text-xs font-semibold leading-xs text-[var(--color-muted-foreground)]", children: [
7627
+ "+",
7628
+ badgeCount - 1
7629
+ ] }),
7630
+ /* @__PURE__ */ jsx55(
7631
+ Icon33,
7632
+ {
7633
+ icon: faChevronDownOutline2,
7634
+ size: "xs",
7635
+ className: "text-[var(--color-foreground)]"
7636
+ }
7637
+ )
7638
+ ] })
7639
+ ]
7640
+ }
7641
+ ) }),
7642
+ /* @__PURE__ */ jsx55(PopoverPrimitive11.Portal, { children: /* @__PURE__ */ jsx55(
7643
+ PopoverPrimitive11.Content,
7644
+ {
7645
+ sideOffset: 4,
7646
+ align: "start",
7647
+ className: cn(
7648
+ "z-50 flex flex-col overflow-clip",
7649
+ "bg-[var(--color-dropdown-bg)] border border-[var(--color-dropdown-border)] rounded-md shadow-lg",
7650
+ "data-[state=open]:animate-in data-[state=open]:fade-in-0 data-[state=open]:zoom-in-95",
7651
+ "data-[state=closed]:animate-out data-[state=closed]:fade-out-0"
7652
+ ),
7653
+ style: { minWidth: dateWide ? "auto" : "240px" },
7654
+ children: /* @__PURE__ */ jsx55(
7655
+ ValueInput,
7656
+ {
7657
+ dataType: propertyDef.type,
7658
+ operator: condition.operator,
7659
+ value: condition.value,
7660
+ onChange: handleValueChange,
7661
+ onSubmit: () => setValueOpen(false),
7662
+ options: propertyDef.options,
7663
+ dynamicOptions: propertyDef.dynamicOptions
7664
+ }
7665
+ )
7666
+ }
7667
+ ) })
7668
+ ] });
7669
+ })(),
7670
+ /* @__PURE__ */ jsx55(
7671
+ FilterNodeActions,
7398
7672
  {
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
- )
7673
+ nodeType: "condition",
7674
+ onDuplicate: onDuplicate ?? (() => {
7675
+ }),
7676
+ onConvert: onTurnIntoGroup ?? (() => {
7677
+ }),
7678
+ onDelete
7410
7679
  }
7411
- ),
7412
- /* @__PURE__ */ jsx54(
7680
+ )
7681
+ ] });
7682
+ };
7683
+ AdvancedRow.displayName = "AdvancedRow";
7684
+
7685
+ // src/components/ui/filter/advanced-group.tsx
7686
+ import * as React49 from "react";
7687
+ import { Icon as Icon34, faRefreshOutline as faRefreshOutline2, faPlusOutline as faPlusOutline2 } from "@l3mpire/icons";
7688
+ import { jsx as jsx56, jsxs as jsxs50 } from "react/jsx-runtime";
7689
+ var AdvancedGroup = ({
7690
+ connector,
7691
+ onConnectorToggle,
7692
+ onDuplicate,
7693
+ onTurnIntoFilter,
7694
+ onDelete,
7695
+ onAddFilter,
7696
+ properties,
7697
+ children
7698
+ }) => {
7699
+ const [addOpen, setAddOpen] = React49.useState(false);
7700
+ return /* @__PURE__ */ jsxs50("div", { className: "flex items-start gap-base w-full min-w-0", children: [
7701
+ connector === "Where" ? /* @__PURE__ */ jsx56("div", { className: "shrink-0 w-[64px] flex items-center justify-end pt-base", children: /* @__PURE__ */ jsx56("span", { className: "text-xs font-semibold leading-xs text-[var(--color-muted-foreground)]", children: "Where" }) }) : /* @__PURE__ */ jsx56("div", { className: "shrink-0 w-[64px] flex items-center justify-end pt-base", children: /* @__PURE__ */ jsxs50(
7413
7702
  "button",
7414
7703
  {
7415
7704
  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)]" })
7705
+ onClick: onConnectorToggle,
7706
+ className: cn(
7707
+ "flex items-center justify-center gap-xs",
7708
+ "min-w-[64px] min-h-[32px] max-h-[32px] px-base py-sm",
7709
+ "bg-gradient-to-t from-[var(--color-btn-outlined-neutral-bg-default)] from-[10%] to-[var(--color-btn-outlined-neutral-bg-gradient-to-default)]",
7710
+ "border border-[var(--color-btn-outlined-neutral-border-default)] rounded-base shadow-sm",
7711
+ "cursor-pointer transition-colors text-xs font-semibold leading-xs text-[var(--color-foreground)]",
7712
+ "hover:from-[var(--color-btn-outlined-neutral-bg-hover)] hover:to-[var(--color-btn-outlined-neutral-bg-gradient-to-hover)]"
7713
+ ),
7714
+ children: [
7715
+ connector,
7716
+ /* @__PURE__ */ jsx56(Icon34, { icon: faRefreshOutline2, size: "xs", className: "text-[var(--color-foreground)]" })
7717
+ ]
7420
7718
  }
7421
- )
7719
+ ) }),
7720
+ /* @__PURE__ */ jsxs50("div", { className: "flex-1 min-w-0 flex flex-col gap-base p-base border border-[var(--color-border)] rounded-md bg-[var(--color-secondary,var(--color-accent))]", children: [
7721
+ children,
7722
+ onAddFilter && properties && /* @__PURE__ */ jsx56(
7723
+ PropertySelector,
7724
+ {
7725
+ properties,
7726
+ onSelect: (prop) => {
7727
+ onAddFilter(prop);
7728
+ setAddOpen(false);
7729
+ },
7730
+ open: addOpen,
7731
+ onOpenChange: setAddOpen,
7732
+ children: /* @__PURE__ */ jsxs50(
7733
+ "button",
7734
+ {
7735
+ type: "button",
7736
+ className: "flex items-center gap-sm px-base py-sm text-sm font-semibold leading-sm text-[var(--color-muted-foreground)] cursor-pointer transition-colors rounded-md hover:bg-[var(--color-accent)] hover:text-[var(--color-foreground)] w-fit",
7737
+ children: [
7738
+ /* @__PURE__ */ jsx56(Icon34, { icon: faPlusOutline2, size: "sm" }),
7739
+ "Add filter"
7740
+ ]
7741
+ }
7742
+ )
7743
+ }
7744
+ )
7745
+ ] }),
7746
+ /* @__PURE__ */ jsx56("div", { className: "shrink-0 pt-base", children: /* @__PURE__ */ jsx56(
7747
+ FilterNodeActions,
7748
+ {
7749
+ nodeType: "group",
7750
+ onDuplicate,
7751
+ onConvert: onTurnIntoFilter,
7752
+ onDelete
7753
+ }
7754
+ ) })
7422
7755
  ] });
7423
7756
  };
7424
- AdvancedRow.displayName = "AdvancedRow";
7757
+ AdvancedGroup.displayName = "AdvancedGroup";
7425
7758
 
7426
7759
  // src/components/ui/filter/advanced-popover.tsx
7427
- import { jsx as jsx55, jsxs as jsxs49 } from "react/jsx-runtime";
7428
- var outlinedBtn = [
7760
+ import { jsx as jsx57, jsxs as jsxs51 } from "react/jsx-runtime";
7761
+ var ghostBtn = [
7429
7762
  "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)]"
7763
+ "min-h-[32px]",
7764
+ "cursor-pointer transition-colors text-sm font-semibold leading-sm",
7765
+ "rounded-md hover:bg-[var(--color-accent)]"
7435
7766
  ];
7436
7767
  var AdvancedPopover = ({
7437
7768
  filters,
@@ -7441,41 +7772,156 @@ var AdvancedPopover = ({
7441
7772
  onOpenChange,
7442
7773
  children
7443
7774
  }) => {
7444
- const [addSelectorOpen, setAddSelectorOpen] = React48.useState(false);
7445
- const [draftPickerOpen, setDraftPickerOpen] = React48.useState(false);
7775
+ const [addSelectorOpen, setAddSelectorOpen] = React50.useState(false);
7776
+ const [draftPickerOpen, setDraftPickerOpen] = React50.useState(false);
7777
+ const [groupSelectorOpen, setGroupSelectorOpen] = React50.useState(false);
7446
7778
  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
7779
  const handleAddFilter = (property) => {
7460
7780
  const newFilter = createFilterWithDefaults(property.id, property.type);
7461
7781
  onFiltersChange([...filters, newFilter]);
7462
7782
  setAddSelectorOpen(false);
7463
7783
  };
7784
+ const handleAddGroup = () => {
7785
+ const group = createEmptyGroup();
7786
+ onFiltersChange([...filters, group]);
7787
+ setGroupSelectorOpen(false);
7788
+ };
7464
7789
  const handleClearAll = () => {
7465
7790
  onFiltersChange([]);
7466
7791
  onOpenChange?.(false);
7467
7792
  };
7468
- const toggleLogicOp = (filterId) => {
7793
+ const handleUpdateNode = (id, updated) => {
7794
+ onFiltersChange(updateNodeInTree(filters, id, () => updated));
7795
+ };
7796
+ const handleDeleteNode = (id) => {
7797
+ onFiltersChange(removeNodeFromTree(filters, id));
7798
+ };
7799
+ const handleDuplicateNode = (id) => {
7800
+ const find = (nodes) => {
7801
+ for (const n of nodes) {
7802
+ if (n.id === id) return n;
7803
+ if (isFilterGroup(n)) {
7804
+ const found = find(n.children);
7805
+ if (found) return found;
7806
+ }
7807
+ }
7808
+ };
7809
+ const node = find(filters);
7810
+ if (!node) return;
7811
+ const clone = duplicateNode(node);
7812
+ clone.logicOperator = node.logicOperator ?? "and";
7813
+ onFiltersChange(insertAfterInTree(filters, id, clone));
7814
+ };
7815
+ const handleWrapInGroup = (id) => {
7816
+ const find = (nodes) => {
7817
+ for (const n of nodes) {
7818
+ if (n.id === id && !isFilterGroup(n)) return n;
7819
+ if (isFilterGroup(n)) {
7820
+ const found = find(n.children);
7821
+ if (found) return found;
7822
+ }
7823
+ }
7824
+ };
7825
+ const condition = find(filters);
7826
+ if (!condition) return;
7827
+ const group = wrapInGroup(condition);
7828
+ onFiltersChange(replaceNodeInTree(filters, id, group));
7829
+ };
7830
+ const handleUnwrapGroup = (id) => {
7831
+ const find = (nodes) => {
7832
+ for (const n of nodes) {
7833
+ if (n.id === id && isFilterGroup(n)) return n;
7834
+ if (isFilterGroup(n)) {
7835
+ const found = find(n.children);
7836
+ if (found) return found;
7837
+ }
7838
+ }
7839
+ };
7840
+ const group = find(filters);
7841
+ if (!group) return;
7842
+ const replacement = unwrapGroup(group);
7843
+ if (replacement) {
7844
+ onFiltersChange(replaceNodeInTree(filters, id, replacement));
7845
+ } else {
7846
+ onFiltersChange(removeNodeFromTree(filters, id));
7847
+ }
7848
+ };
7849
+ const toggleLogicOp = (id) => {
7850
+ onFiltersChange(
7851
+ updateNodeInTree(filters, id, (n) => ({
7852
+ ...n,
7853
+ logicOperator: (n.logicOperator ?? "and") === "and" ? "or" : "and"
7854
+ }))
7855
+ );
7856
+ };
7857
+ const handleGroupChildrenChange = (groupId, children2) => {
7469
7858
  onFiltersChange(
7470
- filters.map(
7471
- (f) => f.id === filterId ? { ...f, logicOperator: (f.logicOperator ?? "and") === "and" ? "or" : "and" } : f
7859
+ updateNodeInTree(
7860
+ filters,
7861
+ groupId,
7862
+ (n) => isFilterGroup(n) ? { ...n, children: children2 } : n
7472
7863
  )
7473
7864
  );
7474
7865
  };
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,
7866
+ const renderNode = (node, index) => {
7867
+ const connector = index === 0 ? "Where" : (node.logicOperator ?? "and") === "and" ? "And" : "Or";
7868
+ if (isFilterGroup(node)) {
7869
+ return /* @__PURE__ */ jsx57(
7870
+ AdvancedGroup,
7871
+ {
7872
+ connector,
7873
+ onConnectorToggle: index > 0 ? () => toggleLogicOp(node.id) : void 0,
7874
+ onDuplicate: () => handleDuplicateNode(node.id),
7875
+ onTurnIntoFilter: () => handleUnwrapGroup(node.id),
7876
+ onDelete: () => handleDeleteNode(node.id),
7877
+ properties,
7878
+ onAddFilter: (prop) => {
7879
+ const newFilter = createFilterWithDefaults(prop.id, prop.type);
7880
+ handleGroupChildrenChange(node.id, [...node.children, newFilter]);
7881
+ },
7882
+ children: node.children.length === 0 ? (
7883
+ /* Draft row in empty group */
7884
+ /* @__PURE__ */ jsx57(
7885
+ DraftRow,
7886
+ {
7887
+ properties,
7888
+ onSelect: (prop) => {
7889
+ const newFilter = createFilterWithDefaults(prop.id, prop.type);
7890
+ handleGroupChildrenChange(node.id, [newFilter]);
7891
+ }
7892
+ }
7893
+ )
7894
+ ) : node.children.map((child, i) => renderNode(child, i))
7895
+ },
7896
+ node.id
7897
+ );
7898
+ }
7899
+ const propDef = getPropertyDef(node.propertyId);
7900
+ if (!propDef) return null;
7901
+ return /* @__PURE__ */ jsx57(
7902
+ AdvancedRow,
7903
+ {
7904
+ connector,
7905
+ onConnectorToggle: index > 0 ? () => toggleLogicOp(node.id) : void 0,
7906
+ propertyDef: propDef,
7907
+ condition: node,
7908
+ properties,
7909
+ onUpdate: (updated) => handleUpdateNode(node.id, updated),
7910
+ onPropertyChange: (p) => {
7911
+ const newCondition = createFilterWithDefaults(p.id, p.type);
7912
+ handleUpdateNode(node.id, { ...newCondition, id: node.id });
7913
+ },
7914
+ onDelete: () => handleDeleteNode(node.id),
7915
+ onDuplicate: () => handleDuplicateNode(node.id),
7916
+ onTurnIntoGroup: () => handleWrapInGroup(node.id)
7917
+ },
7918
+ node.id
7919
+ );
7920
+ };
7921
+ return /* @__PURE__ */ jsxs51(PopoverPrimitive12.Root, { open, onOpenChange, children: [
7922
+ /* @__PURE__ */ jsx57(PopoverPrimitive12.Trigger, { asChild: true, children }),
7923
+ /* @__PURE__ */ jsx57(PopoverPrimitive12.Portal, { children: /* @__PURE__ */ jsxs51(
7924
+ PopoverPrimitive12.Content,
7479
7925
  {
7480
7926
  sideOffset: 4,
7481
7927
  align: "start",
@@ -7487,87 +7933,56 @@ var AdvancedPopover = ({
7487
7933
  "data-[state=open]:animate-in data-[state=open]:fade-in-0 data-[state=open]:zoom-in-95",
7488
7934
  "data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=closed]:zoom-out-95",
7489
7935
  "data-[side=bottom]:slide-in-from-top-2",
7490
- "w-[min(520px,calc(100vw-32px))]"
7936
+ "w-[min(640px,calc(100vw-32px))]"
7491
7937
  ),
7492
7938
  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(
7939
+ /* @__PURE__ */ jsx57("div", { className: "flex flex-col gap-base p-base", children: filters.length > 0 ? filters.map((node, i) => renderNode(node, i)) : /* @__PURE__ */ jsx57(
7940
+ DraftRow,
7941
+ {
7942
+ properties,
7943
+ onSelect: handleAddFilter,
7944
+ open: draftPickerOpen,
7945
+ onOpenChange: setDraftPickerOpen
7946
+ }
7947
+ ) }),
7948
+ /* @__PURE__ */ jsxs51("div", { className: "flex items-center justify-between p-base border-t border-[var(--color-border)]", children: [
7949
+ /* @__PURE__ */ jsxs51("div", { className: "flex items-center gap-sm", children: [
7950
+ /* @__PURE__ */ jsx57(
7516
7951
  PropertySelector,
7517
7952
  {
7518
7953
  properties,
7519
7954
  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
- )
7955
+ open: addSelectorOpen,
7956
+ onOpenChange: setAddSelectorOpen,
7957
+ children: /* @__PURE__ */ jsxs51("button", { type: "button", className: cn(ghostBtn, "text-[var(--color-foreground)]"), children: [
7958
+ /* @__PURE__ */ jsx57(Icon35, { icon: faPlusOutline3, size: "sm", className: "text-[var(--color-foreground)]" }),
7959
+ "Add filter"
7960
+ ] })
7961
+ }
7962
+ ),
7963
+ /* @__PURE__ */ jsxs51(
7964
+ "button",
7965
+ {
7966
+ type: "button",
7967
+ onClick: handleAddGroup,
7968
+ className: cn(ghostBtn, "text-[var(--color-foreground)]"),
7969
+ children: [
7970
+ /* @__PURE__ */ jsx57(Icon35, { icon: faPlusOutline3, size: "sm", className: "text-[var(--color-foreground)]" }),
7971
+ "Add filters group"
7972
+ ]
7546
7973
  }
7547
7974
  )
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(
7975
+ ] }),
7976
+ filters.length > 0 && /* @__PURE__ */ jsxs51(
7565
7977
  "button",
7566
7978
  {
7567
7979
  type: "button",
7568
7980
  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"
7981
+ className: cn(ghostBtn, "text-[var(--color-destructive,#ef4444)]"),
7982
+ children: [
7983
+ /* @__PURE__ */ jsx57(Icon35, { icon: faXmarkOutline3, size: "sm", className: "text-[var(--color-destructive,#ef4444)]" }),
7984
+ "Clear filters"
7985
+ ]
7571
7986
  }
7572
7987
  )
7573
7988
  ] })
@@ -7577,12 +7992,71 @@ var AdvancedPopover = ({
7577
7992
  ] });
7578
7993
  };
7579
7994
  AdvancedPopover.displayName = "AdvancedPopover";
7995
+ var DraftRow = ({
7996
+ properties,
7997
+ onSelect,
7998
+ open: openProp,
7999
+ onOpenChange
8000
+ }) => {
8001
+ const [internalOpen, setInternalOpen] = React50.useState(false);
8002
+ const isControlled = openProp !== void 0;
8003
+ const open = isControlled ? openProp : internalOpen;
8004
+ const setOpen = (v) => {
8005
+ if (!isControlled) setInternalOpen(v);
8006
+ onOpenChange?.(v);
8007
+ };
8008
+ return /* @__PURE__ */ jsxs51("div", { className: "flex items-center gap-base w-full min-w-0", children: [
8009
+ /* @__PURE__ */ jsx57("div", { className: "shrink-0 w-[64px] flex items-center justify-end", children: /* @__PURE__ */ jsx57("span", { className: "text-xs font-semibold leading-xs text-[var(--color-muted-foreground)]", children: "Where" }) }),
8010
+ /* @__PURE__ */ jsx57(
8011
+ PropertySelector,
8012
+ {
8013
+ properties,
8014
+ onSelect: (prop) => {
8015
+ onSelect(prop);
8016
+ setOpen(false);
8017
+ },
8018
+ open,
8019
+ onOpenChange: setOpen,
8020
+ children: /* @__PURE__ */ jsxs51(
8021
+ "button",
8022
+ {
8023
+ type: "button",
8024
+ className: cn(
8025
+ "flex items-center gap-base px-base py-sm min-w-0",
8026
+ "bg-gradient-to-t from-[var(--color-btn-outlined-neutral-bg-default)] to-[var(--color-btn-outlined-neutral-bg-gradient-to-default)]",
8027
+ "border border-[var(--color-btn-outlined-neutral-border-default)] rounded-md shadow-sm",
8028
+ "cursor-pointer transition-colors",
8029
+ "hover:from-[var(--color-btn-outlined-neutral-bg-hover)] hover:to-[var(--color-btn-outlined-neutral-bg-gradient-to-hover)]"
8030
+ ),
8031
+ children: [
8032
+ /* @__PURE__ */ jsx57("span", { className: "text-sm font-regular leading-sm text-[var(--color-muted-foreground)] whitespace-nowrap", children: "Select property" }),
8033
+ /* @__PURE__ */ jsx57(
8034
+ Icon35,
8035
+ {
8036
+ icon: faChevronDownOutline3,
8037
+ size: "xs",
8038
+ className: "shrink-0 text-[var(--color-foreground)]"
8039
+ }
8040
+ )
8041
+ ]
8042
+ }
8043
+ )
8044
+ }
8045
+ )
8046
+ ] });
8047
+ };
7580
8048
 
7581
8049
  // 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";
8050
+ import * as React51 from "react";
8051
+ import * as PopoverPrimitive13 from "@radix-ui/react-popover";
8052
+ import { Icon as Icon36, faSlidersOutline as faSlidersOutline2, faPlusOutline as faPlusOutline4, faChevronDownOutline as faChevronDownOutline4, faXmarkOutline as faXmarkOutline4 } from "@l3mpire/icons";
8053
+ import { jsx as jsx58, jsxs as jsxs52 } from "react/jsx-runtime";
8054
+ var ghostBtn2 = [
8055
+ "flex items-center gap-sm px-base py-sm",
8056
+ "min-h-[32px]",
8057
+ "cursor-pointer transition-colors text-sm font-semibold leading-sm",
8058
+ "rounded-md hover:bg-[var(--color-accent)]"
8059
+ ];
7586
8060
  var SummaryChip = ({
7587
8061
  count,
7588
8062
  filters,
@@ -7594,44 +8068,152 @@ var SummaryChip = ({
7594
8068
  open: openProp,
7595
8069
  onOpenChange
7596
8070
  }) => {
7597
- const [uncontrolledOpen, setUncontrolledOpen] = React49.useState(false);
8071
+ const [uncontrolledOpen, setUncontrolledOpen] = React51.useState(false);
7598
8072
  const isControlled = openProp !== void 0;
7599
8073
  const open = isControlled ? openProp : uncontrolledOpen;
7600
8074
  const setOpen = (v) => {
7601
8075
  if (!isControlled) setUncontrolledOpen(v);
7602
8076
  onOpenChange?.(v);
7603
8077
  };
7604
- const [addSelectorOpen, setAddSelectorOpen] = React49.useState(false);
7605
- const [draftPickerOpen, setDraftPickerOpen] = React49.useState(false);
8078
+ const [addSelectorOpen, setAddSelectorOpen] = React51.useState(false);
8079
+ const [draftPickerOpen, setDraftPickerOpen] = React51.useState(false);
7606
8080
  const getPropertyDef = (propertyId) => properties.find((p) => p.id === propertyId);
7607
- const handleUpdateFilter = (updated) => {
7608
- onFiltersChange(filters.map((f) => f.id === updated.id ? updated : f));
8081
+ const handleAddFilter = (property) => {
8082
+ const newFilter = createFilterWithDefaults(property.id, property.type);
8083
+ onFiltersChange([...filters, newFilter]);
8084
+ setAddSelectorOpen(false);
7609
8085
  };
7610
- const handleDeleteFilter = (id) => {
7611
- const next = filters.filter((f) => f.id !== id);
8086
+ const handleAddGroup = () => {
8087
+ onFiltersChange([...filters, createEmptyGroup()]);
8088
+ };
8089
+ const handleUpdateNode = (id, updated) => {
8090
+ onFiltersChange(updateNodeInTree(filters, id, () => updated));
8091
+ };
8092
+ const handleDeleteNode = (id) => {
8093
+ const next = removeNodeFromTree(filters, id);
7612
8094
  onFiltersChange(next);
7613
8095
  if (next.length === 0) setOpen(false);
7614
8096
  };
7615
- const handlePropertyChange = (filterId, newProp) => {
7616
- const newCondition = createFilterWithDefaults(newProp.id, newProp.type);
8097
+ const handleDuplicateNode = (id) => {
8098
+ const find = (nodes) => {
8099
+ for (const n of nodes) {
8100
+ if (n.id === id) return n;
8101
+ if (isFilterGroup(n)) {
8102
+ const f = find(n.children);
8103
+ if (f) return f;
8104
+ }
8105
+ }
8106
+ };
8107
+ const node = find(filters);
8108
+ if (!node) return;
8109
+ const clone = duplicateNode(node);
8110
+ clone.logicOperator = node.logicOperator ?? "and";
8111
+ onFiltersChange(insertAfterInTree(filters, id, clone));
8112
+ };
8113
+ const handleWrapInGroup = (id) => {
8114
+ const find = (nodes) => {
8115
+ for (const n of nodes) {
8116
+ if (n.id === id && !isFilterGroup(n)) return n;
8117
+ if (isFilterGroup(n)) {
8118
+ const f = find(n.children);
8119
+ if (f) return f;
8120
+ }
8121
+ }
8122
+ };
8123
+ const condition = find(filters);
8124
+ if (!condition) return;
8125
+ onFiltersChange(replaceNodeInTree(filters, id, wrapInGroup(condition)));
8126
+ };
8127
+ const handleUnwrapGroup = (id) => {
8128
+ const find = (nodes) => {
8129
+ for (const n of nodes) {
8130
+ if (n.id === id && isFilterGroup(n)) return n;
8131
+ if (isFilterGroup(n)) {
8132
+ const f = find(n.children);
8133
+ if (f) return f;
8134
+ }
8135
+ }
8136
+ };
8137
+ const group = find(filters);
8138
+ if (!group) return;
8139
+ const replacement = unwrapGroup(group);
8140
+ if (replacement) {
8141
+ onFiltersChange(replaceNodeInTree(filters, id, replacement));
8142
+ } else {
8143
+ onFiltersChange(removeNodeFromTree(filters, id));
8144
+ }
8145
+ };
8146
+ const toggleLogicOp = (id) => {
7617
8147
  onFiltersChange(
7618
- filters.map((f) => f.id === filterId ? { ...newCondition, id: filterId } : f)
8148
+ updateNodeInTree(filters, id, (n) => ({
8149
+ ...n,
8150
+ logicOperator: (n.logicOperator ?? "and") === "and" ? "or" : "and"
8151
+ }))
7619
8152
  );
7620
8153
  };
7621
- const handleAddFilter = (property) => {
7622
- const newFilter = createFilterWithDefaults(property.id, property.type);
7623
- onFiltersChange([...filters, newFilter]);
7624
- setAddSelectorOpen(false);
7625
- };
7626
- const toggleLogicOp = (filterId) => {
8154
+ const handleGroupChildrenChange = (groupId, newChildren) => {
7627
8155
  onFiltersChange(
7628
- filters.map(
7629
- (f) => f.id === filterId ? { ...f, logicOperator: (f.logicOperator ?? "and") === "and" ? "or" : "and" } : f
8156
+ updateNodeInTree(
8157
+ filters,
8158
+ groupId,
8159
+ (n) => isFilterGroup(n) ? { ...n, children: newChildren } : n
7630
8160
  )
7631
8161
  );
7632
8162
  };
7633
- return /* @__PURE__ */ jsxs50(PopoverPrimitive12.Root, { open, onOpenChange: setOpen, children: [
7634
- /* @__PURE__ */ jsx56(PopoverPrimitive12.Trigger, { asChild: true, children: children ?? /* @__PURE__ */ jsxs50(
8163
+ const renderNode = (node, index) => {
8164
+ const connector = index === 0 ? "Where" : (node.logicOperator ?? "and") === "and" ? "And" : "Or";
8165
+ if (isFilterGroup(node)) {
8166
+ return /* @__PURE__ */ jsx58(
8167
+ AdvancedGroup,
8168
+ {
8169
+ connector,
8170
+ onConnectorToggle: index > 0 ? () => toggleLogicOp(node.id) : void 0,
8171
+ onDuplicate: () => handleDuplicateNode(node.id),
8172
+ onTurnIntoFilter: () => handleUnwrapGroup(node.id),
8173
+ onDelete: () => handleDeleteNode(node.id),
8174
+ properties,
8175
+ onAddFilter: (prop) => {
8176
+ const newFilter = createFilterWithDefaults(prop.id, prop.type);
8177
+ handleGroupChildrenChange(node.id, [...node.children, newFilter]);
8178
+ },
8179
+ children: node.children.length === 0 ? /* @__PURE__ */ jsx58(
8180
+ DraftRow2,
8181
+ {
8182
+ properties,
8183
+ onSelect: (prop) => {
8184
+ const newFilter = createFilterWithDefaults(prop.id, prop.type);
8185
+ handleGroupChildrenChange(node.id, [newFilter]);
8186
+ }
8187
+ }
8188
+ ) : node.children.map((child, i) => renderNode(child, i))
8189
+ },
8190
+ node.id
8191
+ );
8192
+ }
8193
+ const propDef = getPropertyDef(node.propertyId);
8194
+ if (!propDef) return null;
8195
+ return /* @__PURE__ */ jsx58(
8196
+ AdvancedRow,
8197
+ {
8198
+ connector,
8199
+ onConnectorToggle: index > 0 ? () => toggleLogicOp(node.id) : void 0,
8200
+ propertyDef: propDef,
8201
+ condition: node,
8202
+ properties,
8203
+ onUpdate: (updated) => handleUpdateNode(node.id, updated),
8204
+ onPropertyChange: (p) => {
8205
+ const newCondition = createFilterWithDefaults(p.id, p.type);
8206
+ handleUpdateNode(node.id, { ...newCondition, id: node.id });
8207
+ },
8208
+ onDelete: () => handleDeleteNode(node.id),
8209
+ onDuplicate: () => handleDuplicateNode(node.id),
8210
+ onTurnIntoGroup: () => handleWrapInGroup(node.id)
8211
+ },
8212
+ node.id
8213
+ );
8214
+ };
8215
+ return /* @__PURE__ */ jsxs52(PopoverPrimitive13.Root, { open, onOpenChange: setOpen, children: [
8216
+ /* @__PURE__ */ jsx58(PopoverPrimitive13.Trigger, { asChild: true, children: children ?? /* @__PURE__ */ jsxs52(
7635
8217
  "button",
7636
8218
  {
7637
8219
  type: "button",
@@ -7645,21 +8227,14 @@ var SummaryChip = ({
7645
8227
  className
7646
8228
  ),
7647
8229
  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 }) })
8230
+ /* @__PURE__ */ jsx58(Icon36, { icon: faSlidersOutline2, size: "sm", className: "shrink-0 text-[var(--color-foreground)]" }),
8231
+ /* @__PURE__ */ jsx58("span", { className: "text-sm font-semibold leading-sm whitespace-nowrap text-[var(--color-foreground)]", children: "Filters" }),
8232
+ count > 0 && /* @__PURE__ */ jsx58("span", { className: "flex items-center p-2xs rounded-xs bg-filter-chip-badge-bg", children: /* @__PURE__ */ jsx58("span", { className: "text-[10px] font-semibold leading-2xs text-filter-chip-badge-text", children: count }) })
7658
8233
  ]
7659
8234
  }
7660
8235
  ) }),
7661
- /* @__PURE__ */ jsx56(PopoverPrimitive12.Portal, { children: /* @__PURE__ */ jsxs50(
7662
- PopoverPrimitive12.Content,
8236
+ /* @__PURE__ */ jsx58(PopoverPrimitive13.Portal, { children: /* @__PURE__ */ jsxs52(
8237
+ PopoverPrimitive13.Content,
7663
8238
  {
7664
8239
  sideOffset: 4,
7665
8240
  align: "start",
@@ -7671,95 +8246,39 @@ var SummaryChip = ({
7671
8246
  "data-[state=open]:animate-in data-[state=open]:fade-in-0 data-[state=open]:zoom-in-95",
7672
8247
  "data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=closed]:zoom-out-95",
7673
8248
  "data-[side=bottom]:slide-in-from-top-2",
7674
- "w-[min(520px,calc(100vw-32px))]"
8249
+ "w-[min(640px,calc(100vw-32px))]"
7675
8250
  ),
7676
8251
  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(
8252
+ /* @__PURE__ */ jsx58("div", { className: "flex flex-col gap-base p-base", children: filters.length > 0 ? filters.map((node, i) => renderNode(node, i)) : /* @__PURE__ */ jsx58(
8253
+ DraftRow2,
8254
+ {
8255
+ properties,
8256
+ onSelect: handleAddFilter,
8257
+ open: draftPickerOpen,
8258
+ onOpenChange: setDraftPickerOpen
8259
+ }
8260
+ ) }),
8261
+ /* @__PURE__ */ jsxs52("div", { className: "flex items-center justify-between p-base border-t border-[var(--color-border)]", children: [
8262
+ /* @__PURE__ */ jsxs52("div", { className: "flex items-center gap-sm", children: [
8263
+ /* @__PURE__ */ jsx58(
7700
8264
  PropertySelector,
7701
8265
  {
7702
8266
  properties,
7703
8267
  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
- )
8268
+ open: addSelectorOpen,
8269
+ onOpenChange: setAddSelectorOpen,
8270
+ children: /* @__PURE__ */ jsxs52("button", { type: "button", className: cn(ghostBtn2, "text-[var(--color-foreground)]"), children: [
8271
+ /* @__PURE__ */ jsx58(Icon36, { icon: faPlusOutline4, size: "sm", className: "text-[var(--color-foreground)]" }),
8272
+ "Add filter"
8273
+ ] })
7730
8274
  }
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(
8275
+ ),
8276
+ /* @__PURE__ */ jsxs52("button", { type: "button", onClick: handleAddGroup, className: cn(ghostBtn2, "text-[var(--color-foreground)]"), children: [
8277
+ /* @__PURE__ */ jsx58(Icon36, { icon: faPlusOutline4, size: "sm", className: "text-[var(--color-foreground)]" }),
8278
+ "Add filters group"
8279
+ ] })
8280
+ ] }),
8281
+ filters.length > 0 && /* @__PURE__ */ jsxs52(
7763
8282
  "button",
7764
8283
  {
7765
8284
  type: "button",
@@ -7767,8 +8286,11 @@ var SummaryChip = ({
7767
8286
  onClearAll();
7768
8287
  setOpen(false);
7769
8288
  },
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"
8289
+ className: cn(ghostBtn2, "text-[var(--color-destructive,#ef4444)]"),
8290
+ children: [
8291
+ /* @__PURE__ */ jsx58(Icon36, { icon: faXmarkOutline4, size: "sm", className: "text-[var(--color-destructive,#ef4444)]" }),
8292
+ "Clear filters"
8293
+ ]
7772
8294
  }
7773
8295
  )
7774
8296
  ] })
@@ -7778,13 +8300,44 @@ var SummaryChip = ({
7778
8300
  ] });
7779
8301
  };
7780
8302
  SummaryChip.displayName = "SummaryChip";
8303
+ var DraftRow2 = ({ properties, onSelect, open: openProp, onOpenChange }) => {
8304
+ const [internalOpen, setInternalOpen] = React51.useState(false);
8305
+ const isCtrl = openProp !== void 0;
8306
+ const open = isCtrl ? openProp : internalOpen;
8307
+ const setOpen = (v) => {
8308
+ if (!isCtrl) setInternalOpen(v);
8309
+ onOpenChange?.(v);
8310
+ };
8311
+ return /* @__PURE__ */ jsxs52("div", { className: "flex items-center gap-base w-full min-w-0", children: [
8312
+ /* @__PURE__ */ jsx58("div", { className: "shrink-0 w-[64px] flex items-center justify-end", children: /* @__PURE__ */ jsx58("span", { className: "text-xs font-semibold leading-xs text-[var(--color-muted-foreground)]", children: "Where" }) }),
8313
+ /* @__PURE__ */ jsx58(PropertySelector, { properties, onSelect: (p) => {
8314
+ onSelect(p);
8315
+ setOpen(false);
8316
+ }, open, onOpenChange: setOpen, children: /* @__PURE__ */ jsxs52(
8317
+ "button",
8318
+ {
8319
+ type: "button",
8320
+ className: cn(
8321
+ "flex items-center gap-base px-base py-sm min-w-0",
8322
+ "bg-gradient-to-t from-[var(--color-btn-outlined-neutral-bg-default)] to-[var(--color-btn-outlined-neutral-bg-gradient-to-default)]",
8323
+ "border border-[var(--color-btn-outlined-neutral-border-default)] rounded-md shadow-sm cursor-pointer transition-colors",
8324
+ "hover:from-[var(--color-btn-outlined-neutral-bg-hover)] hover:to-[var(--color-btn-outlined-neutral-bg-gradient-to-hover)]"
8325
+ ),
8326
+ children: [
8327
+ /* @__PURE__ */ jsx58("span", { className: "text-sm font-regular leading-sm text-[var(--color-muted-foreground)] whitespace-nowrap", children: "Select property" }),
8328
+ /* @__PURE__ */ jsx58(Icon36, { icon: faChevronDownOutline4, size: "xs", className: "shrink-0 text-[var(--color-foreground)]" })
8329
+ ]
8330
+ }
8331
+ ) })
8332
+ ] });
8333
+ };
7781
8334
 
7782
8335
  // src/components/ui/filter/use-filter-bar-mode.ts
7783
- import * as React50 from "react";
8336
+ import * as React52 from "react";
7784
8337
  var DEFAULT_BREAKPOINT = 600;
7785
8338
  function useFilterBarMode(ref, override, breakpoint = DEFAULT_BREAKPOINT) {
7786
- const [mode, setMode] = React50.useState("default");
7787
- React50.useEffect(() => {
8339
+ const [mode, setMode] = React52.useState("default");
8340
+ React52.useEffect(() => {
7788
8341
  if (override) return;
7789
8342
  const el = ref.current;
7790
8343
  if (!el) return;
@@ -7799,7 +8352,7 @@ function useFilterBarMode(ref, override, breakpoint = DEFAULT_BREAKPOINT) {
7799
8352
  }
7800
8353
 
7801
8354
  // src/components/ui/filter/filter-system.tsx
7802
- import { Fragment as Fragment5, jsx as jsx57, jsxs as jsxs51 } from "react/jsx-runtime";
8355
+ import { Fragment as Fragment5, jsx as jsx59, jsxs as jsxs53 } from "react/jsx-runtime";
7803
8356
  var FilterSystem = ({
7804
8357
  properties,
7805
8358
  filterState,
@@ -7811,14 +8364,13 @@ var FilterSystem = ({
7811
8364
  actions,
7812
8365
  className
7813
8366
  }) => {
7814
- const containerRef = React51.useRef(null);
8367
+ const containerRef = React53.useRef(null);
7815
8368
  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;
8369
+ const [propertySelectorOpen, setPropertySelectorOpen] = React53.useState(false);
8370
+ const [advancedOpen, setAdvancedOpen] = React53.useState(false);
8371
+ const [summaryOpen, setSummaryOpen] = React53.useState(false);
8372
+ const [pendingFilterId, setPendingFilterId] = React53.useState(null);
8373
+ const totalCount = filterState.basicFilters.length + countConditions(filterState.advancedFilters);
7822
8374
  const handleAddFilter = (property) => {
7823
8375
  const newFilter = createFilterWithDefaults(property.id, property.type);
7824
8376
  if (newFilter.operator && isNoValueOperator(newFilter.operator)) {
@@ -7904,10 +8456,10 @@ var FilterSystem = ({
7904
8456
  const advancedFilterCount = filterState.advancedFilters.length;
7905
8457
  const showAdvancedChip = hasAdvanced || advancedOpen;
7906
8458
  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: [
8459
+ return /* @__PURE__ */ jsxs53(FilterBar, { ref: containerRef, className, children: [
8460
+ /* @__PURE__ */ jsxs53(FilterBarLeft, { className: "flex-nowrap flex-1 min-w-0 overflow-x-auto scrollbar-none outline-none [&>*]:shrink-0", children: [
7909
8461
  children,
7910
- sortFields && filterState.sort && /* @__PURE__ */ jsx57(
8462
+ sortFields && filterState.sort && /* @__PURE__ */ jsx59(
7911
8463
  SortButton,
7912
8464
  {
7913
8465
  fields: sortFields,
@@ -7917,23 +8469,23 @@ var FilterSystem = ({
7917
8469
  iconOnly: isMinimal
7918
8470
  }
7919
8471
  ),
7920
- isMinimal ? /* @__PURE__ */ jsxs51(Fragment5, { children: [
7921
- /* @__PURE__ */ jsx57(
8472
+ isMinimal ? /* @__PURE__ */ jsxs53(Fragment5, { children: [
8473
+ /* @__PURE__ */ jsx59(
7922
8474
  "div",
7923
8475
  {
7924
8476
  className: showSummaryChip ? "inline-flex" : "inline-flex w-0 overflow-hidden opacity-0 pointer-events-none",
7925
8477
  "aria-hidden": !showSummaryChip || void 0,
7926
- children: /* @__PURE__ */ jsx57(
8478
+ children: /* @__PURE__ */ jsx59(
7927
8479
  SummaryChip,
7928
8480
  {
7929
8481
  count: totalCount,
7930
- filters: allFilters,
8482
+ filters: [...filterState.basicFilters, ...filterState.advancedFilters],
7931
8483
  properties,
7932
- onFiltersChange: (filters) => {
8484
+ onFiltersChange: (nodes) => {
7933
8485
  onFilterStateChange({
7934
8486
  ...filterState,
7935
- basicFilters: filters,
7936
- advancedFilters: []
8487
+ basicFilters: [],
8488
+ advancedFilters: nodes
7937
8489
  });
7938
8490
  },
7939
8491
  onClearAll: handleClearAll,
@@ -7943,7 +8495,7 @@ var FilterSystem = ({
7943
8495
  )
7944
8496
  }
7945
8497
  ),
7946
- !showSummaryChip && /* @__PURE__ */ jsx57(
8498
+ !showSummaryChip && /* @__PURE__ */ jsx59(
7947
8499
  PropertySelector,
7948
8500
  {
7949
8501
  properties,
@@ -7952,13 +8504,13 @@ var FilterSystem = ({
7952
8504
  onOpenChange: setPropertySelectorOpen,
7953
8505
  onAdvancedFilter: handleOpenAdvanced,
7954
8506
  advancedFilterCount,
7955
- children: /* @__PURE__ */ jsx57(FilterBarButton, { iconOnly: true })
8507
+ children: /* @__PURE__ */ jsx59(FilterBarButton, { iconOnly: true })
7956
8508
  }
7957
8509
  )
7958
8510
  ] }) : (
7959
8511
  /* ── DEFAULT MODE ────────────────────────────────────── */
7960
- /* @__PURE__ */ jsxs51(Fragment5, { children: [
7961
- /* @__PURE__ */ jsx57(
8512
+ /* @__PURE__ */ jsxs53(Fragment5, { children: [
8513
+ /* @__PURE__ */ jsx59(
7962
8514
  AdvancedPopover,
7963
8515
  {
7964
8516
  filters: filterState.advancedFilters,
@@ -7966,12 +8518,12 @@ var FilterSystem = ({
7966
8518
  onFiltersChange: handleAdvancedFiltersChange,
7967
8519
  open: advancedOpen,
7968
8520
  onOpenChange: setAdvancedOpen,
7969
- children: /* @__PURE__ */ jsx57(
8521
+ children: /* @__PURE__ */ jsx59(
7970
8522
  "div",
7971
8523
  {
7972
8524
  className: showAdvancedChip ? "inline-flex" : "inline-flex w-0 overflow-hidden opacity-0 pointer-events-none",
7973
8525
  "aria-hidden": !showAdvancedChip || void 0,
7974
- children: /* @__PURE__ */ jsx57(
8526
+ children: /* @__PURE__ */ jsx59(
7975
8527
  AdvancedChip,
7976
8528
  {
7977
8529
  count: filterState.advancedFilters.length,
@@ -7986,7 +8538,7 @@ var FilterSystem = ({
7986
8538
  filterState.basicFilters.map((filter) => {
7987
8539
  const propDef = getPropertyDef(filter.propertyId);
7988
8540
  if (!propDef) return null;
7989
- return /* @__PURE__ */ jsx57(
8541
+ return /* @__PURE__ */ jsx59(
7990
8542
  InteractiveFilterChip,
7991
8543
  {
7992
8544
  propertyDef: propDef,
@@ -8002,7 +8554,7 @@ var FilterSystem = ({
8002
8554
  filter.id
8003
8555
  );
8004
8556
  }),
8005
- /* @__PURE__ */ jsx57(
8557
+ /* @__PURE__ */ jsx59(
8006
8558
  PropertySelector,
8007
8559
  {
8008
8560
  properties,
@@ -8011,29 +8563,29 @@ var FilterSystem = ({
8011
8563
  onOpenChange: setPropertySelectorOpen,
8012
8564
  onAdvancedFilter: handleOpenAdvanced,
8013
8565
  advancedFilterCount,
8014
- children: totalCount > 0 ? /* @__PURE__ */ jsx57(
8566
+ children: totalCount > 0 ? /* @__PURE__ */ jsx59(
8015
8567
  "button",
8016
8568
  {
8017
8569
  type: "button",
8018
8570
  className: "shrink-0 inline-flex items-center justify-center size-8 rounded-md border border-[var(--color-btn-outlined-neutral-border-default)] bg-gradient-to-t from-[var(--color-btn-outlined-neutral-bg-default)] from-[10%] to-[var(--color-btn-outlined-neutral-bg-gradient-to-default)] shadow-sm cursor-pointer transition-colors hover:from-[var(--color-btn-outlined-neutral-bg-hover)] hover:to-[var(--color-btn-outlined-neutral-bg-gradient-to-hover)]",
8019
- children: /* @__PURE__ */ jsx57(Icon35, { icon: faPlusOutline4, size: "sm", className: "text-[var(--color-foreground)]" })
8571
+ children: /* @__PURE__ */ jsx59(Icon37, { icon: faPlusOutline5, size: "sm", className: "text-[var(--color-foreground)]" })
8020
8572
  }
8021
- ) : /* @__PURE__ */ jsx57(FilterBarButton, {})
8573
+ ) : /* @__PURE__ */ jsx59(FilterBarButton, {})
8022
8574
  }
8023
8575
  )
8024
8576
  ] })
8025
8577
  ),
8026
- totalCount > 0 && /* @__PURE__ */ jsx57(
8578
+ totalCount > 0 && /* @__PURE__ */ jsx59(
8027
8579
  "button",
8028
8580
  {
8029
8581
  type: "button",
8030
8582
  onClick: handleClearAll,
8031
8583
  className: "shrink-0 flex items-center gap-sm px-base py-sm min-h-[32px] max-h-[32px] rounded-md cursor-pointer transition-colors hover:bg-[var(--color-accent)]",
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" })
8584
+ children: isMinimal ? /* @__PURE__ */ jsx59(Icon37, { icon: faXmarkOutline5, size: "sm", className: "text-[var(--color-foreground)]" }) : /* @__PURE__ */ jsx59("span", { className: "text-sm font-semibold leading-sm text-[var(--color-foreground)]", children: "Clear" })
8033
8585
  }
8034
8586
  )
8035
8587
  ] }),
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 })
8588
+ actions && /* @__PURE__ */ jsx59(FilterBarRight, { className: "shrink-0 -ml-2xl pl-2xl relative z-10 bg-[linear-gradient(to_right,transparent_0px,var(--filter-bar-bg,var(--color-background,#fff))_24px)]", children: actions })
8037
8589
  ] });
8038
8590
  };
8039
8591
  FilterSystem.displayName = "FilterSystem";