{"version":3,"file":"ComboboxPopover.mjs","names":["comboboxClasses"],"sources":["../../../src/components/ComboboxPopover/ComboboxPopover.tsx"],"sourcesContent":["import { useMemo } from 'react';\nimport cx from 'clsx';\nimport { useUncontrolled } from '@mantine/hooks';\nimport {\n  Factory,\n  genericFactory,\n  Primitive,\n  StylesApiProps,\n  useProps,\n  useResolvedStylesApi,\n} from '../../core';\nimport { CheckIcon } from '../Checkbox';\nimport {\n  Combobox,\n  ComboboxData,\n  ComboboxItem,\n  ComboboxLikeRenderOptionInput,\n  ComboboxLikeStylesNames,\n  ComboboxProps,\n  defaultOptionsFilter,\n  getOptionsLockup,\n  getParsedComboboxData,\n  isOptionsGroup,\n  OptionsDropdown,\n  OptionsFilter,\n  useCombobox,\n} from '../Combobox';\nimport { ComboboxParsedItem } from '../Combobox/Combobox.types';\nimport { isEmptyComboboxData } from '../Combobox/OptionsDropdown/is-empty-combobox-data';\nimport { ScrollArea, ScrollAreaProps } from '../ScrollArea';\nimport { ComboboxPopoverValue } from './ComboboxPopover.types';\nimport { ComboboxPopoverTarget } from './ComboboxPopoverTarget';\nimport comboboxClasses from '../Combobox/Combobox.module.css';\n\nfunction isValueChecked(value: Primitive | Primitive[] | undefined | null, optionValue: Primitive) {\n  return Array.isArray(value) ? value.includes(optionValue) : value === optionValue;\n}\n\ninterface OptionProps {\n  data: ComboboxParsedItem<Primitive>;\n  withCheckIcon?: boolean;\n  withAlignedLabels?: boolean;\n  value?: Primitive | Primitive[] | null;\n  checkIconPosition?: 'left' | 'right';\n  unstyled: boolean | undefined;\n  renderOption?: (input: ComboboxLikeRenderOptionInput<any>) => React.ReactNode;\n}\n\nfunction Option({\n  data,\n  withCheckIcon,\n  withAlignedLabels,\n  value,\n  checkIconPosition,\n  unstyled,\n  renderOption,\n}: OptionProps) {\n  if (isOptionsGroup(data)) {\n    const options = data.items.map((item) => (\n      <Option\n        data={item}\n        value={value}\n        key={`${item.value}`}\n        unstyled={unstyled}\n        withCheckIcon={withCheckIcon}\n        withAlignedLabels={withAlignedLabels}\n        checkIconPosition={checkIconPosition}\n        renderOption={renderOption}\n      />\n    ));\n    return <Combobox.Group label={data.group}>{options}</Combobox.Group>;\n  }\n\n  const checked = isValueChecked(value, data.value);\n  const check =\n    withCheckIcon &&\n    (checked ? (\n      <CheckIcon className={comboboxClasses.optionsDropdownCheckIcon} />\n    ) : withAlignedLabels ? (\n      <div className={comboboxClasses.optionsDropdownCheckPlaceholder} />\n    ) : null);\n\n  const defaultContent = (\n    <>\n      {checkIconPosition === 'left' && check}\n      <span>{data.label}</span>\n      {checkIconPosition === 'right' && check}\n    </>\n  );\n\n  return (\n    <Combobox.Option\n      value={data.value}\n      disabled={data.disabled}\n      className={cx({ [comboboxClasses.optionsDropdownOption]: !unstyled })}\n      data-reverse={checkIconPosition === 'right' || undefined}\n      data-checked={checked || undefined}\n      aria-selected={checked}\n      active={checked}\n    >\n      {typeof renderOption === 'function'\n        ? renderOption({ option: data, checked })\n        : defaultContent}\n    </Combobox.Option>\n  );\n}\n\ninterface SearchableDropdownProps {\n  data: ComboboxParsedItem<Primitive>[];\n  filter: OptionsFilter<Primitive> | undefined;\n  search: string;\n  limit: number | undefined;\n  nothingFoundMessage: React.ReactNode | undefined;\n  withScrollArea: boolean | undefined;\n  maxDropdownHeight: number | string | undefined;\n  value: Primitive | Primitive[] | null;\n  checkIconPosition: 'left' | 'right' | undefined;\n  withCheckIcon: boolean | undefined;\n  withAlignedLabels: boolean | undefined;\n  unstyled: boolean | undefined;\n  renderOption?: (input: ComboboxLikeRenderOptionInput<any>) => React.ReactNode;\n  scrollAreaProps: ScrollAreaProps | undefined;\n  onSearchChange: (event: React.ChangeEvent<HTMLInputElement>) => void;\n}\n\nfunction SearchableDropdown({\n  data,\n  filter,\n  search,\n  limit,\n  nothingFoundMessage,\n  withScrollArea = true,\n  maxDropdownHeight,\n  value,\n  checkIconPosition,\n  withCheckIcon = false,\n  withAlignedLabels = false,\n  unstyled,\n  renderOption,\n  scrollAreaProps,\n  onSearchChange,\n}: SearchableDropdownProps) {\n  const filteredData = (filter || defaultOptionsFilter)({\n    options: data,\n    search,\n    limit: limit ?? Infinity,\n  });\n  const isEmpty = isEmptyComboboxData(filteredData);\n\n  const options = filteredData.map((item, index) => (\n    <Option\n      data={item}\n      key={\n        isOptionsGroup(item)\n          ? `group-${typeof item.group === 'string' ? item.group : index}`\n          : `${item.value}`\n      }\n      withCheckIcon={withCheckIcon}\n      withAlignedLabels={withAlignedLabels}\n      value={value}\n      checkIconPosition={checkIconPosition}\n      unstyled={unstyled}\n      renderOption={renderOption}\n    />\n  ));\n\n  return (\n    <Combobox.Dropdown data-composed>\n      <Combobox.Search value={search} onChange={onSearchChange} placeholder=\"Search...\" />\n      <Combobox.Options>\n        {withScrollArea ? (\n          <ScrollArea.Autosize\n            mah={maxDropdownHeight ?? 220}\n            type=\"scroll\"\n            scrollbarSize=\"var(--combobox-padding)\"\n            offsetScrollbars=\"y\"\n            {...scrollAreaProps}\n          >\n            {options}\n          </ScrollArea.Autosize>\n        ) : (\n          options\n        )}\n        {isEmpty && nothingFoundMessage && <Combobox.Empty>{nothingFoundMessage}</Combobox.Empty>}\n      </Combobox.Options>\n    </Combobox.Dropdown>\n  );\n}\n\nexport type ComboboxPopoverStylesNames = ComboboxLikeStylesNames;\n\nexport interface ComboboxPopoverProps<\n  Multiple extends boolean = false,\n  Value extends Primitive = string,\n> extends StylesApiProps<ComboboxPopoverFactory> {\n  /** If set, multiple items can be selected at the same time */\n  multiple?: Multiple;\n\n  /** Controlled component value */\n  value?: ComboboxPopoverValue<Multiple, Value>;\n\n  /** Uncontrolled component default value */\n  defaultValue?: ComboboxPopoverValue<Multiple, Value>;\n\n  /** Called when value changes */\n  onChange?: (value: ComboboxPopoverValue<Multiple, Value>) => void;\n\n  /** Data used to generate options */\n  data?: ComboboxData<Value>;\n\n  /** Controlled dropdown opened state */\n  dropdownOpened?: boolean;\n\n  /** Uncontrolled dropdown initial opened state */\n  defaultDropdownOpened?: boolean;\n\n  /** Called when dropdown opens */\n  onDropdownOpen?: () => void;\n\n  /** Called when dropdown closes */\n  onDropdownClose?: () => void;\n\n  /** Called when option is submitted from dropdown with mouse click or Enter key */\n  onOptionSubmit?: (value: Value) => void;\n\n  /** Props passed down to Combobox component */\n  comboboxProps?: ComboboxProps;\n\n  /** Function based on which items are filtered and sorted */\n  filter?: OptionsFilter<Value>;\n\n  /** Maximum number of options displayed at a time @default Infinity */\n  limit?: number;\n\n  /** Determines whether the options should be wrapped with ScrollArea.AutoSize @default true */\n  withScrollArea?: boolean;\n\n  /** max-height of the dropdown @default 250 */\n  maxDropdownHeight?: number | string;\n\n  /** If set, the first option is selected when dropdown opens @default false */\n  selectFirstOptionOnDropdownOpen?: boolean;\n\n  /** Displays check icon near the selected option label @default true */\n  withCheckIcon?: boolean;\n\n  /** Aligns unchecked labels with the checked one @default false */\n  withAlignedLabels?: boolean;\n\n  /** Position of the check icon relative to the option label @default 'left' */\n  checkIconPosition?: 'left' | 'right';\n\n  /** Message displayed when no options match the search query or when there is no data */\n  nothingFoundMessage?: React.ReactNode;\n\n  /** Allows searching through options @default false */\n  searchable?: boolean;\n\n  /** Controlled search value */\n  searchValue?: string;\n\n  /** Default search value */\n  defaultSearchValue?: string;\n\n  /** Called when search changes */\n  onSearchChange?: (value: string) => void;\n\n  /** Allows deselecting the selected option by clicking it (only for single mode) @default true */\n  allowDeselect?: boolean;\n\n  /** A function to render content of the option, replaces the default content of the option */\n  renderOption?: (item: ComboboxLikeRenderOptionInput<ComboboxItem>) => React.ReactNode;\n\n  /** Props passed down to the underlying ScrollArea component in the dropdown */\n  scrollAreaProps?: ScrollAreaProps;\n\n  /** Props passed down to the hidden input */\n  hiddenInputProps?: Omit<React.ComponentProps<'input'>, 'value'>;\n\n  /** Hidden input name for form submission */\n  name?: string;\n\n  /** Hidden input form for form submission */\n  form?: string;\n\n  /** Content of the component */\n  children?: React.ReactNode;\n\n  /** Divider used to separate values in the hidden input value attribute @default ',' */\n  hiddenInputValuesDivider?: string;\n}\n\nexport type ComboboxPopoverFactory = Factory<{\n  props: ComboboxPopoverProps;\n  ref: HTMLDivElement;\n  stylesNames: ComboboxPopoverStylesNames;\n  signature: <Multiple extends boolean = false, Value extends Primitive = string>(\n    props: ComboboxPopoverProps<Multiple, Value>\n  ) => React.JSX.Element;\n  staticComponents: {\n    Target: typeof ComboboxPopoverTarget;\n  };\n}>;\n\nconst defaultProps = {\n  withCheckIcon: true,\n  allowDeselect: true,\n  checkIconPosition: 'left',\n  hiddenInputValuesDivider: ',',\n} satisfies Partial<ComboboxPopoverProps>;\n\nexport const ComboboxPopover = genericFactory<ComboboxPopoverFactory>((_props) => {\n  const props = useProps('ComboboxPopover', defaultProps as any, _props);\n  const {\n    classNames,\n    styles,\n    unstyled,\n    vars,\n    children,\n    multiple,\n    value,\n    defaultValue,\n    onChange,\n    data,\n    dropdownOpened,\n    defaultDropdownOpened,\n    onDropdownOpen,\n    onDropdownClose,\n    onOptionSubmit,\n    comboboxProps,\n    filter,\n    limit,\n    withScrollArea,\n    maxDropdownHeight,\n    selectFirstOptionOnDropdownOpen,\n    withCheckIcon,\n    withAlignedLabels,\n    checkIconPosition,\n    nothingFoundMessage,\n    searchable,\n    searchValue,\n    defaultSearchValue,\n    onSearchChange,\n    allowDeselect,\n    renderOption,\n    scrollAreaProps,\n    hiddenInputProps,\n    name,\n    form,\n    hiddenInputValuesDivider,\n    attributes,\n    ...others\n  } = props;\n\n  const parsedData = useMemo(() => getParsedComboboxData(data), [data]);\n  const optionsLockup = useMemo(() => getOptionsLockup(parsedData), [parsedData]);\n\n  const [_value, setValue] = useUncontrolled({\n    value,\n    defaultValue,\n    finalValue: multiple ? ([] as any) : null,\n    onChange,\n  });\n\n  const [_searchValue, setSearchValue] = useUncontrolled({\n    value: searchValue,\n    defaultValue: defaultSearchValue,\n    finalValue: '',\n    onChange: onSearchChange,\n  });\n\n  const combobox = useCombobox({\n    opened: dropdownOpened,\n    defaultOpened: defaultDropdownOpened,\n    onDropdownOpen: () => {\n      onDropdownOpen?.();\n      if (searchable) {\n        combobox.focusSearchInput();\n      }\n      if (selectFirstOptionOnDropdownOpen) {\n        combobox.selectFirstOption();\n      }\n    },\n    onDropdownClose: () => {\n      onDropdownClose?.();\n      combobox.resetSelectedOption();\n      if (searchable) {\n        combobox.focusTarget();\n      }\n    },\n  });\n\n  const handleSearchChange = (val: string) => {\n    setSearchValue(val);\n    combobox.resetSelectedOption();\n  };\n\n  const { resolvedClassNames, resolvedStyles } = useResolvedStylesApi<ComboboxPopoverFactory>({\n    props,\n    styles,\n    classNames,\n  });\n\n  const handleOptionSubmit = (val: string) => {\n    onOptionSubmit?.(val as any);\n    const option = optionsLockup[val];\n\n    if (multiple) {\n      const currentValue = Array.isArray(_value) ? _value : [];\n      if (currentValue.includes(option.value)) {\n        setValue(currentValue.filter((v: any) => v !== option.value) as any);\n      } else {\n        setValue([...currentValue, option.value] as any);\n      }\n      combobox.updateSelectedOptionIndex('selected');\n    } else {\n      const nextValue = allowDeselect && `${option.value}` === `${_value}` ? null : option.value;\n      setValue(nextValue as any);\n      combobox.closeDropdown();\n    }\n\n    if (searchable) {\n      handleSearchChange('');\n    }\n  };\n\n  return (\n    <>\n      <Combobox\n        store={combobox}\n        __staticSelector=\"ComboboxPopover\"\n        classNames={resolvedClassNames}\n        styles={resolvedStyles}\n        unstyled={unstyled}\n        attributes={attributes}\n        onOptionSubmit={handleOptionSubmit}\n        {...comboboxProps}\n        {...others}\n      >\n        {children}\n        {searchable ? (\n          <SearchableDropdown\n            data={parsedData as any}\n            filter={filter as OptionsFilter<Primitive> | undefined}\n            search={_searchValue}\n            limit={limit}\n            nothingFoundMessage={nothingFoundMessage}\n            withScrollArea={withScrollArea}\n            maxDropdownHeight={maxDropdownHeight}\n            value={_value}\n            checkIconPosition={checkIconPosition}\n            withCheckIcon={withCheckIcon}\n            withAlignedLabels={withAlignedLabels}\n            unstyled={unstyled}\n            renderOption={renderOption}\n            scrollAreaProps={scrollAreaProps}\n            onSearchChange={(event) => {\n              handleSearchChange(event.currentTarget.value);\n            }}\n          />\n        ) : (\n          <OptionsDropdown\n            data={parsedData as any}\n            filter={filter as OptionsFilter<Primitive> | undefined}\n            search={undefined}\n            limit={limit}\n            hiddenWhenEmpty={!nothingFoundMessage}\n            withScrollArea={withScrollArea}\n            maxDropdownHeight={maxDropdownHeight}\n            filterOptions={false}\n            value={_value}\n            checkIconPosition={checkIconPosition}\n            withCheckIcon={withCheckIcon}\n            withAlignedLabels={withAlignedLabels}\n            nothingFoundMessage={nothingFoundMessage}\n            unstyled={unstyled}\n            renderOption={renderOption}\n            scrollAreaProps={scrollAreaProps}\n            labelId={undefined}\n            aria-label={undefined}\n          />\n        )}\n      </Combobox>\n      <Combobox.HiddenInput\n        name={name}\n        value={_value}\n        form={form}\n        valuesDivider={hiddenInputValuesDivider}\n        {...hiddenInputProps}\n      />\n    </>\n  );\n});\n\nComboboxPopover.classes = Combobox.classes;\nComboboxPopover.displayName = '@mantine/core/ComboboxPopover';\nComboboxPopover.Target = ComboboxPopoverTarget;\n"],"mappings":"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"}