UNPKG

@mantine/core

Version:

React components library focused on usability, accessibility and developer experience

373 lines (372 loc) 14.8 kB
"use client"; const require_use_props = require("../../core/MantineProvider/use-props/use-props.cjs"); const require_use_resolved_styles_api = require("../../core/styles-api/use-resolved-styles-api/use-resolved-styles-api.cjs"); const require_use_styles = require("../../core/styles-api/use-styles/use-styles.cjs"); const require_extract_style_props = require("../../core/Box/style-props/extract-style-props/extract-style-props.cjs"); const require_factory = require("../../core/factory/factory.cjs"); const require_ScrollArea = require("../ScrollArea/ScrollArea.cjs"); const require_InputBase = require("../InputBase/InputBase.cjs"); const require_use_combobox = require("../Combobox/use-combobox/use-combobox.cjs"); const require_Combobox = require("../Combobox/Combobox.cjs"); const require_CheckIcon = require("../Checkbox/CheckIcon.cjs"); const require_CascaderColumns = require("./CascaderColumns.cjs"); const require_flatten_cascader_paths = require("./flatten-cascader-paths.cjs"); const require_get_cascader_path_options = require("./get-cascader-path-options.cjs"); const require_use_cascader = require("./use-cascader.cjs"); const require_Cascader_module = require("./Cascader.module.cjs"); let react = require("react"); let _mantine_hooks = require("@mantine/hooks"); let react_jsx_runtime = require("react/jsx-runtime"); //#region packages/@mantine/core/src/components/Cascader/Cascader.tsx const defaultProps = { expandTrigger: "click", safeAreaPolygon: true, changeOnSelect: false, allowDeselect: true, withCheckIcon: true, checkIconPosition: "right", withColumns: true, searchable: false, separator: "/", maxDisplayedLevels: 3, previousLevelsControlLabel: "Show previous levels", nextLevelsControlLabel: "Show next levels", maxDropdownHeight: 260, openOnFocus: true, size: "sm" }; function optionLabelToString(option) { return typeof option.label === "string" || typeof option.label === "number" ? String(option.label) : option.value; } function firstEnabledOptionIndex(options) { return options.findIndex((option) => !option.disabled); } function lastEnabledOptionIndex(options) { for (let index = options.length - 1; index >= 0; index -= 1) if (!options[index].disabled) return index; return -1; } function joinPathLabels(options, separator) { return options.map(optionLabelToString).join(` ${separator} `); } function defaultCascaderFilter(query, options, separator) { const trimmed = query.trim().toLowerCase(); if (trimmed.length === 0) return true; return joinPathLabels(options, separator).toLowerCase().includes(trimmed); } function defaultRenderSearchOption(options, separator) { return options.map((option, index) => /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react.Fragment, { children: [index > 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", { "data-cascader-separator": true, children: [ " ", separator, " " ] }), option.label ?? option.value] }, option.value)); } const Cascader = require_factory.factory((_props) => { const props = require_use_props.useProps([ "Input", "InputWrapper", "Cascader" ], defaultProps, _props); const { classNames, className, style, styles, unstyled, vars, size, data, value, defaultValue, onChange, changeOnSelect, closeOnSelect, allowDeselect, withCheckIcon, checkIconPosition, withColumns, expandTrigger, safeAreaPolygon, searchable, searchValue, defaultSearchValue, onSearchChange, filter, renderSearchOption, formatValue, renderOption, separator, columnWidth, maxDisplayedLevels, previousLevelsControlLabel, nextLevelsControlLabel, maxDropdownHeight, nothingFoundMessage, clearable, clearSectionMode, clearButtonProps, onClear, dropdownOpened, defaultDropdownOpened, onDropdownOpen, onDropdownClose, comboboxProps, scrollAreaProps, chevronColor, hiddenInputProps, openOnFocus, variant, onKeyDown, onFocus, onBlur, onClick, readOnly, disabled, radius, rightSection, rightSectionWidth, rightSectionPointerEvents, rightSectionProps, leftSection, leftSectionWidth, leftSectionPointerEvents, leftSectionProps, inputContainer, inputWrapperOrder, withAsterisk, labelProps, descriptionProps, errorProps, successProps, wrapperProps, description, label, error, success, withErrorStyles, withSuccessStyles, name, form, id, placeholder, required, mod, attributes, ...others } = props; const _id = (0, _mantine_hooks.useId)(id); const separatorString = typeof separator === "string" || typeof separator === "number" ? String(separator) : "/"; const combobox = require_use_combobox.useCombobox({ opened: dropdownOpened, defaultOpened: defaultDropdownOpened, onDropdownOpen: () => { onDropdownOpen?.(); cascader.resetActivePath(); }, onDropdownClose: () => { onDropdownClose?.(); if (searchable) setSearchValue(cascader.value ? displayString : ""); } }); const shouldCloseOnSelect = closeOnSelect ?? !allowDeselect; const cascader = require_use_cascader.useCascader({ data, value, defaultValue, onChange, changeOnSelect, allowDeselect, expandTrigger, onLeafSelect: () => { if (shouldCloseOnSelect) combobox.closeDropdown(); } }); const getStyles = require_use_styles.useStyles({ name: "Cascader", classes: require_Cascader_module.default, props, classNames, styles, unstyled, attributes }); const { resolvedClassNames, resolvedStyles } = require_use_resolved_styles_api.useResolvedStylesApi({ props, styles, classNames }); const { styleProps, rest: { type, autoComplete, ...rest } } = require_extract_style_props.extractStyleProps(others); const displayString = (0, react.useMemo)(() => { if (cascader.pathOptions.length === 0 || !cascader.value) return ""; if (formatValue) { const rendered = formatValue({ value: cascader.value, options: cascader.pathOptions }); if (typeof rendered === "string" || typeof rendered === "number") return String(rendered); } return joinPathLabels(cascader.pathOptions, separatorString); }, [ cascader.pathOptions, cascader.value, formatValue, separatorString ]); const [_searchValue, setSearchValue] = (0, _mantine_hooks.useUncontrolled)({ value: searchValue, defaultValue: defaultSearchValue, finalValue: (0, react.useMemo)(() => { if (!searchable || !defaultValue) return ""; return joinPathLabels(require_get_cascader_path_options.getCascaderPathOptions(data, defaultValue), separatorString); }, []), onChange: onSearchChange }); const isSearching = !!searchable && _searchValue.trim().length > 0 && _searchValue !== displayString; (0, react.useEffect)(() => { if (searchable) setSearchValue(cascader.value ? displayString : ""); }, [cascader.value]); const showFlatList = isSearching || !withColumns; const flatPaths = (0, react.useMemo)(() => require_flatten_cascader_paths.flattenCascaderPaths(data), [data]); const flatListItems = (0, react.useMemo)(() => { if (!showFlatList) return []; const base = flatPaths.filter((flatPath) => changeOnSelect ? true : flatPath.leaf); if (!isSearching) return base; return base.filter((flatPath) => filter ? filter(_searchValue, flatPath.options) : defaultCascaderFilter(_searchValue, flatPath.options, separatorString)); }, [ flatPaths, showFlatList, isSearching, _searchValue, changeOnSelect, filter, separatorString ]); const canInteract = !readOnly && !disabled; const handleSearchChange = (nextValue) => { setSearchValue(nextValue); if (canInteract) combobox.openDropdown(); }; const handleKeyDown = (event) => { onKeyDown?.(event); if (event.key === "Escape") { combobox.closeDropdown(); return; } if (showFlatList || !canInteract) return; if (!combobox.dropdownOpened) { if (event.key === "ArrowDown" || event.key === "ArrowUp" || event.key === "ArrowRight" || event.key === "Enter" || !searchable && event.key === " ") { event.preventDefault(); cascader.setKeyboardNav(true); combobox.openDropdown(); if (!cascader.value && (event.key === "ArrowDown" || event.key === "ArrowUp")) { const rootIndex = event.key === "ArrowDown" ? firstEnabledOptionIndex(data) : lastEnabledOptionIndex(data); if (rootIndex >= 0) cascader.setActivePath([data[rootIndex].value]); } } return; } if (cascader.handleColumnsKeyDown(event)) event.preventDefault(); else if (!searchable && event.key === " ") event.preventDefault(); }; const clearButton = /* @__PURE__ */ (0, react_jsx_runtime.jsx)(require_Combobox.Combobox.ClearButton, { ...clearButtonProps, onClear: () => { onClear?.(); cascader.setValue(null); cascader.setActivePath([]); setSearchValue(""); combobox.focusTarget(); } }); const hasValue = Array.isArray(cascader.value) && cascader.value.length > 0; const _clearable = clearable && hasValue && !disabled && !readOnly; const listId = _id ? `${_id}-cascader-list` : void 0; const valueKey = cascader.value ? JSON.stringify(cascader.value) : null; const dropdown = /* @__PURE__ */ (0, react_jsx_runtime.jsx)(require_Combobox.Combobox.Dropdown, { hidden: readOnly || disabled, style: showFlatList ? void 0 : { padding: 0 }, children: showFlatList ? /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(require_Combobox.Combobox.Options, { "aria-label": typeof label === "string" ? label : void 0, children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(require_ScrollArea.ScrollArea.Autosize, { mah: maxDropdownHeight ?? 260, type: "scroll", scrollbarSize: "var(--combobox-padding)", offsetScrollbars: "y", ...scrollAreaProps, children: flatListItems.map((flatPath, index) => { const pathKey = JSON.stringify(flatPath.path); const active = valueKey !== null && pathKey === valueKey; return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(require_Combobox.Combobox.Option, { value: `${index}`, active, disabled: flatPath.disabled, children: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", { ...getStyles("flatOption"), children: [ active && withCheckIcon && checkIconPosition === "left" && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(require_CheckIcon.CheckIcon, { ...getStyles("columnOptionCheck") }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { ...getStyles("columnOptionLabel"), children: renderSearchOption ? renderSearchOption(_searchValue, flatPath.options) : defaultRenderSearchOption(flatPath.options, separator) }), active && withCheckIcon && checkIconPosition !== "left" && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(require_CheckIcon.CheckIcon, { ...getStyles("columnOptionCheck") }) ] }) }, pathKey); }) }), flatListItems.length === 0 && nothingFoundMessage && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(require_Combobox.Combobox.Empty, { children: nothingFoundMessage })] }) : /* @__PURE__ */ (0, react_jsx_runtime.jsx)(require_CascaderColumns.CascaderColumns, { data, activePath: cascader.activePath, value: cascader.value, keyboardNav: cascader.keyboardNav, withCheckIcon, checkIconPosition, renderOption, columnWidth, maxDisplayedLevels, previousLevelsControlLabel, nextLevelsControlLabel, maxDropdownHeight, nothingFoundMessage, getStyles, unstyled, scrollAreaProps, onOptionClick: cascader.handleOptionClick, onOptionMouseEnter: cascader.handleOptionMouseEnter, onColumnsMouseLeave: () => { if (expandTrigger === "hover") cascader.setActivePath(cascader.value ?? []); }, onPointerActivity: () => cascader.setKeyboardNav(false), listId, safeAreaPolygon: expandTrigger === "hover" ? safeAreaPolygon : false }) }); return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)(require_Combobox.Combobox, { store: combobox, __staticSelector: "Cascader", classNames: resolvedClassNames, styles: resolvedStyles, unstyled, readOnly, size, attributes, width: showFlatList ? "target" : "max-content", position: "bottom-start", onOptionSubmit: (val) => { const index = Number(val); const flatPath = flatListItems[index]; if (!flatPath || flatPath.disabled) return; cascader.selectPath(flatPath.path); cascader.setActivePath(flatPath.path); if (shouldCloseOnSelect) combobox.closeDropdown(); }, ...comboboxProps, children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(require_Combobox.Combobox.Target, { targetType: searchable ? "input" : "button", withKeyboardNavigation: showFlatList, autoComplete, children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(require_InputBase.InputBase, { id: _id, __defaultRightSection: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(require_Combobox.Combobox.Chevron, { size, error, unstyled, color: chevronColor }), __clearSection: clearButton, __clearable: _clearable, __clearSectionMode: clearSectionMode, rightSection, rightSectionPointerEvents: rightSectionPointerEvents || "none", ...rest, ...styleProps, size, __staticSelector: "Cascader", disabled, readOnly: readOnly || !searchable, value: searchable ? _searchValue : displayString, onChange: (event) => handleSearchChange(event.currentTarget.value), onFocus: (event) => { if (openOnFocus && searchable && canInteract) combobox.openDropdown(); onFocus?.(event); }, onBlur: (event) => { combobox.closeDropdown(); onBlur?.(event); }, onClick: (event) => { if (canInteract) { cascader.setKeyboardNav(false); if (searchable) combobox.openDropdown(); else combobox.toggleDropdown(); } onClick?.(event); }, onKeyDown: handleKeyDown, classNames: resolvedClassNames, styles: resolvedStyles, unstyled, pointer: !searchable, error, success, attributes, className, style, variant, radius, leftSection, leftSectionWidth, leftSectionPointerEvents, leftSectionProps, rightSectionWidth, rightSectionProps, inputContainer, inputWrapperOrder, withAsterisk, labelProps, descriptionProps, errorProps, successProps, wrapperProps, description, label, withErrorStyles, withSuccessStyles, placeholder, required, mod }) }), dropdown] }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(require_Combobox.Combobox.HiddenInput, { value: cascader.value, name, form, disabled, ...hiddenInputProps })] }); }); Cascader.classes = { ...require_InputBase.InputBase.classes, ...require_Combobox.Combobox.classes, ...require_Cascader_module.default }; Cascader.displayName = "@mantine/core/Cascader"; //#endregion exports.Cascader = Cascader; //# sourceMappingURL=Cascader.cjs.map