@transferwise/components 0.0.0-experimental-7a528f1 → 0.0.0-experimental-3f857d7

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 (36) hide show
  1. package/build/index.esm.js +167 -72
  2. package/build/index.esm.js.map +1 -1
  3. package/build/index.js +167 -71
  4. package/build/index.js.map +1 -1
  5. package/build/main.css +103 -6
  6. package/build/styles/inputs/SelectInput.css +1 -6
  7. package/build/styles/main.css +103 -6
  8. package/build/styles/segmentedControl/SegmentedControl.css +102 -0
  9. package/build/types/index.d.ts +1 -0
  10. package/build/types/index.d.ts.map +1 -1
  11. package/build/types/inputs/SelectInput.d.ts +5 -6
  12. package/build/types/inputs/SelectInput.d.ts.map +1 -1
  13. package/build/types/segmentedControl/SegmentedControl.d.ts +31 -0
  14. package/build/types/segmentedControl/SegmentedControl.d.ts.map +1 -0
  15. package/build/types/segmentedControl/index.d.ts +3 -0
  16. package/build/types/segmentedControl/index.d.ts.map +1 -0
  17. package/build/types/utilities/wrapInFragment.d.ts +3 -0
  18. package/build/types/utilities/wrapInFragment.d.ts.map +1 -0
  19. package/package.json +3 -3
  20. package/src/index.ts +1 -0
  21. package/src/inputs/SelectInput.css +1 -6
  22. package/src/inputs/SelectInput.less +1 -8
  23. package/src/inputs/SelectInput.spec.tsx +0 -26
  24. package/src/inputs/SelectInput.story.tsx +1 -73
  25. package/src/inputs/SelectInput.tsx +85 -104
  26. package/src/main.css +103 -6
  27. package/src/main.less +1 -0
  28. package/src/segmentedControl/SegmentedControl.css +102 -0
  29. package/src/segmentedControl/SegmentedControl.less +102 -0
  30. package/src/segmentedControl/SegmentedControl.spec.tsx +107 -0
  31. package/src/segmentedControl/SegmentedControl.story.tsx +55 -0
  32. package/src/segmentedControl/SegmentedControl.tsx +150 -0
  33. package/src/segmentedControl/__snapshots__/SegmentedControl.spec.tsx.snap +113 -0
  34. package/src/segmentedControl/index.ts +2 -0
  35. package/src/ssr.spec.js +17 -0
  36. package/src/utilities/wrapInFragment.tsx +3 -0
@@ -6454,6 +6454,12 @@ const PolymorphicWithOverrides = /*#__PURE__*/forwardRef(function PolymorphicWit
6454
6454
  });
6455
6455
  });
6456
6456
 
