@transferwise/components 0.0.0-experimental-3ede9cc → 0.0.0-experimental-a8c8413

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.mjs CHANGED
@@ -2,7 +2,7 @@ import * as React from 'react';
2
2
  import React__default, { forwardRef, useId, cloneElement, useState, useEffect, useRef, useMemo, Component, createContext, useContext, useSyncExternalStore, useCallback, useImperativeHandle, createElement, PureComponent, createRef, isValidElement, Children, Fragment as Fragment$1 } from 'react';
3
3
  import classNames from 'classnames';
4
4
  import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
5
- import { ChevronUp, CrossCircleFill, Cross, Check, Info as Info$1, Alert as Alert$1, ClockBorderless, NavigateAway, Briefcase, Person, ArrowRight, Download, ChevronLeft, ChevronRight, AlertCircleFill, CheckCircleFill, ArrowLeft, QuestionMarkCircle, Search, CrossCircle, ChevronDown, ClockFill, Upload as Upload$2, Document, Plus, PlusCircle, Bin } from '@transferwise/icons';
5
+ import { ChevronUp, CrossCircleFill, Cross, Check, Info as Info$1, Alert as Alert$1, ClockBorderless, NavigateAway, Briefcase, Person, ArrowRight, Download, ChevronLeft, ChevronRight, AlertCircleFill, AlertCircle, ArrowLeft, QuestionMarkCircle, Search, CrossCircle, ChevronDown, CheckCircleFill, ClockFill, Upload as Upload$2, Document, Plus, PlusCircle, Bin } from '@transferwise/icons';
6
6
  import { defineMessages, useIntl, injectIntl, IntlProvider } from 'react-intl';
7
7
  import commonmark from 'commonmark';
8
8
  import { useTheme, ThemeProvider } from '@wise/components-theming';
