@transferwise/components 0.0.0-experimental-b67d30b → 0.0.0-experimental-3b13cb3

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
@@ -1,25 +1,25 @@
1
1
  import * as React from 'react';
2
- import React__default, { forwardRef, cloneElement, useState, useEffect, useRef, useMemo, Component, useCallback, createContext, useContext, useImperativeHandle, createElement, PureComponent, createRef, isValidElement, Children, Fragment as Fragment$1 } from 'react';
2
+ import React__default, { forwardRef, cloneElement, useState, useRef, useEffect, useCallback, Component, createContext, useContext, useImperativeHandle, createElement, useMemo, PureComponent, createRef, isValidElement, Children, Fragment as Fragment$1 } from 'react';
3
3
  import { useId } from '@radix-ui/react-id';
4
4
  import classNames from 'classnames';
5
5
  import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
6
- import { ChevronUp, CrossCircleFill, Cross, NavigateAway, Check, Info as Info$1, Alert as Alert$1, ClockBorderless, Briefcase, Person, AlertCircleFill, ArrowLeft, AlertCircle, QuestionMarkCircle, Search, CrossCircle, ChevronDown, CheckCircleFill, ArrowRight, Download, ClockFill, Upload as Upload$2, Document, Plus, PlusCircle } from '@transferwise/icons';
7
- import { defineMessages, useIntl, injectIntl, IntlProvider } from 'react-intl';
8
- import PropTypes from 'prop-types';
9
- import commonmark from 'commonmark';
6
+ import { ChevronUp, NavigateAway, CrossCircleFill, Cross, Card as Card$3, Bank, BankTransfer, Check, Info as Info$1, Alert as Alert$1, ClockBorderless, Briefcase, Person, AlertCircleFill, ArrowLeft, AlertCircle, QuestionMarkCircle, Search, CrossCircle, ChevronDown, CheckCircleFill, ArrowRight, Download, ClockFill, Upload as Upload$2, Document, Plus, PlusCircle } from '@transferwise/icons';
7
+ import { usePopper } from 'react-popper';
10
8
  import { useTheme, ThemeProvider } from '@wise/components-theming';
11
9
  import { CSSTransition } from 'react-transition-group';
12
10
  import { FocusScope } from '@react-aria/focus';
13
11
  import { createPortal } from 'react-dom';
12
+ import { defineMessages, useIntl, injectIntl, IntlProvider } from 'react-intl';
13
+ import PropTypes from 'prop-types';
14
+ import { Flag, Illustration } from '@wise/art';
14
15
  import { useSyncExternalStore } from 'use-sync-external-store/shim/index.js';
15
16
  import { isUndefined, isNumber, isEmpty, isNull } from '@transferwise/neptune-validation';
17
+ import commonmark from 'commonmark';
16
18
  import { formatDate, formatMoney, formatAmount } from '@transferwise/formatting';
17
19
  import { Transition, Listbox } from '@headlessui/react';
18
20
  import mergeProps from 'merge-props';
19
21
  import { useFloating, useDismiss, useRole, useInteractions, FloatingPortal, FloatingFocusManager, offset, flip, shift, size, autoUpdate } from '@floating-ui/react';
20
22
  import { usePreventScroll } from '@react-aria/overlays';
21
- import { usePopper } from 'react-popper';
22
- import { Flag, Illustration } from '@wise/art';
23
23
  import clamp$2 from 'lodash.clamp';
24
24
  import debounce from 'lodash.debounce';
25
25
  import requiredIf from 'react-required-if';
@@ -670,565 +670,358 @@ const ActionOption = ({
670
670
  });
671
671
  };
672
672
 
