@transferwise/components 0.0.0-experimental-e05dfa3 → 0.0.0-experimental-7905c27

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.
Files changed (50) hide show
  1. package/build/index.esm.js +102 -164
  2. package/build/index.esm.js.map +1 -1
  3. package/build/index.js +104 -166
  4. package/build/index.js.map +1 -1
  5. package/build/main.css +1 -1
  6. package/build/styles/dateLookup/DateLookup.css +1 -1
  7. package/build/styles/header/Header.css +1 -1
  8. package/build/styles/main.css +1 -1
  9. package/build/types/dateInput/DateInput.d.ts +2 -0
  10. package/build/types/dateInput/DateInput.d.ts.map +1 -1
  11. package/build/types/dateLookup/DateLookup.d.ts.map +1 -1
  12. package/build/types/dateLookup/monthCalendar/table/MonthCalendarTable.d.ts +1 -1
  13. package/build/types/dateLookup/monthCalendar/table/MonthCalendarTable.d.ts.map +1 -1
  14. package/build/types/dateLookup/tableLink/TableLink.d.ts +2 -16
  15. package/build/types/dateLookup/tableLink/TableLink.d.ts.map +1 -1
  16. package/build/types/dateLookup/tableLink/index.d.ts +1 -1
  17. package/build/types/dateLookup/tableLink/index.d.ts.map +1 -1
  18. package/build/types/dateLookup/yearCalendar/table/YearCalendarTable.d.ts.map +1 -1
  19. package/build/types/select/Select.d.ts.map +1 -1
  20. package/build/types/test-utils/window-mock.d.ts +1 -0
  21. package/build/types/test-utils/window-mock.d.ts.map +1 -1
  22. package/package.json +1 -1
  23. package/src/dateInput/DateInput.js +13 -7
  24. package/src/dateInput/DateInput.spec.js +12 -136
  25. package/src/dateInput/DateInput.story.tsx +49 -2
  26. package/src/dateLookup/DateLookup.css +1 -1
  27. package/src/dateLookup/DateLookup.js +3 -16
  28. package/src/dateLookup/DateLookup.keyboardEvents.spec.js +0 -12
  29. package/src/dateLookup/DateLookup.less +49 -46
  30. package/src/dateLookup/DateLookup.story.js +7 -8
  31. package/src/dateLookup/dayCalendar/table/DayCalendarTable.js +1 -14
  32. package/src/dateLookup/dayCalendar/table/DayCalendarTable.spec.js +0 -25
  33. package/src/dateLookup/monthCalendar/table/MonthCalendarTable.js +20 -33
  34. package/src/dateLookup/monthCalendar/table/MonthCalendarTable.spec.js +0 -33
  35. package/src/dateLookup/tableLink/TableLink.js +70 -0
  36. package/src/dateLookup/yearCalendar/table/YearCalendarTable.js +11 -33
  37. package/src/dateLookup/yearCalendar/table/YearCalendarTable.spec.js +0 -26
  38. package/src/header/Header.css +1 -1
  39. package/src/header/Header.less +0 -5
  40. package/src/inputs/SelectInput.spec.tsx +3 -27
  41. package/src/main.css +1 -1
  42. package/src/phoneNumberInput/PhoneNumberInput.spec.js +4 -20
  43. package/src/select/Select.js +3 -0
  44. package/src/test-utils/window-mock.ts +11 -0
  45. package/build/types/dateLookup/getFocusableTime/getFocusableTime.d.ts +0 -2
  46. package/build/types/dateLookup/getFocusableTime/getFocusableTime.d.ts.map +0 -1
  47. package/src/dateLookup/getFocusableTime/getFocusable.spec.js +0 -38
  48. package/src/dateLookup/getFocusableTime/getFocusableTime.tsx +0 -28
  49. package/src/dateLookup/tableLink/TableLink.tsx +0 -80
  50. /package/src/dateLookup/tableLink/{index.ts → index.js} +0 -0
@@ -8,18 +8,18 @@ import PropTypes from 'prop-types';
8
8
  import { defineMessages, useIntl, injectIntl, IntlProvider } from 'react-intl';
9
9
  import { useTheme, ThemeProvider } from '@wise/components-theming';
