@dnb/eufemia
Version:
DNB Eufemia Design System UI Library
302 lines • 13.7 kB
JavaScript
import _objectWithoutProperties from "@babel/runtime/helpers/esm/objectWithoutProperties";
import _extends from "@babel/runtime/helpers/esm/extends";
import _defineProperty from "@babel/runtime/helpers/esm/defineProperty";
var _em, _em2;
const _excluded = ["value", "title", "children", "error", "help", "size"];
function ownKeys(e, r) { var t = Object.keys(e); if (Object.getOwnPropertySymbols) { var o = Object.getOwnPropertySymbols(e); r && (o = o.filter(function (r) { return Object.getOwnPropertyDescriptor(e, r).enumerable; })), t.push.apply(t, o); } return t; }
function _objectSpread(e) { for (var r = 1; r < arguments.length; r++) { var t = null != arguments[r] ? arguments[r] : {}; r % 2 ? ownKeys(Object(t), !0).forEach(function (r) { _defineProperty(e, r, t[r]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(e, Object.getOwnPropertyDescriptors(t)) : ownKeys(Object(t)).forEach(function (r) { Object.defineProperty(e, r, Object.getOwnPropertyDescriptor(t, r)); }); } return e; }
import React, { useMemo, useCallback } from 'react';
import classnames from 'classnames';
import { convertJsxToString, makeUniqueId } from '../../../../shared/component-helper';
import { ToggleButton, Dropdown, Radio, Autocomplete, HelpButton } from '../../../../components';
import OptionField from '../Option';
import { useFieldProps } from '../../hooks';
import { checkForError } from '../../hooks/useFieldProps';
import { pickSpacingProps } from '../../../../components/flex/utils';
import FieldBlock from '../../FieldBlock';
import { convertCamelCasePropsToSnakeCase } from '../../../../shared/helpers/withCamelCaseProps';
import useDataValue from '../../hooks/useDataValue';
const validDrawerListProps = ['default_value', 'triangle_position', 'label_direction', 'prevent_selection', 'prevent_close', 'keep_open', 'independent_width', 'fixed_position', 'enable_body_lock', 'skip_keysearch', 'ignore_events', 'align_drawer', 'list_class', 'portal_class', 'no_scroll_animation', 'no_animation', 'skip_portal', 'min_height', 'max_height', 'page_offset', 'observer_element', 'cache_hash', 'wrapper_element', 'options_render', 'on_pre_change', 'on_change', 'on_select', 'on_show', 'on_hide'];
const validAutocompleteProps = ['align_autocomplete', 'aria_live_options', 'disable_filter', 'disable_highlighting', 'disable_reorder', 'drawer_class', 'icon_position', 'icon_size', 'indicator_label', 'input_element', 'input_icon', 'input_ref', 'input_value', 'keep_selection', 'keep_value', 'keep_value_and_selection', 'label_direction', 'label_sr_only', 'no_options', 'open_on_focus', 'prevent_selection', 'search_in_word_index', 'search_numbers', 'selected_sr', 'show_all', 'show_clear_button', 'show_options_sr', 'show_submit_button', 'skip_portal', 'status_props', 'status_state', 'submit_button_icon', 'submit_button_title', 'submit_element', 'triangle_position', 'on_type', 'on_focus', 'on_blur', 'on_change', 'on_select', 'on_show', 'on_hide'];
export const listOfValidAutocompleteProps = [...validAutocompleteProps, ...validDrawerListProps];
const validDropdownProps = ['icon_size', 'icon_position', 'triangle_position', 'open_on_focus', 'prevent_selection', 'action_menu', 'more_menu', 'align_dropdown', 'independent_width', 'skip_portal', 'status_state', 'status_props', 'label_direction', 'label_sr_only', 'trigger_element', 'on_change', 'on_select', 'on_show', 'on_hide'];
export const listOfValidDropdownProps = [...validDropdownProps, ...validDrawerListProps];
function Selection(props) {
var _props$autocompletePr;
const clearValue = useMemo(() => `clear-option-${makeUniqueId()}`, []);
const {
id,
className,
variant = 'dropdown',
layout = 'vertical',
optionsLayout = 'vertical',
placeholder,
value,
info,
warning,
error,
hasError,
disabled,
size,
emptyValue,
width = 'large',
htmlAttributes,
setHasFocus,
handleChange,
setDisplayValue,
transformSelection,
data,
dataPath,
children,
additionalArgs,
autocompleteProps,
dropdownProps
} = useFieldProps(props);
const {
getValueByPath
} = useDataValue();
let dataList = data;
if (dataPath) {
dataList = getValueByPath(dataPath);
}
const handleDrawerListChange = useCallback(({
data,
value
}) => {
var _data$selectedKey;
const selectedKey = (_data$selectedKey = data === null || data === void 0 ? void 0 : data.selectedKey) !== null && _data$selectedKey !== void 0 ? _data$selectedKey : value;
handleChange === null || handleChange === void 0 ? void 0 : handleChange(!selectedKey || selectedKey === clearValue ? emptyValue : selectedKey, {
data
});
}, [handleChange, emptyValue, clearValue]);
const onChangeHandler = useCallback(({
value
}) => {
handleChange === null || handleChange === void 0 ? void 0 : handleChange(value === undefined ? emptyValue : value);
}, [handleChange, emptyValue]);
const handleShow = useCallback(({
data
}) => {
setHasFocus(true, data === null || data === void 0 ? void 0 : data.selectedKey);
}, [setHasFocus]);
const handleHide = useCallback(({
data
}) => {
setHasFocus(false, data === null || data === void 0 ? void 0 : data.selectedKey);
}, [setHasFocus]);
const cn = classnames(`dnb-forms-field-selection dnb-forms-field-selection__variant--${variant} dnb-forms-field-selection--layout-${layout} dnb-forms-field-selection--options-layout--${optionsLayout}`, className);
const fieldBlockProps = _objectSpread({
forId: id,
className: cn,
disableStatusSummary: true
}, pickSpacingProps(props));
const onType = props === null || props === void 0 ? void 0 : (_props$autocompletePr = props.autocompleteProps) === null || _props$autocompletePr === void 0 ? void 0 : _props$autocompletePr.onType;
const onTypeAutocompleteHandler = useCallback(event => {
if (typeof onType === 'function') {
const {
value
} = event;
onType(_objectSpread(_objectSpread(_objectSpread({}, event), additionalArgs), {}, {
value: value === '' ? emptyValue : value
}));
}
}, [additionalArgs, emptyValue, onType]);
switch (variant) {
case 'radio':
case 'radio-list':
case 'button':
{
const Component = variant === 'radio' || variant === 'radio-list' ? Radio : ToggleButton;
const items = renderRadioItems({
id,
value,
variant,
info,
warning,
htmlAttributes,
children,
dataList,
hasError,
iterateOverItems: ({
value: v,
label
}) => {
if (v === value) {
setDisplayValue(label);
}
}
});
const additionalFieldBlockProps = {
asFieldset: React.Children.count(items) > 1
};
if (!size) {
additionalFieldBlockProps.labelHeight = 'small';
}
if (variant === 'radio-list') {
additionalFieldBlockProps.contentWidth = width;
}
return React.createElement(FieldBlock, _extends({}, fieldBlockProps, additionalFieldBlockProps), React.createElement(Component.Group, {
role: "radiogroup",
size: size,
className: cn,
layout_direction: optionsLayout === 'horizontal' ? 'row' : 'column',
disabled: disabled,
on_change: onChangeHandler,
value: String(value !== null && value !== void 0 ? value : '')
}, items));
}
case 'autocomplete':
case 'dropdown':
{
var _data$find;
const data = renderDropdownItems(dataList, transformSelection).concat(makeOptions(children, transformSelection)).filter(Boolean);
const displayValue = (_data$find = data.find(item => item.selectedKey === value)) === null || _data$find === void 0 ? void 0 : _data$find.content;
setDisplayValue(displayValue);
const sharedProps = _objectSpread(_objectSpread({
id,
list_class: 'dnb-forms-field-selection__list',
portal_class: 'dnb-forms-field-selection__portal',
title: placeholder,
value: String(value !== null && value !== void 0 ? value : ''),
status: (hasError || checkForError([error, info, warning])) && 'error',
disabled
}, htmlAttributes), {}, {
data,
size,
on_change: handleDrawerListChange,
on_show: handleShow,
on_hide: handleHide,
stretch: true
});
const specificFieldBlockProps = {
contentWidth: width
};
return React.createElement(FieldBlock, _extends({}, fieldBlockProps, specificFieldBlockProps), variant === 'autocomplete' ? React.createElement(Autocomplete, _extends({}, sharedProps, autocompleteProps ? convertCamelCasePropsToSnakeCase(Object.freeze(autocompleteProps), listOfValidAutocompleteProps) : null, {
value: autocompleteProps !== null && autocompleteProps !== void 0 && autocompleteProps.preventSelection ? undefined : value,
on_type: onTypeAutocompleteHandler,
data: !props.data && !props.dataPath && (autocompleteProps === null || autocompleteProps === void 0 ? void 0 : autocompleteProps.mode) === 'async' ? undefined : data,
selectall: true
})) : React.createElement(Dropdown, _extends({}, sharedProps, dropdownProps ? convertCamelCasePropsToSnakeCase(dropdownProps, listOfValidDropdownProps) : null)));
}
}
}
function renderRadioItems({
id,
value: valueProp,
variant,
info,
warning,
htmlAttributes,
children,
dataList,
hasError,
iterateOverItems
}) {
const optionsCount = React.Children.count(children) + ((dataList === null || dataList === void 0 ? void 0 : dataList.length) || 0);
const createOption = (props, i) => {
const {
value,
title,
children,
error,
help,
size
} = props,
rest = _objectWithoutProperties(props, _excluded);
const label = title !== null && title !== void 0 ? title : children;
const suffix = help ? React.createElement(HelpButton, {
size: "small",
title: convertJsxToString(help.title)
}, help.content) : undefined;
iterateOverItems === null || iterateOverItems === void 0 ? void 0 : iterateOverItems({
value,
label
});
const Component = variant === 'radio' || variant === 'radio-list' ? Radio : ToggleButton;
return React.createElement(Component, _extends({
id: optionsCount === 1 ? id : undefined,
key: `option-${i}-${id}`,
label: variant === 'radio' || variant === 'radio-list' ? label : undefined,
text: variant === 'button' ? label : undefined,
role: "radio",
value: String(value !== null && value !== void 0 ? value : valueProp) || undefined,
status: (hasError || checkForError([error, info, warning])) && 'error',
suffix: suffix,
size: size
}, htmlAttributes, rest));
};
return [...(dataList || []).map((props, i) => {
return createOption(props, i);
}), ...(mapOptions(children, {
createOption
}) || [])].filter(Boolean);
}
export function mapOptions(children, {
createOption
}) {
return React.Children.map(children, (child, i) => {
if (React.isValidElement(child)) {
if (child.type === OptionField) {
return createOption(child.props, i);
}
if (child.props.children) {
const nestedChildren = mapOptions(child.props.children, {
createOption
});
return React.cloneElement(child, child.props, nestedChildren);
}
}
return child;
});
}
export function makeOptions(children, transformSelection) {
return React.Children.map(children, child => {
var _child, _child$props, _child$props$children;
if (((_child = child) === null || _child === void 0 ? void 0 : (_child$props = _child['props']) === null || _child$props === void 0 ? void 0 : (_child$props$children = _child$props.children) === null || _child$props$children === void 0 ? void 0 : _child$props$children.type) === OptionField) {
child = child['props'].children;
}
if (React.isValidElement(child) && child.type === OptionField) {
var _ref, _props$title, _props$value;
const props = child.props;
const title = (_ref = (_props$title = props.title) !== null && _props$title !== void 0 ? _props$title : props.children) !== null && _ref !== void 0 ? _ref : _em || (_em = React.createElement("em", null, "Untitled"));
const content = props.text ? [title, props.text] : title;
const selected_value = transformSelection ? transformSelection(props) : undefined;
const selectedKey = String((_props$value = props.value) !== null && _props$value !== void 0 ? _props$value : '');
const disabled = props.disabled;
const style = props.style;
return {
selectedKey,
selected_value,
content,
disabled,
style
};
}
if (child) {
return {
content: child
};
}
});
}
function renderDropdownItems(data, transformSelection) {
return (data === null || data === void 0 ? void 0 : data.map(props => {
const {
value,
title,
text,
disabled,
style
} = props;
return {
selectedKey: value,
content: (text ? [title, text] : title) || _em2 || (_em2 = React.createElement("em", null, "Untitled")),
selected_value: transformSelection ? transformSelection(props) : undefined,
disabled,
style
};
})) || [];
}
Selection._supportsSpacingProps = true;
export default Selection;
//# sourceMappingURL=Selection.js.map