673
- var messages$d = defineMessages({
674
- ariaLabel: {
675
- id: "neptune.CloseButton.ariaLabel"
676
- }
677
- });
678
-
679
- const CloseButton = /*#__PURE__*/forwardRef(function CloseButton({
680
- 'aria-label': ariaLabel,
681
- size = Size.MEDIUM,
682
- filled = false,
683
- className,
684
- onClick,
685
- isDisabled,
686
- testId
687
- }, reference) {
688
- const intl = useIntl();
689
- ariaLabel ??= intl.formatMessage(messages$d.ariaLabel);
690
- const Icon = filled ? CrossCircleFill : Cross;
691
- return /*#__PURE__*/jsx("button", {
692
- ref: reference,
693
- type: "button",
694
- className: classNames('np-close-button', 'close btn-link', 'text-no-decoration', {
695
- 'np-close-button--large': size === Size.MEDIUM,
696
- 'np-close-button--x-large': size === Size.LARGE
697
- }, className),
698
- "aria-label": ariaLabel,
699
- "aria-disabled": isDisabled,
700
- disabled: isDisabled,
701
- "data-testid": testId,
702
- onClick: onClick,
703
- children: /*#__PURE__*/jsx(Icon, {
704
- size: size === Size.SMALL ? 16 : 24
705
- })
706
- });
707
- });
708
-
709
- var messages$c = defineMessages({
710
- opensInNewTab: {
711
- id: "neptune.Link.opensInNewTab"
712
- }
713
- });
714
-
715
- const Link = ({
716
- className,
717
- children,
718
- href,
719
- target,
720
- type,
721
- 'aria-label': ariaLabel,
722
- onClick,
723
- ...props
724
- }) => {
725
- const isBlank = target === '_blank';
726
- const {
727
- formatMessage
728
- } = useIntl();
729
- return /*#__PURE__*/jsxs("a", {
730
- href: href,
731
- target: target,
732
- className: classNames('np-link', type ? `np-text-${type}` : undefined, 'd-inline-flex', className),
733
- "aria-label": ariaLabel,
734
- rel: isBlank ? 'noreferrer' : undefined,
735
- onClick: onClick,
736
- ...props,
737
- children: [children, " ", isBlank && /*#__PURE__*/jsx(NavigateAway, {
738
- title: formatMessage(messages$c.opensInNewTab)
739
- })]
740
- });
741
- };
742
-
743
- const iconTypeMap = {
744
- positive: Check,
745
- neutral: Info$1,
746
- warning: Alert$1,
747
- negative: Cross,
748
- pending: ClockBorderless,
749
- info: Info$1,
750
- error: Cross,
751
- success: Check
752
- };
753
- const StatusIcon = ({
754
- sentiment = 'neutral',
755
- size = 'md'
673
+ const FocusBoundary = ({
674
+ children
756
675
  }) => {
757
- const Icon = iconTypeMap[sentiment];
758
- const iconColor = sentiment === 'warning' || sentiment === 'pending' ? 'dark' : 'light';
759
- return /*#__PURE__*/jsx("span", {
760
- "data-testid": "status-icon",
761
- className: classNames('status-circle', 'status-circle-' + size, sentiment),
762
- children: /*#__PURE__*/jsx(Icon, {
763
- className: classNames('status-icon', iconColor)
676
+ const wrapperReference = useRef(null);
677
+ useEffect(() => {
678
+ wrapperReference.current?.focus({
679
+ preventScroll: true
680
+ });
681
+ }, []);
682
+ return /*#__PURE__*/jsx(FocusScope, {
683
+ contain: true,
684
+ restoreFocus: true,
685
+ children: /*#__PURE__*/jsx("div", {
686
+ ref: wrapperReference,
687
+ tabIndex: -1,
688
+ children: children
764
689
  })
765
690
  });
766
691
  };
767
692
 
768
- const DEFAULT_TYPE = Typography.TITLE_GROUP;
769
- const titleTypeMapping = {
770
- [Typography.TITLE_SCREEN]: 'h1',
771
- [Typography.TITLE_SECTION]: 'h2',
772
- [Typography.TITLE_SUBSECTION]: 'h3',
773
- [Typography.TITLE_BODY]: 'h4',
774
- [Typography.TITLE_GROUP]: 'h5'
775
- };
776
- function Title({
777
- as,
778
- type = DEFAULT_TYPE,
779
- className,
780
- ...props
781
- }) {
782
- const mapping = titleTypeMapping[type];
783
- const isTypeSupported = mapping !== undefined;
784
- if (isTypeSupported) {
785
- const HeaderTag = as ?? mapping;
786
- return /*#__PURE__*/jsx(HeaderTag, {
787
- ...props,
788
- className: classNames(`np-text-${type}`, className)
789
- });
790
- }
791
- const HeaderTag = as ?? titleTypeMapping[DEFAULT_TYPE];
792
- return /*#__PURE__*/jsx(HeaderTag, {
793
- ...props,
794
- className: classNames(`np-text-${DEFAULT_TYPE}`, className)
795
- });
796
- }
797
-
798
- function logActionRequired(message) {
799
- if (['development', 'test'].includes(process?.env?.NODE_ENV)) {
800
- // eslint-disable-next-line no-console
801
- console.warn(message);
802
- }
803
- }
804
- function logActionRequiredIf(message, conditional) {
805
- if (conditional) {
806
- logActionRequired(message);
807
- }
693
+ function withNextPortalWrapper(Component) {
694
+ return function (props) {
695
+ const [mounted, setMounted] = useState(false);
696
+ useEffect(() => {
697
+ setMounted(true);
698
+ }, [setMounted]);
699
+ return mounted ? /*#__PURE__*/createPortal( /*#__PURE__*/jsx(Component, {
700
+ ...props
701
+ }), document.body) : null;
702
+ };
808
703
  }
809
704
 
810
- const reader = new commonmark.Parser();
811
- const writer = new commonmark.HtmlRenderer({
812
- safe: true
813
- });
814
- const NODE_TYPE_LIST = Object.values(MarkdownNodeType);
815
- function Markdown({
816
- as: Element = 'div',
817
- allowList,
818
- blockList,
819
- config,
820
- className,
821
- children
822
- }) {
823
- if (!children) {
824
- return null;
825
- }
826
- const linkTarget = config?.link?.target ?? '_self';
827
- const paragraphClass = config?.paragraph?.className ?? '';
828
- if (allowList != null && blockList != null) {
829
- logActionRequired('Markdown supports only one of `allowList` or `blockList` to be used at a time. `blockList` will be ignored.');
705
+ /**
706
+ * Dimmer state management inspired by Material UI's ModalManager (https://github.com/mui-org/material-ui)
707
+ */
708
+ class DimmerManager {
709
+ /**
710
+ * Dimmer refs
711
+ */
712
+ dimmers;
713
+ constructor() {
714
+ this.dimmers = [];
830
715
  }
831
- const parser = nodes => {
832
- const parsed = reader.parse(nodes);
833
- const toExclude = allowList != null ? NODE_TYPE_LIST.filter(type => !allowList.includes(type)) : blockList;
834
- return toExclude != null ? stripNodes({
835
- parsed,
836
- blockList: toExclude
837
- }) : parsed;
838
- };
839
- const createMarkup = () => {
840
- const parsed = parser(children);
841
- return writer.render(parsed).replace(/<a href="/g, `<a target="${linkTarget}" href="`).replace(/<p>/g, `<p class="${paragraphClass}">`);
842
- };
843
- return /*#__PURE__*/jsx(Element, {
844
- className: className,
845
- dangerouslySetInnerHTML: {
846
- __html: createMarkup()
716
+ add(dimmer) {
717
+ let dimmerIndex = this.dimmers.indexOf(dimmer);
718
+ if (dimmerIndex !== -1) {
719
+ return dimmerIndex;
847
720
  }
848
- });
849
- }
850
- function stripNodes({
851
- blockList,
852
- parsed
853
- }) {
854
- if (!parsed) {
855
- return parsed;
721
+ dimmerIndex = this.dimmers.length;
722
+ this.dimmers.push(dimmer);
723
+ return dimmerIndex;
856
724
  }
857
- const walker = parsed.walker();
858
- for (let event = walker.next(); event != null; event = walker.next()) {
859
- const {
860
- node
861
- } = event;
862
- if (blockList.includes(node.type) && !event.entering) {
863
- while (node.firstChild != null) {
864
- node.insertBefore(node.firstChild);
865
- }
866
- node.unlink();
725
+ remove(dimmer) {
726
+ const dimmerIndex = this.dimmers.indexOf(dimmer);
727
+ if (dimmerIndex !== -1) {
728
+ this.dimmers.splice(dimmerIndex, 1);
867
729
  }
730
+ return dimmerIndex;
731
+ }
732
+ isTop(dimmer) {
733
+ return this.dimmers.length > 0 && this.dimmers[this.dimmers.length - 1] === dimmer;
868
734
  }
869
- return parsed;
870
735
  }
871
736
 
872
- const allowList = [MarkdownNodeType.STRONG];
873
- const InlineMarkdown = props => {
874
- return /*#__PURE__*/jsx(Markdown, {
875
- ...props,
876
- as: "span",
877
- allowList: allowList,
878
- blockList: undefined
879
- });
880
- };
881
- InlineMarkdown.propTypes = {
882
- children: PropTypes.string.isRequired,
883
- className: PropTypes.string
884
- };
885
- InlineMarkdown.defaultProps = {
886
- className: undefined
887
- };
888
-
889
- var AlertArrowPosition;
890
- (function (AlertArrowPosition) {
891
- AlertArrowPosition["TOP_LEFT"] = "up-left";
892
- AlertArrowPosition["TOP"] = "up-center";
893
- AlertArrowPosition["TOP_RIGHT"] = "up-right";
894
- AlertArrowPosition["BOTTOM_LEFT"] = "down-left";
895
- AlertArrowPosition["BOTTOM"] = "down-center";
896
- AlertArrowPosition["BOTTOM_RIGHT"] = "down-right";
897
- })(AlertArrowPosition || (AlertArrowPosition = {}));
898
- function resolveType(type) {
899
- switch (type) {
900
- case 'success':
901
- return 'positive';
902
- case 'info':
903
- return 'neutral';
904
- case 'error':
905
- return 'negative';
906
- default:
907
- return type;
737
+ const EXIT_ANIMATION$1 = 350;
738
+ const dimmerManager = new DimmerManager();
739
+ const handleTouchMove = event => {
740
+ const isTouchedElementDimmer = event.target.classList.contains('dimmer');
741
+ // disable scroll on iOS devices for Dimmer area
742
+ // this is because of bug in WebKit https://bugs.webkit.org/show_bug.cgi?id=220908
743
+ // note: scrolling still works for children(s) as expected
744
+ if (isIosDevice() && isTouchedElementDimmer) {
745
+ event.stopPropagation();
746
+ event.preventDefault();
908
747
  }
909
- }
910
- function Alert({
911
- arrow,
912
- action,
748
+ };
749
+ const Dimmer = ({
913
750
  children,
914
751
  className,
915
- dismissible,
916
- icon,
917
- onDismiss,
918
- message,
919
- size,
920
- title,
921
- type = 'neutral',
922
- variant = 'desktop'
923
- }) {
924
- useEffect(() => {
925
- if (arrow !== undefined) {
926
- logActionRequired("Alert component doesn't support 'arrow' anymore, use 'InlineAlert' instead.");
752
+ disableClickToClose = false,
753
+ contentPosition,
754
+ fadeContentOnEnter = false,
755
+ fadeContentOnExit = false,
756
+ open = false,
757
+ scrollable = false,
758
+ transparent = false,
759
+ onClose
760
+ }) => {
761
+ const [hasNotExited, setHasNotExited] = useState(false);
762
+ const dimmerReference = useRef(null);
763
+ const closeOnClick = event => {
764
+ if (event.target === dimmerReference.current) {
765
+ onClose?.(event);
927
766
  }
928
- }, [arrow]);
929
- useEffect(() => {
930
- if (children !== undefined) {
931
- logActionRequired("Alert component doesn't support 'children' anymore, use 'message' instead.");
767
+ };
768
+ const handleClick = event => {
769
+ if (disableClickToClose || !onClose) {
770
+ return;
932
771
  }
933
- }, [children]);
934
- useEffect(() => {
935
- if (dismissible !== undefined) {
936
- logActionRequired("Alert component doesn't support 'dismissible' anymore, use 'onDismiss' instead.");
772
+ closeOnClick(event);
773
+ };
774
+ const handleKeyDown = useCallback(event => {
775
+ if (event.key !== 'Escape') {
776
+ return;
937
777
  }
938
- }, [dismissible]);
939
- useEffect(() => {
940
- if (size !== undefined) {
941
- logActionRequired("Alert component doesn't support 'size' anymore, please remove that prop.");
778
+ event.stopPropagation();
779
+ if (onClose && dimmerReference.current && dimmerManager.isTop(dimmerReference.current)) {
780
+ onClose(event);
942
781
  }
943
- }, [size]);
944
- const resolvedType = resolveType(type);
782
+ }, [onClose]);
783
+ const onEnter = () => {
784
+ setHasNotExited(true);
785
+ if (dimmerReference.current) {
786
+ dimmerManager.add(dimmerReference.current);
787
+ }
788
+ };
789
+ const onExited = () => {
790
+ setHasNotExited(false);
791
+ if (dimmerReference.current) {
792
+ dimmerManager.remove(dimmerReference.current);
793
+ }
794
+ };
945
795
  useEffect(() => {
946
- if (resolvedType !== type) {
947
- logActionRequired(`Alert component has deprecated '${type}' value for the 'type' prop. Please use '${resolvedType}' instead.`);
796
+ const localReferenceCopy = dimmerReference.current;
797
+ if (open) {
798
+ document.addEventListener('keydown', handleKeyDown);
799
+ localReferenceCopy?.addEventListener('touchmove', handleTouchMove, {
800
+ passive: true
801
+ });
948
802
  }
949
- }, [resolvedType, type]);
950
- const [shouldFire, setShouldFire] = useState(false);
951
- const closeButtonReference = useRef(null);
952
- return /*#__PURE__*/jsxs("div", {
953
- className: classNames('alert d-flex', `alert-${resolvedType}`, arrow != null && alertArrowClassNames(arrow), className),
954
- "data-testid": "alert",
955
- onTouchStart: () => setShouldFire(true),
956
- onTouchEnd: event => {
957
- if (shouldFire && action &&
958
- // Check if current event is triggered from closeButton
959
- event.target instanceof Node && closeButtonReference.current && !closeButtonReference.current.contains(event.target)) {
960
- if (action.target === '_blank') {
961
- window.top?.open(action.href);
962
- } else {
963
- window.top?.location.assign(action.href);
964
- }
965
- }
966
- setShouldFire(false);
967
- },
968
- onTouchMove: () => setShouldFire(false),
969
- children: [/*#__PURE__*/jsxs("div", {
970
- className: classNames('alert__content', 'd-flex', 'flex-grow-1', variant),
971
- "data-testid": variant,
972
- children: [icon ? /*#__PURE__*/jsx("div", {
973
- className: "alert__icon",
974
- children: icon
975
- }) : /*#__PURE__*/jsx(StatusIcon, {
976
- size: Size.LARGE,
977
- sentiment: resolvedType
978
- }), /*#__PURE__*/jsxs("div", {
979
- className: "alert__message",
980
- children: [/*#__PURE__*/jsxs("div", {
981
- role: Sentiment.NEGATIVE === resolvedType ? 'alert' : 'status',
982
- children: [title && /*#__PURE__*/jsx(Title, {
983
- className: "m-b-1",
984
- type: Typography.TITLE_BODY,
985
- children: title
986
- }), /*#__PURE__*/jsx(Body, {
987
- as: "span",
988
- className: "d-block",
989
- type: Typography.BODY_LARGE,
990
- children: children || /*#__PURE__*/jsx(InlineMarkdown, {
991
- children: message
803
+ return () => {
804
+ document.removeEventListener('keydown', handleKeyDown);
805
+ localReferenceCopy?.removeEventListener('touchmove', handleTouchMove);
806
+ };
807
+ }, [handleKeyDown, open]);
808
+ return /*#__PURE__*/jsx(DimmerWrapper, {
809
+ open: open,
810
+ hasNotExited: hasNotExited,
811
+ children: /*#__PURE__*/jsx(CSSTransition, {
812
+ nodeRef: dimmerReference,
813
+ in: open,
814
+ appear: true
815
+ // Wait for animation to finish before unmount.
816
+ ,
817
+ timeout: {
818
+ enter: 0,
819
+ exit: EXIT_ANIMATION$1
820
+ },
821
+ classNames: {
822
+ enter: classNames({
823
+ 'dimmer--enter-fade': fadeContentOnEnter
824
+ }),
825
+ enterDone: classNames('dimmer--enter-done', {
826
+ 'dimmer--enter-fade': fadeContentOnEnter
827
+ }),
828
+ exit: classNames('dimmer--exit', {
829
+ 'dimmer--exit-fade': fadeContentOnExit
830
+ })
831
+ },
832
+ unmountOnExit: true,
833
+ onEnter: onEnter,
834
+ onExited: onExited,
835
+ children: /*#__PURE__*/jsx(DimmerContentWrapper, {
836
+ scrollBody: !transparent,
837
+ children: /*#__PURE__*/jsx(FocusBoundary, {
838
+ children: /*#__PURE__*/jsx("div", {
839
+ ref: dimmerReference,
840
+ className: classNames('dimmer', {
841
+ 'dimmer--scrollable': scrollable,
842
+ 'dimmer--transparent': transparent
843
+ }, className),
844
+ role: "presentation",
845
+ onClick: handleClick,
846
+ children: /*#__PURE__*/jsx("div", {
847
+ className: classNames('dimmer-content-positioner', contentPosition != null && ['d-flex justify-content-center', {
848
+ 'align-items-start': contentPosition === 'top',
849
+ 'align-items-center': contentPosition === 'center',
850
+ 'align-items-end': contentPosition === 'bottom'
851
+ }]),
852
+ children: children
992
853
  })
993
- })]
994
- }), action && /*#__PURE__*/jsx(Link, {
995
- href: action.href,
996
- className: "m-t-1",
997
- "aria-label": action['aria-label'],
998
- target: action.target,
999
- type: Typography.LINK_LARGE,
1000
- children: action.text
1001
- })]
1002
- })]
1003
- }), onDismiss && /*#__PURE__*/jsx(CloseButton, {
1004
- ref: closeButtonReference,
1005
- className: "m-l-2",
1006
- onClick: onDismiss
1007
- })]
854
+ })
855
+ })
856
+ })
857
+ })
1008
858
  });
1009
- }
1010
- function alertArrowClassNames(arrow) {
1011
- switch (arrow) {
1012
- case 'down-center':
1013
- return 'arrow arrow-bottom arrow-center';
1014
- case 'down-left':
1015
- return 'arrow arrow-bottom arrow-left';
1016
- case 'down-right':
1017
- return 'arrow arrow-bottom arrow-right';
1018
- case 'up-center':
1019
- return 'arrow arrow-center';
1020
- case 'up-right':
1021
- return 'arrow arrow-right';
1022
- case 'up-left':
1023
- default:
1024
- return 'arrow';
1025
- }
1026
- }
1027
-
1028
- // TODO: consider to move this enum into component file once we migrate it on TypeScript or replace with some common enum
1029
- var AvatarType;
1030
- (function (AvatarType) {
1031
- AvatarType["THUMBNAIL"] = "thumbnail";
1032
- AvatarType["ICON"] = "icon";
1033
- AvatarType["EMOJI"] = "emoji";
1034
- AvatarType["INITIALS"] = "initials";
1035
- })(AvatarType || (AvatarType = {}));
1036
-
1037
- /*
1038
- * The colors we support generating an Avatar background color from a "seed" for.
1039
- * Changing this array will change the assignment between seeds.
1040
- * Do not change this array.
1041
- */
1042
- const avatarColors = ['--color-bright-blue', '--color-bright-yellow', '--color-bright-pink', '--color-bright-orange'];
1043
- /*
1044
- * Takes in a "seed" string and spits out an index for the color we should use.
1045
- * This implementation has been synced across all three clients so that we consistently
1046
- * generate branded avatar colors when rendering a list of Avatars.
1047
- * Do not change this implementation.
1048
- */
1049
- const hashSeed = seed => {
1050
- const base = 31;
1051
- const modulo = avatarColors.length;
1052
- let hashValue = 0;
1053
- let basePow = 1;
1054
- for (let i = 0; i < seed.length; i += 1) {
1055
- hashValue = (hashValue + seed.charCodeAt(i) * basePow) % modulo;
1056
- basePow = basePow * base % modulo;
1057
- }
1058
- return hashValue;
1059
- };
1060
- const getAvatarColorFromSeed = seed => {
1061
- return avatarColors[hashSeed(seed)];
1062
- };
1063
-
1064
- const backwardsCompatibleSize = size => {
1065
- switch (size) {
1066
- case 'sm':
1067
- return 24;
1068
- case 'md':
1069
- return 48;
1070
- case 'lg':
1071
- return 72;
1072
- default:
1073
- return size;
1074
- }
1075
859
  };
1076
- const Avatar = ({
1077
- backgroundColor = null,
1078
- backgroundColorSeed = null,
1079
- children = null,
1080
- className,
1081
- outlined = false,
1082
- size: sizeFromProps = 48,
1083
- theme = Theme.LIGHT,
1084
- type = 'thumbnail'
860
+ const DimmerWrapper = ({
861
+ open,
862
+ hasNotExited,
863
+ children
1085
864
  }) => {
1086
- const backgroundColorFromSeed = useMemo(() => !backgroundColor && backgroundColorSeed ? `var(${getAvatarColorFromSeed(backgroundColorSeed)})` : undefined, [backgroundColor, backgroundColorSeed]);
1087
- const size = backwardsCompatibleSize(sizeFromProps);
1088
- return /*#__PURE__*/jsx("div", {
1089
- className: classNames('tw-avatar', className, `tw-avatar--${size}`, `tw-avatar--${type}`, {
1090
- 'tw-avatar--outlined': outlined,
1091
- 'tw-avatar--branded': Boolean(backgroundColorFromSeed),
1092
- 'np-text-title-body': type === 'initials'
1093
- }),
1094
- children: /*#__PURE__*/jsx("div", {
1095
- className: "tw-avatar__content",
1096
- style: {
1097
- backgroundColor: backgroundColor || backgroundColorFromSeed
1098
- },
1099
- children: children
1100
- })
865
+ const {
866
+ screenMode,
867
+ theme
868
+ } = useTheme();
869
+ return open || hasNotExited ? /*#__PURE__*/jsx(ThemeProvider, {
870
+ theme: "personal",
871
+ screenMode: theme === 'personal' ? screenMode : 'light',
872
+ isNotRootProvider: true,
873
+ children: children
874
+ }) : /*#__PURE__*/jsx(Fragment, {
875
+ children: children
1101
876
  });
1102
877
  };
1103
-
1104
- const Badge = ({
1105
- badge,
1106
- className = undefined,
1107
- size = Size.SMALL,
1108
- border = Theme.LIGHT,
1109
- children
878
+ const DimmerContentWrapper = ({
879
+ children,
880
+ scrollBody
1110
881
  }) => {
1111
- const classes = classNames('tw-badge', {
1112
- [`tw-badge-border-${border}`]: border,
1113
- [`tw-badge-${size}`]: size
1114
- }, className);
1115
- return /*#__PURE__*/jsxs("div", {
1116
- className: classes,
1117
- children: [/*#__PURE__*/jsx("div", {
1118
- className: "tw-badge__children",
1119
- children: children
1120
- }), /*#__PURE__*/jsx("div", {
1121
- className: "tw-badge__content",
1122
- children: badge
1123
- })]
1124
- });
882
+ useEffect(() => {
883
+ if (scrollBody) {
884
+ addNoScrollClass();
885
+ }
886
+ return () => {
887
+ if (scrollBody) {
888
+ removeNoScrollClass();
889
+ }
890
+ };
891
+ }, [scrollBody]);
892
+ return children;
1125
893
  };
894
+ var Dimmer$1 = withNextPortalWrapper(Dimmer);
1126
895
 
1127
- const OptionalBadge = ({
1128
- url,
1129
- altText,
1130
- statusIcon,
896
+ const POPOVER_OFFSET = [0, 16];
897
+ // By default the flip positioning explores only the opposite alternative. So if left is passed and there's no enough space
898
+ // the right one gets chosen. If there's no space on both sides popover goes back to the initially chosen one left.
899
+ // This mapping forces popover to try the four available positions before going back to the initial chosen one.
900
+ const fallbackPlacements = {
901
+ [Position.TOP]: [Position.BOTTOM, Position.RIGHT, Position.LEFT],
902
+ [Position.BOTTOM]: [Position.TOP, Position.RIGHT, Position.LEFT],
903
+ [Position.LEFT]: [Position.RIGHT, Position.TOP, Position.BOTTOM],
904
+ [Position.RIGHT]: [Position.LEFT, Position.TOP, Position.BOTTOM]
905
+ };
906
+ const Panel = /*#__PURE__*/forwardRef(({
907
+ arrow = false,
908
+ flip = true,
909
+ altAxis = false,
1131
910
  children,
911
+ open = false,
912
+ onClose,
913
+ position = Position.BOTTOM,
914
+ anchorRef,
915
+ anchorWidth = false,
1132
916
  ...rest
1133
- }) => {
1134
- if (url) {
1135
- return /*#__PURE__*/jsx(Badge, {
1136
- badge: /*#__PURE__*/jsx("img", {
1137
- src: url,
1138
- alt: altText
1139
- }),
1140
- ...rest,
1141
- children: children
917
+ }, reference) => {
918
+ const [arrowElement, setArrowElement] = useState(null);
919
+ const [popperElement, setPopperElement] = useState(null);
920
+ const modifiers = [];
921
+ if (altAxis) {
922
+ modifiers.push({
923
+ // https://popper.js.org/docs/v2/modifiers/prevent-overflow
924
+ name: 'preventOverflow',
925
+ options: {
926
+ altAxis: true,
927
+ tether: false
928
+ }
1142
929
  });
1143
930
  }
1144
- if (statusIcon) {
1145
- return /*#__PURE__*/jsx(Badge, {
1146
- badge: /*#__PURE__*/jsx(StatusIcon, {
1147
- sentiment: statusIcon,
1148
- size: Size.SMALL
1149
- }),
1150
- ...rest,
1151
- children: children
931
+ if (arrow) {
932
+ modifiers.push({
933
+ name: 'arrow',
934
+ options: {
935
+ element: arrowElement,
936
+ options: {
937
+ padding: 8 // 8px from the edges of the popper
938
+ }
939
+ }
940
+ });
941
+ // This lets you displace a popper element from its reference element.
942
+ modifiers.push({
943
+ name: 'offset',
944
+ options: {
945
+ offset: POPOVER_OFFSET
946
+ }
1152
947
  });
1153
948
  }
1154
- return /*#__PURE__*/jsx(Fragment, {
949
+ if (flip && fallbackPlacements[position]) {
950
+ modifiers.push({
951
+ name: 'flip',
952
+ options: {
953
+ fallbackPlacements: fallbackPlacements[position]
954
+ }
955
+ });
956
+ }
957
+ const {
958
+ styles,
959
+ attributes,
960
+ forceUpdate
961
+ } = usePopper(anchorRef.current, popperElement, {
962
+ placement: position,
963
+ modifiers
964
+ });
965
+ // If the trigger is not visible when the position is calculated, it will be incorrect. Because this can happen repeatedly (on resize for example),
966
+ // it is most simple just to always position before opening
967
+ useEffect(() => {
968
+ if (open && forceUpdate) {
969
+ forceUpdate();
970
+ }
971
+ }, [open]);
972
+ const contentStyle = {
973
+ ...(anchorWidth ? {
974
+ width: anchorRef.current?.clientWidth
975
+ } : undefined)
976
+ };
977
+ return /*#__PURE__*/jsx(Dimmer$1, {
978
+ open: open,
979
+ transparent: true,
980
+ fadeContentOnEnter: true,
981
+ fadeContentOnExit: true,
982
+ onClose: onClose,
983
+ children: /*#__PURE__*/jsx("div", {
984
+ ...rest,
985
+ ref: setPopperElement,
986
+ role: "dialog"
987
+ // eslint-disable-next-line react/forbid-dom-props
988
+ ,
989
+ style: {
990
+ ...styles.popper
991
+ },
992
+ ...attributes.popper,
993
+ className: classNames('np-panel', {
994
+ 'np-panel--open': open
995
+ }, rest['className']),
996
+ children: /*#__PURE__*/jsxs("div", {
997
+ ref: reference
998
+ /* eslint-disable-next-line react/forbid-dom-props */,
999
+ style: contentStyle,
1000
+ className: classNames('np-panel__content'),
1001
+ children: [children, arrow && /*#__PURE__*/jsx("div", {
1002
+ ref: setArrowElement,
1003
+ className: classNames('np-panel__arrow')
1004
+ // eslint-disable-next-line react/forbid-dom-props
1005
+ ,
1006
+ style: styles.arrow
1007
+ })]
1008
+ })
1009
+ })
1010
+ });
1011
+ });
1012
+
1013
+ const Section = ({
1014
+ children,
1015
+ className,
1016
+ withHorizontalPadding = false
1017
+ }) => {
1018
+ return /*#__PURE__*/jsx("div", {
1019
+ className: classNames('np-section', className, {
1020
+ 'np-section--with-horizontal-padding': withHorizontalPadding
1021
+ }),
1155
1022
  children: children
1156
1023
  });
1157
1024
  };
1158
- const AvatarWrapper = ({
1159
- url,
1160
- profileType,
1161
- profileId,
1162
- badgeUrl,
1163
- badgeAltText,
1164
- badgeStatusIcon,
1165
- name,
1166
- avatarProps,
1167
- badgeProps
1168
- }) => {
1169
- const [hasImageLoadError, setImageLoadError] = useState(false);
1170
- const isBusinessProfile = profileType === ProfileType.BUSINESS;
1171
- // Reset the errored state when url changes
1172
- useEffect(() => setImageLoadError(false), [url]);
1173
- const getAvatarProps = () => {
1174
- if (url && !hasImageLoadError) {
1175
- return {
1176
- type: AvatarType.THUMBNAIL,
1177
- children: /*#__PURE__*/jsx("img", {
1178
- src: url,
1179
- alt: "",
1180
- onError: () => setImageLoadError(true)
1181
- }),
1182
- ...avatarProps
1183
- };
1184
- }
1185
- if (profileType) {
1186
- return {
1187
- type: AvatarType.ICON,
1188
- children: isBusinessProfile ? /*#__PURE__*/jsx(Briefcase, {
1189
- size: "24"
1190
- }) : /*#__PURE__*/jsx(Person, {
1191
- size: "24"
1192
- }),
1193
- ...avatarProps
1194
- };
1195
- }
1196
- if (name) {
1197
- return {
1198
- type: AvatarType.INITIALS,
1199
- children: /*#__PURE__*/jsx(Fragment, {
1200
- children: getInitials(name)
1201
- }),
1202
- backgroundColorSeed: profileId?.toString(),
1203
- ...avatarProps
1204
- };
1205
- }
1206
- return {
1207
- type: AvatarType.ICON,
1208
- children: /*#__PURE__*/jsx(Person, {
1209
- size: "24"
1210
- }),
1211
- ...avatarProps
1212
- };
1213
- };
1214
- return /*#__PURE__*/jsx(OptionalBadge, {
1215
- url: badgeUrl,
1216
- altText: badgeAltText,
1217
- statusIcon: badgeStatusIcon,
1218
- ...badgeProps,
1219
- children: /*#__PURE__*/jsx(Avatar, {
1220
- size: Size.MEDIUM,
1221
- ...getAvatarProps()
1222
- })
1223
- });
1224
- };
1225
- function getInitials(name) {
1226
- const allInitials = name.split(' ').map(part => part[0]).join('').toUpperCase();
1227
- if (allInitials.length === 1) {
1228
- return allInitials[0];
1229
- }
1230
- return allInitials[0] + allInitials.slice(-1);
1231
- }
1232
1025
 
1233
1026
  const radius = {
1234
1027
  xxs: 6,
@@ -1353,7 +1146,7 @@ ProcessIndicator.defaultProps = {
1353
1146
  };
1354
1147
  var ProcessIndicator$1 = ProcessIndicator;
1355
1148
 
1356
- var messages$b = defineMessages({
1149
+ var messages$d = defineMessages({
1357
1150
  loadingAriaLabel: {
1358
1151
  id: "neptune.Button.loadingAriaLabel"
1359
1152
  }
@@ -1370,6 +1163,18 @@ const priorityClassMap = {
1370
1163
  [Priority.TERTIARY]: 'btn-priority-3'
1371
1164
  };
1372
1165
 
1166
+ function logActionRequired(message) {
1167
+ if (['development', 'test'].includes(process?.env?.NODE_ENV)) {
1168
+ // eslint-disable-next-line no-console
1169
+ console.warn(message);
1170
+ }
1171
+ }
1172
+ function logActionRequiredIf(message, conditional) {
1173
+ if (conditional) {
1174
+ logActionRequired(message);
1175
+ }
1176
+ }
1177
+
1373
1178
  const deprecatedTypeMap = {
1374
1179
  [Type.PRIMARY]: ControlType.ACCENT,
1375
1180
  [Type.SECONDARY]: ControlType.ACCENT,
@@ -1472,7 +1277,7 @@ const Button = /*#__PURE__*/forwardRef(({
1472
1277
  className: classes,
1473
1278
  ...props,
1474
1279
  "aria-live": loading ? 'polite' : 'off',
1475
- "aria-label": loading ? intl.formatMessage(messages$b.loadingAriaLabel) : rest['aria-label'],
1280
+ "aria-label": loading ? intl.formatMessage(messages$d.loadingAriaLabel) : rest['aria-label'],
1476
1281
  children: [children, loading && /*#__PURE__*/jsx(ProcessIndicator$1, {
1477
1282
  size: processIndicatorSize(),
1478
1283
  className: "btn-loader"
@@ -1480,806 +1285,415 @@ const Button = /*#__PURE__*/forwardRef(({
1480
1285
  });
1481
1286
  });
1482
1287
 
1483
- const Card$1 = /*#__PURE__*/forwardRef((props, reference) => {
1288
+ var messages$c = defineMessages({
1289
+ opensInNewTab: {
1290
+ id: "neptune.Link.opensInNewTab"
1291
+ }
1292
+ });
1293
+
1294
+ const Link = ({
1295
+ className,
1296
+ children,
1297
+ href,
1298
+ target,
1299
+ type,
1300
+ 'aria-label': ariaLabel,
1301
+ onClick,
1302
+ ...props
1303
+ }) => {
1304
+ const isBlank = target === '_blank';
1484
1305
  const {
1485
- 'aria-label': ariaLabel,
1486
- as: Element,
1487
- isExpanded,
1488
- title,
1489
- details,
1490
- children,
1491
- onClick,
1492
- icon,
1493
- id,
1494
- className,
1495
- ...rest
1496
- } = props;
1497
- const isOpen = !!(isExpanded && children);
1498
- return /*#__PURE__*/jsxs(Element, {
1499
- ref: reference,
1500
- className: classNames('np-card', className, {
1501
- 'np-card--expanded': isOpen,
1502
- 'np-card--inactive': !children,
1503
- 'np-card--has-icon': !!icon
1504
- }),
1505
- id: id,
1506
- "data-testid": rest['data-testid'],
1507
- children: [/*#__PURE__*/jsx(Option$2, {
1508
- "aria-label": ariaLabel,
1509
- as: children ? 'button' : 'div',
1510
- className: classNames('np-card__button'),
1511
- media: icon,
1512
- title: title,
1513
- content: details,
1514
- showMediaAtAllSizes: true,
1515
- button: children && /*#__PURE__*/jsx(Chevron, {
1516
- orientation: isOpen ? Position.TOP : Position.BOTTOM
1517
- }),
1518
- onClick: () => children && onClick(!isExpanded)
1519
- }), /*#__PURE__*/jsx("div", {
1520
- className: classNames('np-card__divider', {
1521
- 'np-card__divider--expanded': isOpen
1522
- })
1523
- }), isOpen && /*#__PURE__*/jsx(Body, {
1524
- as: "span",
1525
- type: Typography.BODY_LARGE,
1526
- className: "np-card__content d-block",
1527
- children: children
1306
+ formatMessage
1307
+ } = useIntl();
1308
+ return /*#__PURE__*/jsxs("a", {
1309
+ href: href,
1310
+ target: target,
1311
+ className: classNames('np-link', type ? `np-text-${type}` : undefined, 'd-inline-flex', className),
1312
+ "aria-label": ariaLabel,
1313
+ rel: isBlank ? 'noreferrer' : undefined,
1314
+ onClick: onClick,
1315
+ ...props,
1316
+ children: [children, " ", isBlank && /*#__PURE__*/jsx(NavigateAway, {
1317
+ title: formatMessage(messages$c.opensInNewTab)
1528
1318
  })]
1529
1319
  });
1530
- });
1531
- const hasChildren = ({
1532
- children
1533
- }) => children;
1534
- Card$1.propTypes = {
1535
- 'aria-label': PropTypes.string,
1536
- as: PropTypes.string,
1537
- isExpanded: requiredIf(PropTypes.bool, hasChildren),
1538
- title: PropTypes.node.isRequired,
1539
- details: PropTypes.node.isRequired,
1540
- onClick: requiredIf(PropTypes.func, hasChildren),
1541
- icon: PropTypes.node,
1542
- children: PropTypes.node,
1543
- id: PropTypes.string,
1544
- className: PropTypes.string,
1545
- 'data-testid': PropTypes.string
1546
- };
1547
- Card$1.defaultProps = {
1548
- 'aria-label': undefined,
1549
- as: 'div',
1550
- children: null,
1551
- id: null,
1552
- className: null,
1553
- 'data-testid': null
1554
1320
  };
1555
- var Card$2 = Card$1;
1556
1321
 
1557
- const CheckboxButton = /*#__PURE__*/forwardRef(({
1558
- checked,
1322
+ const DEFAULT_TYPE = Typography.TITLE_GROUP;
1323
+ const titleTypeMapping = {
1324
+ [Typography.TITLE_SCREEN]: 'h1',
1325
+ [Typography.TITLE_SECTION]: 'h2',
1326
+ [Typography.TITLE_SUBSECTION]: 'h3',
1327
+ [Typography.TITLE_BODY]: 'h4',
1328
+ [Typography.TITLE_GROUP]: 'h5'
1329
+ };
1330
+ function Title({
1331
+ as,
1332
+ type = DEFAULT_TYPE,
1559
1333
  className,
1560
- disabled,
1561
- onChange,
1562
- ...rest
1563
- }, reference) => /*#__PURE__*/jsxs("span", {
1564
- className: classNames('np-checkbox-button', className, disabled && 'disabled'),
1565
- children: [/*#__PURE__*/jsx("input", {
1566
- ...rest,
1567
- ref: reference,
1568
- type: "checkbox",
1569
- disabled: disabled,
1570
- checked: checked,
1571
- onChange: onChange
1572
- }), /*#__PURE__*/jsx("span", {
1573
- className: "tw-checkbox-button",
1574
- children: /*#__PURE__*/jsx("span", {
1575
- className: "tw-checkbox-check"
1576
- })
1577
- })]
1578
- }));
1579
- var CheckboxButton$1 = CheckboxButton;
1334
+ ...props
1335
+ }) {
1336
+ const mapping = titleTypeMapping[type];
1337
+ const isTypeSupported = mapping !== undefined;
1338
+ if (isTypeSupported) {
1339
+ const HeaderTag = as ?? mapping;
1340
+ return /*#__PURE__*/jsx(HeaderTag, {
1341
+ ...props,
1342
+ className: classNames(`np-text-${type}`, className)
1343
+ });
1344
+ }
1345
+ const HeaderTag = as ?? titleTypeMapping[DEFAULT_TYPE];
1346
+ return /*#__PURE__*/jsx(HeaderTag, {
1347
+ ...props,
1348
+ className: classNames(`np-text-${DEFAULT_TYPE}`, className)
1349
+ });
1350
+ }
1580
1351
 
1581
- const Checkbox = ({
1582
- id,
1583
- checked,
1584
- required,
1585
- disabled,
1586
- readOnly,
1587
- label,
1588
- className,
1589
- secondary,
1590
- onChange,
1591
- onFocus,
1592
- onBlur
1352
+ const HeaderAction = ({
1353
+ action
1593
1354
  }) => {
1594
1355
  const {
1595
1356
  isModern
1596
1357
  } = useTheme();
1597
- const classList = classNames('np-checkbox', {
1598
- checkbox: true,
1599
- 'checkbox-lg': secondary,
1600
- disabled: isModern && disabled
1601
- }, className);
1602
- const innerDisabled = disabled || readOnly;
1603
- return /*#__PURE__*/jsx("div", {
1604
- id: id,
1605
- className: classList,
1606
- children: /*#__PURE__*/jsxs("label", {
1607
- className: classNames({
1608
- disabled
1609
- }),
1610
- children: [/*#__PURE__*/jsx(CheckboxButton$1, {
1611
- className: "p-r-2",
1612
- checked: checked,
1613
- disabled: innerDisabled,
1614
- required: !innerDisabled && required,
1615
- onFocus: onFocus,
1616
- onChange: () => onChange(!checked),
1617
- onBlur: onBlur
1618
- }), /*#__PURE__*/jsxs(Body, {
1619
- as: "span",
1620
- className: "np-checkbox__text",
1621
- type: secondary ? Typography.BODY_LARGE_BOLD : Typography.BODY_LARGE,
1622
- children: [/*#__PURE__*/jsx("span", {
1623
- className: required ? 'has-required' : undefined,
1624
- children: label
1625
- }), secondary && /*#__PURE__*/jsx(Body, {
1626
- as: "span",
1627
- className: classNames({
1628
- secondary: !isModern
1629
- }),
1630
- children: secondary
1631
- })]
1632
- })]
1633
- })
1358
+ const props = {
1359
+ 'aria-label': action['aria-label']
1360
+ };
1361
+ if ('href' in action) {
1362
+ return /*#__PURE__*/jsx(Link, {
1363
+ href: action.href,
1364
+ target: action.target,
1365
+ onClick: action.onClick,
1366
+ ...props,
1367
+ children: action.text
1368
+ });
1369
+ }
1370
+ return isModern ? /*#__PURE__*/jsx(Button, {
1371
+ className: "np-header__button",
1372
+ priority: "tertiary",
1373
+ size: "sm",
1374
+ onClick: action.onClick,
1375
+ ...props,
1376
+ children: action.text
1377
+ }) : /*#__PURE__*/jsx(ActionButton, {
1378
+ onClick: action.onClick,
1379
+ ...props,
1380
+ children: action.text
1634
1381
  });
1635
1382
  };
1636
- Checkbox.propTypes = {
1637
- id: PropTypes.string,
1638
- checked: PropTypes.bool,
1639
- required: PropTypes.bool,
1640
- disabled: PropTypes.bool,
1641
- readOnly: PropTypes.bool,
1642
- label: PropTypes.node.isRequired,
1643
- secondary: PropTypes.string,
1644
- onFocus: PropTypes.func,
1645
- onChange: PropTypes.func.isRequired,
1646
- onBlur: PropTypes.func,
1647
- className: PropTypes.string
1648
- };
1649
- Checkbox.defaultProps = {
1650
- id: null,
1651
- checked: false,
1652
- required: false,
1653
- disabled: false,
1654
- readOnly: false,
1655
- secondary: null,
1656
- onFocus: null,
1657
- onBlur: null,
1658
- className: undefined
1659
- };
1660
-
1661
- const CheckboxOption = /*#__PURE__*/forwardRef(({
1662
- checked,
1663
- disabled,
1664
- onChange,
1665
- ...rest
1666
- }, reference) => {
1667
- return /*#__PURE__*/jsx(Option$2, {
1668
- ...rest,
1669
- ref: reference,
1670
- disabled: disabled,
1671
- button: /*#__PURE__*/jsx(CheckboxButton$1, {
1672
- checked: checked,
1673
- disabled: disabled,
1674
- onChange: () => onChange?.(!checked)
1675
- })
1383
+ /**
1384
+ *
1385
+ * Neptune Web: https://transferwise.github.io/neptune-web/components/content/Header
1386
+ *
1387
+ */
1388
+ const Header = ({
1389
+ action,
1390
+ as = 'h5',
1391
+ title,
1392
+ className
1393
+ }) => {
1394
+ if (!action) {
1395
+ return /*#__PURE__*/jsx(Title, {
1396
+ as: as,
1397
+ type: Typography.TITLE_GROUP,
1398
+ className: classNames('np-header', 'np-header__title', className),
1399
+ children: title
1400
+ });
1401
+ }
1402
+ if (as === 'legend') {
1403
+ // eslint-disable-next-line no-console
1404
+ console.warn('Legends should be the first child in a fieldset, and this is not possible when including an action');
1405
+ }
1406
+ return /*#__PURE__*/jsxs("div", {
1407
+ className: classNames('np-header', className),
1408
+ children: [/*#__PURE__*/jsx(Title, {
1409
+ as: as,
1410
+ type: Typography.TITLE_GROUP,
1411
+ className: "np-header__title",
1412
+ children: title
1413
+ }), /*#__PURE__*/jsx(HeaderAction, {
1414
+ action: action
1415
+ })]
1676
1416
  });
1677
- });
1417
+ };
1678
1418
 
1679
- const Chip = ({
1680
- label,
1681
- value,
1682
- onRemove,
1683
- onClick,
1684
- onKeyPress,
1685
- className = undefined,
1686
- 'aria-label': ariaLabel,
1687
- 'aria-checked': ariaChecked,
1688
- role,
1689
- closeButton
1419
+ const useConditionalListener = ({
1420
+ attachListener,
1421
+ callback,
1422
+ eventType,
1423
+ parent
1690
1424
  }) => {
1691
- const isActionable = onClick || onKeyPress;
1692
- const defaultRole = isActionable ? 'button' : undefined;
1693
- const tabIndex = isActionable ? 0 : -1;
1694
- const {
1695
- isModern
1696
- } = useTheme();
1697
- const closeButtonReference = useRef(null);
1698
- const previousCloseButtonShown = useRef();
1699
1425
  useEffect(() => {
1700
- if (closeButtonReference.current != null && previousCloseButtonShown.current === false) {
1701
- closeButtonReference.current?.focus();
1426
+ if (attachListener && !isUndefined(parent)) {
1427
+ parent.addEventListener(eventType, callback, true);
1702
1428
  }
1703
- previousCloseButtonShown.current = closeButtonReference.current != null;
1704
- }, [onRemove]);
1705
- return /*#__PURE__*/jsxs("div", {
1706
- role: role ?? defaultRole,
1707
- tabIndex: tabIndex,
1708
- "aria-label": ariaLabel,
1709
- "aria-checked": ariaChecked,
1710
- className: classNames('np-chip', 'd-flex', 'align-items-center', 'justify-content-between', onRemove ? 'np-chip--removable' : '', className),
1711
- ...(isActionable && {
1712
- onClick,
1713
- onKeyPress
1714
- }),
1715
- children: [isModern ? /*#__PURE__*/jsx(Body, {
1716
- "aria-hidden": !!onRemove,
1717
- type: Typography.BODY_DEFAULT_BOLD,
1718
- children: label
1719
- }) : /*#__PURE__*/jsx("span", {
1720
- "aria-hidden": "false",
1721
- className: "np-chip-label",
1722
- children: label
1723
- }), onRemove ? /*#__PURE__*/jsx(CloseButton, {
1724
- ref: closeButtonReference,
1725
- className: isModern ? `btn-unstyled` : `btn-unstyled m-l-1`,
1726
- "aria-label": closeButton && closeButton['aria-label'],
1727
- size: "sm",
1728
- filled: isModern,
1729
- onClick: onRemove
1730
- }) : null]
1731
- }, value);
1429
+ return () => {
1430
+ if (!isUndefined(parent)) {
1431
+ parent.removeEventListener(eventType, callback, true);
1432
+ }
1433
+ };
1434
+ }, [attachListener, callback, eventType, parent]);
1732
1435
  };
1733
1436
 
1734
- var messages$a = defineMessages({
1735
- ariaLabel: {
1736
- id: "neptune.Chips.ariaLabel"
1737
- }
1738
- });
1739
-
1740
- const Chips = ({
1741
- chips,
1742
- onChange,
1743
- selected,
1744
- 'aria-label': ariaLabel,
1745
- className,
1746
- multiple
1437
+ const DirectionContext = /*#__PURE__*/createContext(Direction.LTR);
1438
+ const DirectionProvider = ({
1439
+ direction,
1440
+ children
1747
1441
  }) => {
1748
- const intl = useIntl();
1749
- const isSelected = value => Array.isArray(selected) ? selected.includes(value) : selected === value;
1750
- const handleOnChange = (selectedValue, isCurrentlyEnabled) => {
1751
- onChange({
1752
- isEnabled: !isCurrentlyEnabled,
1753
- selectedValue
1754
- });
1755
- };
1756
- return /*#__PURE__*/jsx("div", {
1757
- className: classNames('np-chips d-flex', className),
1758
- "aria-label": ariaLabel,
1759
- role: !multiple ? 'radiogroup' : undefined,
1760
- children: chips.map(chip => {
1761
- const chipSelected = isSelected(chip.value);
1762
- return /*#__PURE__*/jsx(Chip, {
1763
- value: chip.value,
1764
- label: chip.label,
1765
- closeButton: {
1766
- 'aria-label': intl.formatMessage(messages$a.ariaLabel, {
1767
- choice: chip.label
1768
- })
1769
- },
1770
- className: classNames('text-xs-nowrap', {
1771
- 'np-chip--selected': chipSelected,
1772
- 'p-r-1': multiple && chipSelected
1773
- }),
1774
- ...(multiple && chipSelected ? {
1775
- onRemove: () => handleOnChange(chip.value, chipSelected),
1776
- 'aria-label': chip.label
1777
- } : {
1778
- onClick: () => handleOnChange(chip.value, chipSelected),
1779
- onKeyPress: () => handleOnChange(chip.value, chipSelected),
1780
- role: !multiple ? 'radio' : undefined,
1781
- 'aria-checked': chipSelected
1782
- })
1783
- }, chip.value);
1784
- })
1442
+ return /*#__PURE__*/jsx(DirectionContext.Provider, {
1443
+ value: direction,
1444
+ children: children
1785
1445
  });
1786
1446
  };
1787
1447
 
1788
- const CircularButton = ({
1789
- className,
1790
- children,
1791
- disabled,
1792
- icon,
1793
- priority = Priority.PRIMARY,
1794
- type = ControlType.ACCENT,
1795
- ...rest
1796
- }) => {
1797
- const classes = classNames('btn np-btn', typeClassMap[type], priorityClassMap[priority]);
1798
- const iconElement = Number(icon.props.size) !== 24 ? /*#__PURE__*/cloneElement(icon, {
1799
- size: 24
1800
- }) : icon;
1801
- return /*#__PURE__*/jsxs("label", {
1802
- className: classNames('np-circular-btn', priority, type, disabled && 'disabled', className),
1803
- children: [/*#__PURE__*/jsx("input", {
1804
- type: "button",
1805
- "aria-label": children,
1806
- className: classes,
1807
- disabled: disabled,
1808
- ...rest
1809
- }), iconElement, /*#__PURE__*/jsx(Body, {
1810
- as: "span",
1811
- className: "np-circular-btn__label",
1812
- type: Typography.BODY_DEFAULT_BOLD,
1813
- children: children
1814
- })]
1815
- });
1448
+ const useDirection = () => {
1449
+ const direction = useContext(DirectionContext);
1450
+ return {
1451
+ direction,
1452
+ isRTL: direction === 'rtl'
1453
+ };
1816
1454
  };
1817
1455
 
1818
- const FocusBoundary = ({
1819
- children
1456
+ const ObserverParams = {
1457
+ threshold: 0.1
1458
+ };
1459
+
1460
+ /**
1461
+ * useHasIntersected.
1462
+ * Use this custom hook to detect when an element has became visible inside the viewport. This hook checks only if the intersection happend.
1463
+ * Once the intersection has happened the hook will not return false even if the element gets out of the viewport.
1464
+ *
1465
+ * @param elRef.elRef
1466
+ * @param {object} [elRef] - node object that contains a react reference to the element that needs to be observed.
1467
+ * @param {strimng} [loading = 'eager'] - string that contains the type of loading.
1468
+ * @param elRef.loading
1469
+ * @usage `const [hasIntersected] = useHasIntersected({imageRef,loading});`
1470
+ */
1471
+ const useHasIntersected = ({
1472
+ elRef,
1473
+ loading
1820
1474
  }) => {
1821
- const wrapperReference = useRef(null);
1822
- useEffect(() => {
1823
- wrapperReference.current?.focus({
1824
- preventScroll: true
1475
+ const [hasIntersected, setHasIntersected] = useState(false);
1476
+ const {
1477
+ current
1478
+ } = elRef || {};
1479
+ const isValidReference = () => {
1480
+ return elRef && current;
1481
+ };
1482
+ const handleOnIntersect = (entries, observer) => {
1483
+ entries.forEach(entry => {
1484
+ if (entry.isIntersecting) {
1485
+ setHasIntersected(true);
1486
+ observer.unobserve(current);
1487
+ }
1825
1488
  });
1826
- }, []);
1827
- return /*#__PURE__*/jsx(FocusScope, {
1828
- contain: true,
1829
- restoreFocus: true,
1830
- children: /*#__PURE__*/jsx("div", {
1831
- ref: wrapperReference,
1832
- tabIndex: -1,
1833
- children: children
1834
- })
1835
- });
1489
+ };
1490
+ useEffect(() => {
1491
+ let observer;
1492
+ let didCancel = false;
1493
+
1494
+ // Check if window is define for SSR and Old browsers fallback
1495
+ if (typeof window === 'undefined' || !window.IntersectionObserver || !isValidReference()) {
1496
+ setHasIntersected(true);
1497
+ } else if (!didCancel) {
1498
+ observer = new IntersectionObserver(handleOnIntersect, ObserverParams);
1499
+ observer.observe(current);
1500
+ }
1501
+ return () => {
1502
+ didCancel = true;
1503
+ if (observer) {
1504
+ observer.unobserve(current);
1505
+ }
1506
+ };
1507
+ }, [elRef]);
1508
+ if (loading === 'eager') {
1509
+ return [false];
1510
+ }
1511
+ return [hasIntersected];
1836
1512
  };
1837
1513
 
1838
- function withNextPortalWrapper(Component) {
1839
- return function (props) {
1840
- const [mounted, setMounted] = useState(false);
1841
- useEffect(() => {
1842
- setMounted(true);
1843
- }, [setMounted]);
1844
- return mounted ? /*#__PURE__*/createPortal( /*#__PURE__*/jsx(Component, {
1845
- ...props
1846
- }), document.body) : null;
1847
- };
1514
+ // eslint-disable-next-line import/extensions
1515
+ function useMedia(query) {
1516
+ return useSyncExternalStore(onStoreChange => {
1517
+ const mediaQueryList = window.matchMedia(query);
1518
+ mediaQueryList.addEventListener('change', onStoreChange);
1519
+ return () => {
1520
+ mediaQueryList.removeEventListener('change', onStoreChange);
1521
+ };
1522
+ }, () => typeof window !== 'undefined' ? window.matchMedia(query).matches : undefined, () => undefined);
1523
+ }
1524
+
1525
+ function useScreenSize(size) {
1526
+ return useMedia(`(min-width: ${size}px)`);
1848
1527
  }
1849
1528
 
1850
1529
  /**
1851
- * Dimmer state management inspired by Material UI's ModalManager (https://github.com/mui-org/material-ui)
1530
+ * @deprecated Prefer `useScreenSize` instead.
1852
1531
  */
1853
- class DimmerManager {
1854
- /**
1855
- * Dimmer refs
1856
- */
1857
- dimmers;
1858
- constructor() {
1859
- this.dimmers = [];
1860
- }
1861
- add(dimmer) {
1862
- let dimmerIndex = this.dimmers.indexOf(dimmer);
1863
- if (dimmerIndex !== -1) {
1864
- return dimmerIndex;
1865
- }
1866
- dimmerIndex = this.dimmers.length;
1867
- this.dimmers.push(dimmer);
1868
- return dimmerIndex;
1869
- }
1870
- remove(dimmer) {
1871
- const dimmerIndex = this.dimmers.indexOf(dimmer);
1872
- if (dimmerIndex !== -1) {
1873
- this.dimmers.splice(dimmerIndex, 1);
1874
- }
1875
- return dimmerIndex;
1876
- }
1877
- isTop(dimmer) {
1878
- return this.dimmers.length > 0 && this.dimmers[this.dimmers.length - 1] === dimmer;
1879
- }
1880
- }
1532
+ const useLayout = () => {
1533
+ const screenXs = useScreenSize(Breakpoint.EXTRA_SMALL);
1534
+ const screenSm = useScreenSize(Breakpoint.SMALL);
1535
+ const screenMd = useScreenSize(Breakpoint.MEDIUM);
1536
+ const screenLg = useScreenSize(Breakpoint.LARGE);
1537
+ const screenXl = useScreenSize(Breakpoint.EXTRA_LARGE);
1538
+ return {
1539
+ isMobile: screenSm != null ? !screenSm : undefined,
1540
+ isExtraSmall: screenXs,
1541
+ isSmall: screenSm,
1542
+ isMedium: screenMd,
1543
+ isLarge: screenLg,
1544
+ isExtraLarge: screenXl
1545
+ };
1546
+ };
1881
1547
 
1882
- const EXIT_ANIMATION$1 = 350;
1883
- const dimmerManager = new DimmerManager();
1884
- const handleTouchMove = event => {
1885
- const isTouchedElementDimmer = event.target.classList.contains('dimmer');
1886
- // disable scroll on iOS devices for Dimmer area
1887
- // this is because of bug in WebKit https://bugs.webkit.org/show_bug.cgi?id=220908
1888
- // note: scrolling still works for children(s) as expected
1889
- if (isIosDevice() && isTouchedElementDimmer) {
1890
- event.stopPropagation();
1891
- event.preventDefault();
1548
+ var messages$b = defineMessages({
1549
+ ariaLabel: {
1550
+ id: "neptune.CloseButton.ariaLabel"
1892
1551
  }
1893
- };
1894
- const Dimmer = ({
1552
+ });
1553
+
1554
+ const CloseButton = /*#__PURE__*/forwardRef(function CloseButton({
1555
+ 'aria-label': ariaLabel,
1556
+ size = Size.MEDIUM,
1557
+ filled = false,
1558
+ className,
1559
+ onClick,
1560
+ isDisabled,
1561
+ testId
1562
+ }, reference) {
1563
+ const intl = useIntl();
1564
+ ariaLabel ??= intl.formatMessage(messages$b.ariaLabel);
1565
+ const Icon = filled ? CrossCircleFill : Cross;
1566
+ return /*#__PURE__*/jsx("button", {
1567
+ ref: reference,
1568
+ type: "button",
1569
+ className: classNames('np-close-button', 'close btn-link', 'text-no-decoration', {
1570
+ 'np-close-button--large': size === Size.MEDIUM,
1571
+ 'np-close-button--x-large': size === Size.LARGE
1572
+ }, className),
1573
+ "aria-label": ariaLabel,
1574
+ "aria-disabled": isDisabled,
1575
+ disabled: isDisabled,
1576
+ "data-testid": testId,
1577
+ onClick: onClick,
1578
+ children: /*#__PURE__*/jsx(Icon, {
1579
+ size: size === Size.SMALL ? 16 : 24
1580
+ })
1581
+ });
1582
+ });
1583
+
1584
+ const EXIT_ANIMATION = 350;
1585
+ const SlidingPanel = /*#__PURE__*/forwardRef(({
1586
+ position = 'left',
1587
+ open,
1588
+ showSlidingPanelBorder,
1589
+ slidingPanelPositionFixed,
1590
+ className,
1591
+ children,
1592
+ ...rest
1593
+ }, reference) => {
1594
+ const localReference = useRef(null);
1595
+ useImperativeHandle(reference, () => localReference.current, []);
1596
+ return /*#__PURE__*/createElement(CSSTransition, {
1597
+ ...rest,
1598
+ key: `sliding-panel--open-${position}`,
1599
+ nodeRef: localReference,
1600
+ in: open
1601
+ // Wait for animation to finish before unmount.
1602
+ ,
1603
+ timeout: {
1604
+ enter: 0,
1605
+ exit: EXIT_ANIMATION
1606
+ },
1607
+ classNames: "sliding-panel",
1608
+ appear: true,
1609
+ unmountOnExit: true
1610
+ }, /*#__PURE__*/jsx("div", {
1611
+ ref: localReference,
1612
+ className: classNames('sliding-panel', `sliding-panel--open-${position}`, showSlidingPanelBorder && `sliding-panel--border-${position}`, slidingPanelPositionFixed && 'sliding-panel--fixed', className),
1613
+ children: children
1614
+ }));
1615
+ });
1616
+
1617
+ const Drawer = ({
1895
1618
  children,
1896
1619
  className,
1897
- disableClickToClose = false,
1898
- contentPosition,
1899
- fadeContentOnEnter = false,
1900
- fadeContentOnExit = false,
1901
- open = false,
1902
- scrollable = false,
1903
- transparent = false,
1904
- onClose
1620
+ footerContent,
1621
+ headerTitle,
1622
+ onClose,
1623
+ open,
1624
+ position
1905
1625
  }) => {
1906
- const [hasNotExited, setHasNotExited] = useState(false);
1907
- const dimmerReference = useRef(null);
1908
- const closeOnClick = event => {
1909
- if (event.target === dimmerReference.current) {
1910
- onClose?.(event);
1911
- }
1912
- };
1913
- const handleClick = event => {
1914
- if (disableClickToClose || !onClose) {
1915
- return;
1916
- }
1917
- closeOnClick(event);
1918
- };
1919
- const handleKeyDown = useCallback(event => {
1920
- if (event.key !== 'Escape') {
1921
- return;
1922
- }
1923
- event.stopPropagation();
1924
- if (onClose && dimmerReference.current && dimmerManager.isTop(dimmerReference.current)) {
1925
- onClose(event);
1926
- }
1927
- }, [onClose]);
1928
- const onEnter = () => {
1929
- setHasNotExited(true);
1930
- if (dimmerReference.current) {
1931
- dimmerManager.add(dimmerReference.current);
1932
- }
1933
- };
1934
- const onExited = () => {
1935
- setHasNotExited(false);
1936
- if (dimmerReference.current) {
1937
- dimmerManager.remove(dimmerReference.current);
1938
- }
1939
- };
1940
- useEffect(() => {
1941
- const localReferenceCopy = dimmerReference.current;
1942
- if (open) {
1943
- document.addEventListener('keydown', handleKeyDown);
1944
- localReferenceCopy?.addEventListener('touchmove', handleTouchMove, {
1945
- passive: true
1946
- });
1947
- }
1948
- return () => {
1949
- document.removeEventListener('keydown', handleKeyDown);
1950
- localReferenceCopy?.removeEventListener('touchmove', handleTouchMove);
1951
- };
1952
- }, [handleKeyDown, open]);
1953
- return /*#__PURE__*/jsx(DimmerWrapper, {
1626
+ logActionRequiredIf('Drawer now expects `onClose`, and will soon make this prop required. Please update your usage to provide it.', !onClose);
1627
+ const {
1628
+ isMobile
1629
+ } = useLayout();
1630
+ const titleId = useId();
1631
+ return /*#__PURE__*/jsx(Dimmer$1, {
1954
1632
  open: open,
1955
- hasNotExited: hasNotExited,
1956
- children: /*#__PURE__*/jsx(CSSTransition, {
1957
- nodeRef: dimmerReference,
1958
- in: open,
1959
- appear: true
1960
- // Wait for animation to finish before unmount.
1961
- ,
1962
- timeout: {
1963
- enter: 0,
1964
- exit: EXIT_ANIMATION$1
1965
- },
1966
- classNames: {
1967
- enter: classNames({
1968
- 'dimmer--enter-fade': fadeContentOnEnter
1969
- }),
1970
- enterDone: classNames('dimmer--enter-done', {
1971
- 'dimmer--enter-fade': fadeContentOnEnter
1972
- }),
1973
- exit: classNames('dimmer--exit', {
1974
- 'dimmer--exit-fade': fadeContentOnExit
1975
- })
1976
- },
1977
- unmountOnExit: true,
1978
- onEnter: onEnter,
1979
- onExited: onExited,
1980
- children: /*#__PURE__*/jsx(DimmerContentWrapper, {
1981
- scrollBody: !transparent,
1982
- children: /*#__PURE__*/jsx(FocusBoundary, {
1983
- children: /*#__PURE__*/jsx("div", {
1984
- ref: dimmerReference,
1985
- className: classNames('dimmer', {
1986
- 'dimmer--scrollable': scrollable,
1987
- 'dimmer--transparent': transparent
1988
- }, className),
1989
- role: "presentation",
1990
- onClick: handleClick,
1991
- children: /*#__PURE__*/jsx("div", {
1992
- className: classNames('dimmer-content-positioner', contentPosition != null && ['d-flex justify-content-center', {
1993
- 'align-items-start': contentPosition === 'top',
1994
- 'align-items-center': contentPosition === 'center',
1995
- 'align-items-end': contentPosition === 'bottom'
1996
- }]),
1997
- children: children
1998
- })
1999
- })
2000
- })
1633
+ onClose: onClose,
1634
+ children: /*#__PURE__*/jsx(SlidingPanel, {
1635
+ open: open,
1636
+ position: isMobile ? Position.BOTTOM : position,
1637
+ children: /*#__PURE__*/jsxs("div", {
1638
+ role: "dialog",
1639
+ "aria-modal": true,
1640
+ "aria-labelledby": headerTitle ? titleId : undefined,
1641
+ className: classNames('np-drawer', className),
1642
+ children: [/*#__PURE__*/jsxs("div", {
1643
+ className: classNames('np-drawer-header', {
1644
+ 'np-drawer-header--withborder': headerTitle
1645
+ }),
1646
+ children: [headerTitle && /*#__PURE__*/jsx(Title, {
1647
+ id: titleId,
1648
+ type: Typography.TITLE_BODY,
1649
+ children: headerTitle
1650
+ }), /*#__PURE__*/jsx(CloseButton, {
1651
+ onClick: onClose
1652
+ })]
1653
+ }), children && /*#__PURE__*/jsx("div", {
1654
+ className: classNames('np-drawer-content'),
1655
+ children: children
1656
+ }), footerContent && /*#__PURE__*/jsx("div", {
1657
+ className: classNames('np-drawer-footer'),
1658
+ children: footerContent
1659
+ })]
2001
1660
  })
2002
1661
  })
2003
1662
  });
2004
1663
  };
2005
- const DimmerWrapper = ({
2006
- open,
2007
- hasNotExited,
2008
- children
2009
- }) => {
2010
- const {
2011
- screenMode,
2012
- theme
2013
- } = useTheme();
2014
- return open || hasNotExited ? /*#__PURE__*/jsx(ThemeProvider, {
2015
- theme: "personal",
2016
- screenMode: theme === 'personal' ? screenMode : 'light',
2017
- isNotRootProvider: true,
2018
- children: children
2019
- }) : /*#__PURE__*/jsx(Fragment, {
2020
- children: children
2021
- });
2022
- };
2023
- const DimmerContentWrapper = ({
2024
- children,
2025
- scrollBody
2026
- }) => {
2027
- useEffect(() => {
2028
- if (scrollBody) {
2029
- addNoScrollClass();
2030
- }
2031
- return () => {
2032
- if (scrollBody) {
2033
- removeNoScrollClass();
2034
- }
2035
- };
2036
- }, [scrollBody]);
2037
- return children;
2038
- };
2039
- var Dimmer$1 = withNextPortalWrapper(Dimmer);
2040
-
2041
- const useConditionalListener = ({
2042
- attachListener,
2043
- callback,
2044
- eventType,
2045
- parent
2046
- }) => {
2047
- useEffect(() => {
2048
- if (attachListener && !isUndefined(parent)) {
2049
- parent.addEventListener(eventType, callback, true);
2050
- }
2051
- return () => {
2052
- if (!isUndefined(parent)) {
2053
- parent.removeEventListener(eventType, callback, true);
2054
- }
2055
- };
2056
- }, [attachListener, callback, eventType, parent]);
2057
- };
2058
-
2059
- const DirectionContext = /*#__PURE__*/createContext(Direction.LTR);
2060
- const DirectionProvider = ({
2061
- direction,
2062
- children
2063
- }) => {
2064
- return /*#__PURE__*/jsx(DirectionContext.Provider, {
2065
- value: direction,
2066
- children: children
2067
- });
2068
- };
2069
-
2070
- const useDirection = () => {
2071
- const direction = useContext(DirectionContext);
2072
- return {
2073
- direction,
2074
- isRTL: direction === 'rtl'
2075
- };
1664
+ Drawer.propTypes = {
1665
+ /** The content to appear in the drawer body. */
1666
+ children: PropTypes.node,
1667
+ className: PropTypes.string,
1668
+ /** The content to appear in the drawer footer. */
1669
+ footerContent: PropTypes.node,
1670
+ /** The content to appear in the drawer header. */
1671
+ headerTitle: PropTypes.node,
1672
+ /** The action to perform on close click. */
1673
+ onClose: PropTypes.func,
1674
+ /** The status of Drawer either open or not. */
1675
+ open: PropTypes.bool,
1676
+ /** The placement of Drawer on the screen either left or right. On mobile it will default to bottom. */
1677
+ position: PropTypes.oneOf(['left', 'right', 'bottom'])
2076
1678
  };
2077
-
2078
- const ObserverParams = {
2079
- threshold: 0.1
1679
+ Drawer.defaultProps = {
1680
+ children: null,
1681
+ className: undefined,
1682
+ footerContent: null,
1683
+ headerTitle: null,
1684
+ onClose: null,
1685
+ open: false,
1686
+ position: Position.RIGHT
2080
1687
  };
1688
+ var Drawer$1 = Drawer;
2081
1689
 
1690
+ const INITIAL_Y_POSITION = 0;
1691
+ const CONTENT_SCROLL_THRESHOLD = 1;
1692
+ const MOVE_OFFSET_THRESHOLD = 50;
2082
1693
  /**
2083
- * useHasIntersected.
2084
- * Use this custom hook to detect when an element has became visible inside the viewport. This hook checks only if the intersection happend.
2085
- * Once the intersection has happened the hook will not return false even if the element gets out of the viewport.
2086
- *
2087
- * @param elRef.elRef
2088
- * @param {object} [elRef] - node object that contains a react reference to the element that needs to be observed.
2089
- * @param {strimng} [loading = 'eager'] - string that contains the type of loading.
2090
- * @param elRef.loading
2091
- * @usage `const [hasIntersected] = useHasIntersected({imageRef,loading});`
2092
- */
2093
- const useHasIntersected = ({
2094
- elRef,
2095
- loading
2096
- }) => {
2097
- const [hasIntersected, setHasIntersected] = useState(false);
2098
- const {
2099
- current
2100
- } = elRef || {};
2101
- const isValidReference = () => {
2102
- return elRef && current;
2103
- };
2104
- const handleOnIntersect = (entries, observer) => {
2105
- entries.forEach(entry => {
2106
- if (entry.isIntersecting) {
2107
- setHasIntersected(true);
2108
- observer.unobserve(current);
2109
- }
2110
- });
2111
- };
2112
- useEffect(() => {
2113
- let observer;
2114
- let didCancel = false;
2115
-
2116
- // Check if window is define for SSR and Old browsers fallback
2117
- if (typeof window === 'undefined' || !window.IntersectionObserver || !isValidReference()) {
2118
- setHasIntersected(true);
2119
- } else if (!didCancel) {
2120
- observer = new IntersectionObserver(handleOnIntersect, ObserverParams);
2121
- observer.observe(current);
2122
- }
2123
- return () => {
2124
- didCancel = true;
2125
- if (observer) {
2126
- observer.unobserve(current);
2127
- }
2128
- };
2129
- }, [elRef]);
2130
- if (loading === 'eager') {
2131
- return [false];
2132
- }
2133
- return [hasIntersected];
2134
- };
2135
-
2136
- // eslint-disable-next-line import/extensions
2137
- function useMedia(query) {
2138
- return useSyncExternalStore(onStoreChange => {
2139
- const mediaQueryList = window.matchMedia(query);
2140
- mediaQueryList.addEventListener('change', onStoreChange);
2141
- return () => {
2142
- mediaQueryList.removeEventListener('change', onStoreChange);
2143
- };
2144
- }, () => typeof window !== 'undefined' ? window.matchMedia(query).matches : undefined, () => undefined);
2145
- }
2146
-
2147
- function useScreenSize(size) {
2148
- return useMedia(`(min-width: ${size}px)`);
2149
- }
2150
-
2151
- /**
2152
- * @deprecated Prefer `useScreenSize` instead.
2153
- */
2154
- const useLayout = () => {
2155
- const screenXs = useScreenSize(Breakpoint.EXTRA_SMALL);
2156
- const screenSm = useScreenSize(Breakpoint.SMALL);
2157
- const screenMd = useScreenSize(Breakpoint.MEDIUM);
2158
- const screenLg = useScreenSize(Breakpoint.LARGE);
2159
- const screenXl = useScreenSize(Breakpoint.EXTRA_LARGE);
2160
- return {
2161
- isMobile: screenSm != null ? !screenSm : undefined,
2162
- isExtraSmall: screenXs,
2163
- isSmall: screenSm,
2164
- isMedium: screenMd,
2165
- isLarge: screenLg,
2166
- isExtraLarge: screenXl
2167
- };
2168
- };
2169
-
2170
- const EXIT_ANIMATION = 350;
2171
- const SlidingPanel = /*#__PURE__*/forwardRef(({
2172
- position = 'left',
2173
- open,
2174
- showSlidingPanelBorder,
2175
- slidingPanelPositionFixed,
2176
- className,
2177
- children,
2178
- ...rest
2179
- }, reference) => {
2180
- const localReference = useRef(null);
2181
- useImperativeHandle(reference, () => localReference.current, []);
2182
- return /*#__PURE__*/createElement(CSSTransition, {
2183
- ...rest,
2184
- key: `sliding-panel--open-${position}`,
2185
- nodeRef: localReference,
2186
- in: open
2187
- // Wait for animation to finish before unmount.
2188
- ,
2189
- timeout: {
2190
- enter: 0,
2191
- exit: EXIT_ANIMATION
2192
- },
2193
- classNames: "sliding-panel",
2194
- appear: true,
2195
- unmountOnExit: true
2196
- }, /*#__PURE__*/jsx("div", {
2197
- ref: localReference,
2198
- className: classNames('sliding-panel', `sliding-panel--open-${position}`, showSlidingPanelBorder && `sliding-panel--border-${position}`, slidingPanelPositionFixed && 'sliding-panel--fixed', className),
2199
- children: children
2200
- }));
2201
- });
2202
-
2203
- const Drawer = ({
2204
- children,
2205
- className,
2206
- footerContent,
2207
- headerTitle,
2208
- onClose,
2209
- open,
2210
- position
2211
- }) => {
2212
- logActionRequiredIf('Drawer now expects `onClose`, and will soon make this prop required. Please update your usage to provide it.', !onClose);
2213
- const {
2214
- isMobile
2215
- } = useLayout();
2216
- const titleId = useId();
2217
- return /*#__PURE__*/jsx(Dimmer$1, {
2218
- open: open,
2219
- onClose: onClose,
2220
- children: /*#__PURE__*/jsx(SlidingPanel, {
2221
- open: open,
2222
- position: isMobile ? Position.BOTTOM : position,
2223
- children: /*#__PURE__*/jsxs("div", {
2224
- role: "dialog",
2225
- "aria-modal": true,
2226
- "aria-labelledby": headerTitle ? titleId : undefined,
2227
- className: classNames('np-drawer', className),
2228
- children: [/*#__PURE__*/jsxs("div", {
2229
- className: classNames('np-drawer-header', {
2230
- 'np-drawer-header--withborder': headerTitle
2231
- }),
2232
- children: [headerTitle && /*#__PURE__*/jsx(Title, {
2233
- id: titleId,
2234
- type: Typography.TITLE_BODY,
2235
- children: headerTitle
2236
- }), /*#__PURE__*/jsx(CloseButton, {
2237
- onClick: onClose
2238
- })]
2239
- }), children && /*#__PURE__*/jsx("div", {
2240
- className: classNames('np-drawer-content'),
2241
- children: children
2242
- }), footerContent && /*#__PURE__*/jsx("div", {
2243
- className: classNames('np-drawer-footer'),
2244
- children: footerContent
2245
- })]
2246
- })
2247
- })
2248
- });
2249
- };
2250
- Drawer.propTypes = {
2251
- /** The content to appear in the drawer body. */
2252
- children: PropTypes.node,
2253
- className: PropTypes.string,
2254
- /** The content to appear in the drawer footer. */
2255
- footerContent: PropTypes.node,
2256
- /** The content to appear in the drawer header. */
2257
- headerTitle: PropTypes.node,
2258
- /** The action to perform on close click. */
2259
- onClose: PropTypes.func,
2260
- /** The status of Drawer either open or not. */
2261
- open: PropTypes.bool,
2262
- /** The placement of Drawer on the screen either left or right. On mobile it will default to bottom. */
2263
- position: PropTypes.oneOf(['left', 'right', 'bottom'])
2264
- };
2265
- Drawer.defaultProps = {
2266
- children: null,
2267
- className: undefined,
2268
- footerContent: null,
2269
- headerTitle: null,
2270
- onClose: null,
2271
- open: false,
2272
- position: Position.RIGHT
2273
- };
2274
- var Drawer$1 = Drawer;
2275
-
2276
- const INITIAL_Y_POSITION = 0;
2277
- const CONTENT_SCROLL_THRESHOLD = 1;
2278
- const MOVE_OFFSET_THRESHOLD = 50;
2279
- /**
2280
- * Neptune: https://transferwise.github.io/neptune/components/bottom-sheet/
2281
- *
2282
- * Neptune Web: https://transferwise.github.io/neptune-web/components/overlays/BottomSheet
1694
+ * Neptune: https://transferwise.github.io/neptune/components/bottom-sheet/
1695
+ *
1696
+ * Neptune Web: https://transferwise.github.io/neptune-web/components/overlays/BottomSheet
2283
1697
  *
2284
1698
  */
2285
1699
  const BottomSheet$1 = props => {
@@ -2446,6 +1860,928 @@ const BottomSheet$1 = props => {
2446
1860
  });
2447
1861
  };
2448
1862
 
1863
+ function SelectOption({
1864
+ selected: selectedValueProp = undefined,
1865
+ ...props
1866
+ }) {
1867
+ const rootRef = useRef(null);
1868
+ const [selected, setSelected] = useState(selectedValueProp);
1869
+ const [showMenu, setShowMenu] = useState(false);
1870
+ function handleOnClick(status) {
1871
+ return () => {
1872
+ console.log('handleOnClick', status);
1873
+ setShowMenu(status);
1874
+ };
1875
+ }
1876
+ function handleOnSelect(data) {
1877
+ return () => {
1878
+ setShowMenu(false);
1879
+ setSelected(data);
1880
+ };
1881
+ }
1882
+ const isSelected = selected !== undefined;
1883
+ const {
1884
+ isMobile
1885
+ } = useLayout();
1886
+ const options = /*#__PURE__*/jsxs(Section, {
1887
+ children: [/*#__PURE__*/jsx(Header, {
1888
+ title: "Payment Methods"
1889
+ }), /*#__PURE__*/jsx(Option$2, {
1890
+ media: /*#__PURE__*/jsx(Flag, {
1891
+ code: "gbp"
1892
+ }),
1893
+ title: "Wise GBP balance",
1894
+ content: /*#__PURE__*/jsxs(Fragment, {
1895
+ children: [/*#__PURE__*/jsx("span", {
1896
+ children: "300 GBP available"
1897
+ }), /*#__PURE__*/jsx("span", {
1898
+ children: "0 GBP in fees, should arrive in seconds"
1899
+ })]
1900
+ }),
1901
+ onClick: handleOnSelect({
1902
+ media: /*#__PURE__*/jsx(Flag, {
1903
+ code: "gbp"
1904
+ }),
1905
+ title: 'Wise GBP balance'
1906
+ })
1907
+ }), /*#__PURE__*/jsx(Option$2, {
1908
+ media: /*#__PURE__*/jsx(Card$3, {}),
1909
+ title: "Credit card",
1910
+ content: /*#__PURE__*/jsxs(Fragment, {
1911
+ children: [/*#__PURE__*/jsx("div", {
1912
+ children: "Transfer the money to Wise using your bank account."
1913
+ }), /*#__PURE__*/jsx("div", {
1914
+ children: "0.32 GBP in fees, should arrive in seconds"
1915
+ })]
1916
+ }),
1917
+ onClick: handleOnSelect({
1918
+ media: /*#__PURE__*/jsx(Card$3, {}),
1919
+ title: 'Credit card',
1920
+ content: 'Pay with your credit card'
1921
+ })
1922
+ }), /*#__PURE__*/jsx(Option$2, {
1923
+ media: /*#__PURE__*/jsx(Card$3, {}),
1924
+ title: "Debit card",
1925
+ content: /*#__PURE__*/jsxs(Fragment, {
1926
+ children: [/*#__PURE__*/jsx("span", {
1927
+ children: "Send from your Visa or Mastercard."
1928
+ }), /*#__PURE__*/jsx("span", {
1929
+ children: "0.74 GBP in fees, should arrive in seconds"
1930
+ })]
1931
+ }),
1932
+ onClick: handleOnSelect({
1933
+ media: /*#__PURE__*/jsx(Card$3, {}),
1934
+ title: 'Debit card',
1935
+ content: 'Pay with your debit card'
1936
+ })
1937
+ }), /*#__PURE__*/jsx(Option$2, {
1938
+ media: /*#__PURE__*/jsx(Bank, {}),
1939
+ title: "Swift Transfer",
1940
+ content: /*#__PURE__*/jsxs(Fragment, {
1941
+ children: [/*#__PURE__*/jsx("span", {
1942
+ children: "Send money internationally. Your bank will charge you extra fees."
1943
+ }), /*#__PURE__*/jsx("span", {
1944
+ children: "0.32 GBP in fees, should arrive by Thursday"
1945
+ })]
1946
+ })
1947
+ }), /*#__PURE__*/jsx(Option$2, {
1948
+ media: /*#__PURE__*/jsx(BankTransfer, {}),
1949
+ title: "Bank Transfer",
1950
+ content: /*#__PURE__*/jsxs(Fragment, {
1951
+ children: [/*#__PURE__*/jsx("span", {
1952
+ children: "Transfer the money to Wise using your bank account."
1953
+ }), /*#__PURE__*/jsx("span", {
1954
+ children: "0.32 GBP in fees, should arrive in seconds"
1955
+ })]
1956
+ })
1957
+ }), /*#__PURE__*/jsx(Option$2, {
1958
+ media: /*#__PURE__*/jsx(Card$3, {}),
1959
+ title: "Debit card"
1960
+ }), /*#__PURE__*/jsx(Option$2, {
1961
+ media: /*#__PURE__*/jsx(Bank, {}),
1962
+ title: "Swift"
1963
+ }), /*#__PURE__*/jsx(Option$2, {
1964
+ media: /*#__PURE__*/jsx(BankTransfer, {}),
1965
+ title: "Bank Transfer"
1966
+ })]
1967
+ });
1968
+ return /*#__PURE__*/jsxs(Fragment, {
1969
+ children: [/*#__PURE__*/jsx(Option$2, {
1970
+ ref: rootRef,
1971
+ media: isSelected ? selected.media : props.media,
1972
+ title: isSelected ? selected.title : props.title,
1973
+ content: isSelected ? selected.content : props.content,
1974
+ className: classNames('np-select-option', {
1975
+ 'np-select-option-selected': isSelected
1976
+ }, props.className),
1977
+ button: isSelected ? /*#__PURE__*/jsx(Chevron, {}) : /*#__PURE__*/jsx(ActionButton, {
1978
+ onClick: handleOnClick(true),
1979
+ children: "Choose"
1980
+ }),
1981
+ onClick: isSelected ? handleOnClick(true) : undefined
1982
+ }), isMobile ? /*#__PURE__*/jsx(BottomSheet$1, {
1983
+ open: showMenu,
1984
+ onClose: handleOnClick(false),
1985
+ children: options
1986
+ }) : /*#__PURE__*/jsx(Panel, {
1987
+ open: showMenu,
1988
+ flip: false,
1989
+ altAxis: true,
1990
+ anchorRef: rootRef,
1991
+ anchorWidth: false,
1992
+ position: Position.BOTTOM,
1993
+ onClose: handleOnClick(false),
1994
+ children: /*#__PURE__*/jsx("div", {
1995
+ className: "np-select-option-list p-a-2",
1996
+ children: options
1997
+ })
1998
+ })]
1999
+ });
2000
+ }
2001
+
2002
+ const iconTypeMap = {
2003
+ positive: Check,
2004
+ neutral: Info$1,
2005
+ warning: Alert$1,
2006
+ negative: Cross,
2007
+ pending: ClockBorderless,
2008
+ info: Info$1,
2009
+ error: Cross,
2010
+ success: Check
2011
+ };
2012
+ const StatusIcon = ({
2013
+ sentiment = 'neutral',
2014
+ size = 'md'
2015
+ }) => {
2016
+ const Icon = iconTypeMap[sentiment];
2017
+ const iconColor = sentiment === 'warning' || sentiment === 'pending' ? 'dark' : 'light';
2018
+ return /*#__PURE__*/jsx("span", {
2019
+ "data-testid": "status-icon",
2020
+ className: classNames('status-circle', 'status-circle-' + size, sentiment),
2021
+ children: /*#__PURE__*/jsx(Icon, {
2022
+ className: classNames('status-icon', iconColor)
2023
+ })
2024
+ });
2025
+ };
2026
+
2027
+ const reader = new commonmark.Parser();
2028
+ const writer = new commonmark.HtmlRenderer({
2029
+ safe: true
2030
+ });
2031
+ const NODE_TYPE_LIST = Object.values(MarkdownNodeType);
2032
+ function Markdown({
2033
+ as: Element = 'div',
2034
+ allowList,
2035
+ blockList,
2036
+ config,
2037
+ className,
2038
+ children
2039
+ }) {
2040
+ if (!children) {
2041
+ return null;
2042
+ }
2043
+ const linkTarget = config?.link?.target ?? '_self';
2044
+ const paragraphClass = config?.paragraph?.className ?? '';
2045
+ if (allowList != null && blockList != null) {
2046
+ logActionRequired('Markdown supports only one of `allowList` or `blockList` to be used at a time. `blockList` will be ignored.');
2047
+ }
2048
+ const parser = nodes => {
2049
+ const parsed = reader.parse(nodes);
2050
+ const toExclude = allowList != null ? NODE_TYPE_LIST.filter(type => !allowList.includes(type)) : blockList;
2051
+ return toExclude != null ? stripNodes({
2052
+ parsed,
2053
+ blockList: toExclude
2054
+ }) : parsed;
2055
+ };
2056
+ const createMarkup = () => {
2057
+ const parsed = parser(children);
2058
+ return writer.render(parsed).replace(/<a href="/g, `<a target="${linkTarget}" href="`).replace(/<p>/g, `<p class="${paragraphClass}">`);
2059
+ };
2060
+ return /*#__PURE__*/jsx(Element, {
2061
+ className: className,
2062
+ dangerouslySetInnerHTML: {
2063
+ __html: createMarkup()
2064
+ }
2065
+ });
2066
+ }
2067
+ function stripNodes({
2068
+ blockList,
2069
+ parsed
2070
+ }) {
2071
+ if (!parsed) {
2072
+ return parsed;
2073
+ }
2074
+ const walker = parsed.walker();
2075
+ for (let event = walker.next(); event != null; event = walker.next()) {
2076
+ const {
2077
+ node
2078
+ } = event;
2079
+ if (blockList.includes(node.type) && !event.entering) {
2080
+ while (node.firstChild != null) {
2081
+ node.insertBefore(node.firstChild);
2082
+ }
2083
+ node.unlink();
2084
+ }
2085
+ }
2086
+ return parsed;
2087
+ }
2088
+
2089
+ const allowList = [MarkdownNodeType.STRONG];
2090
+ const InlineMarkdown = props => {
2091
+ return /*#__PURE__*/jsx(Markdown, {
2092
+ ...props,
2093
+ as: "span",
2094
+ allowList: allowList,
2095
+ blockList: undefined
2096
+ });
2097
+ };
2098
+ InlineMarkdown.propTypes = {
2099
+ children: PropTypes.string.isRequired,
2100
+ className: PropTypes.string
2101
+ };
2102
+ InlineMarkdown.defaultProps = {
2103
+ className: undefined
2104
+ };
2105
+
2106
+ var AlertArrowPosition;
2107
+ (function (AlertArrowPosition) {
2108
+ AlertArrowPosition["TOP_LEFT"] = "up-left";
2109
+ AlertArrowPosition["TOP"] = "up-center";
2110
+ AlertArrowPosition["TOP_RIGHT"] = "up-right";
2111
+ AlertArrowPosition["BOTTOM_LEFT"] = "down-left";
2112
+ AlertArrowPosition["BOTTOM"] = "down-center";
2113
+ AlertArrowPosition["BOTTOM_RIGHT"] = "down-right";
2114
+ })(AlertArrowPosition || (AlertArrowPosition = {}));
2115
+ function resolveType(type) {
2116
+ switch (type) {
2117
+ case 'success':
2118
+ return 'positive';
2119
+ case 'info':
2120
+ return 'neutral';
2121
+ case 'error':
2122
+ return 'negative';
2123
+ default:
2124
+ return type;
2125
+ }
2126
+ }
2127
+ function Alert({
2128
+ arrow,
2129
+ action,
2130
+ children,
2131
+ className,
2132
+ dismissible,
2133
+ icon,
2134
+ onDismiss,
2135
+ message,
2136
+ size,
2137
+ title,
2138
+ type = 'neutral',
2139
+ variant = 'desktop'
2140
+ }) {
2141
+ useEffect(() => {
2142
+ if (arrow !== undefined) {
2143
+ logActionRequired("Alert component doesn't support 'arrow' anymore, use 'InlineAlert' instead.");
2144
+ }
2145
+ }, [arrow]);
2146
+ useEffect(() => {
2147
+ if (children !== undefined) {
2148
+ logActionRequired("Alert component doesn't support 'children' anymore, use 'message' instead.");
2149
+ }
2150
+ }, [children]);
2151
+ useEffect(() => {
2152
+ if (dismissible !== undefined) {
2153
+ logActionRequired("Alert component doesn't support 'dismissible' anymore, use 'onDismiss' instead.");
2154
+ }
2155
+ }, [dismissible]);
2156
+ useEffect(() => {
2157
+ if (size !== undefined) {
2158
+ logActionRequired("Alert component doesn't support 'size' anymore, please remove that prop.");
2159
+ }
2160
+ }, [size]);
2161
+ const resolvedType = resolveType(type);
2162
+ useEffect(() => {
2163
+ if (resolvedType !== type) {
2164
+ logActionRequired(`Alert component has deprecated '${type}' value for the 'type' prop. Please use '${resolvedType}' instead.`);
2165
+ }
2166
+ }, [resolvedType, type]);
2167
+ const [shouldFire, setShouldFire] = useState(false);
2168
+ const closeButtonReference = useRef(null);
2169
+ return /*#__PURE__*/jsxs("div", {
2170
+ className: classNames('alert d-flex', `alert-${resolvedType}`, arrow != null && alertArrowClassNames(arrow), className),
2171
+ "data-testid": "alert",
2172
+ onTouchStart: () => setShouldFire(true),
2173
+ onTouchEnd: event => {
2174
+ if (shouldFire && action &&
2175
+ // Check if current event is triggered from closeButton
2176
+ event.target instanceof Node && closeButtonReference.current && !closeButtonReference.current.contains(event.target)) {
2177
+ if (action.target === '_blank') {
2178
+ window.top?.open(action.href);
2179
+ } else {
2180
+ window.top?.location.assign(action.href);
2181
+ }
2182
+ }
2183
+ setShouldFire(false);
2184
+ },
2185
+ onTouchMove: () => setShouldFire(false),
2186
+ children: [/*#__PURE__*/jsxs("div", {
2187
+ className: classNames('alert__content', 'd-flex', 'flex-grow-1', variant),
2188
+ "data-testid": variant,
2189
+ children: [icon ? /*#__PURE__*/jsx("div", {
2190
+ className: "alert__icon",
2191
+ children: icon
2192
+ }) : /*#__PURE__*/jsx(StatusIcon, {
2193
+ size: Size.LARGE,
2194
+ sentiment: resolvedType
2195
+ }), /*#__PURE__*/jsxs("div", {
2196
+ className: "alert__message",
2197
+ children: [/*#__PURE__*/jsxs("div", {
2198
+ role: Sentiment.NEGATIVE === resolvedType ? 'alert' : 'status',
2199
+ children: [title && /*#__PURE__*/jsx(Title, {
2200
+ className: "m-b-1",
2201
+ type: Typography.TITLE_BODY,
2202
+ children: title
2203
+ }), /*#__PURE__*/jsx(Body, {
2204
+ as: "span",
2205
+ className: "d-block",
2206
+ type: Typography.BODY_LARGE,
2207
+ children: children || /*#__PURE__*/jsx(InlineMarkdown, {
2208
+ children: message
2209
+ })
2210
+ })]
2211
+ }), action && /*#__PURE__*/jsx(Link, {
2212
+ href: action.href,
2213
+ className: "m-t-1",
2214
+ "aria-label": action['aria-label'],
2215
+ target: action.target,
2216
+ type: Typography.LINK_LARGE,
2217
+ children: action.text
2218
+ })]
2219
+ })]
2220
+ }), onDismiss && /*#__PURE__*/jsx(CloseButton, {
2221
+ ref: closeButtonReference,
2222
+ className: "m-l-2",
2223
+ onClick: onDismiss
2224
+ })]
2225
+ });
2226
+ }
2227
+ function alertArrowClassNames(arrow) {
2228
+ switch (arrow) {
2229
+ case 'down-center':
2230
+ return 'arrow arrow-bottom arrow-center';
2231
+ case 'down-left':
2232
+ return 'arrow arrow-bottom arrow-left';
2233
+ case 'down-right':
2234
+ return 'arrow arrow-bottom arrow-right';
2235
+ case 'up-center':
2236
+ return 'arrow arrow-center';
2237
+ case 'up-right':
2238
+ return 'arrow arrow-right';
2239
+ case 'up-left':
2240
+ default:
2241
+ return 'arrow';
2242
+ }
2243
+ }
2244
+
2245
+ // TODO: consider to move this enum into component file once we migrate it on TypeScript or replace with some common enum
2246
+ var AvatarType;
2247
+ (function (AvatarType) {
2248
+ AvatarType["THUMBNAIL"] = "thumbnail";
2249
+ AvatarType["ICON"] = "icon";
2250
+ AvatarType["EMOJI"] = "emoji";
2251
+ AvatarType["INITIALS"] = "initials";
2252
+ })(AvatarType || (AvatarType = {}));
2253
+
2254
+ /*
2255
+ * The colors we support generating an Avatar background color from a "seed" for.
2256
+ * Changing this array will change the assignment between seeds.
2257
+ * Do not change this array.
2258
+ */
2259
+ const avatarColors = ['--color-bright-blue', '--color-bright-yellow', '--color-bright-pink', '--color-bright-orange'];
2260
+ /*
2261
+ * Takes in a "seed" string and spits out an index for the color we should use.
2262
+ * This implementation has been synced across all three clients so that we consistently
2263
+ * generate branded avatar colors when rendering a list of Avatars.
2264
+ * Do not change this implementation.
2265
+ */
2266
+ const hashSeed = seed => {
2267
+ const base = 31;
2268
+ const modulo = avatarColors.length;
2269
+ let hashValue = 0;
2270
+ let basePow = 1;
2271
+ for (let i = 0; i < seed.length; i += 1) {
2272
+ hashValue = (hashValue + seed.charCodeAt(i) * basePow) % modulo;
2273
+ basePow = basePow * base % modulo;
2274
+ }
2275
+ return hashValue;
2276
+ };
2277
+ const getAvatarColorFromSeed = seed => {
2278
+ return avatarColors[hashSeed(seed)];
2279
+ };
2280
+
2281
+ const backwardsCompatibleSize = size => {
2282
+ switch (size) {
2283
+ case 'sm':
2284
+ return 24;
2285
+ case 'md':
2286
+ return 48;
2287
+ case 'lg':
2288
+ return 72;
2289
+ default:
2290
+ return size;
2291
+ }
2292
+ };
2293
+ const Avatar = ({
2294
+ backgroundColor = null,
2295
+ backgroundColorSeed = null,
2296
+ children = null,
2297
+ className,
2298
+ outlined = false,
2299
+ size: sizeFromProps = 48,
2300
+ theme = Theme.LIGHT,
2301
+ type = 'thumbnail'
2302
+ }) => {
2303
+ const backgroundColorFromSeed = useMemo(() => !backgroundColor && backgroundColorSeed ? `var(${getAvatarColorFromSeed(backgroundColorSeed)})` : undefined, [backgroundColor, backgroundColorSeed]);
2304
+ const size = backwardsCompatibleSize(sizeFromProps);
2305
+ return /*#__PURE__*/jsx("div", {
2306
+ className: classNames('tw-avatar', className, `tw-avatar--${size}`, `tw-avatar--${type}`, {
2307
+ 'tw-avatar--outlined': outlined,
2308
+ 'tw-avatar--branded': Boolean(backgroundColorFromSeed),
2309
+ 'np-text-title-body': type === 'initials'
2310
+ }),
2311
+ children: /*#__PURE__*/jsx("div", {
2312
+ className: "tw-avatar__content",
2313
+ style: {
2314
+ backgroundColor: backgroundColor || backgroundColorFromSeed
2315
+ },
2316
+ children: children
2317
+ })
2318
+ });
2319
+ };
2320
+
2321
+ const Badge = ({
2322
+ badge,
2323
+ className = undefined,
2324
+ size = Size.SMALL,
2325
+ border = Theme.LIGHT,
2326
+ children
2327
+ }) => {
2328
+ const classes = classNames('tw-badge', {
2329
+ [`tw-badge-border-${border}`]: border,
2330
+ [`tw-badge-${size}`]: size
2331
+ }, className);
2332
+ return /*#__PURE__*/jsxs("div", {
2333
+ className: classes,
2334
+ children: [/*#__PURE__*/jsx("div", {
2335
+ className: "tw-badge__children",
2336
+ children: children
2337
+ }), /*#__PURE__*/jsx("div", {
2338
+ className: "tw-badge__content",
2339
+ children: badge
2340
+ })]
2341
+ });
2342
+ };
2343
+
2344
+ const OptionalBadge = ({
2345
+ url,
2346
+ altText,
2347
+ statusIcon,
2348
+ children,
2349
+ ...rest
2350
+ }) => {
2351
+ if (url) {
2352
+ return /*#__PURE__*/jsx(Badge, {
2353
+ badge: /*#__PURE__*/jsx("img", {
2354
+ src: url,
2355
+ alt: altText
2356
+ }),
2357
+ ...rest,
2358
+ children: children
2359
+ });
2360
+ }
2361
+ if (statusIcon) {
2362
+ return /*#__PURE__*/jsx(Badge, {
2363
+ badge: /*#__PURE__*/jsx(StatusIcon, {
2364
+ sentiment: statusIcon,
2365
+ size: Size.SMALL
2366
+ }),
2367
+ ...rest,
2368
+ children: children
2369
+ });
2370
+ }
2371
+ return /*#__PURE__*/jsx(Fragment, {
2372
+ children: children
2373
+ });
2374
+ };
2375
+ const AvatarWrapper = ({
2376
+ url,
2377
+ profileType,
2378
+ profileId,
2379
+ badgeUrl,
2380
+ badgeAltText,
2381
+ badgeStatusIcon,
2382
+ name,
2383
+ avatarProps,
2384
+ badgeProps
2385
+ }) => {
2386
+ const [hasImageLoadError, setImageLoadError] = useState(false);
2387
+ const isBusinessProfile = profileType === ProfileType.BUSINESS;
2388
+ // Reset the errored state when url changes
2389
+ useEffect(() => setImageLoadError(false), [url]);
2390
+ const getAvatarProps = () => {
2391
+ if (url && !hasImageLoadError) {
2392
+ return {
2393
+ type: AvatarType.THUMBNAIL,
2394
+ children: /*#__PURE__*/jsx("img", {
2395
+ src: url,
2396
+ alt: "",
2397
+ onError: () => setImageLoadError(true)
2398
+ }),
2399
+ ...avatarProps
2400
+ };
2401
+ }
2402
+ if (profileType) {
2403
+ return {
2404
+ type: AvatarType.ICON,
2405
+ children: isBusinessProfile ? /*#__PURE__*/jsx(Briefcase, {
2406
+ size: "24"
2407
+ }) : /*#__PURE__*/jsx(Person, {
2408
+ size: "24"
2409
+ }),
2410
+ ...avatarProps
2411
+ };
2412
+ }
2413
+ if (name) {
2414
+ return {
2415
+ type: AvatarType.INITIALS,
2416
+ children: /*#__PURE__*/jsx(Fragment, {
2417
+ children: getInitials(name)
2418
+ }),
2419
+ backgroundColorSeed: profileId?.toString(),
2420
+ ...avatarProps
2421
+ };
2422
+ }
2423
+ return {
2424
+ type: AvatarType.ICON,
2425
+ children: /*#__PURE__*/jsx(Person, {
2426
+ size: "24"
2427
+ }),
2428
+ ...avatarProps
2429
+ };
2430
+ };
2431
+ return /*#__PURE__*/jsx(OptionalBadge, {
2432
+ url: badgeUrl,
2433
+ altText: badgeAltText,
2434
+ statusIcon: badgeStatusIcon,
2435
+ ...badgeProps,
2436
+ children: /*#__PURE__*/jsx(Avatar, {
2437
+ size: Size.MEDIUM,
2438
+ ...getAvatarProps()
2439
+ })
2440
+ });
2441
+ };
2442
+ function getInitials(name) {
2443
+ const allInitials = name.split(' ').map(part => part[0]).join('').toUpperCase();
2444
+ if (allInitials.length === 1) {
2445
+ return allInitials[0];
2446
+ }
2447
+ return allInitials[0] + allInitials.slice(-1);
2448
+ }
2449
+
2450
+ const Card$1 = /*#__PURE__*/forwardRef((props, reference) => {
2451
+ const {
2452
+ 'aria-label': ariaLabel,
2453
+ as: Element,
2454
+ isExpanded,
2455
+ title,
2456
+ details,
2457
+ children,
2458
+ onClick,
2459
+ icon,
2460
+ id,
2461
+ className,
2462
+ ...rest
2463
+ } = props;
2464
+ const isOpen = !!(isExpanded && children);
2465
+ return /*#__PURE__*/jsxs(Element, {
2466
+ ref: reference,
2467
+ className: classNames('np-card', className, {
2468
+ 'np-card--expanded': isOpen,
2469
+ 'np-card--inactive': !children,
2470
+ 'np-card--has-icon': !!icon
2471
+ }),
2472
+ id: id,
2473
+ "data-testid": rest['data-testid'],
2474
+ children: [/*#__PURE__*/jsx(Option$2, {
2475
+ "aria-label": ariaLabel,
2476
+ as: children ? 'button' : 'div',
2477
+ className: classNames('np-card__button'),
2478
+ media: icon,
2479
+ title: title,
2480
+ content: details,
2481
+ showMediaAtAllSizes: true,
2482
+ button: children && /*#__PURE__*/jsx(Chevron, {
2483
+ orientation: isOpen ? Position.TOP : Position.BOTTOM
2484
+ }),
2485
+ onClick: () => children && onClick(!isExpanded)
2486
+ }), /*#__PURE__*/jsx("div", {
2487
+ className: classNames('np-card__divider', {
2488
+ 'np-card__divider--expanded': isOpen
2489
+ })
2490
+ }), isOpen && /*#__PURE__*/jsx(Body, {
2491
+ as: "span",
2492
+ type: Typography.BODY_LARGE,
2493
+ className: "np-card__content d-block",
2494
+ children: children
2495
+ })]
2496
+ });
2497
+ });
2498
+ const hasChildren = ({
2499
+ children
2500
+ }) => children;
2501
+ Card$1.propTypes = {
2502
+ 'aria-label': PropTypes.string,
2503
+ as: PropTypes.string,
2504
+ isExpanded: requiredIf(PropTypes.bool, hasChildren),
2505
+ title: PropTypes.node.isRequired,
2506
+ details: PropTypes.node.isRequired,
2507
+ onClick: requiredIf(PropTypes.func, hasChildren),
2508
+ icon: PropTypes.node,
2509
+ children: PropTypes.node,
2510
+ id: PropTypes.string,
2511
+ className: PropTypes.string,
2512
+ 'data-testid': PropTypes.string
2513
+ };
2514
+ Card$1.defaultProps = {
2515
+ 'aria-label': undefined,
2516
+ as: 'div',
2517
+ children: null,
2518
+ id: null,
2519
+ className: null,
2520
+ 'data-testid': null
2521
+ };
2522
+ var Card$2 = Card$1;
2523
+
2524
+ const CheckboxButton = /*#__PURE__*/forwardRef(({
2525
+ checked,
2526
+ className,
2527
+ disabled,
2528
+ onChange,
2529
+ ...rest
2530
+ }, reference) => /*#__PURE__*/jsxs("span", {
2531
+ className: classNames('np-checkbox-button', className, disabled && 'disabled'),
2532
+ children: [/*#__PURE__*/jsx("input", {
2533
+ ...rest,
2534
+ ref: reference,
2535
+ type: "checkbox",
2536
+ disabled: disabled,
2537
+ checked: checked,
2538
+ onChange: onChange
2539
+ }), /*#__PURE__*/jsx("span", {
2540
+ className: "tw-checkbox-button",
2541
+ children: /*#__PURE__*/jsx("span", {
2542
+ className: "tw-checkbox-check"
2543
+ })
2544
+ })]
2545
+ }));
2546
+ var CheckboxButton$1 = CheckboxButton;
2547
+
2548
+ const Checkbox = ({
2549
+ id,
2550
+ checked,
2551
+ required,
2552
+ disabled,
2553
+ readOnly,
2554
+ label,
2555
+ className,
2556
+ secondary,
2557
+ onChange,
2558
+ onFocus,
2559
+ onBlur
2560
+ }) => {
2561
+ const {
2562
+ isModern
2563
+ } = useTheme();
2564
+ const classList = classNames('np-checkbox', {
2565
+ checkbox: true,
2566
+ 'checkbox-lg': secondary,
2567
+ disabled: isModern && disabled
2568
+ }, className);
2569
+ const innerDisabled = disabled || readOnly;
2570
+ return /*#__PURE__*/jsx("div", {
2571
+ id: id,
2572
+ className: classList,
2573
+ children: /*#__PURE__*/jsxs("label", {
2574
+ className: classNames({
2575
+ disabled
2576
+ }),
2577
+ children: [/*#__PURE__*/jsx(CheckboxButton$1, {
2578
+ className: "p-r-2",
2579
+ checked: checked,
2580
+ disabled: innerDisabled,
2581
+ required: !innerDisabled && required,
2582
+ onFocus: onFocus,
2583
+ onChange: () => onChange(!checked),
2584
+ onBlur: onBlur
2585
+ }), /*#__PURE__*/jsxs(Body, {
2586
+ as: "span",
2587
+ className: "np-checkbox__text",
2588
+ type: secondary ? Typography.BODY_LARGE_BOLD : Typography.BODY_LARGE,
2589
+ children: [/*#__PURE__*/jsx("span", {
2590
+ className: required ? 'has-required' : undefined,
2591
+ children: label
2592
+ }), secondary && /*#__PURE__*/jsx(Body, {
2593
+ as: "span",
2594
+ className: classNames({
2595
+ secondary: !isModern
2596
+ }),
2597
+ children: secondary
2598
+ })]
2599
+ })]
2600
+ })
2601
+ });
2602
+ };
2603
+ Checkbox.propTypes = {
2604
+ id: PropTypes.string,
2605
+ checked: PropTypes.bool,
2606
+ required: PropTypes.bool,
2607
+ disabled: PropTypes.bool,
2608
+ readOnly: PropTypes.bool,
2609
+ label: PropTypes.node.isRequired,
2610
+ secondary: PropTypes.string,
2611
+ onFocus: PropTypes.func,
2612
+ onChange: PropTypes.func.isRequired,
2613
+ onBlur: PropTypes.func,
2614
+ className: PropTypes.string
2615
+ };
2616
+ Checkbox.defaultProps = {
2617
+ id: null,
2618
+ checked: false,
2619
+ required: false,
2620
+ disabled: false,
2621
+ readOnly: false,
2622
+ secondary: null,
2623
+ onFocus: null,
2624
+ onBlur: null,
2625
+ className: undefined
2626
+ };
2627
+
2628
+ const CheckboxOption = /*#__PURE__*/forwardRef(({
2629
+ checked,
2630
+ disabled,
2631
+ onChange,
2632
+ ...rest
2633
+ }, reference) => {
2634
+ return /*#__PURE__*/jsx(Option$2, {
2635
+ ...rest,
2636
+ ref: reference,
2637
+ disabled: disabled,
2638
+ button: /*#__PURE__*/jsx(CheckboxButton$1, {
2639
+ checked: checked,
2640
+ disabled: disabled,
2641
+ onChange: () => onChange?.(!checked)
2642
+ })
2643
+ });
2644
+ });
2645
+
2646
+ const Chip = ({
2647
+ label,
2648
+ value,
2649
+ onRemove,
2650
+ onClick,
2651
+ onKeyPress,
2652
+ className = undefined,
2653
+ 'aria-label': ariaLabel,
2654
+ 'aria-checked': ariaChecked,
2655
+ role,
2656
+ closeButton
2657
+ }) => {
2658
+ const isActionable = onClick || onKeyPress;
2659
+ const defaultRole = isActionable ? 'button' : undefined;
2660
+ const tabIndex = isActionable ? 0 : -1;
2661
+ const {
2662
+ isModern
2663
+ } = useTheme();
2664
+ const closeButtonReference = useRef(null);
2665
+ const previousCloseButtonShown = useRef();
2666
+ useEffect(() => {
2667
+ if (closeButtonReference.current != null && previousCloseButtonShown.current === false) {
2668
+ closeButtonReference.current?.focus();
2669
+ }
2670
+ previousCloseButtonShown.current = closeButtonReference.current != null;
2671
+ }, [onRemove]);
2672
+ return /*#__PURE__*/jsxs("div", {
2673
+ role: role ?? defaultRole,
2674
+ tabIndex: tabIndex,
2675
+ "aria-label": ariaLabel,
2676
+ "aria-checked": ariaChecked,
2677
+ className: classNames('np-chip', 'd-flex', 'align-items-center', 'justify-content-between', onRemove ? 'np-chip--removable' : '', className),
2678
+ ...(isActionable && {
2679
+ onClick,
2680
+ onKeyPress
2681
+ }),
2682
+ children: [isModern ? /*#__PURE__*/jsx(Body, {
2683
+ "aria-hidden": !!onRemove,
2684
+ type: Typography.BODY_DEFAULT_BOLD,
2685
+ children: label
2686
+ }) : /*#__PURE__*/jsx("span", {
2687
+ "aria-hidden": "false",
2688
+ className: "np-chip-label",
2689
+ children: label
2690
+ }), onRemove ? /*#__PURE__*/jsx(CloseButton, {
2691
+ ref: closeButtonReference,
2692
+ className: isModern ? `btn-unstyled` : `btn-unstyled m-l-1`,
2693
+ "aria-label": closeButton && closeButton['aria-label'],
2694
+ size: "sm",
2695
+ filled: isModern,
2696
+ onClick: onRemove
2697
+ }) : null]
2698
+ }, value);
2699
+ };
2700
+
2701
+ var messages$a = defineMessages({
2702
+ ariaLabel: {
2703
+ id: "neptune.Chips.ariaLabel"
2704
+ }
2705
+ });
2706
+
2707
+ const Chips = ({
2708
+ chips,
2709
+ onChange,
2710
+ selected,
2711
+ 'aria-label': ariaLabel,
2712
+ className,
2713
+ multiple
2714
+ }) => {
2715
+ const intl = useIntl();
2716
+ const isSelected = value => Array.isArray(selected) ? selected.includes(value) : selected === value;
2717
+ const handleOnChange = (selectedValue, isCurrentlyEnabled) => {
2718
+ onChange({
2719
+ isEnabled: !isCurrentlyEnabled,
2720
+ selectedValue
2721
+ });
2722
+ };
2723
+ return /*#__PURE__*/jsx("div", {
2724
+ className: classNames('np-chips d-flex', className),
2725
+ "aria-label": ariaLabel,
2726
+ role: !multiple ? 'radiogroup' : undefined,
2727
+ children: chips.map(chip => {
2728
+ const chipSelected = isSelected(chip.value);
2729
+ return /*#__PURE__*/jsx(Chip, {
2730
+ value: chip.value,
2731
+ label: chip.label,
2732
+ closeButton: {
2733
+ 'aria-label': intl.formatMessage(messages$a.ariaLabel, {
2734
+ choice: chip.label
2735
+ })
2736
+ },
2737
+ className: classNames('text-xs-nowrap', {
2738
+ 'np-chip--selected': chipSelected,
2739
+ 'p-r-1': multiple && chipSelected
2740
+ }),
2741
+ ...(multiple && chipSelected ? {
2742
+ onRemove: () => handleOnChange(chip.value, chipSelected),
2743
+ 'aria-label': chip.label
2744
+ } : {
2745
+ onClick: () => handleOnChange(chip.value, chipSelected),
2746
+ onKeyPress: () => handleOnChange(chip.value, chipSelected),
2747
+ role: !multiple ? 'radio' : undefined,
2748
+ 'aria-checked': chipSelected
2749
+ })
2750
+ }, chip.value);
2751
+ })
2752
+ });
2753
+ };
2754
+
2755
+ const CircularButton = ({
2756
+ className,
2757
+ children,
2758
+ disabled,
2759
+ icon,
2760
+ priority = Priority.PRIMARY,
2761
+ type = ControlType.ACCENT,
2762
+ ...rest
2763
+ }) => {
2764
+ const classes = classNames('btn np-btn', typeClassMap[type], priorityClassMap[priority]);
2765
+ const iconElement = Number(icon.props.size) !== 24 ? /*#__PURE__*/cloneElement(icon, {
2766
+ size: 24
2767
+ }) : icon;
2768
+ return /*#__PURE__*/jsxs("label", {
2769
+ className: classNames('np-circular-btn', priority, type, disabled && 'disabled', className),
2770
+ children: [/*#__PURE__*/jsx("input", {
2771
+ type: "button",
2772
+ "aria-label": children,
2773
+ className: classes,
2774
+ disabled: disabled,
2775
+ ...rest
2776
+ }), iconElement, /*#__PURE__*/jsx(Body, {
2777
+ as: "span",
2778
+ className: "np-circular-btn__label",
2779
+ type: Typography.BODY_DEFAULT_BOLD,
2780
+ children: children
2781
+ })]
2782
+ });
2783
+ };
2784
+
2449
2785
  const Card = ({
2450
2786
  className,
2451
2787
  children = null,
@@ -2958,124 +3294,6 @@ function shouldPropagateOnBlur({
2958
3294
  return blurElementParent !== focusElementParent;
2959
3295
  }
2960
3296
 
2961
- const POPOVER_OFFSET = [0, 16];
2962
- // By default the flip positioning explores only the opposite alternative. So if left is passed and there's no enough space
2963
- // the right one gets chosen. If there's no space on both sides popover goes back to the initially chosen one left.
2964
- // This mapping forces popover to try the four available positions before going back to the initial chosen one.
2965
- const fallbackPlacements = {
2966
- [Position.TOP]: [Position.BOTTOM, Position.RIGHT, Position.LEFT],
2967
- [Position.BOTTOM]: [Position.TOP, Position.RIGHT, Position.LEFT],
2968
- [Position.LEFT]: [Position.RIGHT, Position.TOP, Position.BOTTOM],
2969
- [Position.RIGHT]: [Position.LEFT, Position.TOP, Position.BOTTOM]
2970
- };
2971
- const Panel = /*#__PURE__*/forwardRef(({
2972
- arrow = false,
2973
- flip = true,
2974
- altAxis = false,
2975
- children,
2976
- open = false,
2977
- onClose,
2978
- position = Position.BOTTOM,
2979
- anchorRef,
2980
- anchorWidth = false,
2981
- ...rest
2982
- }, reference) => {
2983
- const [arrowElement, setArrowElement] = useState(null);
2984
- const [popperElement, setPopperElement] = useState(null);
2985
- const modifiers = [];
2986
- if (altAxis) {
2987
- modifiers.push({
2988
- // https://popper.js.org/docs/v2/modifiers/prevent-overflow
2989
- name: 'preventOverflow',
2990
- options: {
2991
- altAxis: true,
2992
- tether: false
2993
- }
2994
- });
2995
- }
2996
- if (arrow) {
2997
- modifiers.push({
2998
- name: 'arrow',
2999
- options: {
3000
- element: arrowElement,
3001
- options: {
3002
- padding: 8 // 8px from the edges of the popper
3003
- }
3004
- }
3005
- });
3006
- // This lets you displace a popper element from its reference element.
3007
- modifiers.push({
3008
- name: 'offset',
3009
- options: {
3010
- offset: POPOVER_OFFSET
3011
- }
3012
- });
3013
- }
3014
- if (flip && fallbackPlacements[position]) {
3015
- modifiers.push({
3016
- name: 'flip',
3017
- options: {
3018
- fallbackPlacements: fallbackPlacements[position]
3019
- }
3020
- });
3021
- }
3022
- const {
3023
- styles,
3024
- attributes,
3025
- forceUpdate
3026
- } = usePopper(anchorRef.current, popperElement, {
3027
- placement: position,
3028
- modifiers
3029
- });
3030
- // If the trigger is not visible when the position is calculated, it will be incorrect. Because this can happen repeatedly (on resize for example),
3031
- // it is most simple just to always position before opening
3032
- useEffect(() => {
3033
- if (open && forceUpdate) {
3034
- forceUpdate();
3035
- }
3036
- }, [open]);
3037
- const contentStyle = {
3038
- ...(anchorWidth ? {
3039
- width: anchorRef.current?.clientWidth
3040
- } : undefined)
3041
- };
3042
- return /*#__PURE__*/jsx(Dimmer$1, {
3043
- open: open,
3044
- transparent: true,
3045
- fadeContentOnEnter: true,
3046
- fadeContentOnExit: true,
3047
- onClose: onClose,
3048
- children: /*#__PURE__*/jsx("div", {
3049
- ...rest,
3050
- ref: setPopperElement,
3051
- role: "dialog"
3052
- // eslint-disable-next-line react/forbid-dom-props
3053
- ,
3054
- style: {
3055
- ...styles.popper
3056
- },
3057
- ...attributes.popper,
3058
- className: classNames('np-panel', {
3059
- 'np-panel--open': open
3060
- }, rest['className']),
3061
- children: /*#__PURE__*/jsxs("div", {
3062
- ref: reference
3063
- /* eslint-disable-next-line react/forbid-dom-props */,
3064
- style: contentStyle,
3065
- className: classNames('np-panel__content'),
3066
- children: [children, arrow && /*#__PURE__*/jsx("div", {
3067
- ref: setArrowElement,
3068
- className: classNames('np-panel__arrow')
3069
- // eslint-disable-next-line react/forbid-dom-props
3070
- ,
3071
- style: styles.arrow
3072
- })]
3073
- })
3074
- })
3075
- });
3076
- });
3077
- var Panel$1 = Panel;
3078
-
3079
3297
  const ResponsivePanel = /*#__PURE__*/forwardRef(({
3080
3298
  anchorRef,
3081
3299
  arrow = false,
@@ -3097,7 +3315,7 @@ const ResponsivePanel = /*#__PURE__*/forwardRef(({
3097
3315
  children: children
3098
3316
  }, "bottomSheet");
3099
3317
  }
3100
- return /*#__PURE__*/jsx(Panel$1, {
3318
+ return /*#__PURE__*/jsx(Panel, {
3101
3319
  ref: reference,
3102
3320
  flip: flip,
3103
3321
  arrow: arrow,
@@ -4995,73 +5213,6 @@ const Field = ({
4995
5213
  });
4996
5214
  };
4997
5215
 
4998
- const HeaderAction = ({
4999
- action
5000
- }) => {
5001
- const {
5002
- isModern
5003
- } = useTheme();
5004
- const props = {
5005
- 'aria-label': action['aria-label']
5006
- };
5007
- if ('href' in action) {
5008
- return /*#__PURE__*/jsx(Link, {
5009
- href: action.href,
5010
- target: action.target,
5011
- onClick: action.onClick,
5012
- ...props,
5013
- children: action.text
5014
- });
5015
- }
5016
- return isModern ? /*#__PURE__*/jsx(Button, {
5017
- className: "np-header__button",
5018
- priority: "tertiary",
5019
- size: "sm",
5020
- onClick: action.onClick,
5021
- ...props,
5022
- children: action.text
5023
- }) : /*#__PURE__*/jsx(ActionButton, {
5024
- onClick: action.onClick,
5025
- ...props,
5026
- children: action.text
5027
- });
5028
- };
5029
- /**
5030
- *
5031
- * Neptune Web: https://transferwise.github.io/neptune-web/components/content/Header
5032
- *
5033
- */
5034
- const Header = ({
5035
- action,
5036
- as = 'h5',
5037
- title,
5038
- className
5039
- }) => {
5040
- if (!action) {
5041
- return /*#__PURE__*/jsx(Title, {
5042
- as: as,
5043
- type: Typography.TITLE_GROUP,
5044
- className: classNames('np-header', 'np-header__title', className),
5045
- children: title
5046
- });
5047
- }
5048
- if (as === 'legend') {
5049
- // eslint-disable-next-line no-console
5050
- console.warn('Legends should be the first child in a fieldset, and this is not possible when including an action');
5051
- }
5052
- return /*#__PURE__*/jsxs("div", {
5053
- className: classNames('np-header', className),
5054
- children: [/*#__PURE__*/jsx(Title, {
5055
- as: as,
5056
- type: Typography.TITLE_GROUP,
5057
- className: "np-header__title",
5058
- children: title
5059
- }), /*#__PURE__*/jsx(HeaderAction, {
5060
- action: action
5061
- })]
5062
- });
5063
- };
5064
-
5065
5216
  const EmptyTransparentImage = 'data:image/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==';
5066
5217
  const Image = ({
5067
5218
  id,
@@ -8817,12 +8968,6 @@ const PhoneNumberInput = ({
8817
8968
  return explodeNumberModel(cleanValue);
8818
8969
  });
8819
8970
  const [broadcastedValue, setBroadcastedValue] = useState(null);
8820
- const [suffixDirty, setSuffixDirty] = useState(false);
8821
- useEffect(() => {
8822
- if (internalValue.suffix) {
8823
- setSuffixDirty(true);
8824
- }
8825
- }, [internalValue.suffix]);
8826
8971
  const countriesByPrefix = useMemo(() => groupCountriesByPrefix(sortArrayByProperty(excludeCountries(countries, disabledCountries), 'iso3')), [disabledCountries]);
8827
8972
  const onSuffixChange = event => {
8828
8973
  const suffix = event.target.value;
@@ -8886,11 +9031,6 @@ const PhoneNumberInput = ({
8886
9031
  format: country?.phoneFormat
8887
9032
  }));
8888
9033
  },
8889
- onClose: () => {
8890
- if (suffixDirty) {
8891
- onBlur?.();
8892
- }
8893
- },
8894
9034
  ...selectProps
8895
9035
  })
8896
9036
  }), /*#__PURE__*/jsx("div", {
@@ -8910,7 +9050,7 @@ const PhoneNumberInput = ({
8910
9050
  onChange: onSuffixChange,
8911
9051
  onPaste: onPaste,
8912
9052
  onFocus: onFocus,
8913
- onBlur: () => onBlur?.()
9053
+ onBlur: onBlur
8914
9054
  })
8915
9055
  })
8916
9056
  })]
@@ -9520,19 +9660,6 @@ function RadioOption({
9520
9660
  });
9521
9661
  }
9522
9662
 
9523
- const Section = ({
9524
- children,
9525
- className,
9526
- withHorizontalPadding = false
9527
- }) => {
9528
- return /*#__PURE__*/jsx("div", {
9529
- className: classNames('np-section', className, {
9530
- 'np-section--with-horizontal-padding': withHorizontalPadding
9531
- }),
9532
- children: children
9533
- });
9534
- };
9535
-
9536
9663
  const SegmentedControl = ({
9537
9664
  name,
9538
9665
  value,
@@ -10199,7 +10326,7 @@ function Select({
10199
10326
  children: renderOptionsList({
10200
10327
  className: isModern ? '' : 'p-a-1'
10201
10328
  })
10202
- }) : /*#__PURE__*/jsx(Panel$1, {
10329
+ }) : /*#__PURE__*/jsx(Panel, {
10203
10330
  open: open,
10204
10331
  flip: false,
10205
10332
  altAxis: true,
@@ -14484,5 +14611,5 @@ const translations = {
14484
14611
  'zh-HK': zhHK
14485
14612
  };
14486
14613
 
14487
- export { Accordion, ActionButton, ActionOption, Alert, AlertArrowPosition, Avatar, AvatarType, AvatarWrapper, Badge, Card as BaseCard, Body, BottomSheet$1 as BottomSheet, Breakpoint, Button, Card$2 as Card, Checkbox, CheckboxButton$1 as CheckboxButton, CheckboxOption, Chevron, Chip, Chips, CircularButton, ControlType, CriticalCommsBanner, DEFAULT_LANG, DEFAULT_LOCALE, DateInput, DateLookup$1 as DateLookup, DateMode, Decision, DecisionPresentation, DecisionType, DefinitionList$1 as DefinitionList, Dimmer$1 as Dimmer, Direction, DirectionProvider, Display, Drawer$1 as Drawer, DropFade, Emphasis, Field, FileType, FlowNavigation, Header, Image, Info, InfoPresentation, InlineAlert, Input, InputGroup, InputWithDisplayFormat, InstructionsList, Label, LanguageProvider, Layout, Link, ListItem$1 as ListItem, Loader, Logo$1 as Logo, LogoType, Markdown, MarkdownNodeType, Modal, Money, MoneyInput$1 as MoneyInput, MonthFormat, NavigationOption, NavigationOptionList as NavigationOptionsList, Nudge, Option$2 as Option, OverlayHeader$1 as OverlayHeader, PhoneNumberInput, Popover$1 as Popover, Position, Priority, ProcessIndicator$1 as ProcessIndicator, ProfileType, Progress, ProgressBar, PromoCard$1 as PromoCard, PromoCardGroup$1 as PromoCardGroup, Provider, RTL_LANGUAGES, Radio, RadioGroup, RadioOption, SUPPORTED_LANGUAGES, Scroll, SearchInput, Section, SegmentedControl, Select, SelectInput, SelectInputOptionContent, SelectInputTriggerButton, Sentiment, Size, SlidingPanel, SnackbarConsumer, SnackbarContext, SnackbarPortal, SnackbarProvider, Status, StatusIcon, Stepper, Sticky, Summary, Switch, SwitchOption, Tabs$1 as Tabs, TextArea, TextareaWithDisplayFormat, Theme, Title, Tooltip, Type, Typeahead, Typography, Upload$1 as Upload, UploadInput, UploadStep, Variant, Width, adjustLocale, getCountryFromLocale, getDirectionFromLocale, getLangFromLocale, isBrowser, isServerSide, translations, useDirection, useLayout, useScreenSize, useSnackbar };
14614
+ export { Accordion, ActionButton, ActionOption, Alert, AlertArrowPosition, Avatar, AvatarType, AvatarWrapper, Badge, Card as BaseCard, Body, BottomSheet$1 as BottomSheet, Breakpoint, Button, Card$2 as Card, Checkbox, CheckboxButton$1 as CheckboxButton, CheckboxOption, Chevron, Chip, Chips, CircularButton, ControlType, CriticalCommsBanner, DEFAULT_LANG, DEFAULT_LOCALE, DateInput, DateLookup$1 as DateLookup, DateMode, Decision, DecisionPresentation, DecisionType, DefinitionList$1 as DefinitionList, Dimmer$1 as Dimmer, Direction, DirectionProvider, Display, Drawer$1 as Drawer, DropFade, Emphasis, Field, FileType, FlowNavigation, Header, Image, Info, InfoPresentation, InlineAlert, Input, InputGroup, InputWithDisplayFormat, InstructionsList, Label, LanguageProvider, Layout, Link, ListItem$1 as ListItem, Loader, Logo$1 as Logo, LogoType, Markdown, MarkdownNodeType, Modal, Money, MoneyInput$1 as MoneyInput, MonthFormat, NavigationOption, NavigationOptionList as NavigationOptionsList, Nudge, Option$2 as Option, OverlayHeader$1 as OverlayHeader, PhoneNumberInput, Popover$1 as Popover, Position, Priority, ProcessIndicator$1 as ProcessIndicator, ProfileType, Progress, ProgressBar, PromoCard$1 as PromoCard, PromoCardGroup$1 as PromoCardGroup, Provider, RTL_LANGUAGES, Radio, RadioGroup, RadioOption, SUPPORTED_LANGUAGES, Scroll, SearchInput, Section, SegmentedControl, Select, SelectInput, SelectInputOptionContent, SelectInputTriggerButton, SelectOption, Sentiment, Size, SlidingPanel, SnackbarConsumer, SnackbarContext, SnackbarPortal, SnackbarProvider, Status, StatusIcon, Stepper, Sticky, Summary, Switch, SwitchOption, Tabs$1 as Tabs, TextArea, TextareaWithDisplayFormat, Theme, Title, Tooltip, Type, Typeahead, Typography, Upload$1 as Upload, UploadInput, UploadStep, Variant, Width, adjustLocale, getCountryFromLocale, getDirectionFromLocale, getLangFromLocale, isBrowser, isServerSide, translations, useDirection, useLayout, useScreenSize, useSnackbar };
14488
14615
  //# sourceMappingURL=index.mjs.map