@transferwise/components 0.0.0-experimental-ef7ebdb → 0.0.0-experimental-dbd40fc

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.
@@ -43,7 +43,7 @@ const getLocalStorage = () => {
43
43
  return storage.map(item => String(item));
44
44
  }
45
45
  }
46
- } catch {}
46
+ } catch (error) {}
47
47
  return [];
48
48
  };
49
49
  const Nudge = ({
@@ -60,15 +60,6 @@ const Nudge = ({
60
60
  action
61
61
  }) => {
62
62
  const intl = reactIntl.useIntl();
63
- const hasLegacyLink = Boolean(link);
64
- const hasAction = action != null;
65
- const shouldRenderLegacyLink = hasLegacyLink && !hasAction;
66
- React.useEffect(() => {
67
- if (process.env.NODE_ENV !== 'production' && hasAction && (hasLegacyLink || href != null)) {
68
- // eslint-disable-next-line no-console -- Intentional developer warning for conflicting API usage.
69
- console.warn('Nudge received both action and link/href props. Rendering action only. Remove link/href to silence this warning.');
70
- }
71
- }, [hasAction, hasLegacyLink, href]);
72
63
  const getIsDismissed = React.useCallback(() => persistDismissal && id ? !!getLocalStorage()?.find(item => item === id) : false, [persistDismissal, id]);
73
64
  const [nudgeState, setNudgeState] = React.useState(() => ({
74
65
  isDismissed: getIsDismissed(),
@@ -137,7 +128,7 @@ const Nudge = ({
137
128
  type: typography.Typography.BODY_LARGE,
138
129
  className: clsx.clsx('wds-nudge-body'),
139
130
  children: title
140
- }), shouldRenderLegacyLink && /*#__PURE__*/jsxRuntime.jsx(Link.default, {
131
+ }), link && /*#__PURE__*/jsxRuntime.jsx(Link.default, {
141
132
  href: href,
142
133
  type: typography.Typography.LINK_LARGE,
143
134
  className: "wds-nudge-link",
@@ -1 +1 @@
1
- {"version":3,"file":"Nudge.js","sources":["../../src/Nudge/Nudge.tsx"],"sourcesContent":["import { Illustration, Assets } from '@wise/art';\nimport { clsx } from 'clsx';\nimport { ReactNode, useEffect, useState, MouseEvent, useCallback } from 'react';\n\nimport Body from '../Body';\nimport { Typography } from '../common';\nimport Link from '../Link';\nimport type { AlertAction } from '../_deprecated/Alert';\nimport IconButton from '../IconButton';\nimport { Cross } from '@transferwise/icons';\nimport { useIntl } from 'react-intl';\nimport closeBtnMessages from '../common/CloseButton/CloseButton.messages';\n\n// WARNING: Changing this will cause nudges to reappear wherever persist nudge is used and privacy team will need to be updated too\nexport const STORAGE_NAME = 'dismissedNudges';\n\nconst getLocalStorage = (): string[] => {\n try {\n const storageItem = localStorage.getItem(STORAGE_NAME);\n\n if (storageItem) {\n const storage: unknown = JSON.parse(storageItem);\n\n if (Array.isArray(storage)) {\n return storage.map((item) => String(item));\n }\n }\n } catch {}\n\n return [];\n};\n\ntype MediaNameType =\n | `${Assets.GLOBE}`\n | `${Assets.LOCK}`\n | `${Assets.WALLET}`\n | `${Assets.GEAR}`\n | `${Assets.INVITE_LETTER}`\n | `${Assets.PERSONAL_CARD}`\n | `${Assets.BUSINESS_CARD}`\n | `${Assets.HEART}`\n | `${Assets.MULTI_CURRENCY}`\n | `${Assets.SHOPPING_BAG}`\n | `${Assets.FLOWER}`\n | `${Assets.GIFT_BOX}`\n | `${Assets.BACKPACK}`\n | `${Assets.DOCUMENTS}`;\n\ntype BaseProps = {\n /**\n * @deprecated Use `mediaName` instead.\n * Legacy custom media content is no longer used by `Nudge`.\n */\n media?: ReactNode;\n /**\n * Illustration asset name shown at the start of the nudge.\n */\n mediaName?: MediaNameType;\n /** Main nudge message content. */\n title: ReactNode;\n /**\n * Legacy CTA label content.\n * Rendered only when `action` is not provided.\n */\n link?: ReactNode;\n /**\n * Legacy CTA destination for `link`.\n * Ignored when `action` is provided.\n */\n href?: string;\n /**\n * Legacy click handler for `link`.\n * Ignored when `action` is provided.\n */\n onClick?: (event?: MouseEvent<HTMLSpanElement>) => void;\n /** Fired when the user clicks on close button */\n onDismiss?: () => void;\n /**\n * Preferred CTA configuration rendered under the nudge body.\n * Single CTA rule: when `action` is provided, legacy `link`/`href` is not rendered.\n * If your label is short, use `aria-label` to provide more context.\n */\n action?: AlertAction;\n /** Optional class name applied to the root nudge container. */\n className?: string;\n};\n\nexport interface OptionalId extends BaseProps {\n id?: string;\n persistDismissal?: false;\n isPreviouslyDismissed?: undefined;\n}\n\nexport interface RequiredPersistProps extends BaseProps {\n /** This ID should be completely unique to the page and feature as it uses a shared array which could conflict with other nudges in Wise */\n id: string;\n /** Use persist dismissal to keep the nudge dismissed using the browser's localStorage */\n persistDismissal: true;\n /**\n * Fired on mount for determining if nudge has been dismissed before\n *\n * @param {boolean} value - set to true if dismissed previously\n */\n isPreviouslyDismissed?: (value: boolean) => void;\n}\n\nexport type NudgeProps = OptionalId | RequiredPersistProps;\n\nconst Nudge = ({\n mediaName,\n title,\n link,\n href,\n onClick,\n onDismiss,\n persistDismissal,\n isPreviouslyDismissed,\n id,\n className,\n action,\n}: NudgeProps) => {\n const intl = useIntl();\n const hasLegacyLink = Boolean(link);\n const hasAction = action != null;\n const shouldRenderLegacyLink = hasLegacyLink && !hasAction;\n\n useEffect(() => {\n if (process.env.NODE_ENV !== 'production' && hasAction && (hasLegacyLink || href != null)) {\n // eslint-disable-next-line no-console -- Intentional developer warning for conflicting API usage.\n console.warn(\n 'Nudge received both action and link/href props. Rendering action only. Remove link/href to silence this warning.',\n );\n }\n }, [hasAction, hasLegacyLink, href]);\n\n const getIsDismissed = useCallback(\n () => (persistDismissal && id ? !!getLocalStorage()?.find((item) => item === id) : false),\n [persistDismissal, id],\n );\n\n const [nudgeState, setNudgeState] = useState(() => ({\n isDismissed: getIsDismissed(),\n isMounted: false,\n }));\n\n useEffect(() => {\n // eslint-disable-next-line react-hooks/set-state-in-effect -- Setting mount state in mount effect\n setNudgeState((prev) => ({ ...prev, isMounted: true }));\n }, []);\n\n useEffect(() => {\n // eslint-disable-next-line react-hooks/set-state-in-effect -- Syncing dismissed state from localStorage on prop change\n setNudgeState((prev) => ({ ...prev, isDismissed: getIsDismissed() }));\n }, [getIsDismissed, id, persistDismissal]);\n\n const { isDismissed } = nudgeState;\n\n const handleOnDismiss = () => {\n const dismissedNudgesStorage = getLocalStorage();\n\n if (persistDismissal && id) {\n try {\n localStorage.setItem(STORAGE_NAME, JSON.stringify([...dismissedNudgesStorage, id]));\n } catch {}\n\n setNudgeState((prev) => ({ ...prev, isDismissed: true }));\n }\n\n if (onDismiss) {\n onDismiss();\n }\n };\n\n useEffect(() => {\n if (persistDismissal && id && isPreviouslyDismissed) {\n const dismissedNudgesStorage = getLocalStorage();\n const wasDismissed = !!dismissedNudgesStorage?.find((item) => item === id);\n isPreviouslyDismissed(wasDismissed);\n }\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [id, persistDismissal]);\n\n if (persistDismissal && (isDismissed || !nudgeState.isMounted)) {\n return null;\n }\n\n return (\n <div className={clsx('wds-nudge', className)} id={id}>\n {!!mediaName && (\n <div className=\"wds-nudge-media\">\n <Illustration\n name={mediaName}\n className={clsx(`wds-nudge-media-${mediaName}`)}\n size=\"small\"\n disablePadding\n alt=\"\"\n />\n </div>\n )}\n <div className=\"wds-nudge-container\">\n <div className=\"wds-nudge-content\">\n <Body type={Typography.BODY_LARGE} className={clsx('wds-nudge-body')}>\n {title}\n </Body>\n {shouldRenderLegacyLink && (\n <Link\n href={href}\n type={Typography.LINK_LARGE}\n className=\"wds-nudge-link\"\n onClick={onClick}\n >\n {link}\n </Link>\n )}\n {action && (\n <Link\n href={action.href}\n target={action.target}\n className=\"m-t-1\"\n aria-label={action['aria-label']}\n type={Typography.LINK_LARGE}\n onClick={action.onClick}\n >\n {action.text}\n </Link>\n )}\n </div>\n {onDismiss || persistDismissal ? (\n <IconButton\n size={24}\n priority=\"tertiary\"\n aria-label={intl.formatMessage(closeBtnMessages.ariaLabel)}\n onClick={handleOnDismiss}\n >\n <Cross />\n </IconButton>\n ) : null}\n </div>\n </div>\n );\n};\n\nexport default Nudge;\n"],"names":["STORAGE_NAME","getLocalStorage","storageItem","localStorage","getItem","storage","JSON","parse","Array","isArray","map","item","String","Nudge","mediaName","title","link","href","onClick","onDismiss","persistDismissal","isPreviouslyDismissed","id","className","action","intl","useIntl","hasLegacyLink","Boolean","hasAction","shouldRenderLegacyLink","useEffect","process","env","NODE_ENV","console","warn","getIsDismissed","useCallback","find","nudgeState","setNudgeState","useState","isDismissed","isMounted","prev","handleOnDismiss","dismissedNudgesStorage","setItem","stringify","wasDismissed","_jsxs","clsx","children","_jsx","Illustration","name","size","disablePadding","alt","Body","type","Typography","BODY_LARGE","Link","LINK_LARGE","target","text","IconButton","priority","formatMessage","closeBtnMessages","ariaLabel","Cross"],"mappings":"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"}
1
+ {"version":3,"file":"Nudge.js","sources":["../../src/Nudge/Nudge.tsx"],"sourcesContent":["import { Illustration, Assets } from '@wise/art';\nimport { clsx } from 'clsx';\nimport { ReactNode, useEffect, useState, MouseEvent, useCallback } from 'react';\n\nimport Body from '../Body';\nimport { Typography } from '../common';\nimport Link from '../Link';\nimport type { AlertAction } from '../_deprecated/Alert';\nimport IconButton from '../IconButton';\nimport { Cross } from '@transferwise/icons';\nimport { useIntl } from 'react-intl';\nimport closeBtnMessages from '../common/CloseButton/CloseButton.messages';\n\n// WARNING: Changing this will cause nudges to reappear wherever persist nudge is used and privacy team will need to be updated too\nexport const STORAGE_NAME = 'dismissedNudges';\n\nconst getLocalStorage = (): string[] => {\n try {\n const storageItem = localStorage.getItem(STORAGE_NAME);\n\n if (storageItem) {\n const storage: unknown = JSON.parse(storageItem);\n\n if (Array.isArray(storage)) {\n return storage.map((item) => String(item));\n }\n }\n } catch (error) {}\n\n return [];\n};\n\ntype MediaNameType =\n | `${Assets.GLOBE}`\n | `${Assets.LOCK}`\n | `${Assets.WALLET}`\n | `${Assets.GEAR}`\n | `${Assets.INVITE_LETTER}`\n | `${Assets.PERSONAL_CARD}`\n | `${Assets.BUSINESS_CARD}`\n | `${Assets.HEART}`\n | `${Assets.MULTI_CURRENCY}`\n | `${Assets.SHOPPING_BAG}`\n | `${Assets.FLOWER}`\n | `${Assets.GIFT_BOX}`\n | `${Assets.BACKPACK}`\n | `${Assets.DOCUMENTS}`;\n\ntype BaseProps = {\n /** @deprecated Use `mediaName` property instead. */\n media?: ReactNode;\n /** Media name */\n mediaName?: MediaNameType;\n title: ReactNode;\n link?: ReactNode;\n href?: string;\n onClick?: (event?: MouseEvent<HTMLSpanElement>) => void;\n /** Fired when the user clicks on close button */\n onDismiss?: () => void;\n /** An optional call to action to sit under the main body of the nudge. If your label is short, use aria-label to provide more context */\n action?: AlertAction;\n className?: string;\n};\n\nexport interface OptionalId extends BaseProps {\n id?: string;\n persistDismissal?: false;\n isPreviouslyDismissed?: undefined;\n}\n\nexport interface RequiredPersistProps extends BaseProps {\n /** This ID should be completely unique to the page and feature as it uses a shared array which could conflict with other nudges in Wise */\n id: string;\n /** Use persist dismissal to keep the nudge dismissed using the browser's localStorage */\n persistDismissal: true;\n /**\n * Fired on mount for determining if nudge has been dismissed before\n *\n * @param {boolean} value - set to true if dismissed previously\n */\n isPreviouslyDismissed?: (value: boolean) => void;\n}\n\nexport type NudgeProps = OptionalId | RequiredPersistProps;\n\nconst Nudge = ({\n mediaName,\n title,\n link,\n href,\n onClick,\n onDismiss,\n persistDismissal,\n isPreviouslyDismissed,\n id,\n className,\n action,\n}: NudgeProps) => {\n const intl = useIntl();\n const getIsDismissed = useCallback(\n () => (persistDismissal && id ? !!getLocalStorage()?.find((item) => item === id) : false),\n [persistDismissal, id],\n );\n\n const [nudgeState, setNudgeState] = useState(() => ({\n isDismissed: getIsDismissed(),\n isMounted: false,\n }));\n\n useEffect(() => {\n // eslint-disable-next-line react-hooks/set-state-in-effect -- Setting mount state in mount effect\n setNudgeState((prev) => ({ ...prev, isMounted: true }));\n }, []);\n\n useEffect(() => {\n // eslint-disable-next-line react-hooks/set-state-in-effect -- Syncing dismissed state from localStorage on prop change\n setNudgeState((prev) => ({ ...prev, isDismissed: getIsDismissed() }));\n }, [getIsDismissed, id, persistDismissal]);\n\n const { isDismissed } = nudgeState;\n\n const handleOnDismiss = () => {\n const dismissedNudgesStorage = getLocalStorage();\n\n if (persistDismissal && id) {\n try {\n localStorage.setItem(STORAGE_NAME, JSON.stringify([...dismissedNudgesStorage, id]));\n } catch {}\n\n setNudgeState((prev) => ({ ...prev, isDismissed: true }));\n }\n\n if (onDismiss) {\n onDismiss();\n }\n };\n\n useEffect(() => {\n if (persistDismissal && id && isPreviouslyDismissed) {\n const dismissedNudgesStorage = getLocalStorage();\n const wasDismissed = !!dismissedNudgesStorage?.find((item) => item === id);\n isPreviouslyDismissed(wasDismissed);\n }\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [id, persistDismissal]);\n\n if (persistDismissal && (isDismissed || !nudgeState.isMounted)) {\n return null;\n }\n\n return (\n <div className={clsx('wds-nudge', className)} id={id}>\n {!!mediaName && (\n <div className=\"wds-nudge-media\">\n <Illustration\n name={mediaName}\n className={clsx(`wds-nudge-media-${mediaName}`)}\n size=\"small\"\n disablePadding\n alt=\"\"\n />\n </div>\n )}\n <div className=\"wds-nudge-container\">\n <div className=\"wds-nudge-content\">\n <Body type={Typography.BODY_LARGE} className={clsx('wds-nudge-body')}>\n {title}\n </Body>\n {/* Merge these two Link instances into one */}\n {link && (\n <Link\n href={href}\n type={Typography.LINK_LARGE}\n className=\"wds-nudge-link\"\n onClick={onClick}\n >\n {link}\n </Link>\n )}\n {action && (\n <Link\n href={action.href}\n target={action.target}\n className=\"m-t-1\"\n aria-label={action['aria-label']}\n type={Typography.LINK_LARGE}\n onClick={action.onClick}\n >\n {action.text}\n </Link>\n )}\n </div>\n {onDismiss || persistDismissal ? (\n <IconButton\n size={24}\n priority=\"tertiary\"\n aria-label={intl.formatMessage(closeBtnMessages.ariaLabel)}\n onClick={handleOnDismiss}\n >\n <Cross />\n </IconButton>\n ) : null}\n </div>\n </div>\n );\n};\n\nexport default Nudge;\n"],"names":["STORAGE_NAME","getLocalStorage","storageItem","localStorage","getItem","storage","JSON","parse","Array","isArray","map","item","String","error","Nudge","mediaName","title","link","href","onClick","onDismiss","persistDismissal","isPreviouslyDismissed","id","className","action","intl","useIntl","getIsDismissed","useCallback","find","nudgeState","setNudgeState","useState","isDismissed","isMounted","useEffect","prev","handleOnDismiss","dismissedNudgesStorage","setItem","stringify","wasDismissed","_jsxs","clsx","children","_jsx","Illustration","name","size","disablePadding","alt","Body","type","Typography","BODY_LARGE","Link","LINK_LARGE","target","text","IconButton","priority","formatMessage","closeBtnMessages","ariaLabel","Cross"],"mappings":"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"}
@@ -1,6 +1,6 @@
1
1
  import { Illustration } from '@wise/art';
2
2
  import { clsx } from 'clsx';
3
- import { useEffect, useCallback, useState } from 'react';
3
+ import { useCallback, useState, useEffect } from 'react';
4
4
  import Body from '../Body/Body.mjs';
5
5
  import '../common/theme.mjs';
6
6
  import '../common/direction.mjs';
@@ -39,7 +39,7 @@ const getLocalStorage = () => {
39
39
  return storage.map(item => String(item));
40
40
  }
41
41
  }
42
- } catch {}
42
+ } catch (error) {}
43
43
  return [];
44
44
  };
45
45
  const Nudge = ({
@@ -56,15 +56,6 @@ const Nudge = ({
56
56
  action
57
57
  }) => {
58
58
  const intl = useIntl();
59
- const hasLegacyLink = Boolean(link);
60
- const hasAction = action != null;
61
- const shouldRenderLegacyLink = hasLegacyLink && !hasAction;
62
- useEffect(() => {
63
- if (process.env.NODE_ENV !== 'production' && hasAction && (hasLegacyLink || href != null)) {
64
- // eslint-disable-next-line no-console -- Intentional developer warning for conflicting API usage.
65
- console.warn('Nudge received both action and link/href props. Rendering action only. Remove link/href to silence this warning.');
66
- }
67
- }, [hasAction, hasLegacyLink, href]);
68
59
  const getIsDismissed = useCallback(() => persistDismissal && id ? !!getLocalStorage()?.find(item => item === id) : false, [persistDismissal, id]);
69
60
  const [nudgeState, setNudgeState] = useState(() => ({
70
61
  isDismissed: getIsDismissed(),
@@ -133,7 +124,7 @@ const Nudge = ({
133
124
  type: Typography.BODY_LARGE,
134
125
  className: clsx('wds-nudge-body'),
135
126
  children: title
136
- }), shouldRenderLegacyLink && /*#__PURE__*/jsx(Link, {
127
+ }), link && /*#__PURE__*/jsx(Link, {
137
128
  href: href,
138
129
  type: Typography.LINK_LARGE,
139
130
  className: "wds-nudge-link",
@@ -1 +1 @@
1
- {"version":3,"file":"Nudge.mjs","sources":["../../src/Nudge/Nudge.tsx"],"sourcesContent":["import { Illustration, Assets } from '@wise/art';\nimport { clsx } from 'clsx';\nimport { ReactNode, useEffect, useState, MouseEvent, useCallback } from 'react';\n\nimport Body from '../Body';\nimport { Typography } from '../common';\nimport Link from '../Link';\nimport type { AlertAction } from '../_deprecated/Alert';\nimport IconButton from '../IconButton';\nimport { Cross } from '@transferwise/icons';\nimport { useIntl } from 'react-intl';\nimport closeBtnMessages from '../common/CloseButton/CloseButton.messages';\n\n// WARNING: Changing this will cause nudges to reappear wherever persist nudge is used and privacy team will need to be updated too\nexport const STORAGE_NAME = 'dismissedNudges';\n\nconst getLocalStorage = (): string[] => {\n try {\n const storageItem = localStorage.getItem(STORAGE_NAME);\n\n if (storageItem) {\n const storage: unknown = JSON.parse(storageItem);\n\n if (Array.isArray(storage)) {\n return storage.map((item) => String(item));\n }\n }\n } catch {}\n\n return [];\n};\n\ntype MediaNameType =\n | `${Assets.GLOBE}`\n | `${Assets.LOCK}`\n | `${Assets.WALLET}`\n | `${Assets.GEAR}`\n | `${Assets.INVITE_LETTER}`\n | `${Assets.PERSONAL_CARD}`\n | `${Assets.BUSINESS_CARD}`\n | `${Assets.HEART}`\n | `${Assets.MULTI_CURRENCY}`\n | `${Assets.SHOPPING_BAG}`\n | `${Assets.FLOWER}`\n | `${Assets.GIFT_BOX}`\n | `${Assets.BACKPACK}`\n | `${Assets.DOCUMENTS}`;\n\ntype BaseProps = {\n /**\n * @deprecated Use `mediaName` instead.\n * Legacy custom media content is no longer used by `Nudge`.\n */\n media?: ReactNode;\n /**\n * Illustration asset name shown at the start of the nudge.\n */\n mediaName?: MediaNameType;\n /** Main nudge message content. */\n title: ReactNode;\n /**\n * Legacy CTA label content.\n * Rendered only when `action` is not provided.\n */\n link?: ReactNode;\n /**\n * Legacy CTA destination for `link`.\n * Ignored when `action` is provided.\n */\n href?: string;\n /**\n * Legacy click handler for `link`.\n * Ignored when `action` is provided.\n */\n onClick?: (event?: MouseEvent<HTMLSpanElement>) => void;\n /** Fired when the user clicks on close button */\n onDismiss?: () => void;\n /**\n * Preferred CTA configuration rendered under the nudge body.\n * Single CTA rule: when `action` is provided, legacy `link`/`href` is not rendered.\n * If your label is short, use `aria-label` to provide more context.\n */\n action?: AlertAction;\n /** Optional class name applied to the root nudge container. */\n className?: string;\n};\n\nexport interface OptionalId extends BaseProps {\n id?: string;\n persistDismissal?: false;\n isPreviouslyDismissed?: undefined;\n}\n\nexport interface RequiredPersistProps extends BaseProps {\n /** This ID should be completely unique to the page and feature as it uses a shared array which could conflict with other nudges in Wise */\n id: string;\n /** Use persist dismissal to keep the nudge dismissed using the browser's localStorage */\n persistDismissal: true;\n /**\n * Fired on mount for determining if nudge has been dismissed before\n *\n * @param {boolean} value - set to true if dismissed previously\n */\n isPreviouslyDismissed?: (value: boolean) => void;\n}\n\nexport type NudgeProps = OptionalId | RequiredPersistProps;\n\nconst Nudge = ({\n mediaName,\n title,\n link,\n href,\n onClick,\n onDismiss,\n persistDismissal,\n isPreviouslyDismissed,\n id,\n className,\n action,\n}: NudgeProps) => {\n const intl = useIntl();\n const hasLegacyLink = Boolean(link);\n const hasAction = action != null;\n const shouldRenderLegacyLink = hasLegacyLink && !hasAction;\n\n useEffect(() => {\n if (process.env.NODE_ENV !== 'production' && hasAction && (hasLegacyLink || href != null)) {\n // eslint-disable-next-line no-console -- Intentional developer warning for conflicting API usage.\n console.warn(\n 'Nudge received both action and link/href props. Rendering action only. Remove link/href to silence this warning.',\n );\n }\n }, [hasAction, hasLegacyLink, href]);\n\n const getIsDismissed = useCallback(\n () => (persistDismissal && id ? !!getLocalStorage()?.find((item) => item === id) : false),\n [persistDismissal, id],\n );\n\n const [nudgeState, setNudgeState] = useState(() => ({\n isDismissed: getIsDismissed(),\n isMounted: false,\n }));\n\n useEffect(() => {\n // eslint-disable-next-line react-hooks/set-state-in-effect -- Setting mount state in mount effect\n setNudgeState((prev) => ({ ...prev, isMounted: true }));\n }, []);\n\n useEffect(() => {\n // eslint-disable-next-line react-hooks/set-state-in-effect -- Syncing dismissed state from localStorage on prop change\n setNudgeState((prev) => ({ ...prev, isDismissed: getIsDismissed() }));\n }, [getIsDismissed, id, persistDismissal]);\n\n const { isDismissed } = nudgeState;\n\n const handleOnDismiss = () => {\n const dismissedNudgesStorage = getLocalStorage();\n\n if (persistDismissal && id) {\n try {\n localStorage.setItem(STORAGE_NAME, JSON.stringify([...dismissedNudgesStorage, id]));\n } catch {}\n\n setNudgeState((prev) => ({ ...prev, isDismissed: true }));\n }\n\n if (onDismiss) {\n onDismiss();\n }\n };\n\n useEffect(() => {\n if (persistDismissal && id && isPreviouslyDismissed) {\n const dismissedNudgesStorage = getLocalStorage();\n const wasDismissed = !!dismissedNudgesStorage?.find((item) => item === id);\n isPreviouslyDismissed(wasDismissed);\n }\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [id, persistDismissal]);\n\n if (persistDismissal && (isDismissed || !nudgeState.isMounted)) {\n return null;\n }\n\n return (\n <div className={clsx('wds-nudge', className)} id={id}>\n {!!mediaName && (\n <div className=\"wds-nudge-media\">\n <Illustration\n name={mediaName}\n className={clsx(`wds-nudge-media-${mediaName}`)}\n size=\"small\"\n disablePadding\n alt=\"\"\n />\n </div>\n )}\n <div className=\"wds-nudge-container\">\n <div className=\"wds-nudge-content\">\n <Body type={Typography.BODY_LARGE} className={clsx('wds-nudge-body')}>\n {title}\n </Body>\n {shouldRenderLegacyLink && (\n <Link\n href={href}\n type={Typography.LINK_LARGE}\n className=\"wds-nudge-link\"\n onClick={onClick}\n >\n {link}\n </Link>\n )}\n {action && (\n <Link\n href={action.href}\n target={action.target}\n className=\"m-t-1\"\n aria-label={action['aria-label']}\n type={Typography.LINK_LARGE}\n onClick={action.onClick}\n >\n {action.text}\n </Link>\n )}\n </div>\n {onDismiss || persistDismissal ? (\n <IconButton\n size={24}\n priority=\"tertiary\"\n aria-label={intl.formatMessage(closeBtnMessages.ariaLabel)}\n onClick={handleOnDismiss}\n >\n <Cross />\n </IconButton>\n ) : null}\n </div>\n </div>\n );\n};\n\nexport default Nudge;\n"],"names":["STORAGE_NAME","getLocalStorage","storageItem","localStorage","getItem","storage","JSON","parse","Array","isArray","map","item","String","Nudge","mediaName","title","link","href","onClick","onDismiss","persistDismissal","isPreviouslyDismissed","id","className","action","intl","useIntl","hasLegacyLink","Boolean","hasAction","shouldRenderLegacyLink","useEffect","process","env","NODE_ENV","console","warn","getIsDismissed","useCallback","find","nudgeState","setNudgeState","useState","isDismissed","isMounted","prev","handleOnDismiss","dismissedNudgesStorage","setItem","stringify","wasDismissed","_jsxs","clsx","children","_jsx","Illustration","name","size","disablePadding","alt","Body","type","Typography","BODY_LARGE","Link","LINK_LARGE","target","text","IconButton","priority","formatMessage","closeBtnMessages","ariaLabel","Cross"],"mappings":"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"}
1
+ {"version":3,"file":"Nudge.mjs","sources":["../../src/Nudge/Nudge.tsx"],"sourcesContent":["import { Illustration, Assets } from '@wise/art';\nimport { clsx } from 'clsx';\nimport { ReactNode, useEffect, useState, MouseEvent, useCallback } from 'react';\n\nimport Body from '../Body';\nimport { Typography } from '../common';\nimport Link from '../Link';\nimport type { AlertAction } from '../_deprecated/Alert';\nimport IconButton from '../IconButton';\nimport { Cross } from '@transferwise/icons';\nimport { useIntl } from 'react-intl';\nimport closeBtnMessages from '../common/CloseButton/CloseButton.messages';\n\n// WARNING: Changing this will cause nudges to reappear wherever persist nudge is used and privacy team will need to be updated too\nexport const STORAGE_NAME = 'dismissedNudges';\n\nconst getLocalStorage = (): string[] => {\n try {\n const storageItem = localStorage.getItem(STORAGE_NAME);\n\n if (storageItem) {\n const storage: unknown = JSON.parse(storageItem);\n\n if (Array.isArray(storage)) {\n return storage.map((item) => String(item));\n }\n }\n } catch (error) {}\n\n return [];\n};\n\ntype MediaNameType =\n | `${Assets.GLOBE}`\n | `${Assets.LOCK}`\n | `${Assets.WALLET}`\n | `${Assets.GEAR}`\n | `${Assets.INVITE_LETTER}`\n | `${Assets.PERSONAL_CARD}`\n | `${Assets.BUSINESS_CARD}`\n | `${Assets.HEART}`\n | `${Assets.MULTI_CURRENCY}`\n | `${Assets.SHOPPING_BAG}`\n | `${Assets.FLOWER}`\n | `${Assets.GIFT_BOX}`\n | `${Assets.BACKPACK}`\n | `${Assets.DOCUMENTS}`;\n\ntype BaseProps = {\n /** @deprecated Use `mediaName` property instead. */\n media?: ReactNode;\n /** Media name */\n mediaName?: MediaNameType;\n title: ReactNode;\n link?: ReactNode;\n href?: string;\n onClick?: (event?: MouseEvent<HTMLSpanElement>) => void;\n /** Fired when the user clicks on close button */\n onDismiss?: () => void;\n /** An optional call to action to sit under the main body of the nudge. If your label is short, use aria-label to provide more context */\n action?: AlertAction;\n className?: string;\n};\n\nexport interface OptionalId extends BaseProps {\n id?: string;\n persistDismissal?: false;\n isPreviouslyDismissed?: undefined;\n}\n\nexport interface RequiredPersistProps extends BaseProps {\n /** This ID should be completely unique to the page and feature as it uses a shared array which could conflict with other nudges in Wise */\n id: string;\n /** Use persist dismissal to keep the nudge dismissed using the browser's localStorage */\n persistDismissal: true;\n /**\n * Fired on mount for determining if nudge has been dismissed before\n *\n * @param {boolean} value - set to true if dismissed previously\n */\n isPreviouslyDismissed?: (value: boolean) => void;\n}\n\nexport type NudgeProps = OptionalId | RequiredPersistProps;\n\nconst Nudge = ({\n mediaName,\n title,\n link,\n href,\n onClick,\n onDismiss,\n persistDismissal,\n isPreviouslyDismissed,\n id,\n className,\n action,\n}: NudgeProps) => {\n const intl = useIntl();\n const getIsDismissed = useCallback(\n () => (persistDismissal && id ? !!getLocalStorage()?.find((item) => item === id) : false),\n [persistDismissal, id],\n );\n\n const [nudgeState, setNudgeState] = useState(() => ({\n isDismissed: getIsDismissed(),\n isMounted: false,\n }));\n\n useEffect(() => {\n // eslint-disable-next-line react-hooks/set-state-in-effect -- Setting mount state in mount effect\n setNudgeState((prev) => ({ ...prev, isMounted: true }));\n }, []);\n\n useEffect(() => {\n // eslint-disable-next-line react-hooks/set-state-in-effect -- Syncing dismissed state from localStorage on prop change\n setNudgeState((prev) => ({ ...prev, isDismissed: getIsDismissed() }));\n }, [getIsDismissed, id, persistDismissal]);\n\n const { isDismissed } = nudgeState;\n\n const handleOnDismiss = () => {\n const dismissedNudgesStorage = getLocalStorage();\n\n if (persistDismissal && id) {\n try {\n localStorage.setItem(STORAGE_NAME, JSON.stringify([...dismissedNudgesStorage, id]));\n } catch {}\n\n setNudgeState((prev) => ({ ...prev, isDismissed: true }));\n }\n\n if (onDismiss) {\n onDismiss();\n }\n };\n\n useEffect(() => {\n if (persistDismissal && id && isPreviouslyDismissed) {\n const dismissedNudgesStorage = getLocalStorage();\n const wasDismissed = !!dismissedNudgesStorage?.find((item) => item === id);\n isPreviouslyDismissed(wasDismissed);\n }\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [id, persistDismissal]);\n\n if (persistDismissal && (isDismissed || !nudgeState.isMounted)) {\n return null;\n }\n\n return (\n <div className={clsx('wds-nudge', className)} id={id}>\n {!!mediaName && (\n <div className=\"wds-nudge-media\">\n <Illustration\n name={mediaName}\n className={clsx(`wds-nudge-media-${mediaName}`)}\n size=\"small\"\n disablePadding\n alt=\"\"\n />\n </div>\n )}\n <div className=\"wds-nudge-container\">\n <div className=\"wds-nudge-content\">\n <Body type={Typography.BODY_LARGE} className={clsx('wds-nudge-body')}>\n {title}\n </Body>\n {/* Merge these two Link instances into one */}\n {link && (\n <Link\n href={href}\n type={Typography.LINK_LARGE}\n className=\"wds-nudge-link\"\n onClick={onClick}\n >\n {link}\n </Link>\n )}\n {action && (\n <Link\n href={action.href}\n target={action.target}\n className=\"m-t-1\"\n aria-label={action['aria-label']}\n type={Typography.LINK_LARGE}\n onClick={action.onClick}\n >\n {action.text}\n </Link>\n )}\n </div>\n {onDismiss || persistDismissal ? (\n <IconButton\n size={24}\n priority=\"tertiary\"\n aria-label={intl.formatMessage(closeBtnMessages.ariaLabel)}\n onClick={handleOnDismiss}\n >\n <Cross />\n </IconButton>\n ) : null}\n </div>\n </div>\n );\n};\n\nexport default Nudge;\n"],"names":["STORAGE_NAME","getLocalStorage","storageItem","localStorage","getItem","storage","JSON","parse","Array","isArray","map","item","String","error","Nudge","mediaName","title","link","href","onClick","onDismiss","persistDismissal","isPreviouslyDismissed","id","className","action","intl","useIntl","getIsDismissed","useCallback","find","nudgeState","setNudgeState","useState","isDismissed","isMounted","useEffect","prev","handleOnDismiss","dismissedNudgesStorage","setItem","stringify","wasDismissed","_jsxs","clsx","children","_jsx","Illustration","name","size","disablePadding","alt","Body","type","Typography","BODY_LARGE","Link","LINK_LARGE","target","text","IconButton","priority","formatMessage","closeBtnMessages","ariaLabel","Cross"],"mappings":"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"}
package/build/main.css CHANGED
@@ -27121,6 +27121,7 @@ a[data-toggle="tooltip"] {
27121
27121
 
27122
27122
  .wds-Button--medium {
27123
27123
  padding: var(--Button-medium-padding);
27124
+ --Button-iconSpacerSize: 18px;
27124
27125
  }
27125
27126
 
27126
27127
  .wds-Button--medium:has(.wds-Button-avatars) {
@@ -27139,6 +27140,7 @@ a[data-toggle="tooltip"] {
27139
27140
 
27140
27141
  .wds-Button--small {
27141
27142
  padding: var(--Button-small-padding);
27143
+ --Button-iconSpacerSize: 16px;
27142
27144
  }
27143
27145
 
27144
27146
  .wds-Button--small:has(.wds-Button-icon--start) {
@@ -27157,6 +27159,7 @@ a[data-toggle="tooltip"] {
27157
27159
 
27158
27160
  .wds-Button-avatars {
27159
27161
  display: inline-flex;
27162
+ flex-shrink: 0;
27160
27163
  }
27161
27164
 
27162
27165
  .wds-Button-avatars .np-avatar-view .np-avatar-view-content {
@@ -27165,6 +27168,7 @@ a[data-toggle="tooltip"] {
27165
27168
 
27166
27169
  .wds-Button-icon {
27167
27170
  display: inline-block;
27171
+ flex-shrink: 0;
27168
27172
  }
27169
27173
 
27170
27174
  .wds-Button-icon--md {
@@ -27199,6 +27203,13 @@ a[data-toggle="tooltip"] {
27199
27203
  position: relative;
27200
27204
  }
27201
27205
 
27206
+ .wds-Button:has(.wds-Button-icon--start):not(:has(.wds-Button-icon--end)) .wds-Button-label::after,
27207
+ .wds-Button:has(.wds-Button-icon--end):not(:has(.wds-Button-icon--start)) .wds-Button-label::before {
27208
+ content: '';
27209
+ width: var(--Button-iconSpacerSize);
27210
+ flex-shrink: 0;
27211
+ }
27212
+
27202
27213
  .wds-Button-loader {
27203
27214
  position: absolute;
27204
27215
  width: 100%;
@@ -151,6 +151,7 @@
151
151
  }
152
152
  .wds-Button--medium {
153
153
  padding: var(--Button-medium-padding);
154
+ --Button-iconSpacerSize: 18px;
154
155
  }
155
156
  .wds-Button--medium:has(.wds-Button-avatars) {
156
157
  padding-inline-start: 8px;
@@ -165,6 +166,7 @@
165
166
  }
166
167
  .wds-Button--small {
167
168
  padding: var(--Button-small-padding);
169
+ --Button-iconSpacerSize: 16px;
168
170
  }
169
171
  .wds-Button--small:has(.wds-Button-icon--start) {
170
172
  padding-inline-start: 8px;
@@ -179,12 +181,14 @@
179
181
  }
180
182
  .wds-Button-avatars {
181
183
  display: inline-flex;
184
+ flex-shrink: 0;
182
185
  }
183
186
  .wds-Button-avatars .np-avatar-view .np-avatar-view-content {
184
187
  color: var(--Button-color);
185
188
  }
186
189
  .wds-Button-icon {
187
190
  display: inline-block;
191
+ flex-shrink: 0;
188
192
  }
189
193
  .wds-Button-icon--md {
190
194
  --Button-iconSize: 18px;
@@ -212,6 +216,12 @@
212
216
  gap: var(--Button-label-gap);
213
217
  position: relative;
214
218
  }
219
+ .wds-Button:has(.wds-Button-icon--start):not(:has(.wds-Button-icon--end)) .wds-Button-label::after,
220
+ .wds-Button:has(.wds-Button-icon--end):not(:has(.wds-Button-icon--start)) .wds-Button-label::before {
221
+ content: '';
222
+ width: var(--Button-iconSpacerSize);
223
+ flex-shrink: 0;
224
+ }
215
225
  .wds-Button-loader {
216
226
  position: absolute;
217
227
  width: 100%;
@@ -27121,6 +27121,7 @@ a[data-toggle="tooltip"] {
27121
27121
 
27122
27122
  .wds-Button--medium {
27123
27123
  padding: var(--Button-medium-padding);
27124
+ --Button-iconSpacerSize: 18px;
27124
27125
  }
27125
27126
 
27126
27127
  .wds-Button--medium:has(.wds-Button-avatars) {
@@ -27139,6 +27140,7 @@ a[data-toggle="tooltip"] {
27139
27140
 
27140
27141
  .wds-Button--small {
27141
27142
  padding: var(--Button-small-padding);
27143
+ --Button-iconSpacerSize: 16px;
27142
27144
  }
27143
27145
 
27144
27146
  .wds-Button--small:has(.wds-Button-icon--start) {
@@ -27157,6 +27159,7 @@ a[data-toggle="tooltip"] {
27157
27159
 
27158
27160
  .wds-Button-avatars {
27159
27161
  display: inline-flex;
27162
+ flex-shrink: 0;
27160
27163
  }
27161
27164
 
27162
27165
  .wds-Button-avatars .np-avatar-view .np-avatar-view-content {
@@ -27165,6 +27168,7 @@ a[data-toggle="tooltip"] {
27165
27168
 
27166
27169
  .wds-Button-icon {
27167
27170
  display: inline-block;
27171
+ flex-shrink: 0;
27168
27172
  }
27169
27173
 
27170
27174
  .wds-Button-icon--md {
@@ -27199,6 +27203,13 @@ a[data-toggle="tooltip"] {
27199
27203
  position: relative;
27200
27204
  }
27201
27205
 
27206
+ .wds-Button:has(.wds-Button-icon--start):not(:has(.wds-Button-icon--end)) .wds-Button-label::after,
27207
+ .wds-Button:has(.wds-Button-icon--end):not(:has(.wds-Button-icon--start)) .wds-Button-label::before {
27208
+ content: '';
27209
+ width: var(--Button-iconSpacerSize);
27210
+ flex-shrink: 0;
27211
+ }
27212
+
27202
27213
  .wds-Button-loader {
27203
27214
  position: absolute;
27204
27215
  width: 100%;
@@ -4,41 +4,18 @@ import type { AlertAction } from '../_deprecated/Alert';
4
4
  export declare const STORAGE_NAME = "dismissedNudges";
5
5
  type MediaNameType = `${Assets.GLOBE}` | `${Assets.LOCK}` | `${Assets.WALLET}` | `${Assets.GEAR}` | `${Assets.INVITE_LETTER}` | `${Assets.PERSONAL_CARD}` | `${Assets.BUSINESS_CARD}` | `${Assets.HEART}` | `${Assets.MULTI_CURRENCY}` | `${Assets.SHOPPING_BAG}` | `${Assets.FLOWER}` | `${Assets.GIFT_BOX}` | `${Assets.BACKPACK}` | `${Assets.DOCUMENTS}`;
6
6
  type BaseProps = {
7
- /**
8
- * @deprecated Use `mediaName` instead.
9
- * Legacy custom media content is no longer used by `Nudge`.
10
- */
7
+ /** @deprecated Use `mediaName` property instead. */
11
8
  media?: ReactNode;
12
- /**
13
- * Illustration asset name shown at the start of the nudge.
14
- */
9
+ /** Media name */
15
10
  mediaName?: MediaNameType;
16
- /** Main nudge message content. */
17
11
  title: ReactNode;
18
- /**
19
- * Legacy CTA label content.
20
- * Rendered only when `action` is not provided.
21
- */
22
12
  link?: ReactNode;
23
- /**
24
- * Legacy CTA destination for `link`.
25
- * Ignored when `action` is provided.
26
- */
27
13
  href?: string;
28
- /**
29
- * Legacy click handler for `link`.
30
- * Ignored when `action` is provided.
31
- */
32
14
  onClick?: (event?: MouseEvent<HTMLSpanElement>) => void;
33
15
  /** Fired when the user clicks on close button */
34
16
  onDismiss?: () => void;
35
- /**
36
- * Preferred CTA configuration rendered under the nudge body.
37
- * Single CTA rule: when `action` is provided, legacy `link`/`href` is not rendered.
38
- * If your label is short, use `aria-label` to provide more context.
39
- */
17
+ /** An optional call to action to sit under the main body of the nudge. If your label is short, use aria-label to provide more context */
40
18
  action?: AlertAction;
41
- /** Optional class name applied to the root nudge container. */
42
19
  className?: string;
43
20
  };
44
21
  export interface OptionalId extends BaseProps {
@@ -1 +1 @@
1
- {"version":3,"file":"Nudge.d.ts","sourceRoot":"","sources":["../../../src/Nudge/Nudge.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAgB,MAAM,EAAE,MAAM,WAAW,CAAC;AAEjD,OAAO,EAAE,SAAS,EAAuB,UAAU,EAAe,MAAM,OAAO,CAAC;AAKhF,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,sBAAsB,CAAC;AAOxD,eAAO,MAAM,YAAY,oBAAoB,CAAC;AAkB9C,KAAK,aAAa,GACd,GAAG,MAAM,CAAC,KAAK,EAAE,GACjB,GAAG,MAAM,CAAC,IAAI,EAAE,GAChB,GAAG,MAAM,CAAC,MAAM,EAAE,GAClB,GAAG,MAAM,CAAC,IAAI,EAAE,GAChB,GAAG,MAAM,CAAC,aAAa,EAAE,GACzB,GAAG,MAAM,CAAC,aAAa,EAAE,GACzB,GAAG,MAAM,CAAC,aAAa,EAAE,GACzB,GAAG,MAAM,CAAC,KAAK,EAAE,GACjB,GAAG,MAAM,CAAC,cAAc,EAAE,GAC1B,GAAG,MAAM,CAAC,YAAY,EAAE,GACxB,GAAG,MAAM,CAAC,MAAM,EAAE,GAClB,GAAG,MAAM,CAAC,QAAQ,EAAE,GACpB,GAAG,MAAM,CAAC,QAAQ,EAAE,GACpB,GAAG,MAAM,CAAC,SAAS,EAAE,CAAC;AAE1B,KAAK,SAAS,GAAG;IACf;;;OAGG;IACH,KAAK,CAAC,EAAE,SAAS,CAAC;IAClB;;OAEG;IACH,SAAS,CAAC,EAAE,aAAa,CAAC;IAC1B,kCAAkC;IAClC,KAAK,EAAE,SAAS,CAAC;IACjB;;;OAGG;IACH,IAAI,CAAC,EAAE,SAAS,CAAC;IACjB;;;OAGG;IACH,IAAI,CAAC,EAAE,MAAM,CAAC;IACd;;;OAGG;IACH,OAAO,CAAC,EAAE,CAAC,KAAK,CAAC,EAAE,UAAU,CAAC,eAAe,CAAC,KAAK,IAAI,CAAC;IACxD,iDAAiD;IACjD,SAAS,CAAC,EAAE,MAAM,IAAI,CAAC;IACvB;;;;OAIG;IACH,MAAM,CAAC,EAAE,WAAW,CAAC;IACrB,+DAA+D;IAC/D,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB,CAAC;AAEF,MAAM,WAAW,UAAW,SAAQ,SAAS;IAC3C,EAAE,CAAC,EAAE,MAAM,CAAC;IACZ,gBAAgB,CAAC,EAAE,KAAK,CAAC;IACzB,qBAAqB,CAAC,EAAE,SAAS,CAAC;CACnC;AAED,MAAM,WAAW,oBAAqB,SAAQ,SAAS;IACrD,2IAA2I;IAC3I,EAAE,EAAE,MAAM,CAAC;IACX,yFAAyF;IACzF,gBAAgB,EAAE,IAAI,CAAC;IACvB;;;;OAIG;IACH,qBAAqB,CAAC,EAAE,CAAC,KAAK,EAAE,OAAO,KAAK,IAAI,CAAC;CAClD;AAED,MAAM,MAAM,UAAU,GAAG,UAAU,GAAG,oBAAoB,CAAC;AAE3D,QAAA,MAAM,KAAK,GAAI,uHAYZ,UAAU,uCAwHZ,CAAC;AAEF,eAAe,KAAK,CAAC"}
1
+ {"version":3,"file":"Nudge.d.ts","sourceRoot":"","sources":["../../../src/Nudge/Nudge.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAgB,MAAM,EAAE,MAAM,WAAW,CAAC;AAEjD,OAAO,EAAE,SAAS,EAAuB,UAAU,EAAe,MAAM,OAAO,CAAC;AAKhF,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,sBAAsB,CAAC;AAOxD,eAAO,MAAM,YAAY,oBAAoB,CAAC;AAkB9C,KAAK,aAAa,GACd,GAAG,MAAM,CAAC,KAAK,EAAE,GACjB,GAAG,MAAM,CAAC,IAAI,EAAE,GAChB,GAAG,MAAM,CAAC,MAAM,EAAE,GAClB,GAAG,MAAM,CAAC,IAAI,EAAE,GAChB,GAAG,MAAM,CAAC,aAAa,EAAE,GACzB,GAAG,MAAM,CAAC,aAAa,EAAE,GACzB,GAAG,MAAM,CAAC,aAAa,EAAE,GACzB,GAAG,MAAM,CAAC,KAAK,EAAE,GACjB,GAAG,MAAM,CAAC,cAAc,EAAE,GAC1B,GAAG,MAAM,CAAC,YAAY,EAAE,GACxB,GAAG,MAAM,CAAC,MAAM,EAAE,GAClB,GAAG,MAAM,CAAC,QAAQ,EAAE,GACpB,GAAG,MAAM,CAAC,QAAQ,EAAE,GACpB,GAAG,MAAM,CAAC,SAAS,EAAE,CAAC;AAE1B,KAAK,SAAS,GAAG;IACf,oDAAoD;IACpD,KAAK,CAAC,EAAE,SAAS,CAAC;IAClB,kBAAkB;IAClB,SAAS,CAAC,EAAE,aAAa,CAAC;IAC1B,KAAK,EAAE,SAAS,CAAC;IACjB,IAAI,CAAC,EAAE,SAAS,CAAC;IACjB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,OAAO,CAAC,EAAE,CAAC,KAAK,CAAC,EAAE,UAAU,CAAC,eAAe,CAAC,KAAK,IAAI,CAAC;IACxD,iDAAiD;IACjD,SAAS,CAAC,EAAE,MAAM,IAAI,CAAC;IACvB,yIAAyI;IACzI,MAAM,CAAC,EAAE,WAAW,CAAC;IACrB,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB,CAAC;AAEF,MAAM,WAAW,UAAW,SAAQ,SAAS;IAC3C,EAAE,CAAC,EAAE,MAAM,CAAC;IACZ,gBAAgB,CAAC,EAAE,KAAK,CAAC;IACzB,qBAAqB,CAAC,EAAE,SAAS,CAAC;CACnC;AAED,MAAM,WAAW,oBAAqB,SAAQ,SAAS;IACrD,2IAA2I;IAC3I,EAAE,EAAE,MAAM,CAAC;IACX,yFAAyF;IACzF,gBAAgB,EAAE,IAAI,CAAC;IACvB;;;;OAIG;IACH,qBAAqB,CAAC,EAAE,CAAC,KAAK,EAAE,OAAO,KAAK,IAAI,CAAC;CAClD;AAED,MAAM,MAAM,UAAU,GAAG,UAAU,GAAG,oBAAoB,CAAC;AAE3D,QAAA,MAAM,KAAK,GAAI,uHAYZ,UAAU,uCA4GZ,CAAC;AAEF,eAAe,KAAK,CAAC"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@transferwise/components",
3
- "version": "0.0.0-experimental-ef7ebdb",
3
+ "version": "0.0.0-experimental-dbd40fc",
4
4
  "description": "Neptune React components",
5
5
  "license": "Apache-2.0",
6
6
  "repository": {
@@ -151,6 +151,7 @@
151
151
  }
152
152
  .wds-Button--medium {
153
153
  padding: var(--Button-medium-padding);
154
+ --Button-iconSpacerSize: 18px;
154
155
  }
155
156
  .wds-Button--medium:has(.wds-Button-avatars) {
156
157
  padding-inline-start: 8px;
@@ -165,6 +166,7 @@
165
166
  }
166
167
  .wds-Button--small {
167
168
  padding: var(--Button-small-padding);
169
+ --Button-iconSpacerSize: 16px;
168
170
  }
169
171
  .wds-Button--small:has(.wds-Button-icon--start) {
170
172
  padding-inline-start: 8px;
@@ -179,12 +181,14 @@
179
181
  }
180
182
  .wds-Button-avatars {
181
183
  display: inline-flex;
184
+ flex-shrink: 0;
182
185
  }
183
186
  .wds-Button-avatars .np-avatar-view .np-avatar-view-content {
184
187
  color: var(--Button-color);
185
188
  }
186
189
  .wds-Button-icon {
187
190
  display: inline-block;
191
+ flex-shrink: 0;
188
192
  }
189
193
  .wds-Button-icon--md {
190
194
  --Button-iconSize: 18px;
@@ -212,6 +216,12 @@
212
216
  gap: var(--Button-label-gap);
213
217
  position: relative;
214
218
  }
219
+ .wds-Button:has(.wds-Button-icon--start):not(:has(.wds-Button-icon--end)) .wds-Button-label::after,
220
+ .wds-Button:has(.wds-Button-icon--end):not(:has(.wds-Button-icon--start)) .wds-Button-label::before {
221
+ content: '';
222
+ width: var(--Button-iconSpacerSize);
223
+ flex-shrink: 0;
224
+ }
215
225
  .wds-Button-loader {
216
226
  position: absolute;
217
227
  width: 100%;
@@ -124,6 +124,7 @@
124
124
 
125
125
  &--medium {
126
126
  padding: var(--Button-medium-padding);
127
+ --Button-iconSpacerSize: 18px;
127
128
 
128
129
  &:has(.wds-Button-avatars){
129
130
  padding-inline-start: var(--size-8);
@@ -140,6 +141,7 @@
140
141
 
141
142
  &--small {
142
143
  padding: var(--Button-small-padding);
144
+ --Button-iconSpacerSize: 16px;
143
145
 
144
146
  &:has(.wds-Button-icon--start){
145
147
  padding-inline-start: var(--size-8);
@@ -159,6 +161,7 @@
159
161
 
160
162
  &-avatars {
161
163
  display: inline-flex;
164
+ flex-shrink: 0;
162
165
 
163
166
  .np-avatar-view .np-avatar-view-content {
164
167
  color: var(--Button-color);
@@ -168,6 +171,7 @@
168
171
  // Icon styles
169
172
  &-icon {
170
173
  display: inline-block;
174
+ flex-shrink: 0;
171
175
 
172
176
  &--md{
173
177
  --Button-iconSize: 18px;
@@ -202,6 +206,14 @@
202
206
  align-items: center;
203
207
  gap: var(--Button-label-gap);
204
208
  position: relative;
209
+
210
+ // Keep label text visually centered when only one icon addon is present.
211
+ .wds-Button:has(.wds-Button-icon--start):not(:has(.wds-Button-icon--end)) &::after,
212
+ .wds-Button:has(.wds-Button-icon--end):not(:has(.wds-Button-icon--start)) &::before {
213
+ content: '';
214
+ width: var(--Button-iconSpacerSize);
215
+ flex-shrink: 0;
216
+ }
205
217
  }
206
218
 
207
219
  &-loader {
@@ -42,49 +42,6 @@ describe('Nudge', () => {
42
42
  expect(defaultProps.onDismiss).toHaveBeenCalledTimes(1);
43
43
  });
44
44
 
45
- it('renders action only when both action and link/href are supplied', () => {
46
- const consoleWarn = jest.spyOn(console, 'warn').mockImplementation(() => {});
47
-
48
- render(
49
- <Nudge
50
- {...defaultProps}
51
- action={{
52
- text: 'Learn more',
53
- href: '#action-link',
54
- 'aria-label': 'Learn more about rewards',
55
- }}
56
- />,
57
- );
58
-
59
- expect(screen.queryByText('CTA')).not.toBeInTheDocument();
60
-
61
- const actionLink = screen.getByText('Learn more');
62
- expect(actionLink).toBeInTheDocument();
63
- expect(actionLink).toHaveAttribute('href', '#action-link');
64
-
65
- consoleWarn.mockRestore();
66
- });
67
- it('shows a warning in development when both action and link/href are supplied', () => {
68
- const consoleWarn = jest.spyOn(console, 'warn').mockImplementation(() => {});
69
-
70
- render(
71
- <Nudge
72
- {...defaultProps}
73
- action={{
74
- text: 'Learn more',
75
- href: '#action-link',
76
- 'aria-label': 'Learn more about rewards',
77
- }}
78
- />,
79
- );
80
-
81
- expect(consoleWarn).toHaveBeenCalledWith(
82
- 'Nudge received both action and link/href props. Rendering action only. Remove link/href to silence this warning.',
83
- );
84
-
85
- consoleWarn.mockRestore();
86
- });
87
-
88
45
  describe('Nudge persistance', () => {
89
46
  beforeEach(() => {
90
47
  jest.resetAllMocks();
@@ -25,7 +25,7 @@ const getLocalStorage = (): string[] => {
25
25
  return storage.map((item) => String(item));
26
26
  }
27
27
  }
28
- } catch {}
28
+ } catch (error) {}
29
29
 
30
30
  return [];
31
31
  };
@@ -47,41 +47,18 @@ type MediaNameType =
47
47
  | `${Assets.DOCUMENTS}`;
48
48
 
49
49
  type BaseProps = {
50
- /**
51
- * @deprecated Use `mediaName` instead.
52
- * Legacy custom media content is no longer used by `Nudge`.
53
- */
50
+ /** @deprecated Use `mediaName` property instead. */
54
51
  media?: ReactNode;
55
- /**
56
- * Illustration asset name shown at the start of the nudge.
57
- */
52
+ /** Media name */
58
53
  mediaName?: MediaNameType;
59
- /** Main nudge message content. */
60
54
  title: ReactNode;
61
- /**
62
- * Legacy CTA label content.
63
- * Rendered only when `action` is not provided.
64
- */
65
55
  link?: ReactNode;
66
- /**
67
- * Legacy CTA destination for `link`.
68
- * Ignored when `action` is provided.
69
- */
70
56
  href?: string;
71
- /**
72
- * Legacy click handler for `link`.
73
- * Ignored when `action` is provided.
74
- */
75
57
  onClick?: (event?: MouseEvent<HTMLSpanElement>) => void;
76
58
  /** Fired when the user clicks on close button */
77
59
  onDismiss?: () => void;
78
- /**
79
- * Preferred CTA configuration rendered under the nudge body.
80
- * Single CTA rule: when `action` is provided, legacy `link`/`href` is not rendered.
81
- * If your label is short, use `aria-label` to provide more context.
82
- */
60
+ /** An optional call to action to sit under the main body of the nudge. If your label is short, use aria-label to provide more context */
83
61
  action?: AlertAction;
84
- /** Optional class name applied to the root nudge container. */
85
62
  className?: string;
86
63
  };
87
64
 
@@ -120,19 +97,6 @@ const Nudge = ({
120
97
  action,
121
98
  }: NudgeProps) => {
122
99
  const intl = useIntl();
123
- const hasLegacyLink = Boolean(link);
124
- const hasAction = action != null;
125
- const shouldRenderLegacyLink = hasLegacyLink && !hasAction;
126
-
127
- useEffect(() => {
128
- if (process.env.NODE_ENV !== 'production' && hasAction && (hasLegacyLink || href != null)) {
129
- // eslint-disable-next-line no-console -- Intentional developer warning for conflicting API usage.
130
- console.warn(
131
- 'Nudge received both action and link/href props. Rendering action only. Remove link/href to silence this warning.',
132
- );
133
- }
134
- }, [hasAction, hasLegacyLink, href]);
135
-
136
100
  const getIsDismissed = useCallback(
137
101
  () => (persistDismissal && id ? !!getLocalStorage()?.find((item) => item === id) : false),
138
102
  [persistDismissal, id],
@@ -202,7 +166,8 @@ const Nudge = ({
202
166
  <Body type={Typography.BODY_LARGE} className={clsx('wds-nudge-body')}>
203
167
  {title}
204
168
  </Body>
205
- {shouldRenderLegacyLink && (
169
+ {/* Merge these two Link instances into one */}
170
+ {link && (
206
171
  <Link
207
172
  href={href}
208
173
  type={Typography.LINK_LARGE}
package/src/main.css CHANGED
@@ -27121,6 +27121,7 @@ a[data-toggle="tooltip"] {
27121
27121
 
27122
27122
  .wds-Button--medium {
27123
27123
  padding: var(--Button-medium-padding);
27124
+ --Button-iconSpacerSize: 18px;
27124
27125
  }
27125
27126
 
27126
27127
  .wds-Button--medium:has(.wds-Button-avatars) {
@@ -27139,6 +27140,7 @@ a[data-toggle="tooltip"] {
27139
27140
 
27140
27141
  .wds-Button--small {
27141
27142
  padding: var(--Button-small-padding);
27143
+ --Button-iconSpacerSize: 16px;
27142
27144
  }
27143
27145
 
27144
27146
  .wds-Button--small:has(.wds-Button-icon--start) {
@@ -27157,6 +27159,7 @@ a[data-toggle="tooltip"] {
27157
27159
 
27158
27160
  .wds-Button-avatars {
27159
27161
  display: inline-flex;
27162
+ flex-shrink: 0;
27160
27163
  }
27161
27164
 
27162
27165
  .wds-Button-avatars .np-avatar-view .np-avatar-view-content {
@@ -27165,6 +27168,7 @@ a[data-toggle="tooltip"] {
27165
27168
 
27166
27169
  .wds-Button-icon {
27167
27170
  display: inline-block;
27171
+ flex-shrink: 0;
27168
27172
  }
27169
27173
 
27170
27174
  .wds-Button-icon--md {
@@ -27199,6 +27203,13 @@ a[data-toggle="tooltip"] {
27199
27203
  position: relative;
27200
27204
  }
27201
27205
 
27206
+ .wds-Button:has(.wds-Button-icon--start):not(:has(.wds-Button-icon--end)) .wds-Button-label::after,
27207
+ .wds-Button:has(.wds-Button-icon--end):not(:has(.wds-Button-icon--start)) .wds-Button-label::before {
27208
+ content: '';
27209
+ width: var(--Button-iconSpacerSize);
27210
+ flex-shrink: 0;
27211
+ }
27212
+
27202
27213
  .wds-Button-loader {
27203
27214
  position: absolute;
27204
27215
  width: 100%;