@@ -3159,8 +3159,10 @@ const DateInput = ({
3159
3159
  return null;
3160
3160
  };
3161
3161
  const [day, setDay] = useState(() => getInitialDate('day'));
3162
+ const [displayDay, setDisplayDay] = useState(day?.toString());
3162
3163
  const [month, setMonth] = useState(() => getInitialDate('month'));
3163
3164
  const [year, setYear] = useState(() => getInitialDate('year'));
3165
+ const [displayYear, setDisplayYear] = useState(year?.toString());
3164
3166
  const [lastBroadcastedValue, setLastBroadcastedValue] = useState(getDateObject);
3165
3167
  const monthNames = getMonthNames(locale, monthFormat);
3166
3168
  dayLabel ||= formatMessage(messages$9.dayLabel);
@@ -3186,8 +3188,8 @@ const DateInput = ({
3186
3188
  const getSelectElement = () => {
3187
3189
  return /*#__PURE__*/jsxs("label", {
3188
3190
  className: "d-flex flex-column",
3189
- children: [/*#__PURE__*/jsx("span", {
3190
- className: "sr-only",
3191
+ children: [/*#__PURE__*/jsx(Body, {
3192
+ type: Typography.BODY_DEFAULT,
3191
3193
  children: monthLabel
3192
3194
  }), /*#__PURE__*/jsx(SelectInput, {
3193
3195
  name: "month",
@@ -3209,12 +3211,23 @@ const DateInput = ({
3209
3211
  })]
3210
3212
  });
3211
3213
  };
3214
+ const isDayValid = (newDay, newMonth, newYear) => {
3215
+ const maxDay = new Date(newYear, newMonth + 1, 0).getDate();
3216
+ return newDay <= maxDay;
3217
+ };
3212
3218
  const handleInternalValue = (newDay = day, newMonth = month, newYear = year) => {
3213
- if (newDay == null || newMonth == null || newYear == null) {
3219
+ if (newDay == null || newDay === 0 || newMonth == null || newYear == null || newYear === 0) {
3220
+ broadcastNewValue(null);
3221
+ return;
3222
+ }
3223
+ if (!isDayValid(newDay, newMonth, newYear)) {
3214
3224
  broadcastNewValue(null);
3215
3225
  return;
3216
3226
  }
3217
3227
  const dateValue = new Date(newYear, newMonth, newDay);
3228
+ if (newYear < 100) {
3229
+ dateValue.setFullYear(newYear);
3230
+ }
3218
3231
  if (!isDateValid(dateValue)) {
3219
3232
  broadcastNewValue(null);
3220
3233
  return;
@@ -3228,11 +3241,11 @@ const DateInput = ({
3228
3241
  }
3229
3242
  };
3230
3243
  const handleDayChange = event => {
3231
- const {
3232
- checkedDay
3233
- } = checkDate(Number.parseInt(event.target.value, 10), month, year);
3234
- setDay(checkedDay);
3235
- handleInternalValue(checkedDay, month, year);
3244
+ const newDayString = event.target.value.replace(/\D/g, '');
3245
+ const newDayNumber = Number.parseInt(newDayString, 10);
3246
+ setDay(newDayNumber);
3247
+ setDisplayDay(newDayString);
3248
+ handleInternalValue(newDayNumber, month, year);
3236
3249
  };
3237
3250
  const handleMonthChange = selectedMonth => {
3238
3251
  if (selectedMonth === null) {
@@ -3240,30 +3253,19 @@ const DateInput = ({
3240
3253
  handleInternalValue(day, null, year);
3241
3254
  return;
3242
3255
  }
3243
- const {
3244
- checkedDay
3245
- } = checkDate(day, selectedMonth, year);
3246
3256
  setMonth(selectedMonth);
3247
- if (day && checkedDay !== day) {
3248
- setDay(checkedDay);
3249
- }
3250
- handleInternalValue(checkedDay, selectedMonth, year);
3257
+ handleInternalValue(day, selectedMonth, year);
3251
3258
  };
3252
3259
  const handleYearChange = event => {
3253
- const newValue = event.target.value;
3254
- const slicedYear = newValue.length > 4 ? newValue.slice(0, 4) : newValue;
3255
- if (slicedYear.toString().length === 4) {
3256
- // Correct day based on year and month.
3257
- const {
3258
- checkedDay
3259
- } = checkDate(day, month, Number.parseInt(newValue, 10));
3260
- if (day && checkedDay !== day) {
3261
- setDay(checkedDay);
3262
- }
3263
- setYear(Number.parseInt(slicedYear, 10));
3264
- handleInternalValue(checkedDay, month, Number.parseInt(slicedYear, 10));
3260
+ const newYearString = event.target.value.replace(/\D/g, '');
3261
+ const newYearNumber = Number.parseInt(newYearString, 10);
3262
+ if (newYearString.length >= 4 && newYearString.length <= 6) {
3263
+ setYear(newYearNumber);
3264
+ setDisplayYear(newYearString);
3265
+ handleInternalValue(day, month, newYearNumber);
3265
3266
  } else {
3266
- setYear(Number.parseInt(slicedYear, 10));
3267
+ setYear(null);
3268
+ setDisplayYear(newYearString);
3267
3269
  handleInternalValue(day, month, null);
3268
3270
  }
3269
3271
  };
@@ -3273,24 +3275,6 @@ const DateInput = ({
3273
3275
  onChange(newValue != null ? getDateAsString(newValue) : null);
3274
3276
  }
3275
3277
  };
3276
- const checkDate = (newDay = null, newMonth = 0, newYear = null) => {
3277
- let checkedDay = newDay;
3278
- const maxDay = new Date(newYear || 2000, newMonth != null ? newMonth + 1 : 1, 0).getDate();
3279
- if (!newDay) {
3280
- checkedDay = null;
3281
- }
3282
- if (newDay && newDay < 0) {
3283
- checkedDay = 1;
3284
- }
3285
- if (newDay && newMonth || newDay && newDay > 31) {
3286
- checkedDay = newDay > maxDay ? maxDay : newDay;
3287
- }
3288
- return {
3289
- checkedDay,
3290
- checkedMonth: newMonth,
3291
- checkedYear: newYear
3292
- };
3293
- };
3294
3278
  const monthYearOnly = mode === DateMode.MONTH_YEAR;
3295
3279
  const monthWidth = classNames({
3296
3280
  'col-sm-8': monthYearOnly,
@@ -3306,8 +3290,8 @@ const DateInput = ({
3306
3290
  return /*#__PURE__*/jsx("div", {
3307
3291
  className: "col-sm-3",
3308
3292
  children: /*#__PURE__*/jsxs("label", {
3309
- children: [/*#__PURE__*/jsx("span", {
3310
- className: "sr-only",
3293
+ children: [/*#__PURE__*/jsx(Body, {
3294
+ type: Typography.BODY_DEFAULT,
3311
3295
  children: dayLabel
3312
3296
  }), /*#__PURE__*/jsx("div", {
3313
3297
  className: `input-group input-group-${size}`,
@@ -3317,10 +3301,12 @@ const DateInput = ({
3317
3301
  pattern: "[0-9]*",
3318
3302
  name: "day",
3319
3303
  autoComplete: dayAutoComplete,
3320
- value: day || '',
3304
+ value: displayDay || '',
3321
3305
  placeholder: placeholders?.day,
3322
3306
  disabled: disabled,
3323
3307
  min: 1,
3308
+ max: 31,
3309
+ maxLength: 2,
3324
3310
  onChange: event => handleDayChange(event)
3325
3311
  })
3326
3312
  })]
@@ -3331,8 +3317,8 @@ const DateInput = ({
3331
3317
  return /*#__PURE__*/jsx("div", {
3332
3318
  className: "col-sm-4",
3333
3319
  children: /*#__PURE__*/jsxs("label", {
3334
- children: [/*#__PURE__*/jsx("span", {
3335
- className: "sr-only",
3320
+ children: [/*#__PURE__*/jsx(Body, {
3321
+ type: Typography.BODY_DEFAULT,
3336
3322
  children: yearLabel
3337
3323
  }), /*#__PURE__*/jsx("div", {
3338
3324
  className: `input-group input-group-${size}`,
@@ -3343,9 +3329,11 @@ const DateInput = ({
3343
3329
  name: "year",
3344
3330
  autoComplete: yearAutoComplete,
3345
3331
  placeholder: placeholders?.year,
3346
- value: year || '',
3332
+ value: displayYear || '',
3347
3333
  disabled: disabled,
3348
- min: 1,
3334
+ min: 0,
3335
+ max: 9999,
3336
+ maxLength: 6,
3349
3337
  onChange: event => handleYearChange(event)
3350
3338
  })
3351
3339
  })]
@@ -4849,42 +4837,12 @@ function InlineAlert({
4849
4837
  className,
4850
4838
  children
4851
4839
  }) {
4852
- const getStatusIcon = sentiment => {
4853
- switch (sentiment) {
4854
- case Sentiment.POSITIVE:
4855
- case Sentiment.SUCCESS:
4856
- return /*#__PURE__*/jsx(CheckCircleFill, {});
4857
- case Sentiment.WARNING:
4858
- return /*#__PURE__*/jsx(AlertCircleFill, {});
4859
- case Sentiment.NEGATIVE:
4860
- case Sentiment.ERROR:
4861
- return /*#__PURE__*/jsx(CrossCircleFill, {});
4862
- default:
4863
- return null;
4864
- }
4865
- };
4866
- const hasTextChildren = content => {
4867
- let label = '';
4868
- const fillLabel = childrenNodes => {
4869
- React__default.Children.map(childrenNodes, child => {
4870
- if (typeof child === 'string') {
4871
- label += child;
4872
- }
4873
- if (typeof child === 'object' && /*#__PURE__*/React__default.isValidElement(child)) {
4874
- // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access
4875
- fillLabel(child?.props?.children);
4876
- }
4877
- });
4878
- };
4879
- fillLabel(content);
4880
- return !!label.length;
4881
- };
4840
+ const danger = type === 'negative' || type === 'error';
4882
4841
  return /*#__PURE__*/jsxs("div", {
4883
4842
  role: "alert",
4884
4843
  id: id,
4885
- className: classNames('alert alert-detach', `alert-${[Sentiment.NEGATIVE, Sentiment.ERROR].includes(type) ? 'danger' : type}`, className),
4886
- children: [hasTextChildren(children) && getStatusIcon(type), /*#__PURE__*/jsx("div", {
4887
- className: "np-text-body-default",
4844
+ className: classNames('alert alert-detach', `alert-${danger ? 'danger' : type}`, className),
4845
+ children: [danger && /*#__PURE__*/jsx(AlertCircle, {}), /*#__PURE__*/jsx("div", {
4888
4846
  children: children
4889
4847
  })]
4890
4848
  });
@@ -4899,7 +4857,7 @@ const Label = ({
4899
4857
  return /*#__PURE__*/jsx("label", {
4900
4858
  id: id,
4901
4859
  htmlFor: htmlFor,
4902
- className: classNames('control-label d-flex flex-column gap-y-xs m-b-0', className),
4860
+ className: classNames('control-label d-flex flex-column gap-y-1 m-b-0', className),
4903
4861
  children: children
4904
4862
  });
4905
4863
  };
@@ -4907,15 +4865,13 @@ const Label = ({
4907
4865
  const Field = ({
4908
4866
  id,
4909
4867
  label,
4910
- message: propMessage,
4911
- type: propType,
4868
+ hint,
4869
+ error,
4912
4870
  className,
4913
- children,
4914
- ...props
4871
+ children
4915
4872
  }) => {
4916
- const type = props.error ? Sentiment.NEGATIVE : propType;
4917
- const message = props.error || props.hint || propMessage;
4918
- const hasError = type === Sentiment.NEGATIVE;
4873
+ const hasError = Boolean(error);
4874
+ const hasHint = Boolean(hint) && !hasError;
4919
4875
  const labelId = useId();
4920
4876
  const fallbackInputId = useId();
4921
4877
  const inputId = id !== null ? id ?? fallbackInputId : undefined;
@@ -4925,24 +4881,26 @@ const Field = ({
4925
4881
  children: /*#__PURE__*/jsx(InputIdContextProvider, {
4926
4882
  value: inputId,
4927
4883
  children: /*#__PURE__*/jsx(InputDescribedByProvider, {
4928
- value: message ? descriptionId : undefined,
4884
+ value: hasError || hasHint ? descriptionId : undefined,
4929
4885
  children: /*#__PURE__*/jsx(InputInvalidProvider, {
4930
4886
  value: hasError,
4931
4887
  children: /*#__PURE__*/jsxs("div", {
4932
4888
  className: classNames('form-group d-block', {
4933
- 'has-success': type === Sentiment.POSITIVE,
4934
- 'has-warning': type === Sentiment.WARNING,
4935
4889
  'has-error': hasError,
4936
- 'has-info': type === Sentiment.NEUTRAL
4890
+ 'has-info': hasHint
4937
4891
  }, className),
4938
4892
  children: [/*#__PURE__*/jsxs(Label, {
4939
4893
  id: labelId,
4940
4894
  htmlFor: inputId,
4941
4895
  children: [label, children]
4942
- }), message && /*#__PURE__*/jsx(InlineAlert, {
4943
- type: type,
4896
+ }), hasHint && /*#__PURE__*/jsx(InlineAlert, {
4897
+ type: Sentiment.NEUTRAL,
4944
4898
  id: descriptionId,
4945
- children: message
4899
+ children: hint
4900
+ }), hasError && /*#__PURE__*/jsx(InlineAlert, {
4901
+ type: Sentiment.NEGATIVE,
4902
+ id: descriptionId,
4903
+ children: error
4946
4904
  })]
4947
4905
  })
4948
4906
  })