{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "filters",
  "title": "Filters",
  "description": "A composable filter builder with searchable fields, operators, select and multiselect values, text validation, keyboard shortcuts, and i18n labels.",
  "dependencies": [
    "class-variance-authority",
    "lucide-react"
  ],
  "registryDependencies": [
    "button",
    "button-group",
    "dropdown-menu",
    "input",
    "input-group",
    "kbd",
    "scroll-area",
    "tooltip"
  ],
  "files": [
    {
      "path": "registry/corr/components/filters.tsx",
      "content": "\"use client\"\n\nimport * as React from \"react\"\nimport { cva } from \"class-variance-authority\"\nimport {\n  AlertCircleIcon,\n  CheckIcon,\n  PlusIcon,\n  XIcon,\n} from \"lucide-react\"\n\nimport { Button } from \"@/components/ui/button\"\nimport { ButtonGroup, ButtonGroupText } from \"@/components/ui/button-group\"\nimport {\n  DropdownMenu,\n  DropdownMenuCheckboxItem,\n  DropdownMenuContent,\n  DropdownMenuGroup,\n  DropdownMenuItem,\n  DropdownMenuSeparator,\n  DropdownMenuSub,\n  DropdownMenuSubContent,\n  DropdownMenuSubTrigger,\n  DropdownMenuTrigger,\n} from \"@/components/ui/dropdown-menu\"\nimport { Input } from \"@/components/ui/input\"\nimport {\n  InputGroup,\n  InputGroupAddon,\n  InputGroupButton,\n  InputGroupInput,\n  InputGroupText,\n} from \"@/components/ui/input-group\"\nimport { Kbd } from \"@/components/ui/kbd\"\nimport { ScrollArea } from \"@/components/ui/scroll-area\"\nimport {\n  Tooltip,\n  TooltipContent,\n  TooltipProvider,\n  TooltipTrigger,\n} from \"@/components/ui/tooltip\"\nimport { cn } from \"@/lib/utils\"\n\nexport interface FilterI18nConfig {\n  addFilter: string\n  searchFields: string\n  noFieldsFound: string\n  noResultsFound: string\n  select: string\n  true: string\n  false: string\n  min: string\n  max: string\n  to: string\n  typeAndPressEnter: string\n  selected: string\n  selectedCount: string\n  percent: string\n  defaultCurrency: string\n  defaultColor: string\n  addFilterTitle: string\n  operators: {\n    is: string\n    isNot: string\n    isAnyOf: string\n    isNotAnyOf: string\n    includesAll: string\n    excludesAll: string\n    before: string\n    after: string\n    between: string\n    notBetween: string\n    contains: string\n    notContains: string\n    startsWith: string\n    endsWith: string\n    isExactly: string\n    equals: string\n    notEquals: string\n    greaterThan: string\n    lessThan: string\n    overlaps: string\n    includes: string\n    excludes: string\n    includesAllOf: string\n    includesAnyOf: string\n    empty: string\n    notEmpty: string\n  }\n  placeholders: {\n    enterField: (fieldType: string) => string\n    selectField: string\n    searchField: (fieldName: string) => string\n    enterKey: string\n    enterValue: string\n  }\n  helpers: {\n    formatOperator: (operator: string) => string\n  }\n  validation: {\n    invalidEmail: string\n    invalidUrl: string\n    invalidTel: string\n    invalid: string\n  }\n}\n\nexport const DEFAULT_I18N: FilterI18nConfig = {\n  addFilter: \"Filter\",\n  searchFields: \"Filter...\",\n  noFieldsFound: \"No filters found.\",\n  noResultsFound: \"No results found.\",\n  select: \"Select...\",\n  true: \"True\",\n  false: \"False\",\n  min: \"Min\",\n  max: \"Max\",\n  to: \"to\",\n  typeAndPressEnter: \"Type and press Enter to add tag\",\n  selected: \"selected\",\n  selectedCount: \"selected\",\n  percent: \"%\",\n  defaultCurrency: \"$\",\n  defaultColor: \"#000000\",\n  addFilterTitle: \"Add filter\",\n  operators: {\n    is: \"is\",\n    isNot: \"is not\",\n    isAnyOf: \"is any of\",\n    isNotAnyOf: \"is not any of\",\n    includesAll: \"includes all\",\n    excludesAll: \"excludes all\",\n    before: \"before\",\n    after: \"after\",\n    between: \"between\",\n    notBetween: \"not between\",\n    contains: \"contains\",\n    notContains: \"does not contain\",\n    startsWith: \"starts with\",\n    endsWith: \"ends with\",\n    isExactly: \"is exactly\",\n    equals: \"equals\",\n    notEquals: \"not equals\",\n    greaterThan: \"greater than\",\n    lessThan: \"less than\",\n    overlaps: \"overlaps\",\n    includes: \"includes\",\n    excludes: \"excludes\",\n    includesAllOf: \"includes all of\",\n    includesAnyOf: \"includes any of\",\n    empty: \"is empty\",\n    notEmpty: \"is not empty\",\n  },\n  placeholders: {\n    enterField: (fieldType: string) => `Enter ${fieldType}...`,\n    selectField: \"Select...\",\n    searchField: (fieldName: string) => `Search ${fieldName.toLowerCase()}...`,\n    enterKey: \"Enter key...\",\n    enterValue: \"Enter value...\",\n  },\n  helpers: {\n    formatOperator: (operator: string) => operator.replace(/_/g, \" \"),\n  },\n  validation: {\n    invalidEmail: \"Invalid email format\",\n    invalidUrl: \"Invalid URL format\",\n    invalidTel: \"Invalid phone format\",\n    invalid: \"Invalid input format\",\n  },\n}\n\ninterface FilterContextValue {\n  variant: \"solid\" | \"default\"\n  size: \"sm\" | \"default\" | \"lg\"\n  radius: \"default\" | \"full\"\n  i18n: FilterI18nConfig\n  className?: string\n  showSearchInput?: boolean\n  trigger?: React.ReactNode\n  allowMultiple?: boolean\n}\n\nconst FilterContext = React.createContext<FilterContextValue>({\n  variant: \"default\",\n  size: \"default\",\n  radius: \"default\",\n  i18n: DEFAULT_I18N,\n  className: undefined,\n  showSearchInput: true,\n  trigger: undefined,\n  allowMultiple: true,\n})\n\nfunction useFilterContext() {\n  return React.useContext(FilterContext)\n}\n\nconst filtersContainerVariants = cva(\"flex flex-wrap items-center\", {\n  variants: {\n    variant: {\n      solid: \"gap-2\",\n      default: \"\",\n    },\n    size: {\n      sm: \"gap-1.5\",\n      default: \"gap-2.5\",\n      lg: \"gap-3.5\",\n    },\n  },\n  defaultVariants: {\n    variant: \"default\",\n    size: \"default\",\n  },\n})\n\nconst filterControlHeight = {\n  sm: \"h-6!\",\n  default: \"h-7!\",\n  lg: \"h-8!\",\n} as const\n\nexport interface FilterOption<T = unknown> {\n  value: T\n  label: string\n  icon?: React.ReactNode\n  metadata?: Record<string, unknown>\n  className?: string\n}\n\nexport interface FilterOperator {\n  value: string\n  label: string\n  supportsMultiple?: boolean\n}\n\nexport interface CustomRendererProps<T = unknown> {\n  field: FilterFieldConfig<T>\n  values: T[]\n  onChange: (values: T[]) => void\n  operator: string\n}\n\nexport interface FilterFieldGroup<T = unknown> {\n  group?: string\n  fields: FilterFieldConfig<T>[]\n}\n\nexport type FilterFieldsConfig<T = unknown> =\n  | FilterFieldConfig<T>[]\n  | FilterFieldGroup<T>[]\n\nexport interface FilterFieldConfig<T = unknown> {\n  key?: string\n  label?: string\n  icon?: React.ReactNode\n  type?: \"select\" | \"multiselect\" | \"text\" | \"custom\" | \"separator\"\n  group?: string\n  fields?: FilterFieldConfig<T>[]\n  options?: FilterOption<T>[]\n  operators?: FilterOperator[]\n  customRenderer?: (props: CustomRendererProps<T>) => React.ReactNode\n  customValueRenderer?: (\n    values: T[],\n    options: FilterOption<T>[]\n  ) => React.ReactNode\n  placeholder?: string\n  searchable?: boolean\n  maxSelections?: number\n  min?: number\n  max?: number\n  step?: number\n  prefix?: string | React.ReactNode\n  suffix?: string | React.ReactNode\n  pattern?: string\n  validation?: (\n    value: unknown\n  ) => boolean | { valid: boolean; message?: string }\n  allowCustomValues?: boolean\n  className?: string\n  menuPopupClassName?: string\n  groupLabel?: string\n  onLabel?: string\n  offLabel?: string\n  onInputChange?: (event: React.ChangeEvent<HTMLInputElement>) => void\n  defaultOperator?: string\n  value?: T[]\n  onValueChange?: (values: T[]) => void\n}\n\nexport interface Filter<T = unknown> {\n  id: string\n  field: string\n  operator: string\n  values: T[]\n}\n\nexport interface FilterGroup<T = unknown> {\n  id: string\n  label?: string\n  filters: Filter<T>[]\n  fields: FilterFieldConfig<T>[]\n}\n\nfunction isFieldGroup<T = unknown>(\n  item: FilterFieldConfig<T> | FilterFieldGroup<T>\n): item is FilterFieldGroup<T> {\n  return \"fields\" in item && Array.isArray(item.fields)\n}\n\nfunction isGroupLevelField<T = unknown>(field: FilterFieldConfig<T>): boolean {\n  return Boolean(field.group && field.fields)\n}\n\nfunction flattenFields<T = unknown>(\n  fields: FilterFieldsConfig<T>\n): FilterFieldConfig<T>[] {\n  return fields.reduce<FilterFieldConfig<T>[]>((acc, item) => {\n    if (isFieldGroup(item)) {\n      return [...acc, ...item.fields]\n    }\n    if (isGroupLevelField(item)) {\n      return [...acc, ...(item.fields ?? [])]\n    }\n    return [...acc, item]\n  }, [])\n}\n\nfunction getFieldsMap<T = unknown>(\n  fields: FilterFieldsConfig<T>\n): Record<string, FilterFieldConfig<T>> {\n  return flattenFields(fields).reduce(\n    (acc, field) => {\n      if (field.key) {\n        acc[field.key] = field\n      }\n      return acc\n    },\n    {} as Record<string, FilterFieldConfig<T>>\n  )\n}\n\nfunction createOperatorsFromI18n(\n  i18n: FilterI18nConfig\n): Record<string, FilterOperator[]> {\n  return {\n    select: [\n      { value: \"is\", label: i18n.operators.is },\n      { value: \"is_not\", label: i18n.operators.isNot },\n      { value: \"empty\", label: i18n.operators.empty },\n      { value: \"not_empty\", label: i18n.operators.notEmpty },\n    ],\n    multiselect: [\n      { value: \"is_any_of\", label: i18n.operators.isAnyOf },\n      { value: \"is_not_any_of\", label: i18n.operators.isNotAnyOf },\n      { value: \"includes_all\", label: i18n.operators.includesAll },\n      { value: \"excludes_all\", label: i18n.operators.excludesAll },\n      { value: \"empty\", label: i18n.operators.empty },\n      { value: \"not_empty\", label: i18n.operators.notEmpty },\n    ],\n    text: [\n      { value: \"contains\", label: i18n.operators.contains },\n      { value: \"not_contains\", label: i18n.operators.notContains },\n      { value: \"starts_with\", label: i18n.operators.startsWith },\n      { value: \"ends_with\", label: i18n.operators.endsWith },\n      { value: \"is\", label: i18n.operators.isExactly },\n      { value: \"empty\", label: i18n.operators.empty },\n      { value: \"not_empty\", label: i18n.operators.notEmpty },\n    ],\n    custom: [\n      { value: \"is\", label: i18n.operators.is },\n      { value: \"after\", label: i18n.operators.after },\n      { value: \"between\", label: i18n.operators.between },\n      { value: \"empty\", label: i18n.operators.empty },\n      { value: \"not_empty\", label: i18n.operators.notEmpty },\n    ],\n  }\n}\n\nexport const DEFAULT_OPERATORS: Record<string, FilterOperator[]> =\n  createOperatorsFromI18n(DEFAULT_I18N)\n\nfunction getOperatorsForField<T = unknown>(\n  field: FilterFieldConfig<T>,\n  values: T[],\n  i18n: FilterI18nConfig\n): FilterOperator[] {\n  if (field.operators) return field.operators\n\n  const operators = createOperatorsFromI18n(i18n)\n  let fieldType = field.type ?? \"select\"\n\n  if (fieldType === \"select\" && values.length > 1) {\n    fieldType = \"multiselect\"\n  }\n\n  if (fieldType === \"multiselect\") {\n    return operators.multiselect\n  }\n\n  return operators[fieldType] ?? operators.select\n}\n\nfunction FilterInput<T = unknown>({\n  field,\n  onBlur,\n  onKeyDown,\n  className,\n  ...props\n}: React.InputHTMLAttributes<HTMLInputElement> & {\n  className?: string\n  field?: FilterFieldConfig<T>\n}) {\n  const context = useFilterContext()\n  const [isValid, setIsValid] = React.useState(true)\n  const [validationMessage, setValidationMessage] = React.useState(\"\")\n  const inputRef = React.useRef<HTMLInputElement>(null)\n\n  React.useEffect(() => {\n    if (!props.autoFocus) return undefined\n\n    const timer = window.setTimeout(() => {\n      inputRef.current?.focus()\n    }, 300)\n\n    return () => window.clearTimeout(timer)\n  }, [props.autoFocus])\n\n  function validateInput(value: string, pattern?: string): boolean {\n    if (!pattern || !value) return true\n    return new RegExp(pattern).test(value)\n  }\n\n  function handleBlur(event: React.FocusEvent<HTMLInputElement>) {\n    const value = event.target.value\n    const pattern = field?.pattern ?? props.pattern\n\n    if (value && (pattern || field?.validation)) {\n      let valid = true\n      let customMessage = \"\"\n\n      if (field?.validation) {\n        const result = field.validation(value)\n        if (typeof result === \"boolean\") {\n          valid = result\n        } else {\n          valid = result.valid\n          customMessage = result.message ?? \"\"\n        }\n      } else if (pattern) {\n        valid = validateInput(value, pattern)\n      }\n\n      setIsValid(valid)\n      setValidationMessage(\n        valid ? \"\" : customMessage || context.i18n.validation.invalid\n      )\n    } else {\n      setIsValid(true)\n      setValidationMessage(\"\")\n    }\n\n    onBlur?.(event)\n  }\n\n  function handleKeyDown(event: React.KeyboardEvent<HTMLInputElement>) {\n    if (\n      !isValid &&\n      ![\n        \"Tab\",\n        \"Escape\",\n        \"Enter\",\n        \"ArrowUp\",\n        \"ArrowDown\",\n        \"ArrowLeft\",\n        \"ArrowRight\",\n      ].includes(event.key)\n    ) {\n      setIsValid(true)\n      setValidationMessage(\"\")\n    }\n\n    onKeyDown?.(event)\n  }\n\n  return (\n    <InputGroup\n      className={cn(\n        \"w-36\",\n        \"has-[[data-slot=input-group-control]:focus-visible]:border-input\",\n        \"has-[[data-slot=input-group-control]:focus-visible]:ring-0\",\n        \"has-[[data-slot=input-group-control]:focus-visible]:ring-transparent\",\n        filterControlHeight[context.size],\n        className\n      )}\n    >\n      {field?.prefix ? (\n        <InputGroupAddon>\n          <InputGroupText>{field.prefix}</InputGroupText>\n        </InputGroupAddon>\n      ) : null}\n      <InputGroupInput\n        ref={inputRef}\n        aria-invalid={!isValid}\n        aria-describedby={\n          !isValid && validationMessage\n            ? `${field?.key ?? \"input\"}-error`\n            : undefined\n        }\n        onBlur={handleBlur}\n        onKeyDown={handleKeyDown}\n        className={cn(\n          \"focus-visible:border-transparent focus-visible:ring-0 focus-visible:ring-offset-0\",\n          filterControlHeight[context.size],\n          context.size === \"sm\" && \"text-xs\"\n        )}\n        {...props}\n      />\n      {!isValid && validationMessage ? (\n        <InputGroupAddon align=\"inline-end\">\n          <TooltipProvider>\n            <Tooltip>\n              <TooltipTrigger asChild>\n                <InputGroupButton size=\"icon-xs\">\n                  <AlertCircleIcon className=\"size-3.5 text-destructive\" />\n                </InputGroupButton>\n              </TooltipTrigger>\n              <TooltipContent>\n                <p className=\"text-sm\">{validationMessage}</p>\n              </TooltipContent>\n            </Tooltip>\n          </TooltipProvider>\n        </InputGroupAddon>\n      ) : null}\n      {field?.suffix ? (\n        <InputGroupAddon align=\"inline-end\">\n          <InputGroupText>{field.suffix}</InputGroupText>\n        </InputGroupAddon>\n      ) : null}\n    </InputGroup>\n  )\n}\n\nfunction FilterRemoveButton({\n  icon = <XIcon />,\n  ...props\n}: React.ButtonHTMLAttributes<HTMLButtonElement> & {\n  icon?: React.ReactNode\n}) {\n  const context = useFilterContext()\n\n  return (\n    <Button\n      variant=\"outline\"\n      size={\n        context.size === \"sm\"\n          ? \"icon-sm\"\n          : context.size === \"lg\"\n            ? \"icon-lg\"\n            : \"icon\"\n      }\n      {...props}\n    >\n      {icon}\n    </Button>\n  )\n}\n\nfunction FilterOperatorDropdown<T = unknown>({\n  field,\n  operator,\n  values,\n  onChange,\n}: {\n  field: FilterFieldConfig<T>\n  operator: string\n  values: T[]\n  onChange: (operator: string) => void\n}) {\n  const context = useFilterContext()\n  const operators = getOperatorsForField(field, values, context.i18n)\n  const operatorLabel =\n    operators.find((item) => item.value === operator)?.label ??\n    context.i18n.helpers.formatOperator(operator)\n\n  return (\n    <DropdownMenu>\n      <DropdownMenuTrigger asChild>\n        <Button\n          variant=\"outline\"\n          size={context.size}\n          className=\"text-muted-foreground hover:text-foreground\"\n        >\n          {operatorLabel}\n        </Button>\n      </DropdownMenuTrigger>\n      <DropdownMenuContent align=\"start\" className=\"z-[200] w-fit min-w-fit\">\n        {operators.map((item) => (\n          <DropdownMenuItem\n            key={item.value}\n            onClick={() => onChange(item.value)}\n            className=\"flex items-center justify-between data-highlighted:bg-accent data-highlighted:text-accent-foreground\"\n          >\n            <span>{item.label}</span>\n            <CheckIcon\n              className={cn(\n                \"ms-auto size-4 text-primary\",\n                item.value === operator ? \"opacity-100\" : \"opacity-0\"\n              )}\n            />\n          </DropdownMenuItem>\n        ))}\n      </DropdownMenuContent>\n    </DropdownMenu>\n  )\n}\n\nfunction SelectOptionsPopover<T = unknown>({\n  field,\n  values,\n  onChange,\n  onClose,\n  inline = false,\n}: {\n  field: FilterFieldConfig<T>\n  values: T[]\n  onChange: (values: T[]) => void\n  onClose?: () => void\n  inline?: boolean\n}) {\n  const [open, setOpen] = React.useState(false)\n  const [searchInput, setSearchInput] = React.useState(\"\")\n  const [highlightedIndex, setHighlightedIndex] = React.useState(-1)\n  const keyboardNavigationRef = React.useRef(false)\n  const inputRef = React.useRef<HTMLInputElement>(null)\n  const context = useFilterContext()\n  const baseId = React.useId()\n  const isMultiSelect = field.type === \"multiselect\" || values.length > 1\n  const effectiveValues = field.value !== undefined ? field.value : values\n  const selectedOptions =\n    field.options?.filter((item) => effectiveValues.includes(item.value)) ?? []\n  const unselectedOptions =\n    field.options?.filter((item) => !effectiveValues.includes(item.value)) ?? []\n  const filteredSelectedOptions = selectedOptions\n  const filteredUnselectedOptions = unselectedOptions.filter((item) =>\n    item.label.toLowerCase().includes(searchInput.toLowerCase())\n  )\n  const allFilteredOptions = React.useMemo(\n    () => [...filteredSelectedOptions, ...filteredUnselectedOptions],\n    [filteredSelectedOptions, filteredUnselectedOptions]\n  )\n\n  React.useEffect(() => {\n    setHighlightedIndex(-1)\n  }, [searchInput, open])\n\n  React.useEffect(() => {\n    if (highlightedIndex >= 0 && open && keyboardNavigationRef.current) {\n      document\n        .getElementById(`${baseId}-item-${highlightedIndex}`)\n        ?.scrollIntoView({ block: \"nearest\" })\n    }\n  }, [baseId, highlightedIndex, open])\n\n  function handleClose() {\n    setOpen(false)\n    onClose?.()\n  }\n\n  function updateValues(next: T[]) {\n    if (field.onValueChange) {\n      field.onValueChange(next)\n    } else {\n      onChange(next)\n    }\n  }\n\n  function renderMenuContent() {\n    return (\n      <>\n        {field.searchable !== false ? (\n          <>\n            <Input\n              ref={inputRef}\n              role=\"combobox\"\n              aria-autocomplete=\"list\"\n              aria-expanded={true}\n              aria-haspopup=\"listbox\"\n              aria-controls={`${baseId}-listbox`}\n              aria-activedescendant={\n                highlightedIndex >= 0\n                  ? `${baseId}-item-${highlightedIndex}`\n                  : undefined\n              }\n              placeholder={context.i18n.placeholders.searchField(\n                field.label ?? \"\"\n              )}\n              className={cn(\n                \"h-8 rounded-none border-0 bg-transparent! px-2 text-sm shadow-none\",\n                \"focus-visible:border-border focus-visible:ring-0 focus-visible:ring-offset-0\"\n              )}\n              value={searchInput}\n              onChange={(event) => setSearchInput(event.target.value)}\n              onClick={(event) => event.stopPropagation()}\n              onKeyDown={(event) => {\n                if (event.key === \"ArrowDown\") {\n                  event.preventDefault()\n                  keyboardNavigationRef.current = true\n                  if (allFilteredOptions.length > 0) {\n                    setHighlightedIndex((previous) =>\n                      previous < allFilteredOptions.length - 1\n                        ? previous + 1\n                        : 0\n                    )\n                  }\n                } else if (event.key === \"ArrowUp\") {\n                  event.preventDefault()\n                  keyboardNavigationRef.current = true\n                  if (allFilteredOptions.length > 0) {\n                    setHighlightedIndex((previous) =>\n                      previous > 0\n                        ? previous - 1\n                        : allFilteredOptions.length - 1\n                    )\n                  }\n                } else if (event.key === \"ArrowLeft\") {\n                  event.preventDefault()\n                  setOpen(false)\n                } else if (event.key === \"Enter\" && highlightedIndex >= 0) {\n                  event.preventDefault()\n                  const option = allFilteredOptions[highlightedIndex]\n                  if (option) {\n                    const isSelected = effectiveValues.includes(option.value)\n                    const next = isSelected\n                      ? effectiveValues.filter(\n                          (value) => value !== option.value\n                        )\n                      : isMultiSelect\n                        ? [...effectiveValues, option.value]\n                        : [option.value]\n\n                    if (\n                      !isSelected &&\n                      isMultiSelect &&\n                      field.maxSelections &&\n                      next.length > field.maxSelections\n                    ) {\n                      return\n                    }\n\n                    updateValues(next as T[])\n                    if (!isMultiSelect) handleClose()\n                  }\n                }\n                event.stopPropagation()\n              }}\n            />\n            <DropdownMenuSeparator />\n          </>\n        ) : null}\n        <div className=\"relative flex max-h-full\">\n          <div\n            className=\"flex max-h-[min(var(--radix-dropdown-menu-content-available-height),24rem)] w-full scroll-pt-2 scroll-pb-2 flex-col overscroll-contain\"\n            role=\"listbox\"\n            id={`${baseId}-listbox`}\n          >\n            <ScrollArea className=\"size-full min-h-0 **:data-[slot=scroll-area-scrollbar]:m-0 **:data-[slot=scroll-area-viewport]:h-full **:data-[slot=scroll-area-viewport]:overscroll-contain\">\n              {allFilteredOptions.length === 0 ? (\n                <div className=\"py-2 text-center text-sm text-muted-foreground\">\n                  {context.i18n.noResultsFound}\n                </div>\n              ) : null}\n\n              {filteredSelectedOptions.length > 0 ? (\n                <DropdownMenuGroup className=\"px-1\">\n                  {filteredSelectedOptions.map((option, index) => (\n                    <DropdownMenuCheckboxItem\n                      key={String(option.value)}\n                      id={`${baseId}-item-${index}`}\n                      role=\"option\"\n                      aria-selected={highlightedIndex === index}\n                      data-highlighted={\n                        keyboardNavigationRef.current &&\n                        highlightedIndex === index\n                          ? true\n                          : undefined\n                      }\n                      checked={true}\n                      className={cn(\n                        \"gap-1.5 data-highlighted:bg-accent\",\n                        option.className\n                      )}\n                      onSelect={(event) => {\n                        if (isMultiSelect) event.preventDefault()\n                      }}\n                      onCheckedChange={() => {\n                        const next = effectiveValues.filter(\n                          (value) => value !== option.value\n                        )\n                        updateValues(next as T[])\n                        if (!isMultiSelect) handleClose()\n                      }}\n                    >\n                      {option.icon}\n                      <span className=\"truncate\">{option.label}</span>\n                    </DropdownMenuCheckboxItem>\n                  ))}\n                </DropdownMenuGroup>\n              ) : null}\n\n              {filteredSelectedOptions.length > 0 &&\n              filteredUnselectedOptions.length > 0 ? (\n                <DropdownMenuSeparator className=\"mx-0\" />\n              ) : null}\n\n              {filteredUnselectedOptions.length > 0 ? (\n                <DropdownMenuGroup className=\"px-1\">\n                  {filteredUnselectedOptions.map((option, index) => {\n                    const overallIndex = index + filteredSelectedOptions.length\n                    return (\n                      <DropdownMenuCheckboxItem\n                        key={String(option.value)}\n                        id={`${baseId}-item-${overallIndex}`}\n                        role=\"option\"\n                        aria-selected={highlightedIndex === overallIndex}\n                        data-highlighted={\n                          keyboardNavigationRef.current &&\n                          highlightedIndex === overallIndex\n                            ? true\n                            : undefined\n                        }\n                        checked={false}\n                        className={cn(\n                          \"gap-1.5 data-highlighted:bg-accent\",\n                          option.className\n                        )}\n                        onSelect={(event) => {\n                          if (isMultiSelect) event.preventDefault()\n                        }}\n                        onCheckedChange={() => {\n                          const next = isMultiSelect\n                            ? [...effectiveValues, option.value]\n                            : [option.value]\n\n                          if (\n                            isMultiSelect &&\n                            field.maxSelections &&\n                            next.length > field.maxSelections\n                          ) {\n                            return\n                          }\n\n                          updateValues(next as T[])\n                          if (!isMultiSelect) handleClose()\n                        }}\n                      >\n                        {option.icon}\n                        <span className=\"truncate\">{option.label}</span>\n                      </DropdownMenuCheckboxItem>\n                    )\n                  })}\n                </DropdownMenuGroup>\n              ) : null}\n            </ScrollArea>\n          </div>\n        </div>\n      </>\n    )\n  }\n\n  if (inline) {\n    return <div className=\"w-full\">{renderMenuContent()}</div>\n  }\n\n  return (\n    <DropdownMenu\n      open={open}\n      onOpenChange={(nextOpen) => {\n        setOpen(nextOpen)\n        if (!nextOpen) {\n          window.setTimeout(() => setSearchInput(\"\"), 200)\n        }\n      }}\n    >\n      <DropdownMenuTrigger asChild>\n        <Button variant=\"outline\" size={context.size}>\n          <div className=\"flex items-center gap-1.5\">\n            {field.customValueRenderer ? (\n              field.customValueRenderer(values, field.options ?? [])\n            ) : (\n              <>\n                {selectedOptions.length > 0 ? (\n                  <div className=\"flex items-center -space-x-1.5\">\n                    {selectedOptions.slice(0, 3).map((option) => (\n                      <div key={String(option.value)}>{option.icon}</div>\n                    ))}\n                  </div>\n                ) : null}\n                {selectedOptions.length === 1 ? (\n                  selectedOptions[0].label\n                ) : selectedOptions.length > 1 ? (\n                  `${selectedOptions.length} ${context.i18n.selectedCount}`\n                ) : (\n                  context.i18n.select\n                )}\n              </>\n            )}\n          </div>\n        </Button>\n      </DropdownMenuTrigger>\n      <DropdownMenuContent\n        align=\"start\"\n        className={cn(\n          \"z-[200] w-[10.5rem] bg-popover px-0 before:hidden\",\n          field.className\n        )}\n      >\n        {renderMenuContent()}\n      </DropdownMenuContent>\n    </DropdownMenu>\n  )\n}\n\nfunction FilterValueSelector<T = unknown>({\n  field,\n  values,\n  onChange,\n  operator,\n  autoFocus,\n}: {\n  field: FilterFieldConfig<T>\n  values: T[]\n  onChange: (values: T[]) => void\n  operator: string\n  autoFocus?: boolean\n}) {\n  const context = useFilterContext()\n\n  if (operator === \"empty\" || operator === \"not_empty\") return null\n\n  if (field.customRenderer) {\n    return (\n      <ButtonGroupText\n        className={cn(\n          \"bg-background text-start whitespace-nowrap outline-hidden hover:bg-accent aria-expanded:bg-accent dark:bg-input/30\",\n          filterControlHeight[context.size]\n        )}\n      >\n        {field.customRenderer({ field, values, onChange, operator })}\n      </ButtonGroupText>\n    )\n  }\n\n  if (field.type === \"text\") {\n    return (\n      <FilterInput\n        type=\"text\"\n        value={(values[0] as string) ?? \"\"}\n        onChange={(event) => onChange([event.target.value] as T[])}\n        placeholder={field.placeholder}\n        pattern={field.pattern}\n        field={field}\n        className={cn(\"w-36\", field.className)}\n        autoFocus={autoFocus}\n      />\n    )\n  }\n\n  return (\n    <SelectOptionsPopover field={field} values={values} onChange={onChange} />\n  )\n}\n\nexport interface FiltersContentProps<T = unknown> {\n  filters: Filter<T>[]\n  fields: FilterFieldsConfig<T>\n  onChange: (filters: Filter<T>[]) => void\n}\n\nexport function FiltersContent<T = unknown>({\n  filters,\n  fields,\n  onChange,\n}: FiltersContentProps<T>) {\n  const context = useFilterContext()\n  const fieldsMap = React.useMemo(() => getFieldsMap(fields), [fields])\n\n  const updateFilter = React.useCallback(\n    (filterId: string, updates: Partial<Filter<T>>) => {\n      onChange(\n        filters.map((filter) => {\n          if (filter.id !== filterId) return filter\n          const updatedFilter = { ...filter, ...updates }\n          if (\n            updates.operator === \"empty\" ||\n            updates.operator === \"not_empty\"\n          ) {\n            updatedFilter.values = [] as T[]\n          }\n          return updatedFilter\n        })\n      )\n    },\n    [filters, onChange]\n  )\n\n  const removeFilter = React.useCallback(\n    (filterId: string) => {\n      onChange(filters.filter((filter) => filter.id !== filterId))\n    },\n    [filters, onChange]\n  )\n\n  return (\n    <div\n      className={cn(\n        filtersContainerVariants({\n          variant: context.variant,\n          size: context.size,\n        }),\n        context.className\n      )}\n    >\n      {filters.map((filter) => {\n        const field = fieldsMap[filter.field]\n        if (!field) return null\n\n        return (\n          <ButtonGroup key={filter.id}>\n            <ButtonGroupText className={filterControlHeight[context.size]}>\n              {field.icon}\n              {field.label}\n            </ButtonGroupText>\n            <FilterOperatorDropdown<T>\n              field={field}\n              operator={filter.operator}\n              values={filter.values}\n              onChange={(operator) => updateFilter(filter.id, { operator })}\n            />\n            <FilterValueSelector<T>\n              field={field}\n              values={filter.values}\n              onChange={(values) => updateFilter(filter.id, { values })}\n              operator={filter.operator}\n              autoFocus={false}\n            />\n            <FilterRemoveButton onClick={() => removeFilter(filter.id)} />\n          </ButtonGroup>\n        )\n      })}\n    </div>\n  )\n}\n\nexport interface FiltersProps<T = unknown> {\n  filters: Filter<T>[]\n  fields: FilterFieldsConfig<T>\n  onChange: (filters: Filter<T>[]) => void\n  className?: string\n  variant?: \"solid\" | \"default\"\n  size?: \"sm\" | \"default\" | \"lg\"\n  radius?: \"default\" | \"full\"\n  i18n?: Partial<\n    Omit<\n      FilterI18nConfig,\n      \"operators\" | \"placeholders\" | \"helpers\" | \"validation\"\n    >\n  > & {\n    operators?: Partial<FilterI18nConfig[\"operators\"]>\n    placeholders?: Partial<FilterI18nConfig[\"placeholders\"]>\n    helpers?: Partial<FilterI18nConfig[\"helpers\"]>\n    validation?: Partial<FilterI18nConfig[\"validation\"]>\n  }\n  showSearchInput?: boolean\n  trigger?: React.ReactNode\n  allowMultiple?: boolean\n  menuPopupClassName?: string\n  collapseAddButton?: boolean\n  enableShortcut?: boolean\n  shortcutKey?: string\n  shortcutLabel?: string\n}\n\nfunction FilterSubmenuContent<T = unknown>({\n  field,\n  currentValues,\n  isMultiSelect,\n  onToggle,\n  i18n,\n  isActive,\n  onActive,\n  onBack,\n  onClose,\n}: {\n  field: FilterFieldConfig<T>\n  currentValues: T[]\n  isMultiSelect: boolean\n  onToggle: (value: T, isSelected: boolean) => void\n  i18n: FilterI18nConfig\n  isActive?: boolean\n  onActive?: () => void\n  onBack?: () => void\n  onClose?: () => void\n}) {\n  const [searchInput, setSearchInput] = React.useState(\"\")\n  const [highlightedIndex, setHighlightedIndex] = React.useState(-1)\n  const keyboardNavigationRef = React.useRef(false)\n  const inputRef = React.useRef<HTMLInputElement>(null)\n  const baseId = React.useId()\n  const filteredOptions = React.useMemo(() => {\n    return (\n      field.options?.filter((option) => {\n        const isSelected = currentValues.includes(option.value)\n        if (isSelected || !searchInput) return true\n        return option.label.toLowerCase().includes(searchInput.toLowerCase())\n      }) ?? []\n    )\n  }, [currentValues, field.options, searchInput])\n\n  React.useEffect(() => {\n    setHighlightedIndex(-1)\n  }, [searchInput])\n\n  React.useEffect(() => {\n    if (highlightedIndex >= 0 && isActive && keyboardNavigationRef.current) {\n      document\n        .getElementById(`${baseId}-item-${highlightedIndex}`)\n        ?.scrollIntoView({ block: \"nearest\" })\n    }\n  }, [baseId, highlightedIndex, isActive])\n\n  React.useEffect(() => {\n    if (isActive && filteredOptions.length > 0) {\n      setHighlightedIndex(0)\n    }\n  }, [filteredOptions.length, isActive])\n\n  function handleOptionToggle(option: FilterOption<T>) {\n    onToggle(option.value as T, currentValues.includes(option.value))\n    if (!isMultiSelect) {\n      onBack?.()\n    }\n  }\n\n  function handleKeyDown(event: React.KeyboardEvent) {\n    if (event.key === \"ArrowDown\") {\n      event.preventDefault()\n      keyboardNavigationRef.current = true\n      if (filteredOptions.length > 0) {\n        setHighlightedIndex((previous) =>\n          previous < filteredOptions.length - 1 ? previous + 1 : 0\n        )\n      }\n    } else if (event.key === \"ArrowUp\") {\n      event.preventDefault()\n      keyboardNavigationRef.current = true\n      if (filteredOptions.length > 0) {\n        setHighlightedIndex((previous) =>\n          previous > 0 ? previous - 1 : filteredOptions.length - 1\n        )\n      }\n    } else if (event.key === \"ArrowLeft\") {\n      event.preventDefault()\n      onBack?.()\n    } else if (event.key === \"Enter\" && highlightedIndex >= 0) {\n      event.preventDefault()\n      const option = filteredOptions[highlightedIndex]\n      if (option) handleOptionToggle(option)\n    } else if (event.key === \"Escape\") {\n      event.preventDefault()\n      onClose?.()\n    }\n    event.stopPropagation()\n  }\n\n  return (\n    <div className=\"flex flex-col\" onFocus={onActive}>\n      {field.searchable !== false ? (\n        <>\n          <Input\n            ref={inputRef}\n            role=\"combobox\"\n            aria-autocomplete=\"list\"\n            aria-expanded={true}\n            aria-haspopup=\"listbox\"\n            aria-controls={`${baseId}-listbox`}\n            aria-activedescendant={\n              highlightedIndex >= 0\n                ? `${baseId}-item-${highlightedIndex}`\n                : undefined\n            }\n            placeholder={i18n.placeholders.searchField(field.label ?? \"\")}\n            className={cn(\n              \"h-8 rounded-none border-0 bg-transparent! px-2 text-sm shadow-none\",\n              \"focus-visible:border-border focus-visible:ring-0 focus-visible:ring-offset-0\"\n            )}\n            value={searchInput}\n            onChange={(event) => setSearchInput(event.target.value)}\n            onClick={(event) => event.stopPropagation()}\n            onKeyDown={handleKeyDown}\n          />\n          <DropdownMenuSeparator />\n        </>\n      ) : null}\n      <div className=\"relative flex max-h-full\">\n        <div\n          className=\"flex max-h-[min(var(--radix-dropdown-menu-content-available-height),24rem)] w-full scroll-pt-2 scroll-pb-2 flex-col overscroll-contain outline-hidden\"\n          role=\"listbox\"\n          id={`${baseId}-listbox`}\n          tabIndex={field.searchable === false ? 0 : -1}\n          onKeyDown={field.searchable === false ? handleKeyDown : undefined}\n        >\n          <ScrollArea className=\"size-full min-h-0 **:data-[slot=scroll-area-scrollbar]:m-0 **:data-[slot=scroll-area-viewport]:h-full **:data-[slot=scroll-area-viewport]:overscroll-contain\">\n            {filteredOptions.length === 0 ? (\n              <div className=\"py-2 text-center text-sm text-muted-foreground\">\n                {i18n.noResultsFound}\n              </div>\n            ) : (\n              <DropdownMenuGroup>\n                {filteredOptions.map((option, index) => {\n                  const isSelected = currentValues.includes(option.value)\n                  const isHighlighted = highlightedIndex === index\n\n                  return (\n                    <DropdownMenuCheckboxItem\n                      key={String(option.value)}\n                      id={`${baseId}-item-${index}`}\n                      role=\"option\"\n                      aria-selected={isHighlighted}\n                      data-highlighted={\n                        keyboardNavigationRef.current && isHighlighted\n                          ? true\n                          : undefined\n                      }\n                      checked={isSelected}\n                      className={cn(\n                        \"gap-1.5 data-highlighted:bg-accent\",\n                        option.className\n                      )}\n                      onSelect={(event) => {\n                        if (isMultiSelect) event.preventDefault()\n                      }}\n                      onCheckedChange={() => handleOptionToggle(option)}\n                    >\n                      {option.icon}\n                      <span className=\"truncate\">{option.label}</span>\n                    </DropdownMenuCheckboxItem>\n                  )\n                })}\n              </DropdownMenuGroup>\n            )}\n          </ScrollArea>\n        </div>\n      </div>\n    </div>\n  )\n}\n\nexport function Filters<T = unknown>({\n  filters,\n  fields,\n  onChange,\n  className,\n  variant = \"default\",\n  size = \"default\",\n  radius = \"default\",\n  i18n,\n  showSearchInput = true,\n  trigger,\n  allowMultiple = true,\n  menuPopupClassName,\n  enableShortcut = false,\n  shortcutKey = \"f\",\n  shortcutLabel = \"F\",\n}: FiltersProps<T>) {\n  const [addFilterOpen, setAddFilterOpen] = React.useState(false)\n  const [menuSearchInput, setMenuSearchInput] = React.useState(\"\")\n  const [activeMenu, setActiveMenu] = React.useState(\"root\")\n  const [openSubMenu, setOpenSubMenu] = React.useState<string | null>(null)\n  const [highlightedIndex, setHighlightedIndex] = React.useState(-1)\n  const keyboardNavigationRef = React.useRef(false)\n  const [lastAddedFilterId, setLastAddedFilterId] = React.useState<\n    string | null\n  >(null)\n  const [sessionFilterIds, setSessionFilterIds] = React.useState<\n    Record<string, string>\n  >({})\n  const rootInputRef = React.useRef<HTMLInputElement>(null)\n  const rootId = React.useId()\n  const mergedI18n: FilterI18nConfig = {\n    ...DEFAULT_I18N,\n    ...i18n,\n    operators: { ...DEFAULT_I18N.operators, ...i18n?.operators },\n    placeholders: { ...DEFAULT_I18N.placeholders, ...i18n?.placeholders },\n    validation: { ...DEFAULT_I18N.validation, ...i18n?.validation },\n    helpers: { ...DEFAULT_I18N.helpers, ...i18n?.helpers },\n  }\n  const fieldsMap = React.useMemo(() => getFieldsMap(fields), [fields])\n  const selectableFields = React.useMemo(() => {\n    return flattenFields(fields).filter((field) => {\n      if (!field.key || field.type === \"separator\") return false\n      if (allowMultiple) return true\n      return !filters.some((filter) => filter.field === field.key)\n    })\n  }, [allowMultiple, fields, filters])\n  const filteredFields = React.useMemo(() => {\n    return selectableFields.filter(\n      (field) =>\n        !menuSearchInput ||\n        field.label?.toLowerCase().includes(menuSearchInput.toLowerCase())\n    )\n  }, [menuSearchInput, selectableFields])\n\n  React.useEffect(() => {\n    if (!enableShortcut) return undefined\n\n    function handleKeyDown(event: KeyboardEvent) {\n      if (\n        event.key.toLowerCase() === shortcutKey.toLowerCase() &&\n        !addFilterOpen &&\n        !(\n          document.activeElement instanceof HTMLInputElement ||\n          document.activeElement instanceof HTMLTextAreaElement\n        )\n      ) {\n        event.preventDefault()\n        setAddFilterOpen(true)\n      }\n    }\n\n    window.addEventListener(\"keydown\", handleKeyDown)\n    return () => window.removeEventListener(\"keydown\", handleKeyDown)\n  }, [addFilterOpen, enableShortcut, shortcutKey])\n\n  React.useEffect(() => {\n    setHighlightedIndex(-1)\n  }, [menuSearchInput])\n\n  React.useEffect(() => {\n    if (highlightedIndex >= 0 && addFilterOpen && keyboardNavigationRef.current) {\n      document\n        .getElementById(`${rootId}-item-${highlightedIndex}`)\n        ?.scrollIntoView({ block: \"nearest\" })\n    }\n  }, [addFilterOpen, highlightedIndex, rootId])\n\n  React.useEffect(() => {\n    if (!addFilterOpen) setOpenSubMenu(null)\n  }, [addFilterOpen])\n\n  React.useEffect(() => {\n    if (!lastAddedFilterId) return undefined\n    const timer = window.setTimeout(() => setLastAddedFilterId(null), 1000)\n    return () => window.clearTimeout(timer)\n  }, [lastAddedFilterId])\n\n  React.useEffect(() => {\n    if (addFilterOpen && filteredFields.length > 0) {\n      setHighlightedIndex(0)\n    }\n  }, [addFilterOpen, filteredFields.length])\n\n  const updateFilter = React.useCallback(\n    (filterId: string, updates: Partial<Filter<T>>) => {\n      onChange(\n        filters.map((filter) => {\n          if (filter.id !== filterId) return filter\n          const updatedFilter = { ...filter, ...updates }\n          if (\n            updates.operator === \"empty\" ||\n            updates.operator === \"not_empty\"\n          ) {\n            updatedFilter.values = [] as T[]\n          }\n          return updatedFilter\n        })\n      )\n    },\n    [filters, onChange]\n  )\n\n  const removeFilter = React.useCallback(\n    (filterId: string) => {\n      onChange(filters.filter((filter) => filter.id !== filterId))\n    },\n    [filters, onChange]\n  )\n\n  const addFilter = React.useCallback(\n    (fieldKey: string) => {\n      const field = fieldsMap[fieldKey]\n      if (!field?.key) return\n\n      const defaultOperator =\n        field.defaultOperator ??\n        (field.type === \"multiselect\" ? \"is_any_of\" : \"is\")\n      const defaultValues: unknown[] = field.type === \"text\" ? [\"\"] : []\n      const newFilter = createFilter<T>(\n        fieldKey,\n        defaultOperator,\n        defaultValues as T[]\n      )\n\n      setLastAddedFilterId(newFilter.id)\n      onChange([...filters, newFilter])\n      setAddFilterOpen(false)\n      setMenuSearchInput(\"\")\n    },\n    [fieldsMap, filters, onChange]\n  )\n\n  function handleRootKeyDown(event: React.KeyboardEvent<HTMLInputElement>) {\n    if (event.key === \"ArrowDown\") {\n      event.preventDefault()\n      keyboardNavigationRef.current = true\n      if (filteredFields.length > 0) {\n        setHighlightedIndex((previous) =>\n          previous < filteredFields.length - 1 ? previous + 1 : 0\n        )\n      }\n    } else if (event.key === \"ArrowUp\") {\n      event.preventDefault()\n      keyboardNavigationRef.current = true\n      if (filteredFields.length > 0) {\n        setHighlightedIndex((previous) =>\n          previous > 0 ? previous - 1 : filteredFields.length - 1\n        )\n      }\n    } else if (\n      (event.key === \"ArrowRight\" || event.key === \"ArrowLeft\") &&\n      highlightedIndex >= 0\n    ) {\n      const field = filteredFields[highlightedIndex]\n      const hasSubMenu =\n        field &&\n        (field.type === \"select\" || field.type === \"multiselect\") &&\n        field.options?.length\n\n      if (event.key === \"ArrowRight\" && hasSubMenu) {\n        event.preventDefault()\n        setOpenSubMenu(field.key ?? null)\n        setActiveMenu(field.key ?? \"root\")\n      } else if (event.key === \"ArrowLeft\") {\n        event.preventDefault()\n        if (openSubMenu) {\n          setOpenSubMenu(null)\n          setActiveMenu(\"root\")\n        }\n      }\n    } else if (event.key === \"Enter\" && highlightedIndex >= 0) {\n      event.preventDefault()\n      const field = filteredFields[highlightedIndex]\n      if (field.key) {\n        const hasSubMenu =\n          (field.type === \"select\" || field.type === \"multiselect\") &&\n          field.options?.length\n        if (!hasSubMenu) {\n          addFilter(field.key)\n        } else {\n          setOpenSubMenu((previous) =>\n            previous === field.key ? null : (field.key ?? null)\n          )\n          setActiveMenu((previous) =>\n            previous === field.key ? \"root\" : (field.key ?? \"root\")\n          )\n        }\n      }\n    } else if (event.key === \"Escape\") {\n      setAddFilterOpen(false)\n    }\n    event.stopPropagation()\n  }\n\n  return (\n    <FilterContext.Provider\n      value={{\n        variant,\n        size,\n        radius,\n        i18n: mergedI18n,\n        className,\n        trigger,\n        allowMultiple,\n        showSearchInput,\n      }}\n    >\n      <div\n        className={cn(filtersContainerVariants({ variant, size }), className)}\n      >\n        {selectableFields.length > 0 ? (\n          <DropdownMenu\n            open={addFilterOpen}\n            onOpenChange={(open) => {\n              setAddFilterOpen(open)\n              if (!open) {\n                setMenuSearchInput(\"\")\n                setSessionFilterIds({})\n              } else {\n                setActiveMenu(\"root\")\n              }\n            }}\n          >\n            <DropdownMenuTrigger asChild>\n              {trigger ?? (\n                <Button variant=\"outline\" size={size}>\n                  <PlusIcon />\n                  {mergedI18n.addFilter}\n                </Button>\n              )}\n            </DropdownMenuTrigger>\n            <DropdownMenuContent\n              className={cn(\n                \"z-[200] w-[10.5rem] bg-popover before:hidden\",\n                menuPopupClassName\n              )}\n              align=\"start\"\n            >\n              {showSearchInput ? (\n                <>\n                  <div className=\"relative\">\n                    <Input\n                      ref={rootInputRef}\n                      role=\"combobox\"\n                      aria-controls={`${rootId}-listbox`}\n                      aria-activedescendant={\n                        highlightedIndex >= 0\n                          ? `${rootId}-item-${highlightedIndex}`\n                          : undefined\n                      }\n                      placeholder={mergedI18n.searchFields}\n                      className={cn(\n                        \"h-8 rounded-none border-0 bg-transparent! px-2 text-sm shadow-none\",\n                        \"focus-visible:border-border focus-visible:ring-0 focus-visible:ring-offset-0\"\n                      )}\n                      value={menuSearchInput}\n                      onChange={(event) =>\n                        setMenuSearchInput(event.target.value)\n                      }\n                      onClick={(event) => event.stopPropagation()}\n                      onKeyDown={handleRootKeyDown}\n                    />\n                    {enableShortcut && shortcutLabel ? (\n                      <Kbd className=\"absolute top-1/2 right-2 -translate-y-1/2 border bg-background\">\n                        {shortcutLabel}\n                      </Kbd>\n                    ) : null}\n                  </div>\n                  <DropdownMenuSeparator />\n                </>\n              ) : null}\n\n              <div className=\"relative flex max-h-full\">\n                <div\n                  className=\"flex max-h-[min(var(--radix-dropdown-menu-content-available-height),24rem)] w-full scroll-pt-2 scroll-pb-2 flex-col overscroll-contain\"\n                  role=\"listbox\"\n                  id={`${rootId}-listbox`}\n                >\n                  <ScrollArea className=\"**:data-[slot=scroll-area-scrollbar]:m-0\">\n                    {filteredFields.length === 0 ? (\n                      <div className=\"py-2 text-center text-sm text-muted-foreground\">\n                        {mergedI18n.noFieldsFound}\n                      </div>\n                    ) : (\n                      filteredFields.map((field, index) => {\n                        const isHighlighted = highlightedIndex === index\n                        const itemId = `${rootId}-item-${index}`\n                        const hasSubMenu =\n                          (field.type === \"select\" ||\n                            field.type === \"multiselect\") &&\n                          field.options?.length\n\n                        if (hasSubMenu) {\n                          const isMultiSelect = field.type === \"multiselect\"\n                          const fieldKey = field.key as string\n                          const sessionFilterId = sessionFilterIds[fieldKey]\n                          const sessionFilter = sessionFilterId\n                            ? filters.find(\n                                (filter) => filter.id === sessionFilterId\n                              )\n                            : null\n                          const currentValues = sessionFilter?.values ?? []\n\n                          return (\n                            <DropdownMenuSub\n                              key={fieldKey}\n                              open={openSubMenu === fieldKey}\n                              onOpenChange={(open) => {\n                                if (open) {\n                                  setOpenSubMenu((previous) =>\n                                    previous === fieldKey ? previous : fieldKey\n                                  )\n                                } else if (openSubMenu === fieldKey) {\n                                  setOpenSubMenu(null)\n                                  setActiveMenu(\"root\")\n                                }\n                              }}\n                            >\n                              <DropdownMenuSubTrigger\n                                id={itemId}\n                                role=\"option\"\n                                aria-selected={isHighlighted}\n                                data-highlighted={\n                                  keyboardNavigationRef.current && isHighlighted\n                                    ? true\n                                    : undefined\n                                }\n                                className=\"gap-1.5 data-highlighted:bg-accent data-highlighted:text-accent-foreground data-[state=open]:bg-accent data-[state=open]:text-accent-foreground\"\n                              >\n                                {field.icon}\n                                <span>{field.label}</span>\n                              </DropdownMenuSubTrigger>\n                              <DropdownMenuSubContent\n                                collisionPadding={12}\n                                sideOffset={6}\n                                className=\"z-[200] w-[min(10rem,calc(100vw-1.5rem))] bg-popover before:hidden\"\n                              >\n                                <FilterSubmenuContent\n                                  field={field}\n                                  currentValues={currentValues}\n                                  isMultiSelect={isMultiSelect}\n                                  i18n={mergedI18n}\n                                  isActive={activeMenu === fieldKey}\n                                  onActive={() => {\n                                    if (field.searchable !== false) {\n                                      setActiveMenu(fieldKey)\n                                    }\n                                  }}\n                                  onBack={() => {\n                                    setOpenSubMenu(null)\n                                    setActiveMenu(\"root\")\n                                  }}\n                                  onClose={() => setAddFilterOpen(false)}\n                                  onToggle={(value, isSelected) => {\n                                    if (isMultiSelect) {\n                                      const nextValues = isSelected\n                                        ? (currentValues.filter(\n                                            (item) => item !== value\n                                          ) as T[])\n                                        : ([...currentValues, value] as T[])\n\n                                      if (sessionFilter) {\n                                        if (nextValues.length === 0) {\n                                          onChange(\n                                            filters.filter(\n                                              (filter) =>\n                                                filter.id !== sessionFilter.id\n                                            )\n                                          )\n                                          setSessionFilterIds((previous) => ({\n                                            ...previous,\n                                            [fieldKey]: \"\",\n                                          }))\n                                        } else {\n                                          onChange(\n                                            filters.map((filter) =>\n                                              filter.id === sessionFilter.id\n                                                ? {\n                                                    ...filter,\n                                                    values: nextValues,\n                                                  }\n                                                : filter\n                                            )\n                                          )\n                                        }\n                                      } else {\n                                        const newFilter = createFilter<T>(\n                                          fieldKey,\n                                          field.defaultOperator ?? \"is_any_of\",\n                                          nextValues\n                                        )\n                                        onChange([...filters, newFilter])\n                                        setSessionFilterIds((previous) => ({\n                                          ...previous,\n                                          [fieldKey]: newFilter.id,\n                                        }))\n                                      }\n                                    } else {\n                                      const newFilter = createFilter<T>(\n                                        fieldKey,\n                                        field.defaultOperator ?? \"is\",\n                                        [value] as T[]\n                                      )\n                                      setLastAddedFilterId(newFilter.id)\n                                      onChange([...filters, newFilter])\n                                      setAddFilterOpen(false)\n                                    }\n                                  }}\n                                />\n                              </DropdownMenuSubContent>\n                            </DropdownMenuSub>\n                          )\n                        }\n\n                        return (\n                          <DropdownMenuItem\n                            key={field.key}\n                            id={itemId}\n                            role=\"option\"\n                            aria-selected={isHighlighted}\n                            data-highlighted={\n                              keyboardNavigationRef.current && isHighlighted\n                                ? true\n                                : undefined\n                            }\n                            onClick={() => field.key && addFilter(field.key)}\n                            className=\"gap-1.5 data-highlighted:bg-accent data-highlighted:text-accent-foreground\"\n                          >\n                            {field.icon}\n                            <span>{field.label}</span>\n                          </DropdownMenuItem>\n                        )\n                      })\n                    )}\n                  </ScrollArea>\n                </div>\n              </div>\n            </DropdownMenuContent>\n          </DropdownMenu>\n        ) : null}\n\n        {filters.map((filter) => {\n          const field = fieldsMap[filter.field]\n          if (!field) return null\n\n          return (\n            <ButtonGroup key={filter.id}>\n              <ButtonGroupText\n                className={cn(\n                  \"bg-background dark:bg-input/30\",\n                  filterControlHeight[size]\n                )}\n              >\n                {field.icon}\n                {field.label}\n              </ButtonGroupText>\n              <FilterOperatorDropdown<T>\n                field={field}\n                operator={filter.operator}\n                values={filter.values}\n                onChange={(operator) => updateFilter(filter.id, { operator })}\n              />\n              <FilterValueSelector<T>\n                field={field}\n                values={filter.values}\n                operator={filter.operator}\n                onChange={(values) => updateFilter(filter.id, { values })}\n                autoFocus={filter.id === lastAddedFilterId}\n              />\n              <FilterRemoveButton onClick={() => removeFilter(filter.id)} />\n            </ButtonGroup>\n          )\n        })}\n      </div>\n    </FilterContext.Provider>\n  )\n}\n\nexport function createFilter<T = unknown>(\n  field: string,\n  operator?: string,\n  values: T[] = []\n): Filter<T> {\n  return {\n    id: `${Date.now()}-${Math.random().toString(36).substring(2, 11)}`,\n    field,\n    operator: operator ?? \"is\",\n    values,\n  }\n}\n\nexport function createFilterGroup<T = unknown>(\n  id: string,\n  label: string,\n  fields: FilterFieldConfig<T>[],\n  initialFilters: Filter<T>[] = []\n): FilterGroup<T> {\n  return {\n    id,\n    label,\n    filters: initialFilters,\n    fields,\n  }\n}\n",
      "type": "registry:component"
    }
  ],
  "type": "registry:component"
}