@mantine/core
Version:
React components library focused on usability, accessibility and developer experience
373 lines (372 loc) • 14.8 kB
JavaScript
"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