10
10
  import { formatDate, formatNumber, formatMoney, formatAmount } from '@transferwise/formatting';
11
- import throttle from 'lodash.throttle';
12
- import { CSSTransition } from 'react-transition-group';
13
- import { createPortal } from 'react-dom';
14
- import { FocusScope } from '@react-aria/focus';
15
- import mergeRefs from 'react-merge-refs';
16
- import { useSyncExternalStore } from 'use-sync-external-store/shim';
17
- import { isUndefined, isKey, isNumber, isEmpty, isNull, isArray } from '@transferwise/neptune-validation';
18
- import { usePopper } from 'react-popper';
19
11
  import { Transition, Listbox } from '@headlessui/react';
20
12
  import mergeProps from 'merge-props';
13
+ import mergeRefs from 'react-merge-refs';
14
+ import { useSyncExternalStore } from 'use-sync-external-store/shim';
21
15
  import { useFloating, useDismiss, useRole, useInteractions, FloatingPortal, FloatingFocusManager, offset, flip, shift, size, autoUpdate } from '@floating-ui/react';
16
+ import { FocusScope } from '@react-aria/focus';
22
17
  import { usePreventScroll } from '@react-aria/overlays';
18
+ import { CSSTransition } from 'react-transition-group';
19
+ import { usePopper } from 'react-popper';
20
+ import throttle from 'lodash.throttle';
21
+ import { createPortal } from 'react-dom';
22
+ import { isUndefined, isKey, isNumber, isEmpty, isNull, isArray } from '@transferwise/neptune-validation';
23
23
  import { Illustration } from '@wise/art';
24
24
  import clamp$2 from 'lodash.clamp';
25
25
  import debounce from 'lodash.debounce';
@@ -2900,6 +2900,8 @@ const INITIAL_DEFAULT_STATE = {
2900
2900
  day: null
2901
2901
  };
