@l3mpire/ui 2.8.0 → 2.9.1

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/USAGE.md CHANGED
@@ -875,13 +875,13 @@ import {
875
875
  type FilterState, type PropertyDefinition, type SortField,
876
876
  } from "@l3mpire/ui";
877
877
 
878
- // Full interactive system (manages state internally)
878
+ // Full interactive system (manages state, Clear button, responsive)
879
879
  <FilterSystem
880
880
  properties={PROPERTIES}
881
881
  filterState={filterState}
882
882
  onFilterStateChange={setFilterState}
883
883
  sortFields={SORT_FIELDS}
884
- actions={<><Button>Discard</Button><SaveViewButton /></>}
884
+ actions={<SaveViewButton />}
885
885
  >
886
886
  <SearchBar size="sm" className="w-[200px]" />
887
887
  </FilterSystem>
@@ -909,9 +909,18 @@ import {
909
909
  | `FilterChip` | Presentational segmented chip |
910
910
  | `InteractiveFilterChip` | FilterChip with per-segment popovers (property, operator, value, kebab) |
911
911
  | `PropertySelector` | 2-level popover: categories → properties with search |
912
- | `AdvancedChip` | "Advanced filter (N)" pill with close button |
913
- | `AdvancedPopover` | Wide popover with Where/And rows |
912
+ | `AdvancedChip` | Split button "Advanced filters (N)" + close (outlined neutral) |
913
+ | `AdvancedPopover` | Popover with Where/And/Or rows, property/operator selects, inline value input |
914
914
  | `SaveViewButton` | Split button (Save view + dropdown chevron) |
915
+ | `SummaryChip` | Minimal mode: "Filters (N)" with interactive popover |
916
+
917
+ **Responsive:** FilterSystem auto-detects container width via `ResizeObserver`:
918
+ - **Default** (>600px): full chips, labels, "Filters" button
919
+ - **Minimal** (≤600px): SummaryChip "Filters (N)" with interactive popover, icon-only Sort/Filter buttons
920
+
921
+ **Built-in Clear:** appears automatically when filters are active ("Clear" text in default, × icon in minimal).
922
+
923
+ **And/Or toggle:** each row in the advanced popover has an independent And/Or toggle button (click to switch).
915
924
 
916
925
  | Utility | Purpose |
917
926
  |---|---|
package/dist/index.d.mts CHANGED
@@ -883,8 +883,10 @@ interface AdvancedChipProps extends React.ButtonHTMLAttributes<HTMLButtonElement
883
883
  declare const AdvancedChip: React.ForwardRefExoticComponent<AdvancedChipProps & React.RefAttributes<HTMLButtonElement>>;
884
884
 
885
885
  interface AdvancedRowProps {
886
- /** "Where" for the first row, "And" for subsequent. */
887
- connector: "Where" | "And";
886
+ /** "Where" for the first row, "And"/"Or" for subsequent. */
887
+ connector: "Where" | "And" | "Or";
888
+ /** Called when the And/Or toggle is clicked. */
889
+ onConnectorToggle?: () => void;
888
890
  propertyDef: PropertyDefinition;
889
891
  condition: FilterCondition;
890
892
  properties: PropertyDefinition[];
package/dist/index.d.ts CHANGED
@@ -883,8 +883,10 @@ interface AdvancedChipProps extends React.ButtonHTMLAttributes<HTMLButtonElement
883
883
  declare const AdvancedChip: React.ForwardRefExoticComponent<AdvancedChipProps & React.RefAttributes<HTMLButtonElement>>;
884
884
 
885
885
  interface AdvancedRowProps {
886
- /** "Where" for the first row, "And" for subsequent. */
887
- connector: "Where" | "And";
886
+ /** "Where" for the first row, "And"/"Or" for subsequent. */
887
+ connector: "Where" | "And" | "Or";
888
+ /** Called when the And/Or toggle is clicked. */
889
+ onConnectorToggle?: () => void;
888
890
  propertyDef: PropertyDefinition;
889
891
  condition: FilterCondition;
890
892
  properties: PropertyDefinition[];
package/dist/index.js CHANGED
@@ -6428,68 +6428,82 @@ InteractiveFilterChip.displayName = "InteractiveFilterChip";
6428
6428
 
6429
6429
  // src/components/ui/filter/filter-system.tsx
6430
6430
  var React48 = __toESM(require("react"));
6431
+ var import_icons34 = require("@l3mpire/icons");
6431
6432
 
6432
6433
  // src/components/ui/filter/advanced-chip.tsx
6433
6434
  var React43 = __toESM(require("react"));
6434
6435
  var import_icons30 = require("@l3mpire/icons");
6435
6436
  var import_jsx_runtime46 = require("react/jsx-runtime");
6437
+ var btnBase = [
6438
+ "flex items-center justify-center",
6439
+ "min-h-[32px] max-h-[32px]",
6440
+ "bg-gradient-to-t from-[var(--color-btn-outlined-neutral-bg-default)] from-[10%] to-[var(--color-btn-outlined-neutral-bg-gradient-to-default)]",
6441
+ "border border-[var(--color-btn-outlined-neutral-border-default)] shadow-sm",
6442
+ "cursor-pointer transition-colors",
6443
+ "hover:from-[var(--color-btn-outlined-neutral-bg-hover)] hover:to-[var(--color-btn-outlined-neutral-bg-gradient-to-hover)]"
6444
+ ];
6436
6445
  var AdvancedChip = React43.forwardRef(
6437
- ({ className, count, onClear, onClick, ...props }, ref) => /* @__PURE__ */ (0, import_jsx_runtime46.jsxs)(
6438
- "div",
6439
- {
6440
- className: cn(
6441
- "inline-flex items-center overflow-clip",
6442
- "bg-[var(--color-primary)]/5 border border-[var(--color-primary)]/30 rounded-md",
6443
- className
6444
- ),
6445
- children: [
6446
- /* @__PURE__ */ (0, import_jsx_runtime46.jsxs)(
6447
- "button",
6448
- {
6449
- ref,
6450
- type: "button",
6451
- onClick,
6452
- className: "flex items-center gap-sm px-base py-sm cursor-pointer transition-colors hover:bg-[var(--color-primary)]/10",
6453
- ...props,
6454
- children: [
6455
- /* @__PURE__ */ (0, import_jsx_runtime46.jsx)("span", { className: "text-sm font-medium leading-sm whitespace-nowrap text-[var(--color-primary)]", children: "Advanced filter" }),
6456
- /* @__PURE__ */ (0, import_jsx_runtime46.jsx)("span", { className: "flex items-center p-2xs rounded-xs bg-filter-chip-badge-bg", children: /* @__PURE__ */ (0, import_jsx_runtime46.jsx)("span", { className: "text-[10px] font-medium leading-2xs text-filter-chip-badge-text", children: count }) })
6457
- ]
6458
- }
6446
+ ({ className, count, onClear, onClick, ...props }, ref) => /* @__PURE__ */ (0, import_jsx_runtime46.jsxs)("div", { className: cn("inline-flex items-center", className), children: [
6447
+ /* @__PURE__ */ (0, import_jsx_runtime46.jsxs)(
6448
+ "button",
6449
+ {
6450
+ ref,
6451
+ type: "button",
6452
+ onClick,
6453
+ className: cn(
6454
+ btnBase,
6455
+ "gap-sm px-base py-sm min-w-[80px]",
6456
+ "rounded-l-md -mr-px"
6459
6457
  ),
6460
- onClear && /* @__PURE__ */ (0, import_jsx_runtime46.jsxs)(import_jsx_runtime46.Fragment, { children: [
6461
- /* @__PURE__ */ (0, import_jsx_runtime46.jsx)("span", { className: "w-px h-4 bg-[var(--color-primary)]/20" }),
6462
- /* @__PURE__ */ (0, import_jsx_runtime46.jsx)(
6463
- "button",
6464
- {
6465
- type: "button",
6466
- onClick: (e) => {
6467
- e.stopPropagation();
6468
- onClear();
6469
- },
6470
- className: "flex items-center justify-center p-sm cursor-pointer transition-colors hover:bg-[var(--color-primary)]/10",
6471
- "aria-label": "Clear all advanced filters",
6472
- children: /* @__PURE__ */ (0, import_jsx_runtime46.jsx)(import_icons30.Icon, { icon: import_icons30.faXmarkOutline, size: "xs", className: "text-[var(--color-primary)]" })
6473
- }
6474
- )
6475
- ] })
6476
- ]
6477
- }
6478
- )
6458
+ ...props,
6459
+ children: [
6460
+ /* @__PURE__ */ (0, import_jsx_runtime46.jsx)("span", { className: "text-sm font-medium leading-sm whitespace-nowrap text-[var(--color-foreground)]", children: "Advanced filters" }),
6461
+ /* @__PURE__ */ (0, import_jsx_runtime46.jsx)("span", { className: "flex items-center p-2xs rounded-xs bg-filter-chip-badge-bg", children: /* @__PURE__ */ (0, import_jsx_runtime46.jsx)("span", { className: "text-[10px] font-medium leading-2xs text-filter-chip-badge-text", children: count }) })
6462
+ ]
6463
+ }
6464
+ ),
6465
+ onClear && /* @__PURE__ */ (0, import_jsx_runtime46.jsx)(
6466
+ "button",
6467
+ {
6468
+ type: "button",
6469
+ onClick: (e) => {
6470
+ e.stopPropagation();
6471
+ onClear();
6472
+ },
6473
+ className: cn(
6474
+ btnBase,
6475
+ "p-sm",
6476
+ "rounded-r-md -ml-px"
6477
+ ),
6478
+ "aria-label": "Clear all advanced filters",
6479
+ children: /* @__PURE__ */ (0, import_jsx_runtime46.jsx)(import_icons30.Icon, { icon: import_icons30.faXmarkOutline, size: "sm", className: "text-[var(--color-foreground)]" })
6480
+ }
6481
+ )
6482
+ ] })
6479
6483
  );
6480
6484
  AdvancedChip.displayName = "AdvancedChip";
6481
6485
 
6482
6486
  // src/components/ui/filter/advanced-popover.tsx
6483
6487
  var React45 = __toESM(require("react"));
6484
6488
  var PopoverPrimitive10 = __toESM(require("@radix-ui/react-popover"));
6489
+ var import_icons32 = require("@l3mpire/icons");
6485
6490
 
6486
6491
  // src/components/ui/filter/advanced-row.tsx
6487
6492
  var React44 = __toESM(require("react"));
6488
6493
  var PopoverPrimitive9 = __toESM(require("@radix-ui/react-popover"));
6489
6494
  var import_icons31 = require("@l3mpire/icons");
6490
6495
  var import_jsx_runtime47 = require("react/jsx-runtime");
6496
+ var selectBtnStyle = [
6497
+ "flex items-center gap-base",
6498
+ "px-base py-sm",
6499
+ "bg-gradient-to-t from-[var(--color-btn-outlined-neutral-bg-default)] to-[var(--color-btn-outlined-neutral-bg-gradient-to-default)]",
6500
+ "border border-[var(--color-btn-outlined-neutral-border-default)] rounded-md shadow-sm",
6501
+ "cursor-pointer transition-colors",
6502
+ "hover:from-[var(--color-btn-outlined-neutral-bg-hover)] hover:to-[var(--color-btn-outlined-neutral-bg-gradient-to-hover)]"
6503
+ ];
6491
6504
  var AdvancedRow = ({
6492
6505
  connector,
6506
+ onConnectorToggle,
6493
6507
  propertyDef,
6494
6508
  condition,
6495
6509
  properties,
@@ -6498,7 +6512,6 @@ var AdvancedRow = ({
6498
6512
  onDelete
6499
6513
  }) => {
6500
6514
  const [operatorOpen, setOperatorOpen] = React44.useState(false);
6501
- const [valueOpen, setValueOpen] = React44.useState(false);
6502
6515
  const [propertyOpen, setPropertyOpen] = React44.useState(false);
6503
6516
  const handleOperatorSelect = (op) => {
6504
6517
  if (isNoValueOperator(op)) {
@@ -6513,46 +6526,36 @@ var AdvancedRow = ({
6513
6526
  onUpdate({ ...condition, value: val });
6514
6527
  };
6515
6528
  const displayValue = condition.value == null ? "" : typeof condition.value === "string" ? condition.value : String(condition.value);
6516
- const groupedProps = React44.useMemo(() => {
6517
- const map = /* @__PURE__ */ new Map();
6518
- for (const p of properties) {
6519
- const arr = map.get(p.group) ?? [];
6520
- arr.push(p);
6521
- map.set(p.group, arr);
6522
- }
6523
- return map;
6524
- }, [properties]);
6525
- return /* @__PURE__ */ (0, import_jsx_runtime47.jsxs)("div", { className: "group flex items-center gap-base py-xs", children: [
6526
- /* @__PURE__ */ (0, import_jsx_runtime47.jsx)(
6527
- "span",
6529
+ return /* @__PURE__ */ (0, import_jsx_runtime47.jsxs)("div", { className: "flex items-center gap-base w-full", children: [
6530
+ connector === "Where" ? /* @__PURE__ */ (0, import_jsx_runtime47.jsx)("div", { className: "shrink-0 w-[64px] flex items-center justify-end", children: /* @__PURE__ */ (0, import_jsx_runtime47.jsx)("span", { className: "text-xs font-medium leading-xs text-[var(--color-muted-foreground)]", children: "Where" }) }) : /* @__PURE__ */ (0, import_jsx_runtime47.jsxs)(
6531
+ "button",
6528
6532
  {
6533
+ type: "button",
6534
+ onClick: onConnectorToggle,
6529
6535
  className: cn(
6530
- "shrink-0 w-[52px] text-xs font-medium leading-xs text-right",
6531
- connector === "Where" ? "text-[var(--color-muted-foreground)]" : "text-[var(--color-muted-foreground)]"
6536
+ "shrink-0 flex items-center justify-center gap-xs",
6537
+ "min-w-[64px] min-h-[24px] max-h-[24px] p-xs",
6538
+ "bg-gradient-to-t from-[var(--color-btn-outlined-neutral-bg-default)] from-[10%] to-[var(--color-btn-outlined-neutral-bg-gradient-to-default)]",
6539
+ "border border-[var(--color-btn-outlined-neutral-border-default)] rounded-base shadow-sm",
6540
+ "cursor-pointer transition-colors text-xs font-medium leading-xs text-[var(--color-foreground)]",
6541
+ "hover:from-[var(--color-btn-outlined-neutral-bg-hover)] hover:to-[var(--color-btn-outlined-neutral-bg-gradient-to-hover)]"
6532
6542
  ),
6533
- children: /* @__PURE__ */ (0, import_jsx_runtime47.jsxs)("span", { className: "flex items-center justify-end gap-2xs", children: [
6543
+ children: [
6534
6544
  connector,
6535
- connector === "And" && /* @__PURE__ */ (0, import_jsx_runtime47.jsx)(import_icons31.Icon, { icon: import_icons31.faRefreshOutline, size: "xs", className: "text-[var(--color-muted-foreground)]" })
6536
- ] })
6545
+ /* @__PURE__ */ (0, import_jsx_runtime47.jsx)(import_icons31.Icon, { icon: import_icons31.faRefreshOutline, size: "xs", className: "text-[var(--color-foreground)]" })
6546
+ ]
6537
6547
  }
6538
6548
  ),
6539
6549
  /* @__PURE__ */ (0, import_jsx_runtime47.jsxs)(PopoverPrimitive9.Root, { open: propertyOpen, onOpenChange: setPropertyOpen, children: [
6540
- /* @__PURE__ */ (0, import_jsx_runtime47.jsx)(PopoverPrimitive9.Trigger, { asChild: true, children: /* @__PURE__ */ (0, import_jsx_runtime47.jsxs)(
6541
- "button",
6542
- {
6543
- type: "button",
6544
- className: "flex items-center gap-xs px-base py-sm rounded-base border border-[var(--color-input)] bg-[var(--color-background)] cursor-pointer hover:bg-[var(--color-accent)] transition-colors",
6545
- children: [
6546
- /* @__PURE__ */ (0, import_jsx_runtime47.jsx)(import_icons31.Icon, { icon: propertyDef.icon, size: "xs", className: "text-[var(--color-muted-foreground)]" }),
6547
- /* @__PURE__ */ (0, import_jsx_runtime47.jsxs)("span", { className: "text-sm font-regular leading-sm text-[var(--color-foreground)] whitespace-nowrap", children: [
6548
- propertyDef.groupLabel,
6549
- " \u203A ",
6550
- propertyDef.label
6551
- ] }),
6552
- /* @__PURE__ */ (0, import_jsx_runtime47.jsx)("svg", { width: "10", height: "10", viewBox: "0 0 10 10", fill: "currentColor", className: "text-[var(--color-muted-foreground)]", children: /* @__PURE__ */ (0, import_jsx_runtime47.jsx)("path", { d: "M2.5 4L5 6.5L7.5 4", stroke: "currentColor", strokeWidth: "1.2", fill: "none", strokeLinecap: "round" }) })
6553
- ]
6554
- }
6555
- ) }),
6550
+ /* @__PURE__ */ (0, import_jsx_runtime47.jsx)(PopoverPrimitive9.Trigger, { asChild: true, children: /* @__PURE__ */ (0, import_jsx_runtime47.jsxs)("button", { type: "button", className: cn(selectBtnStyle, "shrink-0 min-w-[80px]"), children: [
6551
+ /* @__PURE__ */ (0, import_jsx_runtime47.jsx)(import_icons31.Icon, { icon: propertyDef.icon, size: "sm", className: "shrink-0 text-[var(--color-muted-foreground)]" }),
6552
+ /* @__PURE__ */ (0, import_jsx_runtime47.jsxs)("span", { className: "text-sm font-regular leading-sm text-[var(--color-foreground)] whitespace-nowrap", children: [
6553
+ propertyDef.groupLabel,
6554
+ " > ",
6555
+ propertyDef.label
6556
+ ] }),
6557
+ /* @__PURE__ */ (0, import_jsx_runtime47.jsx)(import_icons31.Icon, { icon: import_icons31.faChevronDownOutline, size: "xs", className: "shrink-0 text-[var(--color-foreground)]" })
6558
+ ] }) }),
6556
6559
  /* @__PURE__ */ (0, import_jsx_runtime47.jsx)(PopoverPrimitive9.Portal, { children: /* @__PURE__ */ (0, import_jsx_runtime47.jsx)(
6557
6560
  PopoverPrimitive9.Content,
6558
6561
  {
@@ -6565,7 +6568,7 @@ var AdvancedRow = ({
6565
6568
  "data-[state=closed]:animate-out data-[state=closed]:fade-out-0",
6566
6569
  "min-w-[200px]"
6567
6570
  ),
6568
- children: Array.from(groupedProps.entries()).map(([group, props]) => /* @__PURE__ */ (0, import_jsx_runtime47.jsx)("div", { className: "flex flex-col", children: props.map((p) => /* @__PURE__ */ (0, import_jsx_runtime47.jsxs)(
6571
+ children: properties.map((p) => /* @__PURE__ */ (0, import_jsx_runtime47.jsxs)(
6569
6572
  "button",
6570
6573
  {
6571
6574
  type: "button",
@@ -6584,22 +6587,15 @@ var AdvancedRow = ({
6584
6587
  ]
6585
6588
  },
6586
6589
  p.id
6587
- )) }, group))
6590
+ ))
6588
6591
  }
6589
6592
  ) })
6590
6593
  ] }),
6591
6594
  /* @__PURE__ */ (0, import_jsx_runtime47.jsxs)(PopoverPrimitive9.Root, { open: operatorOpen, onOpenChange: setOperatorOpen, children: [
6592
- /* @__PURE__ */ (0, import_jsx_runtime47.jsx)(PopoverPrimitive9.Trigger, { asChild: true, children: /* @__PURE__ */ (0, import_jsx_runtime47.jsxs)(
6593
- "button",
6594
- {
6595
- type: "button",
6596
- className: "flex items-center gap-xs px-base py-sm rounded-base border border-[var(--color-input)] bg-[var(--color-background)] cursor-pointer hover:bg-[var(--color-accent)] transition-colors",
6597
- children: [
6598
- /* @__PURE__ */ (0, import_jsx_runtime47.jsx)("span", { className: "text-sm font-regular leading-sm text-[var(--color-foreground)] whitespace-nowrap", children: condition.operator ?? "select" }),
6599
- /* @__PURE__ */ (0, import_jsx_runtime47.jsx)("svg", { width: "10", height: "10", viewBox: "0 0 10 10", fill: "currentColor", className: "text-[var(--color-muted-foreground)]", children: /* @__PURE__ */ (0, import_jsx_runtime47.jsx)("path", { d: "M2.5 4L5 6.5L7.5 4", stroke: "currentColor", strokeWidth: "1.2", fill: "none", strokeLinecap: "round" }) })
6600
- ]
6601
- }
6602
- ) }),
6595
+ /* @__PURE__ */ (0, import_jsx_runtime47.jsx)(PopoverPrimitive9.Trigger, { asChild: true, children: /* @__PURE__ */ (0, import_jsx_runtime47.jsxs)("button", { type: "button", className: cn(selectBtnStyle, "shrink-0 w-[103px]"), children: [
6596
+ /* @__PURE__ */ (0, import_jsx_runtime47.jsx)("span", { className: "flex-1 text-sm font-regular leading-sm text-[var(--color-foreground)] whitespace-nowrap text-left", children: condition.operator ?? "Select" }),
6597
+ /* @__PURE__ */ (0, import_jsx_runtime47.jsx)(import_icons31.Icon, { icon: import_icons31.faChevronDownOutline, size: "xs", className: "shrink-0 text-[var(--color-foreground)]" })
6598
+ ] }) }),
6603
6599
  /* @__PURE__ */ (0, import_jsx_runtime47.jsx)(PopoverPrimitive9.Portal, { children: /* @__PURE__ */ (0, import_jsx_runtime47.jsx)(
6604
6600
  PopoverPrimitive9.Content,
6605
6601
  {
@@ -6629,9 +6625,10 @@ var AdvancedRow = ({
6629
6625
  type: "text",
6630
6626
  value: displayValue,
6631
6627
  onChange: (e) => handleValueChange(e.target.value),
6632
- placeholder: "Enter value...",
6628
+ placeholder: "Placeholder",
6633
6629
  className: cn(
6634
- "flex-1 min-w-[100px] px-base py-sm rounded-base border border-[var(--color-input)]",
6630
+ "w-[160px] shrink-0 px-base py-sm rounded-md",
6631
+ "border border-[var(--color-input)]",
6635
6632
  "bg-[var(--color-background)] text-sm font-regular leading-sm text-[var(--color-foreground)]",
6636
6633
  "placeholder:text-[var(--color-muted-foreground)]",
6637
6634
  "focus:outline-none focus:ring-2 focus:ring-[var(--color-ring)] focus:ring-offset-0"
@@ -6643,9 +6640,9 @@ var AdvancedRow = ({
6643
6640
  {
6644
6641
  type: "button",
6645
6642
  onClick: onDelete,
6646
- className: "shrink-0 flex items-center justify-center p-sm rounded-base opacity-0 group-hover:opacity-100 cursor-pointer transition-opacity hover:bg-[var(--color-accent)]",
6643
+ className: "ml-auto shrink-0 flex items-center justify-center p-sm rounded-md cursor-pointer transition-colors hover:bg-[var(--color-accent)]",
6647
6644
  "aria-label": "Remove filter",
6648
- children: /* @__PURE__ */ (0, import_jsx_runtime47.jsx)(import_icons31.Icon, { icon: import_icons31.faEllipsisVerticalOutline, size: "sm", className: "text-[var(--color-muted-foreground)]" })
6645
+ children: /* @__PURE__ */ (0, import_jsx_runtime47.jsx)(import_icons31.Icon, { icon: import_icons31.faXmarkOutline, size: "sm", className: "text-[var(--color-foreground)]" })
6649
6646
  }
6650
6647
  )
6651
6648
  ] });
@@ -6654,6 +6651,14 @@ AdvancedRow.displayName = "AdvancedRow";
6654
6651
 
6655
6652
  // src/components/ui/filter/advanced-popover.tsx
6656
6653
  var import_jsx_runtime48 = require("react/jsx-runtime");
6654
+ var outlinedBtn = [
6655
+ "flex items-center gap-sm px-base py-sm",
6656
+ "min-h-[32px] max-h-[32px] min-w-[80px]",
6657
+ "bg-gradient-to-t from-[var(--color-btn-outlined-neutral-bg-default)] from-[10%] to-[var(--color-btn-outlined-neutral-bg-gradient-to-default)]",
6658
+ "border border-[var(--color-btn-outlined-neutral-border-default)] rounded-md shadow-sm",
6659
+ "cursor-pointer transition-colors text-sm font-medium leading-sm text-[var(--color-foreground)]",
6660
+ "hover:from-[var(--color-btn-outlined-neutral-bg-hover)] hover:to-[var(--color-btn-outlined-neutral-bg-gradient-to-hover)]"
6661
+ ];
6657
6662
  var AdvancedPopover = ({
6658
6663
  filters,
6659
6664
  properties,
@@ -6663,6 +6668,7 @@ var AdvancedPopover = ({
6663
6668
  children
6664
6669
  }) => {
6665
6670
  const [addSelectorOpen, setAddSelectorOpen] = React45.useState(false);
6671
+ const [logicOps, setLogicOps] = React45.useState({});
6666
6672
  const getPropertyDef = (propertyId) => properties.find((p) => p.id === propertyId);
6667
6673
  const handleUpdateFilter = (updated) => {
6668
6674
  onFiltersChange(filters.map((f) => f.id === updated.id ? updated : f));
@@ -6685,6 +6691,12 @@ var AdvancedPopover = ({
6685
6691
  onFiltersChange([]);
6686
6692
  onOpenChange?.(false);
6687
6693
  };
6694
+ const toggleLogicOp = (filterId) => {
6695
+ setLogicOps((prev) => ({
6696
+ ...prev,
6697
+ [filterId]: (prev[filterId] ?? "and") === "and" ? "or" : "and"
6698
+ }));
6699
+ };
6688
6700
  return /* @__PURE__ */ (0, import_jsx_runtime48.jsxs)(PopoverPrimitive10.Root, { open, onOpenChange, children: [
6689
6701
  /* @__PURE__ */ (0, import_jsx_runtime48.jsx)(PopoverPrimitive10.Trigger, { asChild: true, children }),
6690
6702
  /* @__PURE__ */ (0, import_jsx_runtime48.jsx)(PopoverPrimitive10.Portal, { children: /* @__PURE__ */ (0, import_jsx_runtime48.jsxs)(
@@ -6693,22 +6705,22 @@ var AdvancedPopover = ({
6693
6705
  sideOffset: 4,
6694
6706
  align: "start",
6695
6707
  className: cn(
6696
- "z-50 flex flex-col overflow-clip",
6697
- "bg-[var(--color-dropdown-bg)] border border-[var(--color-dropdown-border)] rounded-md shadow-lg",
6708
+ "z-50 flex flex-col",
6709
+ "bg-[var(--color-background)] rounded-md shadow-lg",
6698
6710
  "data-[state=open]:animate-in data-[state=open]:fade-in-0 data-[state=open]:zoom-in-95",
6699
6711
  "data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=closed]:zoom-out-95",
6700
- "data-[side=bottom]:slide-in-from-top-2",
6701
- "min-w-[520px] max-w-[90vw]"
6712
+ "data-[side=bottom]:slide-in-from-top-2"
6702
6713
  ),
6703
6714
  children: [
6704
- /* @__PURE__ */ (0, import_jsx_runtime48.jsxs)("div", { className: "flex flex-col px-base pt-base", children: [
6715
+ /* @__PURE__ */ (0, import_jsx_runtime48.jsxs)("div", { className: "flex flex-col gap-base p-base", children: [
6705
6716
  filters.map((filter, i) => {
6706
6717
  const propDef = getPropertyDef(filter.propertyId);
6707
6718
  if (!propDef) return null;
6708
6719
  return /* @__PURE__ */ (0, import_jsx_runtime48.jsx)(
6709
6720
  AdvancedRow,
6710
6721
  {
6711
- connector: i === 0 ? "Where" : "And",
6722
+ connector: i === 0 ? "Where" : (logicOps[filter.id] ?? "and") === "and" ? "And" : "Or",
6723
+ onConnectorToggle: i > 0 ? () => toggleLogicOp(filter.id) : void 0,
6712
6724
  propertyDef: propDef,
6713
6725
  condition: filter,
6714
6726
  properties,
@@ -6721,7 +6733,7 @@ var AdvancedPopover = ({
6721
6733
  }),
6722
6734
  filters.length === 0 && /* @__PURE__ */ (0, import_jsx_runtime48.jsx)("p", { className: "py-base text-sm text-[var(--color-muted-foreground)]", children: "No advanced filters yet." })
6723
6735
  ] }),
6724
- /* @__PURE__ */ (0, import_jsx_runtime48.jsxs)("div", { className: "flex items-center justify-between px-base py-base border-t border-[var(--color-border)]", children: [
6736
+ /* @__PURE__ */ (0, import_jsx_runtime48.jsxs)("div", { className: "flex items-center justify-between p-base border-t border-[var(--color-border)]", children: [
6725
6737
  /* @__PURE__ */ (0, import_jsx_runtime48.jsx)(
6726
6738
  PropertySelector,
6727
6739
  {
@@ -6729,14 +6741,10 @@ var AdvancedPopover = ({
6729
6741
  onSelect: handleAddFilter,
6730
6742
  open: addSelectorOpen,
6731
6743
  onOpenChange: setAddSelectorOpen,
6732
- children: /* @__PURE__ */ (0, import_jsx_runtime48.jsx)(
6733
- "button",
6734
- {
6735
- type: "button",
6736
- className: "text-sm font-regular leading-sm text-[var(--color-muted-foreground)] hover:text-[var(--color-foreground)] cursor-pointer transition-colors",
6737
- children: "+ Add filter"
6738
- }
6739
- )
6744
+ children: /* @__PURE__ */ (0, import_jsx_runtime48.jsxs)("button", { type: "button", className: cn(outlinedBtn), children: [
6745
+ /* @__PURE__ */ (0, import_jsx_runtime48.jsx)(import_icons32.Icon, { icon: import_icons32.faPlusOutline, size: "sm", className: "text-[var(--color-foreground)]" }),
6746
+ "Add filter"
6747
+ ] })
6740
6748
  }
6741
6749
  ),
6742
6750
  /* @__PURE__ */ (0, import_jsx_runtime48.jsx)(
@@ -6744,7 +6752,7 @@ var AdvancedPopover = ({
6744
6752
  {
6745
6753
  type: "button",
6746
6754
  onClick: handleClearAll,
6747
- className: "text-sm font-regular leading-sm text-[var(--color-muted-foreground)] hover:text-[var(--color-foreground)] cursor-pointer transition-colors",
6755
+ className: "text-sm font-medium leading-sm text-[var(--color-foreground)] cursor-pointer transition-colors hover:opacity-70 px-base py-sm",
6748
6756
  children: "Clear all filters"
6749
6757
  }
6750
6758
  )
@@ -6759,7 +6767,7 @@ AdvancedPopover.displayName = "AdvancedPopover";
6759
6767
  // src/components/ui/filter/summary-chip.tsx
6760
6768
  var React46 = __toESM(require("react"));
6761
6769
  var PopoverPrimitive11 = __toESM(require("@radix-ui/react-popover"));
6762
- var import_icons32 = require("@l3mpire/icons");
6770
+ var import_icons33 = require("@l3mpire/icons");
6763
6771
  var import_jsx_runtime49 = require("react/jsx-runtime");
6764
6772
  var SummaryChip = ({
6765
6773
  count,
@@ -6771,6 +6779,7 @@ var SummaryChip = ({
6771
6779
  }) => {
6772
6780
  const [open, setOpen] = React46.useState(false);
6773
6781
  const [addSelectorOpen, setAddSelectorOpen] = React46.useState(false);
6782
+ const [logicOps, setLogicOps] = React46.useState({});
6774
6783
  const getPropertyDef = (propertyId) => properties.find((p) => p.id === propertyId);
6775
6784
  const handleUpdateFilter = (updated) => {
6776
6785
  onFiltersChange(filters.map((f) => f.id === updated.id ? updated : f));
@@ -6799,24 +6808,23 @@ var SummaryChip = ({
6799
6808
  className: cn(
6800
6809
  "inline-flex items-center gap-sm px-base py-sm",
6801
6810
  "min-h-[32px] max-h-[32px]",
6802
- count > 0 ? "bg-[var(--color-primary)]/5 border border-[var(--color-primary)]/30 text-[var(--color-primary)]" : "bg-filter-chip-bg border border-filter-chip-border text-[var(--color-foreground)]",
6803
- "rounded-md text-sm font-medium leading-sm",
6804
- "cursor-pointer transition-colors hover:opacity-80",
6811
+ "bg-gradient-to-t from-[var(--color-btn-outlined-neutral-bg-default)] from-[10%] to-[var(--color-btn-outlined-neutral-bg-gradient-to-default)]",
6812
+ "border border-[var(--color-btn-outlined-neutral-border-default)] rounded-md shadow-sm",
6813
+ "cursor-pointer transition-colors",
6814
+ "hover:from-[var(--color-btn-outlined-neutral-bg-hover)] hover:to-[var(--color-btn-outlined-neutral-bg-gradient-to-hover)]",
6805
6815
  className
6806
6816
  ),
6807
6817
  children: [
6808
6818
  /* @__PURE__ */ (0, import_jsx_runtime49.jsx)(
6809
- import_icons32.Icon,
6819
+ import_icons33.Icon,
6810
6820
  {
6811
- icon: import_icons32.faFilterOutline,
6821
+ icon: import_icons33.faSlidersOutline,
6812
6822
  size: "sm",
6813
- className: count > 0 ? "text-[var(--color-primary)]" : "text-[var(--color-muted-foreground)]"
6823
+ className: "shrink-0 text-[var(--color-foreground)]"
6814
6824
  }
6815
6825
  ),
6816
- /* @__PURE__ */ (0, import_jsx_runtime49.jsxs)("span", { className: "whitespace-nowrap", children: [
6817
- "Filters",
6818
- count > 0 && ` (${count})`
6819
- ] })
6826
+ /* @__PURE__ */ (0, import_jsx_runtime49.jsx)("span", { className: "text-sm font-medium leading-sm whitespace-nowrap text-[var(--color-foreground)]", children: "Filters" }),
6827
+ count > 0 && /* @__PURE__ */ (0, import_jsx_runtime49.jsx)("span", { className: "flex items-center p-2xs rounded-xs bg-filter-chip-badge-bg", children: /* @__PURE__ */ (0, import_jsx_runtime49.jsx)("span", { className: "text-[10px] font-medium leading-2xs text-filter-chip-badge-text", children: count }) })
6820
6828
  ]
6821
6829
  }
6822
6830
  ) }),
@@ -6834,14 +6842,15 @@ var SummaryChip = ({
6834
6842
  "min-w-[420px] max-w-[90vw]"
6835
6843
  ),
6836
6844
  children: [
6837
- /* @__PURE__ */ (0, import_jsx_runtime49.jsxs)("div", { className: "flex flex-col px-base pt-base", children: [
6845
+ /* @__PURE__ */ (0, import_jsx_runtime49.jsxs)("div", { className: "flex flex-col gap-base p-base", children: [
6838
6846
  filters.map((filter, i) => {
6839
6847
  const propDef = getPropertyDef(filter.propertyId);
6840
6848
  if (!propDef) return null;
6841
6849
  return /* @__PURE__ */ (0, import_jsx_runtime49.jsx)(
6842
6850
  AdvancedRow,
6843
6851
  {
6844
- connector: i === 0 ? "Where" : "And",
6852
+ connector: i === 0 ? "Where" : (logicOps[filter.id] ?? "and") === "and" ? "And" : "Or",
6853
+ onConnectorToggle: i > 0 ? () => setLogicOps((prev) => ({ ...prev, [filter.id]: (prev[filter.id] ?? "and") === "and" ? "or" : "and" })) : void 0,
6845
6854
  propertyDef: propDef,
6846
6855
  condition: filter,
6847
6856
  properties,
@@ -6854,7 +6863,7 @@ var SummaryChip = ({
6854
6863
  }),
6855
6864
  filters.length === 0 && /* @__PURE__ */ (0, import_jsx_runtime49.jsx)("p", { className: "py-base text-sm text-[var(--color-muted-foreground)]", children: "No active filters." })
6856
6865
  ] }),
6857
- /* @__PURE__ */ (0, import_jsx_runtime49.jsxs)("div", { className: "flex items-center justify-between px-base py-base border-t border-[var(--color-border)]", children: [
6866
+ /* @__PURE__ */ (0, import_jsx_runtime49.jsxs)("div", { className: "flex items-center justify-between p-base border-t border-[var(--color-border)]", children: [
6858
6867
  /* @__PURE__ */ (0, import_jsx_runtime49.jsx)(
6859
6868
  PropertySelector,
6860
6869
  {
@@ -6866,9 +6875,16 @@ var SummaryChip = ({
6866
6875
  "button",
6867
6876
  {
6868
6877
  type: "button",
6869
- className: "flex items-center gap-xs text-sm font-regular leading-sm text-[var(--color-muted-foreground)] hover:text-[var(--color-foreground)] cursor-pointer transition-colors",
6878
+ className: cn(
6879
+ "flex items-center gap-sm px-base py-sm",
6880
+ "min-h-[32px] max-h-[32px] min-w-[80px]",
6881
+ "bg-gradient-to-t from-[var(--color-btn-outlined-neutral-bg-default)] from-[10%] to-[var(--color-btn-outlined-neutral-bg-gradient-to-default)]",
6882
+ "border border-[var(--color-btn-outlined-neutral-border-default)] rounded-md shadow-sm",
6883
+ "cursor-pointer transition-colors text-sm font-medium leading-sm text-[var(--color-foreground)]",
6884
+ "hover:from-[var(--color-btn-outlined-neutral-bg-hover)] hover:to-[var(--color-btn-outlined-neutral-bg-gradient-to-hover)]"
6885
+ ),
6870
6886
  children: [
6871
- /* @__PURE__ */ (0, import_jsx_runtime49.jsx)(import_icons32.Icon, { icon: import_icons32.faPlusOutline, size: "xs" }),
6887
+ /* @__PURE__ */ (0, import_jsx_runtime49.jsx)(import_icons33.Icon, { icon: import_icons33.faPlusOutline, size: "sm", className: "text-[var(--color-foreground)]" }),
6872
6888
  "Add filter"
6873
6889
  ]
6874
6890
  }
@@ -6883,7 +6899,7 @@ var SummaryChip = ({
6883
6899
  onClearAll();
6884
6900
  setOpen(false);
6885
6901
  },
6886
- className: "text-sm font-regular leading-sm text-[var(--color-muted-foreground)] hover:text-[var(--color-foreground)] cursor-pointer transition-colors",
6902
+ className: "text-sm font-medium leading-sm text-[var(--color-foreground)] cursor-pointer transition-colors hover:opacity-70 px-base py-sm",
6887
6903
  children: "Clear all filters"
6888
6904
  }
6889
6905
  )
@@ -7103,6 +7119,15 @@ var FilterSystem = ({
7103
7119
  }
7104
7120
  )
7105
7121
  ] })
7122
+ ),
7123
+ totalCount > 0 && /* @__PURE__ */ (0, import_jsx_runtime50.jsx)(
7124
+ "button",
7125
+ {
7126
+ type: "button",
7127
+ onClick: handleClearAll,
7128
+ className: "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)]",
7129
+ children: isMinimal ? /* @__PURE__ */ (0, import_jsx_runtime50.jsx)(import_icons34.Icon, { icon: import_icons34.faXmarkOutline, size: "sm", className: "text-[var(--color-foreground)]" }) : /* @__PURE__ */ (0, import_jsx_runtime50.jsx)("span", { className: "text-sm font-medium leading-sm text-[var(--color-foreground)]", children: "Clear" })
7130
+ }
7106
7131
  )
7107
7132
  ] }),
7108
7133
  actions && /* @__PURE__ */ (0, import_jsx_runtime50.jsx)(FilterBarRight, { children: actions })
@@ -7113,7 +7138,7 @@ FilterSystem.displayName = "FilterSystem";
7113
7138
  // src/components/ui/date-picker.tsx
7114
7139
  var React49 = __toESM(require("react"));
7115
7140
  var PopoverPrimitive12 = __toESM(require("@radix-ui/react-popover"));
7116
- var import_icons33 = require("@l3mpire/icons");
7141
+ var import_icons35 = require("@l3mpire/icons");
7117
7142
  var import_jsx_runtime51 = require("react/jsx-runtime");
7118
7143
  function getDaysInMonth(year, month) {
7119
7144
  return new Date(year, month + 1, 0).getDate();
@@ -7281,19 +7306,19 @@ var DatePickerSelects = React49.forwardRef(({ className, formatDate = defaultFor
7281
7306
  children: /* @__PURE__ */ (0, import_jsx_runtime51.jsxs)("div", { className: "flex items-center gap-base w-full", children: [
7282
7307
  /* @__PURE__ */ (0, import_jsx_runtime51.jsxs)("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: [
7283
7308
  /* @__PURE__ */ (0, import_jsx_runtime51.jsx)("span", { className: "flex-1 text-sm font-regular leading-sm text-datepicker-header-text truncate", children: fromDate ? formatDate(fromDate) : "Start date" }),
7284
- /* @__PURE__ */ (0, import_jsx_runtime51.jsx)(import_icons33.Icon, { icon: import_icons33.faCalendarOutline, size: "sm", className: "shrink-0 text-datepicker-header-text" })
7309
+ /* @__PURE__ */ (0, import_jsx_runtime51.jsx)(import_icons35.Icon, { icon: import_icons35.faCalendarOutline, size: "sm", className: "shrink-0 text-datepicker-header-text" })
7285
7310
  ] }),
7286
7311
  /* @__PURE__ */ (0, import_jsx_runtime51.jsx)(
7287
- import_icons33.Icon,
7312
+ import_icons35.Icon,
7288
7313
  {
7289
- icon: import_icons33.faArrowRightOutline,
7314
+ icon: import_icons35.faArrowRightOutline,
7290
7315
  size: "sm",
7291
7316
  className: "shrink-0 text-datepicker-header-weekday"
7292
7317
  }
7293
7318
  ),
7294
7319
  /* @__PURE__ */ (0, import_jsx_runtime51.jsxs)("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: [
7295
7320
  /* @__PURE__ */ (0, import_jsx_runtime51.jsx)("span", { className: "flex-1 text-sm font-regular leading-sm text-datepicker-header-text truncate", children: toDate ? formatDate(toDate) : "End date" }),
7296
- /* @__PURE__ */ (0, import_jsx_runtime51.jsx)(import_icons33.Icon, { icon: import_icons33.faCalendarOutline, size: "sm", className: "shrink-0 text-datepicker-header-text" })
7321
+ /* @__PURE__ */ (0, import_jsx_runtime51.jsx)(import_icons35.Icon, { icon: import_icons35.faCalendarOutline, size: "sm", className: "shrink-0 text-datepicker-header-text" })
7297
7322
  ] })
7298
7323
  ] })
7299
7324
  }
@@ -7403,7 +7428,7 @@ var DatePickerCalendar = React49.forwardRef(({ className, header, ...props }, re
7403
7428
  onClick: goToPrevMonth,
7404
7429
  className: "flex items-center justify-center p-xs rounded-base hover:bg-datepicker-day-bg-hover transition-colors cursor-pointer",
7405
7430
  "aria-label": "Previous month",
7406
- children: /* @__PURE__ */ (0, import_jsx_runtime51.jsx)(import_icons33.Icon, { icon: import_icons33.faChevronLeftOutline, size: "xs", className: "text-datepicker-header-nav" })
7431
+ children: /* @__PURE__ */ (0, import_jsx_runtime51.jsx)(import_icons35.Icon, { icon: import_icons35.faChevronLeftOutline, size: "xs", className: "text-datepicker-header-nav" })
7407
7432
  }
7408
7433
  ),
7409
7434
  /* @__PURE__ */ (0, import_jsx_runtime51.jsx)(
@@ -7413,7 +7438,7 @@ var DatePickerCalendar = React49.forwardRef(({ className, header, ...props }, re
7413
7438
  onClick: goToNextMonth,
7414
7439
  className: "flex items-center justify-center p-xs rounded-base hover:bg-datepicker-day-bg-hover transition-colors cursor-pointer",
7415
7440
  "aria-label": "Next month",
7416
- children: /* @__PURE__ */ (0, import_jsx_runtime51.jsx)(import_icons33.Icon, { icon: import_icons33.faChevronRightOutline, size: "xs", className: "text-datepicker-header-nav" })
7441
+ children: /* @__PURE__ */ (0, import_jsx_runtime51.jsx)(import_icons35.Icon, { icon: import_icons35.faChevronRightOutline, size: "xs", className: "text-datepicker-header-nav" })
7417
7442
  }
7418
7443
  )
7419
7444
  ] })