@razorpay/blade
Version:
The Design System that powers Razorpay
286 lines (276 loc) • 12.3 kB
JavaScript
import _defineProperty from '@babel/runtime/helpers/defineProperty';
import _slicedToArray from '@babel/runtime/helpers/slicedToArray';
import React__default from 'react';
import { useDropdown } from '../../Dropdown/useDropdown.js';
import { BaseDropdownInputTrigger } from './BaseDropdownInputTrigger.js';
import '../../../utils/assignWithoutSideEffects/index.js';
import '../../Box/BaseBox/index.js';
import { dropdownComponentIds } from '../../Dropdown/dropdownComponentIds.js';
import '../../../utils/index.js';
import { jsx } from 'react/jsx-runtime';
import { isReactNative } from '../../../utils/platform/isReactNative.js';
import { BaseBox } from '../../Box/BaseBox/BaseBox.web.js';
import { assignWithoutSideEffects } from '../../../utils/assignWithoutSideEffects/assignWithoutSideEffects.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 useAutoComplete = function useAutoComplete(_ref) {
var props = _ref.props,
inputValue = _ref.inputValue,
setInputValue = _ref.setInputValue,
getOptionValues = _ref.getOptionValues;
var _useDropdown = useDropdown(),
onBaseDropdownInputKeydown = _useDropdown.onTriggerKeydown,
isOpen = _useDropdown.isOpen,
setIsOpen = _useDropdown.setIsOpen,
selectedIndices = _useDropdown.selectedIndices,
setSelectedIndices = _useDropdown.setSelectedIndices,
setControlledValueIndices = _useDropdown.setControlledValueIndices,
isControlled = _useDropdown.isControlled,
options = _useDropdown.options,
setGlobalFilteredValues = _useDropdown.setFilteredValues,
activeTagIndex = _useDropdown.activeTagIndex,
setActiveTagIndex = _useDropdown.setActiveTagIndex,
setActiveIndex = _useDropdown.setActiveIndex,
globalFilteredValues = _useDropdown.filteredValues,
selectionType = _useDropdown.selectionType,
triggererRef = _useDropdown.triggererRef,
hasAutoCompleteInHeader = _useDropdown.hasAutoCompleteInHeader;
var resetFilters = function resetFilters() {
return setGlobalFilteredValues(getOptionValues());
};
// Makes sure that first item is always in focus
React__default.useEffect(function () {
var firstItemOptionIndex = options.findIndex(function (option) {
return option.value === globalFilteredValues[0];
});
if (firstItemOptionIndex >= 0) {
setActiveIndex(firstItemOptionIndex);
}
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [globalFilteredValues.length, options.length]);
// When input is empty or its single select, we want all items to be shown in filter on open of dropdown
React__default.useEffect(function () {
if (isOpen && !inputValue) {
resetFilters();
}
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [isOpen, options]);
React__default.useEffect(function () {
if (isOpen && selectionType === 'single') {
resetFilters();
}
// Just setting autoFocus is setting the input in focus state but its not showing keyboard active.
// We do this in web to get around that
if (hasAutoCompleteInHeader && isOpen && !isReactNative()) {
var _triggererRef$current;
(_triggererRef$current = triggererRef.current) === null || _triggererRef$current === void 0 ? void 0 : _triggererRef$current.focus();
}
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [isOpen]);
var onInputValueChange = function onInputValueChange(_ref2) {
var _props$onInputValueCh;
var name = _ref2.name,
value = _ref2.value;
setInputValue(value !== null && value !== void 0 ? value : '');
(_props$onInputValueCh = props.onInputValueChange) === null || _props$onInputValueCh === void 0 ? void 0 : _props$onInputValueCh.call(props, {
name: name,
value: value
});
setActiveTagIndex(-1);
if (!isOpen) {
setIsOpen(true);
}
// default filtering when filteredValues is uncontrolled
if (!props.filteredValues) {
// eslint-disable-next-line no-lonely-if
if (value && options && options.length > 0) {
var filteredOptions = getOptionValues().filter(function (optionValue) {
return optionValue.toLowerCase().includes(value.toLowerCase());
});
setGlobalFilteredValues(filteredOptions);
} else {
resetFilters();
}
}
};
var onTriggerKeydown = function onTriggerKeydown(e) {
// Pressing backspace on empty input should remove the last tag
if (e.key === 'Backspace' && !inputValue && activeTagIndex < 0 && selectedIndices.length > 0) {
if (isControlled) {
setControlledValueIndices(selectedIndices.slice(0, -1));
} else {
setSelectedIndices(selectedIndices.slice(0, -1));
}
}
onBaseDropdownInputKeydown === null || onBaseDropdownInputKeydown === void 0 ? void 0 : onBaseDropdownInputKeydown(e);
};
var onSelectionChange = function onSelectionChange(_ref3) {
var _props$onChange;
var values = _ref3.values;
console.log('selection change', values);
if (selectionType === 'multiple') {
var _props$onInputValueCh2;
setInputValue('');
(_props$onInputValueCh2 = props.onInputValueChange) === null || _props$onInputValueCh2 === void 0 ? void 0 : _props$onInputValueCh2.call(props, {
name: props.name,
value: ''
});
setActiveTagIndex(-1);
resetFilters();
} else {
var _options$find, _props$onInputValueCh3;
var displayText = (_options$find = options.find(function (option) {
return option.value === values[0];
})) === null || _options$find === void 0 ? void 0 : _options$find.title;
(_props$onInputValueCh3 = props.onInputValueChange) === null || _props$onInputValueCh3 === void 0 ? void 0 : _props$onInputValueCh3.call(props, {
name: props.name,
value: displayText
});
// Use displayText as inputValue only if its not controlled by user
if (hasAutoCompleteInHeader) {
setInputValue('');
} else if (typeof props.value === 'undefined') {
setInputValue(displayText !== null && displayText !== void 0 ? displayText : '');
}
}
(_props$onChange = props.onChange) === null || _props$onChange === void 0 ? void 0 : _props$onChange.call(props, {
name: props.name,
values: values
});
};
return {
onSelectionChange: onSelectionChange,
onTriggerKeydown: onTriggerKeydown,
onInputValueChange: onInputValueChange
};
};
var _AutoComplete = function _AutoComplete(props, ref) {
var _props$inputValue, _props$autoFocus;
var _React$useState = React__default.useState(''),
_React$useState2 = _slicedToArray(_React$useState, 2),
uncontrolledInputValue = _React$useState2[0],
setInputValue = _React$useState2[1];
var inputValue = (_props$inputValue = props.inputValue) !== null && _props$inputValue !== void 0 ? _props$inputValue : uncontrolledInputValue;
var _useDropdown2 = useDropdown(),
options = _useDropdown2.options,
setGlobalFilteredValues = _useDropdown2.setFilteredValues,
hasAutoCompleteInHeader = _useDropdown2.hasAutoCompleteInHeader,
setHasAutoCompleteInHeader = _useDropdown2.setHasAutoCompleteInHeader,
_onTriggerClick = _useDropdown2.onTriggerClick,
dropdownTriggerer = _useDropdown2.dropdownTriggerer;
var getOptionValues = React__default.useCallback(function () {
return options.map(function (option) {
return option.value;
});
}, [options]);
var _useAutoComplete = useAutoComplete({
props: props,
inputValue: inputValue,
setInputValue: setInputValue,
getOptionValues: getOptionValues
}),
onSelectionChange = _useAutoComplete.onSelectionChange,
onTriggerKeydown = _useAutoComplete.onTriggerKeydown,
onInputValueChange = _useAutoComplete.onInputValueChange;
React__default.useEffect(function () {
if (dropdownTriggerer !== dropdownComponentIds.triggers.AutoComplete) {
// When AutoComplete is mounted but not as trigger,
// it has to be somewhere in the BottomSheet (most likely header based on UI but works in other parts too)
setHasAutoCompleteInHeader(true);
}
// eslint-disable-next-line react-hooks/exhaustive-deps
}, []);
// handles controlled filteredValues state (syncs it with our global filteredValues)
React__default.useEffect(function () {
if (props.filteredValues) {
setGlobalFilteredValues(props.filteredValues);
}
}, [props.filteredValues, setGlobalFilteredValues]);
// set autoFocus to true when used inside bottomsheet
var defaultAutoFocusState = hasAutoCompleteInHeader ? true : undefined;
return /*#__PURE__*/jsx(BaseBox, {
position: "relative",
children: /*#__PURE__*/jsx(BaseDropdownInputTrigger, _objectSpread(_objectSpread({}, props), {}, {
// eslint-disable-next-line jsx-a11y/no-autofocus
autoFocus: (_props$autoFocus = props.autoFocus) !== null && _props$autoFocus !== void 0 ? _props$autoFocus : defaultAutoFocusState
// eslint-disable-next-line @typescript-eslint/no-explicit-any
,
ref: ref,
onChange: onSelectionChange,
isSelectInput: false,
inputValue: inputValue,
syncInputValueWithSelection: function syncInputValueWithSelection(value) {
var _selectedOption$title;
if (!value) {
setInputValue('');
return;
}
var selectedOption = options.find(function (option) {
return option.value === value;
});
setInputValue((_selectedOption$title = selectedOption === null || selectedOption === void 0 ? void 0 : selectedOption.title) !== null && _selectedOption$title !== void 0 ? _selectedOption$title : '');
},
onTriggerKeydown: onTriggerKeydown,
onInputValueChange: onInputValueChange,
onTriggerClick: function onTriggerClick(triggerEvent) {
var _props$onClick;
if (!hasAutoCompleteInHeader) {
// we don't want clicking on autocomplete to open / close Dropdown when it is used inside BottomSheet's header
_onTriggerClick();
}
props === null || props === void 0 ? void 0 : (_props$onClick = props.onClick) === null || _props$onClick === void 0 ? void 0 : _props$onClick.call(props, triggerEvent);
}
}))
});
};
/**
* ### AutoComplete
*
* Extension on top of SelectInput which allows you type and filter between ActionList items
*
* To be used in combination of `Dropdown` and `ActionList` component
*
* ---
*
* #### Usage in Desktop
*
* ```diff
* <Dropdown>
* + <AutoComplete label="Select Fruits" />
* <DropdownOverlay>
* <ActionList>
* <ActionListItem title="Mango" value="mango" />
* <ActionListItem title="Apple" value="apple" />
* </ActionList>
* </DropdownOverlay>
* </Dropdown>
* ```
*
* #### Usage in Mobile
*
* ```diff
* <Dropdown>
* + <SelectInput label="Select Fruits" />
* <BottomSheet>
* <BottomSheetHeader>
* + <AutoComplete label="Select Fruits" />
* </BottomSheetHeader>
* <BottomSheetBody>
* <ActionList>
* <ActionListItem title="Mango" value="mango" />
* <ActionListItem title="Apple" value="apple" />
* </ActionList>
* </BottomSheetBody>
* </BottomSheet>
* </Dropdown>
* ```
*
* ---
*
* Checkout {@link https://blade.razorpay.com/?path=/docs/components-dropdown-with-autocomplete--with-single-select AutoComplete Documentation}.
*/
var AutoComplete = /*#__PURE__*/assignWithoutSideEffects( /*#__PURE__*/React__default.forwardRef(_AutoComplete), {
componentId: dropdownComponentIds.triggers.AutoComplete
});
export { AutoComplete };
//# sourceMappingURL=AutoComplete.js.map