From aab430ad7e73a0aa4930c131768b29b53037b628 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=9Cst=C3=BCn=20=C3=96zg=C3=BCr?= Date: Wed, 27 Nov 2024 14:13:39 +0300 Subject: [PATCH] Do not validate options by default in OptionsDropdown Previously Mantine punished the common scenario of duplicate keys too heavily, resulting in component failures in duplicate options data. Now duplicate values are silently ignored as in React. --- .../OptionsDropdown/OptionsDropdown.tsx | 304 ++++++++++-------- 1 file changed, 161 insertions(+), 143 deletions(-) diff --git a/packages/@mantine/core/src/components/Combobox/OptionsDropdown/OptionsDropdown.tsx b/packages/@mantine/core/src/components/Combobox/OptionsDropdown/OptionsDropdown.tsx index 712f3a9b9a7..bfcef59d455 100644 --- a/packages/@mantine/core/src/components/Combobox/OptionsDropdown/OptionsDropdown.tsx +++ b/packages/@mantine/core/src/components/Combobox/OptionsDropdown/OptionsDropdown.tsx @@ -1,173 +1,191 @@ -import cx from 'clsx'; -import { CheckIcon } from '../../Checkbox'; -import { ScrollArea, ScrollAreaProps } from '../../ScrollArea/ScrollArea'; -import { Combobox } from '../Combobox'; -import { ComboboxItem, ComboboxLikeRenderOptionInput, ComboboxParsedItem } from '../Combobox.types'; -import { defaultOptionsFilter, FilterOptionsInput } from './default-options-filter'; -import { isEmptyComboboxData } from './is-empty-combobox-data'; -import { isOptionsGroup } from './is-options-group'; -import { validateOptions } from './validate-options'; -import classes from '../Combobox.module.css'; +import cx from "clsx"; +import { CheckIcon } from "../../Checkbox"; +import { ScrollArea, ScrollAreaProps } from "../../ScrollArea/ScrollArea"; +import { Combobox } from "../Combobox"; +import { + ComboboxItem, + ComboboxLikeRenderOptionInput, + ComboboxParsedItem, +} from "../Combobox.types"; +import { + defaultOptionsFilter, + FilterOptionsInput, +} from "./default-options-filter"; +import { isEmptyComboboxData } from "./is-empty-combobox-data"; +import { isOptionsGroup } from "./is-options-group"; +import { validateOptions as validateOptionsFn } from "./validate-options"; +import classes from "../Combobox.module.css"; export type OptionsFilter = (input: FilterOptionsInput) => ComboboxParsedItem[]; export interface OptionsGroup { - group: string; - items: ComboboxItem[]; + group: string; + items: ComboboxItem[]; } export type OptionsData = (ComboboxItem | OptionsGroup)[]; interface OptionProps { - data: ComboboxItem | OptionsGroup; - withCheckIcon?: boolean; - value?: string | string[] | null; - checkIconPosition?: 'left' | 'right'; - unstyled: boolean | undefined; - renderOption?: (input: ComboboxLikeRenderOptionInput) => React.ReactNode; + data: ComboboxItem | OptionsGroup; + withCheckIcon?: boolean; + value?: string | string[] | null; + checkIconPosition?: "left" | "right"; + unstyled: boolean | undefined; + renderOption?: (input: ComboboxLikeRenderOptionInput) => React.ReactNode; } -function isValueChecked(value: string | string[] | undefined | null, optionValue: string) { - return Array.isArray(value) ? value.includes(optionValue) : value === optionValue; +function isValueChecked( + value: string | string[] | undefined | null, + optionValue: string, +) { + return Array.isArray(value) + ? value.includes(optionValue) + : value === optionValue; } function Option({ - data, - withCheckIcon, - value, - checkIconPosition, - unstyled, - renderOption, + data, + withCheckIcon, + value, + checkIconPosition, + unstyled, + renderOption, }: OptionProps) { - if (!isOptionsGroup(data)) { - const checked = isValueChecked(value, data.value); - const check = withCheckIcon && checked && ( - - ); + if (!isOptionsGroup(data)) { + const checked = isValueChecked(value, data.value); + const check = withCheckIcon && checked && ( + + ); - const defaultContent = ( - <> - {checkIconPosition === 'left' && check} - {data.label} - {checkIconPosition === 'right' && check} - - ); + const defaultContent = ( + <> + {checkIconPosition === "left" && check} + {data.label} + {checkIconPosition === "right" && check} + + ); - return ( - - {typeof renderOption === 'function' - ? renderOption({ option: data, checked }) - : defaultContent} - - ); - } + return ( + + {typeof renderOption === "function" + ? renderOption({ option: data, checked }) + : defaultContent} + + ); + } - const options = data.items.map((item) => ( -