@transferwise/components 45.27.0 → 45.28.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/build/index.js CHANGED
@@ -6894,6 +6894,7 @@ function SelectInput({
6894
6894
  size = 'md',
6895
6895
  className,
6896
6896
  onChange,
6897
+ onSearchChange,
6897
6898
  onClear
6898
6899
  }) {
6899
6900
  const [open, setOpen] = React.useState(false);
@@ -6964,7 +6965,8 @@ function SelectInput({
6964
6965
  filterable: filterable,
6965
6966
  filterPlaceholder: filterPlaceholder,
6966
6967
  searchInputRef: searchInputRef,
6967
- listboxRef: listboxRef
6968
+ listboxRef: listboxRef,
6969
+ onSearchChange: onSearchChange
6968
6970
  })
6969
6971
  })
6970
6972
  });
@@ -7032,7 +7034,8 @@ function SelectInputOptions({
7032
7034
  filterable = false,
7033
7035
  filterPlaceholder,
7034
7036
  searchInputRef,
7035
- listboxRef
7037
+ listboxRef,
7038
+ onSearchChange
7036
7039
  }) {
7037
7040
  const intl = reactIntl.useIntl();
7038
7041
  const controllerRef = filterable ? searchInputRef : listboxRef;
@@ -7084,6 +7087,9 @@ function SelectInputOptions({
7084
7087
  },
7085
7088
  onChange: event => {
7086
7089
  setQuery(event.currentTarget.value);
7090
+ if (onSearchChange) {
7091
+ onSearchChange(event.currentTarget.value);
7092
+ }
7087
7093
  }
7088
7094
  })