2902
2902
  const DateInput = ({
2903
+ 'aria-labelledby': ariaLabelledBy,
2904
+ 'aria-label': ariaLabel,
2903
2905
  disabled,
2904
2906
  size,
2905
2907
  value,
@@ -2965,20 +2967,25 @@ const DateInput = ({
2965
2967
  const getSelectElement = () => {
2966
2968
  const months = getMonthNames(locale, monthFormat);
2967
2969
  return /*#__PURE__*/jsxs("label", {
2970
+ className: "d-flex flex-column",
2968
2971
  children: [/*#__PURE__*/jsx("span", {
2969
2972
  className: "sr-only",
2970
2973
  children: monthLabel
2971
- }), /*#__PURE__*/jsx(Select, {
2972
- id: id ? `${id}-select` : undefined,
2974
+ }), /*#__PURE__*/jsx(SelectInput, {
2973
2975
  name: "month",
2974
2976
  disabled: disabled,
2975
2977
  placeholder: placeholders.month,
2976
- options: getMonthsOptions(),
2978
+ items: getMonthsOptions(),
2977
2979
  size: size,
2978
- selected: month === null ? null : {
2980
+ value: month === null ? null : {
2979
2981
  value: month,
2980
2982
  label: months[month]
2981
2983
  },
2984
+ renderValue: ({
2985
+ label
2986
+ }) => /*#__PURE__*/jsx(SelectInputOptionContent, {
2987
+ title: label
2988
+ }),
2982
2989
  onChange: selectedValue => handleMonthChange(selectedValue),
2983
2990
  ...selectProps
2984
2991
  })]
@@ -2989,8 +2996,11 @@ const DateInput = ({
2989
2996
  const months = getMonthNames(locale, monthFormat);
2990
2997
  months.forEach((label, index) => {
2991
2998
  options.push({
2992
- value: index,
2993
- label
2999
+ type: 'option',
3000
+ value: {
3001
+ label,
3002
+ value: index
3003
+ }
2994
3004
  });
2995
3005
  });
2996
3006
  return options;
@@ -3087,6 +3097,8 @@ const DateInput = ({
3087
3097
  return /*#__PURE__*/jsx("div", {
3088
3098
  className: "tw-date",
3089
3099
  id: id,
3100
+ "aria-labelledby": ariaLabelledBy,
3101
+ "aria-label": ariaLabel,
3090
3102
  onFocus: event => shouldPropagateOnFocus(event) ? onFocus && onFocus() : event.stopPropagation(),
3091
3103
  onBlur: event => shouldPropagateOnBlur(event) ? onBlur && onBlur() : event.stopPropagation(),
3092
3104
  children: /*#__PURE__*/jsxs("div", {
@@ -3169,6 +3181,8 @@ function shouldPropagateOnBlur({
3169
3181
  return blurElementParent !== focusElementParent;
3170
3182
  }
3171
3183
  DateInput.propTypes = {
3184
+ 'aria-label': PropTypes.string,
3185
+ 'aria-labelledby': PropTypes.string,
3172
3186
  disabled: PropTypes.bool,
3173
3187
  size: PropTypes.oneOf(['sm', 'md', 'lg']),
3174
3188
  value: PropTypes.oneOfType([PropTypes.string, PropTypes.instanceOf(Date)]),
@@ -3564,28 +3578,6 @@ DateHeader.defaultProps = {
3564
3578
  };
3565
3579
  var DateHeader$1 = DateHeader;
3566
3580
 
3567
- function getFocusableTime(isSelected, isNow, isDisabled, timeSpan) {
3568
- let selected = null;
3569
- let now = null;
3570
- let disabled = null;
3571
- for (const time of timeSpan) {
3572
- if (isSelected(time)) {
3573
- selected = time;
3574
- break;
3575
- }
3576
- if (isNow(time)) {
3577
- now = time;
3578
- }
3579
- if (!isDisabled(time) && disabled === null) {
3580
- disabled = time;
3581
- }
3582
- if (selected) {
3583
- break;
3584
- }
3585
- }
3586
- return selected || now || disabled;
3587
- }
3588
-
3589
3581
  // NB! Using with UTC timestamp (YYYY-MM-DD) might lead to unexpected results, for example
3590
3582
  // getStartOfDay(new Date('1995-01-01')) in Los Angeles returns 31 Dec 1994, but in
3591
3583
  // in Singapore it is 1 Jan 1995.
@@ -3597,57 +3589,59 @@ function getStartOfDay(date) {
3597
3589
  return new Date(date.getFullYear(), date.getMonth(), date.getDate());
3598
3590
  }
3599
3591
 
3600
- const TableLink = ({
3601
- item,
3602
- type,
3603
- title,
3604
- longTitle,
3605
- active,
3606
- disabled,
3607
- today,
3608
- autofocus,
3609
- onClick,
3610
- intl: {
3611
- formatMessage
3612
- }
3613
- }) => {
3614
- const buttonRef = useRef(null);
3615
- useEffect(() => {
3616
- if (autofocus) {
3617
- setTimeout(() => {
3618
- buttonRef.current?.focus();
3619
- }, 0);
3620
- }
3621
- }, [autofocus]);
3622
- const onCalendarClick = event => {
3592
+ class TableLink extends PureComponent {
3593
+ onClick = event => {
3623
3594
  event.preventDefault();
3624
- if (!disabled) {
3625
- onClick(item);
3595
+ if (!this.props.disabled) {
3596
+ this.props.onClick(this.props.item);
3626
3597
  }
3627
3598
  };
3628
- const calculateAriaLabel = () => {
3599
+ calculateAriaLabel = (longTitle, title, active, type, formatMessage) => {
3629
3600
  if (active) {
3630
- return `${longTitle || title || ''}, ${formatMessage(messages$6.selected)} ${formatMessage(messages$6[type])}`;
3601
+ return `${longTitle || title}, ${formatMessage(messages$6.selected)} ${formatMessage(messages$6[type])}`;
3631
3602
  }
3632
3603
  return longTitle || title;
3633
3604
  };
3634
- return /*#__PURE__*/jsx(Fragment, {
3635
- children: /*#__PURE__*/jsx("button", {
3636
- ref: buttonRef,
3637
- type: "button",
3638
- className: classNames(`tw-date-lookup-${type}-option np-text-body-default-bold`, {
3639
- active: !!active
3640
- }, {
3641
- today: !!today
3642
- }),
3643
- disabled: disabled,
3644
- tabIndex: autofocus ? 0 : -1,
3645
- "aria-label": calculateAriaLabel(),
3646
- "aria-pressed": active,
3647
- onClick: onCalendarClick,
3648
- children: title || item
3649
- })
3650
- });
3605
+ render() {
3606
+ const {
3607
+ item,
3608
+ type,
3609
+ title,
3610
+ longTitle,
3611
+ active,
3612
+ disabled,
3613
+ today,
3614
+ intl: {
3615
+ formatMessage
3616
+ }
3617
+ } = this.props;
3618
+ return /*#__PURE__*/jsx(Fragment, {
3619
+ children: /*#__PURE__*/jsx("button", {
3620
+ type: "button",
3621
+ className: `tw-date-lookup-${type}-option ${active ? 'active' : ''} ${today ? 'today' : ''} np-text-body-default-bold`,
3622
+ disabled: disabled,
3623
+ "aria-label": this.calculateAriaLabel(longTitle, title, active, type, formatMessage),
3624
+ "aria-pressed": active,
3625
+ onClick: this.onClick,
3626
+ children: title || item
3627
+ })
3628
+ });
3629
+ }
3630
+ }
3631
+ TableLink.propTypes = {
3632
+ item: PropTypes.number.isRequired,
3633
+ // day (1-31), month (0-11) or year (2018 etc)
3634
+ type: PropTypes.oneOf(['day', 'month', 'year']).isRequired,
3635
+ title: PropTypes.string,
3636
+ longTitle: PropTypes.string,
3637
+ active: PropTypes.bool.isRequired,
3638
+ disabled: PropTypes.bool.isRequired,
3639
+ today: PropTypes.bool.isRequired,
3640
+ onClick: PropTypes.func.isRequired
3641
+ };
3642
+ TableLink.defaultProps = {
3643
+ title: null,
3644
+ longTitle: null
3651
3645
  };
3652
3646
  var TableLink$1 = injectIntl(TableLink);
3653
3647
 
@@ -3720,17 +3714,6 @@ class DayCalendarTable extends PureComponent {
3720
3714
  } = this.props;
3721
3715
  return !!(selectedDate && +new Date(viewYear, viewMonth, day) === +selectedDate);
3722
3716
  };
3723
- isToday = day => {
3724
- const {
3725
- viewMonth,
3726
- viewYear
3727
- } = this.props;
3728
- return +getStartOfDay(new Date()) === +new Date(viewYear, viewMonth, day);
3729
- };
3730
- getAutofocusDay = weeks => {
3731
- const days = weeks.flatMap(week => week);
3732
- return getFocusableTime(this.isActive, this.isToday, this.isDisabled, days);
3733
- };
3734
3717
  render() {
3735
3718
  const {
3736
3719
  viewMonth,
@@ -3740,7 +3723,6 @@ class DayCalendarTable extends PureComponent {
3740
3723
  }
3741
3724
  } = this.props;
3742
3725
  const weeks = this.getTableStructure();
3743
- let autoFocusDay = this.getAutofocusDay(weeks, viewMonth, viewYear);
3744
3726
  return /*#__PURE__*/jsxs("table", {
3745
3727
  className: "table table-condensed table-bordered tw-date-lookup-calendar m-b-0",
3746
3728
  children: [/*#__PURE__*/jsx("thead", {
@@ -3770,11 +3752,10 @@ class DayCalendarTable extends PureComponent {
3770
3752
  item: day,
3771
3753
  type: "day",
3772
3754
  title: formatDate(new Date(viewYear, viewMonth, day), locale, SHORT_DAY_FORMAT),
3773
- autofocus: day === autoFocusDay,
3774
3755
  longTitle: formatDate(new Date(viewYear, viewMonth, day), locale),
3775
3756
  active: this.isActive(day),
3776
3757
  disabled: this.isDisabled(day),
3777
- today: this.isToday(day),
3758
+ today: +getStartOfDay(new Date()) === +new Date(viewYear, viewMonth, day),
3778
3759
  onClick: this.selectDay
3779
3760
  })
3780
3761
  }, dayIndex))
@@ -3875,11 +3856,11 @@ var DayCalendar$1 = injectIntl(DayCalendar);
3875
3856
 
3876
3857
  const ROWS$1 = 3;
3877
3858
  const COLS$1 = 4;
3878
- const MONTH_ONLY_FORMAT = {
3859
+ const MONTH_ONLY_FORMAY = {
3879
3860
  month: 'short'
3880
3861
  };
3881
3862
  const MonthCalendarTable = ({
3882
- selectedDate,
3863
+ selectedDate: selected,
3883
3864
  min,
3884
3865
  max,
3885
3866
  viewYear,
@@ -3889,32 +3870,19 @@ const MonthCalendarTable = ({
3889
3870
  const {
3890
3871
  locale
3891
3872
  } = useIntl();
3892
- const getLink = month => {
3893
- return /*#__PURE__*/jsx(TableLink$1, {
3894
- item: month,
3895
- type: "month",
3896
- title: formatDate(new Date(viewYear, month), locale, MONTH_ONLY_FORMAT),
3897
- active: isSelected(month),
3898
- disabled: isDisabled(month),
3899
- today: viewYear === new Date().getFullYear() && month === new Date().getMonth(),
3900
- autofocus: autofocusMonth === month,
3901
- onClick: onSelect
3902
- });
3903
- };
3904
- const isSelected = month => {
3905
- return selectedDate && month === selectedDate.getMonth() && viewYear === selectedDate.getFullYear();
3906
- };
3907
- const isThisMonth = month => {
3908
- return viewYear === new Date().getFullYear() && month === new Date().getMonth();
3909
- };
3873
+ const getLink = month => /*#__PURE__*/jsx(TableLink$1, {
3874
+ item: month,
3875
+ type: "month",
3876
+ title: formatDate(new Date(viewYear, month), locale, MONTH_ONLY_FORMAY),
3877
+ active: !!(selected && month === selected.getMonth() && viewYear === selected.getFullYear()),
3878
+ disabled: isDisabled(month),
3879
+ today: viewYear === new Date().getFullYear() && month === new Date().getMonth(),
3880
+ onClick: onSelect
3881
+ });
3910
3882
  const isDisabled = month => {
3911
3883
  const date = new Date(viewYear, month);
3912
3884
  return !!(min && date < new Date(min.getFullYear(), min.getMonth()) || max && date > new Date(max.getFullYear(), max.getMonth()));
3913
3885
  };
3914
- const autofocusMonth = (() => {
3915
- const months = [...new Array(ROWS$1 * COLS$1)].map((_, index) => index);
3916
- return getFocusableTime(isSelected, isThisMonth, isDisabled, months);
3917
- })();
3918
3886
  return /*#__PURE__*/jsxs("table", {
3919
3887
  className: "table table-condensed table-bordered tw-date-lookup-calendar np-text-body-default-bold m-b-0",
3920
3888
  children: [/*#__PURE__*/jsx("thead", {
@@ -4033,31 +4001,15 @@ const YearCalendarTable = ({
4033
4001
  locale
4034
4002
  } = useIntl();
4035
4003
  const startYear = viewYear - viewYear % 20;
4036
- const getLink = year => {
4037
- return /*#__PURE__*/jsx(TableLink$1, {
4038
- item: year,
4039
- type: "year",
4040
- title: formatDate(new Date(year, 0), locale, YEAR_ONLY_FORMAT),
4041
- active: !!(selectedDate && year === selectedDate.getFullYear()),
4042
- disabled: isDisabled(year),
4043
- today: year === new Date().getFullYear(),
4044
- autofocus: autofocusYear === year,
4045
- onClick: onSelect
4046
- });
4047
- };
4048
- const isSelected = year => {
4049
- return selectedDate && year === selectedDate.getFullYear();
4050
- };
4051
- const isThisYear = year => {
4052
- return year === new Date().getFullYear();
4053
- };
4054
- const isDisabled = year => {
4055
- return !!(min && year < min.getFullYear() || max && year > max.getFullYear());
4056
- };
4057
- const autofocusYear = (() => {
4058
- const years = [...new Array(ROWS * COLS)].map((_, index) => startYear + index);
4059
- return getFocusableTime(isSelected, isThisYear, isDisabled, years);
4060
- })();
4004
+ const getLink = year => /*#__PURE__*/jsx(TableLink$1, {
4005
+ item: year,
4006
+ type: "year",
4007
+ title: formatDate(new Date(year, 0), locale, YEAR_ONLY_FORMAT),
4008
+ active: !!(selectedDate && year === selectedDate.getFullYear()),
4009
+ disabled: !!(min && year < min.getFullYear() || max && year > max.getFullYear()),
4010
+ today: year === new Date().getFullYear(),
4011
+ onClick: onSelect
4012
+ });
4061
4013
  return /*#__PURE__*/jsxs("table", {
4062
4014
  className: "table table-condensed table-bordered tw-date-lookup-calendar m-b-0",
4063
4015
  children: [/*#__PURE__*/jsx("thead", {
@@ -4164,7 +4116,6 @@ class DateLookup extends PureComponent {
4164
4116
  super(props);
4165
4117
  this.state = {
4166
4118
  selectedDate: getStartOfDay(props.value),
4167
- originalDate: null,
4168
4119
  min: getStartOfDay(props.min),
4169
4120
  max: getStartOfDay(props.max),
4170
4121
  viewMonth: (props.value || new Date()).getMonth(),
@@ -4227,15 +4178,6 @@ class DateLookup extends PureComponent {
4227
4178
  onFocus();
4228
4179
  }
4229
4180
  };
4230
- discard = () => {
4231
- const {
4232
- originalDate
4233
- } = this.state;
4234
- if (originalDate !== null) {
4235
- this.props.onChange(originalDate);
4236
- }
4237
- this.close();
4238
- };
4239
4181
  close = () => {
4240
4182
  const {
4241
4183
  onBlur
@@ -4249,8 +4191,7 @@ class DateLookup extends PureComponent {
4249
4191
  };
4250
4192
  handleKeyDown = event => {
4251
4193
  const {
4252
- open,
4253
- originalDate
4194
+ open
4254
4195
  } = this.state;
4255
4196
  switch (event.keyCode) {
4256
4197
  case KeyCodes.LEFT:
@@ -4286,7 +4227,6 @@ class DateLookup extends PureComponent {
4286
4227
  event.preventDefault();
4287
4228
  break;
4288
4229
  case KeyCodes.ESCAPE:
4289
- originalDate && this.props.onChange(originalDate);
4290
4230
  this.close();
4291
4231
  event.preventDefault();
4292
4232
  break;
@@ -4297,14 +4237,8 @@ class DateLookup extends PureComponent {
4297
4237
  selectedDate,
4298
4238
  min,
4299
4239
  max,
4300
- mode,
4301
- originalDate
4240
+ mode
4302
4241
  } = this.state;
4303
- if (originalDate === null) {
4304
- this.setState({
4305
- originalDate: selectedDate
4306
- });
4307
- }
4308
4242
  let date;
4309
4243
  if (selectedDate) {
4310
4244
  date = new Date(mode === MODE.YEAR ? selectedDate.getFullYear() + yearsToAdd : selectedDate.getFullYear(), mode === MODE.MONTH ? selectedDate.getMonth() + monthsToAdd : selectedDate.getMonth(), mode === MODE.DAY ? selectedDate.getDate() + daysToAdd : selectedDate.getDate());
@@ -4437,7 +4371,7 @@ class DateLookup extends PureComponent {
4437
4371
  open: open,
4438
4372
  className: "tw-date-lookup-menu",
4439
4373
  position: Position.BOTTOM,
4440
- onClose: this.discard,
4374
+ onClose: this.close,
4441
4375
  children: this.getCalendar()
4442
4376
  })]
4443
4377
  });
@@ -7912,6 +7846,10 @@ const getUniqueIdForOption = (parentId = '', option) => {
7912
7846
  const uniqueOptionId = option.value || (option.label?.replace(/\s/g, '') ?? '');
7913
7847
  return `option-${parentId}-${uniqueOptionId}`;
7914
7848
  };
7849
+
7850
+ /**
7851
+ * @deprecated Use `SelectInput` instead (https://neptune.wise.design/blog/2023-11-28-adopting-our-new-selectinput)
7852
+ */
7915
7853
  function Select({
7916
7854
  placeholder,
7917
7855
  id,