6457
+ function wrapInFragment(value) {
6458
+ return /*#__PURE__*/jsx(Fragment, {
6459
+ children: value
6460
+ });
6461
+ }
6462
+
6457
6463
  var messages$4 = defineMessages({
6458
6464
  noResultsFound: {
6459
6465
  id: "neptune.SelectInput.noResultsFound"
@@ -6794,10 +6800,10 @@ const defaultRenderTrigger = ({
6794
6800
  children: /*#__PURE__*/jsx(SelectInputTriggerButton, {
6795
6801
  as: ButtonInput,
6796
6802
  size: size,
6797
- children: /*#__PURE__*/jsx("span", {
6798
- className: classNames('np-select-input-content', placeholderShown && 'np-select-input-placeholder'),
6799
- children: content
6800
- })
6803
+ children: placeholderShown ? /*#__PURE__*/jsxs("span", {
6804
+ className: "np-select-input-placeholder",
6805
+ children: [" ", content]
6806
+ }) : content
6801
6807
  })
6802
6808
  });
6803
6809
  function SelectInputClearButton({
@@ -6818,13 +6824,12 @@ function SelectInputClearButton({
6818
6824
  const noop = () => {};
6819
6825
  function SelectInput({
6820
6826
  name,
6821
- multiple,
6822
6827
  placeholder,
6823
6828
  items,
6824
6829
  defaultValue,
6825
6830
  value: controlledValue,
6826
6831
  compareValues,
6827
- renderValue = String,
6832
+ renderValue = wrapInFragment,
6828
6833
  renderFooter,
6829
6834
  renderTrigger = defaultRenderTrigger,
6830
6835
  filterable,
@@ -6853,7 +6858,6 @@ function SelectInput({
6853
6858
  const controllerRef = filterable ? searchInputRef : listboxRef;
6854
6859
  return /*#__PURE__*/jsx(Listbox, {
6855
6860
  name: name,
6856
- multiple: multiple,
6857
6861
  defaultValue: defaultValue,
6858
6862
  value: controlledValue
6859
6863
  // TODO: Remove assertion when upgrading TypeScript to v5
@@ -6862,78 +6866,73 @@ function SelectInput({
6862
6866
  by: compareValues,
6863
6867
  disabled: disabled,
6864
6868
  onChange: value => {
6865
- if (!multiple) {
6866
- setOpen(false);
6867
- }
6869
+ setOpen(false);
6868
6870
  onChange?.(value);
6869
6871
  },
6870
6872
  children: ({
6871
6873
  disabled: uiDisabled,
6872
6874
  value
6873
- }) => {
6874
- const placeholderShown = multiple && Array.isArray(value) ? value.length === 0 : value == null;
6875
- return /*#__PURE__*/jsx(OptionsOverlay, {
6876
- placement: "bottom-start",
6877
- open: open,
6878
- renderTrigger: ({
6879
- ref,
6880
- getInteractionProps
6881
- }) => /*#__PURE__*/jsx(SelectInputTriggerButtonPropsContext.Provider, {
6882
- // eslint-disable-next-line react/jsx-no-constructed-context-values
6883
- value: {
6884
- ref: mergeRefs([ref, triggerRef]),
6885
- ...mergeProps({
6886
- onClick: () => {
6875
+ }) => /*#__PURE__*/jsx(OptionsOverlay, {
6876
+ placement: "bottom-start",
6877
+ open: open,
6878
+ renderTrigger: ({
6879
+ ref,
6880
+ getInteractionProps
6881
+ }) => /*#__PURE__*/jsx(SelectInputTriggerButtonPropsContext.Provider, {
6882
+ // eslint-disable-next-line react/jsx-no-constructed-context-values
6883
+ value: {
6884
+ ref: mergeRefs([ref, triggerRef]),
6885
+ ...mergeProps({
6886
+ onClick: () => {
6887
+ setOpen(prev => !prev);
6888
+ },
6889
+ onKeyDown: event => {
6890
+ if (event.key === ' ' || event.key === 'Enter' || event.key === 'ArrowDown' || event.key === 'ArrowUp') {
6887
6891
  setOpen(prev => !prev);
6888
- },
6889
- onKeyDown: event => {
6890
- if (event.key === ' ' || event.key === 'Enter' || event.key === 'ArrowDown' || event.key === 'ArrowUp') {
6891
- setOpen(prev => !prev);
6892
- }
6893
6892
  }
6894
- }, getInteractionProps())
6895
- },
6896
- children: renderTrigger({
6897
- content: !placeholderShown ? /*#__PURE__*/jsx(SelectInputOptionContentWithinTriggerContext.Provider, {
6898
- value: true,
6899
- children: multiple && Array.isArray(value) ? value.map(option => renderValue(option, true)).join(', ') : renderValue(value, true)
6900
- }) : placeholder,
6901
- placeholderShown,
6902
- clear: onClear != null ? () => {
6903
- onClear();
6904
- triggerRef.current?.focus({
6905
- preventScroll: true
6906
- });
6907
- } : undefined,
6908
- disabled: uiDisabled,
6909
- size,
6910
- className
6911
- })
6912
- }),
6913
- initialFocusRef: controllerRef,
6914
- size: filterable ? 'lg' : 'md',
6915
- padding: "none",
6916
- onClose: () => {
6917
- setOpen(false);
6918
- },
6919
- onCloseEnd: () => {
6920
- if (filterQuery !== '') {
6921
- setFilterQuery('');
6922
- }
6893
+ }
6894
+ }, getInteractionProps())
6923
6895
  },
6924
- children: /*#__PURE__*/jsx(SelectInputOptions, {
6925
- items: items,
6926
- renderValue: renderValue,
6927
- renderFooter: renderFooter,
6928
- filterable: filterable,
6929
- filterPlaceholder: filterPlaceholder,
6930
- searchInputRef: searchInputRef,
6931
- listboxRef: listboxRef,
6932
- filterQuery: filterQuery,
6933
- onFilterChange: setFilterQuery
6896
+ children: renderTrigger({
6897
+ content: value != null ? /*#__PURE__*/jsx(SelectInputOptionContentWithinTriggerContext.Provider, {
6898
+ value: true,
6899
+ children: renderValue(value, true)
6900
+ }) : placeholder,
6901
+ placeholderShown: value == null,
6902
+ clear: onClear != null ? () => {
6903
+ onClear();
6904
+ triggerRef.current?.focus({
6905
+ preventScroll: true
6906
+ });
6907
+ } : undefined,
6908
+ disabled: uiDisabled,
6909
+ size,
6910
+ className
6934
6911
  })
6935
- });
6936
- }
6912
+ }),
6913
+ initialFocusRef: controllerRef,
6914
+ size: filterable ? 'lg' : 'md',
6915
+ padding: "none",
6916
+ onClose: () => {
6917
+ setOpen(false);
6918
+ },
6919
+ onCloseEnd: () => {
6920
+ if (filterQuery !== '') {
6921
+ setFilterQuery('');
6922
+ }
6923
+ },
6924
+ children: /*#__PURE__*/jsx(SelectInputOptions, {
6925
+ items: items,
6926
+ renderValue: renderValue,
6927
+ renderFooter: renderFooter,
6928
+ filterable: filterable,
6929
+ filterPlaceholder: filterPlaceholder,
6930
+ searchInputRef: searchInputRef,
6931
+ listboxRef: listboxRef,
6932
+ filterQuery: filterQuery,
6933
+ onFilterChange: setFilterQuery
6934
+ })
6935
+ })
6937
6936
  });
6938
6937
  }
6939
6938
  function SelectInputTriggerButton({
@@ -6996,7 +6995,7 @@ const SelectInputOptionsContainer = /*#__PURE__*/forwardRef(function SelectInput
6996
6995
  });
6997
6996
  function SelectInputOptions({
6998
6997
  items,
6999
- renderValue = String,
6998
+ renderValue = wrapInFragment,
7000
6999
  renderFooter,
7001
7000
  filterable = false,
7002
7001
  filterPlaceholder,
@@ -11200,6 +11199,102 @@ Select.defaultProps = {
11200
11199
  dropdownProps: {}
11201
11200
  };
11202
11201
 
11202
+ const SegmentedControl = ({
11203
+ name,
11204
+ defaultValue,
11205
+ mode = 'input',
11206
+ segments,
11207
+ onChange
11208
+ }) => {
11209
+ const [selectedValue, setSelectedValue] = useState(defaultValue || segments[0].value);
11210
+ const [animate, setAnimate] = useState(false);
11211
+ const segmentsRef = useRef(null);
11212
+ if (segments.length > 3) {
11213
+ throw new Error('SegmentedControl only supports up to 3 segments');
11214
+ }
11215
+ const segmentsWithRefs = segments.map(segment => ({
11216
+ ...segment,
11217
+ ref: /*#__PURE__*/createRef()
11218
+ }));
11219
+ const updateSegmentPosition = () => {
11220
+ const selectedSegmentRef = segmentsWithRefs.find(segment => segment.value === selectedValue)?.ref;
11221
+ // We grab the active segments style object from the ref
11222
+ // and set the css variables to the selected segments width and x position.
11223
+ // This is so we can animate the highlight to the selected segment
11224
+ if (selectedSegmentRef?.current && segmentsRef.current) {
11225
+ const {
11226
+ style
11227
+ } = segmentsRef.current;
11228
+ style.setProperty('--segment-highlight-width', `${selectedSegmentRef.current.offsetWidth}px`);
11229
+ style.setProperty('--segment-highlight-x', `${selectedSegmentRef.current.offsetLeft}px`);
11230
+ }
11231
+ };
11232
+ useEffect(() => {
11233
+ updateSegmentPosition();
11234
+ const handleWindowSizeChange = () => {
11235
+ setAnimate(false);
11236
+ updateSegmentPosition();
11237
+ };
11238
+ window.addEventListener('resize', handleWindowSizeChange);
11239
+ return () => {
11240
+ window.removeEventListener('resize', handleWindowSizeChange);
11241
+ };
11242
+ // eslint-disable-next-line react-hooks/exhaustive-deps
11243
+ }, [segmentsWithRefs, selectedValue]);
11244
+ useEffect(() => {
11245
+ onChange(selectedValue);
11246
+ }, [onChange, selectedValue]);
11247
+ return /*#__PURE__*/jsx("div", {
11248
+ ref: segmentsRef,
11249
+ "data-testid": "segmented-control",
11250
+ className: classNames('segmented-control', {
11251
+ 'segmented-control--input': mode === 'input'
11252
+ }),
11253
+ children: /*#__PURE__*/jsx("div", {
11254
+ className: classNames('segmented-control__segments', {
11255
+ 'segmented-control__segments--no-animate': !animate
11256
+ }),
11257
+ children: segmentsWithRefs.map(segment => mode === 'input' ? /*#__PURE__*/jsxs("label", {
11258
+ ref: segment.ref,
11259
+ htmlFor: segment.id,
11260
+ className: classNames('segmented-control__segment', {
11261
+ 'segmented-control__selected-segment': selectedValue === segment.value
11262
+ }),
11263
+ children: [/*#__PURE__*/jsx("input", {
11264
+ type: "radio",
11265
+ className: "segmented-control__radio-input",
11266
+ id: segment.id,
11267
+ name: name,
11268
+ value: segment.value,
11269
+ checked: selectedValue === segment.value,
11270
+ onChange: () => {
11271
+ setAnimate(true);
11272
+ setSelectedValue(segment.value);
11273
+ }
11274
+ }), /*#__PURE__*/jsx("div", {
11275
+ className: "segmented-control__label-text",
11276
+ children: segment.label
11277
+ })]
11278
+ }, segment.id) : /*#__PURE__*/jsx("button", {
11279
+ ref: segment.ref,
11280
+ type: "button",
11281
+ role: "tab",
11282
+ id: segment.id,
11283
+ "aria-controls": segment.controls,
11284
+ "aria-selected": selectedValue === segment.value,
11285
+ className: classNames('segmented-control__segment', 'segmented-control__button', {
11286
+ 'segmented-control__selected-segment': selectedValue === segment.value
11287
+ }),
11288
+ onClick: () => {
11289
+ setAnimate(true);
11290
+ setSelectedValue(segment.value);
11291
+ },
11292
+ children: segment.label
11293
+ }, segment.id))
11294
+ })
11295
+ });
11296
+ };
11297
+
11203
11298
  const CSS_TRANSITION_DURATION = 400;
11204
11299
  class Snackbar extends Component {
11205
11300
  /** @type {RefObject<HTMLSpanElement>} */
@@ -15598,5 +15693,5 @@ const translations = {
15598
15693
  'zh-HK': zhHK
15599
15694
  };
15600
15695
 
15601
- 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$1 as 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 };
15696
+ 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$1 as 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$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 };
15602
15697
  //# sourceMappingURL=index.esm.js.map