@l3mpire/ui 2.11.0 → 2.13.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/USAGE.md CHANGED
@@ -946,12 +946,38 @@ import {
946
946
  | `SummaryChip` | Minimal mode: "Filters (N)" with interactive popover |
947
947
 
948
948
  **Responsive:** FilterSystem auto-detects container width via `ResizeObserver`:
949
- - **Default** (>600px): full chips, labels, "Filters" button
950
- - **Minimal** (≤600px): SummaryChip "Filters (N)" with interactive popover, icon-only Sort/Filter buttons
949
+ - **Default** (>breakpoint): full chips, labels, "Filters" button
950
+ - **Minimal** (≤breakpoint): SummaryChip "Filters (N)" with interactive popover, icon-only Sort/Filter buttons
951
+ - The breakpoint is configurable via the `breakpoint` prop on `FilterSystem` (default: `600`).
951
952
 
952
953
  **Built-in Clear:** appears inline after the last filter chip ("Clear" text in default, × icon in minimal). Separate from "Discard changes" which goes in `actions` (right side) to revert a saved view.
953
954
 
954
- **And/Or toggle:** each row in the advanced popover has an independent And/Or toggle button (click to switch).
955
+ **And/Or toggle:** each row in the advanced popover has an independent And/Or toggle button. The choice is **persisted on each `FilterCondition` as `logicOperator: "and" | "or"`** (defaults to `"and"` when undefined), so it survives remounts and can be serialized.
956
+
957
+ **Advanced filter shortcut:** the PropertySelector footer shows an "Advanced filter · N rule(s)" item. Clicking it closes the property selector and opens the advanced popover directly in its initial empty state — where the user picks the first property inline via a "Where | [Select property ▾]" draft row. When no advanced filters exist yet, clicking this shortcut makes the AdvancedChip appear with the popover already open; closing without adding a filter removes the chip automatically.
958
+
959
+ **Dynamic options ("Me", "Unassigned", …):** enum/tags/relation properties accept a `dynamicOptions` array. Each entry is `{ value, label, description?, icon? }` and is rendered at the top of the SingleSelect / MultiSelect dropdown with a divider separating it from the regular options. The `value` is a sentinel string stored on `FilterCondition.value` — the DS only renders, the consuming app resolves it at query time (e.g. `"__me__"` → `currentUser.id`). This keeps session/business logic out of the DS while still getting a consistent visual treatment.
960
+
961
+ ```tsx
962
+ {
963
+ id: "contact_owner",
964
+ label: "Contact owner",
965
+ type: "enum",
966
+ icon: faUserOutline,
967
+ group: "contact",
968
+ groupLabel: "Contact",
969
+ options: ["Quentin", "Simon", "Philippe"],
970
+ dynamicOptions: [
971
+ {
972
+ value: "__me__",
973
+ label: "Me",
974
+ description: "This value is dynamically applied to the current user",
975
+ icon: faBoltOutline,
976
+ },
977
+ { value: "__deactivated__", label: "All deactivated and removed owners", icon: faBoltOutline },
978
+ ],
979
+ }
980
+ ```
955
981
 
956
982
  | Utility | Purpose |
957
983
  |---|---|
package/dist/index.d.mts CHANGED
@@ -357,7 +357,7 @@ interface NumberInputProps extends Omit<React.InputHTMLAttributes<HTMLInputEleme
357
357
  declare const NumberInput: React.ForwardRefExoticComponent<NumberInputProps & React.RefAttributes<HTMLInputElement>>;
358
358
 
359
359
  declare const typographyVariants: (props?: ({
360
- variant?: "xs" | "sm" | "md" | "lg" | "h2" | "h3" | "h1" | null | undefined;
360
+ variant?: "xs" | "sm" | "md" | "lg" | "h1" | "h2" | "h3" | null | undefined;
361
361
  weight?: "bold" | "regular" | "semibold" | null | undefined;
362
362
  } & class_variance_authority_types.ClassProp) | undefined) => string;
363
363
  interface TypographyProps extends React.HTMLAttributes<HTMLElement>, VariantProps<typeof typographyVariants> {
@@ -676,12 +676,28 @@ declare const FilterChip: React.ForwardRefExoticComponent<FilterChipProps & Reac
676
676
  type DataType = "text" | "number" | "date" | "enum" | "tags" | "boolean" | "relation";
677
677
  type TextOperator = "contains" | "does not contain" | "is" | "is not" | "starts with" | "ends with" | "is empty" | "is not empty";
678
678
  type NumberOperator = "=" | "≠" | ">" | "<" | "≥" | "≤" | "is between" | "is empty" | "is not empty";
679
- type DateOperator = "is" | "is before" | "is after" | "is on or before" | "is on or after" | "is between" | "is relative" | "is empty" | "is not empty";
679
+ type DateOperator = "is" | "is before" | "is after" | "is on or before" | "is on or after" | "is between" | "is empty" | "is not empty";
680
680
  type EnumOperator = "is" | "is not" | "is any of" | "is none of" | "is empty" | "is not empty";
681
681
  type TagsOperator = "contains" | "does not contain" | "contains any of" | "contains all of" | "is empty" | "is not empty";
682
682
  type BooleanOperator = "is true" | "is false";
683
683
  type RelationOperator = "is" | "is not" | "is any of" | "is none of" | "is empty" | "is not empty";
684
684
  type OperatorType = TextOperator | NumberOperator | DateOperator | EnumOperator | TagsOperator | BooleanOperator | RelationOperator;
685
+ /**
686
+ * A "smart" / dynamic option shown at the top of a relation or enum selector
687
+ * (e.g. "Me", "My team", "Unassigned"). The value is a sentinel string that
688
+ * the consuming app resolves at query time (e.g. `__me__` → `currentUser.id`).
689
+ *
690
+ * The design system only handles the rendering (icon + label + description +
691
+ * divider above the regular options). Resolving the sentinels is an app
692
+ * concern.
693
+ */
694
+ interface DynamicOption {
695
+ /** Sentinel value stored on FilterCondition.value (e.g. "__me__"). */
696
+ value: string;
697
+ label: string;
698
+ description?: string;
699
+ icon?: _l3mpire_icons.IconDefinition;
700
+ }
685
701
  interface PropertyDefinition {
686
702
  id: string;
687
703
  label: string;
@@ -690,6 +706,12 @@ interface PropertyDefinition {
690
706
  group: string;
691
707
  groupLabel: string;
692
708
  options?: string[];
709
+ /**
710
+ * Dynamic/smart options rendered at the top of the value selector with a
711
+ * divider. Only used for enum, tags, and relation types. The app resolves
712
+ * the sentinel values at query time.
713
+ */
714
+ dynamicOptions?: DynamicOption[];
693
715
  relationConfig?: {
694
716
  entity: string;
695
717
  displayProperty: string;
@@ -698,11 +720,14 @@ interface PropertyDefinition {
698
720
  };
699
721
  }
700
722
  type FilterValue = string | number | boolean | Date | [number, number] | [Date, Date] | string[] | null;
723
+ type LogicOperator = "and" | "or";
701
724
  interface FilterCondition {
702
725
  id: string;
703
726
  propertyId: string;
704
727
  operator: OperatorType | null;
705
728
  value: FilterValue;
729
+ /** Logic connector to the previous filter. Defaults to "and". */
730
+ logicOperator?: LogicOperator;
706
731
  }
707
732
  interface FilterState {
708
733
  basicFilters: FilterCondition[];
@@ -811,6 +836,8 @@ interface ValueInputProps {
811
836
  onChange: (value: FilterValue) => void;
812
837
  onSubmit?: () => void;
813
838
  options?: string[];
839
+ /** Dynamic/smart entries rendered at the top with a divider. */
840
+ dynamicOptions?: DynamicOption[];
814
841
  className?: string;
815
842
  }
816
843
  declare const ValueInput: React.FC<ValueInputProps>;
@@ -821,6 +848,13 @@ interface PropertySelectorProps {
821
848
  open?: boolean;
822
849
  onOpenChange?: (open: boolean) => void;
823
850
  children?: React.ReactNode;
851
+ /**
852
+ * When provided, renders an "Advanced filter" item at the bottom of the
853
+ * popover with a divider above it.
854
+ */
855
+ onAdvancedFilter?: () => void;
856
+ /** Count of existing advanced filter rules, displayed next to the item. */
857
+ advancedFilterCount?: number;
824
858
  }
825
859
  declare const PropertySelector: React.FC<PropertySelectorProps>;
826
860
 
@@ -865,10 +899,10 @@ declare const InteractiveFilterChip: React.FC<InteractiveFilterChipProps>;
865
899
  type FilterBarMode = "default" | "minimal";
866
900
  /**
867
901
  * Observes the container width and returns the appropriate FilterBar mode.
868
- * - default: > 600px
869
- * - minimal: ≤ 600px
902
+ * - default: > breakpoint
903
+ * - minimal: ≤ breakpoint
870
904
  */
871
- declare function useFilterBarMode(ref: React.RefObject<HTMLElement | null>, override?: FilterBarMode): FilterBarMode;
905
+ declare function useFilterBarMode(ref: React.RefObject<HTMLElement | null>, override?: FilterBarMode, breakpoint?: number): FilterBarMode;
872
906
 
873
907
  interface FilterSystemProps {
874
908
  properties: PropertyDefinition[];
@@ -877,6 +911,8 @@ interface FilterSystemProps {
877
911
  sortFields?: SortField[];
878
912
  /** Force a specific mode instead of auto-detecting via ResizeObserver. */
879
913
  mode?: FilterBarMode;
914
+ /** Width breakpoint (px) for switching to minimal mode. Default: 600. */
915
+ breakpoint?: number;
880
916
  children?: React.ReactNode;
881
917
  actions?: React.ReactNode;
882
918
  className?: string;
@@ -924,6 +960,9 @@ interface SummaryChipProps {
924
960
  /** Custom trigger element. When omitted, renders the default "Filters (N)" button. */
925
961
  children?: React.ReactNode;
926
962
  className?: string;
963
+ /** Controlled open state. */
964
+ open?: boolean;
965
+ onOpenChange?: (open: boolean) => void;
927
966
  }
928
967
  declare const SummaryChip: React.FC<SummaryChipProps>;
929
968
 
package/dist/index.d.ts CHANGED
@@ -357,7 +357,7 @@ interface NumberInputProps extends Omit<React.InputHTMLAttributes<HTMLInputEleme
357
357
  declare const NumberInput: React.ForwardRefExoticComponent<NumberInputProps & React.RefAttributes<HTMLInputElement>>;
358
358
 
359
359
  declare const typographyVariants: (props?: ({
360
- variant?: "xs" | "sm" | "md" | "lg" | "h2" | "h3" | "h1" | null | undefined;
360
+ variant?: "xs" | "sm" | "md" | "lg" | "h1" | "h2" | "h3" | null | undefined;
361
361
  weight?: "bold" | "regular" | "semibold" | null | undefined;
362
362
  } & class_variance_authority_types.ClassProp) | undefined) => string;
363
363
  interface TypographyProps extends React.HTMLAttributes<HTMLElement>, VariantProps<typeof typographyVariants> {
@@ -676,12 +676,28 @@ declare const FilterChip: React.ForwardRefExoticComponent<FilterChipProps & Reac
676
676
  type DataType = "text" | "number" | "date" | "enum" | "tags" | "boolean" | "relation";
677
677
  type TextOperator = "contains" | "does not contain" | "is" | "is not" | "starts with" | "ends with" | "is empty" | "is not empty";
678
678
  type NumberOperator = "=" | "≠" | ">" | "<" | "≥" | "≤" | "is between" | "is empty" | "is not empty";
679
- type DateOperator = "is" | "is before" | "is after" | "is on or before" | "is on or after" | "is between" | "is relative" | "is empty" | "is not empty";
679
+ type DateOperator = "is" | "is before" | "is after" | "is on or before" | "is on or after" | "is between" | "is empty" | "is not empty";
680
680
  type EnumOperator = "is" | "is not" | "is any of" | "is none of" | "is empty" | "is not empty";
681
681
  type TagsOperator = "contains" | "does not contain" | "contains any of" | "contains all of" | "is empty" | "is not empty";
682
682
  type BooleanOperator = "is true" | "is false";
683
683
  type RelationOperator = "is" | "is not" | "is any of" | "is none of" | "is empty" | "is not empty";
684
684
  type OperatorType = TextOperator | NumberOperator | DateOperator | EnumOperator | TagsOperator | BooleanOperator | RelationOperator;
685
+ /**
686
+ * A "smart" / dynamic option shown at the top of a relation or enum selector
687
+ * (e.g. "Me", "My team", "Unassigned"). The value is a sentinel string that
688
+ * the consuming app resolves at query time (e.g. `__me__` → `currentUser.id`).
689
+ *
690
+ * The design system only handles the rendering (icon + label + description +
691
+ * divider above the regular options). Resolving the sentinels is an app
692
+ * concern.
693
+ */
694
+ interface DynamicOption {
695
+ /** Sentinel value stored on FilterCondition.value (e.g. "__me__"). */
696
+ value: string;
697
+ label: string;
698
+ description?: string;
699
+ icon?: _l3mpire_icons.IconDefinition;
700
+ }
685
701
  interface PropertyDefinition {
686
702
  id: string;
687
703
  label: string;
@@ -690,6 +706,12 @@ interface PropertyDefinition {
690
706
  group: string;
691
707
  groupLabel: string;
692
708
  options?: string[];
709
+ /**
710
+ * Dynamic/smart options rendered at the top of the value selector with a
711
+ * divider. Only used for enum, tags, and relation types. The app resolves
712
+ * the sentinel values at query time.
713
+ */
714
+ dynamicOptions?: DynamicOption[];
693
715
  relationConfig?: {
694
716
  entity: string;
695
717
  displayProperty: string;
@@ -698,11 +720,14 @@ interface PropertyDefinition {
698
720
  };
699
721
  }
700
722
  type FilterValue = string | number | boolean | Date | [number, number] | [Date, Date] | string[] | null;
723
+ type LogicOperator = "and" | "or";
701
724
  interface FilterCondition {
702
725
  id: string;
703
726
  propertyId: string;
704
727
  operator: OperatorType | null;
705
728
  value: FilterValue;
729
+ /** Logic connector to the previous filter. Defaults to "and". */
730
+ logicOperator?: LogicOperator;
706
731
  }
707
732
  interface FilterState {
708
733
  basicFilters: FilterCondition[];
@@ -811,6 +836,8 @@ interface ValueInputProps {
811
836
  onChange: (value: FilterValue) => void;
812
837
  onSubmit?: () => void;
813
838
  options?: string[];
839
+ /** Dynamic/smart entries rendered at the top with a divider. */
840
+ dynamicOptions?: DynamicOption[];
814
841
  className?: string;
815
842
  }
816
843
  declare const ValueInput: React.FC<ValueInputProps>;
@@ -821,6 +848,13 @@ interface PropertySelectorProps {
821
848
  open?: boolean;
822
849
  onOpenChange?: (open: boolean) => void;
823
850
  children?: React.ReactNode;
851
+ /**
852
+ * When provided, renders an "Advanced filter" item at the bottom of the
853
+ * popover with a divider above it.
854
+ */
855
+ onAdvancedFilter?: () => void;
856
+ /** Count of existing advanced filter rules, displayed next to the item. */
857
+ advancedFilterCount?: number;
824
858
  }
825
859
  declare const PropertySelector: React.FC<PropertySelectorProps>;
826
860
 
@@ -865,10 +899,10 @@ declare const InteractiveFilterChip: React.FC<InteractiveFilterChipProps>;
865
899
  type FilterBarMode = "default" | "minimal";
866
900
  /**
867
901
  * Observes the container width and returns the appropriate FilterBar mode.
868
- * - default: > 600px
869
- * - minimal: ≤ 600px
902
+ * - default: > breakpoint
903
+ * - minimal: ≤ breakpoint
870
904
  */
871
- declare function useFilterBarMode(ref: React.RefObject<HTMLElement | null>, override?: FilterBarMode): FilterBarMode;
905
+ declare function useFilterBarMode(ref: React.RefObject<HTMLElement | null>, override?: FilterBarMode, breakpoint?: number): FilterBarMode;
872
906
 
873
907
  interface FilterSystemProps {
874
908
  properties: PropertyDefinition[];
@@ -877,6 +911,8 @@ interface FilterSystemProps {
877
911
  sortFields?: SortField[];
878
912
  /** Force a specific mode instead of auto-detecting via ResizeObserver. */
879
913
  mode?: FilterBarMode;
914
+ /** Width breakpoint (px) for switching to minimal mode. Default: 600. */
915
+ breakpoint?: number;
880
916
  children?: React.ReactNode;
881
917
  actions?: React.ReactNode;
882
918
  className?: string;
@@ -924,6 +960,9 @@ interface SummaryChipProps {
924
960
  /** Custom trigger element. When omitted, renders the default "Filters (N)" button. */
925
961
  children?: React.ReactNode;
926
962
  className?: string;
963
+ /** Controlled open state. */
964
+ open?: boolean;
965
+ onOpenChange?: (open: boolean) => void;
927
966
  }
928
967
  declare const SummaryChip: React.FC<SummaryChipProps>;
929
968