@transferwise/components 0.0.0-experimental-693e956 → 0.0.0-experimental-d729abf

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (46) hide show
  1. package/build/i18n/en.json +1 -0
  2. package/build/index.js +2320 -2234
  3. package/build/index.js.map +1 -1
  4. package/build/index.mjs +2322 -2237
  5. package/build/index.mjs.map +1 -1
  6. package/build/main.css +31 -10
  7. package/build/styles/main.css +31 -10
  8. package/build/styles/selectOption/SelectOption.css +31 -0
  9. package/build/styles/uploadInput/UploadInput.css +0 -10
  10. package/build/types/index.d.ts +2 -0
  11. package/build/types/index.d.ts.map +1 -1
  12. package/build/types/selectOption/SelectOption.d.ts +20 -0
  13. package/build/types/selectOption/SelectOption.d.ts.map +1 -0
  14. package/build/types/selectOption/SelectOption.messages.d.ts +8 -0
  15. package/build/types/selectOption/SelectOption.messages.d.ts.map +1 -0
  16. package/build/types/selectOption/index.d.ts +3 -0
  17. package/build/types/selectOption/index.d.ts.map +1 -0
  18. package/build/types/slidingPanel/SlidingPanel.d.ts +1 -0
  19. package/build/types/slidingPanel/SlidingPanel.d.ts.map +1 -1
  20. package/build/types/sticky/Sticky.d.ts +31 -3
  21. package/build/types/sticky/Sticky.d.ts.map +1 -1
  22. package/build/types/uploadInput/types.d.ts +1 -9
  23. package/build/types/uploadInput/types.d.ts.map +1 -1
  24. package/build/types/uploadInput/uploadItem/UploadItem.d.ts.map +1 -1
  25. package/package.json +2 -2
  26. package/src/i18n/en.json +1 -0
  27. package/src/index.ts +2 -0
  28. package/src/main.css +31 -10
  29. package/src/main.less +1 -0
  30. package/src/selectOption/SelectOption.css +31 -0
  31. package/src/selectOption/SelectOption.less +27 -0
  32. package/src/selectOption/SelectOption.messages.ts +8 -0
  33. package/src/selectOption/SelectOption.story.tsx +167 -0
  34. package/src/selectOption/SelectOption.tsx +134 -0
  35. package/src/selectOption/index.ts +2 -0
  36. package/src/slidingPanel/SlidingPanel.spec.js +2 -1
  37. package/src/slidingPanel/SlidingPanel.tsx +3 -0
  38. package/src/sticky/Sticky.spec.tsx +71 -0
  39. package/src/sticky/Sticky.story.tsx +46 -13
  40. package/src/sticky/Sticky.tsx +48 -4
  41. package/src/uploadInput/UploadInput.css +0 -10
  42. package/src/uploadInput/UploadInput.less +0 -11
  43. package/src/uploadInput/UploadInput.story.tsx +7 -50
  44. package/src/uploadInput/types.ts +1 -11
  45. package/src/uploadInput/uploadItem/UploadItem.tsx +6 -25
  46. package/src/sticky/Sticky.spec.js +0 -34
package/build/index.mjs CHANGED
@@ -1,22 +1,22 @@
1
1
  import * as React from 'react';
2
- import React__default, { forwardRef, useId, cloneElement, useState, useEffect, useRef, useMemo, Component, createContext, useContext, useSyncExternalStore, useCallback, useImperativeHandle, createElement, PureComponent, createRef, isValidElement, Children, Fragment as Fragment$1 } from 'react';
2
+ import React__default, { forwardRef, useId, cloneElement, useState, useRef, useEffect, useCallback, Component, createContext, useContext, useSyncExternalStore, useImperativeHandle, createElement, Children, useMemo, PureComponent, createRef, isValidElement, Fragment as Fragment$1 } from 'react';
3
3
  import classNames from 'classnames';
4
4
  import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
5
- import { ChevronUp, CrossCircleFill, Cross, Check, Info as Info$1, Alert as Alert$1, ClockBorderless, NavigateAway, Briefcase, Person, ArrowRight, Download, ChevronLeft, ChevronRight, AlertCircleFill, AlertCircle, ArrowLeft, QuestionMarkCircle, Search, CrossCircle, ChevronDown, CheckCircleFill, ClockFill, Upload as Upload$2, Document, Plus, PlusCircle } from '@transferwise/icons';
6
- import { defineMessages, useIntl, injectIntl, IntlProvider } from 'react-intl';
7
- import PropTypes from 'prop-types';
8
- import commonmark from 'commonmark';
5
+ import { ChevronUp, NavigateAway, CrossCircleFill, Cross, Check, Info as Info$1, Alert as Alert$1, ClockBorderless, Briefcase, Person, ArrowRight, Download, ChevronLeft, ChevronRight, AlertCircleFill, AlertCircle, ArrowLeft, QuestionMarkCircle, Search, CrossCircle, ChevronDown, CheckCircleFill, ClockFill, Upload as Upload$2, Document, Plus, PlusCircle } from '@transferwise/icons';
6
+ import { usePopper } from 'react-popper';
9
7
  import { useTheme, ThemeProvider } from '@wise/components-theming';
10
8
  import { CSSTransition } from 'react-transition-group';
11
9
  import { FocusScope } from '@react-aria/focus';
12
10
  import { createPortal } from 'react-dom';
11
+ import { defineMessages, useIntl, injectIntl, IntlProvider } from 'react-intl';
13
12
  import { isUndefined, isNumber, isEmpty, isNull } from '@transferwise/neptune-validation';
13
+ import PropTypes from 'prop-types';
14
+ import commonmark from 'commonmark';
14
15
  import { formatDate, formatMoney, formatAmount } from '@transferwise/formatting';
15
16
  import { Transition, Listbox } from '@headlessui/react';
16
17
  import mergeProps from 'merge-props';
17
18
  import { useFloating, useDismiss, useRole, useInteractions, FloatingPortal, FloatingFocusManager, offset, flip, shift, size, autoUpdate } from '@floating-ui/react';
18
19
  import { usePreventScroll } from '@react-aria/overlays';
19
- import { usePopper } from 'react-popper';
20
20
  import { Flag, Illustration } from '@wise/art';
21
21
  import clamp$2 from 'lodash.clamp';
22
22
  import debounce from 'lodash.debounce';
@@ -664,585 +664,358 @@ const ActionOption = ({
664
664
  });
665
665
  };
666
666
 
