@transferwise/components 46.7.0 → 46.9.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.
Files changed (50) hide show
  1. package/build/index.esm.js +154 -76
  2. package/build/index.esm.js.map +1 -1
  3. package/build/index.js +155 -76
  4. package/build/index.js.map +1 -1
  5. package/build/main.css +101 -0
  6. package/build/styles/main.css +101 -0
  7. package/build/styles/segmentedControl/SegmentedControl.css +101 -0
  8. package/build/types/checkboxOption/CheckboxOption.d.ts +2 -2
  9. package/build/types/checkboxOption/CheckboxOption.d.ts.map +1 -1
  10. package/build/types/index.d.ts +4 -0
  11. package/build/types/index.d.ts.map +1 -1
  12. package/build/types/segmentedControl/SegmentedControl.d.ts +31 -0
  13. package/build/types/segmentedControl/SegmentedControl.d.ts.map +1 -0
  14. package/build/types/segmentedControl/index.d.ts +3 -0
  15. package/build/types/segmentedControl/index.d.ts.map +1 -0
  16. package/build/types/snackbar/Snackbar.d.ts +30 -22
  17. package/build/types/snackbar/Snackbar.d.ts.map +1 -1
  18. package/build/types/snackbar/SnackbarContext.d.ts +7 -2
  19. package/build/types/snackbar/SnackbarContext.d.ts.map +1 -1
  20. package/build/types/snackbar/SnackbarProvider.d.ts +7 -12
  21. package/build/types/snackbar/SnackbarProvider.d.ts.map +1 -1
  22. package/build/types/snackbar/index.d.ts +2 -0
  23. package/build/types/snackbar/index.d.ts.map +1 -0
  24. package/build/types/snackbar/useSnackbar.d.ts +1 -1
  25. package/build/types/snackbar/useSnackbar.d.ts.map +1 -1
  26. package/build/types/withNextPortal/withNextPortal.d.ts +1 -1
  27. package/build/types/withNextPortal/withNextPortal.d.ts.map +1 -1
  28. package/package.json +9 -18
  29. package/src/checkboxOption/CheckboxOption.tsx +2 -2
  30. package/src/index.ts +4 -0
  31. package/src/main.css +101 -0
  32. package/src/main.less +1 -0
  33. package/src/segmentedControl/SegmentedControl.css +101 -0
  34. package/src/segmentedControl/SegmentedControl.less +101 -0
  35. package/src/segmentedControl/SegmentedControl.spec.tsx +106 -0
  36. package/src/segmentedControl/SegmentedControl.story.tsx +55 -0
  37. package/src/segmentedControl/SegmentedControl.tsx +175 -0
  38. package/src/segmentedControl/index.ts +2 -0
  39. package/src/snackbar/{Snackbar.story.js → Snackbar.story.tsx} +2 -1
  40. package/src/snackbar/{Snackbar.js → Snackbar.tsx} +31 -32
  41. package/src/snackbar/SnackbarContext.ts +11 -0
  42. package/src/snackbar/SnackbarProvider.tsx +39 -0
  43. package/src/ssr.spec.js +17 -0
  44. package/src/withDisplayFormat/WithDisplayFormat.spec.js +1 -1
  45. package/src/withDisplayFormat/WithDisplayFormat.tsx +1 -1
  46. package/src/withNextPortal/withNextPortal.tsx +1 -1
  47. package/src/snackbar/SnackbarContext.js +0 -4
  48. package/src/snackbar/SnackbarProvider.js +0 -51
  49. /package/src/snackbar/{index.js → index.ts} +0 -0
  50. /package/src/snackbar/{useSnackbar.js → useSnackbar.ts} +0 -0
