@transferwise/components 0.0.0-experimental-09f7900 → 0.0.0-experimental-0985009

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