667
- var messages$d = defineMessages({
668
- ariaLabel: {
669
- id: "neptune.CloseButton.ariaLabel"
670
- }
671
- });
672
-
673
- const CloseButton = /*#__PURE__*/forwardRef(function CloseButton({
674
- 'aria-label': ariaLabel,
675
- size = Size.MEDIUM,
676
- filled = false,
677
- className,
678
- onClick,
679
- isDisabled,
680
- testId
681
- }, reference) {
682
- const intl = useIntl();
683
- ariaLabel ??= intl.formatMessage(messages$d.ariaLabel);
684
- const Icon = filled ? CrossCircleFill : Cross;
685
- return /*#__PURE__*/jsx("button", {
686
- ref: reference,
687
- type: "button",
688
- className: classNames('np-close-button', 'close btn-link', 'text-no-decoration', {
689
- 'np-close-button--large': size === Size.MEDIUM,
690
- 'np-close-button--x-large': size === Size.LARGE
691
- }, className),
692
- "aria-label": ariaLabel,
693
- "aria-disabled": isDisabled,
694
- disabled: isDisabled,
695
- "data-testid": testId,
696
- onClick: onClick,
697
- children: /*#__PURE__*/jsx(Icon, {
698
- size: size === Size.SMALL ? 16 : 24
699
- })
700
- });
701
- });
702
-
703
- const iconTypeMap = {
704
- positive: Check,
705
- neutral: Info$1,
706
- warning: Alert$1,
707
- negative: Cross,
708
- pending: ClockBorderless,
709
- info: Info$1,
710
- error: Cross,
711
- success: Check
712
- };
713
- const StatusIcon = ({
714
- sentiment = 'neutral',
715
- size = 'md'
667
+ const FocusBoundary = ({
668
+ children
716
669
  }) => {
717
- const Icon = iconTypeMap[sentiment];
718
- const iconColor = sentiment === 'warning' || sentiment === 'pending' ? 'dark' : 'light';
719
- return /*#__PURE__*/jsx("span", {
720
- "data-testid": "status-icon",
721
- className: classNames('status-circle', 'status-circle-' + size, sentiment),
722
- children: /*#__PURE__*/jsx(Icon, {
723
- className: classNames('status-icon', iconColor)
670
+ const wrapperReference = useRef(null);
671
+ useEffect(() => {
672
+ wrapperReference.current?.focus({
673
+ preventScroll: true
674
+ });
675
+ }, []);
676
+ return /*#__PURE__*/jsx(FocusScope, {
677
+ contain: true,
678
+ restoreFocus: true,
679
+ children: /*#__PURE__*/jsx("div", {
680
+ ref: wrapperReference,
681
+ tabIndex: -1,
682
+ children: children
724
683
  })
725
684
  });
726
685
  };
727
686
 
728
- const DEFAULT_TYPE = Typography.TITLE_GROUP;
729
- const titleTypeMapping = {
730
- [Typography.TITLE_SCREEN]: 'h1',
731
- [Typography.TITLE_SECTION]: 'h2',
732
- [Typography.TITLE_SUBSECTION]: 'h3',
733
- [Typography.TITLE_BODY]: 'h4',
734
- [Typography.TITLE_GROUP]: 'h5'
735
- };
736
- function Title({
737
- as,
738
- type = DEFAULT_TYPE,
739
- className,
740
- ...props
741
- }) {
742
- const mapping = titleTypeMapping[type];
743
- const isTypeSupported = mapping !== undefined;
744
- if (isTypeSupported) {
745
- const HeaderTag = as ?? mapping;
746
- return /*#__PURE__*/jsx(HeaderTag, {
747
- ...props,
748
- className: classNames(`np-text-${type}`, className)
749
- });
750
- }
751
- const HeaderTag = as ?? titleTypeMapping[DEFAULT_TYPE];
752
- return /*#__PURE__*/jsx(HeaderTag, {
753
- ...props,
754
- className: classNames(`np-text-${DEFAULT_TYPE}`, className)
755
- });
756
- }
757
-
758
- function logActionRequired(message) {
759
- if (typeof process !== 'undefined' && process.env?.NODE_ENV !== 'production') {
760
- // eslint-disable-next-line no-console
761
- console.warn(message);
762
- }
763
- }
764
- function logActionRequiredIf(message, conditional) {
765
- if (conditional) {
766
- logActionRequired(message);
767
- }
687
+ function withNextPortalWrapper(Component) {
688
+ return function (props) {
689
+ const [mounted, setMounted] = useState(false);
690
+ useEffect(() => {
691
+ setMounted(true);
692
+ }, [setMounted]);
693
+ return mounted ? /*#__PURE__*/createPortal( /*#__PURE__*/jsx(Component, {
694
+ ...props
695
+ }), document.body) : null;
696
+ };
768
697
  }
769
698
 
770
- const reader = new commonmark.Parser();
771
- const writer = new commonmark.HtmlRenderer({
772
- safe: true
773
- });
774
- const NODE_TYPE_LIST = Object.values(MarkdownNodeType);
775
- function Markdown({
776
- as: Element = 'div',
777
- allowList,
778
- blockList,
779
- config,
780
- className,
781
- children
782
- }) {
783
- if (!children) {
784
- return null;
785
- }
786
- const linkTarget = config?.link?.target ?? '_self';
787
- const paragraphClass = config?.paragraph?.className ?? '';
788
- if (allowList != null && blockList != null) {
789
- logActionRequired('Markdown supports only one of `allowList` or `blockList` to be used at a time. `blockList` will be ignored.');
699
+ /**
700
+ * Dimmer state management inspired by Material UI's ModalManager (https://github.com/mui-org/material-ui)
701
+ */
702
+ class DimmerManager {
703
+ /**
704
+ * Dimmer refs
705
+ */
706
+ dimmers;
707
+ constructor() {
708
+ this.dimmers = [];
790
709
  }
791
- const parser = nodes => {
792
- const parsed = reader.parse(nodes);
793
- const toExclude = allowList != null ? NODE_TYPE_LIST.filter(type => !allowList.includes(type)) : blockList;
794
- return toExclude != null ? stripNodes({
795
- parsed,
796
- blockList: toExclude
797
- }) : parsed;
798
- };
799
- const createMarkup = () => {
800
- const parsed = parser(children);
801
- return writer.render(parsed).replace(/<a href="/g, `<a target="${linkTarget}" href="`).replace(/<p>/g, `<p class="${paragraphClass}">`);
802
- };
803
- return /*#__PURE__*/jsx(Element, {
804
- className: className,
805
- dangerouslySetInnerHTML: {
806
- __html: createMarkup()
710
+ add(dimmer) {
711
+ let dimmerIndex = this.dimmers.indexOf(dimmer);
712
+ if (dimmerIndex !== -1) {
713
+ return dimmerIndex;
807
714
  }
808
- });
809
- }
810
- function stripNodes({
811
- blockList,
812
- parsed
813
- }) {
814
- if (!parsed) {
815
- return parsed;
715
+ dimmerIndex = this.dimmers.length;
716
+ this.dimmers.push(dimmer);
717
+ return dimmerIndex;
816
718
  }
817
- const walker = parsed.walker();
818
- for (let event = walker.next(); event != null; event = walker.next()) {
819
- const {
820
- node
821
- } = event;
822
- if (blockList.includes(node.type) && !event.entering) {
823
- while (node.firstChild != null) {
824
- node.insertBefore(node.firstChild);
825
- }
826
- node.unlink();
719
+ remove(dimmer) {
720
+ const dimmerIndex = this.dimmers.indexOf(dimmer);
721
+ if (dimmerIndex !== -1) {
722
+ this.dimmers.splice(dimmerIndex, 1);
827
723
  }
724
+ return dimmerIndex;
725
+ }
726
+ isTop(dimmer) {
727
+ return this.dimmers.length > 0 && this.dimmers[this.dimmers.length - 1] === dimmer;
828
728
  }
829
- return parsed;
830
729
  }
831
730
 
832
- const allowList = [MarkdownNodeType.STRONG];
833
- const InlineMarkdown = props => {
834
- return /*#__PURE__*/jsx(Markdown, {
835
- ...props,
836
- as: "span",
837
- allowList: allowList,
838
- blockList: undefined
839
- });
840
- };
841
- InlineMarkdown.propTypes = {
842
- children: PropTypes.string.isRequired,
843
- className: PropTypes.string
844
- };
845
- InlineMarkdown.defaultProps = {
846
- className: undefined
847
- };
848
-
849
- var messages$c = defineMessages({
850
- opensInNewTab: {
851
- id: "neptune.Link.opensInNewTab"
731
+ const EXIT_ANIMATION$1 = 350;
732
+ const dimmerManager = new DimmerManager();
733
+ const handleTouchMove = event => {
734
+ const isTouchedElementDimmer = event.target.classList.contains('dimmer');
735
+ // disable scroll on iOS devices for Dimmer area
736
+ // this is because of bug in WebKit https://bugs.webkit.org/show_bug.cgi?id=220908
737
+ // note: scrolling still works for children(s) as expected
738
+ if (isIosDevice() && isTouchedElementDimmer) {
739
+ event.stopPropagation();
740
+ event.preventDefault();
852
741
  }
853
- });
854
-
855
- const Link = ({
856
- className,
857
- children,
858
- href,
859
- target,
860
- type,
861
- 'aria-label': ariaLabel,
862
- onClick,
863
- ...props
864
- }) => {
865
- const isBlank = target === '_blank';
866
- const {
867
- formatMessage
868
- } = useIntl();
869
- return /*#__PURE__*/jsxs("a", {
870
- href: href,
871
- target: target,
872
- className: classNames('np-link', type ? `np-text-${type}` : undefined, 'd-inline-flex', className),
873
- "aria-label": ariaLabel,
874
- rel: isBlank ? 'noreferrer' : undefined,
875
- onClick: onClick,
876
- ...props,
877
- children: [children, " ", isBlank && /*#__PURE__*/jsx(NavigateAway, {
878
- title: formatMessage(messages$c.opensInNewTab)
879
- })]
880
- });
881
- };
882
-
883
- function Action({
884
- action,
885
- className
886
- }) {
887
- if ('href' in action) {
888
- return /*#__PURE__*/jsx(Link, {
889
- href: action.href,
890
- className: className,
891
- "aria-label": action['aria-label'],
892
- target: action.target,
893
- type: Typography.LINK_LARGE,
894
- onClick: action.onClick,
895
- children: action.text
896
- });
897
- }
898
- return /*#__PURE__*/jsx("button", {
899
- type: "button",
900
- "aria-label": action['aria-label'],
901
- className: classNames('btn-unstyled np-text-link-large', className),
902
- onClick: action.onClick,
903
- children: action.text
904
- });
905
- }
906
-
907
- var AlertArrowPosition;
908
- (function (AlertArrowPosition) {
909
- AlertArrowPosition["TOP_LEFT"] = "up-left";
910
- AlertArrowPosition["TOP"] = "up-center";
911
- AlertArrowPosition["TOP_RIGHT"] = "up-right";
912
- AlertArrowPosition["BOTTOM_LEFT"] = "down-left";
913
- AlertArrowPosition["BOTTOM"] = "down-center";
914
- AlertArrowPosition["BOTTOM_RIGHT"] = "down-right";
915
- })(AlertArrowPosition || (AlertArrowPosition = {}));
916
- function resolveType(type) {
917
- switch (type) {
918
- case 'success':
919
- return 'positive';
920
- case 'info':
921
- return 'neutral';
922
- case 'error':
923
- return 'negative';
924
- default:
925
- return type;
926
- }
927
- }
928
- function Alert({
929
- arrow,
930
- action,
742
+ };
743
+ const Dimmer = ({
931
744
  children,
932
745
  className,
933
- dismissible,
934
- icon,
935
- onDismiss,
936
- message,
937
- size,
938
- title,
939
- type = 'neutral',
940
- variant = 'desktop'
941
- }) {
942
- useEffect(() => {
943
- if (arrow !== undefined) {
944
- logActionRequired("Alert component doesn't support 'arrow' anymore, use 'InlineAlert' instead.");
746
+ disableClickToClose = false,
747
+ contentPosition,
748
+ fadeContentOnEnter = false,
749
+ fadeContentOnExit = false,
750
+ open = false,
751
+ scrollable = false,
752
+ transparent = false,
753
+ onClose
754
+ }) => {
755
+ const [hasNotExited, setHasNotExited] = useState(false);
756
+ const dimmerReference = useRef(null);
757
+ const closeOnClick = event => {
758
+ if (event.target === dimmerReference.current) {
759
+ onClose?.(event);
945
760
  }
946
- }, [arrow]);
947
- useEffect(() => {
948
- if (children !== undefined) {
949
- logActionRequired("Alert component doesn't support 'children' anymore, use 'message' instead.");
761
+ };
762
+ const handleClick = event => {
763
+ if (disableClickToClose || !onClose) {
764
+ return;
950
765
  }
951
- }, [children]);
952
- useEffect(() => {
953
- if (dismissible !== undefined) {
954
- logActionRequired("Alert component doesn't support 'dismissible' anymore, use 'onDismiss' instead.");
766
+ closeOnClick(event);
767
+ };
768
+ const handleKeyDown = useCallback(event => {
769
+ if (event.key !== 'Escape') {
770
+ return;
955
771
  }
956
- }, [dismissible]);
957
- useEffect(() => {
958
- if (size !== undefined) {
959
- logActionRequired("Alert component doesn't support 'size' anymore, please remove that prop.");
772
+ event.stopPropagation();
773
+ if (onClose && dimmerReference.current && dimmerManager.isTop(dimmerReference.current)) {
774
+ onClose(event);
960
775
  }
961
- }, [size]);
962
- const resolvedType = resolveType(type);
776
+ }, [onClose]);
777
+ const onEnter = () => {
778
+ setHasNotExited(true);
779
+ if (dimmerReference.current) {
780
+ dimmerManager.add(dimmerReference.current);
781
+ }
782
+ };
783
+ const onExited = () => {
784
+ setHasNotExited(false);
785
+ if (dimmerReference.current) {
786
+ dimmerManager.remove(dimmerReference.current);
787
+ }
788
+ };
963
789
  useEffect(() => {
964
- if (resolvedType !== type) {
965
- logActionRequired(`Alert component has deprecated '${type}' value for the 'type' prop. Please use '${resolvedType}' instead.`);
790
+ const localReferenceCopy = dimmerReference.current;
791
+ if (open) {
792
+ document.addEventListener('keydown', handleKeyDown);
793
+ localReferenceCopy?.addEventListener('touchmove', handleTouchMove, {
794
+ passive: true
795
+ });
966
796
  }
967
- }, [resolvedType, type]);
968
- const [shouldFire, setShouldFire] = useState(false);
969
- const closeButtonReference = useRef(null);
970
- return /*#__PURE__*/jsxs("div", {
971
- className: classNames('alert d-flex', `alert-${resolvedType}`, arrow != null && alertArrowClassNames(arrow), className),
972
- "data-testid": "alert",
973
- onTouchStart: () => setShouldFire(true),
974
- onTouchEnd: event => {
975
- if (shouldFire && action?.href &&
976
- // Check if current event is triggered from closeButton
977
- event.target instanceof Node && closeButtonReference.current && !closeButtonReference.current.contains(event.target)) {
978
- if (action.target === '_blank') {
979
- window.top?.open(action.href);
980
- } else {
981
- window.top?.location.assign(action.href);
982
- }
983
- }
984
- setShouldFire(false);
985
- },
986
- onTouchMove: () => setShouldFire(false),
987
- children: [/*#__PURE__*/jsxs("div", {
988
- className: classNames('alert__content', 'd-flex', 'flex-grow-1', variant),
989
- "data-testid": variant,
990
- children: [icon ? /*#__PURE__*/jsx("div", {
991
- className: "alert__icon",
992
- children: icon
993
- }) : /*#__PURE__*/jsx(StatusIcon, {
994
- size: Size.LARGE,
995
- sentiment: resolvedType
996
- }), /*#__PURE__*/jsxs("div", {
997
- className: "alert__message",
998
- children: [/*#__PURE__*/jsxs("div", {
999
- role: Sentiment.NEGATIVE === resolvedType ? 'alert' : 'status',
1000
- children: [title && /*#__PURE__*/jsx(Title, {
1001
- className: "m-b-1",
1002
- type: Typography.TITLE_BODY,
1003
- children: title
1004
- }), /*#__PURE__*/jsx(Body, {
1005
- as: "span",
1006
- className: "d-block",
1007
- type: Typography.BODY_LARGE,
1008
- children: children || /*#__PURE__*/jsx(InlineMarkdown, {
1009
- children: message
797
+ return () => {
798
+ document.removeEventListener('keydown', handleKeyDown);
799
+ localReferenceCopy?.removeEventListener('touchmove', handleTouchMove);
800
+ };
801
+ }, [handleKeyDown, open]);
802
+ return /*#__PURE__*/jsx(DimmerWrapper, {
803
+ open: open,
804
+ hasNotExited: hasNotExited,
805
+ children: /*#__PURE__*/jsx(CSSTransition, {
806
+ nodeRef: dimmerReference,
807
+ in: open,
808
+ appear: true
809
+ // Wait for animation to finish before unmount.
810
+ ,
811
+ timeout: {
812
+ enter: 0,
813
+ exit: EXIT_ANIMATION$1
814
+ },
815
+ classNames: {
816
+ enter: classNames({
817
+ 'dimmer--enter-fade': fadeContentOnEnter
818
+ }),
819
+ enterDone: classNames('dimmer--enter-done', {
820
+ 'dimmer--enter-fade': fadeContentOnEnter
821
+ }),
822
+ exit: classNames('dimmer--exit', {
823
+ 'dimmer--exit-fade': fadeContentOnExit
824
+ })
825
+ },
826
+ unmountOnExit: true,
827
+ onEnter: onEnter,
828
+ onExited: onExited,
829
+ children: /*#__PURE__*/jsx(DimmerContentWrapper, {
830
+ scrollBody: !transparent,
831
+ children: /*#__PURE__*/jsx(FocusBoundary, {
832
+ children: /*#__PURE__*/jsx("div", {
833
+ ref: dimmerReference,
834
+ className: classNames('dimmer', {
835
+ 'dimmer--scrollable': scrollable,
836
+ 'dimmer--transparent': transparent
837
+ }, className),
838
+ role: "presentation",
839
+ onClick: handleClick,
840
+ children: /*#__PURE__*/jsx("div", {
841
+ className: classNames('dimmer-content-positioner', contentPosition != null && ['d-flex justify-content-center', {
842
+ 'align-items-start': contentPosition === 'top',
843
+ 'align-items-center': contentPosition === 'center',
844
+ 'align-items-end': contentPosition === 'bottom'
845
+ }]),
846
+ children: children
1010
847
  })
1011
- })]
1012
- }), action && /*#__PURE__*/jsx(Action, {
1013
- action: action,
1014
- className: "m-t-1"
1015
- })]
1016
- })]
1017
- }), onDismiss && /*#__PURE__*/jsx(CloseButton, {
1018
- ref: closeButtonReference,
1019
- className: "m-l-2",
1020
- onClick: onDismiss
1021
- })]
848
+ })
849
+ })
850
+ })
851
+ })
1022
852
  });
1023
- }
1024
- function alertArrowClassNames(arrow) {
1025
- switch (arrow) {
1026
- case 'down-center':
1027
- return 'arrow arrow-bottom arrow-center';
1028
- case 'down-left':
1029
- return 'arrow arrow-bottom arrow-left';
1030
- case 'down-right':
1031
- return 'arrow arrow-bottom arrow-right';
1032
- case 'up-center':
1033
- return 'arrow arrow-center';
1034
- case 'up-right':
1035
- return 'arrow arrow-right';
1036
- case 'up-left':
1037
- default:
1038
- return 'arrow';
1039
- }
1040
- }
1041
-
1042
- // TODO: consider to move this enum into component file once we migrate it on TypeScript or replace with some common enum
1043
- var AvatarType;
1044
- (function (AvatarType) {
1045
- AvatarType["THUMBNAIL"] = "thumbnail";
1046
- AvatarType["ICON"] = "icon";
1047
- AvatarType["EMOJI"] = "emoji";
1048
- AvatarType["INITIALS"] = "initials";
1049
- })(AvatarType || (AvatarType = {}));
1050
-
1051
- /*
1052
- * The colors we support generating an Avatar background color from a "seed" for.
1053
- * Changing this array will change the assignment between seeds.
1054
- * Do not change this array.
1055
- */
1056
- const avatarColors = ['--color-bright-blue', '--color-bright-yellow', '--color-bright-pink', '--color-bright-orange'];
1057
- /*
1058
- * Takes in a "seed" string and spits out an index for the color we should use.
1059
- * This implementation has been synced across all three clients so that we consistently
1060
- * generate branded avatar colors when rendering a list of Avatars.
1061
- * Do not change this implementation.
1062
- */
1063
- const hashSeed = seed => {
1064
- const base = 31;
1065
- const modulo = avatarColors.length;
1066
- let hashValue = 0;
1067
- let basePow = 1;
1068
- for (let i = 0; i < seed.length; i += 1) {
1069
- hashValue = (hashValue + seed.charCodeAt(i) * basePow) % modulo;
1070
- basePow = basePow * base % modulo;
1071
- }
1072
- return hashValue;
1073
- };
1074
- const getAvatarColorFromSeed = seed => {
1075
- return avatarColors[hashSeed(seed)];
1076
- };
1077
-
1078
- const backwardsCompatibleSize = size => {
1079
- switch (size) {
1080
- case 'sm':
1081
- return 24;
1082
- case 'md':
1083
- return 48;
1084
- case 'lg':
1085
- return 72;
1086
- default:
1087
- return size;
1088
- }
1089
853
  };
1090
- const Avatar = ({
1091
- backgroundColor = null,
1092
- backgroundColorSeed = null,
1093
- children = null,
1094
- className,
1095
- outlined = false,
1096
- size: sizeFromProps = 48,
1097
- theme = Theme.LIGHT,
1098
- type = 'thumbnail'
854
+ const DimmerWrapper = ({
855
+ open,
856
+ hasNotExited,
857
+ children
1099
858
  }) => {
1100
- const backgroundColorFromSeed = useMemo(() => !backgroundColor && backgroundColorSeed ? `var(${getAvatarColorFromSeed(backgroundColorSeed)})` : undefined, [backgroundColor, backgroundColorSeed]);
1101
- const size = backwardsCompatibleSize(sizeFromProps);
1102
- return /*#__PURE__*/jsx("div", {
1103
- className: classNames('tw-avatar', className, `tw-avatar--${size}`, `tw-avatar--${type}`, {
1104
- 'tw-avatar--outlined': outlined,
1105
- 'tw-avatar--branded': Boolean(backgroundColorFromSeed),
1106
- 'np-text-title-body': type === 'initials'
1107
- }),
1108
- children: /*#__PURE__*/jsx("div", {
1109
- className: "tw-avatar__content",
1110
- style: {
1111
- backgroundColor: backgroundColor || backgroundColorFromSeed
1112
- },
1113
- children: children
1114
- })
859
+ const {
860
+ screenMode,
861
+ theme
862
+ } = useTheme();
863
+ return open || hasNotExited ? /*#__PURE__*/jsx(ThemeProvider, {
864
+ theme: "personal",
865
+ screenMode: theme === 'personal' ? screenMode : 'light',
866
+ isNotRootProvider: true,
867
+ children: children
868
+ }) : /*#__PURE__*/jsx(Fragment, {
869
+ children: children
1115
870
  });
1116
871
  };
1117
-
1118
- const Badge = ({
1119
- badge,
1120
- className = undefined,
1121
- size = Size.SMALL,
1122
- border = Theme.LIGHT,
1123
- children
872
+ const DimmerContentWrapper = ({
873
+ children,
874
+ scrollBody
1124
875
  }) => {
1125
- const classes = classNames('tw-badge', {
1126
- [`tw-badge-border-${border}`]: border,
1127
- [`tw-badge-${size}`]: size
1128
- }, className);
1129
- return /*#__PURE__*/jsxs("div", {
1130
- className: classes,
1131
- children: [/*#__PURE__*/jsx("div", {
1132
- className: "tw-badge__children",
1133
- children: children
1134
- }), /*#__PURE__*/jsx("div", {
1135
- className: "tw-badge__content",
1136
- children: badge
1137
- })]
1138
- });
876
+ useEffect(() => {
877
+ if (scrollBody) {
878
+ addNoScrollClass();
879
+ }
880
+ return () => {
881
+ if (scrollBody) {
882
+ removeNoScrollClass();
883
+ }
884
+ };
885
+ }, [scrollBody]);
886
+ return children;
1139
887
  };
888
+ var Dimmer$1 = withNextPortalWrapper(Dimmer);
1140
889
 
1141
- const OptionalBadge = ({
1142
- url,
1143
- altText,
1144
- statusIcon,
890
+ const POPOVER_OFFSET = [0, 16];
891
+ // By default the flip positioning explores only the opposite alternative. So if left is passed and there's no enough space
892
+ // the right one gets chosen. If there's no space on both sides popover goes back to the initially chosen one left.
893
+ // This mapping forces popover to try the four available positions before going back to the initial chosen one.
894
+ const fallbackPlacements = {
895
+ [Position.TOP]: [Position.BOTTOM, Position.RIGHT, Position.LEFT],
896
+ [Position.BOTTOM]: [Position.TOP, Position.RIGHT, Position.LEFT],
897
+ [Position.LEFT]: [Position.RIGHT, Position.TOP, Position.BOTTOM],
898
+ [Position.RIGHT]: [Position.LEFT, Position.TOP, Position.BOTTOM]
899
+ };
900
+ const Panel = /*#__PURE__*/forwardRef(function Panel({
901
+ arrow = false,
902
+ flip = true,
903
+ altAxis = false,
1145
904
  children,
905
+ open = false,
906
+ onClose,
907
+ position = Position.BOTTOM,
908
+ anchorRef,
909
+ anchorWidth = false,
1146
910
  ...rest
1147
- }) => {
1148
- if (url) {
1149
- return /*#__PURE__*/jsx(Badge, {
1150
- badge: /*#__PURE__*/jsx("img", {
1151
- src: url,
1152
- alt: altText
1153
- }),
1154
- ...rest,
1155
- children: children
911
+ }, reference) {
912
+ const [arrowElement, setArrowElement] = useState(null);
913
+ const [popperElement, setPopperElement] = useState(null);
914
+ const modifiers = [];
915
+ if (altAxis) {
916
+ modifiers.push({
917
+ // https://popper.js.org/docs/v2/modifiers/prevent-overflow
918
+ name: 'preventOverflow',
919
+ options: {
920
+ altAxis: true,
921
+ tether: false
922
+ }
1156
923
  });
1157
924
  }
1158
- if (statusIcon) {
1159
- return /*#__PURE__*/jsx(Badge, {
1160
- badge: /*#__PURE__*/jsx(StatusIcon, {
1161
- sentiment: statusIcon,
1162
- size: Size.SMALL
1163
- }),
1164
- ...rest,
1165
- children: children
925
+ if (arrow) {
926
+ modifiers.push({
927
+ name: 'arrow',
928
+ options: {
929
+ element: arrowElement,
930
+ options: {
931
+ padding: 8 // 8px from the edges of the popper
932
+ }
933
+ }
934
+ });
935
+ // This lets you displace a popper element from its reference element.
936
+ modifiers.push({
937
+ name: 'offset',
938
+ options: {
939
+ offset: POPOVER_OFFSET
940
+ }
1166
941
  });
1167
942
  }
1168
- return /*#__PURE__*/jsx(Fragment, {
1169
- children: children
943
+ if (flip && fallbackPlacements[position]) {
944
+ modifiers.push({
945
+ name: 'flip',
946
+ options: {
947
+ fallbackPlacements: fallbackPlacements[position]
948
+ }
949
+ });
950
+ }
951
+ const {
952
+ styles,
953
+ attributes,
954
+ forceUpdate
955
+ } = usePopper(anchorRef.current, popperElement, {
956
+ placement: position,
957
+ modifiers
1170
958
  });
1171
- };
1172
- const AvatarWrapper = ({
1173
- url,
1174
- profileType,
1175
- profileId,
1176
- badgeUrl,
1177
- badgeAltText,
1178
- badgeStatusIcon,
1179
- name,
1180
- avatarProps,
1181
- badgeProps
1182
- }) => {
1183
- const [hasImageLoadError, setImageLoadError] = useState(false);
1184
- const isBusinessProfile = profileType === ProfileType.BUSINESS;
1185
- // Reset the errored state when url changes
1186
- useEffect(() => setImageLoadError(false), [url]);
1187
- const getAvatarProps = () => {
1188
- if (url && !hasImageLoadError) {
1189
- return {
1190
- type: AvatarType.THUMBNAIL,
1191
- children: /*#__PURE__*/jsx("img", {
1192
- src: url,
1193
- alt: "",
1194
- onError: () => setImageLoadError(true)
1195
- }),
1196
- ...avatarProps
1197
- };
1198
- }
1199
- if (profileType) {
1200
- return {
1201
- type: AvatarType.ICON,
1202
- children: isBusinessProfile ? /*#__PURE__*/jsx(Briefcase, {
1203
- size: "24"
1204
- }) : /*#__PURE__*/jsx(Person, {
1205
- size: "24"
1206
- }),
1207
- ...avatarProps
1208
- };
959
+ // If the trigger is not visible when the position is calculated, it will be incorrect. Because this can happen repeatedly (on resize for example),
960
+ // it is most simple just to always position before opening
961
+ useEffect(() => {
962
+ if (open && forceUpdate) {
963
+ forceUpdate();
1209
964
  }
1210
- if (name) {
1211
- return {
1212
- type: AvatarType.INITIALS,
1213
- children: /*#__PURE__*/jsx(Fragment, {
1214
- children: getInitials(name)
1215
- }),
1216
- backgroundColorSeed: profileId?.toString(),
1217
- ...avatarProps
1218
- };
1219
- }
1220
- return {
1221
- type: AvatarType.ICON,
1222
- children: /*#__PURE__*/jsx(Person, {
1223
- size: "24"
1224
- }),
1225
- ...avatarProps
1226
- };
965
+ }, [open]);
966
+ const contentStyle = {
967
+ ...(anchorWidth ? {
968
+ width: anchorRef.current?.clientWidth
969
+ } : undefined)
1227
970
  };
1228
- return /*#__PURE__*/jsx(OptionalBadge, {
1229
- url: badgeUrl,
1230
- altText: badgeAltText,
1231
- statusIcon: badgeStatusIcon,
1232
- ...badgeProps,
1233
- children: /*#__PURE__*/jsx(Avatar, {
1234
- size: Size.MEDIUM,
1235
- ...getAvatarProps()
971
+ return /*#__PURE__*/jsx(Dimmer$1, {
972
+ open: open,
973
+ transparent: true,
974
+ fadeContentOnEnter: true,
975
+ fadeContentOnExit: true,
976
+ onClose: onClose,
977
+ children: /*#__PURE__*/jsx("div", {
978
+ ...rest,
979
+ ref: setPopperElement,
980
+ role: "dialog"
981
+ // eslint-disable-next-line react/forbid-dom-props
982
+ ,
983
+ style: {
984
+ ...styles.popper
985
+ },
986
+ ...attributes.popper,
987
+ className: classNames('np-panel', {
988
+ 'np-panel--open': open
989
+ }, rest.className),
990
+ children: /*#__PURE__*/jsxs("div", {
991
+ ref: reference
992
+ /* eslint-disable-next-line react/forbid-dom-props */,
993
+ style: contentStyle,
994
+ className: classNames('np-panel__content'),
995
+ children: [children, arrow && /*#__PURE__*/jsx("div", {
996
+ ref: setArrowElement,
997
+ className: classNames('np-panel__arrow')
998
+ // eslint-disable-next-line react/forbid-dom-props
999
+ ,
1000
+ style: styles.arrow
1001
+ })]
1002
+ })
1236
1003
  })
1237
1004
  });
1005
+ });
1006
+
1007
+ const Section = ({
1008
+ children,
1009
+ className,
1010
+ withHorizontalPadding = false
1011
+ }) => {
1012
+ return /*#__PURE__*/jsx("div", {
1013
+ className: classNames('np-section', className, {
1014
+ 'np-section--with-horizontal-padding': withHorizontalPadding
1015
+ }),
1016
+ children: children
1017
+ });
1238
1018
  };
1239
- function getInitials(name) {
1240
- const allInitials = name.split(' ').map(part => part[0]).join('').toUpperCase();
1241
- if (allInitials.length === 1) {
1242
- return allInitials[0];
1243
- }
1244
- return allInitials[0] + allInitials.slice(-1);
1245
- }
1246
1019
 
1247
1020
  const radius = {
1248
1021
  xxs: 6,
@@ -1351,7 +1124,7 @@ class ProcessIndicator extends Component {
1351
1124
  }
1352
1125
  }
1353
1126
 
1354
- var messages$b = defineMessages({
1127
+ var messages$e = defineMessages({
1355
1128
  loadingAriaLabel: {
1356
1129
  id: "neptune.Button.loadingAriaLabel"
1357
1130
  }
@@ -1368,6 +1141,18 @@ const priorityClassMap = {
1368
1141
  [Priority.TERTIARY]: 'btn-priority-3'
1369
1142
  };
1370
1143
 
1144
+ function logActionRequired(message) {
1145
+ if (typeof process !== 'undefined' && process.env?.NODE_ENV !== 'production') {
1146
+ // eslint-disable-next-line no-console
1147
+ console.warn(message);
1148
+ }
1149
+ }
1150
+ function logActionRequiredIf(message, conditional) {
1151
+ if (conditional) {
1152
+ logActionRequired(message);
1153
+ }
1154
+ }
1155
+
1371
1156
  const deprecatedTypeMap = {
1372
1157
  [Type.PRIMARY]: ControlType.ACCENT,
1373
1158
  [Type.SECONDARY]: ControlType.ACCENT,
@@ -1470,7 +1255,7 @@ const Button = /*#__PURE__*/forwardRef(({
1470
1255
  className: classes,
1471
1256
  ...props,
1472
1257
  "aria-live": loading ? 'polite' : 'off',
1473
- "aria-label": loading ? intl.formatMessage(messages$b.loadingAriaLabel) : rest['aria-label'],
1258
+ "aria-label": loading ? intl.formatMessage(messages$e.loadingAriaLabel) : rest['aria-label'],
1474
1259
  children: [children, loading && /*#__PURE__*/jsx(ProcessIndicator, {
1475
1260
  size: processIndicatorSize(),
1476
1261
  className: "btn-loader"
@@ -1478,55 +1263,137 @@ const Button = /*#__PURE__*/forwardRef(({
1478
1263
  });
1479
1264
  });
1480
1265
 
1481
- const Card$2 = /*#__PURE__*/forwardRef(({
1266
+ var messages$d = defineMessages({
1267
+ opensInNewTab: {
1268
+ id: "neptune.Link.opensInNewTab"
1269
+ }
1270
+ });
1271
+
1272
+ const Link = ({
1482
1273
  className,
1483
- children = null,
1484
- id,
1485
- isDisabled = false,
1486
- isSmall = false,
1487
- onDismiss,
1488
- testId,
1274
+ children,
1275
+ href,
1276
+ target,
1277
+ type,
1278
+ 'aria-label': ariaLabel,
1279
+ onClick,
1489
1280
  ...props
1490
- }, ref) => {
1491
- const closeButtonReference = useRef(null);
1492
- return /*#__PURE__*/jsxs("div", {
1493
- ref: ref,
1494
- className: classNames('np-Card', {
1495
- 'np-Card--small': !!isSmall,
1496
- 'is-disabled': !!isDisabled
1497
- }, className),
1498
- id: id,
1499
- "data-testid": testId,
1281
+ }) => {
1282
+ const isBlank = target === '_blank';
1283
+ const {
1284
+ formatMessage
1285
+ } = useIntl();
1286
+ return /*#__PURE__*/jsxs("a", {
1287
+ href: href,
1288
+ target: target,
1289
+ className: classNames('np-link', type ? `np-text-${type}` : undefined, 'd-inline-flex', className),
1290
+ "aria-label": ariaLabel,
1291
+ rel: isBlank ? 'noreferrer' : undefined,
1292
+ onClick: onClick,
1500
1293
  ...props,
1501
- children: [onDismiss && /*#__PURE__*/jsx(CloseButton, {
1502
- ref: closeButtonReference,
1503
- className: "np-Card-closeButton",
1504
- size: isSmall ? 'sm' : 'md',
1505
- isDisabled: isDisabled,
1506
- testId: "close-button",
1507
- onClick: e => {
1508
- stopPropagation$1(e);
1509
- onDismiss();
1510
- }
1511
- }), children]
1294
+ children: [children, " ", isBlank && /*#__PURE__*/jsx(NavigateAway, {
1295
+ title: formatMessage(messages$d.opensInNewTab)
1296
+ })]
1512
1297
  });
1513
- });
1514
- Card$2.displayName = 'Card';
1298
+ };
1515
1299
 
1516
- function Display({
1517
- as: Heading = 'h1',
1518
- type = Typography.DISPLAY_LARGE,
1519
- children,
1300
+ const DEFAULT_TYPE = Typography.TITLE_GROUP;
1301
+ const titleTypeMapping = {
1302
+ [Typography.TITLE_SCREEN]: 'h1',
1303
+ [Typography.TITLE_SECTION]: 'h2',
1304
+ [Typography.TITLE_SUBSECTION]: 'h3',
1305
+ [Typography.TITLE_BODY]: 'h4',
1306
+ [Typography.TITLE_GROUP]: 'h5'
1307
+ };
1308
+ function Title({
1309
+ as,
1310
+ type = DEFAULT_TYPE,
1520
1311
  className,
1521
- id
1312
+ ...props
1522
1313
  }) {
1523
- return /*#__PURE__*/jsx(Heading, {
1524
- id: id,
1525
- className: classNames(`np-text-${type}`, 'text-primary', className),
1526
- children: children
1314
+ const mapping = titleTypeMapping[type];
1315
+ const isTypeSupported = mapping !== undefined;
1316
+ if (isTypeSupported) {
1317
+ const HeaderTag = as ?? mapping;
1318
+ return /*#__PURE__*/jsx(HeaderTag, {
1319
+ ...props,
1320
+ className: classNames(`np-text-${type}`, className)
1321
+ });
1322
+ }
1323
+ const HeaderTag = as ?? titleTypeMapping[DEFAULT_TYPE];
1324
+ return /*#__PURE__*/jsx(HeaderTag, {
1325
+ ...props,
1326
+ className: classNames(`np-text-${DEFAULT_TYPE}`, className)
1527
1327
  });
1528
1328
  }
1529
1329
 
1330
+ const HeaderAction = ({
1331
+ action
1332
+ }) => {
1333
+ const {
1334
+ isModern
1335
+ } = useTheme();
1336
+ const props = {
1337
+ 'aria-label': action['aria-label']
1338
+ };
1339
+ if ('href' in action) {
1340
+ return /*#__PURE__*/jsx(Link, {
1341
+ href: action.href,
1342
+ target: action.target,
1343
+ onClick: action.onClick,
1344
+ ...props,
1345
+ children: action.text
1346
+ });
1347
+ }
1348
+ return isModern ? /*#__PURE__*/jsx(Button, {
1349
+ className: "np-header__button",
1350
+ priority: "tertiary",
1351
+ size: "sm",
1352
+ onClick: action.onClick,
1353
+ ...props,
1354
+ children: action.text
1355
+ }) : /*#__PURE__*/jsx(ActionButton, {
1356
+ onClick: action.onClick,
1357
+ ...props,
1358
+ children: action.text
1359
+ });
1360
+ };
1361
+ /**
1362
+ *
1363
+ * Neptune Web: https://transferwise.github.io/neptune-web/components/content/Header
1364
+ *
1365
+ */
1366
+ const Header = ({
1367
+ action,
1368
+ as = 'h5',
1369
+ title,
1370
+ className
1371
+ }) => {
1372
+ if (!action) {
1373
+ return /*#__PURE__*/jsx(Title, {
1374
+ as: as,
1375
+ type: Typography.TITLE_GROUP,
1376
+ className: classNames('np-header', 'np-header__title', className),
1377
+ children: title
1378
+ });
1379
+ }
1380
+ if (as === 'legend') {
1381
+ // eslint-disable-next-line no-console
1382
+ console.warn('Legends should be the first child in a fieldset, and this is not possible when including an action');
1383
+ }
1384
+ return /*#__PURE__*/jsxs("div", {
1385
+ className: classNames('np-header', className),
1386
+ children: [/*#__PURE__*/jsx(Title, {
1387
+ as: as,
1388
+ type: Typography.TITLE_GROUP,
1389
+ className: "np-header__title",
1390
+ children: title
1391
+ }), /*#__PURE__*/jsx(HeaderAction, {
1392
+ action: action
1393
+ })]
1394
+ });
1395
+ };
1396
+
1530
1397
  const useConditionalListener = ({
1531
1398
  attachListener,
1532
1399
  callback,
@@ -1655,1375 +1522,1881 @@ const useLayout = () => {
1655
1522
  };
1656
1523
  };
1657
1524
 
1658
- const EmptyTransparentImage = 'data:image/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==';
1659
- const Image = ({
1660
- id,
1661
- src,
1662
- alt,
1663
- onLoad,
1664
- onError,
1665
- className,
1666
- loading,
1667
- stretch = true,
1668
- role,
1669
- shrink = true
1670
- }) => {
1671
- const elementReference = useRef(null);
1672
- const [hasIntersected] = useHasIntersected({
1673
- elRef: elementReference,
1674
- loading
1675
- });
1676
- let imageSource = src;
1677
- let imageOnLoad = onLoad;
1678
- if (loading === 'lazy' && !hasIntersected) {
1679
- imageSource = EmptyTransparentImage;
1680
- imageOnLoad = undefined;
1525
+ var messages$c = defineMessages({
1526
+ ariaLabel: {
1527
+ id: "neptune.CloseButton.ariaLabel"
1681
1528
  }
1682
- return /*#__PURE__*/jsx("img", {
1683
- ref: elementReference,
1684
- id: id,
1685
- alt: alt,
1686
- src: imageSource,
1687
- className: classNames(['tw-image', {
1688
- 'tw-image__stretch': stretch,
1689
- 'tw-image__shrink': shrink
1690
- }, className]),
1691
- role: role,
1692
- onLoad: imageOnLoad,
1693
- onError: onError
1694
- });
1695
- };
1529
+ });
1696
1530
 
1697
- const defaultPromoCardContext = {
1698
- state: '',
1699
- isDisabled: false,
1700
- // eslint-disable-next-line @typescript-eslint/no-empty-function
1701
- onChange: () => {}
1702
- };
1703
- /**
1704
- * The PromoCard context object.
1705
- */
1706
- const PromoCardContext = /*#__PURE__*/createContext(defaultPromoCardContext);
1707
- /**
1708
- * A custom hook for accessing the PromoCard context object.
1709
- *
1710
- * The `usePromoCardContext` hook is used to access the PromoCard context object
1711
- * from within a child PromoCard component. It throws an error if the context
1712
- * object is not available, which can help with debugging and development.
1713
- *
1714
- * @returns {PromoCardContextType} - The PromoCard context object.
1715
- */
1716
- const usePromoCardContext = () => {
1717
- return useContext(PromoCardContext);
1718
- };
1531
+ const CloseButton = /*#__PURE__*/forwardRef(function CloseButton({
1532
+ 'aria-label': ariaLabel,
1533
+ size = Size.MEDIUM,
1534
+ filled = false,
1535
+ className,
1536
+ onClick,
1537
+ isDisabled,
1538
+ testId
1539
+ }, reference) {
1540
+ const intl = useIntl();
1541
+ ariaLabel ??= intl.formatMessage(messages$c.ariaLabel);
1542
+ const Icon = filled ? CrossCircleFill : Cross;
1543
+ return /*#__PURE__*/jsx("button", {
1544
+ ref: reference,
1545
+ type: "button",
1546
+ className: classNames('np-close-button', 'close btn-link', 'text-no-decoration', {
1547
+ 'np-close-button--large': size === Size.MEDIUM,
1548
+ 'np-close-button--x-large': size === Size.LARGE
1549
+ }, className),
1550
+ "aria-label": ariaLabel,
1551
+ "aria-disabled": isDisabled,
1552
+ disabled: isDisabled,
1553
+ "data-testid": testId,
1554
+ onClick: onClick,
1555
+ children: /*#__PURE__*/jsx(Icon, {
1556
+ size: size === Size.SMALL ? 16 : 24
1557
+ })
1558
+ });
1559
+ });
1719
1560
 
1720
- const PromoCardIndicator = ({
1561
+ const EXIT_ANIMATION = 350;
1562
+ const SlidingPanel = /*#__PURE__*/forwardRef(({
1563
+ position = 'left',
1564
+ open,
1565
+ showSlidingPanelBorder,
1566
+ slidingPanelPositionFixed,
1721
1567
  className,
1722
1568
  children,
1723
- label,
1724
- icon,
1725
- isSmall = false,
1726
- testid,
1569
+ testId,
1727
1570
  ...rest
1728
- }) => {
1729
- const isIconString = icon && typeof icon === 'string';
1730
- const IconComponent = isIconString && {
1731
- check: Check,
1732
- arrow: ArrowRight,
1733
- download: Download
1734
- }[icon];
1735
- return /*#__PURE__*/jsxs("div", {
1736
- className: classNames('np-Card-indicator', className),
1737
- "data-testid": testid,
1571
+ }, reference) => {
1572
+ const localReference = useRef(null);
1573
+ useImperativeHandle(reference, () => localReference.current, []);
1574
+ return /*#__PURE__*/createElement(CSSTransition, {
1738
1575
  ...rest,
1739
- children: [label && /*#__PURE__*/jsx(Body, {
1740
- as: "span",
1741
- type: Typography.BODY_LARGE_BOLD,
1742
- className: "np-Card-indicatorText",
1743
- children: label
1744
- }), icon && /*#__PURE__*/jsx(Avatar, {
1745
- type: AvatarType.ICON,
1746
- size: isSmall ? 40 : 56,
1747
- backgroundColor: "var(--Card-indicator-icon-background-color)",
1748
- className: "np-Card-indicatorIcon",
1749
- children: IconComponent ? /*#__PURE__*/jsx(IconComponent, {
1750
- size: 24,
1751
- "aria-hidden": "true"
1752
- }) : icon
1753
- }), children]
1754
- });
1755
- };
1576
+ key: `sliding-panel--open-${position}`,
1577
+ nodeRef: localReference,
1578
+ in: open
1579
+ // Wait for animation to finish before unmount.
1580
+ ,
1581
+ timeout: {
1582
+ enter: 0,
1583
+ exit: EXIT_ANIMATION
1584
+ },
1585
+ classNames: "sliding-panel",
1586
+ appear: true,
1587
+ unmountOnExit: true
1588
+ }, /*#__PURE__*/jsx("div", {
1589
+ ref: localReference,
1590
+ "data-testid": testId,
1591
+ className: classNames('sliding-panel', `sliding-panel--open-${position}`, showSlidingPanelBorder && `sliding-panel--border-${position}`, slidingPanelPositionFixed && 'sliding-panel--fixed', className),
1592
+ children: children
1593
+ }));
1594
+ });
1756
1595
 
1757
- const PromoCard = /*#__PURE__*/forwardRef(({
1596
+ const Drawer = ({
1597
+ children,
1758
1598
  className,
1759
- description,
1760
- defaultChecked,
1761
- download,
1762
- href,
1763
- hrefLang,
1764
- id,
1765
- headingLevel = 'h3',
1766
- imageAlt,
1767
- imageClass,
1768
- imageSource,
1769
- indicatorLabel,
1770
- indicatorIcon,
1771
- isChecked,
1772
- isDisabled,
1773
- onClick,
1774
- onKeyDown,
1775
- rel,
1776
- tabIndex,
1777
- target,
1778
- testId,
1779
- title,
1780
- type,
1781
- value,
1782
- isSmall,
1783
- useDisplayFont = true,
1784
- anchorRef,
1785
- anchorId,
1786
- ...props
1787
- }, ref) => {
1788
- // Set the `checked` state to the value of `defaultChecked` if it is truthy,
1789
- // or the value of `isChecked` if it is truthy, or `false` if neither
1790
- // is truthy.
1599
+ footerContent,
1600
+ headerTitle,
1601
+ onClose,
1602
+ open,
1603
+ position
1604
+ }) => {
1605
+ logActionRequiredIf('Drawer now expects `onClose`, and will soon make this prop required. Please update your usage to provide it.', !onClose);
1791
1606
  const {
1792
- state,
1793
- onChange,
1794
- isDisabled: contextIsDisabled
1795
- } = usePromoCardContext();
1796
- const [checked, setChecked] = useState(type === 'checkbox' ? defaultChecked ?? isChecked ?? false : false);
1797
- const handleClick = () => {
1798
- if (type === 'radio') {
1799
- onChange(value || ''); // Update the context state for radio
1800
- } else if (type === 'checkbox') {
1801
- setChecked(!checked); // Update local state for checkbox
1802
- }
1803
- };
1804
- const fallbackId = useId();
1805
- const componentId = id || fallbackId;
1806
- // Set the icon to `'arrow'` if `href` is truthy and `type` is falsy, or
1807
- // `'download'` if `download` is truthy. If neither condition is true, set
1808
- // `icon` to `undefined`.
1809
- // Create a function to get icon type
1810
- const getIconType = () => {
1811
- if (indicatorIcon) {
1812
- return indicatorIcon;
1813
- }
1814
- if (download) {
1815
- return 'download';
1816
- }
1817
- if (href && !type) {
1818
- return 'arrow';
1819
- }
1820
- return undefined;
1821
- };
1822
- // Define all class names string based on the values of the `href`, `type`,
1823
- // `checked`, and `className` props.
1824
- const commonClasses = classNames({
1825
- 'np-Card--promoCard': true,
1826
- 'np-Card--checked': !href && type,
1827
- 'np-Card--link': href && !type,
1828
- 'is-checked': type === 'radio' ? value === state : type === 'checkbox' ? checked : undefined
1829
- }, className);
1830
- // Object with common props that will be passed to the `Card` components
1831
- const commonProps = {
1832
- className: commonClasses,
1833
- id: componentId,
1834
- isDisabled: isDisabled || contextIsDisabled,
1835
- onClick,
1836
- onKeyDown,
1837
- ref,
1838
- 'data-testid': testId,
1839
- isSmall
1840
- };
1841
- // Object with Anchor props that will be passed to the `a` element. These
1842
- // won't be refurned if set to `isDisabled`
1843
- const anchorProps = href && !isDisabled ? {
1844
- download,
1845
- href: href || undefined,
1846
- hrefLang,
1847
- rel,
1848
- target,
1849
- ref: anchorRef,
1850
- id: anchorId
1851
- } : {};
1852
- // Object of all Checked props that will be passed to the root `Card` component
1853
- const checkedProps = (type === 'checkbox' || type === 'radio') && !href ? {
1854
- ...commonProps,
1855
- 'aria-checked': type === 'radio' ? value === state : type === 'checkbox' ? checked : undefined,
1856
- 'aria-describedby': `${componentId}-title`,
1857
- 'aria-disabled': isDisabled,
1858
- 'data-value': value ?? undefined,
1859
- role: type === 'checkbox' || type === 'radio' ? type : undefined,
1860
- onClick: handleClick,
1861
- onKeyDown: event => {
1862
- if (event.key === 'Enter' || event.key === ' ') {
1863
- handleClick();
1864
- }
1865
- },
1866
- ref,
1867
- tabIndex: 0
1868
- } : {};
1869
- const getTitle = () => {
1870
- const titleContent = href && !type ? /*#__PURE__*/jsx("a", {
1871
- className: "np-Card-titleLink",
1872
- ...anchorProps,
1873
- children: title
1874
- }) : title;
1875
- const titleProps = {
1876
- id: `${componentId}-title`,
1877
- as: headingLevel,
1878
- className: 'np-Card-title'
1879
- };
1880
- return useDisplayFont ? /*#__PURE__*/jsx(Display, {
1881
- type: Typography.DISPLAY_SMALL,
1882
- ...titleProps,
1883
- children: titleContent
1884
- }) : /*#__PURE__*/jsx(Title, {
1885
- type: Typography.TITLE_SUBSECTION,
1886
- ...titleProps,
1887
- children: titleContent
1888
- });
1889
- };
1890
- useEffect(() => {
1891
- setChecked(defaultChecked ?? isChecked ?? false);
1892
- }, [defaultChecked, isChecked]);
1893
- return /*#__PURE__*/jsxs(Card$2, {
1894
- ...commonProps,
1895
- ...checkedProps,
1896
- ...props,
1897
- children: [(value === state || checked) && /*#__PURE__*/jsx("span", {
1898
- className: "np-Card-check",
1899
- children: /*#__PURE__*/jsx(Check, {
1900
- size: 24,
1901
- "aria-hidden": "true"
1902
- })
1903
- }), getTitle(), /*#__PURE__*/jsx(Body, {
1904
- className: "np-Card-description",
1905
- children: description
1906
- }), imageSource && /*#__PURE__*/jsx("div", {
1907
- className: classNames('np-Card-image', {
1908
- imageClass
1909
- }),
1910
- children: /*#__PURE__*/jsx(Image, {
1911
- src: imageSource,
1912
- alt: imageAlt || '',
1913
- loading: "lazy"
1607
+ isMobile
1608
+ } = useLayout();
1609
+ const titleId = useId();
1610
+ return /*#__PURE__*/jsx(Dimmer$1, {
1611
+ open: open,
1612
+ onClose: onClose,
1613
+ children: /*#__PURE__*/jsx(SlidingPanel, {
1614
+ open: open,
1615
+ position: isMobile ? Position.BOTTOM : position,
1616
+ children: /*#__PURE__*/jsxs("div", {
1617
+ role: "dialog",
1618
+ "aria-modal": true,
1619
+ "aria-labelledby": headerTitle ? titleId : undefined,
1620
+ className: classNames('np-drawer', className),
1621
+ children: [/*#__PURE__*/jsxs("div", {
1622
+ className: classNames('np-drawer-header', {
1623
+ 'np-drawer-header--withborder': headerTitle
1624
+ }),
1625
+ children: [headerTitle && /*#__PURE__*/jsx(Title, {
1626
+ id: titleId,
1627
+ type: Typography.TITLE_BODY,
1628
+ children: headerTitle
1629
+ }), /*#__PURE__*/jsx(CloseButton, {
1630
+ onClick: onClose
1631
+ })]
1632
+ }), children && /*#__PURE__*/jsx("div", {
1633
+ className: classNames('np-drawer-content'),
1634
+ children: children
1635
+ }), footerContent && /*#__PURE__*/jsx("div", {
1636
+ className: classNames('np-drawer-footer'),
1637
+ children: footerContent
1638
+ })]
1914
1639
  })
1915
- }), /*#__PURE__*/jsx(PromoCardIndicator, {
1916
- label: indicatorLabel,
1917
- icon: getIconType(),
1918
- isSmall: isSmall
1919
- })]
1640
+ })
1920
1641
  });
1921
- });
1922
- var PromoCard$1 = /*#__PURE__*/React__default.memo(PromoCard);
1642
+ };
1643
+ Drawer.propTypes = {
1644
+ /** The content to appear in the drawer body. */
1645
+ children: PropTypes.node,
1646
+ className: PropTypes.string,
1647
+ /** The content to appear in the drawer footer. */
1648
+ footerContent: PropTypes.node,
1649
+ /** The content to appear in the drawer header. */
1650
+ headerTitle: PropTypes.node,
1651
+ /** The status of Drawer either open or not. */
1652
+ open: PropTypes.bool,
1653
+ /** The placement of Drawer on the screen either left or right. On mobile it will default to bottom. */
1654
+ position: PropTypes.oneOf(['left', 'right', 'bottom']),
1655
+ /** The action to perform on close click. */
1656
+ onClose: PropTypes.func
1657
+ };
1658
+ Drawer.defaultProps = {
1659
+ children: null,
1660
+ className: undefined,
1661
+ footerContent: null,
1662
+ headerTitle: null,
1663
+ onClose: null,
1664
+ open: false,
1665
+ position: Position.RIGHT
1666
+ };
1667
+ var Drawer$1 = Drawer;
1923
1668
 
1924
- const LEFT_SCROLL_OFFSET = 8;
1925
- const Carousel = ({
1926
- header,
1927
- className,
1928
- cards,
1929
- onClick
1930
- }) => {
1931
- const [scrollPosition, setScrollPosition] = useState(0);
1932
- const [previousScrollPosition, setPreviousScrollPosition] = useState(0);
1933
- const [scrollIsAtEnd, setScrollIsAtEnd] = useState(false);
1934
- const [visibleCardOnMobileView, setVisibleCardOnMobileView] = useState('');
1935
- const carouselElementRef = useRef(null);
1936
- const carouselCardsRef = useRef([]);
1937
- const isLeftActionButtonEnabled = scrollPosition > LEFT_SCROLL_OFFSET;
1938
- const areActionButtonsEnabled = isLeftActionButtonEnabled || !scrollIsAtEnd;
1939
- const [focusedCard, setFocusedCard] = useState(cards?.[0]?.id);
1940
- const updateScrollButtonsState = () => {
1941
- if (carouselElementRef.current) {
1942
- const {
1943
- scrollWidth,
1944
- offsetWidth
1945
- } = carouselElementRef.current;
1946
- const scrollAtEnd = scrollWidth - offsetWidth <= scrollPosition + LEFT_SCROLL_OFFSET;
1947
- setScrollIsAtEnd(scrollAtEnd);
1948
- }
1949
- const scrollDirecton = scrollPosition > previousScrollPosition ? 'right' : 'left';
1950
- const cardsInFullViewIds = [];
1951
- carouselCardsRef.current.forEach(card => {
1952
- if (isVisible(carouselElementRef.current, card.cardElement)) {
1953
- // eslint-disable-next-line functional/immutable-data
1954
- cardsInFullViewIds.push(card.cardElement.getAttribute('id') ?? '');
1955
- }
1956
- });
1957
- if (cardsInFullViewIds.length >= 1) {
1958
- const visibleCardIndex = scrollDirecton === 'right' ? cardsInFullViewIds.length - 1 : 0;
1959
- const visibleCardId = cardsInFullViewIds[visibleCardIndex];
1960
- setVisibleCardOnMobileView(visibleCardId);
1961
- setFocusedCard(visibleCardId);
1962
- }
1963
- setPreviousScrollPosition(scrollPosition);
1964
- };
1965
- const scrollCarousel = (direction = 'right') => {
1966
- if (carouselElementRef.current) {
1967
- const {
1968
- scrollWidth
1969
- } = carouselElementRef.current;
1970
- const cardWidth = scrollWidth / carouselCardsRef.current.length;
1971
- const res = Math.floor(cardWidth - cardWidth * 0.05);
1972
- carouselElementRef.current.scrollBy({
1973
- left: direction === 'right' ? res : -res,
1974
- behavior: 'smooth'
1975
- });
1976
- }
1977
- };
1978
- const handleOnKeyDown = (event, index) => {
1979
- if (event.key === 'ArrowRight' || event.key === 'ArrowLeft') {
1980
- const nextIndex = event.key === 'ArrowRight' ? index + 1 : index - 1;
1981
- const nextCard = cards[nextIndex];
1982
- if (nextCard) {
1983
- const ref = carouselCardsRef.current[nextIndex];
1984
- if (ref.type === 'promo') {
1985
- ref.anchorElement?.focus();
1669
+ const INITIAL_Y_POSITION = 0;
1670
+ const CONTENT_SCROLL_THRESHOLD = 1;
1671
+ const MOVE_OFFSET_THRESHOLD = 50;
1672
+ /**
1673
+ * Neptune: https://transferwise.github.io/neptune/components/bottom-sheet/
1674
+ *
1675
+ * Neptune Web: https://transferwise.github.io/neptune-web/components/overlays/BottomSheet
1676
+ *
1677
+ */
1678
+ const BottomSheet$1 = props => {
1679
+ const bottomSheetReference = useRef(null);
1680
+ const topBarReference = useRef(null);
1681
+ const contentReference = useRef(null);
1682
+ const [pressed, setPressed] = useState(false);
1683
+ /**
1684
+ * Used to track `requestAnimationFrame` requests
1685
+ *
1686
+ * @see https://developer.mozilla.org/en-US/docs/Web/API/window/requestAnimationFrame#return_value
1687
+ */
1688
+ const animationId = useRef(0);
1689
+ /**
1690
+ * Difference between initial coordinate ({@link initialYCoordinate})
1691
+ * and new position (when user moves component), it's get calculated on `onTouchMove` and `onMouseMove` events
1692
+ *
1693
+ * @see {@link calculateOffsetAfterMove}
1694
+ */
1695
+ const moveOffset = useRef(0);
1696
+ const initialYCoordinate = useRef(0);
1697
+ // apply shadow to the bottom of top-bar when scroll over content
1698
+ useConditionalListener({
1699
+ attachListener: props.open && !isServerSide(),
1700
+ callback: () => {
1701
+ if (topBarReference.current !== null) {
1702
+ const {
1703
+ classList
1704
+ } = topBarReference.current;
1705
+ if (!isContentScrollPositionAtTop()) {
1706
+ classList.add('np-bottom-sheet--top-bar--shadow');
1986
1707
  } else {
1987
- ref.cardElement?.focus();
1708
+ classList.remove('np-bottom-sheet--top-bar--shadow');
1988
1709
  }
1989
- scrollCardIntoView(carouselCardsRef.current[nextIndex].cardElement, nextCard);
1990
- event.preventDefault();
1991
1710
  }
1711
+ },
1712
+ eventType: 'scroll',
1713
+ parent: isServerSide() ? undefined : document
1714
+ });
1715
+ function move(newHeight) {
1716
+ if (bottomSheetReference.current !== null) {
1717
+ bottomSheetReference.current.style.transform = `translateY(${newHeight}px)`;
1992
1718
  }
1993
- if (event.key === 'Enter' || event.key === ' ') {
1994
- event.currentTarget.click();
1719
+ }
1720
+ function close(event) {
1721
+ setPressed(false);
1722
+ moveOffset.current = INITIAL_Y_POSITION;
1723
+ if (bottomSheetReference.current !== null) {
1724
+ bottomSheetReference.current.style.removeProperty('transform');
1725
+ }
1726
+ if (props.onClose) {
1727
+ props.onClose(event);
1995
1728
  }
1729
+ }
1730
+ const onSwipeStart = event => {
1731
+ initialYCoordinate.current = ('touches' in event ? event.touches[0] : event).clientY;
1732
+ setPressed(true);
1996
1733
  };
1997
- const scrollCardIntoView = (element, card) => {
1998
- element.scrollIntoView({
1999
- behavior: 'smooth',
2000
- block: 'nearest',
2001
- inline: 'center'
2002
- });
2003
- setFocusedCard(card.id);
1734
+ const onSwipeMove = event => {
1735
+ if (pressed) {
1736
+ const {
1737
+ clientY
1738
+ } = 'touches' in event ? event.touches[0] : event;
1739
+ const offset = calculateOffsetAfterMove(clientY);
1740
+ // check whether move is to the bottom only and content scroll position is at the top
1741
+ if (offset > INITIAL_Y_POSITION && isContentScrollPositionAtTop()) {
1742
+ moveOffset.current = offset;
1743
+ animationId.current = requestAnimationFrame(() => {
1744
+ if (animationId.current !== undefined && bottomSheetReference.current !== null) {
1745
+ move(offset);
1746
+ }
1747
+ });
1748
+ }
1749
+ }
2004
1750
  };
1751
+ function onSwipeEnd(event) {
1752
+ // stop moving component
1753
+ cancelAnimationFrame(animationId.current);
1754
+ setPressed(false);
1755
+ // check whether move down is strong enough
1756
+ // and content scroll position is at the top to close the component
1757
+ if (moveOffset.current > MOVE_OFFSET_THRESHOLD && isContentScrollPositionAtTop()) {
1758
+ close(event);
1759
+ }
1760
+ // otherwise move component back to default (initial) position
1761
+ else {
1762
+ move(INITIAL_Y_POSITION);
1763
+ }
1764
+ moveOffset.current = INITIAL_Y_POSITION;
1765
+ }
1766
+ function isContentScrollPositionAtTop() {
1767
+ return contentReference?.current?.scrollTop !== undefined && contentReference.current.scrollTop <= CONTENT_SCROLL_THRESHOLD;
1768
+ }
1769
+ /**
1770
+ * Calculates how hard user moves component,
1771
+ * result value used to determine whether to hide component or re-position to default state
1772
+ *
1773
+ * @param afterMoveYCoordinate
1774
+ */
1775
+ function calculateOffsetAfterMove(afterMoveYCoordinate) {
1776
+ return afterMoveYCoordinate - initialYCoordinate.current;
1777
+ }
1778
+ /**
1779
+ * Set `max-height` for content part (in order to keep it scrollable for content overflow cases) of the component
1780
+ * and ensures space for safe zone (32px) at the top.
1781
+ */
1782
+ function setContentMaxHeight() {
1783
+ const safeZoneHeight = '64px';
1784
+ const topbarHeight = '32px';
1785
+ const windowHight = isServerSide() ? 0 : window.innerHeight;
1786
+ /**
1787
+ * Calculate _real_ height of the screen (taking into account parts of browser interface).
1788
+ *
1789
+ * See https://css-tricks.com/the-trick-to-viewport-units-on-mobile for more details.
1790
+ */
1791
+ const screenHeight = `${windowHight * 0.01 * 100}px`;
1792
+ return {
1793
+ maxHeight: `calc(${screenHeight} - ${safeZoneHeight} - ${topbarHeight})`
1794
+ };
1795
+ }
1796
+ const is400Zoom = useMedia(`(max-width: ${Breakpoint.ZOOM_400}px)`);
1797
+ return is400Zoom ? /*#__PURE__*/jsx(Drawer$1, {
1798
+ open: props.open,
1799
+ className: props.className,
1800
+ onClose: close,
1801
+ children: props.children
1802
+ }) : /*#__PURE__*/jsx(Dimmer$1, {
1803
+ open: props.open,
1804
+ fadeContentOnEnter: true,
1805
+ fadeContentOnExit: true,
1806
+ onClose: close,
1807
+ children: /*#__PURE__*/jsx(SlidingPanel, {
1808
+ ref: bottomSheetReference,
1809
+ open: props.open,
1810
+ position: Position.BOTTOM,
1811
+ className: classNames('np-bottom-sheet', props.className),
1812
+ children: /*#__PURE__*/jsxs("div", {
1813
+ role: "dialog",
1814
+ "aria-modal": true,
1815
+ onTouchStart: onSwipeStart,
1816
+ onTouchMove: onSwipeMove,
1817
+ onTouchEnd: onSwipeEnd,
1818
+ onMouseDown: onSwipeStart,
1819
+ onMouseMove: onSwipeMove,
1820
+ onMouseUp: onSwipeEnd,
1821
+ children: [/*#__PURE__*/jsxs("div", {
1822
+ ref: topBarReference,
1823
+ className: "np-bottom-sheet--top-bar",
1824
+ children: [/*#__PURE__*/jsx("div", {
1825
+ className: "np-bottom-sheet--handler"
1826
+ }), /*#__PURE__*/jsx(CloseButton, {
1827
+ size: "sm",
1828
+ className: "sr-only np-bottom-sheet--close-btn",
1829
+ onClick: close
1830
+ })]
1831
+ }), /*#__PURE__*/jsx("div", {
1832
+ ref: contentReference,
1833
+ style: setContentMaxHeight(),
1834
+ className: "np-bottom-sheet--content",
1835
+ children: props.children
1836
+ })]
1837
+ })
1838
+ })
1839
+ });
1840
+ };
1841
+
1842
+ const NavigationOption = /*#__PURE__*/forwardRef(({
1843
+ as: component = 'button',
1844
+ disabled = false,
1845
+ onClick,
1846
+ className,
1847
+ ...rest
1848
+ }, reference) => {
1849
+ if ('href' in rest && rest.href) {
1850
+ component = 'a';
1851
+ }
1852
+ return /*#__PURE__*/jsx(Option$2, {
1853
+ ...rest,
1854
+ ref: reference,
1855
+ as: component,
1856
+ className: classNames('np-navigation-option', className),
1857
+ button: /*#__PURE__*/jsx(Chevron, {
1858
+ orientation: Position.RIGHT,
1859
+ disabled: disabled,
1860
+ className: "d-block"
1861
+ }),
1862
+ disabled: disabled,
1863
+ onClick: event => {
1864
+ if (disabled) {
1865
+ event.preventDefault();
1866
+ return;
1867
+ }
1868
+ if (onClick) {
1869
+ onClick(event);
1870
+ }
1871
+ }
1872
+ });
1873
+ });
1874
+
1875
+ const NavigationOptionList = ({
1876
+ children
1877
+ }) => {
1878
+ return /*#__PURE__*/jsx("ul", {
1879
+ className: "np-navigation-options-list",
1880
+ children: Children.map(children, child => /*#__PURE__*/jsx("li", {
1881
+ className: "np-navigation-options-list__item",
1882
+ children: child
1883
+ }, child?.toString()))
1884
+ });
1885
+ };
1886
+
1887
+ const FieldLabelIdContext = /*#__PURE__*/createContext(undefined);
1888
+ const FieldLabelIdContextProvider = FieldLabelIdContext.Provider;
1889
+ const InputIdContext = /*#__PURE__*/createContext(undefined);
1890
+ const InputIdContextProvider = InputIdContext.Provider;
1891
+ const InputDescribedByContext = /*#__PURE__*/createContext(undefined);
1892
+ const InputDescribedByProvider = InputDescribedByContext.Provider;
1893
+ const InputInvalidContext = /*#__PURE__*/createContext(undefined);
1894
+ const InputInvalidProvider = InputInvalidContext.Provider;
1895
+ function useInputAttributes({
1896
+ nonLabelable
1897
+ } = {}) {
1898
+ const labelId = useContext(FieldLabelIdContext);
1899
+ return {
1900
+ id: useContext(InputIdContext),
1901
+ 'aria-labelledby': nonLabelable ? labelId : undefined,
1902
+ 'aria-describedby': useContext(InputDescribedByContext),
1903
+ 'aria-invalid': useContext(InputInvalidContext)
1904
+ };
1905
+ }
1906
+ function withInputAttributes(Component, args) {
1907
+ function ComponentWithInputAttributes(props) {
1908
+ return /*#__PURE__*/jsx(Component, {
1909
+ inputAttributes: useInputAttributes(args),
1910
+ ...props
1911
+ });
1912
+ }
1913
+ ComponentWithInputAttributes.displayName = `withInputAttributes(${Component.displayName || Component.name || 'Component'})`;
1914
+ return ComponentWithInputAttributes;
1915
+ }
1916
+
1917
+ var messages$b = defineMessages({
1918
+ actionLabel: {
1919
+ id: "neptune.SelectOption.action.label"
1920
+ }
1921
+ });
1922
+
1923
+ function SelectOption({
1924
+ selected: selectedValueProp = undefined,
1925
+ optionsTitle,
1926
+ options,
1927
+ onChange,
1928
+ action,
1929
+ ...props
1930
+ }) {
1931
+ const intl = useIntl();
1932
+ const rootRef = useRef(null);
1933
+ const [selected, setSelected] = useState(selectedValueProp);
1934
+ const [showOptions, setShowOptions] = useState(false);
1935
+ const inputAttributes = useInputAttributes();
1936
+ function handleOnClick(showOptionsStatus) {
1937
+ return () => {
1938
+ setShowOptions(showOptionsStatus);
1939
+ };
1940
+ }
1941
+ function handleOnChange(data) {
1942
+ return () => {
1943
+ setShowOptions(false);
1944
+ setSelected(data);
1945
+ onChange(data);
1946
+ };
1947
+ }
1948
+ const isSelected = selected !== undefined;
1949
+ const {
1950
+ isMobile
1951
+ } = useLayout();
1952
+ function getOptionsContent(isMobileView = false) {
1953
+ return /*#__PURE__*/jsx("div", {
1954
+ className: classNames('np-select-option-list'),
1955
+ children: options.map(optionsGroup =>
1956
+ /*#__PURE__*/
1957
+ // eslint-disable-next-line react/jsx-key
1958
+ jsxs(Section, {
1959
+ className: classNames('np-select-option-group', {
1960
+ 'p-a-2': !isMobileView
1961
+ }),
1962
+ children: [optionsGroup.title && /*#__PURE__*/jsx(Header, {
1963
+ title: optionsGroup.title
1964
+ }), /*#__PURE__*/jsx(NavigationOptionList, {
1965
+ children: optionsGroup.options.map(option =>
1966
+ /*#__PURE__*/
1967
+ // eslint-disable-next-line react/jsx-key
1968
+ jsx(NavigationOption, {
1969
+ isContainerAligned: isMobileView,
1970
+ showMediaCircle: true,
1971
+ showMediaAtAllSizes: true,
1972
+ media: option.media,
1973
+ title: option.title,
1974
+ content: option.content,
1975
+ onClick: handleOnChange(option)
1976
+ }))
1977
+ })]
1978
+ }))
1979
+ });
1980
+ }
1981
+ return /*#__PURE__*/jsxs(Fragment, {
1982
+ children: [/*#__PURE__*/jsx(Option$2, {
1983
+ ref: rootRef,
1984
+ ...props,
1985
+ ...inputAttributes,
1986
+ showMediaAtAllSizes: true,
1987
+ media: (isSelected ? selected : props).media,
1988
+ title: (isSelected ? selected : props).title,
1989
+ content: (isSelected ? selected : props).content,
1990
+ className: classNames('np-select-option', {
1991
+ 'np-select-option-selected': isSelected
1992
+ }, props.className),
1993
+ button: isSelected ? /*#__PURE__*/jsx(Chevron, {}) : /*#__PURE__*/jsx(ActionButton, {
1994
+ disabled: props.disabled,
1995
+ onClick: handleOnClick(true),
1996
+ children: action?.label || intl.formatMessage(messages$b.actionLabel)
1997
+ }),
1998
+ onClick: isSelected ? handleOnClick(true) : undefined
1999
+ }), isMobile ? /*#__PURE__*/jsx(BottomSheet$1, {
2000
+ open: showOptions,
2001
+ onClose: handleOnClick(false),
2002
+ children: getOptionsContent(true)
2003
+ }) : /*#__PURE__*/jsx(Panel, {
2004
+ anchorWidth: true,
2005
+ open: showOptions,
2006
+ flip: false,
2007
+ altAxis: false,
2008
+ anchorRef: rootRef,
2009
+ position: Position.BOTTOM,
2010
+ onClose: handleOnClick(false),
2011
+ children: getOptionsContent(false)
2012
+ })]
2013
+ });
2014
+ }
2015
+
2016
+ const iconTypeMap = {
2017
+ positive: Check,
2018
+ neutral: Info$1,
2019
+ warning: Alert$1,
2020
+ negative: Cross,
2021
+ pending: ClockBorderless,
2022
+ info: Info$1,
2023
+ error: Cross,
2024
+ success: Check
2025
+ };
2026
+ const StatusIcon = ({
2027
+ sentiment = 'neutral',
2028
+ size = 'md'
2029
+ }) => {
2030
+ const Icon = iconTypeMap[sentiment];
2031
+ const iconColor = sentiment === 'warning' || sentiment === 'pending' ? 'dark' : 'light';
2032
+ return /*#__PURE__*/jsx("span", {
2033
+ "data-testid": "status-icon",
2034
+ className: classNames('status-circle', 'status-circle-' + size, sentiment),
2035
+ children: /*#__PURE__*/jsx(Icon, {
2036
+ className: classNames('status-icon', iconColor)
2037
+ })
2038
+ });
2039
+ };
2040
+
2041
+ const reader = new commonmark.Parser();
2042
+ const writer = new commonmark.HtmlRenderer({
2043
+ safe: true
2044
+ });
2045
+ const NODE_TYPE_LIST = Object.values(MarkdownNodeType);
2046
+ function Markdown({
2047
+ as: Element = 'div',
2048
+ allowList,
2049
+ blockList,
2050
+ config,
2051
+ className,
2052
+ children
2053
+ }) {
2054
+ if (!children) {
2055
+ return null;
2056
+ }
2057
+ const linkTarget = config?.link?.target ?? '_self';
2058
+ const paragraphClass = config?.paragraph?.className ?? '';
2059
+ if (allowList != null && blockList != null) {
2060
+ logActionRequired('Markdown supports only one of `allowList` or `blockList` to be used at a time. `blockList` will be ignored.');
2061
+ }
2062
+ const parser = nodes => {
2063
+ const parsed = reader.parse(nodes);
2064
+ const toExclude = allowList != null ? NODE_TYPE_LIST.filter(type => !allowList.includes(type)) : blockList;
2065
+ return toExclude != null ? stripNodes({
2066
+ parsed,
2067
+ blockList: toExclude
2068
+ }) : parsed;
2069
+ };
2070
+ const createMarkup = () => {
2071
+ const parsed = parser(children);
2072
+ return writer.render(parsed).replace(/<a href="/g, `<a target="${linkTarget}" href="`).replace(/<p>/g, `<p class="${paragraphClass}">`);
2073
+ };
2074
+ return /*#__PURE__*/jsx(Element, {
2075
+ className: className,
2076
+ dangerouslySetInnerHTML: {
2077
+ __html: createMarkup()
2078
+ }
2079
+ });
2080
+ }
2081
+ function stripNodes({
2082
+ blockList,
2083
+ parsed
2084
+ }) {
2085
+ if (!parsed) {
2086
+ return parsed;
2087
+ }
2088
+ const walker = parsed.walker();
2089
+ for (let event = walker.next(); event != null; event = walker.next()) {
2090
+ const {
2091
+ node
2092
+ } = event;
2093
+ if (blockList.includes(node.type) && !event.entering) {
2094
+ while (node.firstChild != null) {
2095
+ node.insertBefore(node.firstChild);
2096
+ }
2097
+ node.unlink();
2098
+ }
2099
+ }
2100
+ return parsed;
2101
+ }
2102
+
2103
+ const allowList = [MarkdownNodeType.STRONG];
2104
+ const InlineMarkdown = props => {
2105
+ return /*#__PURE__*/jsx(Markdown, {
2106
+ ...props,
2107
+ as: "span",
2108
+ allowList: allowList,
2109
+ blockList: undefined
2110
+ });
2111
+ };
2112
+ InlineMarkdown.propTypes = {
2113
+ children: PropTypes.string.isRequired,
2114
+ className: PropTypes.string
2115
+ };
2116
+ InlineMarkdown.defaultProps = {
2117
+ className: undefined
2118
+ };
2119
+
2120
+ function Action({
2121
+ action,
2122
+ className
2123
+ }) {
2124
+ if ('href' in action) {
2125
+ return /*#__PURE__*/jsx(Link, {
2126
+ href: action.href,
2127
+ className: className,
2128
+ "aria-label": action['aria-label'],
2129
+ target: action.target,
2130
+ type: Typography.LINK_LARGE,
2131
+ onClick: action.onClick,
2132
+ children: action.text
2133
+ });
2134
+ }
2135
+ return /*#__PURE__*/jsx("button", {
2136
+ type: "button",
2137
+ "aria-label": action['aria-label'],
2138
+ className: classNames('btn-unstyled np-text-link-large', className),
2139
+ onClick: action.onClick,
2140
+ children: action.text
2141
+ });
2142
+ }
2143
+
2144
+ var AlertArrowPosition;
2145
+ (function (AlertArrowPosition) {
2146
+ AlertArrowPosition["TOP_LEFT"] = "up-left";
2147
+ AlertArrowPosition["TOP"] = "up-center";
2148
+ AlertArrowPosition["TOP_RIGHT"] = "up-right";
2149
+ AlertArrowPosition["BOTTOM_LEFT"] = "down-left";
2150
+ AlertArrowPosition["BOTTOM"] = "down-center";
2151
+ AlertArrowPosition["BOTTOM_RIGHT"] = "down-right";
2152
+ })(AlertArrowPosition || (AlertArrowPosition = {}));
2153
+ function resolveType(type) {
2154
+ switch (type) {
2155
+ case 'success':
2156
+ return 'positive';
2157
+ case 'info':
2158
+ return 'neutral';
2159
+ case 'error':
2160
+ return 'negative';
2161
+ default:
2162
+ return type;
2163
+ }
2164
+ }
2165
+ function Alert({
2166
+ arrow,
2167
+ action,
2168
+ children,
2169
+ className,
2170
+ dismissible,
2171
+ icon,
2172
+ onDismiss,
2173
+ message,
2174
+ size,
2175
+ title,
2176
+ type = 'neutral',
2177
+ variant = 'desktop'
2178
+ }) {
2005
2179
  useEffect(() => {
2006
- updateScrollButtonsState();
2007
- // eslint-disable-next-line react-hooks/exhaustive-deps
2008
- }, [scrollPosition]);
2180
+ if (arrow !== undefined) {
2181
+ logActionRequired("Alert component doesn't support 'arrow' anymore, use 'InlineAlert' instead.");
2182
+ }
2183
+ }, [arrow]);
2009
2184
  useEffect(() => {
2010
- window.addEventListener('resize', updateScrollButtonsState);
2011
- return () => {
2012
- window.removeEventListener('resize', updateScrollButtonsState);
2013
- };
2014
- // eslint-disable-next-line react-hooks/exhaustive-deps
2015
- }, []);
2016
- const addElementToCardsRefArray = (index, ref) => {
2017
- if (ref) {
2018
- // eslint-disable-next-line functional/immutable-data
2019
- carouselCardsRef.current[index] = {
2020
- type: ref.type ?? carouselCardsRef.current?.[index]?.type,
2021
- cardElement: ref.cardElement ?? carouselCardsRef.current?.[index]?.cardElement,
2022
- anchorElement: ref.anchorElement ?? carouselCardsRef.current?.[index]?.anchorElement
2023
- };
2185
+ if (children !== undefined) {
2186
+ logActionRequired("Alert component doesn't support 'children' anymore, use 'message' instead.");
2024
2187
  }
2025
- };
2188
+ }, [children]);
2189
+ useEffect(() => {
2190
+ if (dismissible !== undefined) {
2191
+ logActionRequired("Alert component doesn't support 'dismissible' anymore, use 'onDismiss' instead.");
2192
+ }
2193
+ }, [dismissible]);
2194
+ useEffect(() => {
2195
+ if (size !== undefined) {
2196
+ logActionRequired("Alert component doesn't support 'size' anymore, please remove that prop.");
2197
+ }
2198
+ }, [size]);
2199
+ const resolvedType = resolveType(type);
2200
+ useEffect(() => {
2201
+ if (resolvedType !== type) {
2202
+ logActionRequired(`Alert component has deprecated '${type}' value for the 'type' prop. Please use '${resolvedType}' instead.`);
2203
+ }
2204
+ }, [resolvedType, type]);
2205
+ const [shouldFire, setShouldFire] = useState(false);
2206
+ const closeButtonReference = useRef(null);
2026
2207
  return /*#__PURE__*/jsxs("div", {
2027
- className: classNames('carousel-wrapper', className),
2028
- children: [/*#__PURE__*/jsxs("div", {
2029
- className: "d-flex justify-content-between carousel__header",
2030
- children: [typeof header === 'string' ? /*#__PURE__*/jsx(Title, {
2031
- as: "span",
2032
- type: "title-body",
2033
- children: header
2034
- }) : header, areActionButtonsEnabled ? /*#__PURE__*/jsxs("div", {
2035
- className: "hidden-xs",
2036
- children: [/*#__PURE__*/jsx(ActionButton, {
2037
- className: "carousel__scroll-button",
2038
- tabIndex: -1,
2039
- priority: "secondary",
2040
- disabled: !isLeftActionButtonEnabled,
2041
- "aria-hidden": "true",
2042
- "data-testid": "scroll-carousel-left",
2043
- onClick: () => scrollCarousel('left'),
2044
- children: /*#__PURE__*/jsx(ChevronLeft, {})
2045
- }), /*#__PURE__*/jsx(ActionButton, {
2046
- tabIndex: -1,
2047
- className: "carousel__scroll-button m-l-1",
2048
- priority: "secondary",
2049
- "aria-hidden": "true",
2050
- "data-testid": "scroll-carousel-right",
2051
- disabled: scrollIsAtEnd,
2052
- onClick: () => scrollCarousel(),
2053
- children: /*#__PURE__*/jsx(ChevronRight, {})
2054
- })]
2055
- }) : null]
2056
- }), /*#__PURE__*/jsx("div", {
2057
- ref: carouselElementRef,
2058
- tabIndex: -1,
2059
- role: "list",
2060
- className: "carousel",
2061
- onScroll: event => {
2062
- const target = event.target;
2063
- setScrollPosition(target.scrollLeft);
2064
- },
2065
- children: cards?.map((card, index) => {
2066
- const sharedProps = {
2067
- id: card.id,
2068
- className: classNames('carousel__card', {
2069
- 'carousel__card--focused': card.id === focusedCard
2070
- }),
2071
- onClick: () => {
2072
- card.onClick?.();
2073
- onClick?.(card.id);
2074
- },
2075
- onFocus: event => {
2076
- scrollCardIntoView(event.currentTarget, card);
2077
- }
2078
- };
2079
- const cardContent = card.type !== 'promo' ? /*#__PURE__*/jsx("div", {
2080
- id: `${card.id}-content`,
2081
- className: classNames('carousel__card-content', {
2082
- [card.className ?? '']: !!card.className
2083
- })
2084
- // eslint-disable-next-line react/forbid-dom-props
2085
- ,
2086
- style: card.styles,
2087
- children: card.content
2088
- }) : null;
2089
- if (card.type === 'button') {
2090
- return /*#__PURE__*/jsx("div", {
2091
- "aria-labelledby": `${card.id}-content`,
2092
- role: "listitem",
2093
- children: /*#__PURE__*/jsx("div", {
2094
- ...sharedProps,
2095
- ref: el => {
2096
- if (el) {
2097
- // eslint-disable-next-line functional/immutable-data
2098
- carouselCardsRef.current[index] = {
2099
- type: 'default',
2100
- cardElement: el
2101
- };
2102
- }
2103
- },
2104
- role: "button",
2105
- tabIndex: 0,
2106
- onKeyDown: event => handleOnKeyDown(event, index),
2107
- children: cardContent
2108
- })
2109
- }, card.id);
2208
+ className: classNames('alert d-flex', `alert-${resolvedType}`, arrow != null && alertArrowClassNames(arrow), className),
2209
+ "data-testid": "alert",
2210
+ onTouchStart: () => setShouldFire(true),
2211
+ onTouchEnd: event => {
2212
+ if (shouldFire && action?.href &&
2213
+ // Check if current event is triggered from closeButton
2214
+ event.target instanceof Node && closeButtonReference.current && !closeButtonReference.current.contains(event.target)) {
2215
+ if (action.target === '_blank') {
2216
+ window.top?.open(action.href);
2217
+ } else {
2218
+ window.top?.location.assign(action.href);
2110
2219
  }
2111
- if (card.type === 'promo') {
2112
- return /*#__PURE__*/jsx("div", {
2113
- id: card.id,
2114
- role: "listitem",
2115
- "aria-labelledby": `${card.id}-anchor`,
2116
- children: /*#__PURE__*/jsx(PromoCard$1, {
2117
- ...card,
2118
- type: undefined,
2119
- ...sharedProps,
2120
- ref: el => {
2121
- if (el) {
2122
- addElementToCardsRefArray(index, {
2123
- type: 'promo',
2124
- cardElement: el
2125
- });
2126
- }
2127
- },
2128
- anchorRef: el => {
2129
- if (el) {
2130
- addElementToCardsRefArray(index, {
2131
- type: 'promo',
2132
- anchorElement: el
2133
- });
2134
- }
2135
- },
2136
- anchorId: `${card.id}-anchor`,
2137
- onKeyDown: event => handleOnKeyDown(event, index)
2220
+ }
2221
+ setShouldFire(false);
2222
+ },
2223
+ onTouchMove: () => setShouldFire(false),
2224
+ children: [/*#__PURE__*/jsxs("div", {
2225
+ className: classNames('alert__content', 'd-flex', 'flex-grow-1', variant),
2226
+ "data-testid": variant,
2227
+ children: [icon ? /*#__PURE__*/jsx("div", {
2228
+ className: "alert__icon",
2229
+ children: icon
2230
+ }) : /*#__PURE__*/jsx(StatusIcon, {
2231
+ size: Size.LARGE,
2232
+ sentiment: resolvedType
2233
+ }), /*#__PURE__*/jsxs("div", {
2234
+ className: "alert__message",
2235
+ children: [/*#__PURE__*/jsxs("div", {
2236
+ role: Sentiment.NEGATIVE === resolvedType ? 'alert' : 'status',
2237
+ children: [title && /*#__PURE__*/jsx(Title, {
2238
+ className: "m-b-1",
2239
+ type: Typography.TITLE_BODY,
2240
+ children: title
2241
+ }), /*#__PURE__*/jsx(Body, {
2242
+ as: "span",
2243
+ className: "d-block",
2244
+ type: Typography.BODY_LARGE,
2245
+ children: children || /*#__PURE__*/jsx(InlineMarkdown, {
2246
+ children: message
2138
2247
  })
2139
- }, card.id);
2140
- }
2141
- return /*#__PURE__*/jsx("div", {
2142
- "aria-labelledby": `${card.id}-content`,
2143
- role: "listitem",
2144
- children: /*#__PURE__*/jsx("a", {
2145
- ...sharedProps,
2146
- ref: el => {
2147
- if (el) {
2148
- // eslint-disable-next-line functional/immutable-data
2149
- carouselCardsRef.current[index] = {
2150
- type: 'default',
2151
- cardElement: el
2152
- };
2153
- }
2154
- },
2155
- href: card.href,
2156
- rel: "noreferrer",
2157
- onKeyDown: event => handleOnKeyDown(event, index),
2158
- children: cardContent
2159
- })
2160
- }, card.id);
2161
- })
2162
- }), /*#__PURE__*/jsx("div", {
2163
- className: "visible-xs",
2164
- children: /*#__PURE__*/jsx("div", {
2165
- className: "carousel__indicators",
2166
- children: cards?.map((card, index) => /*#__PURE__*/jsx("button", {
2167
- "data-testid": `${card.id}-indicator`,
2168
- tabIndex: -1,
2169
- "aria-hidden": true,
2170
- type: "button",
2171
- className: classNames('carousel__indicator', {
2172
- 'carousel__indicator--selected': card.id === visibleCardOnMobileView
2173
- }),
2174
- onClick: () => {
2175
- scrollCardIntoView(carouselCardsRef.current[index].cardElement, card);
2176
- }
2177
- }, `${card.id}-indicator`))
2178
- })
2248
+ })]
2249
+ }), action && /*#__PURE__*/jsx(Action, {
2250
+ action: action,
2251
+ className: "m-t-1"
2252
+ })]
2253
+ })]
2254
+ }), onDismiss && /*#__PURE__*/jsx(CloseButton, {
2255
+ ref: closeButtonReference,
2256
+ className: "m-l-2",
2257
+ onClick: onDismiss
2179
2258
  })]
2180
2259
  });
2181
- };
2182
- const isVisible = (container, el) => {
2183
- const cWidth = container.offsetWidth;
2184
- const cScrollOffset = container.scrollLeft;
2185
- const elemLeft = el.offsetLeft - container.offsetLeft;
2186
- const elemRight = elemLeft + el.offsetWidth;
2187
- return elemLeft >= cScrollOffset && elemRight <= cScrollOffset + cWidth;
2188
- };
2260
+ }
2261
+ function alertArrowClassNames(arrow) {
2262
+ switch (arrow) {
2263
+ case 'down-center':
2264
+ return 'arrow arrow-bottom arrow-center';
2265
+ case 'down-left':
2266
+ return 'arrow arrow-bottom arrow-left';
2267
+ case 'down-right':
2268
+ return 'arrow arrow-bottom arrow-right';
2269
+ case 'up-center':
2270
+ return 'arrow arrow-center';
2271
+ case 'up-right':
2272
+ return 'arrow arrow-right';
2273
+ case 'up-left':
2274
+ default:
2275
+ return 'arrow';
2276
+ }
2277
+ }
2189
2278
 
2190
- const Card = /*#__PURE__*/forwardRef((props, reference) => {
2191
- const {
2192
- 'aria-label': ariaLabel,
2193
- as: Element,
2194
- isExpanded,
2195
- title,
2196
- details,
2197
- children,
2198
- onClick,
2199
- icon,
2200
- id,
2201
- className,
2202
- ...rest
2203
- } = props;
2204
- const isOpen = !!(isExpanded && children);
2205
- return /*#__PURE__*/jsxs(Element, {
2206
- ref: reference,
2207
- className: classNames('np-card', className, {
2208
- 'np-card--expanded': isOpen,
2209
- 'np-card--inactive': !children,
2210
- 'np-card--has-icon': !!icon
2211
- }),
2212
- id: id,
2213
- "data-testid": rest['data-testid'],
2214
- children: [/*#__PURE__*/jsx(Option$2, {
2215
- "aria-label": ariaLabel,
2216
- as: children ? 'button' : 'div',
2217
- className: classNames('np-card__button'),
2218
- media: icon,
2219
- title: title,
2220
- content: details,
2221
- showMediaAtAllSizes: true,
2222
- button: children && /*#__PURE__*/jsx(Chevron, {
2223
- orientation: isOpen ? Position.TOP : Position.BOTTOM
2224
- }),
2225
- onClick: () => children && onClick(!isExpanded)
2226
- }), /*#__PURE__*/jsx("div", {
2227
- className: classNames('np-card__divider', {
2228
- 'np-card__divider--expanded': isOpen
2229
- })
2230
- }), isOpen && /*#__PURE__*/jsx(Body, {
2231
- as: "span",
2232
- type: Typography.BODY_LARGE,
2233
- className: "np-card__content d-block",
2234
- children: children
2235
- })]
2236
- });
2237
- });
2238
- const hasChildren = ({
2239
- children
2240
- }) => children;
2241
- Card.propTypes = {
2242
- 'aria-label': PropTypes.string,
2243
- as: PropTypes.string,
2244
- isExpanded: requiredIf(PropTypes.bool, hasChildren),
2245
- title: PropTypes.node.isRequired,
2246
- details: PropTypes.node.isRequired,
2247
- onClick: requiredIf(PropTypes.func, hasChildren),
2248
- icon: PropTypes.node,
2249
- children: PropTypes.node,
2250
- id: PropTypes.string,
2251
- className: PropTypes.string,
2252
- 'data-testid': PropTypes.string
2279
+ // TODO: consider to move this enum into component file once we migrate it on TypeScript or replace with some common enum
2280
+ var AvatarType;
2281
+ (function (AvatarType) {
2282
+ AvatarType["THUMBNAIL"] = "thumbnail";
2283
+ AvatarType["ICON"] = "icon";
2284
+ AvatarType["EMOJI"] = "emoji";
2285
+ AvatarType["INITIALS"] = "initials";
2286
+ })(AvatarType || (AvatarType = {}));
2287
+
2288
+ /*
2289
+ * The colors we support generating an Avatar background color from a "seed" for.
2290
+ * Changing this array will change the assignment between seeds.
2291
+ * Do not change this array.
2292
+ */
2293
+ const avatarColors = ['--color-bright-blue', '--color-bright-yellow', '--color-bright-pink', '--color-bright-orange'];
2294
+ /*
2295
+ * Takes in a "seed" string and spits out an index for the color we should use.
2296
+ * This implementation has been synced across all three clients so that we consistently
2297
+ * generate branded avatar colors when rendering a list of Avatars.
2298
+ * Do not change this implementation.
2299
+ */
2300
+ const hashSeed = seed => {
2301
+ const base = 31;
2302
+ const modulo = avatarColors.length;
2303
+ let hashValue = 0;
2304
+ let basePow = 1;
2305
+ for (let i = 0; i < seed.length; i += 1) {
2306
+ hashValue = (hashValue + seed.charCodeAt(i) * basePow) % modulo;
2307
+ basePow = basePow * base % modulo;
2308
+ }
2309
+ return hashValue;
2253
2310
  };
2254
- Card.defaultProps = {
2255
- 'aria-label': undefined,
2256
- as: 'div',
2257
- children: null,
2258
- id: null,
2259
- className: null,
2260
- 'data-testid': null
2311
+ const getAvatarColorFromSeed = seed => {
2312
+ return avatarColors[hashSeed(seed)];
2261
2313
  };
2262
- var Card$1 = Card;
2263
-
2264
- const CheckboxButton = /*#__PURE__*/forwardRef(({
2265
- checked,
2266
- className,
2267
- disabled,
2268
- onChange,
2269
- ...rest
2270
- }, reference) => /*#__PURE__*/jsxs("span", {
2271
- className: classNames('np-checkbox-button', className, disabled && 'disabled'),
2272
- children: [/*#__PURE__*/jsx("input", {
2273
- ...rest,
2274
- ref: reference,
2275
- type: "checkbox",
2276
- disabled: disabled,
2277
- checked: checked,
2278
- onChange: onChange
2279
- }), /*#__PURE__*/jsx("span", {
2280
- className: "tw-checkbox-button",
2281
- children: /*#__PURE__*/jsx("span", {
2282
- className: "tw-checkbox-check"
2283
- })
2284
- })]
2285
- }));
2286
- var CheckboxButton$1 = CheckboxButton;
2287
2314
 
2288
- const Checkbox = ({
2289
- id,
2290
- checked,
2291
- required,
2292
- disabled,
2293
- readOnly,
2294
- label,
2315
+ const backwardsCompatibleSize = size => {
2316
+ switch (size) {
2317
+ case 'sm':
2318
+ return 24;
2319
+ case 'md':
2320
+ return 48;
2321
+ case 'lg':
2322
+ return 72;
2323
+ default:
2324
+ return size;
2325
+ }
2326
+ };
2327
+ const Avatar = ({
2328
+ backgroundColor = null,
2329
+ backgroundColorSeed = null,
2330
+ children = null,
2295
2331
  className,
2296
- secondary,
2297
- onChange,
2298
- onFocus,
2299
- onBlur
2332
+ outlined = false,
2333
+ size: sizeFromProps = 48,
2334
+ theme = Theme.LIGHT,
2335
+ type = 'thumbnail'
2300
2336
  }) => {
2301
- const {
2302
- isModern
2303
- } = useTheme();
2304
- const classList = classNames('np-checkbox', {
2305
- checkbox: true,
2306
- 'checkbox-lg': secondary,
2307
- disabled: isModern && disabled
2308
- }, className);
2309
- const innerDisabled = disabled || readOnly;
2337
+ const backgroundColorFromSeed = useMemo(() => !backgroundColor && backgroundColorSeed ? `var(${getAvatarColorFromSeed(backgroundColorSeed)})` : undefined, [backgroundColor, backgroundColorSeed]);
2338
+ const size = backwardsCompatibleSize(sizeFromProps);
2310
2339
  return /*#__PURE__*/jsx("div", {
2311
- id: id,
2312
- className: classList,
2313
- children: /*#__PURE__*/jsxs("label", {
2314
- className: classNames({
2315
- disabled
2316
- }),
2317
- children: [/*#__PURE__*/jsx(CheckboxButton$1, {
2318
- className: "p-r-2",
2319
- checked: checked,
2320
- disabled: innerDisabled,
2321
- required: !innerDisabled && required,
2322
- onFocus: onFocus,
2323
- onChange: () => onChange(!checked),
2324
- onBlur: onBlur
2325
- }), /*#__PURE__*/jsxs(Body, {
2326
- as: "span",
2327
- className: "np-checkbox__text",
2328
- type: secondary ? Typography.BODY_LARGE_BOLD : Typography.BODY_LARGE,
2329
- children: [/*#__PURE__*/jsx("span", {
2330
- className: required ? 'has-required' : undefined,
2331
- children: label
2332
- }), secondary && /*#__PURE__*/jsx(Body, {
2333
- as: "span",
2334
- className: classNames({
2335
- secondary: !isModern
2336
- }),
2337
- children: secondary
2338
- })]
2339
- })]
2340
- })
2341
- });
2342
- };
2343
- Checkbox.propTypes = {
2344
- id: PropTypes.string,
2345
- checked: PropTypes.bool,
2346
- required: PropTypes.bool,
2347
- disabled: PropTypes.bool,
2348
- readOnly: PropTypes.bool,
2349
- label: PropTypes.node.isRequired,
2350
- secondary: PropTypes.string,
2351
- onFocus: PropTypes.func,
2352
- onChange: PropTypes.func.isRequired,
2353
- onBlur: PropTypes.func,
2354
- className: PropTypes.string
2340
+ className: classNames('tw-avatar', className, `tw-avatar--${size}`, `tw-avatar--${type}`, {
2341
+ 'tw-avatar--outlined': outlined,
2342
+ 'tw-avatar--branded': Boolean(backgroundColorFromSeed),
2343
+ 'np-text-title-body': type === 'initials'
2344
+ }),
2345
+ children: /*#__PURE__*/jsx("div", {
2346
+ className: "tw-avatar__content",
2347
+ style: {
2348
+ backgroundColor: backgroundColor || backgroundColorFromSeed
2349
+ },
2350
+ children: children
2351
+ })
2352
+ });
2355
2353
  };
2356
- Checkbox.defaultProps = {
2357
- id: null,
2358
- checked: false,
2359
- required: false,
2360
- disabled: false,
2361
- readOnly: false,
2362
- secondary: null,
2363
- onFocus: null,
2364
- onBlur: null,
2365
- className: undefined
2354
+
2355
+ const Badge = ({
2356
+ badge,
2357
+ className = undefined,
2358
+ size = Size.SMALL,
2359
+ border = Theme.LIGHT,
2360
+ children
2361
+ }) => {
2362
+ const classes = classNames('tw-badge', {
2363
+ [`tw-badge-border-${border}`]: border,
2364
+ [`tw-badge-${size}`]: size
2365
+ }, className);
2366
+ return /*#__PURE__*/jsxs("div", {
2367
+ className: classes,
2368
+ children: [/*#__PURE__*/jsx("div", {
2369
+ className: "tw-badge__children",
2370
+ children: children
2371
+ }), /*#__PURE__*/jsx("div", {
2372
+ className: "tw-badge__content",
2373
+ children: badge
2374
+ })]
2375
+ });
2366
2376
  };
2367
2377
 
2368
- const CheckboxOption = /*#__PURE__*/forwardRef(({
2369
- checked,
2370
- disabled,
2371
- onChange,
2378
+ const OptionalBadge = ({
2379
+ url,
2380
+ altText,
2381
+ statusIcon,
2382
+ children,
2372
2383
  ...rest
2373
- }, reference) => {
2374
- return /*#__PURE__*/jsx(Option$2, {
2375
- ...rest,
2376
- ref: reference,
2377
- disabled: disabled,
2378
- button: /*#__PURE__*/jsx(CheckboxButton$1, {
2379
- checked: checked,
2380
- disabled: disabled,
2381
- onChange: () => onChange?.(!checked)
2384
+ }) => {
2385
+ if (url) {
2386
+ return /*#__PURE__*/jsx(Badge, {
2387
+ badge: /*#__PURE__*/jsx("img", {
2388
+ src: url,
2389
+ alt: altText
2390
+ }),
2391
+ ...rest,
2392
+ children: children
2393
+ });
2394
+ }
2395
+ if (statusIcon) {
2396
+ return /*#__PURE__*/jsx(Badge, {
2397
+ badge: /*#__PURE__*/jsx(StatusIcon, {
2398
+ sentiment: statusIcon,
2399
+ size: Size.SMALL
2400
+ }),
2401
+ ...rest,
2402
+ children: children
2403
+ });
2404
+ }
2405
+ return /*#__PURE__*/jsx(Fragment, {
2406
+ children: children
2407
+ });
2408
+ };
2409
+ const AvatarWrapper = ({
2410
+ url,
2411
+ profileType,
2412
+ profileId,
2413
+ badgeUrl,
2414
+ badgeAltText,
2415
+ badgeStatusIcon,
2416
+ name,
2417
+ avatarProps,
2418
+ badgeProps
2419
+ }) => {
2420
+ const [hasImageLoadError, setImageLoadError] = useState(false);
2421
+ const isBusinessProfile = profileType === ProfileType.BUSINESS;
2422
+ // Reset the errored state when url changes
2423
+ useEffect(() => setImageLoadError(false), [url]);
2424
+ const getAvatarProps = () => {
2425
+ if (url && !hasImageLoadError) {
2426
+ return {
2427
+ type: AvatarType.THUMBNAIL,
2428
+ children: /*#__PURE__*/jsx("img", {
2429
+ src: url,
2430
+ alt: "",
2431
+ onError: () => setImageLoadError(true)
2432
+ }),
2433
+ ...avatarProps
2434
+ };
2435
+ }
2436
+ if (profileType) {
2437
+ return {
2438
+ type: AvatarType.ICON,
2439
+ children: isBusinessProfile ? /*#__PURE__*/jsx(Briefcase, {
2440
+ size: "24"
2441
+ }) : /*#__PURE__*/jsx(Person, {
2442
+ size: "24"
2443
+ }),
2444
+ ...avatarProps
2445
+ };
2446
+ }
2447
+ if (name) {
2448
+ return {
2449
+ type: AvatarType.INITIALS,
2450
+ children: /*#__PURE__*/jsx(Fragment, {
2451
+ children: getInitials(name)
2452
+ }),
2453
+ backgroundColorSeed: profileId?.toString(),
2454
+ ...avatarProps
2455
+ };
2456
+ }
2457
+ return {
2458
+ type: AvatarType.ICON,
2459
+ children: /*#__PURE__*/jsx(Person, {
2460
+ size: "24"
2461
+ }),
2462
+ ...avatarProps
2463
+ };
2464
+ };
2465
+ return /*#__PURE__*/jsx(OptionalBadge, {
2466
+ url: badgeUrl,
2467
+ altText: badgeAltText,
2468
+ statusIcon: badgeStatusIcon,
2469
+ ...badgeProps,
2470
+ children: /*#__PURE__*/jsx(Avatar, {
2471
+ size: Size.MEDIUM,
2472
+ ...getAvatarProps()
2382
2473
  })
2383
2474
  });
2384
- });
2475
+ };
2476
+ function getInitials(name) {
2477
+ const allInitials = name.split(' ').map(part => part[0]).join('').toUpperCase();
2478
+ if (allInitials.length === 1) {
2479
+ return allInitials[0];
2480
+ }
2481
+ return allInitials[0] + allInitials.slice(-1);
2482
+ }
2385
2483
 
2386
- const Chip = ({
2387
- label,
2388
- value,
2389
- onRemove,
2390
- onClick,
2391
- onKeyPress,
2392
- className = undefined,
2393
- 'aria-label': ariaLabel,
2394
- 'aria-checked': ariaChecked,
2395
- role,
2396
- closeButton
2397
- }) => {
2398
- const isActionable = onClick || onKeyPress;
2399
- const defaultRole = isActionable ? 'button' : undefined;
2400
- const tabIndex = isActionable ? 0 : -1;
2401
- const {
2402
- isModern
2403
- } = useTheme();
2484
+ const Card$2 = /*#__PURE__*/forwardRef(({
2485
+ className,
2486
+ children = null,
2487
+ id,
2488
+ isDisabled = false,
2489
+ isSmall = false,
2490
+ onDismiss,
2491
+ testId,
2492
+ ...props
2493
+ }, ref) => {
2404
2494
  const closeButtonReference = useRef(null);
2405
- const previousCloseButtonShown = useRef(undefined);
2406
- useEffect(() => {
2407
- if (closeButtonReference.current != null && previousCloseButtonShown.current === false) {
2408
- closeButtonReference.current?.focus();
2409
- }
2410
- previousCloseButtonShown.current = closeButtonReference.current != null;
2411
- }, [onRemove]);
2412
2495
  return /*#__PURE__*/jsxs("div", {
2413
- role: role ?? defaultRole,
2414
- tabIndex: tabIndex,
2415
- "aria-label": ariaLabel,
2416
- "aria-checked": ariaChecked,
2417
- className: classNames('np-chip', 'd-flex', 'align-items-center', 'justify-content-between', onRemove ? 'np-chip--removable' : '', className),
2418
- ...(isActionable && {
2419
- onClick,
2420
- onKeyPress
2421
- }),
2422
- children: [isModern ? /*#__PURE__*/jsx(Body, {
2423
- "aria-hidden": !!onRemove,
2424
- type: Typography.BODY_DEFAULT_BOLD,
2425
- children: label
2426
- }) : /*#__PURE__*/jsx("span", {
2427
- "aria-hidden": "false",
2428
- className: "np-chip-label",
2429
- children: label
2430
- }), onRemove ? /*#__PURE__*/jsx(CloseButton, {
2496
+ ref: ref,
2497
+ className: classNames('np-Card', {
2498
+ 'np-Card--small': !!isSmall,
2499
+ 'is-disabled': !!isDisabled
2500
+ }, className),
2501
+ id: id,
2502
+ "data-testid": testId,
2503
+ ...props,
2504
+ children: [onDismiss && /*#__PURE__*/jsx(CloseButton, {
2431
2505
  ref: closeButtonReference,
2432
- className: isModern ? `btn-unstyled` : `btn-unstyled m-l-1`,
2433
- "aria-label": closeButton?.['aria-label'],
2434
- size: "sm",
2435
- filled: isModern,
2436
- onClick: onRemove
2437
- }) : null]
2438
- }, value);
2439
- };
2440
-
2441
- var messages$a = defineMessages({
2442
- ariaLabel: {
2443
- id: "neptune.Chips.ariaLabel"
2444
- }
2506
+ className: "np-Card-closeButton",
2507
+ size: isSmall ? 'sm' : 'md',
2508
+ isDisabled: isDisabled,
2509
+ testId: "close-button",
2510
+ onClick: e => {
2511
+ stopPropagation$1(e);
2512
+ onDismiss();
2513
+ }
2514
+ }), children]
2515
+ });
2445
2516
  });
2517
+ Card$2.displayName = 'Card';
2446
2518
 
2447
- const Chips = ({
2448
- chips,
2449
- onChange,
2450
- selected,
2451
- 'aria-label': ariaLabel,
2519
+ function Display({
2520
+ as: Heading = 'h1',
2521
+ type = Typography.DISPLAY_LARGE,
2522
+ children,
2523
+ className,
2524
+ id
2525
+ }) {
2526
+ return /*#__PURE__*/jsx(Heading, {
2527
+ id: id,
2528
+ className: classNames(`np-text-${type}`, 'text-primary', className),
2529
+ children: children
2530
+ });
2531
+ }
2532
+
2533
+ const EmptyTransparentImage = 'data:image/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==';
2534
+ const Image = ({
2535
+ id,
2536
+ src,
2537
+ alt,
2538
+ onLoad,
2539
+ onError,
2452
2540
  className,
2453
- multiple
2541
+ loading,
2542
+ stretch = true,
2543
+ role,
2544
+ shrink = true
2454
2545
  }) => {
2455
- const intl = useIntl();
2456
- const isSelected = value => Array.isArray(selected) ? selected.includes(value) : selected === value;
2457
- const handleOnChange = (selectedValue, isCurrentlyEnabled) => {
2458
- onChange({
2459
- isEnabled: !isCurrentlyEnabled,
2460
- selectedValue
2461
- });
2462
- };
2463
- return /*#__PURE__*/jsx("div", {
2464
- className: classNames('np-chips d-flex', className),
2465
- "aria-label": ariaLabel,
2466
- role: !multiple ? 'radiogroup' : undefined,
2467
- children: chips.map(chip => {
2468
- const chipSelected = isSelected(chip.value);
2469
- return /*#__PURE__*/jsx(Chip, {
2470
- value: chip.value,
2471
- label: chip.label,
2472
- closeButton: {
2473
- 'aria-label': intl.formatMessage(messages$a.ariaLabel, {
2474
- choice: chip.label
2475
- })
2476
- },
2477
- className: classNames('text-xs-nowrap', {
2478
- 'np-chip--selected': chipSelected,
2479
- 'p-r-1': multiple && chipSelected
2480
- }),
2481
- ...(multiple && chipSelected ? {
2482
- onRemove: () => handleOnChange(chip.value, chipSelected),
2483
- 'aria-label': chip.label
2484
- } : {
2485
- onClick: () => handleOnChange(chip.value, chipSelected),
2486
- onKeyPress: () => handleOnChange(chip.value, chipSelected),
2487
- role: !multiple ? 'radio' : undefined,
2488
- 'aria-checked': chipSelected
2489
- })
2490
- }, chip.value);
2491
- })
2546
+ const elementReference = useRef(null);
2547
+ const [hasIntersected] = useHasIntersected({
2548
+ elRef: elementReference,
2549
+ loading
2550
+ });
2551
+ let imageSource = src;
2552
+ let imageOnLoad = onLoad;
2553
+ if (loading === 'lazy' && !hasIntersected) {
2554
+ imageSource = EmptyTransparentImage;
2555
+ imageOnLoad = undefined;
2556
+ }
2557
+ return /*#__PURE__*/jsx("img", {
2558
+ ref: elementReference,
2559
+ id: id,
2560
+ alt: alt,
2561
+ src: imageSource,
2562
+ className: classNames(['tw-image', {
2563
+ 'tw-image__stretch': stretch,
2564
+ 'tw-image__shrink': shrink
2565
+ }, className]),
2566
+ role: role,
2567
+ onLoad: imageOnLoad,
2568
+ onError: onError
2492
2569
  });
2493
2570
  };
2494
2571
 
2495
- const CircularButton = ({
2572
+ const defaultPromoCardContext = {
2573
+ state: '',
2574
+ isDisabled: false,
2575
+ // eslint-disable-next-line @typescript-eslint/no-empty-function
2576
+ onChange: () => {}
2577
+ };
2578
+ /**
2579
+ * The PromoCard context object.
2580
+ */
2581
+ const PromoCardContext = /*#__PURE__*/createContext(defaultPromoCardContext);
2582
+ /**
2583
+ * A custom hook for accessing the PromoCard context object.
2584
+ *
2585
+ * The `usePromoCardContext` hook is used to access the PromoCard context object
2586
+ * from within a child PromoCard component. It throws an error if the context
2587
+ * object is not available, which can help with debugging and development.
2588
+ *
2589
+ * @returns {PromoCardContextType} - The PromoCard context object.
2590
+ */
2591
+ const usePromoCardContext = () => {
2592
+ return useContext(PromoCardContext);
2593
+ };
2594
+
2595
+ const PromoCardIndicator = ({
2496
2596
  className,
2497
2597
  children,
2498
- disabled,
2598
+ label,
2499
2599
  icon,
2500
- priority = Priority.PRIMARY,
2501
- type = ControlType.ACCENT,
2600
+ isSmall = false,
2601
+ testid,
2502
2602
  ...rest
2503
2603
  }) => {
2504
- const classes = classNames('btn np-btn', typeClassMap[type], priorityClassMap[priority]);
2505
- const iconElement = Number(icon.props.size) !== 24 ? /*#__PURE__*/cloneElement(icon, {
2506
- size: 24
2507
- }) : icon;
2508
- return /*#__PURE__*/jsxs("label", {
2509
- className: classNames('np-circular-btn', priority, type, disabled && 'disabled', className),
2510
- children: [/*#__PURE__*/jsx("input", {
2511
- type: "button",
2512
- "aria-label": children,
2513
- className: classes,
2514
- disabled: disabled,
2515
- ...rest
2516
- }), iconElement, /*#__PURE__*/jsx(Body, {
2604
+ const isIconString = icon && typeof icon === 'string';
2605
+ const IconComponent = isIconString && {
2606
+ check: Check,
2607
+ arrow: ArrowRight,
2608
+ download: Download
2609
+ }[icon];
2610
+ return /*#__PURE__*/jsxs("div", {
2611
+ className: classNames('np-Card-indicator', className),
2612
+ "data-testid": testid,
2613
+ ...rest,
2614
+ children: [label && /*#__PURE__*/jsx(Body, {
2517
2615
  as: "span",
2518
- className: "np-circular-btn__label",
2519
- type: Typography.BODY_DEFAULT_BOLD,
2520
- children: children
2521
- })]
2616
+ type: Typography.BODY_LARGE_BOLD,
2617
+ className: "np-Card-indicatorText",
2618
+ children: label
2619
+ }), icon && /*#__PURE__*/jsx(Avatar, {
2620
+ type: AvatarType.ICON,
2621
+ size: isSmall ? 40 : 56,
2622
+ backgroundColor: "var(--Card-indicator-icon-background-color)",
2623
+ className: "np-Card-indicatorIcon",
2624
+ children: IconComponent ? /*#__PURE__*/jsx(IconComponent, {
2625
+ size: 24,
2626
+ "aria-hidden": "true"
2627
+ }) : icon
2628
+ }), children]
2522
2629
  });
2523
2630
  };
2524
2631
 
2525
- const FocusBoundary = ({
2526
- children
2527
- }) => {
2528
- const wrapperReference = useRef(null);
2529
- useEffect(() => {
2530
- wrapperReference.current?.focus({
2531
- preventScroll: true
2632
+ const PromoCard = /*#__PURE__*/forwardRef(({
2633
+ className,
2634
+ description,
2635
+ defaultChecked,
2636
+ download,
2637
+ href,
2638
+ hrefLang,
2639
+ id,
2640
+ headingLevel = 'h3',
2641
+ imageAlt,
2642
+ imageClass,
2643
+ imageSource,
2644
+ indicatorLabel,
2645
+ indicatorIcon,
2646
+ isChecked,
2647
+ isDisabled,
2648
+ onClick,
2649
+ onKeyDown,
2650
+ rel,
2651
+ tabIndex,
2652
+ target,
2653
+ testId,
2654
+ title,
2655
+ type,
2656
+ value,
2657
+ isSmall,
2658
+ useDisplayFont = true,
2659
+ anchorRef,
2660
+ anchorId,
2661
+ ...props
2662
+ }, ref) => {
2663
+ // Set the `checked` state to the value of `defaultChecked` if it is truthy,
2664
+ // or the value of `isChecked` if it is truthy, or `false` if neither
2665
+ // is truthy.
2666
+ const {
2667
+ state,
2668
+ onChange,
2669
+ isDisabled: contextIsDisabled
2670
+ } = usePromoCardContext();
2671
+ const [checked, setChecked] = useState(type === 'checkbox' ? defaultChecked ?? isChecked ?? false : false);
2672
+ const handleClick = () => {
2673
+ if (type === 'radio') {
2674
+ onChange(value || ''); // Update the context state for radio
2675
+ } else if (type === 'checkbox') {
2676
+ setChecked(!checked); // Update local state for checkbox
2677
+ }
2678
+ };
2679
+ const fallbackId = useId();
2680
+ const componentId = id || fallbackId;
2681
+ // Set the icon to `'arrow'` if `href` is truthy and `type` is falsy, or
2682
+ // `'download'` if `download` is truthy. If neither condition is true, set
2683
+ // `icon` to `undefined`.
2684
+ // Create a function to get icon type
2685
+ const getIconType = () => {
2686
+ if (indicatorIcon) {
2687
+ return indicatorIcon;
2688
+ }
2689
+ if (download) {
2690
+ return 'download';
2691
+ }
2692
+ if (href && !type) {
2693
+ return 'arrow';
2694
+ }
2695
+ return undefined;
2696
+ };
2697
+ // Define all class names string based on the values of the `href`, `type`,
2698
+ // `checked`, and `className` props.
2699
+ const commonClasses = classNames({
2700
+ 'np-Card--promoCard': true,
2701
+ 'np-Card--checked': !href && type,
2702
+ 'np-Card--link': href && !type,
2703
+ 'is-checked': type === 'radio' ? value === state : type === 'checkbox' ? checked : undefined
2704
+ }, className);
2705
+ // Object with common props that will be passed to the `Card` components
2706
+ const commonProps = {
2707
+ className: commonClasses,
2708
+ id: componentId,
2709
+ isDisabled: isDisabled || contextIsDisabled,
2710
+ onClick,
2711
+ onKeyDown,
2712
+ ref,
2713
+ 'data-testid': testId,
2714
+ isSmall
2715
+ };
2716
+ // Object with Anchor props that will be passed to the `a` element. These
2717
+ // won't be refurned if set to `isDisabled`
2718
+ const anchorProps = href && !isDisabled ? {
2719
+ download,
2720
+ href: href || undefined,
2721
+ hrefLang,
2722
+ rel,
2723
+ target,
2724
+ ref: anchorRef,
2725
+ id: anchorId
2726
+ } : {};
2727
+ // Object of all Checked props that will be passed to the root `Card` component
2728
+ const checkedProps = (type === 'checkbox' || type === 'radio') && !href ? {
2729
+ ...commonProps,
2730
+ 'aria-checked': type === 'radio' ? value === state : type === 'checkbox' ? checked : undefined,
2731
+ 'aria-describedby': `${componentId}-title`,
2732
+ 'aria-disabled': isDisabled,
2733
+ 'data-value': value ?? undefined,
2734
+ role: type === 'checkbox' || type === 'radio' ? type : undefined,
2735
+ onClick: handleClick,
2736
+ onKeyDown: event => {
2737
+ if (event.key === 'Enter' || event.key === ' ') {
2738
+ handleClick();
2739
+ }
2740
+ },
2741
+ ref,
2742
+ tabIndex: 0
2743
+ } : {};
2744
+ const getTitle = () => {
2745
+ const titleContent = href && !type ? /*#__PURE__*/jsx("a", {
2746
+ className: "np-Card-titleLink",
2747
+ ...anchorProps,
2748
+ children: title
2749
+ }) : title;
2750
+ const titleProps = {
2751
+ id: `${componentId}-title`,
2752
+ as: headingLevel,
2753
+ className: 'np-Card-title'
2754
+ };
2755
+ return useDisplayFont ? /*#__PURE__*/jsx(Display, {
2756
+ type: Typography.DISPLAY_SMALL,
2757
+ ...titleProps,
2758
+ children: titleContent
2759
+ }) : /*#__PURE__*/jsx(Title, {
2760
+ type: Typography.TITLE_SUBSECTION,
2761
+ ...titleProps,
2762
+ children: titleContent
2532
2763
  });
2533
- }, []);
2534
- return /*#__PURE__*/jsx(FocusScope, {
2535
- contain: true,
2536
- restoreFocus: true,
2537
- children: /*#__PURE__*/jsx("div", {
2538
- ref: wrapperReference,
2539
- tabIndex: -1,
2540
- children: children
2541
- })
2542
- });
2543
- };
2544
-
2545
- function withNextPortalWrapper(Component) {
2546
- return function (props) {
2547
- const [mounted, setMounted] = useState(false);
2548
- useEffect(() => {
2549
- setMounted(true);
2550
- }, [setMounted]);
2551
- return mounted ? /*#__PURE__*/createPortal( /*#__PURE__*/jsx(Component, {
2552
- ...props
2553
- }), document.body) : null;
2554
2764
  };
2555
- }
2556
-
2557
- /**
2558
- * Dimmer state management inspired by Material UI's ModalManager (https://github.com/mui-org/material-ui)
2559
- */
2560
- class DimmerManager {
2561
- /**
2562
- * Dimmer refs
2563
- */
2564
- dimmers;
2565
- constructor() {
2566
- this.dimmers = [];
2567
- }
2568
- add(dimmer) {
2569
- let dimmerIndex = this.dimmers.indexOf(dimmer);
2570
- if (dimmerIndex !== -1) {
2571
- return dimmerIndex;
2572
- }
2573
- dimmerIndex = this.dimmers.length;
2574
- this.dimmers.push(dimmer);
2575
- return dimmerIndex;
2576
- }
2577
- remove(dimmer) {
2578
- const dimmerIndex = this.dimmers.indexOf(dimmer);
2579
- if (dimmerIndex !== -1) {
2580
- this.dimmers.splice(dimmerIndex, 1);
2581
- }
2582
- return dimmerIndex;
2583
- }
2584
- isTop(dimmer) {
2585
- return this.dimmers.length > 0 && this.dimmers[this.dimmers.length - 1] === dimmer;
2586
- }
2587
- }
2765
+ useEffect(() => {
2766
+ setChecked(defaultChecked ?? isChecked ?? false);
2767
+ }, [defaultChecked, isChecked]);
2768
+ return /*#__PURE__*/jsxs(Card$2, {
2769
+ ...commonProps,
2770
+ ...checkedProps,
2771
+ ...props,
2772
+ children: [(value === state || checked) && /*#__PURE__*/jsx("span", {
2773
+ className: "np-Card-check",
2774
+ children: /*#__PURE__*/jsx(Check, {
2775
+ size: 24,
2776
+ "aria-hidden": "true"
2777
+ })
2778
+ }), getTitle(), /*#__PURE__*/jsx(Body, {
2779
+ className: "np-Card-description",
2780
+ children: description
2781
+ }), imageSource && /*#__PURE__*/jsx("div", {
2782
+ className: classNames('np-Card-image', {
2783
+ imageClass
2784
+ }),
2785
+ children: /*#__PURE__*/jsx(Image, {
2786
+ src: imageSource,
2787
+ alt: imageAlt || '',
2788
+ loading: "lazy"
2789
+ })
2790
+ }), /*#__PURE__*/jsx(PromoCardIndicator, {
2791
+ label: indicatorLabel,
2792
+ icon: getIconType(),
2793
+ isSmall: isSmall
2794
+ })]
2795
+ });
2796
+ });
2797
+ var PromoCard$1 = /*#__PURE__*/React__default.memo(PromoCard);
2588
2798
 
2589
- const EXIT_ANIMATION$1 = 350;
2590
- const dimmerManager = new DimmerManager();
2591
- const handleTouchMove = event => {
2592
- const isTouchedElementDimmer = event.target.classList.contains('dimmer');
2593
- // disable scroll on iOS devices for Dimmer area
2594
- // this is because of bug in WebKit https://bugs.webkit.org/show_bug.cgi?id=220908
2595
- // note: scrolling still works for children(s) as expected
2596
- if (isIosDevice() && isTouchedElementDimmer) {
2597
- event.stopPropagation();
2598
- event.preventDefault();
2599
- }
2600
- };
2601
- const Dimmer = ({
2602
- children,
2799
+ const LEFT_SCROLL_OFFSET = 8;
2800
+ const Carousel = ({
2801
+ header,
2603
2802
  className,
2604
- disableClickToClose = false,
2605
- contentPosition,
2606
- fadeContentOnEnter = false,
2607
- fadeContentOnExit = false,
2608
- open = false,
2609
- scrollable = false,
2610
- transparent = false,
2611
- onClose
2803
+ cards,
2804
+ onClick
2612
2805
  }) => {
2613
- const [hasNotExited, setHasNotExited] = useState(false);
2614
- const dimmerReference = useRef(null);
2615
- const closeOnClick = event => {
2616
- if (event.target === dimmerReference.current) {
2617
- onClose?.(event);
2806
+ const [scrollPosition, setScrollPosition] = useState(0);
2807
+ const [previousScrollPosition, setPreviousScrollPosition] = useState(0);
2808
+ const [scrollIsAtEnd, setScrollIsAtEnd] = useState(false);
2809
+ const [visibleCardOnMobileView, setVisibleCardOnMobileView] = useState('');
2810
+ const carouselElementRef = useRef(null);
2811
+ const carouselCardsRef = useRef([]);
2812
+ const isLeftActionButtonEnabled = scrollPosition > LEFT_SCROLL_OFFSET;
2813
+ const areActionButtonsEnabled = isLeftActionButtonEnabled || !scrollIsAtEnd;
2814
+ const [focusedCard, setFocusedCard] = useState(cards?.[0]?.id);
2815
+ const updateScrollButtonsState = () => {
2816
+ if (carouselElementRef.current) {
2817
+ const {
2818
+ scrollWidth,
2819
+ offsetWidth
2820
+ } = carouselElementRef.current;
2821
+ const scrollAtEnd = scrollWidth - offsetWidth <= scrollPosition + LEFT_SCROLL_OFFSET;
2822
+ setScrollIsAtEnd(scrollAtEnd);
2618
2823
  }
2619
- };
2620
- const handleClick = event => {
2621
- if (disableClickToClose || !onClose) {
2622
- return;
2824
+ const scrollDirecton = scrollPosition > previousScrollPosition ? 'right' : 'left';
2825
+ const cardsInFullViewIds = [];
2826
+ carouselCardsRef.current.forEach(card => {
2827
+ if (isVisible(carouselElementRef.current, card.cardElement)) {
2828
+ // eslint-disable-next-line functional/immutable-data
2829
+ cardsInFullViewIds.push(card.cardElement.getAttribute('id') ?? '');
2830
+ }
2831
+ });
2832
+ if (cardsInFullViewIds.length >= 1) {
2833
+ const visibleCardIndex = scrollDirecton === 'right' ? cardsInFullViewIds.length - 1 : 0;
2834
+ const visibleCardId = cardsInFullViewIds[visibleCardIndex];
2835
+ setVisibleCardOnMobileView(visibleCardId);
2836
+ setFocusedCard(visibleCardId);
2623
2837
  }
2624
- closeOnClick(event);
2838
+ setPreviousScrollPosition(scrollPosition);
2625
2839
  };
2626
- const handleKeyDown = useCallback(event => {
2627
- if (event.key !== 'Escape') {
2628
- return;
2840
+ const scrollCarousel = (direction = 'right') => {
2841
+ if (carouselElementRef.current) {
2842
+ const {
2843
+ scrollWidth
2844
+ } = carouselElementRef.current;
2845
+ const cardWidth = scrollWidth / carouselCardsRef.current.length;
2846
+ const res = Math.floor(cardWidth - cardWidth * 0.05);
2847
+ carouselElementRef.current.scrollBy({
2848
+ left: direction === 'right' ? res : -res,
2849
+ behavior: 'smooth'
2850
+ });
2629
2851
  }
2630
- event.stopPropagation();
2631
- if (onClose && dimmerReference.current && dimmerManager.isTop(dimmerReference.current)) {
2632
- onClose(event);
2852
+ };
2853
+ const handleOnKeyDown = (event, index) => {
2854
+ if (event.key === 'ArrowRight' || event.key === 'ArrowLeft') {
2855
+ const nextIndex = event.key === 'ArrowRight' ? index + 1 : index - 1;
2856
+ const nextCard = cards[nextIndex];
2857
+ if (nextCard) {
2858
+ const ref = carouselCardsRef.current[nextIndex];
2859
+ if (ref.type === 'promo') {
2860
+ ref.anchorElement?.focus();
2861
+ } else {
2862
+ ref.cardElement?.focus();
2863
+ }
2864
+ scrollCardIntoView(carouselCardsRef.current[nextIndex].cardElement, nextCard);
2865
+ event.preventDefault();
2866
+ }
2633
2867
  }
2634
- }, [onClose]);
2635
- const onEnter = () => {
2636
- setHasNotExited(true);
2637
- if (dimmerReference.current) {
2638
- dimmerManager.add(dimmerReference.current);
2868
+ if (event.key === 'Enter' || event.key === ' ') {
2869
+ event.currentTarget.click();
2639
2870
  }
2640
2871
  };
2641
- const onExited = () => {
2642
- setHasNotExited(false);
2643
- if (dimmerReference.current) {
2644
- dimmerManager.remove(dimmerReference.current);
2645
- }
2872
+ const scrollCardIntoView = (element, card) => {
2873
+ element.scrollIntoView({
2874
+ behavior: 'smooth',
2875
+ block: 'nearest',
2876
+ inline: 'center'
2877
+ });
2878
+ setFocusedCard(card.id);
2646
2879
  };
2647
2880
  useEffect(() => {
2648
- const localReferenceCopy = dimmerReference.current;
2649
- if (open) {
2650
- document.addEventListener('keydown', handleKeyDown);
2651
- localReferenceCopy?.addEventListener('touchmove', handleTouchMove, {
2652
- passive: true
2653
- });
2881
+ updateScrollButtonsState();
2882
+ // eslint-disable-next-line react-hooks/exhaustive-deps
2883
+ }, [scrollPosition]);
2884
+ useEffect(() => {
2885
+ window.addEventListener('resize', updateScrollButtonsState);
2886
+ return () => {
2887
+ window.removeEventListener('resize', updateScrollButtonsState);
2888
+ };
2889
+ // eslint-disable-next-line react-hooks/exhaustive-deps
2890
+ }, []);
2891
+ const addElementToCardsRefArray = (index, ref) => {
2892
+ if (ref) {
2893
+ // eslint-disable-next-line functional/immutable-data
2894
+ carouselCardsRef.current[index] = {
2895
+ type: ref.type ?? carouselCardsRef.current?.[index]?.type,
2896
+ cardElement: ref.cardElement ?? carouselCardsRef.current?.[index]?.cardElement,
2897
+ anchorElement: ref.anchorElement ?? carouselCardsRef.current?.[index]?.anchorElement
2898
+ };
2654
2899
  }
2655
- return () => {
2656
- document.removeEventListener('keydown', handleKeyDown);
2657
- localReferenceCopy?.removeEventListener('touchmove', handleTouchMove);
2658
- };
2659
- }, [handleKeyDown, open]);
2660
- return /*#__PURE__*/jsx(DimmerWrapper, {
2661
- open: open,
2662
- hasNotExited: hasNotExited,
2663
- children: /*#__PURE__*/jsx(CSSTransition, {
2664
- nodeRef: dimmerReference,
2665
- in: open,
2666
- appear: true
2667
- // Wait for animation to finish before unmount.
2668
- ,
2669
- timeout: {
2670
- enter: 0,
2671
- exit: EXIT_ANIMATION$1
2672
- },
2673
- classNames: {
2674
- enter: classNames({
2675
- 'dimmer--enter-fade': fadeContentOnEnter
2676
- }),
2677
- enterDone: classNames('dimmer--enter-done', {
2678
- 'dimmer--enter-fade': fadeContentOnEnter
2679
- }),
2680
- exit: classNames('dimmer--exit', {
2681
- 'dimmer--exit-fade': fadeContentOnExit
2682
- })
2900
+ };
2901
+ return /*#__PURE__*/jsxs("div", {
2902
+ className: classNames('carousel-wrapper', className),
2903
+ children: [/*#__PURE__*/jsxs("div", {
2904
+ className: "d-flex justify-content-between carousel__header",
2905
+ children: [typeof header === 'string' ? /*#__PURE__*/jsx(Title, {
2906
+ as: "span",
2907
+ type: "title-body",
2908
+ children: header
2909
+ }) : header, areActionButtonsEnabled ? /*#__PURE__*/jsxs("div", {
2910
+ className: "hidden-xs",
2911
+ children: [/*#__PURE__*/jsx(ActionButton, {
2912
+ className: "carousel__scroll-button",
2913
+ tabIndex: -1,
2914
+ priority: "secondary",
2915
+ disabled: !isLeftActionButtonEnabled,
2916
+ "aria-hidden": "true",
2917
+ "data-testid": "scroll-carousel-left",
2918
+ onClick: () => scrollCarousel('left'),
2919
+ children: /*#__PURE__*/jsx(ChevronLeft, {})
2920
+ }), /*#__PURE__*/jsx(ActionButton, {
2921
+ tabIndex: -1,
2922
+ className: "carousel__scroll-button m-l-1",
2923
+ priority: "secondary",
2924
+ "aria-hidden": "true",
2925
+ "data-testid": "scroll-carousel-right",
2926
+ disabled: scrollIsAtEnd,
2927
+ onClick: () => scrollCarousel(),
2928
+ children: /*#__PURE__*/jsx(ChevronRight, {})
2929
+ })]
2930
+ }) : null]
2931
+ }), /*#__PURE__*/jsx("div", {
2932
+ ref: carouselElementRef,
2933
+ tabIndex: -1,
2934
+ role: "list",
2935
+ className: "carousel",
2936
+ onScroll: event => {
2937
+ const target = event.target;
2938
+ setScrollPosition(target.scrollLeft);
2683
2939
  },
2684
- unmountOnExit: true,
2685
- onEnter: onEnter,
2686
- onExited: onExited,
2687
- children: /*#__PURE__*/jsx(DimmerContentWrapper, {
2688
- scrollBody: !transparent,
2689
- children: /*#__PURE__*/jsx(FocusBoundary, {
2690
- children: /*#__PURE__*/jsx("div", {
2691
- ref: dimmerReference,
2692
- className: classNames('dimmer', {
2693
- 'dimmer--scrollable': scrollable,
2694
- 'dimmer--transparent': transparent
2695
- }, className),
2696
- role: "presentation",
2697
- onClick: handleClick,
2940
+ children: cards?.map((card, index) => {
2941
+ const sharedProps = {
2942
+ id: card.id,
2943
+ className: classNames('carousel__card', {
2944
+ 'carousel__card--focused': card.id === focusedCard
2945
+ }),
2946
+ onClick: () => {
2947
+ card.onClick?.();
2948
+ onClick?.(card.id);
2949
+ },
2950
+ onFocus: event => {
2951
+ scrollCardIntoView(event.currentTarget, card);
2952
+ }
2953
+ };
2954
+ const cardContent = card.type !== 'promo' ? /*#__PURE__*/jsx("div", {
2955
+ id: `${card.id}-content`,
2956
+ className: classNames('carousel__card-content', {
2957
+ [card.className ?? '']: !!card.className
2958
+ })
2959
+ // eslint-disable-next-line react/forbid-dom-props
2960
+ ,
2961
+ style: card.styles,
2962
+ children: card.content
2963
+ }) : null;
2964
+ if (card.type === 'button') {
2965
+ return /*#__PURE__*/jsx("div", {
2966
+ "aria-labelledby": `${card.id}-content`,
2967
+ role: "listitem",
2698
2968
  children: /*#__PURE__*/jsx("div", {
2699
- className: classNames('dimmer-content-positioner', contentPosition != null && ['d-flex justify-content-center', {
2700
- 'align-items-start': contentPosition === 'top',
2701
- 'align-items-center': contentPosition === 'center',
2702
- 'align-items-end': contentPosition === 'bottom'
2703
- }]),
2704
- children: children
2969
+ ...sharedProps,
2970
+ ref: el => {
2971
+ if (el) {
2972
+ // eslint-disable-next-line functional/immutable-data
2973
+ carouselCardsRef.current[index] = {
2974
+ type: 'default',
2975
+ cardElement: el
2976
+ };
2977
+ }
2978
+ },
2979
+ role: "button",
2980
+ tabIndex: 0,
2981
+ onKeyDown: event => handleOnKeyDown(event, index),
2982
+ children: cardContent
2983
+ })
2984
+ }, card.id);
2985
+ }
2986
+ if (card.type === 'promo') {
2987
+ return /*#__PURE__*/jsx("div", {
2988
+ id: card.id,
2989
+ role: "listitem",
2990
+ "aria-labelledby": `${card.id}-anchor`,
2991
+ children: /*#__PURE__*/jsx(PromoCard$1, {
2992
+ ...card,
2993
+ type: undefined,
2994
+ ...sharedProps,
2995
+ ref: el => {
2996
+ if (el) {
2997
+ addElementToCardsRefArray(index, {
2998
+ type: 'promo',
2999
+ cardElement: el
3000
+ });
3001
+ }
3002
+ },
3003
+ anchorRef: el => {
3004
+ if (el) {
3005
+ addElementToCardsRefArray(index, {
3006
+ type: 'promo',
3007
+ anchorElement: el
3008
+ });
3009
+ }
3010
+ },
3011
+ anchorId: `${card.id}-anchor`,
3012
+ onKeyDown: event => handleOnKeyDown(event, index)
2705
3013
  })
3014
+ }, card.id);
3015
+ }
3016
+ return /*#__PURE__*/jsx("div", {
3017
+ "aria-labelledby": `${card.id}-content`,
3018
+ role: "listitem",
3019
+ children: /*#__PURE__*/jsx("a", {
3020
+ ...sharedProps,
3021
+ ref: el => {
3022
+ if (el) {
3023
+ // eslint-disable-next-line functional/immutable-data
3024
+ carouselCardsRef.current[index] = {
3025
+ type: 'default',
3026
+ cardElement: el
3027
+ };
3028
+ }
3029
+ },
3030
+ href: card.href,
3031
+ rel: "noreferrer",
3032
+ onKeyDown: event => handleOnKeyDown(event, index),
3033
+ children: cardContent
2706
3034
  })
2707
- })
3035
+ }, card.id);
2708
3036
  })
2709
- })
3037
+ }), /*#__PURE__*/jsx("div", {
3038
+ className: "visible-xs",
3039
+ children: /*#__PURE__*/jsx("div", {
3040
+ className: "carousel__indicators",
3041
+ children: cards?.map((card, index) => /*#__PURE__*/jsx("button", {
3042
+ "data-testid": `${card.id}-indicator`,
3043
+ tabIndex: -1,
3044
+ "aria-hidden": true,
3045
+ type: "button",
3046
+ className: classNames('carousel__indicator', {
3047
+ 'carousel__indicator--selected': card.id === visibleCardOnMobileView
3048
+ }),
3049
+ onClick: () => {
3050
+ scrollCardIntoView(carouselCardsRef.current[index].cardElement, card);
3051
+ }
3052
+ }, `${card.id}-indicator`))
3053
+ })
3054
+ })]
3055
+ });
3056
+ };
3057
+ const isVisible = (container, el) => {
3058
+ const cWidth = container.offsetWidth;
3059
+ const cScrollOffset = container.scrollLeft;
3060
+ const elemLeft = el.offsetLeft - container.offsetLeft;
3061
+ const elemRight = elemLeft + el.offsetWidth;
3062
+ return elemLeft >= cScrollOffset && elemRight <= cScrollOffset + cWidth;
3063
+ };
3064
+
3065
+ const Card = /*#__PURE__*/forwardRef((props, reference) => {
3066
+ const {
3067
+ 'aria-label': ariaLabel,
3068
+ as: Element,
3069
+ isExpanded,
3070
+ title,
3071
+ details,
3072
+ children,
3073
+ onClick,
3074
+ icon,
3075
+ id,
3076
+ className,
3077
+ ...rest
3078
+ } = props;
3079
+ const isOpen = !!(isExpanded && children);
3080
+ return /*#__PURE__*/jsxs(Element, {
3081
+ ref: reference,
3082
+ className: classNames('np-card', className, {
3083
+ 'np-card--expanded': isOpen,
3084
+ 'np-card--inactive': !children,
3085
+ 'np-card--has-icon': !!icon
3086
+ }),
3087
+ id: id,
3088
+ "data-testid": rest['data-testid'],
3089
+ children: [/*#__PURE__*/jsx(Option$2, {
3090
+ "aria-label": ariaLabel,
3091
+ as: children ? 'button' : 'div',
3092
+ className: classNames('np-card__button'),
3093
+ media: icon,
3094
+ title: title,
3095
+ content: details,
3096
+ showMediaAtAllSizes: true,
3097
+ button: children && /*#__PURE__*/jsx(Chevron, {
3098
+ orientation: isOpen ? Position.TOP : Position.BOTTOM
3099
+ }),
3100
+ onClick: () => children && onClick(!isExpanded)
3101
+ }), /*#__PURE__*/jsx("div", {
3102
+ className: classNames('np-card__divider', {
3103
+ 'np-card__divider--expanded': isOpen
3104
+ })
3105
+ }), isOpen && /*#__PURE__*/jsx(Body, {
3106
+ as: "span",
3107
+ type: Typography.BODY_LARGE,
3108
+ className: "np-card__content d-block",
3109
+ children: children
3110
+ })]
2710
3111
  });
2711
- };
2712
- const DimmerWrapper = ({
2713
- open,
2714
- hasNotExited,
3112
+ });
3113
+ const hasChildren = ({
2715
3114
  children
3115
+ }) => children;
3116
+ Card.propTypes = {
3117
+ 'aria-label': PropTypes.string,
3118
+ as: PropTypes.string,
3119
+ isExpanded: requiredIf(PropTypes.bool, hasChildren),
3120
+ title: PropTypes.node.isRequired,
3121
+ details: PropTypes.node.isRequired,
3122
+ onClick: requiredIf(PropTypes.func, hasChildren),
3123
+ icon: PropTypes.node,
3124
+ children: PropTypes.node,
3125
+ id: PropTypes.string,
3126
+ className: PropTypes.string,
3127
+ 'data-testid': PropTypes.string
3128
+ };
3129
+ Card.defaultProps = {
3130
+ 'aria-label': undefined,
3131
+ as: 'div',
3132
+ children: null,
3133
+ id: null,
3134
+ className: null,
3135
+ 'data-testid': null
3136
+ };
3137
+ var Card$1 = Card;
3138
+
3139
+ const CheckboxButton = /*#__PURE__*/forwardRef(({
3140
+ checked,
3141
+ className,
3142
+ disabled,
3143
+ onChange,
3144
+ ...rest
3145
+ }, reference) => /*#__PURE__*/jsxs("span", {
3146
+ className: classNames('np-checkbox-button', className, disabled && 'disabled'),
3147
+ children: [/*#__PURE__*/jsx("input", {
3148
+ ...rest,
3149
+ ref: reference,
3150
+ type: "checkbox",
3151
+ disabled: disabled,
3152
+ checked: checked,
3153
+ onChange: onChange
3154
+ }), /*#__PURE__*/jsx("span", {
3155
+ className: "tw-checkbox-button",
3156
+ children: /*#__PURE__*/jsx("span", {
3157
+ className: "tw-checkbox-check"
3158
+ })
3159
+ })]
3160
+ }));
3161
+ var CheckboxButton$1 = CheckboxButton;
3162
+
3163
+ const Checkbox = ({
3164
+ id,
3165
+ checked,
3166
+ required,
3167
+ disabled,
3168
+ readOnly,
3169
+ label,
3170
+ className,
3171
+ secondary,
3172
+ onChange,
3173
+ onFocus,
3174
+ onBlur
2716
3175
  }) => {
2717
3176
  const {
2718
- screenMode,
2719
- theme
3177
+ isModern
2720
3178
  } = useTheme();
2721
- return open || hasNotExited ? /*#__PURE__*/jsx(ThemeProvider, {
2722
- theme: "personal",
2723
- screenMode: theme === 'personal' ? screenMode : 'light',
2724
- isNotRootProvider: true,
2725
- children: children
2726
- }) : /*#__PURE__*/jsx(Fragment, {
2727
- children: children
3179
+ const classList = classNames('np-checkbox', {
3180
+ checkbox: true,
3181
+ 'checkbox-lg': secondary,
3182
+ disabled: isModern && disabled
3183
+ }, className);
3184
+ const innerDisabled = disabled || readOnly;
3185
+ return /*#__PURE__*/jsx("div", {
3186
+ id: id,
3187
+ className: classList,
3188
+ children: /*#__PURE__*/jsxs("label", {
3189
+ className: classNames({
3190
+ disabled
3191
+ }),
3192
+ children: [/*#__PURE__*/jsx(CheckboxButton$1, {
3193
+ className: "p-r-2",
3194
+ checked: checked,
3195
+ disabled: innerDisabled,
3196
+ required: !innerDisabled && required,
3197
+ onFocus: onFocus,
3198
+ onChange: () => onChange(!checked),
3199
+ onBlur: onBlur
3200
+ }), /*#__PURE__*/jsxs(Body, {
3201
+ as: "span",
3202
+ className: "np-checkbox__text",
3203
+ type: secondary ? Typography.BODY_LARGE_BOLD : Typography.BODY_LARGE,
3204
+ children: [/*#__PURE__*/jsx("span", {
3205
+ className: required ? 'has-required' : undefined,
3206
+ children: label
3207
+ }), secondary && /*#__PURE__*/jsx(Body, {
3208
+ as: "span",
3209
+ className: classNames({
3210
+ secondary: !isModern
3211
+ }),
3212
+ children: secondary
3213
+ })]
3214
+ })]
3215
+ })
2728
3216
  });
2729
3217
  };
2730
- const DimmerContentWrapper = ({
2731
- children,
2732
- scrollBody
2733
- }) => {
2734
- useEffect(() => {
2735
- if (scrollBody) {
2736
- addNoScrollClass();
2737
- }
2738
- return () => {
2739
- if (scrollBody) {
2740
- removeNoScrollClass();
2741
- }
2742
- };
2743
- }, [scrollBody]);
2744
- return children;
3218
+ Checkbox.propTypes = {
3219
+ id: PropTypes.string,
3220
+ checked: PropTypes.bool,
3221
+ required: PropTypes.bool,
3222
+ disabled: PropTypes.bool,
3223
+ readOnly: PropTypes.bool,
3224
+ label: PropTypes.node.isRequired,
3225
+ secondary: PropTypes.string,
3226
+ onFocus: PropTypes.func,
3227
+ onChange: PropTypes.func.isRequired,
3228
+ onBlur: PropTypes.func,
3229
+ className: PropTypes.string
3230
+ };
3231
+ Checkbox.defaultProps = {
3232
+ id: null,
3233
+ checked: false,
3234
+ required: false,
3235
+ disabled: false,
3236
+ readOnly: false,
3237
+ secondary: null,
3238
+ onFocus: null,
3239
+ onBlur: null,
3240
+ className: undefined
2745
3241
  };
2746
- var Dimmer$1 = withNextPortalWrapper(Dimmer);
2747
3242
 
2748
- const EXIT_ANIMATION = 350;
2749
- const SlidingPanel = /*#__PURE__*/forwardRef(({
2750
- position = 'left',
2751
- open,
2752
- showSlidingPanelBorder,
2753
- slidingPanelPositionFixed,
2754
- className,
2755
- children,
3243
+ const CheckboxOption = /*#__PURE__*/forwardRef(({
3244
+ checked,
3245
+ disabled,
3246
+ onChange,
2756
3247
  ...rest
2757
3248
  }, reference) => {
2758
- const localReference = useRef(null);
2759
- useImperativeHandle(reference, () => localReference.current, []);
2760
- return /*#__PURE__*/createElement(CSSTransition, {
3249
+ return /*#__PURE__*/jsx(Option$2, {
2761
3250
  ...rest,
2762
- key: `sliding-panel--open-${position}`,
2763
- nodeRef: localReference,
2764
- in: open
2765
- // Wait for animation to finish before unmount.
2766
- ,
2767
- timeout: {
2768
- enter: 0,
2769
- exit: EXIT_ANIMATION
2770
- },
2771
- classNames: "sliding-panel",
2772
- appear: true,
2773
- unmountOnExit: true
2774
- }, /*#__PURE__*/jsx("div", {
2775
- ref: localReference,
2776
- className: classNames('sliding-panel', `sliding-panel--open-${position}`, showSlidingPanelBorder && `sliding-panel--border-${position}`, slidingPanelPositionFixed && 'sliding-panel--fixed', className),
2777
- children: children
2778
- }));
3251
+ ref: reference,
3252
+ disabled: disabled,
3253
+ button: /*#__PURE__*/jsx(CheckboxButton$1, {
3254
+ checked: checked,
3255
+ disabled: disabled,
3256
+ onChange: () => onChange?.(!checked)
3257
+ })
3258
+ });
3259
+ });
3260
+
3261
+ const Chip = ({
3262
+ label,
3263
+ value,
3264
+ onRemove,
3265
+ onClick,
3266
+ onKeyPress,
3267
+ className = undefined,
3268
+ 'aria-label': ariaLabel,
3269
+ 'aria-checked': ariaChecked,
3270
+ role,
3271
+ closeButton
3272
+ }) => {
3273
+ const isActionable = onClick || onKeyPress;
3274
+ const defaultRole = isActionable ? 'button' : undefined;
3275
+ const tabIndex = isActionable ? 0 : -1;
3276
+ const {
3277
+ isModern
3278
+ } = useTheme();
3279
+ const closeButtonReference = useRef(null);
3280
+ const previousCloseButtonShown = useRef(undefined);
3281
+ useEffect(() => {
3282
+ if (closeButtonReference.current != null && previousCloseButtonShown.current === false) {
3283
+ closeButtonReference.current?.focus();
3284
+ }
3285
+ previousCloseButtonShown.current = closeButtonReference.current != null;
3286
+ }, [onRemove]);
3287
+ return /*#__PURE__*/jsxs("div", {
3288
+ role: role ?? defaultRole,
3289
+ tabIndex: tabIndex,
3290
+ "aria-label": ariaLabel,
3291
+ "aria-checked": ariaChecked,
3292
+ className: classNames('np-chip', 'd-flex', 'align-items-center', 'justify-content-between', onRemove ? 'np-chip--removable' : '', className),
3293
+ ...(isActionable && {
3294
+ onClick,
3295
+ onKeyPress
3296
+ }),
3297
+ children: [isModern ? /*#__PURE__*/jsx(Body, {
3298
+ "aria-hidden": !!onRemove,
3299
+ type: Typography.BODY_DEFAULT_BOLD,
3300
+ children: label
3301
+ }) : /*#__PURE__*/jsx("span", {
3302
+ "aria-hidden": "false",
3303
+ className: "np-chip-label",
3304
+ children: label
3305
+ }), onRemove ? /*#__PURE__*/jsx(CloseButton, {
3306
+ ref: closeButtonReference,
3307
+ className: isModern ? `btn-unstyled` : `btn-unstyled m-l-1`,
3308
+ "aria-label": closeButton?.['aria-label'],
3309
+ size: "sm",
3310
+ filled: isModern,
3311
+ onClick: onRemove
3312
+ }) : null]
3313
+ }, value);
3314
+ };
3315
+
3316
+ var messages$a = defineMessages({
3317
+ ariaLabel: {
3318
+ id: "neptune.Chips.ariaLabel"
3319
+ }
2779
3320
  });
2780
3321
 
2781
- const Drawer = ({
2782
- children,
3322
+ const Chips = ({
3323
+ chips,
3324
+ onChange,
3325
+ selected,
3326
+ 'aria-label': ariaLabel,
2783
3327
  className,
2784
- footerContent,
2785
- headerTitle,
2786
- onClose,
2787
- open,
2788
- position
3328
+ multiple
2789
3329
  }) => {
2790
- logActionRequiredIf('Drawer now expects `onClose`, and will soon make this prop required. Please update your usage to provide it.', !onClose);
2791
- const {
2792
- isMobile
2793
- } = useLayout();
2794
- const titleId = useId();
2795
- return /*#__PURE__*/jsx(Dimmer$1, {
2796
- open: open,
2797
- onClose: onClose,
2798
- children: /*#__PURE__*/jsx(SlidingPanel, {
2799
- open: open,
2800
- position: isMobile ? Position.BOTTOM : position,
2801
- children: /*#__PURE__*/jsxs("div", {
2802
- role: "dialog",
2803
- "aria-modal": true,
2804
- "aria-labelledby": headerTitle ? titleId : undefined,
2805
- className: classNames('np-drawer', className),
2806
- children: [/*#__PURE__*/jsxs("div", {
2807
- className: classNames('np-drawer-header', {
2808
- 'np-drawer-header--withborder': headerTitle
2809
- }),
2810
- children: [headerTitle && /*#__PURE__*/jsx(Title, {
2811
- id: titleId,
2812
- type: Typography.TITLE_BODY,
2813
- children: headerTitle
2814
- }), /*#__PURE__*/jsx(CloseButton, {
2815
- onClick: onClose
2816
- })]
2817
- }), children && /*#__PURE__*/jsx("div", {
2818
- className: classNames('np-drawer-content'),
2819
- children: children
2820
- }), footerContent && /*#__PURE__*/jsx("div", {
2821
- className: classNames('np-drawer-footer'),
2822
- children: footerContent
2823
- })]
2824
- })
2825
- })
2826
- });
2827
- };
2828
- Drawer.propTypes = {
2829
- /** The content to appear in the drawer body. */
2830
- children: PropTypes.node,
2831
- className: PropTypes.string,
2832
- /** The content to appear in the drawer footer. */
2833
- footerContent: PropTypes.node,
2834
- /** The content to appear in the drawer header. */
2835
- headerTitle: PropTypes.node,
2836
- /** The status of Drawer either open or not. */
2837
- open: PropTypes.bool,
2838
- /** The placement of Drawer on the screen either left or right. On mobile it will default to bottom. */
2839
- position: PropTypes.oneOf(['left', 'right', 'bottom']),
2840
- /** The action to perform on close click. */
2841
- onClose: PropTypes.func
2842
- };
2843
- Drawer.defaultProps = {
2844
- children: null,
2845
- className: undefined,
2846
- footerContent: null,
2847
- headerTitle: null,
2848
- onClose: null,
2849
- open: false,
2850
- position: Position.RIGHT
2851
- };
2852
- var Drawer$1 = Drawer;
2853
-
2854
- const INITIAL_Y_POSITION = 0;
2855
- const CONTENT_SCROLL_THRESHOLD = 1;
2856
- const MOVE_OFFSET_THRESHOLD = 50;
2857
- /**
2858
- * Neptune: https://transferwise.github.io/neptune/components/bottom-sheet/
2859
- *
2860
- * Neptune Web: https://transferwise.github.io/neptune-web/components/overlays/BottomSheet
2861
- *
2862
- */
2863
- const BottomSheet$1 = props => {
2864
- const bottomSheetReference = useRef(null);
2865
- const topBarReference = useRef(null);
2866
- const contentReference = useRef(null);
2867
- const [pressed, setPressed] = useState(false);
2868
- /**
2869
- * Used to track `requestAnimationFrame` requests
2870
- *
2871
- * @see https://developer.mozilla.org/en-US/docs/Web/API/window/requestAnimationFrame#return_value
2872
- */
2873
- const animationId = useRef(0);
2874
- /**
2875
- * Difference between initial coordinate ({@link initialYCoordinate})
2876
- * and new position (when user moves component), it's get calculated on `onTouchMove` and `onMouseMove` events
2877
- *
2878
- * @see {@link calculateOffsetAfterMove}
2879
- */
2880
- const moveOffset = useRef(0);
2881
- const initialYCoordinate = useRef(0);
2882
- // apply shadow to the bottom of top-bar when scroll over content
2883
- useConditionalListener({
2884
- attachListener: props.open && !isServerSide(),
2885
- callback: () => {
2886
- if (topBarReference.current !== null) {
2887
- const {
2888
- classList
2889
- } = topBarReference.current;
2890
- if (!isContentScrollPositionAtTop()) {
2891
- classList.add('np-bottom-sheet--top-bar--shadow');
2892
- } else {
2893
- classList.remove('np-bottom-sheet--top-bar--shadow');
2894
- }
2895
- }
2896
- },
2897
- eventType: 'scroll',
2898
- parent: isServerSide() ? undefined : document
2899
- });
2900
- function move(newHeight) {
2901
- if (bottomSheetReference.current !== null) {
2902
- bottomSheetReference.current.style.transform = `translateY(${newHeight}px)`;
2903
- }
2904
- }
2905
- function close(event) {
2906
- setPressed(false);
2907
- moveOffset.current = INITIAL_Y_POSITION;
2908
- if (bottomSheetReference.current !== null) {
2909
- bottomSheetReference.current.style.removeProperty('transform');
2910
- }
2911
- if (props.onClose) {
2912
- props.onClose(event);
2913
- }
2914
- }
2915
- const onSwipeStart = event => {
2916
- initialYCoordinate.current = ('touches' in event ? event.touches[0] : event).clientY;
2917
- setPressed(true);
2918
- };
2919
- const onSwipeMove = event => {
2920
- if (pressed) {
2921
- const {
2922
- clientY
2923
- } = 'touches' in event ? event.touches[0] : event;
2924
- const offset = calculateOffsetAfterMove(clientY);
2925
- // check whether move is to the bottom only and content scroll position is at the top
2926
- if (offset > INITIAL_Y_POSITION && isContentScrollPositionAtTop()) {
2927
- moveOffset.current = offset;
2928
- animationId.current = requestAnimationFrame(() => {
2929
- if (animationId.current !== undefined && bottomSheetReference.current !== null) {
2930
- move(offset);
2931
- }
2932
- });
2933
- }
2934
- }
3330
+ const intl = useIntl();
3331
+ const isSelected = value => Array.isArray(selected) ? selected.includes(value) : selected === value;
3332
+ const handleOnChange = (selectedValue, isCurrentlyEnabled) => {
3333
+ onChange({
3334
+ isEnabled: !isCurrentlyEnabled,
3335
+ selectedValue
3336
+ });
2935
3337
  };
2936
- function onSwipeEnd(event) {
2937
- // stop moving component
2938
- cancelAnimationFrame(animationId.current);
2939
- setPressed(false);
2940
- // check whether move down is strong enough
2941
- // and content scroll position is at the top to close the component
2942
- if (moveOffset.current > MOVE_OFFSET_THRESHOLD && isContentScrollPositionAtTop()) {
2943
- close(event);
2944
- }
2945
- // otherwise move component back to default (initial) position
2946
- else {
2947
- move(INITIAL_Y_POSITION);
2948
- }
2949
- moveOffset.current = INITIAL_Y_POSITION;
2950
- }
2951
- function isContentScrollPositionAtTop() {
2952
- return contentReference?.current?.scrollTop !== undefined && contentReference.current.scrollTop <= CONTENT_SCROLL_THRESHOLD;
2953
- }
2954
- /**
2955
- * Calculates how hard user moves component,
2956
- * result value used to determine whether to hide component or re-position to default state
2957
- *
2958
- * @param afterMoveYCoordinate
2959
- */
2960
- function calculateOffsetAfterMove(afterMoveYCoordinate) {
2961
- return afterMoveYCoordinate - initialYCoordinate.current;
2962
- }
2963
- /**
2964
- * Set `max-height` for content part (in order to keep it scrollable for content overflow cases) of the component
2965
- * and ensures space for safe zone (32px) at the top.
2966
- */
2967
- function setContentMaxHeight() {
2968
- const safeZoneHeight = '64px';
2969
- const topbarHeight = '32px';
2970
- const windowHight = isServerSide() ? 0 : window.innerHeight;
2971
- /**
2972
- * Calculate _real_ height of the screen (taking into account parts of browser interface).
2973
- *
2974
- * See https://css-tricks.com/the-trick-to-viewport-units-on-mobile for more details.
2975
- */
2976
- const screenHeight = `${windowHight * 0.01 * 100}px`;
2977
- return {
2978
- maxHeight: `calc(${screenHeight} - ${safeZoneHeight} - ${topbarHeight})`
2979
- };
2980
- }
2981
- const is400Zoom = useMedia(`(max-width: ${Breakpoint.ZOOM_400}px)`);
2982
- return is400Zoom ? /*#__PURE__*/jsx(Drawer$1, {
2983
- open: props.open,
2984
- className: props.className,
2985
- onClose: close,
2986
- children: props.children
2987
- }) : /*#__PURE__*/jsx(Dimmer$1, {
2988
- open: props.open,
2989
- fadeContentOnEnter: true,
2990
- fadeContentOnExit: true,
2991
- onClose: close,
2992
- children: /*#__PURE__*/jsx(SlidingPanel, {
2993
- ref: bottomSheetReference,
2994
- open: props.open,
2995
- position: Position.BOTTOM,
2996
- className: classNames('np-bottom-sheet', props.className),
2997
- children: /*#__PURE__*/jsxs("div", {
2998
- role: "dialog",
2999
- "aria-modal": true,
3000
- onTouchStart: onSwipeStart,
3001
- onTouchMove: onSwipeMove,
3002
- onTouchEnd: onSwipeEnd,
3003
- onMouseDown: onSwipeStart,
3004
- onMouseMove: onSwipeMove,
3005
- onMouseUp: onSwipeEnd,
3006
- children: [/*#__PURE__*/jsxs("div", {
3007
- ref: topBarReference,
3008
- className: "np-bottom-sheet--top-bar",
3009
- children: [/*#__PURE__*/jsx("div", {
3010
- className: "np-bottom-sheet--handler"
3011
- }), /*#__PURE__*/jsx(CloseButton, {
3012
- size: "sm",
3013
- className: "sr-only np-bottom-sheet--close-btn",
3014
- onClick: close
3015
- })]
3016
- }), /*#__PURE__*/jsx("div", {
3017
- ref: contentReference,
3018
- style: setContentMaxHeight(),
3019
- className: "np-bottom-sheet--content",
3020
- children: props.children
3021
- })]
3022
- })
3338
+ return /*#__PURE__*/jsx("div", {
3339
+ className: classNames('np-chips d-flex', className),
3340
+ "aria-label": ariaLabel,
3341
+ role: !multiple ? 'radiogroup' : undefined,
3342
+ children: chips.map(chip => {
3343
+ const chipSelected = isSelected(chip.value);
3344
+ return /*#__PURE__*/jsx(Chip, {
3345
+ value: chip.value,
3346
+ label: chip.label,
3347
+ closeButton: {
3348
+ 'aria-label': intl.formatMessage(messages$a.ariaLabel, {
3349
+ choice: chip.label
3350
+ })
3351
+ },
3352
+ className: classNames('text-xs-nowrap', {
3353
+ 'np-chip--selected': chipSelected,
3354
+ 'p-r-1': multiple && chipSelected
3355
+ }),
3356
+ ...(multiple && chipSelected ? {
3357
+ onRemove: () => handleOnChange(chip.value, chipSelected),
3358
+ 'aria-label': chip.label
3359
+ } : {
3360
+ onClick: () => handleOnChange(chip.value, chipSelected),
3361
+ onKeyPress: () => handleOnChange(chip.value, chipSelected),
3362
+ role: !multiple ? 'radio' : undefined,
3363
+ 'aria-checked': chipSelected
3364
+ })
3365
+ }, chip.value);
3023
3366
  })
3024
3367
  });
3025
3368
  };
3026
3369
 
3370
+ const CircularButton = ({
3371
+ className,
3372
+ children,
3373
+ disabled,
3374
+ icon,
3375
+ priority = Priority.PRIMARY,
3376
+ type = ControlType.ACCENT,
3377
+ ...rest
3378
+ }) => {
3379
+ const classes = classNames('btn np-btn', typeClassMap[type], priorityClassMap[priority]);
3380
+ const iconElement = Number(icon.props.size) !== 24 ? /*#__PURE__*/cloneElement(icon, {
3381
+ size: 24
3382
+ }) : icon;
3383
+ return /*#__PURE__*/jsxs("label", {
3384
+ className: classNames('np-circular-btn', priority, type, disabled && 'disabled', className),
3385
+ children: [/*#__PURE__*/jsx("input", {
3386
+ type: "button",
3387
+ "aria-label": children,
3388
+ className: classes,
3389
+ disabled: disabled,
3390
+ ...rest
3391
+ }), iconElement, /*#__PURE__*/jsx(Body, {
3392
+ as: "span",
3393
+ className: "np-circular-btn__label",
3394
+ type: Typography.BODY_DEFAULT_BOLD,
3395
+ children: children
3396
+ })]
3397
+ });
3398
+ };
3399
+
3027
3400
  function CriticalCommsBanner({
3028
3401
  title,
3029
3402
  subtitle,
@@ -3137,36 +3510,6 @@ const isMonthAndYearFormat = dateString => validDateString(dateString) && dateSt
3137
3510
  const MDY = new Set(['en-US']);
3138
3511
  const YMD = new Set(['hu', 'hu-HU', 'zh-HK', 'zh-CN', 'ja', 'ja-JP']);
3139
3512
 
3140
- const FieldLabelIdContext = /*#__PURE__*/createContext(undefined);
3141
- const FieldLabelIdContextProvider = FieldLabelIdContext.Provider;
3142
- const InputIdContext = /*#__PURE__*/createContext(undefined);
3143
- const InputIdContextProvider = InputIdContext.Provider;
3144
- const InputDescribedByContext = /*#__PURE__*/createContext(undefined);
3145
- const InputDescribedByProvider = InputDescribedByContext.Provider;
3146
- const InputInvalidContext = /*#__PURE__*/createContext(undefined);
3147
- const InputInvalidProvider = InputInvalidContext.Provider;
3148
- function useInputAttributes({
3149
- nonLabelable
3150
- } = {}) {
3151
- const labelId = useContext(FieldLabelIdContext);
3152
- return {
3153
- id: useContext(InputIdContext),
3154
- 'aria-labelledby': nonLabelable ? labelId : undefined,
3155
- 'aria-describedby': useContext(InputDescribedByContext),
3156
- 'aria-invalid': useContext(InputInvalidContext)
3157
- };
3158
- }
3159
- function withInputAttributes(Component, args) {
3160
- function ComponentWithInputAttributes(props) {
3161
- return /*#__PURE__*/jsx(Component, {
3162
- inputAttributes: useInputAttributes(args),
3163
- ...props
3164
- });
3165
- }
3166
- ComponentWithInputAttributes.displayName = `withInputAttributes(${Component.displayName || Component.name || 'Component'})`;
3167
- return ComponentWithInputAttributes;
3168
- }
3169
-
3170
3513
  var messages$9 = defineMessages({
3171
3514
  monthLabel: {
3172
3515
  id: "neptune.DateInput.month.label"
@@ -3412,214 +3755,96 @@ const DateInput = ({
3412
3755
  onChange: event => handleDayChange(event)
3413
3756
  })
3414
3757
  })]
3415
- })
3416
- });
3417
- };
3418
- const getYear = () => {
3419
- return /*#__PURE__*/jsx("div", {
3420
- className: "col-sm-4",
3421
- children: /*#__PURE__*/jsxs("label", {
3422
- children: [/*#__PURE__*/jsx("span", {
3423
- className: "sr-only",
3424
- children: yearLabel
3425
- }), /*#__PURE__*/jsx("div", {
3426
- className: `input-group input-group-${size}`,
3427
- children: /*#__PURE__*/jsx(Input, {
3428
- type: "text",
3429
- inputMode: "numeric",
3430
- pattern: "[0-9]*",
3431
- name: "year",
3432
- autoComplete: yearAutoComplete,
3433
- placeholder: placeholders?.year,
3434
- value: year || '',
3435
- disabled: disabled,
3436
- min: 1,
3437
- onChange: event => handleYearChange(event)
3438
- })
3439
- })]
3440
- })
3441
- });
3442
- };
3443
- const monthBeforeDay = MDY.has(locale);
3444
- const yearFirst = YMD.has(locale);
3445
- return /*#__PURE__*/jsx("div", {
3446
- className: "tw-date",
3447
- ...inputAttributes,
3448
- id: id,
3449
- "aria-labelledby": ariaLabelledBy,
3450
- "aria-label": ariaLabel,
3451
- role: "group" // Add role attribute to indicate container for interactive elements
3452
- ,
3453
- onFocus: event => shouldPropagateOnFocus(event) ? onFocus && onFocus(event) : event.stopPropagation(),
3454
- onBlur: event => shouldPropagateOnBlur(event) ? onBlur && onBlur(event) : event.stopPropagation(),
3455
- children: /*#__PURE__*/jsx("div", {
3456
- className: "row",
3457
- children: (() => {
3458
- if (monthYearOnly) {
3459
- return /*#__PURE__*/jsxs(Fragment, {
3460
- children: [!yearFirst && getMonth(), getYear(), yearFirst && getMonth()]
3461
- });
3462
- }
3463
- if (monthBeforeDay) {
3464
- return /*#__PURE__*/jsxs(Fragment, {
3465
- children: [getMonth(), getDay(), getYear()]
3466
- });
3467
- }
3468
- if (yearFirst) {
3469
- return /*#__PURE__*/jsxs(Fragment, {
3470
- children: [getYear(), getMonth(), getDay()]
3471
- });
3472
- }
3473
- return /*#__PURE__*/jsxs(Fragment, {
3474
- children: [getDay(), getMonth(), getYear()]
3475
- });
3476
- })()
3477
- })
3478
- });
3479
- };
3480
- // Should only propagate if the relatedTarget is not part of this DateInput component.
3481
- function shouldPropagateOnFocus({
3482
- target,
3483
- relatedTarget
3484
- }) {
3485
- const targetParent = target.closest('.tw-date');
3486
- const relatedParent = relatedTarget && relatedTarget.closest('.tw-date');
3487
- return targetParent !== relatedParent;
3488
- }
3489
- // Should only propagate if the relatedTarget or the activeElement is not part of this DateInput component.
3490
- function shouldPropagateOnBlur({
3491
- target,
3492
- relatedTarget
3493
- }) {
3494
- const blurElementParent = target.closest('.tw-date');
3495
- // Even though FocusEvent.relatedTarget is supported by IE
3496
- // (https://developer.mozilla.org/en-US/docs/Web/API/FocusEvent/relatedTarget)
3497
- // "IE11 sets document.activeElement to the next focused element before the blur event is called."
3498
- // (https://stackoverflow.com/a/49325196/986241)
3499
- // Therefore if the relatedTarget is null, we try the document.activeElement,
3500
- // which may contain the HTML element that is gaining focus
3501
- const focusElement = relatedTarget || (document.activeElement !== target ? document.activeElement : null);
3502
- const focusElementParent = focusElement && focusElement.closest('.tw-date');
3503
- return blurElementParent !== focusElementParent;
3504
- }
3505
-
3506
- const POPOVER_OFFSET = [0, 16];
3507
- // By default the flip positioning explores only the opposite alternative. So if left is passed and there's no enough space
3508
- // the right one gets chosen. If there's no space on both sides popover goes back to the initially chosen one left.
3509
- // This mapping forces popover to try the four available positions before going back to the initial chosen one.
3510
- const fallbackPlacements = {
3511
- [Position.TOP]: [Position.BOTTOM, Position.RIGHT, Position.LEFT],
3512
- [Position.BOTTOM]: [Position.TOP, Position.RIGHT, Position.LEFT],
3513
- [Position.LEFT]: [Position.RIGHT, Position.TOP, Position.BOTTOM],
3514
- [Position.RIGHT]: [Position.LEFT, Position.TOP, Position.BOTTOM]
3515
- };
3516
- const Panel = /*#__PURE__*/forwardRef(function Panel({
3517
- arrow = false,
3518
- flip = true,
3519
- altAxis = false,
3520
- children,
3521
- open = false,
3522
- onClose,
3523
- position = Position.BOTTOM,
3524
- anchorRef,
3525
- anchorWidth = false,
3526
- ...rest
3527
- }, reference) {
3528
- const [arrowElement, setArrowElement] = useState(null);
3529
- const [popperElement, setPopperElement] = useState(null);
3530
- const modifiers = [];
3531
- if (altAxis) {
3532
- modifiers.push({
3533
- // https://popper.js.org/docs/v2/modifiers/prevent-overflow
3534
- name: 'preventOverflow',
3535
- options: {
3536
- altAxis: true,
3537
- tether: false
3538
- }
3539
- });
3540
- }
3541
- if (arrow) {
3542
- modifiers.push({
3543
- name: 'arrow',
3544
- options: {
3545
- element: arrowElement,
3546
- options: {
3547
- padding: 8 // 8px from the edges of the popper
3548
- }
3549
- }
3550
- });
3551
- // This lets you displace a popper element from its reference element.
3552
- modifiers.push({
3553
- name: 'offset',
3554
- options: {
3555
- offset: POPOVER_OFFSET
3556
- }
3557
- });
3558
- }
3559
- if (flip && fallbackPlacements[position]) {
3560
- modifiers.push({
3561
- name: 'flip',
3562
- options: {
3563
- fallbackPlacements: fallbackPlacements[position]
3564
- }
3565
- });
3566
- }
3567
- const {
3568
- styles,
3569
- attributes,
3570
- forceUpdate
3571
- } = usePopper(anchorRef.current, popperElement, {
3572
- placement: position,
3573
- modifiers
3574
- });
3575
- // If the trigger is not visible when the position is calculated, it will be incorrect. Because this can happen repeatedly (on resize for example),
3576
- // it is most simple just to always position before opening
3577
- useEffect(() => {
3578
- if (open && forceUpdate) {
3579
- forceUpdate();
3580
- }
3581
- }, [open]);
3582
- const contentStyle = {
3583
- ...(anchorWidth ? {
3584
- width: anchorRef.current?.clientWidth
3585
- } : undefined)
3758
+ })
3759
+ });
3586
3760
  };
3587
- return /*#__PURE__*/jsx(Dimmer$1, {
3588
- open: open,
3589
- transparent: true,
3590
- fadeContentOnEnter: true,
3591
- fadeContentOnExit: true,
3592
- onClose: onClose,
3593
- children: /*#__PURE__*/jsx("div", {
3594
- ...rest,
3595
- ref: setPopperElement,
3596
- role: "dialog"
3597
- // eslint-disable-next-line react/forbid-dom-props
3598
- ,
3599
- style: {
3600
- ...styles.popper
3601
- },
3602
- ...attributes.popper,
3603
- className: classNames('np-panel', {
3604
- 'np-panel--open': open
3605
- }, rest.className),
3606
- children: /*#__PURE__*/jsxs("div", {
3607
- ref: reference
3608
- /* eslint-disable-next-line react/forbid-dom-props */,
3609
- style: contentStyle,
3610
- className: classNames('np-panel__content'),
3611
- children: [children, arrow && /*#__PURE__*/jsx("div", {
3612
- ref: setArrowElement,
3613
- className: classNames('np-panel__arrow')
3614
- // eslint-disable-next-line react/forbid-dom-props
3615
- ,
3616
- style: styles.arrow
3761
+ const getYear = () => {
3762
+ return /*#__PURE__*/jsx("div", {
3763
+ className: "col-sm-4",
3764
+ children: /*#__PURE__*/jsxs("label", {
3765
+ children: [/*#__PURE__*/jsx("span", {
3766
+ className: "sr-only",
3767
+ children: yearLabel
3768
+ }), /*#__PURE__*/jsx("div", {
3769
+ className: `input-group input-group-${size}`,
3770
+ children: /*#__PURE__*/jsx(Input, {
3771
+ type: "text",
3772
+ inputMode: "numeric",
3773
+ pattern: "[0-9]*",
3774
+ name: "year",
3775
+ autoComplete: yearAutoComplete,
3776
+ placeholder: placeholders?.year,
3777
+ value: year || '',
3778
+ disabled: disabled,
3779
+ min: 1,
3780
+ onChange: event => handleYearChange(event)
3781
+ })
3617
3782
  })]
3618
3783
  })
3784
+ });
3785
+ };
3786
+ const monthBeforeDay = MDY.has(locale);
3787
+ const yearFirst = YMD.has(locale);
3788
+ return /*#__PURE__*/jsx("div", {
3789
+ className: "tw-date",
3790
+ ...inputAttributes,
3791
+ id: id,
3792
+ "aria-labelledby": ariaLabelledBy,
3793
+ "aria-label": ariaLabel,
3794
+ role: "group" // Add role attribute to indicate container for interactive elements
3795
+ ,
3796
+ onFocus: event => shouldPropagateOnFocus(event) ? onFocus && onFocus(event) : event.stopPropagation(),
3797
+ onBlur: event => shouldPropagateOnBlur(event) ? onBlur && onBlur(event) : event.stopPropagation(),
3798
+ children: /*#__PURE__*/jsx("div", {
3799
+ className: "row",
3800
+ children: (() => {
3801
+ if (monthYearOnly) {
3802
+ return /*#__PURE__*/jsxs(Fragment, {
3803
+ children: [!yearFirst && getMonth(), getYear(), yearFirst && getMonth()]
3804
+ });
3805
+ }
3806
+ if (monthBeforeDay) {
3807
+ return /*#__PURE__*/jsxs(Fragment, {
3808
+ children: [getMonth(), getDay(), getYear()]
3809
+ });
3810
+ }
3811
+ if (yearFirst) {
3812
+ return /*#__PURE__*/jsxs(Fragment, {
3813
+ children: [getYear(), getMonth(), getDay()]
3814
+ });
3815
+ }
3816
+ return /*#__PURE__*/jsxs(Fragment, {
3817
+ children: [getDay(), getMonth(), getYear()]
3818
+ });
3819
+ })()
3619
3820
  })
3620
3821
  });
3621
- });
3622
- var Panel$1 = Panel;
3822
+ };
3823
+ // Should only propagate if the relatedTarget is not part of this DateInput component.
3824
+ function shouldPropagateOnFocus({
3825
+ target,
3826
+ relatedTarget
3827
+ }) {
3828
+ const targetParent = target.closest('.tw-date');
3829
+ const relatedParent = relatedTarget && relatedTarget.closest('.tw-date');
3830
+ return targetParent !== relatedParent;
3831
+ }
3832
+ // Should only propagate if the relatedTarget or the activeElement is not part of this DateInput component.
3833
+ function shouldPropagateOnBlur({
3834
+ target,
3835
+ relatedTarget
3836
+ }) {
3837
+ const blurElementParent = target.closest('.tw-date');
3838
+ // Even though FocusEvent.relatedTarget is supported by IE
3839
+ // (https://developer.mozilla.org/en-US/docs/Web/API/FocusEvent/relatedTarget)
3840
+ // "IE11 sets document.activeElement to the next focused element before the blur event is called."
3841
+ // (https://stackoverflow.com/a/49325196/986241)
3842
+ // Therefore if the relatedTarget is null, we try the document.activeElement,
3843
+ // which may contain the HTML element that is gaining focus
3844
+ const focusElement = relatedTarget || (document.activeElement !== target ? document.activeElement : null);
3845
+ const focusElementParent = focusElement && focusElement.closest('.tw-date');
3846
+ return blurElementParent !== focusElementParent;
3847
+ }
3623
3848
 
3624
3849
  const ResponsivePanel = /*#__PURE__*/forwardRef(function ResponsivePanel({
3625
3850
  anchorRef,
@@ -3642,7 +3867,7 @@ const ResponsivePanel = /*#__PURE__*/forwardRef(function ResponsivePanel({
3642
3867
  children: children
3643
3868
  }, "bottomSheet");
3644
3869
  }
3645
- return /*#__PURE__*/jsx(Panel$1, {
3870
+ return /*#__PURE__*/jsx(Panel, {
3646
3871
  ref: reference,
3647
3872
  flip: flip,
3648
3873
  arrow: arrow,
@@ -4617,39 +4842,6 @@ var DateLookup$1 = withInputAttributes(DateLookup, {
4617
4842
  nonLabelable: true
4618
4843
  });
4619
4844
 
4620
- const NavigationOption = /*#__PURE__*/forwardRef(({
4621
- as: component = 'button',
4622
- disabled = false,
4623
- onClick,
4624
- className,
4625
- ...rest
4626
- }, reference) => {
4627
- if ('href' in rest && rest.href) {
4628
- component = 'a';
4629
- }
4630
- return /*#__PURE__*/jsx(Option$2, {
4631
- ...rest,
4632
- ref: reference,
4633
- as: component,
4634
- className: classNames('np-navigation-option', className),
4635
- button: /*#__PURE__*/jsx(Chevron, {
4636
- orientation: Position.RIGHT,
4637
- disabled: disabled,
4638
- className: "d-block"
4639
- }),
4640
- disabled: disabled,
4641
- onClick: event => {
4642
- if (disabled) {
4643
- event.preventDefault();
4644
- return;
4645
- }
4646
- if (onClick) {
4647
- onClick(event);
4648
- }
4649
- }
4650
- });
4651
- });
4652
-
4653
4845
  const Tile = ({
4654
4846
  className,
4655
4847
  description,
@@ -5524,73 +5716,6 @@ const FlowNavigation = ({
5524
5716
  });
5525
5717
  };
5526
5718
 
5527
- const HeaderAction = ({
5528
- action
5529
- }) => {
5530
- const {
5531
- isModern
5532
- } = useTheme();
5533
- const props = {
5534
- 'aria-label': action['aria-label']
5535
- };
5536
- if ('href' in action) {
5537
- return /*#__PURE__*/jsx(Link, {
5538
- href: action.href,
5539
- target: action.target,
5540
- onClick: action.onClick,
5541
- ...props,
5542
- children: action.text
5543
- });
5544
- }
5545
- return isModern ? /*#__PURE__*/jsx(Button, {
5546
- className: "np-header__button",
5547
- priority: "tertiary",
5548
- size: "sm",
5549
- onClick: action.onClick,
5550
- ...props,
5551
- children: action.text
5552
- }) : /*#__PURE__*/jsx(ActionButton, {
5553
- onClick: action.onClick,
5554
- ...props,
5555
- children: action.text
5556
- });
5557
- };
5558
- /**
5559
- *
5560
- * Neptune Web: https://transferwise.github.io/neptune-web/components/content/Header
5561
- *
5562
- */
5563
- const Header = ({
5564
- action,
5565
- as = 'h5',
5566
- title,
5567
- className
5568
- }) => {
5569
- if (!action) {
5570
- return /*#__PURE__*/jsx(Title, {
5571
- as: as,
5572
- type: Typography.TITLE_GROUP,
5573
- className: classNames('np-header', 'np-header__title', className),
5574
- children: title
5575
- });
5576
- }
5577
- if (as === 'legend') {
5578
- // eslint-disable-next-line no-console
5579
- console.warn('Legends should be the first child in a fieldset, and this is not possible when including an action');
5580
- }
5581
- return /*#__PURE__*/jsxs("div", {
5582
- className: classNames('np-header', className),
5583
- children: [/*#__PURE__*/jsx(Title, {
5584
- as: as,
5585
- type: Typography.TITLE_GROUP,
5586
- className: "np-header__title",
5587
- children: title
5588
- }), /*#__PURE__*/jsx(HeaderAction, {
5589
- action: action
5590
- })]
5591
- });
5592
- };
5593
-
5594
5719
  // TODO: consider to move this enum into component file once we migrate it on TypeScript or replace with some common enum
5595
5720
  var InfoPresentation;
5596
5721
  (function (InfoPresentation) {
@@ -7759,18 +7884,6 @@ var MoneyInput$1 = injectIntl(withInputAttributes(MoneyInput, {
7759
7884
  nonLabelable: true
7760
7885
  }));
7761
7886
 
7762
- const NavigationOptionList = ({
7763
- children
7764
- }) => {
7765
- return /*#__PURE__*/jsx("ul", {
7766
- className: "np-navigation-options-list",
7767
- children: Children.map(children, child => /*#__PURE__*/jsx("li", {
7768
- className: "np-navigation-options-list__item",
7769
- children: child
7770
- }, child?.toString()))
7771
- });
7772
- };
7773
-
7774
7887
  const STORAGE_NAME = 'dismissedNudges';
7775
7888
  const getLocalStorage = () => {
7776
7889
  try {
@@ -9567,6 +9680,7 @@ var en = {
9567
9680
  "neptune.PhoneNumberInput.SelectInput.placeholder": "Select an option...",
9568
9681
  "neptune.Select.searchPlaceholder": "Search...",
9569
9682
  "neptune.SelectInput.noResultsFound": "No results found",
9683
+ "neptune.SelectOption.action.label": "Choose",
9570
9684
  "neptune.Summary.statusDone": "Item done",
9571
9685
  "neptune.Summary.statusNotDone": "Item to do",
9572
9686
  "neptune.Summary.statusPending": "Item pending",
@@ -9794,19 +9908,6 @@ function RadioOption({
9794
9908
  });
9795
9909
  }
9796
9910
 
9797
- const Section = ({
9798
- children,
9799
- className,
9800
- withHorizontalPadding = false
9801
- }) => {
9802
- return /*#__PURE__*/jsx("div", {
9803
- className: classNames('np-section', className, {
9804
- 'np-section--with-horizontal-padding': withHorizontalPadding
9805
- }),
9806
- children: children
9807
- });
9808
- };
9809
-
9810
9911
  const SegmentedControl = ({
9811
9912
  name,
9812
9913
  value,
@@ -10460,7 +10561,7 @@ function Select({
10460
10561
  children: renderOptionsList({
10461
10562
  className: isModern ? '' : 'p-a-1'
10462
10563
  })
10463
- }) : /*#__PURE__*/jsx(Panel$1, {
10564
+ }) : /*#__PURE__*/jsx(Panel, {
10464
10565
  open: open,
10465
10566
  flip: false,
10466
10567
  altAxis: true,
@@ -10710,19 +10811,21 @@ function SnackbarProvider({
10710
10811
  });
10711
10812
  }
10712
10813
 
10713
- function Sticky({
10814
+ const Sticky = ({
10714
10815
  open = true,
10715
- position = 'bottom',
10716
- children
10717
- }) {
10816
+ position = Position.BOTTOM,
10817
+ children,
10818
+ testId
10819
+ }) => {
10718
10820
  return /*#__PURE__*/jsx(SlidingPanel, {
10821
+ testId: testId,
10719
10822
  open: open,
10720
10823
  position: position,
10721
10824
  slidingPanelPositionFixed: true,
10722
10825
  showSlidingPanelBorder: true,
10723
10826
  children: children
10724
10827
  });
10725
- }
10828
+ };
10726
10829
 
10727
10830
  var messages$1 = defineMessages({
10728
10831
  statusNotDone: {
@@ -13363,7 +13466,6 @@ const UploadItem = ({
13363
13466
  status,
13364
13467
  filename,
13365
13468
  error,
13366
- errors,
13367
13469
  url
13368
13470
  } = file;
13369
13471
  const {
@@ -13371,7 +13473,7 @@ const UploadItem = ({
13371
13473
  } = useTheme();
13372
13474
  const isSucceeded = [Status.SUCCEEDED, undefined].includes(status) && !!url;
13373
13475
  const getIcon = () => {
13374
- if (error || errors?.length || status === Status.FAILED) {
13476
+ if (error || status === Status.FAILED) {
13375
13477
  return isModern ? /*#__PURE__*/jsx(StatusIcon, {
13376
13478
  size: Size.SMALL,
13377
13479
  sentiment: Sentiment.NEGATIVE
@@ -13410,30 +13512,13 @@ const UploadItem = ({
13410
13512
  children: processIndicator
13411
13513
  }); // Scale down ProcessIndicator to be 20px*20px to match `icons`
13412
13514
  };
13413
- const getErrorMessage = error => typeof error === 'object' ? error.message : error || formatMessage(MESSAGES.uploadingFailed);
13414
- const getMultipleErrors = errors => {
13415
- if (!errors?.length) {
13416
- return null;
13417
- }
13418
- if (errors?.length === 1) {
13419
- return getErrorMessage(errors[0]);
13420
- }
13421
- return /*#__PURE__*/jsx("ul", {
13422
- className: "np-upload-input-errors m-b-0",
13423
- children: errors.map((error, index) => {
13424
- // eslint-disable-next-line react/no-array-index-key
13425
- return /*#__PURE__*/jsx("li", {
13426
- children: getErrorMessage(error)
13427
- }, index);
13428
- })
13429
- });
13430
- };
13515
+ const getErrorMessage = () => typeof error === 'object' ? error.message : error || formatMessage(MESSAGES.uploadingFailed);
13431
13516
  const getDescription = () => {
13432
- if (error || errors?.length || status === Status.FAILED) {
13517
+ if (error || status === Status.FAILED) {
13433
13518
  return /*#__PURE__*/jsx(Body, {
13434
13519
  type: Typography.BODY_DEFAULT_BOLD,
13435
13520
  className: "text-negative",
13436
- children: errors?.length ? getMultipleErrors(errors) : getErrorMessage(error)
13521
+ children: getErrorMessage()
13437
13522
  });
13438
13523
  }
13439
13524
  switch (status) {
@@ -14764,5 +14849,5 @@ const translations = {
14764
14849
  'zh-HK': zhHK
14765
14850
  };
14766
14851
 
14767
- export { Accordion, ActionButton, ActionOption, Alert, AlertArrowPosition, Avatar, AvatarType, AvatarWrapper, Badge, Card$2 as BaseCard, Body, BottomSheet$1 as BottomSheet, Breakpoint, Button, Card$1 as Card, Carousel, 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, 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$1 as Typeahead, Typography, Upload$1 as Upload, UploadInput, UploadStep, Variant, Width, adjustLocale, getCountryFromLocale, getDirectionFromLocale, getLangFromLocale, isBrowser, isServerSide, translations, useDirection, useLayout, useScreenSize, useSnackbar };
14852
+ export { Accordion, ActionButton, ActionOption, Alert, AlertArrowPosition, Avatar, AvatarType, AvatarWrapper, Badge, Card$2 as BaseCard, Body, BottomSheet$1 as BottomSheet, Breakpoint, Button, Card$1 as Card, Carousel, 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, 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$1 as Typeahead, Typography, Upload$1 as Upload, UploadInput, UploadStep, Variant, Width, adjustLocale, getCountryFromLocale, getDirectionFromLocale, getLangFromLocale, isBrowser, isServerSide, translations, useDirection, useLayout, useScreenSize, useSnackbar };
14768
14853
  //# sourceMappingURL=index.mjs.map