7089
7095
  }) : null, /*#__PURE__*/jsxRuntime.jsxs("section", {
@@ -7813,1139 +7819,526 @@ Money.propTypes = {
7813
7819
  var Money$1 = Money;
7814
7820
 
7815
7821
  var messages$3 = reactIntl.defineMessages({
7816
- searchPlaceholder: {
7817
- id: "neptune.Select.searchPlaceholder"
7822
+ selectPlaceholder: {
7823
+ id: "neptune.MoneyInput.Select.placeholder"
7818
7824
  }
7819
7825
  });
7820
7826
 
7821
- // Option.tsx NEW
7822
- function Option$1({
7823
- label,
7824
- currency = '',
7825
- note = '',
7826
- secondary = '',
7827
- icon,
7828
- classNames = {},
7829
- selected = false
7830
- }) {
7831
- const {
7832
- isModern
7833
- } = componentsTheming.useTheme();
7834
- const style = classes => classes.map(className => classNames[className] || className).join(' ');
7835
- const currencyClassNames = currency ? style(['currency-flag', `currency-flag-${currency.toLowerCase()}`]) : undefined;
7836
- const iconElement = icon ? /*#__PURE__*/React.cloneElement(icon, {
7837
- size: 24,
7838
- className: 'tw-icon'
7839
- }) : currency && /*#__PURE__*/jsxRuntime.jsx("i", {
7840
- className: currencyClassNames
7841
- });
7842
- const titleAndNoteElement = /*#__PURE__*/jsxRuntime.jsxs(Body, {
7843
- as: "span",
7844
- type: exports.Typography.BODY_LARGE,
7845
- className: selected ? 'text-ellipsis' : undefined,
7846
- children: [label, note && /*#__PURE__*/jsxRuntime.jsx(Body, {
7847
- as: "span",
7848
- className: isModern ? 'm-l-1' : 'm-l-1 body-2',
7849
- children: note
7850
- })]
7851
- });
7852
- const secondaryElementClassNames = () => {
7853
- let classes = undefined;
7854
- if (selected) {
7855
- classes = 'text-ellipsis';
7856
- }
7857
- if (isModern) {
7858
- return classes;
7859
- }
7860
- return `${classes ? classes + ' ' : ''}body-2`;
7861
- };
7862
- const secondaryElement = secondary && /*#__PURE__*/jsxRuntime.jsx(Body, {
7863
- className: secondaryElementClassNames(),
7864
- children: secondary
7865
- });
7866
- return iconElement ? /*#__PURE__*/jsxRuntime.jsxs("div", {
7867
- className: "d-flex np-option-content",
7868
- children: [/*#__PURE__*/jsxRuntime.jsx("div", {
7869
- className: `d-flex flex-column${selected ? ' justify-content-center' : ''}`,
7870
- children: iconElement
7871
- }), /*#__PURE__*/jsxRuntime.jsxs("div", {
7872
- className: "d-flex flex-column justify-content-center",
7873
- children: [titleAndNoteElement, secondaryElement]
7874
- })]
7875
- }) : /*#__PURE__*/jsxRuntime.jsxs(jsxRuntime.Fragment, {
7876
- children: [iconElement, titleAndNoteElement, secondaryElement]
7877
- });
7827
+ // TODO: do not duplicate this between formatting and components
7828
+ const currencyDecimals = {
7829
+ BIF: 0,
7830
+ BYR: 0,
7831
+ CLP: 0,
7832
+ DJF: 0,
7833
+ GNF: 0,
7834
+ JPY: 0,
7835
+ KMF: 0,
7836
+ KRW: 0,
7837
+ MGA: 0,
7838
+ PYG: 0,
7839
+ RWF: 0,
7840
+ VND: 0,
7841
+ VUV: 0,
7842
+ XAF: 0,
7843
+ XOF: 0,
7844
+ XPF: 0,
7845
+ // technically HUF does have decimals, but due to the exchange rate banks
7846
+ // do not accept decimal amounts
7847
+ HUF: 0,
7848
+ BHD: 3,
7849
+ JOD: 3,
7850
+ KWD: 3,
7851
+ OMR: 3,
7852
+ TND: 3
7853
+ };
7854
+ const DEFAULT_CURRENCY_DECIMALS = 2;
7855
+ function isNumberLocaleSupported() {
7856
+ const number = 1234;
7857
+ const numberString = number.toLocaleString && number.toLocaleString(DEFAULT_LOCALE);
7858
+ return numberString === '1,234';
7878
7859
  }
7879
-
7880
- const SearchBox = /*#__PURE__*/React.forwardRef(({
7881
- id,
7882
- classNames = {},
7883
- focusedOptionId,
7884
- onChange,
7885
- onClick,
7886
- placeholder = undefined,
7887
- value = ''
7888
- }, reference) => {
7889
- const style = className => classNames[className] || className;
7890
- return /*#__PURE__*/jsxRuntime.jsx("li", {
7891
- className: style('border-bottom'),
7892
- children: /*#__PURE__*/jsxRuntime.jsx("a", {
7893
- className: `${style('np-select-filter-link')} ${style('p-a-0')}`,
7894
- children: /*#__PURE__*/jsxRuntime.jsxs("div", {
7895
- className: style('input-group'),
7896
- children: [/*#__PURE__*/jsxRuntime.jsx("span", {
7897
- className: classNames__default.default('input-group-addon', 'input-group-addon--search'),
7898
- children: /*#__PURE__*/jsxRuntime.jsx(icons.Search, {
7899
- className: classNames__default.default(style('tw-icon'), style('tw-icon-search')),
7900
- size: 24
7901
- })
7902
- }), /*#__PURE__*/jsxRuntime.jsx(Input, {
7903
- ref: reference,
7904
- id: id,
7905
- role: "searchbox",
7906
- inputMode: "search",
7907
- className: classNames__default.default(style('np-select-filter')),
7908
- placeholder: placeholder,
7909
- value: value,
7910
- spellCheck: "false",
7911
- "aria-activedescendant": focusedOptionId,
7912
- onChange: onChange,
7913
- onClick: onClick
7914
- })]
7915
- })
7916
- })
7917
- });
7918
- });
7919
- var SearchBox$1 = SearchBox;
7920
-
7921
- const DEFAULT_SEARCH_VALUE = '';
7922
- const DEFAULT_OPTIONS_PAGE_SIZE = 1000;
7923
- const includesString = (string1, string2) => string1.toLowerCase().includes(string2.toLowerCase());
7924
- function defaultFilterFunction(option, searchValue) {
7925
- if (isPlaceholderOption(option)) {
7926
- return true;
7860
+ function getValidLocale(locale) {
7861
+ try {
7862
+ const noUnderscoreLocale = locale.replace(/_/, '-');
7863
+ Intl.NumberFormat(noUnderscoreLocale);
7864
+ return noUnderscoreLocale;
7865
+ } catch {
7866
+ return 'en-GB';
7927
7867
  }
7928
- const {
7929
- label,
7930
- note,
7931
- secondary,
7932
- currency,
7933
- searchStrings
7934
- } = option;
7935
- return !!label && includesString(label, searchValue) || !!note && includesString(note, searchValue) || !!secondary && includesString(secondary, searchValue) || !!currency && includesString(currency, searchValue) || !!searchStrings && searchStrings.some(string => includesString(string, searchValue));
7936
- }
7937
- function isActionableOption(option) {
7938
- return !option.header && !option.separator && !option.disabled;
7939
7868
  }
7940
- function isHeaderOption(option) {
7941
- return option != null && 'header' in option;
7869
+ function getCurrencyDecimals(currency = '') {
7870
+ const upperCaseCurrency = currency.toUpperCase();
7871
+ if (Object.prototype.hasOwnProperty.call(currencyDecimals, upperCaseCurrency)) {
7872
+ return currencyDecimals[upperCaseCurrency];
7873
+ }
7874
+ return DEFAULT_CURRENCY_DECIMALS;
7942
7875
  }
7943
- function isSeparatorOption(option) {
7944
- return option != null && 'separator' in option;
7876
+ function getDecimalSeparator(locale) {
7877
+ return isNumberLocaleSupported() ? 1.1.toLocaleString(locale)[1] : '.';
7945
7878
  }
7946
- function clamp(from, to, value) {
7947
- return Math.max(Math.min(to, value), from);
7879
+ function parseAmount(number, currency, locale) {
7880
+ const validLocale = getValidLocale(locale);
7881
+ const precision = getCurrencyDecimals(currency);
7882
+ const groupSeparator = isNumberLocaleSupported() ? 10000 .toLocaleString(validLocale)[2] : ',';
7883
+ const decimalSeparator = getDecimalSeparator(validLocale);
7884
+ const numberWithStandardDecimalSeparator = (number ? `${number}` : '').replace(new RegExp(`\\${groupSeparator}`, 'g'), '').replace(new RegExp(`\\${decimalSeparator}`, 'g'), '.').replace(/[^0-9.]/g, '');
7885
+ const parsedAmount = parseFloat(parseFloat(numberWithStandardDecimalSeparator).toFixed(precision));
7886
+ return Math.abs(parsedAmount);
7948
7887
  }
7949
7888
 
7950
- /**
7951
- * No option or placeholder option is selected
7952
- */
7953
- const DEFAULT_SELECTED_OPTION = null;
7954
- function isPlaceholderOption(option) {
7955
- return option === DEFAULT_SELECTED_OPTION || 'placeholder' in option;
7956
- }
7957
- function isSearchableOption(option) {
7958
- return !isHeaderOption(option) && !isSeparatorOption(option) && !isPlaceholderOption(option);
7959
- }
7960
- const getUniqueIdForOption = (parentId = '', option) => {
7961
- if (option == null) {
7962
- return undefined;
7889
+ const Currency = PropTypes__default.default.shape({
7890
+ header: PropTypes__default.default.string,
7891
+ value: PropTypes__default.default.string,
7892
+ label: PropTypes__default.default.string,
7893
+ currency: PropTypes__default.default.string,
7894
+ note: PropTypes__default.default.string,
7895
+ searchable: PropTypes__default.default.string
7896
+ });
7897
+ const isNumberOrNull = v => neptuneValidation.isNumber(v) || neptuneValidation.isNull(v);
7898
+ const formatAmountIfSet = (amount, currency, locale, maxLengthOverride) => {
7899
+ if (maxLengthOverride) {
7900
+ return amount || '';
7901
+ } else {
7902
+ return typeof amount === 'number' ? formatting.formatAmount(amount, currency, locale) : '';
7963
7903
  }
7964
- const uniqueOptionId = option.value || (option.label?.replace(/\s/g, '') ?? '');
7965
- return `option-${parentId}-${uniqueOptionId}`;
7966
7904
  };
7967
-
7968
- /**
7969
- * @deprecated Use `SelectInput` instead (https://neptune.wise.design/blog/2023-11-28-adopting-our-new-selectinput)
7970
- */
7971
- function Select({
7972
- placeholder,
7973
- id,
7974
- required,
7975
- disabled,
7976
- inverse,
7977
- dropdownWidth,
7978
- size,
7979
- block,
7980
- selected,
7981
- search,
7982
- onChange,
7983
- onFocus,
7984
- onBlur,
7985
- options: defaultOptions,
7986
- onSearchChange,
7987
- searchValue: initSearchValue,
7988
- searchPlaceholder,
7989
- // eslint-disable-next-line unicorn/prevent-abbreviations
7990
- classNames: classNamesProp,
7991
- dropdownUp,
7992
- dropdownProps,
7993
- buttonProps
7994
- }) {
7995
- const {
7996
- formatMessage
7997
- } = reactIntl.useIntl();
7998
- const {
7999
- isModern
8000
- } = componentsTheming.useTheme();
8001
- const s = className => classNamesProp[className] || className;
8002
- const [open, setOpen] = React.useState(false);
8003
- const [searchValue, setSearchValue] = React.useState(DEFAULT_SEARCH_VALUE);
8004
- const [keyboardFocusedOptionIndex, setKeyboardFocusedOptionIndex] = React.useState(null);
8005
- const keyboardFocusedReference = React.useRef();
8006
- const previousKeyboardFocusedOptionIndex = React.useRef();
8007
- const [numberOfOptionsShown, setNumberOfOptionsShown] = React.useState(DEFAULT_OPTIONS_PAGE_SIZE);
8008
- const searchBoxReference = React.useRef(null);
8009
- const selectReference = React.useRef(null);
8010
- const dropdownButtonReference = React.useRef(null);
8011
- const optionsListReference = React.useRef(null);
8012
- const isSearchEnabled = !!onSearchChange || !!search;
8013
- const isDropdownAutoWidth = dropdownWidth == null;
8014
- const fallbackButtonId = React.useMemo(() => getSimpleRandomId('np-select-'), []);
8015
- const options = React.useMemo(() => {
8016
- if (!search || !searchValue) {
8017
- return defaultOptions;
8018
- }
8019
- return defaultOptions.filter(isSearchableOption).filter(option => {
8020
- if (typeof search === 'function') {
8021
- return search(option, searchValue);
8022
- } else {
8023
- return defaultFilterFunction(option, searchValue);
8024
- }
7905
+ const parseNumber = (amount, currency, locale, maxLengthOverride) => {
7906
+ if (!maxLengthOverride) {
7907
+ return parseAmount(amount, currency, locale);
7908
+ }
7909
+ if (maxLengthOverride && amount.length > maxLengthOverride) {
7910
+ return 0;
7911
+ }
7912
+ return +amount;
7913
+ };
7914
+ const inputKeyCodeAllowlist = new Set([KeyCodes.BACKSPACE, KeyCodes.DELETE, KeyCodes.COMMA, KeyCodes.PERIOD, KeyCodes.DOWN, KeyCodes.UP, KeyCodes.LEFT, KeyCodes.RIGHT, KeyCodes.ENTER, KeyCodes.ESCAPE, KeyCodes.TAB]);
7915
+ const inputKeyAllowlist = new Set([Key.PERIOD, Key.COMMA]);
7916
+ class MoneyInput extends React.Component {
7917
+ constructor(props) {
7918
+ super(props);
7919
+ const {
7920
+ locale
7921
+ } = this.props.intl;
7922
+ this.formatMessage = this.props.intl.formatMessage;
7923
+ this.state = {
7924
+ searchQuery: '',
7925
+ selectedOption: this.props.selectedCurrency,
7926
+ formattedAmount: formatAmountIfSet(props.amount, props.selectedCurrency.currency, locale, props.maxLengthOverride),
7927
+ locale
7928
+ };
7929
+ }
7930
+ UNSAFE_componentWillReceiveProps(nextProps) {
7931
+ this.setState({
7932
+ locale: nextProps?.intl?.locale
8025
7933
  });
8026
- }, [defaultOptions, search, searchValue]);
8027
- const selectableOptions = React.useMemo(() => options.filter(isActionableOption), [options]);
8028
- const focusedOption = selectableOptions[keyboardFocusedOptionIndex];
8029
- const computedId = id || fallbackButtonId;
8030
- const listboxId = `${computedId}-listbox`;
8031
- const searchBoxId = `${computedId}-searchbox`;
8032
- const {
8033
- isMobile
8034
- } = useLayout();
8035
- React.useEffect(() => {
8036
- let cancelled;
8037
- if (keyboardFocusedOptionIndex >= 0) {
8038
- requestAnimationFrame(() => {
8039
- if (!cancelled) {
8040
- if (isSearchEnabled) {
8041
- keyboardFocusedReference.current?.scrollIntoView?.({
8042
- block: 'center'
8043
- });
8044
- } else {
8045
- keyboardFocusedReference.current?.focus();
8046
- }
8047
- }
7934
+ if (!this.amountFocused) {
7935
+ this.setState({
7936
+ formattedAmount: formatAmountIfSet(nextProps.amount, nextProps.selectedCurrency.currency, nextProps?.intl?.locale, nextProps.maxLengthOverride)
8048
7937
  });
8049
- return () => {
8050
- cancelled = true;
8051
- };
8052
7938
  }
8053
- }, [keyboardFocusedOptionIndex, isSearchEnabled]);
8054
- const handleOnClick = () => {
8055
- setOpen(true);
7939
+ }
7940
+ isInputAllowedForKeyEvent = event => {
7941
+ const {
7942
+ keyCode,
7943
+ metaKey,
7944
+ key,
7945
+ ctrlKey
7946
+ } = event;
7947
+ const isNumberKey = neptuneValidation.isNumber(parseInt(key, 10));
7948
+ return isNumberKey || metaKey || ctrlKey || inputKeyCodeAllowlist.has(keyCode) || inputKeyAllowlist.has(key);
8056
7949
  };
8057
- const handleTouchStart = event => {
8058
- if (event.currentTarget === event.target && open) {
8059
- handleCloseOptions();
7950
+ handleKeyDown = event => {
7951
+ if (!this.isInputAllowedForKeyEvent(event)) {
7952
+ event.preventDefault();
8060
7953
  }
8061
7954
  };
8062
- const handleOnFocus = event => {
8063
- if (onFocus) {
8064
- onFocus(event);
7955
+ handlePaste = event => {
7956
+ const paste = (event.clipboardData || window.clipboardData).getData('text');
7957
+ const {
7958
+ locale
7959
+ } = this.state;
7960
+ const parsed = neptuneValidation.isEmpty(paste) ? null : parseNumber(paste, this.props.selectedCurrency.currency, locale, this.props.maxLengthOverride);
7961
+ if (isNumberOrNull(parsed)) {
7962
+ this.setState({
7963
+ formattedAmount: formatAmountIfSet(parsed, this.props.selectedCurrency.currency, locale, this.props.maxLengthOverride)
7964
+ });
7965
+ this.props.onAmountChange(parsed);
8065
7966
  }
7967
+ event.preventDefault();
8066
7968
  };
8067
- const handleOnBlur = event => {
7969
+ onAmountChange = event => {
8068
7970
  const {
8069
- nativeEvent
8070
- } = event;
8071
- if (nativeEvent) {
8072
- const elementReceivingFocus = nativeEvent.relatedTarget;
8073
- const select = event.currentTarget;
8074
- if (select && elementReceivingFocus && select.contains(elementReceivingFocus)) {
8075
- return;
8076
- }
8077
- }
8078
- if (onBlur) {
8079
- onBlur(event);
7971
+ value
7972
+ } = event.target;
7973
+ this.setState({
7974
+ formattedAmount: value
7975
+ });
7976
+ const parsed = neptuneValidation.isEmpty(value) ? null : parseNumber(value, this.props.selectedCurrency.currency, this.state.locale, this.props.maxLengthOverride);
7977
+ if (isNumberOrNull(parsed)) {
7978
+ this.props.onAmountChange(parsed);
8080
7979
  }
8081
7980
  };
8082
- const handleSearchChange = event => {
8083
- setNumberOfOptionsShown(DEFAULT_OPTIONS_PAGE_SIZE);
8084
- setSearchValue(event.target.value);
8085
- if (onSearchChange) {
8086
- onSearchChange(event.target.value);
8087
- }
7981
+ onAmountBlur = () => {
7982
+ this.amountFocused = false;
7983
+ this.setAmount();
8088
7984
  };
8089
- const handleKeyDown = event => {
8090
- switch (event.keyCode) {
8091
- case KeyCodes.UP:
8092
- case KeyCodes.DOWN:
8093
- if (open) {
8094
- moveFocusWithDifference(event.keyCode === KeyCodes.UP ? -1 : 1);
8095
- } else {
8096
- setOpen(true);
8097
- }
8098
- stopPropagation$1(event);
8099
- break;
8100
- case KeyCodes.SPACE:
8101
- if (event.target !== searchBoxReference.current) {
8102
- if (open) {
8103
- selectKeyboardFocusedOption();
8104
- } else {
8105
- setOpen(true);
8106
- }
8107
- stopPropagation$1(event);
8108
- }
8109
- break;
8110
- case KeyCodes.ENTER:
8111
- if (open) {
8112
- selectKeyboardFocusedOption();
8113
- } else {
8114
- setOpen(true);
8115
- }
8116
- stopPropagation$1(event);
8117
- break;
8118
- case KeyCodes.ESCAPE:
8119
- handleCloseOptions();
8120
- stopPropagation$1(event);
8121
- break;
8122
- case KeyCodes.TAB:
8123
- if (open) {
8124
- selectKeyboardFocusedOption();
8125
- }
8126
- break;
8127
- }
7985
+ onAmountFocus = () => {
7986
+ this.amountFocused = true;
8128
7987
  };
8129
- function selectKeyboardFocusedOption() {
8130
- if (keyboardFocusedOptionIndex != null) {
8131
- selectableOptions.length > 0 && selectOption(selectableOptions[keyboardFocusedOptionIndex]);
8132
- }
8133
- }
8134
- function moveFocusWithDifference(difference) {
8135
- const selectedOptionIndex = selectableOptions.reduce((optionIndex, current, index) => {
8136
- if (optionIndex != null) {
8137
- return optionIndex;
8138
- }
8139
- if (isOptionSelected(selected, current)) {
8140
- return index;
8141
- }
8142
- return null;
8143
- }, null);
8144
- const previousFocusedIndex = previousKeyboardFocusedOptionIndex.current ?? -1;
8145
- let indexToStartMovingFrom = previousFocusedIndex;
8146
- if (previousFocusedIndex === -1) {
8147
- if (selectedOptionIndex == null) {
8148
- setKeyboardFocusedOptionIndex(0);
7988
+ mapOption = item => {
7989
+ return {
7990
+ type: 'option',
7991
+ value: item,
7992
+ filterMatchers: [item.value, item.label, item.note, item.searchable]
7993
+ };
7994
+ };
7995
+ getSelectOptions() {
7996
+ const selectOptions = [...filterOptionsForQuery(this.props.currencies, this.state.searchQuery)];
7997
+ let formattedOptions = [];
7998
+ let groupIndex = null;
7999
+ selectOptions.forEach(item => {
8000
+ if (item.header) {
8001
+ formattedOptions.push({
8002
+ type: 'group',
8003
+ label: item.header,
8004
+ options: []
8005
+ });
8006
+ groupIndex = formattedOptions.length - 1;
8149
8007
  } else {
8150
- indexToStartMovingFrom = selectedOptionIndex;
8008
+ if (groupIndex === null) {
8009
+ formattedOptions.push(this.mapOption(item));
8010
+ } else {
8011
+ formattedOptions[groupIndex]?.options.push(this.mapOption(item));
8012
+ }
8151
8013
  }
8152
- }
8153
- const unClampedNewIndex = indexToStartMovingFrom + difference;
8154
- const newIndex = clamp(0, selectableOptions.length - 1, unClampedNewIndex);
8155
- setKeyboardFocusedOptionIndex(newIndex);
8014
+ });
8015
+ return formattedOptions;
8156
8016
  }
8157
- React.useEffect(() => {
8158
- if (open) {
8159
- if (!isMobile || searchValue) {
8160
- if (isSearchEnabled && !!searchBoxReference.current) {
8161
- searchBoxReference.current.focus();
8162
- }
8163
- if (!isSearchEnabled && optionsListReference.current && (previousKeyboardFocusedOptionIndex.current == null || Number.isNaN(previousKeyboardFocusedOptionIndex.current))) {
8164
- optionsListReference.current.focus();
8165
- }
8017
+ setAmount() {
8018
+ this.setState(previousState => {
8019
+ const parsed = parseNumber(previousState.formattedAmount, this.props.selectedCurrency.currency, previousState.locale, this.props.maxLengthOverride);
8020
+ if (!isNumberOrNull(parsed)) {
8021
+ return {
8022
+ formattedAmount: previousState.formattedAmount
8023
+ };
8166
8024
  }
8167
- previousKeyboardFocusedOptionIndex.current = keyboardFocusedOptionIndex;
8168
- } else {
8169
- previousKeyboardFocusedOptionIndex.current = null;
8025
+ return {
8026
+ formattedAmount: formatAmountIfSet(parsed, this.props.selectedCurrency.currency, previousState.locale, this.props.maxLengthOverride)
8027
+ };
8028
+ });
8029
+ }
8030
+ handleSelectChange = value => {
8031
+ this.handleSearchChange('');
8032
+ this.setState({
8033
+ selectedOption: value
8034
+ });
8035
+ this.props.onCurrencyChange(value);
8036
+ };
8037
+ handleCustomAction = () => {
8038
+ this.handleSearchChange('');
8039
+ if (this.props.onCustomAction) {
8040
+ this.props.onCustomAction();
8170
8041
  }
8171
- }, [open, searchValue, isSearchEnabled, isMobile, keyboardFocusedOptionIndex]);
8172
- const handleCloseOptions = () => {
8173
- setOpen(false);
8174
- setKeyboardFocusedOptionIndex(null);
8175
- if (dropdownButtonReference.current) {
8176
- dropdownButtonReference.current.focus();
8042
+ };
8043
+ handleSearchChange = searchQuery => {
8044
+ this.setState({
8045
+ searchQuery
8046
+ });
8047
+ if (this.props.onSearchChange) {
8048
+ this.props.onSearchChange({
8049
+ searchQuery,
8050
+ filteredOptions: filterOptionsForQuery(this.props.currencies, searchQuery)
8051
+ });
8177
8052
  }
8178
8053
  };
8179
- function createSelectHandlerForOption(option) {
8180
- return event => {
8181
- stopPropagation$1(event);
8182
- selectOption(option);
8183
- };
8184
- }
8185
- function selectOption(option) {
8186
- onChange(isPlaceholderOption(option) ? DEFAULT_SELECTED_OPTION : option);
8187
- handleCloseOptions();
8188
- }
8189
- function renderOptionsList({
8190
- className
8191
- } = {}) {
8192
- const dropdownClass = classNames__default.default(s('np-dropdown-menu'), {
8193
- [s('np-dropdown-menu-desktop')]: !isMobile,
8194
- [s(`np-dropdown-menu-${dropdownWidth}`)]: !isMobile && !isDropdownAutoWidth
8195
- }, s(className));
8196
- const showPlaceholder = !required && !isSearchEnabled && Boolean(placeholder);
8197
- return /*#__PURE__*/jsxRuntime.jsxs("ul", {
8198
- ref: optionsListReference,
8199
- id: listboxId,
8200
- role: "listbox",
8201
- "aria-orientation": "vertical",
8202
- "aria-activedescendant": getUniqueIdForOption(id, selected),
8203
- tabIndex: "-1",
8204
- className: dropdownClass,
8205
- ...dropdownProps,
8206
- children: [showPlaceholder && /*#__PURE__*/jsxRuntime.jsx(PlaceHolderOption, {}), isSearchEnabled && /*#__PURE__*/jsxRuntime.jsx(SearchBox$1, {
8207
- ref: searchBoxReference,
8208
- id: searchBoxId,
8209
- classNames: classNamesProp,
8210
- value: initSearchValue || searchValue,
8211
- placeholder: searchPlaceholder || formatMessage(messages$3.searchPlaceholder),
8212
- focusedOptionId: getUniqueIdForOption(id, focusedOption),
8213
- onChange: handleSearchChange,
8214
- onClick: stopPropagation$1
8215
- }), options.slice(0, numberOfOptionsShown).map(renderOption), numberOfOptionsShown < options.length && /*#__PURE__*/jsxRuntime.jsx(ShowMoreOption, {})]
8216
- });
8217
- }
8218
- function ShowMoreOption() {
8219
- function handleOnClick(event) {
8220
- stopPropagation$1(event);
8221
- setNumberOfOptionsShown(numberOfOptionsShown + DEFAULT_OPTIONS_PAGE_SIZE);
8222
- }
8223
- return (
8224
- /*#__PURE__*/
8225
- /* eslint-disable-next-line jsx-a11y/no-noninteractive-element-interactions */
8226
- jsxRuntime.jsx("li", {
8227
- className: classNames__default.default(s('clickable'), s('border-bottom'), s('show-more')),
8228
- onClick: handleOnClick,
8229
- onKeyPress: handleOnClick,
8230
- children: /*#__PURE__*/jsxRuntime.jsx("a", {
8231
- children: "..."
8232
- })
8233
- })
8234
- );
8235
- }
8236
- function PlaceHolderOption() {
8237
- const placeholderOption = {
8238
- placeholder
8054
+ style = className => this.props.classNames[className] || className;
8055
+ render() {
8056
+ const {
8057
+ selectedCurrency,
8058
+ onCurrencyChange,
8059
+ size,
8060
+ addon,
8061
+ id,
8062
+ selectProps,
8063
+ maxLengthOverride
8064
+ } = this.props;
8065
+ const selectOptions = this.getSelectOptions();
8066
+ const getFirstOption = () => {
8067
+ if (selectOptions.length !== 0) {
8068
+ const firstOption = selectOptions[0];
8069
+ if (firstOption.type === 'option') {
8070
+ return firstOption.value;
8071
+ }
8072
+ if (firstOption.type === 'group' && firstOption.options.length !== 0) {
8073
+ return firstOption.options[0].value;
8074
+ }
8075
+ }
8076
+ return null;
8239
8077
  };
8240
- return (
8241
- /*#__PURE__*/
8242
- /* eslint-disable-next-line jsx-a11y/no-noninteractive-element-interactions */
8243
- jsxRuntime.jsx("li", {
8244
- className: classNames__default.default(s('clickable'), s('border-bottom')),
8245
- onClick: createSelectHandlerForOption(placeholderOption),
8246
- onKeyPress: createSelectHandlerForOption(placeholderOption),
8247
- children: /*#__PURE__*/jsxRuntime.jsx("a", {
8248
- children: placeholder
8078
+ const firstOption = getFirstOption();
8079
+ const isFixedCurrency = !this.state.searchQuery && (selectOptions.length === 1 && firstOption.currency === selectedCurrency.currency || !onCurrencyChange);
8080
+ const disabled = !this.props.onAmountChange;
8081
+ return /*#__PURE__*/jsxRuntime.jsxs("div", {
8082
+ className: classNames__default.default(this.style('tw-money-input'), this.style('input-group'), this.style(`input-group-${size}`)),
8083
+ children: [/*#__PURE__*/jsxRuntime.jsx(Input, {
8084
+ id: id,
8085
+ value: this.state.formattedAmount,
8086
+ inputMode: "decimal",
8087
+ disabled: disabled,
8088
+ maxLength: maxLengthOverride,
8089
+ placeholder: formatAmountIfSet(this.props.placeholder, this.props.selectedCurrency.currency, this.state.locale, this.props.maxLengthOverride),
8090
+ autoComplete: "off",
8091
+ onKeyDown: this.handleKeyDown,
8092
+ onChange: this.onAmountChange,
8093
+ onFocus: this.onAmountFocus,
8094
+ onBlur: this.onAmountBlur,
8095
+ onPaste: this.handlePaste
8096
+ }), addon && /*#__PURE__*/jsxRuntime.jsx("span", {
8097
+ className: classNames__default.default(this.style('input-group-addon'), this.style(`input-${size}`), disabled ? this.style('disabled') : ''),
8098
+ children: addon
8099
+ }), isFixedCurrency ? /*#__PURE__*/jsxRuntime.jsxs("div", {
8100
+ className: classNames__default.default(this.style('input-group-addon'), this.style(`input-${size}`), this.style('tw-money-input__fixed-currency'), disabled ? this.style('disabled') : ''),
8101
+ children: [(size === 'lg' || size === 'md') && /*#__PURE__*/jsxRuntime.jsx("span", {
8102
+ className: classNames__default.default(this.style('money-input-currency-flag'), this.style('m-r-2')),
8103
+ children: /*#__PURE__*/jsxRuntime.jsx(art.Flag, {
8104
+ code: selectedCurrency.currency.toLowerCase(),
8105
+ intrinsicSize: 24
8106
+ })
8107
+ }), /*#__PURE__*/jsxRuntime.jsx(Title, {
8108
+ as: "span",
8109
+ type: exports.Typography.TITLE_SUBSECTION,
8110
+ className: size === 'lg' ? this.style('m-r-1') : '',
8111
+ children: selectedCurrency.currency.toUpperCase()
8112
+ })]
8113
+ }) : /*#__PURE__*/jsxRuntime.jsx("div", {
8114
+ className: classNames__default.default(this.style('input-group-btn'), this.style('amount-currency-select-btn')),
8115
+ children: /*#__PURE__*/jsxRuntime.jsx(SelectInput, {
8116
+ items: selectOptions,
8117
+ value: this.state.selectedOption,
8118
+ compareValues: "currency",
8119
+ renderValue: (currency, withinTrigger) => {
8120
+ return /*#__PURE__*/jsxRuntime.jsx(SelectInputOptionContent, {
8121
+ title: currency.label,
8122
+ note: withinTrigger ? undefined : currency.note,
8123
+ icon: /*#__PURE__*/jsxRuntime.jsx(art.Flag, {
8124
+ code: currency.currency,
8125
+ intrinsicSize: 24
8126
+ })
8127
+ });
8128
+ },
8129
+ renderFooter: this.props.onCustomAction ? () =>
8130
+ /*#__PURE__*/
8131
+ // eslint-disable-next-line jsx-a11y/click-events-have-key-events
8132
+ jsxRuntime.jsx("div", {
8133
+ role: "button",
8134
+ tabIndex: "0",
8135
+ onClick: this.handleCustomAction,
8136
+ children: this.props.customActionLabel
8137
+ }) : null,
8138
+ placeholder: this.formatMessage(messages$3.selectPlaceholder),
8139
+ filterable: true,
8140
+ filterPlaceholder: this.props.searchPlaceholder,
8141
+ disabled: disabled,
8142
+ size: size,
8143
+ onChange: this.handleSelectChange,
8144
+ onSearchChange: this.handleSearchChange,
8145
+ ...selectProps
8249
8146
  })
8250
- })
8251
- );
8252
- }
8253
-
8254
- // eslint-disable-next-line react/prop-types
8255
- function SeparatorOption() {
8256
- return /*#__PURE__*/jsxRuntime.jsx("li", {
8257
- className: s('np-separator'),
8258
- "aria-hidden": true
8259
- });
8260
- }
8261
-
8262
- // eslint-disable-next-line react/prop-types
8263
- function HeaderOption({
8264
- children
8265
- }) {
8266
- return /*#__PURE__*/jsxRuntime.jsx("li", {
8267
- // eslint-disable-line jsx-a11y/no-noninteractive-element-interactions
8268
- className: classNames__default.default(s('np-dropdown-header'), s('np-text-title-group')),
8269
- onClick: stopPropagation$1,
8270
- onKeyPress: stopPropagation$1,
8271
- children: children
8147
+ })]
8272
8148
  });
8273
8149
  }
8274
- function isOptionSelected(selected, option) {
8275
- return selected?.value === option?.value;
8150
+ }
8151
+ function filterOptionsForQuery(options, query) {
8152
+ if (!query) {
8153
+ return options;
8276
8154
  }
8277
- const renderOption = (option, index) => {
8278
- const separatorOption = option;
8279
- if (isSeparatorOption(separatorOption) && separatorOption?.separator) {
8280
- return /*#__PURE__*/jsxRuntime.jsx(SeparatorOption, {}, index);
8281
- }
8282
- const headerOption = option;
8283
- if (isHeaderOption(headerOption) && headerOption.header) {
8284
- return /*#__PURE__*/jsxRuntime.jsx(HeaderOption, {
8285
- children: headerOption.header
8286
- }, index);
8155
+ const filteredOptions = removeDuplicateValueOptions(options).filter(option => isCurrencyOptionAndFitsQuery(option, query));
8156
+ return sortOptionsLabelsToFirst(filteredOptions, query);
8157
+ }
8158
+ function removeDuplicateValueOptions(options) {
8159
+ const result = [];
8160
+ const resultValues = [];
8161
+ options.forEach(option => {
8162
+ if (option.value && !resultValues.includes(option.value)) {
8163
+ result.push(option);
8164
+ resultValues.push(option.value);
8287
8165
  }
8288
- const isActive = isOptionSelected(selected, option);
8289
- const selectOption = option;
8290
- const isFocusedWithKeyboard = !selectOption.disabled && keyboardFocusedOptionIndex === getIndexWithoutHeadersForIndexWithHeaders(index);
8291
- const className = classNames__default.default(s('np-dropdown-item'), selectOption.disabled ? [s('disabled')] : s('clickable'), {
8292
- [s('active')]: isActive,
8293
- [s('np-dropdown-item--focused')]: isFocusedWithKeyboard
8294
- });
8295
- const handleOnClick = selectOption.disabled ? stopPropagation$1 : createSelectHandlerForOption(selectOption);
8296
- return (
8297
- /*#__PURE__*/
8298
- /* eslint-disable-next-line jsx-a11y/no-noninteractive-element-interactions */
8299
- jsxRuntime.jsx("li", {
8300
- ref: isFocusedWithKeyboard ? keyboardFocusedReference : undefined,
8301
- id: getUniqueIdForOption(id, option),
8302
- "aria-selected": isActive,
8303
- "aria-disabled": option.disabled,
8304
- role: "option",
8305
- tabIndex: "-1",
8306
- className: className,
8307
- onClick: handleOnClick,
8308
- onKeyPress: handleOnClick,
8309
- children: /*#__PURE__*/jsxRuntime.jsx("a", {
8310
- disabled: selectOption.disabled,
8311
- children: /*#__PURE__*/jsxRuntime.jsx(Option$1, {
8312
- ...selectOption,
8313
- classNames: classNamesProp
8314
- })
8315
- })
8316
- }, index)
8317
- );
8318
- };
8319
- function getIndexWithoutHeadersForIndexWithHeaders(index) {
8320
- return options.reduce((sum, option, currentIndex) => {
8321
- if (currentIndex < index && isActionableOption(option)) {
8322
- return sum + 1;
8323
- }
8324
- return sum;
8325
- }, 0);
8166
+ });
8167
+ return result;
8168
+ }
8169
+ function isCurrencyOptionAndFitsQuery(option, query) {
8170
+ if (!option.value) {
8171
+ return false;
8326
8172
  }
8327
- const hasActiveOptions = !!defaultOptions.length;
8328
- if (open && (initSearchValue || searchValue)) {
8329
- if (hasActiveOptions && keyboardFocusedOptionIndex == null) {
8330
- setKeyboardFocusedOptionIndex(0);
8173
+ return contains(option.label, query) || contains(option.searchable, query) || contains(option.note, query);
8174
+ }
8175
+ function contains(property, query) {
8176
+ return property && property.toLowerCase().includes(query.toLowerCase());
8177
+ }
8178
+ function sortOptionsLabelsToFirst(options, query) {
8179
+ return options.sort((first, second) => {
8180
+ const firstContains = contains(first.label, query);
8181
+ const secondContains = contains(second.label, query);
8182
+ if (firstContains && secondContains) {
8183
+ return 0;
8331
8184
  }
8332
- if (!hasActiveOptions && keyboardFocusedOptionIndex != null) {
8333
- setKeyboardFocusedOptionIndex(null);
8185
+ if (firstContains) {
8186
+ return -1;
8334
8187
  }
8335
- }
8336
- return /*#__PURE__*/jsxRuntime.jsxs("div", {
8337
- // eslint-disable-line jsx-a11y/no-static-element-interactions
8338
- ref: selectReference,
8339
- className: classNames__default.default(s('np-select'), block ? s('btn-block') : null, s('btn-group')),
8340
- onKeyDown: handleKeyDown,
8341
- onTouchMove: handleTouchStart,
8342
- onFocus: handleOnFocus,
8343
- onBlur: handleOnBlur,
8344
- children: [/*#__PURE__*/jsxRuntime.jsxs(Button, {
8345
- ref: dropdownButtonReference,
8346
- id: computedId,
8347
- block: block,
8348
- size: size,
8349
- htmlType: "button",
8350
- className: classNames__default.default(s('np-dropdown-toggle'), s('np-text-body-large'), inverse ? s('np-dropdown-toggle-navy') : null)
8351
- // reset Button's styles
8352
- ,
8353
- type: null,
8354
- priority: null,
8355
- disabled: disabled,
8356
- "aria-controls": listboxId,
8357
- "aria-expanded": open,
8358
- "aria-autocomplete": "none",
8359
- onClick: handleOnClick,
8360
- ...buttonProps,
8361
- children: [selected ? /*#__PURE__*/jsxRuntime.jsx(Option$1, {
8362
- ...selected,
8363
- classNames: classNamesProp,
8364
- selected: true
8365
- }) : /*#__PURE__*/jsxRuntime.jsx("span", {
8366
- className: s('form-control-placeholder'),
8367
- children: placeholder
8368
- }), /*#__PURE__*/jsxRuntime.jsx(Chevron$1
8369
- // disabled={disabled}
8370
- , {
8371
- className: classNames__default.default(s('tw-icon'), s('tw-chevron-up-icon'), s('tw-chevron'), s('bottom'), s('np-select-chevron'))
8372
- })]
8373
- }), isMobile ? isSearchEnabled ? /*#__PURE__*/jsxRuntime.jsx(Drawer$1, {
8374
- open: open,
8375
- headerTitle: searchPlaceholder || formatMessage(messages$3.searchPlaceholder),
8376
- onClose: handleCloseOptions,
8377
- children: renderOptionsList()
8378
- }) : /*#__PURE__*/jsxRuntime.jsx(BottomSheet$2, {
8379
- open: open,
8380
- onClose: handleCloseOptions,
8381
- children: renderOptionsList({
8382
- className: isModern ? '' : 'p-a-1'
8383
- })
8384
- }) : /*#__PURE__*/jsxRuntime.jsx(Panel$1, {
8385
- open: open,
8386
- flip: false,
8387
- altAxis: true,
8388
- anchorRef: selectReference,
8389
- anchorWidth: isDropdownAutoWidth,
8390
- position: dropdownUp ? exports.Position.TOP : exports.Position.BOTTOM,
8391
- onClose: handleCloseOptions,
8392
- children: renderOptionsList({
8393
- className: 'p-a-1'
8394
- })
8395
- })]
8188
+ if (secondContains) {
8189
+ return 1;
8190
+ }
8191
+ return 0;
8396
8192
  });
8397
8193
  }
8398
- Select.propTypes = {
8399
- placeholder: PropTypes__default.default.string,
8194
+ MoneyInput.propTypes = {
8400
8195
  id: PropTypes__default.default.string,
8401
- required: PropTypes__default.default.bool,
8402
- disabled: PropTypes__default.default.bool,
8403
- inverse: PropTypes__default.default.bool,
8404
- dropdownRight: PropTypes__default.default.oneOf(['xs', 'sm', 'md', 'lg', 'xl']),
8405
- dropdownWidth: PropTypes__default.default.oneOf(['sm', 'md', 'lg']),
8196
+ currencies: PropTypes__default.default.arrayOf(Currency).isRequired,
8197
+ selectedCurrency: Currency.isRequired,
8198
+ onCurrencyChange: PropTypes__default.default.func,
8199
+ placeholder: PropTypes__default.default.number,
8200
+ amount: PropTypes__default.default.number,
8406
8201
  size: PropTypes__default.default.oneOf(['sm', 'md', 'lg']),
8407
- block: PropTypes__default.default.bool,
8408
- selected: PropTypes__default.default.shape({
8409
- value: PropTypes__default.default.any.isRequired,
8410
- label: PropTypes__default.default.node,
8411
- icon: PropTypes__default.default.node,
8412
- currency: PropTypes__default.default.string,
8413
- note: PropTypes__default.default.node,
8414
- secondary: PropTypes__default.default.node
8415
- }),
8416
- /**
8417
- * Search toggle
8418
- * if `true` default search functionality being enabled (not case sensitive search in option labels & currency props)
8419
- * if `function` you can define your own search function to implement custom search experience. This search function used while filtering the options array. The custom search function takes two parameters. First is the option the second is the keyword.
8420
- */
8421
- search: PropTypes__default.default.oneOfType([PropTypes__default.default.bool, PropTypes__default.default.func]),
8422
- onChange: PropTypes__default.default.func.isRequired,
8423
- onFocus: PropTypes__default.default.func,
8424
- onBlur: PropTypes__default.default.func,
8425
- options: PropTypes__default.default.arrayOf(PropTypes__default.default.shape({
8426
- value: PropTypes__default.default.any,
8427
- label: PropTypes__default.default.node,
8428
- header: PropTypes__default.default.node,
8429
- icon: PropTypes__default.default.node,
8430
- currency: PropTypes__default.default.string,
8431
- note: PropTypes__default.default.node,
8432
- secondary: PropTypes__default.default.node,
8433
- separator: PropTypes__default.default.bool,
8434
- disabled: PropTypes__default.default.bool,
8435
- searchStrings: PropTypes__default.default.arrayOf(PropTypes__default.default.string)
8436
- })).isRequired,
8202
+ onAmountChange: PropTypes__default.default.func,
8203
+ addon: PropTypes__default.default.node,
8204
+ searchPlaceholder: PropTypes__default.default.string,
8437
8205
  /**
8438
- * To have full control of your search value and response use `onSearchChange` function combined with `searchValue` and custom filtering on the options array.
8439
- * DO NOT USE TOGETHER WITH `search` PROPERTY
8206
+ * Allows the consumer to react to searching, while the search itself is handled internally. Called with `{ searchQuery: string, filteredOptions: Currency[] }`
8440
8207
  */
8441
8208
  onSearchChange: PropTypes__default.default.func,
8442
- searchValue: PropTypes__default.default.string,
8443
- searchPlaceholder: PropTypes__default.default.string,
8209
+ customActionLabel: PropTypes__default.default.node,
8210
+ onCustomAction: PropTypes__default.default.func,
8444
8211
  classNames: PropTypes__default.default.objectOf(PropTypes__default.default.string),
8445
- dropdownUp: PropTypes__default.default.bool,
8446
- buttonProps: PropTypes__default.default.object,
8447
- dropdownProps: PropTypes__default.default.object
8212
+ selectProps: PropTypes__default.default.object,
8213
+ maxLengthOverride: PropTypes__default.default.number
8448
8214
  };
8449
- Select.defaultProps = {
8450
- id: undefined,
8451
- placeholder: undefined,
8452
- size: 'md',
8453
- dropdownRight: null,
8454
- dropdownWidth: null,
8455
- inverse: false,
8456
- required: false,
8457
- disabled: false,
8458
- block: true,
8459
- selected: null,
8460
- onFocus: null,
8461
- onBlur: null,
8215
+ MoneyInput.defaultProps = {
8216
+ id: null,
8217
+ size: exports.Size.LARGE,
8218
+ addon: null,
8219
+ searchPlaceholder: '',
8462
8220
  onSearchChange: undefined,
8463
- search: false,
8464
- searchValue: '',
8465
- searchPlaceholder: undefined,
8221
+ onCurrencyChange: null,
8222
+ placeholder: null,
8223
+ amount: null,
8224
+ onAmountChange: null,
8225
+ customActionLabel: '',
8226
+ onCustomAction: null,
8466
8227
  classNames: {},
8467
- dropdownUp: false,
8468
- buttonProps: {},
8469
- dropdownProps: {}
8228
+ selectProps: {},
8229
+ maxLengthOverride: null
8470
8230
  };
8231
+ var MoneyInput$1 = reactIntl.injectIntl(MoneyInput);
8471
8232
 
8472
- var messages$2 = reactIntl.defineMessages({
8473
- selectPlaceholder: {
8474
- id: "neptune.MoneyInput.Select.placeholder"
8475
- }
8476
- });
8477
-
8478
- // TODO: do not duplicate this between formatting and components
8479
- const currencyDecimals = {
8480
- BIF: 0,
8481
- BYR: 0,
8482
- CLP: 0,
8483
- DJF: 0,
8484
- GNF: 0,
8485
- JPY: 0,
8486
- KMF: 0,
8487
- KRW: 0,
8488
- MGA: 0,
8489
- PYG: 0,
8490
- RWF: 0,
8491
- VND: 0,
8492
- VUV: 0,
8493
- XAF: 0,
8494
- XOF: 0,
8495
- XPF: 0,
8496
- // technically HUF does have decimals, but due to the exchange rate banks
8497
- // do not accept decimal amounts
8498
- HUF: 0,
8499
- BHD: 3,
8500
- JOD: 3,
8501
- KWD: 3,
8502
- OMR: 3,
8503
- TND: 3
8233
+ const NavigationOptionList = ({
8234
+ children
8235
+ }) => {
8236
+ return /*#__PURE__*/jsxRuntime.jsx("ul", {
8237
+ className: "np-navigation-options-list",
8238
+ children: React.Children.map(children, child => /*#__PURE__*/jsxRuntime.jsx("li", {
8239
+ className: "np-navigation-options-list__item",
8240
+ children: child
8241
+ }, child.key))
8242
+ });
8504
8243
  };
8505
- const DEFAULT_CURRENCY_DECIMALS = 2;
8506
- function isNumberLocaleSupported() {
8507
- const number = 1234;
8508
- const numberString = number.toLocaleString && number.toLocaleString(DEFAULT_LOCALE);
8509
- return numberString === '1,234';
8510
- }
8511
- function getValidLocale(locale) {
8512
- try {
8513
- const noUnderscoreLocale = locale.replace(/_/, '-');
8514
- Intl.NumberFormat(noUnderscoreLocale);
8515
- return noUnderscoreLocale;
8516
- } catch {
8517
- return 'en-GB';
8518
- }
8519
- }
8520
- function getCurrencyDecimals(currency = '') {
8521
- const upperCaseCurrency = currency.toUpperCase();
8522
- if (Object.prototype.hasOwnProperty.call(currencyDecimals, upperCaseCurrency)) {
8523
- return currencyDecimals[upperCaseCurrency];
8524
- }
8525
- return DEFAULT_CURRENCY_DECIMALS;
8526
- }
8527
- function getDecimalSeparator(locale) {
8528
- return isNumberLocaleSupported() ? 1.1.toLocaleString(locale)[1] : '.';
8529
- }
8530
- function parseAmount(number, currency, locale) {
8531
- const validLocale = getValidLocale(locale);
8532
- const precision = getCurrencyDecimals(currency);
8533
- const groupSeparator = isNumberLocaleSupported() ? 10000 .toLocaleString(validLocale)[2] : ',';
8534
- const decimalSeparator = getDecimalSeparator(validLocale);
8535
- const numberWithStandardDecimalSeparator = (number ? `${number}` : '').replace(new RegExp(`\\${groupSeparator}`, 'g'), '').replace(new RegExp(`\\${decimalSeparator}`, 'g'), '.').replace(/[^0-9.]/g, '');
8536
- const parsedAmount = parseFloat(parseFloat(numberWithStandardDecimalSeparator).toFixed(precision));
8537
- return Math.abs(parsedAmount);
8538
- }
8539
-
8540
- const Currency = PropTypes__default.default.shape({
8541
- header: PropTypes__default.default.string,
8542
- value: PropTypes__default.default.string,
8543
- label: PropTypes__default.default.string,
8544
- currency: PropTypes__default.default.string,
8545
- note: PropTypes__default.default.string,
8546
- searchable: PropTypes__default.default.string
8547
- });
8548
- const CUSTOM_ACTION = 'CUSTOM_ACTION';
8549
- const isNumberOrNull = v => neptuneValidation.isNumber(v) || neptuneValidation.isNull(v);
8550
- const formatAmountIfSet = (amount, currency, locale, maxLengthOverride) => {
8551
- if (maxLengthOverride) {
8552
- return amount || '';
8553
- } else {
8554
- return typeof amount === 'number' ? formatting.formatAmount(amount, currency, locale) : '';
8555
- }
8244
+ NavigationOptionList.propTypes = {
8245
+ children: PropTypes__default.default.node.isRequired
8556
8246
  };
8557
- const parseNumber = (amount, currency, locale, maxLengthOverride) => {
8558
- if (!maxLengthOverride) {
8559
- return parseAmount(amount, currency, locale);
8560
- }
8561
- if (maxLengthOverride && amount.length > maxLengthOverride) {
8562
- return 0;
8563
- }
8564
- return +amount;
8247
+ var NavigationOptionList$1 = NavigationOptionList;
8248
+
8249
+ const STORAGE_NAME = 'dismissedNudges';
8250
+ const getLocalStorage = () => {
8251
+ try {
8252
+ const storageItem = localStorage.getItem(STORAGE_NAME);
8253
+ if (storageItem) {
8254
+ const storage = JSON.parse(storageItem);
8255
+ if (Array.isArray(storage)) {
8256
+ return storage;
8257
+ }
8258
+ }
8259
+ // eslint-disable-next-line unicorn/prefer-optional-catch-binding, no-empty
8260
+ } catch (error) {}
8261
+ return [];
8565
8262
  };
8566
- const inputKeyCodeAllowlist = new Set([KeyCodes.BACKSPACE, KeyCodes.DELETE, KeyCodes.COMMA, KeyCodes.PERIOD, KeyCodes.DOWN, KeyCodes.UP, KeyCodes.LEFT, KeyCodes.RIGHT, KeyCodes.ENTER, KeyCodes.ESCAPE, KeyCodes.TAB]);
8567
- const inputKeyAllowlist = new Set([Key.PERIOD, Key.COMMA]);
8568
- class MoneyInput extends React.Component {
8569
- constructor(props) {
8570
- super(props);
8571
- const {
8572
- locale
8573
- } = this.props.intl;
8574
- this.formatMessage = this.props.intl.formatMessage;
8575
- this.state = {
8576
- searchQuery: '',
8577
- formattedAmount: formatAmountIfSet(props.amount, props.selectedCurrency.currency, locale, props.maxLengthOverride),
8578
- locale
8579
- };
8580
- }
8581
- UNSAFE_componentWillReceiveProps(nextProps) {
8582
- this.setState({
8583
- locale: nextProps?.intl?.locale
8584
- });
8585
- if (!this.amountFocused) {
8586
- this.setState({
8587
- formattedAmount: formatAmountIfSet(nextProps.amount, nextProps.selectedCurrency.currency, nextProps?.intl?.locale, nextProps.maxLengthOverride)
8588
- });
8589
- }
8590
- }
8591
- isInputAllowedForKeyEvent = event => {
8592
- const {
8593
- keyCode,
8594
- metaKey,
8595
- key,
8596
- ctrlKey
8597
- } = event;
8598
- const isNumberKey = neptuneValidation.isNumber(parseInt(key, 10));
8599
- return isNumberKey || metaKey || ctrlKey || inputKeyCodeAllowlist.has(keyCode) || inputKeyAllowlist.has(key);
8600
- };
8601
- handleKeyDown = event => {
8602
- if (!this.isInputAllowedForKeyEvent(event)) {
8603
- event.preventDefault();
8604
- }
8605
- };
8606
- handlePaste = event => {
8607
- const paste = (event.clipboardData || window.clipboardData).getData('text');
8608
- const {
8609
- locale
8610
- } = this.state;
8611
- const parsed = neptuneValidation.isEmpty(paste) ? null : parseNumber(paste, this.props.selectedCurrency.currency, locale, this.props.maxLengthOverride);
8612
- if (isNumberOrNull(parsed)) {
8613
- this.setState({
8614
- formattedAmount: formatAmountIfSet(parsed, this.props.selectedCurrency.currency, locale, this.props.maxLengthOverride)
8615
- });
8616
- this.props.onAmountChange(parsed);
8263
+ const Nudge = ({
8264
+ media,
8265
+ mediaName,
8266
+ title,
8267
+ link,
8268
+ href,
8269
+ onClick,
8270
+ onDismiss,
8271
+ persistDismissal,
8272
+ isPreviouslyDismissed,
8273
+ id,
8274
+ className
8275
+ }) => {
8276
+ const [isDismissed, setIsDismissed] = React.useState(false);
8277
+ const [isMounted, setIsMounted] = React.useState(false);
8278
+ const handleOnDismiss = () => {
8279
+ const dismissedNudgesStorage = getLocalStorage();
8280
+ if (persistDismissal && id) {
8281
+ try {
8282
+ localStorage.setItem(STORAGE_NAME, JSON.stringify([...(dismissedNudgesStorage ? dismissedNudgesStorage : []), id]));
8283
+ // eslint-disable-next-line unicorn/prefer-optional-catch-binding, no-empty
8284
+ } catch (error) {}
8285
+ setIsDismissed(true);
8617
8286
  }
8618
- event.preventDefault();
8619
- };
8620
- onAmountChange = event => {
8621
- const {
8622
- value
8623
- } = event.target;
8624
- this.setState({
8625
- formattedAmount: value
8626
- });
8627
- const parsed = neptuneValidation.isEmpty(value) ? null : parseNumber(value, this.props.selectedCurrency.currency, this.state.locale, this.props.maxLengthOverride);
8628
- if (isNumberOrNull(parsed)) {
8629
- this.props.onAmountChange(parsed);
8287
+ if (onDismiss) {
8288
+ onDismiss();
8630
8289
  }
8631
8290
  };
8632
- onAmountBlur = () => {
8633
- this.amountFocused = false;
8634
- this.setAmount();
8635
- };
8636
- onAmountFocus = () => {
8637
- this.amountFocused = true;
8638
- };
8639
- getSelectOptions() {
8640
- const selectOptions = [...filterOptionsForQuery(this.props.currencies, this.state.searchQuery)];
8641
- if (this.props.onCustomAction) {
8642
- selectOptions.push({
8643
- value: CUSTOM_ACTION,
8644
- label: this.props.customActionLabel
8645
- });
8646
- }
8647
- return selectOptions;
8648
- }
8649
- setAmount() {
8650
- this.setState(previousState => {
8651
- const parsed = parseNumber(previousState.formattedAmount, this.props.selectedCurrency.currency, previousState.locale, this.props.maxLengthOverride);
8652
- if (!isNumberOrNull(parsed)) {
8653
- return {
8654
- formattedAmount: previousState.formattedAmount
8655
- };
8291
+ React.useEffect(() => {
8292
+ if (persistDismissal && id) {
8293
+ const dismissedNudgesStorage = getLocalStorage();
8294
+ let isDismissed = false;
8295
+ if (dismissedNudgesStorage && dismissedNudgesStorage.find(item => item === id)) {
8296
+ setIsDismissed(true);
8297
+ isDismissed = true;
8298
+ }
8299
+ if (isPreviouslyDismissed) {
8300
+ isPreviouslyDismissed(isDismissed);
8656
8301
  }
8657
- return {
8658
- formattedAmount: formatAmountIfSet(parsed, this.props.selectedCurrency.currency, previousState.locale, this.props.maxLengthOverride)
8659
- };
8660
- });
8661
- }
8662
- handleSelectChange = value => {
8663
- this.handleSearchChange('');
8664
- if (this.props.onCustomAction && value.value === CUSTOM_ACTION) {
8665
- this.props.onCustomAction();
8666
- } else {
8667
- this.props.onCurrencyChange(value);
8668
- }
8669
- };
8670
- handleSearchChange = searchQuery => {
8671
- this.setState({
8672
- searchQuery
8673
- });
8674
- if (this.props.onSearchChange) {
8675
- this.props.onSearchChange({
8676
- searchQuery,
8677
- filteredOptions: filterOptionsForQuery(this.props.currencies, searchQuery)
8678
- });
8679
8302
  }
8680
- };
8681
- style = className => this.props.classNames[className] || className;
8682
- render() {
8683
- const {
8684
- selectedCurrency,
8685
- onCurrencyChange,
8686
- size,
8687
- addon,
8688
- id,
8689
- selectProps,
8690
- maxLengthOverride
8691
- } = this.props;
8692
- const selectOptions = this.getSelectOptions();
8693
- const isFixedCurrency = !this.state.searchQuery && (selectOptions.length === 1 && selectOptions[0].currency === selectedCurrency.currency || !onCurrencyChange);
8694
- const disabled = !this.props.onAmountChange;
8695
- return /*#__PURE__*/jsxRuntime.jsxs("div", {
8696
- className: classNames__default.default(this.style('tw-money-input'), this.style('input-group'), this.style(`input-group-${size}`)),
8697
- children: [/*#__PURE__*/jsxRuntime.jsx(Input, {
8698
- id: id,
8699
- value: this.state.formattedAmount,
8700
- inputMode: "decimal",
8701
- disabled: disabled,
8702
- maxLength: maxLengthOverride,
8703
- placeholder: formatAmountIfSet(this.props.placeholder, this.props.selectedCurrency.currency, this.state.locale, this.props.maxLengthOverride),
8704
- autoComplete: "off",
8705
- onKeyDown: this.handleKeyDown,
8706
- onChange: this.onAmountChange,
8707
- onFocus: this.onAmountFocus,
8708
- onBlur: this.onAmountBlur,
8709
- onPaste: this.handlePaste
8710
- }), addon && /*#__PURE__*/jsxRuntime.jsx("span", {
8711
- className: classNames__default.default(this.style('input-group-addon'), this.style(`input-${size}`), disabled ? this.style('disabled') : ''),
8712
- children: addon
8713
- }), isFixedCurrency ? /*#__PURE__*/jsxRuntime.jsxs("div", {
8714
- className: classNames__default.default(this.style('input-group-addon'), this.style(`input-${size}`), this.style('tw-money-input__fixed-currency'), disabled ? this.style('disabled') : ''),
8715
- children: [(size === 'lg' || size === 'md') && /*#__PURE__*/jsxRuntime.jsxs(jsxRuntime.Fragment, {
8716
- children: [/*#__PURE__*/jsxRuntime.jsx("i", {
8717
- className: classNames__default.default(this.style('tw-money-input__keyline'))
8718
- }), /*#__PURE__*/jsxRuntime.jsx("i", {
8719
- className: classNames__default.default(this.style('currency-flag'), this.style(`currency-flag-${selectedCurrency.currency.toLowerCase()}`), this.style('m-r-2'))
8720
- })]
8721
- }), /*#__PURE__*/jsxRuntime.jsx(Title, {
8722
- as: "span",
8723
- type: exports.Typography.TITLE_SUBSECTION,
8724
- className: size === 'lg' ? this.style('m-r-1') : '',
8725
- children: selectedCurrency.currency.toUpperCase()
8726
- })]
8727
- }) : /*#__PURE__*/jsxRuntime.jsx("div", {
8728
- className: classNames__default.default(this.style('input-group-btn'), this.style('amount-currency-select-btn')),
8729
- children: /*#__PURE__*/jsxRuntime.jsx(Select, {
8730
- id: id ? `${id}-select` : undefined,
8731
- classNames: this.props.classNames,
8732
- options: selectOptions,
8733
- selected: {
8734
- ...selectedCurrency,
8735
- label: /*#__PURE__*/jsxRuntime.jsx(Title, {
8736
- as: "span",
8737
- type: exports.Typography.TITLE_SUBSECTION,
8738
- className: "tw-money-input__text",
8739
- children: selectedCurrency.label
8740
- }),
8741
- note: null
8742
- },
8743
- placeholder: this.formatMessage(messages$2.selectPlaceholder),
8744
- searchPlaceholder: this.props.searchPlaceholder,
8745
- searchValue: this.state.searchQuery,
8746
- size: size,
8747
- required: true,
8748
- dropdownWidth: exports.Size.LARGE,
8749
- inverse: true,
8750
- onChange: this.handleSelectChange,
8751
- onSearchChange: this.handleSearchChange,
8752
- ...selectProps
8753
- })
8754
- })]
8755
- });
8756
- }
8757
- }
8758
- function filterOptionsForQuery(options, query) {
8759
- if (!query) {
8760
- return options;
8303
+ setIsMounted(true);
8304
+ // eslint-disable-next-line react-hooks/exhaustive-deps
8305
+ }, [id, persistDismissal]);
8306
+ if (persistDismissal && (isDismissed || !isMounted)) {
8307
+ return null;
8761
8308
  }
8762
- const filteredOptions = removeDuplicateValueOptions(options).filter(option => isCurrencyOptionAndFitsQuery(option, query));
8763
- return sortOptionsLabelsToFirst(filteredOptions, query);
8764
- }
8765
- function removeDuplicateValueOptions(options) {
8766
- const result = [];
8767
- const resultValues = [];
8768
- options.forEach(option => {
8769
- if (option.value && !resultValues.includes(option.value)) {
8770
- result.push(option);
8771
- resultValues.push(option.value);
8772
- }
8773
- });
8774
- return result;
8775
- }
8776
- function isCurrencyOptionAndFitsQuery(option, query) {
8777
- if (!option.value) {
8778
- return false;
8779
- }
8780
- return contains(option.label, query) || contains(option.searchable, query) || contains(option.note, query);
8781
- }
8782
- function contains(property, query) {
8783
- return property && property.toLowerCase().includes(query.toLowerCase());
8784
- }
8785
- function sortOptionsLabelsToFirst(options, query) {
8786
- return options.sort((first, second) => {
8787
- const firstContains = contains(first.label, query);
8788
- const secondContains = contains(second.label, query);
8789
- if (firstContains && secondContains) {
8790
- return 0;
8791
- }
8792
- if (firstContains) {
8793
- return -1;
8794
- }
8795
- if (secondContains) {
8796
- return 1;
8797
- }
8798
- return 0;
8799
- });
8800
- }
8801
- MoneyInput.propTypes = {
8802
- id: PropTypes__default.default.string,
8803
- currencies: PropTypes__default.default.arrayOf(Currency).isRequired,
8804
- selectedCurrency: Currency.isRequired,
8805
- onCurrencyChange: PropTypes__default.default.func,
8806
- placeholder: PropTypes__default.default.number,
8807
- amount: PropTypes__default.default.number,
8808
- size: PropTypes__default.default.oneOf(['sm', 'md', 'lg']),
8809
- onAmountChange: PropTypes__default.default.func,
8810
- addon: PropTypes__default.default.node,
8811
- searchPlaceholder: PropTypes__default.default.string,
8812
- /**
8813
- * Allows the consumer to react to searching, while the search itself is handled internally. Called with `{ searchQuery: string, filteredOptions: Currency[] }`
8814
- */
8815
- onSearchChange: PropTypes__default.default.func,
8816
- customActionLabel: PropTypes__default.default.node,
8817
- onCustomAction: PropTypes__default.default.func,
8818
- classNames: PropTypes__default.default.objectOf(PropTypes__default.default.string),
8819
- selectProps: PropTypes__default.default.object,
8820
- maxLengthOverride: PropTypes__default.default.number
8821
- };
8822
- MoneyInput.defaultProps = {
8823
- id: null,
8824
- size: exports.Size.LARGE,
8825
- addon: null,
8826
- searchPlaceholder: '',
8827
- onSearchChange: undefined,
8828
- onCurrencyChange: null,
8829
- placeholder: null,
8830
- amount: null,
8831
- onAmountChange: null,
8832
- customActionLabel: '',
8833
- onCustomAction: null,
8834
- classNames: {},
8835
- selectProps: {},
8836
- maxLengthOverride: null
8837
- };
8838
- var MoneyInput$1 = reactIntl.injectIntl(MoneyInput);
8839
-
8840
- const NavigationOptionList = ({
8841
- children
8842
- }) => {
8843
- return /*#__PURE__*/jsxRuntime.jsx("ul", {
8844
- className: "np-navigation-options-list",
8845
- children: React.Children.map(children, child => /*#__PURE__*/jsxRuntime.jsx("li", {
8846
- className: "np-navigation-options-list__item",
8847
- children: child
8848
- }, child.key))
8849
- });
8850
- };
8851
- NavigationOptionList.propTypes = {
8852
- children: PropTypes__default.default.node.isRequired
8853
- };
8854
- var NavigationOptionList$1 = NavigationOptionList;
8855
-
8856
- const STORAGE_NAME = 'dismissedNudges';
8857
- const getLocalStorage = () => {
8858
- try {
8859
- const storageItem = localStorage.getItem(STORAGE_NAME);
8860
- if (storageItem) {
8861
- const storage = JSON.parse(storageItem);
8862
- if (Array.isArray(storage)) {
8863
- return storage;
8864
- }
8865
- }
8866
- // eslint-disable-next-line unicorn/prefer-optional-catch-binding, no-empty
8867
- } catch (error) {}
8868
- return [];
8869
- };
8870
- const Nudge = ({
8871
- media,
8872
- mediaName,
8873
- title,
8874
- link,
8875
- href,
8876
- onClick,
8877
- onDismiss,
8878
- persistDismissal,
8879
- isPreviouslyDismissed,
8880
- id,
8881
- className
8882
- }) => {
8883
- const [isDismissed, setIsDismissed] = React.useState(false);
8884
- const [isMounted, setIsMounted] = React.useState(false);
8885
- const handleOnDismiss = () => {
8886
- const dismissedNudgesStorage = getLocalStorage();
8887
- if (persistDismissal && id) {
8888
- try {
8889
- localStorage.setItem(STORAGE_NAME, JSON.stringify([...(dismissedNudgesStorage ? dismissedNudgesStorage : []), id]));
8890
- // eslint-disable-next-line unicorn/prefer-optional-catch-binding, no-empty
8891
- } catch (error) {}
8892
- setIsDismissed(true);
8893
- }
8894
- if (onDismiss) {
8895
- onDismiss();
8896
- }
8897
- };
8898
- React.useEffect(() => {
8899
- if (persistDismissal && id) {
8900
- const dismissedNudgesStorage = getLocalStorage();
8901
- let isDismissed = false;
8902
- if (dismissedNudgesStorage && dismissedNudgesStorage.find(item => item === id)) {
8903
- setIsDismissed(true);
8904
- isDismissed = true;
8905
- }
8906
- if (isPreviouslyDismissed) {
8907
- isPreviouslyDismissed(isDismissed);
8908
- }
8909
- }
8910
- setIsMounted(true);
8911
- // eslint-disable-next-line react-hooks/exhaustive-deps
8912
- }, [id, persistDismissal]);
8913
- if (persistDismissal && (isDismissed || !isMounted)) {
8914
- return null;
8915
- }
8916
- return /*#__PURE__*/jsxRuntime.jsxs("div", {
8917
- className: classNames__default.default('wds-nudge', className),
8918
- id: id,
8919
- children: [!!mediaName && /*#__PURE__*/jsxRuntime.jsx("div", {
8920
- className: "wds-nudge-media",
8921
- children: /*#__PURE__*/jsxRuntime.jsx(art.Illustration, {
8922
- name: mediaName,
8923
- className: classNames__default.default(`wds-nudge-media-${mediaName}`),
8924
- size: "small",
8925
- disablePadding: true,
8926
- alt: ""
8927
- })
8928
- }), /*#__PURE__*/jsxRuntime.jsxs("div", {
8929
- className: "wds-nudge-container",
8930
- children: [/*#__PURE__*/jsxRuntime.jsxs("div", {
8931
- className: "wds-nudge-content",
8932
- children: [/*#__PURE__*/jsxRuntime.jsx(Body, {
8933
- type: exports.Typography.BODY_LARGE,
8934
- className: classNames__default.default('wds-nudge-body'),
8935
- children: title
8936
- }), link && /*#__PURE__*/jsxRuntime.jsx(Link, {
8937
- href: href,
8938
- type: exports.Typography.LINK_LARGE,
8939
- className: "wds-nudge-link",
8940
- onClick: onClick,
8941
- children: link
8942
- })]
8943
- }), onDismiss || persistDismissal ? /*#__PURE__*/jsxRuntime.jsx(CloseButton, {
8944
- className: "wds-nudge-control",
8945
- size: "sm",
8946
- onClick: handleOnDismiss
8947
- }) : null]
8948
- })]
8309
+ return /*#__PURE__*/jsxRuntime.jsxs("div", {
8310
+ className: classNames__default.default('wds-nudge', className),
8311
+ id: id,
8312
+ children: [!!mediaName && /*#__PURE__*/jsxRuntime.jsx("div", {
8313
+ className: "wds-nudge-media",
8314
+ children: /*#__PURE__*/jsxRuntime.jsx(art.Illustration, {
8315
+ name: mediaName,
8316
+ className: classNames__default.default(`wds-nudge-media-${mediaName}`),
8317
+ size: "small",
8318
+ disablePadding: true,
8319
+ alt: ""
8320
+ })
8321
+ }), /*#__PURE__*/jsxRuntime.jsxs("div", {
8322
+ className: "wds-nudge-container",
8323
+ children: [/*#__PURE__*/jsxRuntime.jsxs("div", {
8324
+ className: "wds-nudge-content",
8325
+ children: [/*#__PURE__*/jsxRuntime.jsx(Body, {
8326
+ type: exports.Typography.BODY_LARGE,
8327
+ className: classNames__default.default('wds-nudge-body'),
8328
+ children: title
8329
+ }), link && /*#__PURE__*/jsxRuntime.jsx(Link, {
8330
+ href: href,
8331
+ type: exports.Typography.LINK_LARGE,
8332
+ className: "wds-nudge-link",
8333
+ onClick: onClick,
8334
+ children: link
8335
+ })]
8336
+ }), onDismiss || persistDismissal ? /*#__PURE__*/jsxRuntime.jsx(CloseButton, {
8337
+ className: "wds-nudge-control",
8338
+ size: "sm",
8339
+ onClick: handleOnDismiss
8340
+ }) : null]
8341
+ })]
8949
8342
  });
8950
8343
  };
8951
8344
 
@@ -11058,179 +10451,836 @@ const Radio = ({
11058
10451
  })]
11059
10452
  })
11060
10453
  });
11061
- };
11062
- Radio.propTypes = {
11063
- avatar: PropTypes__default.default.element,
11064
- checked: PropTypes__default.default.bool,
11065
- disabled: PropTypes__default.default.bool,
10454
+ };
10455
+ Radio.propTypes = {
10456
+ avatar: PropTypes__default.default.element,
10457
+ checked: PropTypes__default.default.bool,
10458
+ disabled: PropTypes__default.default.bool,
10459
+ id: PropTypes__default.default.string,
10460
+ label: PropTypes__default.default.string.isRequired,
10461
+ name: PropTypes__default.default.string.isRequired,
10462
+ onChange: PropTypes__default.default.func.isRequired,
10463
+ secondary: PropTypes__default.default.string,
10464
+ value: PropTypes__default.default.oneOfType([PropTypes__default.default.number, PropTypes__default.default.string]),
10465
+ className: PropTypes__default.default.string
10466
+ };
10467
+ Radio.defaultProps = {
10468
+ avatar: undefined,
10469
+ checked: false,
10470
+ disabled: false,
10471
+ id: null,
10472
+ secondary: null,
10473
+ value: '',
10474
+ className: undefined
10475
+ };
10476
+ var Radio$1 = Radio;
10477
+
10478
+ class RadioGroup extends React.Component {
10479
+ constructor(props) {
10480
+ super(props);
10481
+ this.state = {
10482
+ selectedValue: props.selectedValue
10483
+ };
10484
+ }
10485
+ handleOnChange = selectedValue => {
10486
+ const {
10487
+ onChange
10488
+ } = this.props;
10489
+ this.setState({
10490
+ selectedValue
10491
+ }, onChange && onChange(selectedValue));
10492
+ };
10493
+ render() {
10494
+ const {
10495
+ radios,
10496
+ name
10497
+ } = this.props;
10498
+ const {
10499
+ selectedValue
10500
+ } = this.state;
10501
+ return radios && radios.length > 0 ? /*#__PURE__*/jsxRuntime.jsx(jsxRuntime.Fragment, {
10502
+ children: radios.map(({
10503
+ id,
10504
+ avatar,
10505
+ value,
10506
+ label,
10507
+ disabled,
10508
+ secondary,
10509
+ readOnly
10510
+ }, index) => /*#__PURE__*/jsxRuntime.jsx(Radio$1
10511
+ // eslint-disable-next-line react/no-array-index-key
10512
+ , {
10513
+ id: id,
10514
+ value: value,
10515
+ label: label,
10516
+ name: name,
10517
+ disabled: disabled,
10518
+ checked: selectedValue === value,
10519
+ secondary: secondary,
10520
+ readOnly: readOnly,
10521
+ avatar: avatar,
10522
+ onChange: value_ => this.handleOnChange(value_)
10523
+ }, index))
10524
+ }) : null;
10525
+ }
10526
+ }
10527
+ RadioGroup.propTypes = {
10528
+ radios: PropTypes__default.default.arrayOf(PropTypes__default.default.shape({
10529
+ id: PropTypes__default.default.string,
10530
+ avatar: PropTypes__default.default.element,
10531
+ value: PropTypes__default.default.oneOfType([PropTypes__default.default.number, PropTypes__default.default.string]),
10532
+ secondary: PropTypes__default.default.string,
10533
+ label: PropTypes__default.default.string.isRequired,
10534
+ disabled: PropTypes__default.default.bool,
10535
+ readOnly: PropTypes__default.default.bool
10536
+ })).isRequired,
10537
+ onChange: PropTypes__default.default.func.isRequired,
10538
+ selectedValue: PropTypes__default.default.oneOfType([PropTypes__default.default.number, PropTypes__default.default.string]),
10539
+ name: PropTypes__default.default.string.isRequired
10540
+ };
10541
+ RadioGroup.defaultProps = {
10542
+ selectedValue: null
10543
+ };
10544
+ var RadioGroup$1 = RadioGroup;
10545
+
10546
+ const RadioOption = ({
10547
+ 'aria-label': ariaLabel,
10548
+ media,
10549
+ title,
10550
+ content,
10551
+ id,
10552
+ name,
10553
+ checked,
10554
+ onChange,
10555
+ complex,
10556
+ disabled,
10557
+ value,
10558
+ showMediaCircle,
10559
+ showMediaAtAllSizes,
10560
+ isContainerAligned
10561
+ }) => {
10562
+ const sharedProps = {
10563
+ 'aria-label': ariaLabel,
10564
+ media,
10565
+ title,
10566
+ content,
10567
+ name,
10568
+ complex,
10569
+ disabled,
10570
+ showMediaCircle,
10571
+ showMediaAtAllSizes,
10572
+ isContainerAligned
10573
+ };
10574
+ return /*#__PURE__*/jsxRuntime.jsx(Option$2, {
10575
+ ...sharedProps,
10576
+ button: /*#__PURE__*/jsxRuntime.jsx(RadioButton$1, {
10577
+ id: id,
10578
+ name: name,
10579
+ checked: checked,
10580
+ disabled: disabled,
10581
+ value: value,
10582
+ onChange: onChange
10583
+ })
10584
+ });
10585
+ };
10586
+ RadioOption.propTypes = {
10587
+ 'aria-label': PropTypes__default.default.string,
10588
+ media: PropTypes__default.default.node,
10589
+ id: PropTypes__default.default.string.isRequired,
10590
+ name: PropTypes__default.default.string.isRequired,
10591
+ title: PropTypes__default.default.node.isRequired,
10592
+ content: PropTypes__default.default.node,
10593
+ checked: PropTypes__default.default.bool,
10594
+ onChange: PropTypes__default.default.func.isRequired,
10595
+ complex: PropTypes__default.default.bool,
10596
+ disabled: PropTypes__default.default.bool,
10597
+ value: PropTypes__default.default.string,
10598
+ showMediaCircle: PropTypes__default.default.bool,
10599
+ showMediaAtAllSizes: PropTypes__default.default.bool,
10600
+ isContainerAligned: PropTypes__default.default.bool
10601
+ };
10602
+ RadioOption.defaultProps = {
10603
+ 'aria-label': undefined,
10604
+ media: null,
10605
+ content: null,
10606
+ checked: false,
10607
+ complex: false,
10608
+ disabled: false,
10609
+ showMediaCircle: true,
10610
+ showMediaAtAllSizes: false,
10611
+ isContainerAligned: false,
10612
+ value: ''
10613
+ };
10614
+ var RadioOption$1 = RadioOption;
10615
+
10616
+ const Section = ({
10617
+ children,
10618
+ className,
10619
+ withHorizontalPadding = false
10620
+ }) => {
10621
+ return /*#__PURE__*/jsxRuntime.jsx("div", {
10622
+ className: classNames__default.default('np-section', className, {
10623
+ 'np-section--with-horizontal-padding': withHorizontalPadding
10624
+ }),
10625
+ children: children
10626
+ });
10627
+ };
10628
+
10629
+ var messages$2 = reactIntl.defineMessages({
10630
+ searchPlaceholder: {
10631
+ id: "neptune.Select.searchPlaceholder"
10632
+ }
10633
+ });
10634
+
10635
+ // Option.tsx NEW
10636
+ function Option$1({
10637
+ label,
10638
+ currency = '',
10639
+ note = '',
10640
+ secondary = '',
10641
+ icon,
10642
+ classNames = {},
10643
+ selected = false
10644
+ }) {
10645
+ const {
10646
+ isModern
10647
+ } = componentsTheming.useTheme();
10648
+ const style = classes => classes.map(className => classNames[className] || className).join(' ');
10649
+ const currencyClassNames = currency ? style(['currency-flag', `currency-flag-${currency.toLowerCase()}`]) : undefined;
10650
+ const iconElement = icon ? /*#__PURE__*/React.cloneElement(icon, {
10651
+ size: 24,
10652
+ className: 'tw-icon'
10653
+ }) : currency && /*#__PURE__*/jsxRuntime.jsx("i", {
10654
+ className: currencyClassNames
10655
+ });
10656
+ const titleAndNoteElement = /*#__PURE__*/jsxRuntime.jsxs(Body, {
10657
+ as: "span",
10658
+ type: exports.Typography.BODY_LARGE,
10659
+ className: selected ? 'text-ellipsis' : undefined,
10660
+ children: [label, note && /*#__PURE__*/jsxRuntime.jsx(Body, {
10661
+ as: "span",
10662
+ className: isModern ? 'm-l-1' : 'm-l-1 body-2',
10663
+ children: note
10664
+ })]
10665
+ });
10666
+ const secondaryElementClassNames = () => {
10667
+ let classes = undefined;
10668
+ if (selected) {
10669
+ classes = 'text-ellipsis';
10670
+ }
10671
+ if (isModern) {
10672
+ return classes;
10673
+ }
10674
+ return `${classes ? classes + ' ' : ''}body-2`;
10675
+ };
10676
+ const secondaryElement = secondary && /*#__PURE__*/jsxRuntime.jsx(Body, {
10677
+ className: secondaryElementClassNames(),
10678
+ children: secondary
10679
+ });
10680
+ return iconElement ? /*#__PURE__*/jsxRuntime.jsxs("div", {
10681
+ className: "d-flex np-option-content",
10682
+ children: [/*#__PURE__*/jsxRuntime.jsx("div", {
10683
+ className: `d-flex flex-column${selected ? ' justify-content-center' : ''}`,
10684
+ children: iconElement
10685
+ }), /*#__PURE__*/jsxRuntime.jsxs("div", {
10686
+ className: "d-flex flex-column justify-content-center",
10687
+ children: [titleAndNoteElement, secondaryElement]
10688
+ })]
10689
+ }) : /*#__PURE__*/jsxRuntime.jsxs(jsxRuntime.Fragment, {
10690
+ children: [iconElement, titleAndNoteElement, secondaryElement]
10691
+ });
10692
+ }
10693
+
10694
+ const SearchBox = /*#__PURE__*/React.forwardRef(({
10695
+ id,
10696
+ classNames = {},
10697
+ focusedOptionId,
10698
+ onChange,
10699
+ onClick,
10700
+ placeholder = undefined,
10701
+ value = ''
10702
+ }, reference) => {
10703
+ const style = className => classNames[className] || className;
10704
+ return /*#__PURE__*/jsxRuntime.jsx("li", {
10705
+ className: style('border-bottom'),
10706
+ children: /*#__PURE__*/jsxRuntime.jsx("a", {
10707
+ className: `${style('np-select-filter-link')} ${style('p-a-0')}`,
10708
+ children: /*#__PURE__*/jsxRuntime.jsxs("div", {
10709
+ className: style('input-group'),
10710
+ children: [/*#__PURE__*/jsxRuntime.jsx("span", {
10711
+ className: classNames__default.default('input-group-addon', 'input-group-addon--search'),
10712
+ children: /*#__PURE__*/jsxRuntime.jsx(icons.Search, {
10713
+ className: classNames__default.default(style('tw-icon'), style('tw-icon-search')),
10714
+ size: 24
10715
+ })
10716
+ }), /*#__PURE__*/jsxRuntime.jsx(Input, {
10717
+ ref: reference,
10718
+ id: id,
10719
+ role: "searchbox",
10720
+ inputMode: "search",
10721
+ className: classNames__default.default(style('np-select-filter')),
10722
+ placeholder: placeholder,
10723
+ value: value,
10724
+ spellCheck: "false",
10725
+ "aria-activedescendant": focusedOptionId,
10726
+ onChange: onChange,
10727
+ onClick: onClick
10728
+ })]
10729
+ })
10730
+ })
10731
+ });
10732
+ });
10733
+ var SearchBox$1 = SearchBox;
10734
+
10735
+ const DEFAULT_SEARCH_VALUE = '';
10736
+ const DEFAULT_OPTIONS_PAGE_SIZE = 1000;
10737
+ const includesString = (string1, string2) => string1.toLowerCase().includes(string2.toLowerCase());
10738
+ function defaultFilterFunction(option, searchValue) {
10739
+ if (isPlaceholderOption(option)) {
10740
+ return true;
10741
+ }
10742
+ const {
10743
+ label,
10744
+ note,
10745
+ secondary,
10746
+ currency,
10747
+ searchStrings
10748
+ } = option;
10749
+ return !!label && includesString(label, searchValue) || !!note && includesString(note, searchValue) || !!secondary && includesString(secondary, searchValue) || !!currency && includesString(currency, searchValue) || !!searchStrings && searchStrings.some(string => includesString(string, searchValue));
10750
+ }
10751
+ function isActionableOption(option) {
10752
+ return !option.header && !option.separator && !option.disabled;
10753
+ }
10754
+ function isHeaderOption(option) {
10755
+ return option != null && 'header' in option;
10756
+ }
10757
+ function isSeparatorOption(option) {
10758
+ return option != null && 'separator' in option;
10759
+ }
10760
+ function clamp(from, to, value) {
10761
+ return Math.max(Math.min(to, value), from);
10762
+ }
10763
+
10764
+ /**
10765
+ * No option or placeholder option is selected
10766
+ */
10767
+ const DEFAULT_SELECTED_OPTION = null;
10768
+ function isPlaceholderOption(option) {
10769
+ return option === DEFAULT_SELECTED_OPTION || 'placeholder' in option;
10770
+ }
10771
+ function isSearchableOption(option) {
10772
+ return !isHeaderOption(option) && !isSeparatorOption(option) && !isPlaceholderOption(option);
10773
+ }
10774
+ const getUniqueIdForOption = (parentId = '', option) => {
10775
+ if (option == null) {
10776
+ return undefined;
10777
+ }
10778
+ const uniqueOptionId = option.value || (option.label?.replace(/\s/g, '') ?? '');
10779
+ return `option-${parentId}-${uniqueOptionId}`;
10780
+ };
10781
+
10782
+ /**
10783
+ * @deprecated Use `SelectInput` instead (https://neptune.wise.design/blog/2023-11-28-adopting-our-new-selectinput)
10784
+ */
10785
+ function Select({
10786
+ placeholder,
10787
+ id,
10788
+ required,
10789
+ disabled,
10790
+ inverse,
10791
+ dropdownWidth,
10792
+ size,
10793
+ block,
10794
+ selected,
10795
+ search,
10796
+ onChange,
10797
+ onFocus,
10798
+ onBlur,
10799
+ options: defaultOptions,
10800
+ onSearchChange,
10801
+ searchValue: initSearchValue,
10802
+ searchPlaceholder,
10803
+ // eslint-disable-next-line unicorn/prevent-abbreviations
10804
+ classNames: classNamesProp,
10805
+ dropdownUp,
10806
+ dropdownProps,
10807
+ buttonProps
10808
+ }) {
10809
+ const {
10810
+ formatMessage
10811
+ } = reactIntl.useIntl();
10812
+ const {
10813
+ isModern
10814
+ } = componentsTheming.useTheme();
10815
+ const s = className => classNamesProp[className] || className;
10816
+ const [open, setOpen] = React.useState(false);
10817
+ const [searchValue, setSearchValue] = React.useState(DEFAULT_SEARCH_VALUE);
10818
+ const [keyboardFocusedOptionIndex, setKeyboardFocusedOptionIndex] = React.useState(null);
10819
+ const keyboardFocusedReference = React.useRef();
10820
+ const previousKeyboardFocusedOptionIndex = React.useRef();
10821
+ const [numberOfOptionsShown, setNumberOfOptionsShown] = React.useState(DEFAULT_OPTIONS_PAGE_SIZE);
10822
+ const searchBoxReference = React.useRef(null);
10823
+ const selectReference = React.useRef(null);
10824
+ const dropdownButtonReference = React.useRef(null);
10825
+ const optionsListReference = React.useRef(null);
10826
+ const isSearchEnabled = !!onSearchChange || !!search;
10827
+ const isDropdownAutoWidth = dropdownWidth == null;
10828
+ const fallbackButtonId = React.useMemo(() => getSimpleRandomId('np-select-'), []);
10829
+ const options = React.useMemo(() => {
10830
+ if (!search || !searchValue) {
10831
+ return defaultOptions;
10832
+ }
10833
+ return defaultOptions.filter(isSearchableOption).filter(option => {
10834
+ if (typeof search === 'function') {
10835
+ return search(option, searchValue);
10836
+ } else {
10837
+ return defaultFilterFunction(option, searchValue);
10838
+ }
10839
+ });
10840
+ }, [defaultOptions, search, searchValue]);
10841
+ const selectableOptions = React.useMemo(() => options.filter(isActionableOption), [options]);
10842
+ const focusedOption = selectableOptions[keyboardFocusedOptionIndex];
10843
+ const computedId = id || fallbackButtonId;
10844
+ const listboxId = `${computedId}-listbox`;
10845
+ const searchBoxId = `${computedId}-searchbox`;
10846
+ const {
10847
+ isMobile
10848
+ } = useLayout();
10849
+ React.useEffect(() => {
10850
+ let cancelled;
10851
+ if (keyboardFocusedOptionIndex >= 0) {
10852
+ requestAnimationFrame(() => {
10853
+ if (!cancelled) {
10854
+ if (isSearchEnabled) {
10855
+ keyboardFocusedReference.current?.scrollIntoView?.({
10856
+ block: 'center'
10857
+ });
10858
+ } else {
10859
+ keyboardFocusedReference.current?.focus();
10860
+ }
10861
+ }
10862
+ });
10863
+ return () => {
10864
+ cancelled = true;
10865
+ };
10866
+ }
10867
+ }, [keyboardFocusedOptionIndex, isSearchEnabled]);
10868
+ const handleOnClick = () => {
10869
+ setOpen(true);
10870
+ };
10871
+ const handleTouchStart = event => {
10872
+ if (event.currentTarget === event.target && open) {
10873
+ handleCloseOptions();
10874
+ }
10875
+ };
10876
+ const handleOnFocus = event => {
10877
+ if (onFocus) {
10878
+ onFocus(event);
10879
+ }
10880
+ };
10881
+ const handleOnBlur = event => {
10882
+ const {
10883
+ nativeEvent
10884
+ } = event;
10885
+ if (nativeEvent) {
10886
+ const elementReceivingFocus = nativeEvent.relatedTarget;
10887
+ const select = event.currentTarget;
10888
+ if (select && elementReceivingFocus && select.contains(elementReceivingFocus)) {
10889
+ return;
10890
+ }
10891
+ }
10892
+ if (onBlur) {
10893
+ onBlur(event);
10894
+ }
10895
+ };
10896
+ const handleSearchChange = event => {
10897
+ setNumberOfOptionsShown(DEFAULT_OPTIONS_PAGE_SIZE);
10898
+ setSearchValue(event.target.value);
10899
+ if (onSearchChange) {
10900
+ onSearchChange(event.target.value);
10901
+ }
10902
+ };
10903
+ const handleKeyDown = event => {
10904
+ switch (event.keyCode) {
10905
+ case KeyCodes.UP:
10906
+ case KeyCodes.DOWN:
10907
+ if (open) {
10908
+ moveFocusWithDifference(event.keyCode === KeyCodes.UP ? -1 : 1);
10909
+ } else {
10910
+ setOpen(true);
10911
+ }
10912
+ stopPropagation$1(event);
10913
+ break;
10914
+ case KeyCodes.SPACE:
10915
+ if (event.target !== searchBoxReference.current) {
10916
+ if (open) {
10917
+ selectKeyboardFocusedOption();
10918
+ } else {
10919
+ setOpen(true);
10920
+ }
10921
+ stopPropagation$1(event);
10922
+ }
10923
+ break;
10924
+ case KeyCodes.ENTER:
10925
+ if (open) {
10926
+ selectKeyboardFocusedOption();
10927
+ } else {
10928
+ setOpen(true);
10929
+ }
10930
+ stopPropagation$1(event);
10931
+ break;
10932
+ case KeyCodes.ESCAPE:
10933
+ handleCloseOptions();
10934
+ stopPropagation$1(event);
10935
+ break;
10936
+ case KeyCodes.TAB:
10937
+ if (open) {
10938
+ selectKeyboardFocusedOption();
10939
+ }
10940
+ break;
10941
+ }
10942
+ };
10943
+ function selectKeyboardFocusedOption() {
10944
+ if (keyboardFocusedOptionIndex != null) {
10945
+ selectableOptions.length > 0 && selectOption(selectableOptions[keyboardFocusedOptionIndex]);
10946
+ }
10947
+ }
10948
+ function moveFocusWithDifference(difference) {
10949
+ const selectedOptionIndex = selectableOptions.reduce((optionIndex, current, index) => {
10950
+ if (optionIndex != null) {
10951
+ return optionIndex;
10952
+ }
10953
+ if (isOptionSelected(selected, current)) {
10954
+ return index;
10955
+ }
10956
+ return null;
10957
+ }, null);
10958
+ const previousFocusedIndex = previousKeyboardFocusedOptionIndex.current ?? -1;
10959
+ let indexToStartMovingFrom = previousFocusedIndex;
10960
+ if (previousFocusedIndex === -1) {
10961
+ if (selectedOptionIndex == null) {
10962
+ setKeyboardFocusedOptionIndex(0);
10963
+ } else {
10964
+ indexToStartMovingFrom = selectedOptionIndex;
10965
+ }
10966
+ }
10967
+ const unClampedNewIndex = indexToStartMovingFrom + difference;
10968
+ const newIndex = clamp(0, selectableOptions.length - 1, unClampedNewIndex);
10969
+ setKeyboardFocusedOptionIndex(newIndex);
10970
+ }
10971
+ React.useEffect(() => {
10972
+ if (open) {
10973
+ if (!isMobile || searchValue) {
10974
+ if (isSearchEnabled && !!searchBoxReference.current) {
10975
+ searchBoxReference.current.focus();
10976
+ }
10977
+ if (!isSearchEnabled && optionsListReference.current && (previousKeyboardFocusedOptionIndex.current == null || Number.isNaN(previousKeyboardFocusedOptionIndex.current))) {
10978
+ optionsListReference.current.focus();
10979
+ }
10980
+ }
10981
+ previousKeyboardFocusedOptionIndex.current = keyboardFocusedOptionIndex;
10982
+ } else {
10983
+ previousKeyboardFocusedOptionIndex.current = null;
10984
+ }
10985
+ }, [open, searchValue, isSearchEnabled, isMobile, keyboardFocusedOptionIndex]);
10986
+ const handleCloseOptions = () => {
10987
+ setOpen(false);
10988
+ setKeyboardFocusedOptionIndex(null);
10989
+ if (dropdownButtonReference.current) {
10990
+ dropdownButtonReference.current.focus();
10991
+ }
10992
+ };
10993
+ function createSelectHandlerForOption(option) {
10994
+ return event => {
10995
+ stopPropagation$1(event);
10996
+ selectOption(option);
10997
+ };
10998
+ }
10999
+ function selectOption(option) {
11000
+ onChange(isPlaceholderOption(option) ? DEFAULT_SELECTED_OPTION : option);
11001
+ handleCloseOptions();
11002
+ }
11003
+ function renderOptionsList({
11004
+ className
11005
+ } = {}) {
11006
+ const dropdownClass = classNames__default.default(s('np-dropdown-menu'), {
11007
+ [s('np-dropdown-menu-desktop')]: !isMobile,
11008
+ [s(`np-dropdown-menu-${dropdownWidth}`)]: !isMobile && !isDropdownAutoWidth
11009
+ }, s(className));
11010
+ const showPlaceholder = !required && !isSearchEnabled && Boolean(placeholder);
11011
+ return /*#__PURE__*/jsxRuntime.jsxs("ul", {
11012
+ ref: optionsListReference,
11013
+ id: listboxId,
11014
+ role: "listbox",
11015
+ "aria-orientation": "vertical",
11016
+ "aria-activedescendant": getUniqueIdForOption(id, selected),
11017
+ tabIndex: "-1",
11018
+ className: dropdownClass,
11019
+ ...dropdownProps,
11020
+ children: [showPlaceholder && /*#__PURE__*/jsxRuntime.jsx(PlaceHolderOption, {}), isSearchEnabled && /*#__PURE__*/jsxRuntime.jsx(SearchBox$1, {
11021
+ ref: searchBoxReference,
11022
+ id: searchBoxId,
11023
+ classNames: classNamesProp,
11024
+ value: initSearchValue || searchValue,
11025
+ placeholder: searchPlaceholder || formatMessage(messages$2.searchPlaceholder),
11026
+ focusedOptionId: getUniqueIdForOption(id, focusedOption),
11027
+ onChange: handleSearchChange,
11028
+ onClick: stopPropagation$1
11029
+ }), options.slice(0, numberOfOptionsShown).map(renderOption), numberOfOptionsShown < options.length && /*#__PURE__*/jsxRuntime.jsx(ShowMoreOption, {})]
11030
+ });
11031
+ }
11032
+ function ShowMoreOption() {
11033
+ function handleOnClick(event) {
11034
+ stopPropagation$1(event);
11035
+ setNumberOfOptionsShown(numberOfOptionsShown + DEFAULT_OPTIONS_PAGE_SIZE);
11036
+ }
11037
+ return (
11038
+ /*#__PURE__*/
11039
+ /* eslint-disable-next-line jsx-a11y/no-noninteractive-element-interactions */
11040
+ jsxRuntime.jsx("li", {
11041
+ className: classNames__default.default(s('clickable'), s('border-bottom'), s('show-more')),
11042
+ onClick: handleOnClick,
11043
+ onKeyPress: handleOnClick,
11044
+ children: /*#__PURE__*/jsxRuntime.jsx("a", {
11045
+ children: "..."
11046
+ })
11047
+ })
11048
+ );
11049
+ }
11050
+ function PlaceHolderOption() {
11051
+ const placeholderOption = {
11052
+ placeholder
11053
+ };
11054
+ return (
11055
+ /*#__PURE__*/
11056
+ /* eslint-disable-next-line jsx-a11y/no-noninteractive-element-interactions */
11057
+ jsxRuntime.jsx("li", {
11058
+ className: classNames__default.default(s('clickable'), s('border-bottom')),
11059
+ onClick: createSelectHandlerForOption(placeholderOption),
11060
+ onKeyPress: createSelectHandlerForOption(placeholderOption),
11061
+ children: /*#__PURE__*/jsxRuntime.jsx("a", {
11062
+ children: placeholder
11063
+ })
11064
+ })
11065
+ );
11066
+ }
11067
+
11068
+ // eslint-disable-next-line react/prop-types
11069
+ function SeparatorOption() {
11070
+ return /*#__PURE__*/jsxRuntime.jsx("li", {
11071
+ className: s('np-separator'),
11072
+ "aria-hidden": true
11073
+ });
11074
+ }
11075
+
11076
+ // eslint-disable-next-line react/prop-types
11077
+ function HeaderOption({
11078
+ children
11079
+ }) {
11080
+ return /*#__PURE__*/jsxRuntime.jsx("li", {
11081
+ // eslint-disable-line jsx-a11y/no-noninteractive-element-interactions
11082
+ className: classNames__default.default(s('np-dropdown-header'), s('np-text-title-group')),
11083
+ onClick: stopPropagation$1,
11084
+ onKeyPress: stopPropagation$1,
11085
+ children: children
11086
+ });
11087
+ }
11088
+ function isOptionSelected(selected, option) {
11089
+ return selected?.value === option?.value;
11090
+ }
11091
+ const renderOption = (option, index) => {
11092
+ const separatorOption = option;
11093
+ if (isSeparatorOption(separatorOption) && separatorOption?.separator) {
11094
+ return /*#__PURE__*/jsxRuntime.jsx(SeparatorOption, {}, index);
11095
+ }
11096
+ const headerOption = option;
11097
+ if (isHeaderOption(headerOption) && headerOption.header) {
11098
+ return /*#__PURE__*/jsxRuntime.jsx(HeaderOption, {
11099
+ children: headerOption.header
11100
+ }, index);
11101
+ }
11102
+ const isActive = isOptionSelected(selected, option);
11103
+ const selectOption = option;
11104
+ const isFocusedWithKeyboard = !selectOption.disabled && keyboardFocusedOptionIndex === getIndexWithoutHeadersForIndexWithHeaders(index);
11105
+ const className = classNames__default.default(s('np-dropdown-item'), selectOption.disabled ? [s('disabled')] : s('clickable'), {
11106
+ [s('active')]: isActive,
11107
+ [s('np-dropdown-item--focused')]: isFocusedWithKeyboard
11108
+ });
11109
+ const handleOnClick = selectOption.disabled ? stopPropagation$1 : createSelectHandlerForOption(selectOption);
11110
+ return (
11111
+ /*#__PURE__*/
11112
+ /* eslint-disable-next-line jsx-a11y/no-noninteractive-element-interactions */
11113
+ jsxRuntime.jsx("li", {
11114
+ ref: isFocusedWithKeyboard ? keyboardFocusedReference : undefined,
11115
+ id: getUniqueIdForOption(id, option),
11116
+ "aria-selected": isActive,
11117
+ "aria-disabled": option.disabled,
11118
+ role: "option",
11119
+ tabIndex: "-1",
11120
+ className: className,
11121
+ onClick: handleOnClick,
11122
+ onKeyPress: handleOnClick,
11123
+ children: /*#__PURE__*/jsxRuntime.jsx("a", {
11124
+ disabled: selectOption.disabled,
11125
+ children: /*#__PURE__*/jsxRuntime.jsx(Option$1, {
11126
+ ...selectOption,
11127
+ classNames: classNamesProp
11128
+ })
11129
+ })
11130
+ }, index)
11131
+ );
11132
+ };
11133
+ function getIndexWithoutHeadersForIndexWithHeaders(index) {
11134
+ return options.reduce((sum, option, currentIndex) => {
11135
+ if (currentIndex < index && isActionableOption(option)) {
11136
+ return sum + 1;
11137
+ }
11138
+ return sum;
11139
+ }, 0);
11140
+ }
11141
+ const hasActiveOptions = !!defaultOptions.length;
11142
+ if (open && (initSearchValue || searchValue)) {
11143
+ if (hasActiveOptions && keyboardFocusedOptionIndex == null) {
11144
+ setKeyboardFocusedOptionIndex(0);
11145
+ }
11146
+ if (!hasActiveOptions && keyboardFocusedOptionIndex != null) {
11147
+ setKeyboardFocusedOptionIndex(null);
11148
+ }
11149
+ }
11150
+ return /*#__PURE__*/jsxRuntime.jsxs("div", {
11151
+ // eslint-disable-line jsx-a11y/no-static-element-interactions
11152
+ ref: selectReference,
11153
+ className: classNames__default.default(s('np-select'), block ? s('btn-block') : null, s('btn-group')),
11154
+ onKeyDown: handleKeyDown,
11155
+ onTouchMove: handleTouchStart,
11156
+ onFocus: handleOnFocus,
11157
+ onBlur: handleOnBlur,
11158
+ children: [/*#__PURE__*/jsxRuntime.jsxs(Button, {
11159
+ ref: dropdownButtonReference,
11160
+ id: computedId,
11161
+ block: block,
11162
+ size: size,
11163
+ htmlType: "button",
11164
+ className: classNames__default.default(s('np-dropdown-toggle'), s('np-text-body-large'), inverse ? s('np-dropdown-toggle-navy') : null)
11165
+ // reset Button's styles
11166
+ ,
11167
+ type: null,
11168
+ priority: null,
11169
+ disabled: disabled,
11170
+ "aria-controls": listboxId,
11171
+ "aria-expanded": open,
11172
+ "aria-autocomplete": "none",
11173
+ onClick: handleOnClick,
11174
+ ...buttonProps,
11175
+ children: [selected ? /*#__PURE__*/jsxRuntime.jsx(Option$1, {
11176
+ ...selected,
11177
+ classNames: classNamesProp,
11178
+ selected: true
11179
+ }) : /*#__PURE__*/jsxRuntime.jsx("span", {
11180
+ className: s('form-control-placeholder'),
11181
+ children: placeholder
11182
+ }), /*#__PURE__*/jsxRuntime.jsx(Chevron$1
11183
+ // disabled={disabled}
11184
+ , {
11185
+ className: classNames__default.default(s('tw-icon'), s('tw-chevron-up-icon'), s('tw-chevron'), s('bottom'), s('np-select-chevron'))
11186
+ })]
11187
+ }), isMobile ? isSearchEnabled ? /*#__PURE__*/jsxRuntime.jsx(Drawer$1, {
11188
+ open: open,
11189
+ headerTitle: searchPlaceholder || formatMessage(messages$2.searchPlaceholder),
11190
+ onClose: handleCloseOptions,
11191
+ children: renderOptionsList()
11192
+ }) : /*#__PURE__*/jsxRuntime.jsx(BottomSheet$2, {
11193
+ open: open,
11194
+ onClose: handleCloseOptions,
11195
+ children: renderOptionsList({
11196
+ className: isModern ? '' : 'p-a-1'
11197
+ })
11198
+ }) : /*#__PURE__*/jsxRuntime.jsx(Panel$1, {
11199
+ open: open,
11200
+ flip: false,
11201
+ altAxis: true,
11202
+ anchorRef: selectReference,
11203
+ anchorWidth: isDropdownAutoWidth,
11204
+ position: dropdownUp ? exports.Position.TOP : exports.Position.BOTTOM,
11205
+ onClose: handleCloseOptions,
11206
+ children: renderOptionsList({
11207
+ className: 'p-a-1'
11208
+ })
11209
+ })]
11210
+ });
11211
+ }
11212
+ Select.propTypes = {
11213
+ placeholder: PropTypes__default.default.string,
11066
11214
  id: PropTypes__default.default.string,
11067
- label: PropTypes__default.default.string.isRequired,
11068
- name: PropTypes__default.default.string.isRequired,
11215
+ required: PropTypes__default.default.bool,
11216
+ disabled: PropTypes__default.default.bool,
11217
+ inverse: PropTypes__default.default.bool,
11218
+ dropdownRight: PropTypes__default.default.oneOf(['xs', 'sm', 'md', 'lg', 'xl']),
11219
+ dropdownWidth: PropTypes__default.default.oneOf(['sm', 'md', 'lg']),
11220
+ size: PropTypes__default.default.oneOf(['sm', 'md', 'lg']),
11221
+ block: PropTypes__default.default.bool,
11222
+ selected: PropTypes__default.default.shape({
11223
+ value: PropTypes__default.default.any.isRequired,
11224
+ label: PropTypes__default.default.node,
11225
+ icon: PropTypes__default.default.node,
11226
+ currency: PropTypes__default.default.string,
11227
+ note: PropTypes__default.default.node,
11228
+ secondary: PropTypes__default.default.node
11229
+ }),
11230
+ /**
11231
+ * Search toggle
11232
+ * if `true` default search functionality being enabled (not case sensitive search in option labels & currency props)
11233
+ * if `function` you can define your own search function to implement custom search experience. This search function used while filtering the options array. The custom search function takes two parameters. First is the option the second is the keyword.
11234
+ */
11235
+ search: PropTypes__default.default.oneOfType([PropTypes__default.default.bool, PropTypes__default.default.func]),
11069
11236
  onChange: PropTypes__default.default.func.isRequired,
11070
- secondary: PropTypes__default.default.string,
11071
- value: PropTypes__default.default.oneOfType([PropTypes__default.default.number, PropTypes__default.default.string]),
11072
- className: PropTypes__default.default.string
11073
- };
11074
- Radio.defaultProps = {
11075
- avatar: undefined,
11076
- checked: false,
11077
- disabled: false,
11078
- id: null,
11079
- secondary: null,
11080
- value: '',
11081
- className: undefined
11082
- };
11083
- var Radio$1 = Radio;
11084
-
11085
- class RadioGroup extends React.Component {
11086
- constructor(props) {
11087
- super(props);
11088
- this.state = {
11089
- selectedValue: props.selectedValue
11090
- };
11091
- }
11092
- handleOnChange = selectedValue => {
11093
- const {
11094
- onChange
11095
- } = this.props;
11096
- this.setState({
11097
- selectedValue
11098
- }, onChange && onChange(selectedValue));
11099
- };
11100
- render() {
11101
- const {
11102
- radios,
11103
- name
11104
- } = this.props;
11105
- const {
11106
- selectedValue
11107
- } = this.state;
11108
- return radios && radios.length > 0 ? /*#__PURE__*/jsxRuntime.jsx(jsxRuntime.Fragment, {
11109
- children: radios.map(({
11110
- id,
11111
- avatar,
11112
- value,
11113
- label,
11114
- disabled,
11115
- secondary,
11116
- readOnly
11117
- }, index) => /*#__PURE__*/jsxRuntime.jsx(Radio$1
11118
- // eslint-disable-next-line react/no-array-index-key
11119
- , {
11120
- id: id,
11121
- value: value,
11122
- label: label,
11123
- name: name,
11124
- disabled: disabled,
11125
- checked: selectedValue === value,
11126
- secondary: secondary,
11127
- readOnly: readOnly,
11128
- avatar: avatar,
11129
- onChange: value_ => this.handleOnChange(value_)
11130
- }, index))
11131
- }) : null;
11132
- }
11133
- }
11134
- RadioGroup.propTypes = {
11135
- radios: PropTypes__default.default.arrayOf(PropTypes__default.default.shape({
11136
- id: PropTypes__default.default.string,
11137
- avatar: PropTypes__default.default.element,
11138
- value: PropTypes__default.default.oneOfType([PropTypes__default.default.number, PropTypes__default.default.string]),
11139
- secondary: PropTypes__default.default.string,
11140
- label: PropTypes__default.default.string.isRequired,
11237
+ onFocus: PropTypes__default.default.func,
11238
+ onBlur: PropTypes__default.default.func,
11239
+ options: PropTypes__default.default.arrayOf(PropTypes__default.default.shape({
11240
+ value: PropTypes__default.default.any,
11241
+ label: PropTypes__default.default.node,
11242
+ header: PropTypes__default.default.node,
11243
+ icon: PropTypes__default.default.node,
11244
+ currency: PropTypes__default.default.string,
11245
+ note: PropTypes__default.default.node,
11246
+ secondary: PropTypes__default.default.node,
11247
+ separator: PropTypes__default.default.bool,
11141
11248
  disabled: PropTypes__default.default.bool,
11142
- readOnly: PropTypes__default.default.bool
11249
+ searchStrings: PropTypes__default.default.arrayOf(PropTypes__default.default.string)
11143
11250
  })).isRequired,
11144
- onChange: PropTypes__default.default.func.isRequired,
11145
- selectedValue: PropTypes__default.default.oneOfType([PropTypes__default.default.number, PropTypes__default.default.string]),
11146
- name: PropTypes__default.default.string.isRequired
11147
- };
11148
- RadioGroup.defaultProps = {
11149
- selectedValue: null
11150
- };
11151
- var RadioGroup$1 = RadioGroup;
11152
-
11153
- const RadioOption = ({
11154
- 'aria-label': ariaLabel,
11155
- media,
11156
- title,
11157
- content,
11158
- id,
11159
- name,
11160
- checked,
11161
- onChange,
11162
- complex,
11163
- disabled,
11164
- value,
11165
- showMediaCircle,
11166
- showMediaAtAllSizes,
11167
- isContainerAligned
11168
- }) => {
11169
- const sharedProps = {
11170
- 'aria-label': ariaLabel,
11171
- media,
11172
- title,
11173
- content,
11174
- name,
11175
- complex,
11176
- disabled,
11177
- showMediaCircle,
11178
- showMediaAtAllSizes,
11179
- isContainerAligned
11180
- };
11181
- return /*#__PURE__*/jsxRuntime.jsx(Option$2, {
11182
- ...sharedProps,
11183
- button: /*#__PURE__*/jsxRuntime.jsx(RadioButton$1, {
11184
- id: id,
11185
- name: name,
11186
- checked: checked,
11187
- disabled: disabled,
11188
- value: value,
11189
- onChange: onChange
11190
- })
11191
- });
11192
- };
11193
- RadioOption.propTypes = {
11194
- 'aria-label': PropTypes__default.default.string,
11195
- media: PropTypes__default.default.node,
11196
- id: PropTypes__default.default.string.isRequired,
11197
- name: PropTypes__default.default.string.isRequired,
11198
- title: PropTypes__default.default.node.isRequired,
11199
- content: PropTypes__default.default.node,
11200
- checked: PropTypes__default.default.bool,
11201
- onChange: PropTypes__default.default.func.isRequired,
11202
- complex: PropTypes__default.default.bool,
11203
- disabled: PropTypes__default.default.bool,
11204
- value: PropTypes__default.default.string,
11205
- showMediaCircle: PropTypes__default.default.bool,
11206
- showMediaAtAllSizes: PropTypes__default.default.bool,
11207
- isContainerAligned: PropTypes__default.default.bool
11251
+ /**
11252
+ * To have full control of your search value and response use `onSearchChange` function combined with `searchValue` and custom filtering on the options array.
11253
+ * DO NOT USE TOGETHER WITH `search` PROPERTY
11254
+ */
11255
+ onSearchChange: PropTypes__default.default.func,
11256
+ searchValue: PropTypes__default.default.string,
11257
+ searchPlaceholder: PropTypes__default.default.string,
11258
+ classNames: PropTypes__default.default.objectOf(PropTypes__default.default.string),
11259
+ dropdownUp: PropTypes__default.default.bool,
11260
+ buttonProps: PropTypes__default.default.object,
11261
+ dropdownProps: PropTypes__default.default.object
11208
11262
  };
11209
- RadioOption.defaultProps = {
11210
- 'aria-label': undefined,
11211
- media: null,
11212
- content: null,
11213
- checked: false,
11214
- complex: false,
11263
+ Select.defaultProps = {
11264
+ id: undefined,
11265
+ placeholder: undefined,
11266
+ size: 'md',
11267
+ dropdownRight: null,
11268
+ dropdownWidth: null,
11269
+ inverse: false,
11270
+ required: false,
11215
11271
  disabled: false,
11216
- showMediaCircle: true,
11217
- showMediaAtAllSizes: false,
11218
- isContainerAligned: false,
11219
- value: ''
11220
- };
11221
- var RadioOption$1 = RadioOption;
11222
-
11223
- const Section = ({
11224
- children,
11225
- className,
11226
- withHorizontalPadding = false
11227
- }) => {
11228
- return /*#__PURE__*/jsxRuntime.jsx("div", {
11229
- className: classNames__default.default('np-section', className, {
11230
- 'np-section--with-horizontal-padding': withHorizontalPadding
11231
- }),
11232
- children: children
11233
- });
11272
+ block: true,
11273
+ selected: null,
11274
+ onFocus: null,
11275
+ onBlur: null,
11276
+ onSearchChange: undefined,
11277
+ search: false,
11278
+ searchValue: '',
11279
+ searchPlaceholder: undefined,
11280
+ classNames: {},
11281
+ dropdownUp: false,
11282
+ buttonProps: {},
11283
+ dropdownProps: {}
11234
11284
  };
11235
11285
 
11236
11286
  const CSS_TRANSITION_DURATION = 400;