@@ -2578,7 +2578,7 @@ const CheckboxOption = /*#__PURE__*/forwardRef(({
2578
2578
  button: /*#__PURE__*/jsx(CheckboxButton$1, {
2579
2579
  checked: checked,
2580
2580
  disabled: disabled,
2581
- onChange: () => onChange(!checked)
2581
+ onChange: () => onChange?.(!checked)
2582
2582
  })
2583
2583
  });
2584
2584
  });
@@ -7510,7 +7510,7 @@ class WithDisplayFormat extends Component {
7510
7510
  const cursorPosition = getCursorPositionAfterKeystroke(action, selectionStart, selectionEnd, displayPattern, pastedLength);
7511
7511
  setTimeout(() => {
7512
7512
  if (triggerEvent) {
7513
- triggerEvent.currentTarget.setSelectionRange(cursorPosition, cursorPosition);
7513
+ triggerEvent.target.setSelectionRange(cursorPosition, cursorPosition);
7514
7514
  }
7515
7515
  this.setState({
7516
7516
  selectionStart: cursorPosition,
@@ -9879,7 +9879,6 @@ const PromoCard = /*#__PURE__*/forwardRef(({
9879
9879
  setChecked(!checked); // Update local state for checkbox
9880
9880
  }
9881
9881
  };
9882
-
9883
9882
  const componentId = `${id || generateRandomId()}`;
9884
9883
  // Set the icon to `'arrow'` if `href` is truthy and `type` is falsy, or
9885
9884
  // `'download'` if `download` is truthy. If neither condition is true, set
@@ -11043,20 +11042,124 @@ Select.defaultProps = {
11043
11042
  dropdownProps: {}
11044
11043
  };
11045
11044
 
11045
+ const SegmentedControl = ({
11046
+ name,
11047
+ defaultValue,
11048
+ mode = 'input',
11049
+ segments,
11050
+ onChange
11051
+ }) => {
11052
+ const [selectedValue, setSelectedValue] = useState(defaultValue || segments[0].value);
11053
+ const [animate, setAnimate] = useState(false);
11054
+ const segmentsRef = useRef(null);
11055
+ if (segments.length > 3) {
11056
+ throw new Error('SegmentedControl only supports up to 3 segments. Please refer to: https://wise.design/components/segmented-control');
11057
+ }
11058
+ const segmentsWithRefs = segments.map(segment => ({
11059
+ ...segment,
11060
+ ref: /*#__PURE__*/createRef()
11061
+ }));
11062
+ const updateSegmentPosition = () => {
11063
+ const selectedSegmentRef = segmentsWithRefs.find(segment => segment.value === selectedValue)?.ref;
11064
+ // We grab the active segments style object from the ref
11065
+ // and set the css variables to the selected segments width and x position.
11066
+ // This is so we can animate the highlight to the selected segment
11067
+ if (selectedSegmentRef?.current && segmentsRef.current) {
11068
+ const {
11069
+ style
11070
+ } = segmentsRef.current;
11071
+ style.setProperty('--segment-highlight-width', `${selectedSegmentRef.current.offsetWidth}px`);
11072
+ style.setProperty('--segment-highlight-x', `${selectedSegmentRef.current.offsetLeft}px`);
11073
+ }
11074
+ };
11075
+ useEffect(() => {
11076
+ updateSegmentPosition();
11077
+ const handleWindowSizeChange = () => {
11078
+ setAnimate(false);
11079
+ updateSegmentPosition();
11080
+ };
11081
+ window.addEventListener('resize', handleWindowSizeChange);
11082
+ return () => {
11083
+ window.removeEventListener('resize', handleWindowSizeChange);
11084
+ };
11085
+ // eslint-disable-next-line react-hooks/exhaustive-deps
11086
+ }, [segmentsWithRefs, selectedValue]);
11087
+ useEffect(() => {
11088
+ onChange(selectedValue);
11089
+ }, [onChange, selectedValue]);
11090
+ return /*#__PURE__*/jsx("div", {
11091
+ ref: segmentsRef,
11092
+ "data-testid": "segmented-control",
11093
+ className: classNames('segmented-control', {
11094
+ 'segmented-control--input': mode === 'input'
11095
+ }),
11096
+ children: /*#__PURE__*/jsx("div", {
11097
+ className: classNames('segmented-control__segments', {
11098
+ 'segmented-control__segments--no-animate': !animate
11099
+ }),
11100
+ children: segmentsWithRefs.map(segment => mode === 'input' ? /*#__PURE__*/jsxs("label", {
11101
+ ref: segment.ref,
11102
+ htmlFor: segment.id,
11103
+ className: classNames('segmented-control__segment', {
11104
+ 'segmented-control__selected-segment': selectedValue === segment.value
11105
+ }),
11106
+ children: [/*#__PURE__*/jsx("input", {
11107
+ type: "radio",
11108
+ className: "segmented-control__radio-input",
11109
+ id: segment.id,
11110
+ name: name,
11111
+ value: segment.value,
11112
+ checked: selectedValue === segment.value,
11113
+ onChange: () => {
11114
+ setAnimate(true);
11115
+ setSelectedValue(segment.value);
11116
+ }
11117
+ }), /*#__PURE__*/jsx(Body, {
11118
+ className: "segmented-control__text",
11119
+ as: "span",
11120
+ type: selectedValue === segment.value ? Typography.BODY_DEFAULT_BOLD : Typography.BODY_DEFAULT,
11121
+ children: segment.label
11122
+ })]
11123
+ }, segment.id) : /*#__PURE__*/jsx("button", {
11124
+ ref: segment.ref,
11125
+ type: "button",
11126
+ role: "tab",
11127
+ id: segment.id,
11128
+ "aria-controls": segment.controls,
11129
+ "aria-selected": selectedValue === segment.value,
11130
+ className: classNames('segmented-control__segment', 'segmented-control__button', {
11131
+ 'segmented-control__selected-segment': selectedValue === segment.value
11132
+ }),
11133
+ onClick: () => {
11134
+ setAnimate(true);
11135
+ setSelectedValue(segment.value);
11136
+ },
11137
+ children: /*#__PURE__*/jsx(Body, {
11138
+ as: "span",
11139
+ className: "segmented-control__text",
11140
+ type: selectedValue === segment.value ? Typography.BODY_DEFAULT_BOLD : Typography.BODY_DEFAULT,
11141
+ children: segment.label
11142
+ })
11143
+ }, segment.id))
11144
+ })
11145
+ });
11146
+ };
11147
+
11046
11148
  const CSS_TRANSITION_DURATION = 400;
11047
11149
  class Snackbar extends Component {
11048
- /** @type {RefObject<HTMLSpanElement>} */
11049
11150
  bodyRef = /*#__PURE__*/createRef();
11050
- constructor() {
11051
- super();
11151
+ timeout = 0;
11152
+ transitionTimeout = 0;
11153
+ constructor(props) {
11154
+ super(props);
11052
11155
  this.state = {
11053
11156
  visible: false,
11054
11157
  text: ''
11055
11158
  };
11056
11159
  }
11057
11160
  componentWillUnmount() {
11058
- clearTimeout(this.timeout);
11059
- clearTimeout(this.transitionTimeout);
11161
+ window.clearTimeout(this.timeout);
11162
+ window.clearTimeout(this.transitionTimeout);
11060
11163
  }
11061
11164
  shouldComponentUpdate(nextProps, nextState) {
11062
11165
  if (!nextProps.text) {
@@ -11071,7 +11174,7 @@ class Snackbar extends Component {
11071
11174
  const {
11072
11175
  timeout
11073
11176
  } = this.props;
11074
- this.timeout = setTimeout(() => {
11177
+ this.timeout = window.setTimeout(() => {
11075
11178
  this.setState({
11076
11179
  visible: false
11077
11180
  });
@@ -11094,12 +11197,12 @@ class Snackbar extends Component {
11094
11197
  this.setLeaveTimeout();
11095
11198
  });
11096
11199
  } else if (previousProps.timestamp !== timestamp) {
11097
- clearTimeout(this.timeout);
11200
+ window.clearTimeout(this.timeout);
11098
11201
  if (this.state.visible) {
11099
11202
  this.setState({
11100
11203
  visible: false
11101
11204
  }, () => {
11102
- this.transitionTimeout = setTimeout(() => {
11205
+ this.transitionTimeout = window.setTimeout(() => {
11103
11206
  this.setState({
11104
11207
  visible: true,
11105
11208
  action,
@@ -11124,7 +11227,7 @@ class Snackbar extends Component {
11124
11227
  const {
11125
11228
  action,
11126
11229
  text,
11127
- theme,
11230
+ theme = Theme.LIGHT,
11128
11231
  visible
11129
11232
  } = this.state;
11130
11233
  const {
@@ -11158,74 +11261,51 @@ class Snackbar extends Component {
11158
11261
  }
11159
11262
  }
11160
11263
  Snackbar.contextType = DirectionContext;
11161
- Snackbar.propTypes = {
11162
- action: PropTypes.shape({
11163
- label: PropTypes.string.isRequired,
11164
- onClick: PropTypes.func
11165
- }),
11166
- text: PropTypes.node.isRequired,
11167
- theme: PropTypes.oneOf(['light', 'dark']),
11168
- timeout: PropTypes.number.isRequired,
11169
- timestamp: PropTypes.number.isRequired
11170
- };
11171
- Snackbar.defaultProps = {
11172
- action: null,
11173
- theme: Theme.LIGHT
11174
- };
11175
11264
  var SnackbarPortal = withNextPortalWrapper(Snackbar);
11176
11265
 
11177
- const SnackbarContext = /*#__PURE__*/createContext();
11266
+ const SnackbarContext = /*#__PURE__*/createContext({
11267
+ createSnackbar: () => {}
11268
+ });
11178
11269
  const SnackbarConsumer = SnackbarContext.Consumer;
11179
11270
 
11180
- class SnackbarProvider extends Component {
11181
- constructor() {
11182
- super();
11183
- this.state = {
11184
- text: '',
11185
- timestamp: 0
11186
- };
11187
- }
11188
- create = ({
11271
+ function SnackbarProvider({
11272
+ timeout = 4500,
11273
+ children
11274
+ }) {
11275
+ const [state, setState] = useState({
11276
+ text: '',
11277
+ timestamp: 0
11278
+ });
11279
+ const {
11189
11280
  action,
11190
11281
  text,
11191
- theme
11192
- }) => {
11193
- this.setState({
11194
- action,
11195
- text,
11196
- theme,
11197
- timestamp: Date.now()
11198
- });
11199
- };
11200
- render() {
11201
- const {
11202
- action,
11203
- text,
11204
- theme,
11205
- timestamp
11206
- } = this.state;
11207
- return /*#__PURE__*/jsxs(SnackbarContext.Provider, {
11208
- value: {
11209
- createSnackbar: this.create
11210
- },
11211
- children: [/*#__PURE__*/jsx(SnackbarPortal, {
11212
- action: action,
11213
- text: text,
11214
- timestamp: timestamp,
11215
- timeout: this.props.timeout,
11216
- theme: theme
11217
- }), this.props.children]
11218
- });
11219
- }
11282
+ theme,
11283
+ timestamp
11284
+ } = state;
11285
+ return /*#__PURE__*/jsxs(SnackbarContext.Provider, {
11286
+ value: useMemo(() => ({
11287
+ createSnackbar: ({
11288
+ action,
11289
+ text,
11290
+ theme
11291
+ }) => {
11292
+ setState({
11293
+ action,
11294
+ text,
11295
+ theme,
11296
+ timestamp: Date.now()
11297
+ });
11298
+ }
11299
+ }), []),
11300
+ children: [/*#__PURE__*/jsx(SnackbarPortal, {
11301
+ action: action,
11302
+ text: text,
11303
+ timestamp: timestamp,
11304
+ timeout: timeout,
11305
+ theme: theme
11306
+ }), children]
11307
+ });
11220
11308
  }
11221
- SnackbarProvider.propTypes = {
11222
- children: PropTypes.node.isRequired,
11223
- timeout: PropTypes.number
11224
- };
11225
- SnackbarProvider.defaultProps = {
11226
- timeout: 4500
11227
- };
11228
- var SnackbarProvider$1 = SnackbarProvider;
11229
11309
 
11230
11310
  const Sticky = ({
11231
11311
  open,
@@ -13827,7 +13907,6 @@ const UploadButton = ({
13827
13907
  if (areAllFilesAllowed) {
13828
13908
  return null; //file input by default allows all files
13829
13909
  }
13830
-
13831
13910
  if (Array.isArray(fileTypes)) {
13832
13911
  return {
13833
13912
  accept: fileTypes.join(',')
@@ -14025,7 +14104,6 @@ const UploadItem = ({
14025
14104
  children: processIndicator
14026
14105
  }); // Scale down ProcessIndicator to be 20px*20px to match `icons`
14027
14106
  };
14028
-
14029
14107
  const getErrorMessage = () => typeof error === 'object' && error.message || error || formatMessage(MESSAGES.uploadingFailed);
14030
14108
  const getDescription = () => {
14031
14109
  if (error || status === Status.FAILED) {
@@ -15441,5 +15519,5 @@ const translations = {
15441
15519
  'zh-HK': zhHK
15442
15520
  };
15443
15521
 
15444
- export { Accordion, ActionButton, ActionOption, Alert$1 as Alert, ArrowPosition as AlertArrowPosition, Avatar, AvatarType, AvatarWrapper, Badge, Card as BaseCard, Body, BottomSheet$2 as BottomSheet, Breakpoint, Button, Card$2 as Card, Checkbox$1 as Checkbox, CheckboxButton$1 as CheckboxButton, CheckboxOption, Chevron, Chip, Chips, CircularButton$1 as CircularButton, ControlType, CriticalCommsBanner, DEFAULT_LANG, DEFAULT_LOCALE, DateInput$1 as DateInput, DateLookup$1 as DateLookup, DateMode, Decision$1 as Decision, Presentation as DecisionPresentation, Type as DecisionType, DefinitionList$1 as DefinitionList, Dimmer$1 as Dimmer, Direction, DirectionProvider, Display, Drawer$1 as Drawer, DropFade, DynamicFieldDefinitionList$1 as DynamicFieldDefinitionList, Emphasis, FileType, FlowNavigation, Header, Image, Info, InfoPresentation, InlineAlert, Input, InputGroup, InputWithDisplayFormat, InstructionsList$1 as InstructionsList, LanguageProvider, Layout$1 as Layout, Link, ListItem$1 as ListItem, Loader$1 as Loader, Logo$1 as Logo, LogoType, Markdown$1 as Markdown, MarkdownNodeType, Modal, Money$1 as Money, MoneyInput$1 as MoneyInput, MonthFormat, NavigationOption, NavigationOptionList$1 as NavigationOptionsList, Nudge, Option$2 as Option, OverlayHeader$1 as OverlayHeader, PhoneNumberInput, Popover$2 as Popover, Position, Priority, ProcessIndicator$1 as ProcessIndicator, ProfileType, Progress, ProgressBar, PromoCard$1 as PromoCard, PromoCard$1 as PromoCardGroup, Provider$1 as Provider, RTL_LANGUAGES, Radio$1 as Radio, RadioGroup$1 as RadioGroup, RadioOption$1 as RadioOption, SUPPORTED_LANGUAGES, Scroll, SearchInput, Section, Select, SelectInput, SelectInputOptionContent, SelectInputTriggerButton, Sentiment, Size, SlidingPanel$1 as SlidingPanel, SnackbarConsumer, SnackbarContext, SnackbarPortal, SnackbarProvider$1 as SnackbarProvider, Status, StatusIcon, Stepper, Sticky$1 as Sticky, Summary, Switch, SwitchOption, Tabs$1 as Tabs, TextArea, TextareaWithDisplayFormat, Theme, Title, Tooltip$1 as Tooltip, Type$1 as Type, Typeahead, Typography, Upload$1 as Upload, UploadInput, UploadStep, Variant, Width, adjustLocale, getCountryFromLocale, getDirectionFromLocale, getLangFromLocale, isBrowser, isServerSide, translations, useDirection, useLayout, useScreenSize, useSnackbar };
15522
+ export { Accordion, ActionButton, ActionOption, Alert$1 as Alert, ArrowPosition as AlertArrowPosition, Avatar, AvatarType, AvatarWrapper, Badge, Card as BaseCard, Body, BottomSheet$2 as BottomSheet, Breakpoint, Button, Card$2 as Card, Checkbox$1 as Checkbox, CheckboxButton$1 as CheckboxButton, CheckboxOption, Chevron, Chip, Chips, CircularButton$1 as CircularButton, ControlType, CriticalCommsBanner, DEFAULT_LANG, DEFAULT_LOCALE, DateInput$1 as DateInput, DateLookup$1 as DateLookup, DateMode, Decision$1 as Decision, Presentation as DecisionPresentation, Type as DecisionType, DefinitionList$1 as DefinitionList, Dimmer$1 as Dimmer, Direction, DirectionProvider, Display, Drawer$1 as Drawer, DropFade, DynamicFieldDefinitionList$1 as DynamicFieldDefinitionList, Emphasis, FileType, FlowNavigation, Header, Image, Info, InfoPresentation, InlineAlert, Input, InputGroup, InputWithDisplayFormat, InstructionsList$1 as InstructionsList, LanguageProvider, Layout$1 as Layout, Link, ListItem$1 as ListItem, Loader$1 as Loader, Logo$1 as Logo, LogoType, Markdown$1 as Markdown, MarkdownNodeType, Modal, Money$1 as Money, MoneyInput$1 as MoneyInput, MonthFormat, NavigationOption, NavigationOptionList$1 as NavigationOptionsList, Nudge, Option$2 as Option, OverlayHeader$1 as OverlayHeader, PhoneNumberInput, Popover$2 as Popover, Position, Priority, ProcessIndicator$1 as ProcessIndicator, ProfileType, Progress, ProgressBar, PromoCard$1 as PromoCard, PromoCard$1 as PromoCardGroup, Provider$1 as Provider, RTL_LANGUAGES, Radio$1 as Radio, RadioGroup$1 as RadioGroup, RadioOption$1 as RadioOption, SUPPORTED_LANGUAGES, Scroll, SearchInput, Section, SegmentedControl, Select, SelectInput, SelectInputOptionContent, SelectInputTriggerButton, Sentiment, Size, SlidingPanel$1 as SlidingPanel, SnackbarConsumer, SnackbarContext, SnackbarPortal, SnackbarProvider, Status, StatusIcon, Stepper, Sticky$1 as Sticky, Summary, Switch, SwitchOption, Tabs$1 as Tabs, TextArea, TextareaWithDisplayFormat, Theme, Title, Tooltip$1 as Tooltip, Type$1 as Type, Typeahead, Typography, Upload$1 as Upload, UploadInput, UploadStep, Variant, Width, adjustLocale, getCountryFromLocale, getDirectionFromLocale, getLangFromLocale, isBrowser, isServerSide, translations, useDirection, useLayout, useScreenSize, useSnackbar };
15445
15523
  //# sourceMappingURL=index.esm.js.map