@razorpay/blade
Version:
The Design System that powers Razorpay
348 lines (336 loc) • 15.9 kB
JavaScript
import _defineProperty from '@babel/runtime/helpers/defineProperty';
import React__default from 'react';
import '../BaseInput/index.js';
import { InputChevronIcon } from './InputChevronIcon.web.js';
import isEmpty from '../../../utils/lodashButBetter/isEmpty.js';
import { useDropdown } from '../../Dropdown/useDropdown.js';
import '../../../utils/index.js';
import { getActionListContainerRole } from '../../ActionList/getA11yRoles.js';
import '../../../utils/metaAttribute/index.js';
import { getTagsGroup } from '../../Tag/getTagsGroup.js';
import { useFirstRender } from '../../../utils/useFirstRender.js';
import { useTableContext } from '../../Table/TableContext.js';
import { rowDensityToIsTableInputCellMapping, tableEditableCellRowDensityToInputSizeMap, validationStateToInputTrailingIconMap } from '../../Table/tokens.js';
import { useTableEditableCell } from '../../Table/TableEditableCellContext.js';
import '../../../utils/makeAnalyticsAttribute/index.js';
import '../../../utils/fireNativeEvent/index.js';
import { dropdownComponentIds } from '../../Dropdown/dropdownComponentIds.js';
import { jsx } from 'react/jsx-runtime';
import { isBrowser } from '../../../utils/platform/isBrowser.js';
import { fireNativeEvent } from '../../../utils/fireNativeEvent/fireNativeEvent.web.js';
import { isReactNative } from '../../../utils/platform/isReactNative.js';
import { BaseInput } from '../BaseInput/BaseInput.js';
import { MetaConstants } from '../../../utils/metaAttribute/metaConstants.js';
import { makeAnalyticsAttribute } from '../../../utils/makeAnalyticsAttribute/makeAnalyticsAttribute.js';
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; }
var useControlledDropdownInput = function useControlledDropdownInput(props) {
var isFirstRender = useFirstRender();
var _useDropdown = useDropdown(),
changeCallbackTriggerer = _useDropdown.changeCallbackTriggerer,
isControlled = _useDropdown.isControlled,
options = _useDropdown.options,
selectedIndices = _useDropdown.selectedIndices,
controlledValueIndices = _useDropdown.controlledValueIndices,
setSelectedIndices = _useDropdown.setSelectedIndices,
selectionType = _useDropdown.selectionType,
setIsControlled = _useDropdown.setIsControlled;
var getValuesArrayFromIndices = function getValuesArrayFromIndices() {
var indices = [];
if (isControlled) {
indices = controlledValueIndices;
} else {
indices = selectedIndices;
}
return indices.map(function (selectionIndex) {
return options[selectionIndex].value;
});
};
var selectValues = function selectValues(valuesToSelect) {
if (options.length > 0) {
// we use empty `''` for clearing the input
if (isEmpty(valuesToSelect)) {
setSelectedIndices([]);
} else if (typeof valuesToSelect === 'string') {
// single select control
var selectedItemIndex = options.findIndex(function (option) {
return option.value === valuesToSelect;
});
if (selectedItemIndex >= 0) {
setSelectedIndices([selectedItemIndex]);
}
} else {
// multiselect control
// Handles repeated values in user state
var uniqueValues = Array.from(new Set(valuesToSelect));
// Handle selectionType single with multiselect values
var userValues = selectionType === 'single' ? [valuesToSelect === null || valuesToSelect === void 0 ? void 0 : valuesToSelect[0]] : uniqueValues;
var selectedItemIndices = userValues.map(function (optionValue) {
return options.findIndex(function (option) {
return option.value === optionValue;
});
}).filter(function (value) {
return value >= 0;
});
setSelectedIndices(selectedItemIndices);
}
}
};
// Handles `defaultValue` prop
React__default.useEffect(function () {
if (options.length > 0 && props.defaultValue) {
selectValues(props.defaultValue);
}
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [options.length]);
// Handles `value` prop
React__default.useEffect(function () {
if (options.length > 0 && props.value !== undefined) {
if (!isControlled) {
setIsControlled(true);
}
selectValues(props.value);
// in single select AutoComplete, we have to set inputValue of autocomplete according to the new selection.
if (selectionType === 'single' && !Array.isArray(props.value) && !props.isSelectInput) {
var _props$syncInputValue;
(_props$syncInputValue = props.syncInputValueWithSelection) === null || _props$syncInputValue === void 0 ? void 0 : _props$syncInputValue.call(props, props.value);
}
}
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [props.value, options]);
// onChange behaviour
React__default.useEffect(function () {
// Ignore calling onChange on mount
if (!isFirstRender) {
var _props$onChange;
(_props$onChange = props.onChange) === null || _props$onChange === void 0 ? void 0 : _props$onChange.call(props, {
name: props.name,
values: getValuesArrayFromIndices()
});
if (isBrowser()) {
fireNativeEvent(props.triggererRef, ['change', 'input']);
}
}
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [changeCallbackTriggerer]);
};
var _BaseDropdownInputTrigger = function _BaseDropdownInputTrigger(props, ref) {
var _props$placeholder, _props$validationStat, _props$maxRows, _props$label;
var _useDropdown2 = useDropdown(),
isOpen = _useDropdown2.isOpen,
activeTagIndex = _useDropdown2.activeTagIndex,
setActiveTagIndex = _useDropdown2.setActiveTagIndex,
displayValue = _useDropdown2.displayValue,
selectionType = _useDropdown2.selectionType,
dropdownTriggerer = _useDropdown2.dropdownTriggerer,
dropdownBaseId = _useDropdown2.dropdownBaseId,
selectedIndices = _useDropdown2.selectedIndices,
triggererRef = _useDropdown2.triggererRef,
headerAutoCompleteRef = _useDropdown2.headerAutoCompleteRef,
triggererWrapperRef = _useDropdown2.triggererWrapperRef,
isTagDismissedRef = _useDropdown2.isTagDismissedRef,
onTriggerClick = _useDropdown2.onTriggerClick,
value = _useDropdown2.value,
shouldIgnoreBlurAnimation = _useDropdown2.shouldIgnoreBlurAnimation,
setShouldIgnoreBlurAnimation = _useDropdown2.setShouldIgnoreBlurAnimation,
activeIndex = _useDropdown2.activeIndex,
hasFooterAction = _useDropdown2.hasFooterAction,
options = _useDropdown2.options,
removeOption = _useDropdown2.removeOption,
setChangeCallbackTriggerer = _useDropdown2.setChangeCallbackTriggerer,
changeCallbackTriggerer = _useDropdown2.changeCallbackTriggerer;
var _useTableContext = useTableContext(),
rowDensity = _useTableContext.rowDensity;
var _useTableEditableCell = useTableEditableCell(),
isInsideTableEditableCell = _useTableEditableCell.isInsideTableEditableCell;
var dropdownTriggerPlaceholder = (_props$placeholder = props.placeholder) !== null && _props$placeholder !== void 0 ? _props$placeholder : 'Select Option';
var isAutoCompleteInHeader = !props.isSelectInput && dropdownTriggerer !== dropdownComponentIds.triggers.AutoComplete;
var getShowAllTags = React__default.useCallback(function () {
if (isAutoCompleteInHeader) {
// When AutoComplete is in bottomsheet header, we never want to show all tags in outer select input
if (props.isSelectInput) {
return false;
}
// ... And we always want to show all tags in inner AutoComplete
return true;
}
return isOpen;
}, [isAutoCompleteInHeader, props.isSelectInput, isOpen]);
useControlledDropdownInput({
onChange: props.onChange,
name: props.name,
value: props.value,
defaultValue: props.defaultValue,
syncInputValueWithSelection: props.syncInputValueWithSelection,
isSelectInput: props.isSelectInput,
triggererRef: triggererRef
});
var getValue = function getValue() {
var prefix = '';
if (props.labelPosition === 'inside-input' && props.label) {
prefix = "".concat(props.label, ": ");
}
if (props.isSelectInput) {
if (selectionType === 'single') {
return "".concat(prefix).concat(displayValue);
}
// In multiselect, we return tags so no display value is required
return undefined;
}
// In AutoComplete, input has a special value too
return props.inputValue;
};
var getTags = React__default.useMemo(function () {
return function (_ref) {
var size = _ref.size;
if (selectionType === 'single') {
return undefined;
}
return getTagsGroup({
size: size,
tags: selectedIndices.map(function (selectedIndex) {
var _options$selectedInde;
return (_options$selectedInde = options[selectedIndex]) === null || _options$selectedInde === void 0 ? void 0 : _options$selectedInde.title;
}),
activeTagIndex: activeTagIndex,
isDisabled: props.isDisabled,
onDismiss: function onDismiss(_ref2) {
var tagIndex = _ref2.tagIndex;
if (isTagDismissedRef.current) {
isTagDismissedRef.current.value = true;
}
if (!isReactNative()) {
var _triggererRef$current;
(_triggererRef$current = triggererRef.current) === null || _triggererRef$current === void 0 ? void 0 : _triggererRef$current.focus();
}
removeOption(selectedIndices[tagIndex]);
setChangeCallbackTriggerer(Number(changeCallbackTriggerer) + 1);
}
});
};
},
// eslint-disable-next-line react-hooks/exhaustive-deps
[selectedIndices, selectionType, activeTagIndex, changeCallbackTriggerer, options]);
var tableInputProps = {
isTableInputCell: rowDensityToIsTableInputCellMapping[rowDensity],
id: 'table-editable-cell-input',
size: tableEditableCellRowDensityToInputSizeMap[rowDensity],
trailingIcon: validationStateToInputTrailingIconMap[(_props$validationStat = props.validationState) !== null && _props$validationStat !== void 0 ? _props$validationStat : 'none'],
showHintsAsTooltip: true
};
var isValidationStateNone = props.validationState === 'none' || props.validationState === undefined;
return /*#__PURE__*/jsx(BaseInput, _objectSpread(_objectSpread(_objectSpread({
as: props.isSelectInput ? 'button' : 'input',
ref: isReactNative() ? null :
// eslint-disable-next-line @typescript-eslint/no-explicit-any
function (node) {
if (isAutoCompleteInHeader) {
headerAutoCompleteRef.current = node;
} else {
triggererRef.current = node;
}
if (ref) {
if (typeof ref === 'function') {
ref(node);
} else {
ref.current = node;
}
}
},
isDropdownTrigger: true,
setInputWrapperRef: function setInputWrapperRef(wrapperNode) {
// when autocomplete is in header, its not a trigger but a component inside of DropdownOverlay
if (!isAutoCompleteInHeader) {
triggererWrapperRef.current = wrapperNode;
}
},
maxTagRows: (_props$maxRows = props.maxRows) !== null && _props$maxRows !== void 0 ? _props$maxRows : 'single',
tags: getTags({
size: props.size || 'medium'
}),
showAllTags: getShowAllTags(),
activeTagIndex: activeTagIndex,
setActiveTagIndex: setActiveTagIndex,
shouldIgnoreBlurAnimation: shouldIgnoreBlurAnimation,
setShouldIgnoreBlurAnimation: setShouldIgnoreBlurAnimation,
textAlign: "left"
// Form Props
,
label: props.label,
placeholder: selectionType === 'multiple' && selectedIndices.length > 0 ? undefined : dropdownTriggerPlaceholder,
hideLabelText: ((_props$label = props.label) === null || _props$label === void 0 ? void 0 : _props$label.length) === 0,
accessibilityLabel: props.accessibilityLabel,
labelPosition: props.labelPosition === 'inside-input' ? undefined : props.labelPosition,
isLabelInsideInput: props.labelPosition === 'inside-input',
necessityIndicator: props.necessityIndicator,
autoCompleteSuggestionType: "none",
validationState: props.validationState,
helpText: props.helpText,
errorText: props.errorText,
successText: props.successText,
name: props.name,
isDisabled: props.isDisabled,
isRequired: props.isRequired,
prefix: props.prefix,
suffix: props.suffix,
autoFocus: props.autoFocus // eslint-disable-line jsx-a11y/no-autofocus
,
value: getValue(),
onClick: function onClick(e) {
var _props$onTriggerClick;
if (props.isDisabled) {
return;
}
(_props$onTriggerClick = props.onTriggerClick) === null || _props$onTriggerClick === void 0 ? void 0 : _props$onTriggerClick.call(props, e);
},
onFocus: props.onFocus,
onBlur: function onBlur(_ref3) {
var _props$onBlur;
var name = _ref3.name;
(_props$onBlur = props.onBlur) === null || _props$onBlur === void 0 ? void 0 : _props$onBlur.call(props, {
name: name,
value: value
});
},
leadingIcon: props.icon
// Meta Props
,
componentName: props.isSelectInput ? MetaConstants.SelectInput : MetaConstants.AutoComplete,
testID: props.testID
// a11y Props
,
id: "".concat(dropdownBaseId, "-trigger"),
labelId: "".concat(dropdownBaseId, "-label"),
role: isAutoCompleteInHeader ? 'searchbox' : 'combobox',
hasPopup: isAutoCompleteInHeader ? false : getActionListContainerRole(hasFooterAction, dropdownTriggerer),
isPopupExpanded: isOpen,
activeDescendant: activeIndex >= 0 ? "".concat(dropdownBaseId, "-").concat(activeIndex) : undefined,
popupId: isAutoCompleteInHeader ? undefined : "".concat(dropdownBaseId, "-actionlist")
// Special Props for Unique behaviour between Select and AutoComplete
,
onChange: props.isSelectInput ? undefined : props.onInputValueChange,
onKeyDown: props.onTriggerKeydown,
size: props.size
}, makeAnalyticsAttribute(props)), {}, {
onTrailingInteractionElementClick: function onTrailingInteractionElementClick() {
if (!props.isDisabled) {
// Icon onClicks to the SelectInput itself
if (!isReactNative()) {
var _triggererRef$current2;
(_triggererRef$current2 = triggererRef.current) === null || _triggererRef$current2 === void 0 ? void 0 : _triggererRef$current2.focus();
}
onTriggerClick();
}
},
trailingInteractionElement: isAutoCompleteInHeader || isInsideTableEditableCell && !isValidationStateNone ? null : /*#__PURE__*/jsx(InputChevronIcon, {
isDisabled: props.isDisabled,
isOpen: isOpen
})
}, isInsideTableEditableCell ? tableInputProps : undefined), {}, {
// When AutoComplete is present inside DropdownOverlay, the floating ui adds tabIndex -1 internally. We override it with tabIndex 0 here
tabIndex: isAutoCompleteInHeader ? 0 : undefined
}));
};
var BaseDropdownInputTrigger = /*#__PURE__*/React__default.forwardRef(_BaseDropdownInputTrigger);
export { BaseDropdownInputTrigger };
//# sourceMappingURL=BaseDropdownInputTrigger.js.map