@transferwise/components 46.86.2 → 46.87.0
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/main.css +11 -0
- package/build/nudge/Nudge.js.map +1 -1
- package/build/nudge/Nudge.mjs.map +1 -1
- package/build/styles/main.css +11 -0
- package/build/styles/nudge/Nudge.css +11 -0
- package/build/types/nudge/Nudge.d.ts +1 -1
- package/build/types/nudge/Nudge.d.ts.map +1 -1
- package/build/types/uploadInput/uploadButton/getAllowedFileTypes.d.ts.map +1 -1
- package/build/uploadInput/uploadButton/getAllowedFileTypes.js +23 -3
- package/build/uploadInput/uploadButton/getAllowedFileTypes.js.map +1 -1
- package/build/uploadInput/uploadButton/getAllowedFileTypes.mjs +23 -3
- package/build/uploadInput/uploadButton/getAllowedFileTypes.mjs.map +1 -1
- package/package.json +3 -3
- package/src/drawer/Drawer.spec.tsx +93 -0
- package/src/main.css +11 -0
- package/src/nudge/Nudge.css +11 -0
- package/src/nudge/Nudge.less +3 -0
- package/src/nudge/Nudge.story.tsx +10 -0
- package/src/nudge/Nudge.tsx +2 -1
- package/src/uploadInput/UploadInput.tests.story.tsx +5 -5
- package/src/uploadInput/uploadButton/getAllowedFileTypes.spec.ts +12 -0
- package/src/uploadInput/uploadButton/getAllowedFileTypes.ts +33 -7
- package/src/drawer/Drawer.rtl.spec.tsx +0 -59
- package/src/drawer/Drawer.spec.js +0 -101
- package/src/drawer/__snapshots__/Drawer.rtl.spec.tsx.snap +0 -55
package/build/main.css
CHANGED
|
@@ -3689,6 +3689,17 @@ html:not([dir="rtl"]) .np-navigation-option {
|
|
|
3689
3689
|
margin-left: 0;
|
|
3690
3690
|
margin-right: 1px;
|
|
3691
3691
|
}
|
|
3692
|
+
.wds-nudge-media-flower {
|
|
3693
|
+
margin-left: -24px;
|
|
3694
|
+
margin-top: 11px;
|
|
3695
|
+
position: absolute;
|
|
3696
|
+
width: 156px;
|
|
3697
|
+
}
|
|
3698
|
+
[dir="rtl"] .wds-nudge-media-flower {
|
|
3699
|
+
transform: scaleX(-1);
|
|
3700
|
+
margin-left: 0;
|
|
3701
|
+
margin-right: -24px;
|
|
3702
|
+
}
|
|
3692
3703
|
.wds-nudge-container {
|
|
3693
3704
|
align-items: stretch;
|
|
3694
3705
|
display: flex;
|
package/build/nudge/Nudge.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Nudge.js","sources":["../../src/nudge/Nudge.tsx"],"sourcesContent":["import { Illustration, Assets, IllustrationNames } from '@wise/art';\nimport { clsx } from 'clsx';\nimport { ReactNode, useEffect, useState, MouseEvent } from 'react';\n\nimport Body from '../body';\nimport { Typography } from '../common';\nimport { CloseButton } from '../common/closeButton';\nimport Link from '../link';\nimport { Action, ActionOptions } from '../common/action/Action';\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 // eslint-disable-next-line unicorn/prefer-optional-catch-binding, no-empty\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\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?: ActionOptions;\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 Props = OptionalId | RequiredPersistProps;\n\nconst Nudge = ({\n media,\n mediaName,\n title,\n link,\n href,\n onClick,\n onDismiss,\n persistDismissal,\n isPreviouslyDismissed,\n id,\n className,\n action,\n}: Props) => {\n const [isDismissed, setIsDismissed] = useState(false);\n const [isMounted, setIsMounted] = useState(false);\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 // eslint-disable-next-line unicorn/prefer-optional-catch-binding, no-empty\n } catch (error) {}\n\n setIsDismissed(true);\n }\n\n if (onDismiss) {\n onDismiss();\n }\n };\n\n useEffect(() => {\n if (persistDismissal && id) {\n const dismissedNudgesStorage = getLocalStorage();\n let isDismissed = false;\n\n if (dismissedNudgesStorage?.find((item) => item === id)) {\n setIsDismissed(true);\n isDismissed = true;\n }\n\n if (isPreviouslyDismissed) {\n isPreviouslyDismissed(isDismissed);\n }\n }\n\n setIsMounted(true);\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [id, persistDismissal]);\n\n if (persistDismissal && (isDismissed || !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 as IllustrationNames}\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 {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 && <Action action={action} className=\"m-t-1\" />}\n </div>\n {onDismiss || persistDismissal ? (\n <CloseButton className=\"wds-nudge-control\" size=\"sm\" onClick={handleOnDismiss} />\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","media","mediaName","title","link","href","onClick","onDismiss","persistDismissal","isPreviouslyDismissed","id","className","action","isDismissed","setIsDismissed","useState","isMounted","setIsMounted","handleOnDismiss","dismissedNudgesStorage","setItem","stringify","useEffect","find","_jsxs","clsx","children","_jsx","Illustration","name","size","disablePadding","alt","Body","type","Typography","BODY_LARGE","Link","LINK_LARGE","Action","CloseButton"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAWO,MAAMA,YAAY,GAAG,kBAAiB;AAE7C,MAAMC,eAAe,GAAGA,MAAe;EACrC,IAAI;AACF,IAAA,MAAMC,WAAW,GAAGC,YAAY,CAACC,OAAO,CAACJ,YAAY,CAAC,CAAA;AAEtD,IAAA,IAAIE,WAAW,EAAE;AACf,MAAA,MAAMG,OAAO,GAAYC,IAAI,CAACC,KAAK,CAACL,WAAW,CAAC,CAAA;AAEhD,MAAA,IAAIM,KAAK,CAACC,OAAO,CAACJ,OAAO,CAAC,EAAE;QAC1B,OAAOA,OAAO,CAACK,GAAG,CAAEC,IAAI,IAAKC,MAAM,CAACD,IAAI,CAAC,CAAC,CAAA;AAC5C,OAAA;AACF,KAAA;AACA;AACF,GAAC,CAAC,OAAOE,KAAK,EAAE,EAAC;AAEjB,EAAA,OAAO,EAAE,CAAA;AACX,CAAC,CAAA;
|
|
1
|
+
{"version":3,"file":"Nudge.js","sources":["../../src/nudge/Nudge.tsx"],"sourcesContent":["import { Illustration, Assets, IllustrationNames } from '@wise/art';\nimport { clsx } from 'clsx';\nimport { ReactNode, useEffect, useState, MouseEvent } from 'react';\n\nimport Body from '../body';\nimport { Typography } from '../common';\nimport { CloseButton } from '../common/closeButton';\nimport Link from '../link';\nimport { Action, ActionOptions } from '../common/action/Action';\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 // eslint-disable-next-line unicorn/prefer-optional-catch-binding, no-empty\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\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?: ActionOptions;\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 Props = OptionalId | RequiredPersistProps;\n\nconst Nudge = ({\n media,\n mediaName,\n title,\n link,\n href,\n onClick,\n onDismiss,\n persistDismissal,\n isPreviouslyDismissed,\n id,\n className,\n action,\n}: Props) => {\n const [isDismissed, setIsDismissed] = useState(false);\n const [isMounted, setIsMounted] = useState(false);\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 // eslint-disable-next-line unicorn/prefer-optional-catch-binding, no-empty\n } catch (error) {}\n\n setIsDismissed(true);\n }\n\n if (onDismiss) {\n onDismiss();\n }\n };\n\n useEffect(() => {\n if (persistDismissal && id) {\n const dismissedNudgesStorage = getLocalStorage();\n let isDismissed = false;\n\n if (dismissedNudgesStorage?.find((item) => item === id)) {\n setIsDismissed(true);\n isDismissed = true;\n }\n\n if (isPreviouslyDismissed) {\n isPreviouslyDismissed(isDismissed);\n }\n }\n\n setIsMounted(true);\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [id, persistDismissal]);\n\n if (persistDismissal && (isDismissed || !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 as IllustrationNames}\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 {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 && <Action action={action} className=\"m-t-1\" />}\n </div>\n {onDismiss || persistDismissal ? (\n <CloseButton className=\"wds-nudge-control\" size=\"sm\" onClick={handleOnDismiss} />\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","media","mediaName","title","link","href","onClick","onDismiss","persistDismissal","isPreviouslyDismissed","id","className","action","isDismissed","setIsDismissed","useState","isMounted","setIsMounted","handleOnDismiss","dismissedNudgesStorage","setItem","stringify","useEffect","find","_jsxs","clsx","children","_jsx","Illustration","name","size","disablePadding","alt","Body","type","Typography","BODY_LARGE","Link","LINK_LARGE","Action","CloseButton"],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Nudge.mjs","sources":["../../src/nudge/Nudge.tsx"],"sourcesContent":["import { Illustration, Assets, IllustrationNames } from '@wise/art';\nimport { clsx } from 'clsx';\nimport { ReactNode, useEffect, useState, MouseEvent } from 'react';\n\nimport Body from '../body';\nimport { Typography } from '../common';\nimport { CloseButton } from '../common/closeButton';\nimport Link from '../link';\nimport { Action, ActionOptions } from '../common/action/Action';\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 // eslint-disable-next-line unicorn/prefer-optional-catch-binding, no-empty\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\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?: ActionOptions;\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 Props = OptionalId | RequiredPersistProps;\n\nconst Nudge = ({\n media,\n mediaName,\n title,\n link,\n href,\n onClick,\n onDismiss,\n persistDismissal,\n isPreviouslyDismissed,\n id,\n className,\n action,\n}: Props) => {\n const [isDismissed, setIsDismissed] = useState(false);\n const [isMounted, setIsMounted] = useState(false);\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 // eslint-disable-next-line unicorn/prefer-optional-catch-binding, no-empty\n } catch (error) {}\n\n setIsDismissed(true);\n }\n\n if (onDismiss) {\n onDismiss();\n }\n };\n\n useEffect(() => {\n if (persistDismissal && id) {\n const dismissedNudgesStorage = getLocalStorage();\n let isDismissed = false;\n\n if (dismissedNudgesStorage?.find((item) => item === id)) {\n setIsDismissed(true);\n isDismissed = true;\n }\n\n if (isPreviouslyDismissed) {\n isPreviouslyDismissed(isDismissed);\n }\n }\n\n setIsMounted(true);\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [id, persistDismissal]);\n\n if (persistDismissal && (isDismissed || !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 as IllustrationNames}\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 {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 && <Action action={action} className=\"m-t-1\" />}\n </div>\n {onDismiss || persistDismissal ? (\n <CloseButton className=\"wds-nudge-control\" size=\"sm\" onClick={handleOnDismiss} />\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","media","mediaName","title","link","href","onClick","onDismiss","persistDismissal","isPreviouslyDismissed","id","className","action","isDismissed","setIsDismissed","useState","isMounted","setIsMounted","handleOnDismiss","dismissedNudgesStorage","setItem","stringify","useEffect","find","_jsxs","clsx","children","_jsx","Illustration","name","size","disablePadding","alt","Body","type","Typography","BODY_LARGE","Link","LINK_LARGE","Action","CloseButton"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;AAWO,MAAMA,YAAY,GAAG,kBAAiB;AAE7C,MAAMC,eAAe,GAAGA,MAAe;EACrC,IAAI;AACF,IAAA,MAAMC,WAAW,GAAGC,YAAY,CAACC,OAAO,CAACJ,YAAY,CAAC,CAAA;AAEtD,IAAA,IAAIE,WAAW,EAAE;AACf,MAAA,MAAMG,OAAO,GAAYC,IAAI,CAACC,KAAK,CAACL,WAAW,CAAC,CAAA;AAEhD,MAAA,IAAIM,KAAK,CAACC,OAAO,CAACJ,OAAO,CAAC,EAAE;QAC1B,OAAOA,OAAO,CAACK,GAAG,CAAEC,IAAI,IAAKC,MAAM,CAACD,IAAI,CAAC,CAAC,CAAA;AAC5C,OAAA;AACF,KAAA;AACA;AACF,GAAC,CAAC,OAAOE,KAAK,EAAE,EAAC;AAEjB,EAAA,OAAO,EAAE,CAAA;AACX,CAAC,CAAA;
|
|
1
|
+
{"version":3,"file":"Nudge.mjs","sources":["../../src/nudge/Nudge.tsx"],"sourcesContent":["import { Illustration, Assets, IllustrationNames } from '@wise/art';\nimport { clsx } from 'clsx';\nimport { ReactNode, useEffect, useState, MouseEvent } from 'react';\n\nimport Body from '../body';\nimport { Typography } from '../common';\nimport { CloseButton } from '../common/closeButton';\nimport Link from '../link';\nimport { Action, ActionOptions } from '../common/action/Action';\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 // eslint-disable-next-line unicorn/prefer-optional-catch-binding, no-empty\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\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?: ActionOptions;\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 Props = OptionalId | RequiredPersistProps;\n\nconst Nudge = ({\n media,\n mediaName,\n title,\n link,\n href,\n onClick,\n onDismiss,\n persistDismissal,\n isPreviouslyDismissed,\n id,\n className,\n action,\n}: Props) => {\n const [isDismissed, setIsDismissed] = useState(false);\n const [isMounted, setIsMounted] = useState(false);\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 // eslint-disable-next-line unicorn/prefer-optional-catch-binding, no-empty\n } catch (error) {}\n\n setIsDismissed(true);\n }\n\n if (onDismiss) {\n onDismiss();\n }\n };\n\n useEffect(() => {\n if (persistDismissal && id) {\n const dismissedNudgesStorage = getLocalStorage();\n let isDismissed = false;\n\n if (dismissedNudgesStorage?.find((item) => item === id)) {\n setIsDismissed(true);\n isDismissed = true;\n }\n\n if (isPreviouslyDismissed) {\n isPreviouslyDismissed(isDismissed);\n }\n }\n\n setIsMounted(true);\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [id, persistDismissal]);\n\n if (persistDismissal && (isDismissed || !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 as IllustrationNames}\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 {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 && <Action action={action} className=\"m-t-1\" />}\n </div>\n {onDismiss || persistDismissal ? (\n <CloseButton className=\"wds-nudge-control\" size=\"sm\" onClick={handleOnDismiss} />\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","media","mediaName","title","link","href","onClick","onDismiss","persistDismissal","isPreviouslyDismissed","id","className","action","isDismissed","setIsDismissed","useState","isMounted","setIsMounted","handleOnDismiss","dismissedNudgesStorage","setItem","stringify","useEffect","find","_jsxs","clsx","children","_jsx","Illustration","name","size","disablePadding","alt","Body","type","Typography","BODY_LARGE","Link","LINK_LARGE","Action","CloseButton"],"mappings":"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"}
|
package/build/styles/main.css
CHANGED
|
@@ -3689,6 +3689,17 @@ html:not([dir="rtl"]) .np-navigation-option {
|
|
|
3689
3689
|
margin-left: 0;
|
|
3690
3690
|
margin-right: 1px;
|
|
3691
3691
|
}
|
|
3692
|
+
.wds-nudge-media-flower {
|
|
3693
|
+
margin-left: -24px;
|
|
3694
|
+
margin-top: 11px;
|
|
3695
|
+
position: absolute;
|
|
3696
|
+
width: 156px;
|
|
3697
|
+
}
|
|
3698
|
+
[dir="rtl"] .wds-nudge-media-flower {
|
|
3699
|
+
transform: scaleX(-1);
|
|
3700
|
+
margin-left: 0;
|
|
3701
|
+
margin-right: -24px;
|
|
3702
|
+
}
|
|
3692
3703
|
.wds-nudge-container {
|
|
3693
3704
|
align-items: stretch;
|
|
3694
3705
|
display: flex;
|
|
@@ -136,6 +136,17 @@
|
|
|
136
136
|
margin-left: 0;
|
|
137
137
|
margin-right: 1px;
|
|
138
138
|
}
|
|
139
|
+
.wds-nudge-media-flower {
|
|
140
|
+
margin-left: -24px;
|
|
141
|
+
margin-top: 11px;
|
|
142
|
+
position: absolute;
|
|
143
|
+
width: 156px;
|
|
144
|
+
}
|
|
145
|
+
[dir="rtl"] .wds-nudge-media-flower {
|
|
146
|
+
transform: scaleX(-1);
|
|
147
|
+
margin-left: 0;
|
|
148
|
+
margin-right: -24px;
|
|
149
|
+
}
|
|
139
150
|
.wds-nudge-container {
|
|
140
151
|
align-items: stretch;
|
|
141
152
|
display: flex;
|
|
@@ -2,7 +2,7 @@ import { Assets } from '@wise/art';
|
|
|
2
2
|
import { ReactNode, MouseEvent } from 'react';
|
|
3
3
|
import { ActionOptions } from '../common/action/Action';
|
|
4
4
|
export declare const STORAGE_NAME = "dismissedNudges";
|
|
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}`;
|
|
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}`;
|
|
6
6
|
type BaseProps = {
|
|
7
7
|
/** @deprecated use `mediaName` property instead */
|
|
8
8
|
media?: ReactNode;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Nudge.d.ts","sourceRoot":"","sources":["../../../src/nudge/Nudge.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAgB,MAAM,EAAqB,MAAM,WAAW,CAAC;AAEpE,OAAO,EAAE,SAAS,EAAuB,UAAU,EAAE,MAAM,OAAO,CAAC;AAMnE,OAAO,EAAU,aAAa,EAAE,MAAM,yBAAyB,CAAC;AAGhE,eAAO,MAAM,YAAY,oBAAoB,CAAC;AAmB9C,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,CAAC;
|
|
1
|
+
{"version":3,"file":"Nudge.d.ts","sourceRoot":"","sources":["../../../src/nudge/Nudge.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAgB,MAAM,EAAqB,MAAM,WAAW,CAAC;AAEpE,OAAO,EAAE,SAAS,EAAuB,UAAU,EAAE,MAAM,OAAO,CAAC;AAMnE,OAAO,EAAU,aAAa,EAAE,MAAM,yBAAyB,CAAC;AAGhE,eAAO,MAAM,YAAY,oBAAoB,CAAC;AAmB9C,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,CAAC;AAEvB,KAAK,SAAS,GAAG;IACf,mDAAmD;IACnD,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,aAAa,CAAC;IACvB,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,KAAK,GAAG,UAAU,GAAG,oBAAoB,CAAC;AAEtD,QAAA,MAAM,KAAK,iIAaR,KAAK,uCAgFP,CAAC;AAEF,eAAe,KAAK,CAAC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"getAllowedFileTypes.d.ts","sourceRoot":"","sources":["../../../../src/uploadInput/uploadButton/getAllowedFileTypes.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,cAAc,CAAC;
|
|
1
|
+
{"version":3,"file":"getAllowedFileTypes.d.ts","sourceRoot":"","sources":["../../../../src/uploadInput/uploadButton/getAllowedFileTypes.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,cAAc,CAAC;AAqBxC,QAAA,MAAM,mBAAmB,cAAe,SAAS,QAAQ,EAAE,GAAG,SAAS,MAAM,EAAE,KAAG,MAAM,EAcpF,CAAC;AAEL,eAAe,mBAAmB,CAAC"}
|
|
@@ -1,8 +1,28 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
-
const
|
|
4
|
-
|
|
5
|
-
.
|
|
3
|
+
const parseFileType = fileType => {
|
|
4
|
+
if (fileType?.includes('.')) {
|
|
5
|
+
return fileType.replace('.', '').toUpperCase();
|
|
6
|
+
}
|
|
7
|
+
const mimeType = fileType?.split('/');
|
|
8
|
+
if (mimeType?.length > 1) {
|
|
9
|
+
let parsedType = mimeType[1];
|
|
10
|
+
if (parsedType.toLocaleLowerCase() === 'jpeg') {
|
|
11
|
+
parsedType = 'jpg, '.concat(parsedType).toUpperCase();
|
|
12
|
+
}
|
|
13
|
+
return parsedType.toUpperCase();
|
|
14
|
+
}
|
|
15
|
+
return fileType;
|
|
16
|
+
};
|
|
17
|
+
const getAllowedFileTypes = fileTypes => fileTypes.map(fileType => {
|
|
18
|
+
const splittedFileTypes = fileType?.split(',');
|
|
19
|
+
if (splittedFileTypes?.length > 1) {
|
|
20
|
+
// If `fileType` contains `format` and `mime` types, remove mime types, proceed only with format types
|
|
21
|
+
return splittedFileTypes.filter(splittedFileType => !splittedFileType?.includes('/')).map(splittedFileType => parseFileType(splittedFileType)).join(', ');
|
|
22
|
+
}
|
|
23
|
+
// If `fileType` contains only `format` or `mime` type, parse the type
|
|
24
|
+
return parseFileType(fileType);
|
|
25
|
+
});
|
|
6
26
|
|
|
7
27
|
module.exports = getAllowedFileTypes;
|
|
8
28
|
//# sourceMappingURL=getAllowedFileTypes.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"getAllowedFileTypes.js","sources":["../../../src/uploadInput/uploadButton/getAllowedFileTypes.ts"],"sourcesContent":["import { FileType } from '../../common';\n\nconst getAllowedFileTypes = (fileTypes: readonly FileType[] | readonly string[]): string[] =>\n fileTypes.map((
|
|
1
|
+
{"version":3,"file":"getAllowedFileTypes.js","sources":["../../../src/uploadInput/uploadButton/getAllowedFileTypes.ts"],"sourcesContent":["import { FileType } from '../../common';\n\nconst parseFileType = (fileType: string): string => {\n if (fileType?.includes('.')) {\n return fileType.replace('.', '').toUpperCase();\n }\n\n const mimeType = fileType?.split('/');\n if (mimeType?.length > 1) {\n let parsedType = mimeType[1];\n\n if (parsedType.toLocaleLowerCase() === 'jpeg') {\n parsedType = 'jpg, '.concat(parsedType).toUpperCase();\n }\n\n return parsedType.toUpperCase();\n }\n\n return fileType;\n};\n\nconst getAllowedFileTypes = (fileTypes: readonly FileType[] | readonly string[]): string[] =>\n fileTypes.map((fileType: string) => {\n const splittedFileTypes = fileType?.split(',');\n\n if (splittedFileTypes?.length > 1) {\n // If `fileType` contains `format` and `mime` types, remove mime types, proceed only with format types\n return splittedFileTypes\n .filter((splittedFileType: string) => !splittedFileType?.includes('/'))\n .map((splittedFileType: string) => parseFileType(splittedFileType))\n .join(', ');\n }\n\n // If `fileType` contains only `format` or `mime` type, parse the type\n return parseFileType(fileType);\n });\n\nexport default getAllowedFileTypes;\n"],"names":["parseFileType","fileType","includes","replace","toUpperCase","mimeType","split","length","parsedType","toLocaleLowerCase","concat","getAllowedFileTypes","fileTypes","map","splittedFileTypes","filter","splittedFileType","join"],"mappings":";;AAEA,MAAMA,aAAa,GAAIC,QAAgB,IAAY;AACjD,EAAA,IAAIA,QAAQ,EAAEC,QAAQ,CAAC,GAAG,CAAC,EAAE;IAC3B,OAAOD,QAAQ,CAACE,OAAO,CAAC,GAAG,EAAE,EAAE,CAAC,CAACC,WAAW,EAAE,CAAA;AAChD,GAAA;AAEA,EAAA,MAAMC,QAAQ,GAAGJ,QAAQ,EAAEK,KAAK,CAAC,GAAG,CAAC,CAAA;AACrC,EAAA,IAAID,QAAQ,EAAEE,MAAM,GAAG,CAAC,EAAE;AACxB,IAAA,IAAIC,UAAU,GAAGH,QAAQ,CAAC,CAAC,CAAC,CAAA;AAE5B,IAAA,IAAIG,UAAU,CAACC,iBAAiB,EAAE,KAAK,MAAM,EAAE;MAC7CD,UAAU,GAAG,OAAO,CAACE,MAAM,CAACF,UAAU,CAAC,CAACJ,WAAW,EAAE,CAAA;AACvD,KAAA;AAEA,IAAA,OAAOI,UAAU,CAACJ,WAAW,EAAE,CAAA;AACjC,GAAA;AAEA,EAAA,OAAOH,QAAQ,CAAA;AACjB,CAAC,CAAA;AAEKU,MAAAA,mBAAmB,GAAIC,SAAkD,IAC7EA,SAAS,CAACC,GAAG,CAAEZ,QAAgB,IAAI;AACjC,EAAA,MAAMa,iBAAiB,GAAGb,QAAQ,EAAEK,KAAK,CAAC,GAAG,CAAC,CAAA;AAE9C,EAAA,IAAIQ,iBAAiB,EAAEP,MAAM,GAAG,CAAC,EAAE;AACjC;AACA,IAAA,OAAOO,iBAAiB,CACrBC,MAAM,CAAEC,gBAAwB,IAAK,CAACA,gBAAgB,EAAEd,QAAQ,CAAC,GAAG,CAAC,CAAC,CACtEW,GAAG,CAAEG,gBAAwB,IAAKhB,aAAa,CAACgB,gBAAgB,CAAC,CAAC,CAClEC,IAAI,CAAC,IAAI,CAAC,CAAA;AACf,GAAA;AAEA;EACA,OAAOjB,aAAa,CAACC,QAAQ,CAAC,CAAA;AAChC,CAAC;;;;"}
|
|
@@ -1,6 +1,26 @@
|
|
|
1
|
-
const
|
|
2
|
-
|
|
3
|
-
.
|
|
1
|
+
const parseFileType = fileType => {
|
|
2
|
+
if (fileType?.includes('.')) {
|
|
3
|
+
return fileType.replace('.', '').toUpperCase();
|
|
4
|
+
}
|
|
5
|
+
const mimeType = fileType?.split('/');
|
|
6
|
+
if (mimeType?.length > 1) {
|
|
7
|
+
let parsedType = mimeType[1];
|
|
8
|
+
if (parsedType.toLocaleLowerCase() === 'jpeg') {
|
|
9
|
+
parsedType = 'jpg, '.concat(parsedType).toUpperCase();
|
|
10
|
+
}
|
|
11
|
+
return parsedType.toUpperCase();
|
|
12
|
+
}
|
|
13
|
+
return fileType;
|
|
14
|
+
};
|
|
15
|
+
const getAllowedFileTypes = fileTypes => fileTypes.map(fileType => {
|
|
16
|
+
const splittedFileTypes = fileType?.split(',');
|
|
17
|
+
if (splittedFileTypes?.length > 1) {
|
|
18
|
+
// If `fileType` contains `format` and `mime` types, remove mime types, proceed only with format types
|
|
19
|
+
return splittedFileTypes.filter(splittedFileType => !splittedFileType?.includes('/')).map(splittedFileType => parseFileType(splittedFileType)).join(', ');
|
|
20
|
+
}
|
|
21
|
+
// If `fileType` contains only `format` or `mime` type, parse the type
|
|
22
|
+
return parseFileType(fileType);
|
|
23
|
+
});
|
|
4
24
|
|
|
5
25
|
export { getAllowedFileTypes as default };
|
|
6
26
|
//# sourceMappingURL=getAllowedFileTypes.mjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"getAllowedFileTypes.mjs","sources":["../../../src/uploadInput/uploadButton/getAllowedFileTypes.ts"],"sourcesContent":["import { FileType } from '../../common';\n\nconst getAllowedFileTypes = (fileTypes: readonly FileType[] | readonly string[]): string[] =>\n fileTypes.map((
|
|
1
|
+
{"version":3,"file":"getAllowedFileTypes.mjs","sources":["../../../src/uploadInput/uploadButton/getAllowedFileTypes.ts"],"sourcesContent":["import { FileType } from '../../common';\n\nconst parseFileType = (fileType: string): string => {\n if (fileType?.includes('.')) {\n return fileType.replace('.', '').toUpperCase();\n }\n\n const mimeType = fileType?.split('/');\n if (mimeType?.length > 1) {\n let parsedType = mimeType[1];\n\n if (parsedType.toLocaleLowerCase() === 'jpeg') {\n parsedType = 'jpg, '.concat(parsedType).toUpperCase();\n }\n\n return parsedType.toUpperCase();\n }\n\n return fileType;\n};\n\nconst getAllowedFileTypes = (fileTypes: readonly FileType[] | readonly string[]): string[] =>\n fileTypes.map((fileType: string) => {\n const splittedFileTypes = fileType?.split(',');\n\n if (splittedFileTypes?.length > 1) {\n // If `fileType` contains `format` and `mime` types, remove mime types, proceed only with format types\n return splittedFileTypes\n .filter((splittedFileType: string) => !splittedFileType?.includes('/'))\n .map((splittedFileType: string) => parseFileType(splittedFileType))\n .join(', ');\n }\n\n // If `fileType` contains only `format` or `mime` type, parse the type\n return parseFileType(fileType);\n });\n\nexport default getAllowedFileTypes;\n"],"names":["parseFileType","fileType","includes","replace","toUpperCase","mimeType","split","length","parsedType","toLocaleLowerCase","concat","getAllowedFileTypes","fileTypes","map","splittedFileTypes","filter","splittedFileType","join"],"mappings":"AAEA,MAAMA,aAAa,GAAIC,QAAgB,IAAY;AACjD,EAAA,IAAIA,QAAQ,EAAEC,QAAQ,CAAC,GAAG,CAAC,EAAE;IAC3B,OAAOD,QAAQ,CAACE,OAAO,CAAC,GAAG,EAAE,EAAE,CAAC,CAACC,WAAW,EAAE,CAAA;AAChD,GAAA;AAEA,EAAA,MAAMC,QAAQ,GAAGJ,QAAQ,EAAEK,KAAK,CAAC,GAAG,CAAC,CAAA;AACrC,EAAA,IAAID,QAAQ,EAAEE,MAAM,GAAG,CAAC,EAAE;AACxB,IAAA,IAAIC,UAAU,GAAGH,QAAQ,CAAC,CAAC,CAAC,CAAA;AAE5B,IAAA,IAAIG,UAAU,CAACC,iBAAiB,EAAE,KAAK,MAAM,EAAE;MAC7CD,UAAU,GAAG,OAAO,CAACE,MAAM,CAACF,UAAU,CAAC,CAACJ,WAAW,EAAE,CAAA;AACvD,KAAA;AAEA,IAAA,OAAOI,UAAU,CAACJ,WAAW,EAAE,CAAA;AACjC,GAAA;AAEA,EAAA,OAAOH,QAAQ,CAAA;AACjB,CAAC,CAAA;AAEKU,MAAAA,mBAAmB,GAAIC,SAAkD,IAC7EA,SAAS,CAACC,GAAG,CAAEZ,QAAgB,IAAI;AACjC,EAAA,MAAMa,iBAAiB,GAAGb,QAAQ,EAAEK,KAAK,CAAC,GAAG,CAAC,CAAA;AAE9C,EAAA,IAAIQ,iBAAiB,EAAEP,MAAM,GAAG,CAAC,EAAE;AACjC;AACA,IAAA,OAAOO,iBAAiB,CACrBC,MAAM,CAAEC,gBAAwB,IAAK,CAACA,gBAAgB,EAAEd,QAAQ,CAAC,GAAG,CAAC,CAAC,CACtEW,GAAG,CAAEG,gBAAwB,IAAKhB,aAAa,CAACgB,gBAAgB,CAAC,CAAC,CAClEC,IAAI,CAAC,IAAI,CAAC,CAAA;AACf,GAAA;AAEA;EACA,OAAOjB,aAAa,CAACC,QAAQ,CAAC,CAAA;AAChC,CAAC;;;;"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@transferwise/components",
|
|
3
|
-
"version": "46.
|
|
3
|
+
"version": "46.87.0",
|
|
4
4
|
"description": "Neptune React components",
|
|
5
5
|
"license": "Apache-2.0",
|
|
6
6
|
"repository": {
|
|
@@ -92,8 +92,8 @@
|
|
|
92
92
|
"rollup-preserve-directives": "^1.1.1",
|
|
93
93
|
"storybook": "^8.2.2",
|
|
94
94
|
"@transferwise/less-config": "3.1.0",
|
|
95
|
-
"@
|
|
96
|
-
"@
|
|
95
|
+
"@transferwise/neptune-css": "14.20.1",
|
|
96
|
+
"@wise/components-theming": "1.6.1"
|
|
97
97
|
},
|
|
98
98
|
"peerDependencies": {
|
|
99
99
|
"@transferwise/icons": "^3.13.1",
|
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
import { render, screen, userEvent, mockMatchMedia } from '../test-utils';
|
|
2
|
+
import { Position } from '../common';
|
|
3
|
+
|
|
4
|
+
import Drawer from './Drawer';
|
|
5
|
+
|
|
6
|
+
jest.mock('../common/DOMOperations');
|
|
7
|
+
mockMatchMedia();
|
|
8
|
+
|
|
9
|
+
describe('Drawer', () => {
|
|
10
|
+
const renderedComponent = (props: React.ComponentProps<typeof Drawer>) =>
|
|
11
|
+
render(<Drawer {...props} />);
|
|
12
|
+
|
|
13
|
+
const props = {
|
|
14
|
+
open: true,
|
|
15
|
+
onClose: jest.fn(),
|
|
16
|
+
headerTitle: 'Drawer Title',
|
|
17
|
+
footerContent: <div>Footer Content</div>,
|
|
18
|
+
children: <p>Drawer Content</p>,
|
|
19
|
+
className: 'drawer-class',
|
|
20
|
+
};
|
|
21
|
+
|
|
22
|
+
beforeEach(() => {
|
|
23
|
+
jest.clearAllMocks();
|
|
24
|
+
});
|
|
25
|
+
|
|
26
|
+
it('renders the Drawer component', () => {
|
|
27
|
+
renderedComponent(props);
|
|
28
|
+
expect(screen.getByRole('dialog')).toBeInTheDocument();
|
|
29
|
+
});
|
|
30
|
+
|
|
31
|
+
it('renders the header title', () => {
|
|
32
|
+
renderedComponent(props);
|
|
33
|
+
expect(screen.getByText('Drawer Title')).toBeInTheDocument();
|
|
34
|
+
});
|
|
35
|
+
|
|
36
|
+
it('renders the footer content', () => {
|
|
37
|
+
renderedComponent(props);
|
|
38
|
+
expect(screen.getByText('Footer Content')).toBeInTheDocument();
|
|
39
|
+
});
|
|
40
|
+
|
|
41
|
+
it('renders the children content', () => {
|
|
42
|
+
renderedComponent(props);
|
|
43
|
+
expect(screen.getByText('Drawer Content')).toBeInTheDocument();
|
|
44
|
+
});
|
|
45
|
+
|
|
46
|
+
it('passes through the className prop', () => {
|
|
47
|
+
renderedComponent({ ...props, className: 'drawer-class' });
|
|
48
|
+
expect(screen.getByRole('dialog')).toHaveClass('drawer-class');
|
|
49
|
+
});
|
|
50
|
+
|
|
51
|
+
it('calls onClose when the close button is clicked', async () => {
|
|
52
|
+
renderedComponent(props);
|
|
53
|
+
await userEvent.click(screen.getByLabelText('Close'));
|
|
54
|
+
expect(props.onClose).toHaveBeenCalled();
|
|
55
|
+
});
|
|
56
|
+
|
|
57
|
+
it('calls onClose if the dimmer is clicked', async () => {
|
|
58
|
+
render(<Drawer {...props} />);
|
|
59
|
+
await userEvent.click(screen.getByRole('button'));
|
|
60
|
+
expect(props.onClose).toHaveBeenCalledTimes(1);
|
|
61
|
+
});
|
|
62
|
+
|
|
63
|
+
it('does not call onClose if the drawer content is clicked', async () => {
|
|
64
|
+
render(<Drawer {...props}>Drawer Content</Drawer>);
|
|
65
|
+
await userEvent.click(screen.getByText('Drawer Content'));
|
|
66
|
+
expect(props.onClose).not.toHaveBeenCalled();
|
|
67
|
+
});
|
|
68
|
+
|
|
69
|
+
it('does not render the Drawer when open is false', () => {
|
|
70
|
+
renderedComponent({ ...props, open: false });
|
|
71
|
+
expect(screen.queryByRole('dialog')).not.toBeInTheDocument();
|
|
72
|
+
});
|
|
73
|
+
|
|
74
|
+
it('renders the Drawer with the correct aria-labelledby attribute', () => {
|
|
75
|
+
renderedComponent(props);
|
|
76
|
+
expect(screen.getByRole('dialog')).toHaveAttribute('aria-labelledby');
|
|
77
|
+
});
|
|
78
|
+
|
|
79
|
+
it('renders the Drawer with the correct position', () => {
|
|
80
|
+
renderedComponent({ ...props, position: Position.LEFT });
|
|
81
|
+
expect(screen.getByRole('dialog').parentElement).toHaveClass('sliding-panel--open-left');
|
|
82
|
+
});
|
|
83
|
+
|
|
84
|
+
it('renders the Drawer with the correct role attribute', () => {
|
|
85
|
+
renderedComponent(props);
|
|
86
|
+
expect(screen.getByRole('dialog')).toHaveAttribute('role', 'dialog');
|
|
87
|
+
});
|
|
88
|
+
|
|
89
|
+
it('renders the Drawer with the correct aria-modal attribute', () => {
|
|
90
|
+
renderedComponent(props);
|
|
91
|
+
expect(screen.getByRole('dialog')).toHaveAttribute('aria-modal', 'true');
|
|
92
|
+
});
|
|
93
|
+
});
|
package/src/main.css
CHANGED
|
@@ -3689,6 +3689,17 @@ html:not([dir="rtl"]) .np-navigation-option {
|
|
|
3689
3689
|
margin-left: 0;
|
|
3690
3690
|
margin-right: 1px;
|
|
3691
3691
|
}
|
|
3692
|
+
.wds-nudge-media-flower {
|
|
3693
|
+
margin-left: -24px;
|
|
3694
|
+
margin-top: 11px;
|
|
3695
|
+
position: absolute;
|
|
3696
|
+
width: 156px;
|
|
3697
|
+
}
|
|
3698
|
+
[dir="rtl"] .wds-nudge-media-flower {
|
|
3699
|
+
transform: scaleX(-1);
|
|
3700
|
+
margin-left: 0;
|
|
3701
|
+
margin-right: -24px;
|
|
3702
|
+
}
|
|
3692
3703
|
.wds-nudge-container {
|
|
3693
3704
|
align-items: stretch;
|
|
3694
3705
|
display: flex;
|
package/src/nudge/Nudge.css
CHANGED
|
@@ -136,6 +136,17 @@
|
|
|
136
136
|
margin-left: 0;
|
|
137
137
|
margin-right: 1px;
|
|
138
138
|
}
|
|
139
|
+
.wds-nudge-media-flower {
|
|
140
|
+
margin-left: -24px;
|
|
141
|
+
margin-top: 11px;
|
|
142
|
+
position: absolute;
|
|
143
|
+
width: 156px;
|
|
144
|
+
}
|
|
145
|
+
[dir="rtl"] .wds-nudge-media-flower {
|
|
146
|
+
transform: scaleX(-1);
|
|
147
|
+
margin-left: 0;
|
|
148
|
+
margin-right: -24px;
|
|
149
|
+
}
|
|
139
150
|
.wds-nudge-container {
|
|
140
151
|
align-items: stretch;
|
|
141
152
|
display: flex;
|
package/src/nudge/Nudge.less
CHANGED
|
@@ -104,6 +104,16 @@ export const Default = () => {
|
|
|
104
104
|
onClick={action('action clicked')}
|
|
105
105
|
onDismiss={action('dismissed')}
|
|
106
106
|
/>
|
|
107
|
+
|
|
108
|
+
<Nudge
|
|
109
|
+
mediaName={Assets.FLOWER}
|
|
110
|
+
className="m-b-2"
|
|
111
|
+
title="Text that is no longer than two lines."
|
|
112
|
+
link="Link"
|
|
113
|
+
href="#"
|
|
114
|
+
onClick={action('action clicked')}
|
|
115
|
+
onDismiss={action('dismissed')}
|
|
116
|
+
/>
|
|
107
117
|
</div>
|
|
108
118
|
);
|
|
109
119
|
};
|
package/src/nudge/Nudge.tsx
CHANGED
|
@@ -38,7 +38,8 @@ type MediaNameType =
|
|
|
38
38
|
| `${Assets.BUSINESS_CARD}`
|
|
39
39
|
| `${Assets.HEART}`
|
|
40
40
|
| `${Assets.MULTI_CURRENCY}`
|
|
41
|
-
| `${Assets.SHOPPING_BAG}
|
|
41
|
+
| `${Assets.SHOPPING_BAG}`
|
|
42
|
+
| `${Assets.FLOWER}`;
|
|
42
43
|
|
|
43
44
|
type BaseProps = {
|
|
44
45
|
/** @deprecated use `mediaName` property instead */
|
|
@@ -4,7 +4,7 @@ import { Meta, StoryObj } from '@storybook/react';
|
|
|
4
4
|
import { Status } from '../common';
|
|
5
5
|
import UploadInput, { UploadInputProps } from './UploadInput';
|
|
6
6
|
import { UploadedFile, UploadResponse } from './types';
|
|
7
|
-
import { userEvent
|
|
7
|
+
import { userEvent } from '@storybook/test';
|
|
8
8
|
|
|
9
9
|
const meta: Meta<typeof UploadInput> = {
|
|
10
10
|
title: 'Forms/UploadInput/Tests',
|
|
@@ -65,8 +65,8 @@ const createDelayedPromise = async ({
|
|
|
65
65
|
});
|
|
66
66
|
|
|
67
67
|
const props = {
|
|
68
|
-
onUploadFile: async (
|
|
69
|
-
onDeleteFile: async (
|
|
68
|
+
onUploadFile: async () => createDelayedPromise(),
|
|
69
|
+
onDeleteFile: async () => createDelayedPromise(),
|
|
70
70
|
};
|
|
71
71
|
|
|
72
72
|
export const UploadInputWithDescriptionFromProps: Story = {
|
|
@@ -268,7 +268,7 @@ export const DeletingTop: Story = {
|
|
|
268
268
|
files: [files[0], files[1], files[2]],
|
|
269
269
|
multiple: true,
|
|
270
270
|
},
|
|
271
|
-
play: async (
|
|
271
|
+
play: async () => {
|
|
272
272
|
await userEvent.tab();
|
|
273
273
|
await triggerModalAndConfirm();
|
|
274
274
|
await triggerModalAndConfirm({ isLink: false });
|
|
@@ -282,7 +282,7 @@ export const DeletingBottom: Story = {
|
|
|
282
282
|
files: [files[0], files[1], files[2]],
|
|
283
283
|
multiple: true,
|
|
284
284
|
},
|
|
285
|
-
play: async (
|
|
285
|
+
play: async () => {
|
|
286
286
|
await userEvent.tab();
|
|
287
287
|
await userEvent.tab();
|
|
288
288
|
await userEvent.tab();
|
|
@@ -38,4 +38,16 @@ describe('getAllowedFileTypes', () => {
|
|
|
38
38
|
expect(allowedFileTypes).toStrictEqual(['*']);
|
|
39
39
|
});
|
|
40
40
|
});
|
|
41
|
+
|
|
42
|
+
describe('using only mime types', () => {
|
|
43
|
+
const mimeTypes = ['application/json', 'image/jpeg'];
|
|
44
|
+
|
|
45
|
+
beforeAll(() => {
|
|
46
|
+
allowedFileTypes = getAllowedFileTypes(mimeTypes);
|
|
47
|
+
});
|
|
48
|
+
|
|
49
|
+
it('returns the original mime types', () => {
|
|
50
|
+
expect(allowedFileTypes).toStrictEqual(['JSON', 'JPG, JPEG']);
|
|
51
|
+
});
|
|
52
|
+
});
|
|
41
53
|
});
|
|
@@ -1,12 +1,38 @@
|
|
|
1
1
|
import { FileType } from '../../common';
|
|
2
2
|
|
|
3
|
+
const parseFileType = (fileType: string): string => {
|
|
4
|
+
if (fileType?.includes('.')) {
|
|
5
|
+
return fileType.replace('.', '').toUpperCase();
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
const mimeType = fileType?.split('/');
|
|
9
|
+
if (mimeType?.length > 1) {
|
|
10
|
+
let parsedType = mimeType[1];
|
|
11
|
+
|
|
12
|
+
if (parsedType.toLocaleLowerCase() === 'jpeg') {
|
|
13
|
+
parsedType = 'jpg, '.concat(parsedType).toUpperCase();
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
return parsedType.toUpperCase();
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
return fileType;
|
|
20
|
+
};
|
|
21
|
+
|
|
3
22
|
const getAllowedFileTypes = (fileTypes: readonly FileType[] | readonly string[]): string[] =>
|
|
4
|
-
fileTypes.map((
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
23
|
+
fileTypes.map((fileType: string) => {
|
|
24
|
+
const splittedFileTypes = fileType?.split(',');
|
|
25
|
+
|
|
26
|
+
if (splittedFileTypes?.length > 1) {
|
|
27
|
+
// If `fileType` contains `format` and `mime` types, remove mime types, proceed only with format types
|
|
28
|
+
return splittedFileTypes
|
|
29
|
+
.filter((splittedFileType: string) => !splittedFileType?.includes('/'))
|
|
30
|
+
.map((splittedFileType: string) => parseFileType(splittedFileType))
|
|
31
|
+
.join(', ');
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
// If `fileType` contains only `format` or `mime` type, parse the type
|
|
35
|
+
return parseFileType(fileType);
|
|
36
|
+
});
|
|
11
37
|
|
|
12
38
|
export default getAllowedFileTypes;
|
|
@@ -1,59 +0,0 @@
|
|
|
1
|
-
import { DimmerProps } from '../dimmer';
|
|
2
|
-
import { SlidingPanelProps } from '../slidingPanel';
|
|
3
|
-
import { mockMatchMedia, render, screen, userEvent } from '../test-utils';
|
|
4
|
-
|
|
5
|
-
import Drawer from './Drawer';
|
|
6
|
-
|
|
7
|
-
mockMatchMedia();
|
|
8
|
-
|
|
9
|
-
jest.mock(
|
|
10
|
-
'../dimmer',
|
|
11
|
-
() =>
|
|
12
|
-
function Dimmer({ open, children }: DimmerProps) {
|
|
13
|
-
return open ? <div className="dimmer">{children}</div> : null;
|
|
14
|
-
},
|
|
15
|
-
);
|
|
16
|
-
|
|
17
|
-
jest.mock(
|
|
18
|
-
'../slidingPanel',
|
|
19
|
-
() =>
|
|
20
|
-
function SlidingPanel({ open, children }: SlidingPanelProps) {
|
|
21
|
-
return open ? <div className="sliding-panel">{children}</div> : null;
|
|
22
|
-
},
|
|
23
|
-
);
|
|
24
|
-
|
|
25
|
-
describe('Drawer', () => {
|
|
26
|
-
const props = {
|
|
27
|
-
onClose: jest.fn(),
|
|
28
|
-
open: true,
|
|
29
|
-
};
|
|
30
|
-
|
|
31
|
-
afterEach(() => {
|
|
32
|
-
jest.clearAllMocks();
|
|
33
|
-
});
|
|
34
|
-
|
|
35
|
-
it('renders content when open', () => {
|
|
36
|
-
const { container } = render(<Drawer {...props}>content</Drawer>);
|
|
37
|
-
|
|
38
|
-
expect(container).toMatchSnapshot();
|
|
39
|
-
});
|
|
40
|
-
|
|
41
|
-
it("doesn't render content when closed", () => {
|
|
42
|
-
const { container } = render(
|
|
43
|
-
<Drawer {...props} open={false}>
|
|
44
|
-
content
|
|
45
|
-
</Drawer>,
|
|
46
|
-
);
|
|
47
|
-
|
|
48
|
-
expect(container).toMatchSnapshot();
|
|
49
|
-
});
|
|
50
|
-
|
|
51
|
-
it('calls onClose when user clicks close button', async () => {
|
|
52
|
-
render(<Drawer {...props}>content</Drawer>);
|
|
53
|
-
expect(props.onClose).not.toHaveBeenCalled();
|
|
54
|
-
await userEvent.click(getCloseButton());
|
|
55
|
-
expect(props.onClose).toHaveBeenCalledTimes(1);
|
|
56
|
-
});
|
|
57
|
-
|
|
58
|
-
const getCloseButton = () => screen.getByLabelText('Close');
|
|
59
|
-
});
|
|
@@ -1,101 +0,0 @@
|
|
|
1
|
-
import { mount } from 'enzyme';
|
|
2
|
-
|
|
3
|
-
import { mockMatchMedia } from '../test-utils';
|
|
4
|
-
import Title from '../title/Title';
|
|
5
|
-
|
|
6
|
-
import Drawer from '.';
|
|
7
|
-
|
|
8
|
-
mockMatchMedia();
|
|
9
|
-
jest.mock('../common');
|
|
10
|
-
jest.useFakeTimers();
|
|
11
|
-
|
|
12
|
-
jest.mock(
|
|
13
|
-
'../dimmer',
|
|
14
|
-
() =>
|
|
15
|
-
function Dimmer({ open, children }) {
|
|
16
|
-
return open ? <div className="dimmer">{children}</div> : null;
|
|
17
|
-
},
|
|
18
|
-
);
|
|
19
|
-
|
|
20
|
-
jest.mock(
|
|
21
|
-
'../slidingPanel',
|
|
22
|
-
() =>
|
|
23
|
-
function SlidingPanel({ open, children }) {
|
|
24
|
-
return open ? <div className="sliding-panel">{children}</div> : null;
|
|
25
|
-
},
|
|
26
|
-
);
|
|
27
|
-
|
|
28
|
-
const defaultLocale = 'en-GB';
|
|
29
|
-
|
|
30
|
-
jest.mock('react-intl', () => ({
|
|
31
|
-
injectIntl: (Component) =>
|
|
32
|
-
function InjectedComponent(props) {
|
|
33
|
-
return <Component {...props} intl={{ locale: defaultLocale }} />;
|
|
34
|
-
},
|
|
35
|
-
useIntl: () => ({ locale: defaultLocale, formatMessage: (id) => String(id) }),
|
|
36
|
-
defineMessages: (translations) => translations,
|
|
37
|
-
}));
|
|
38
|
-
|
|
39
|
-
describe('Drawer', () => {
|
|
40
|
-
let component;
|
|
41
|
-
const props = {
|
|
42
|
-
open: true,
|
|
43
|
-
position: 'left',
|
|
44
|
-
onClose: jest.fn(),
|
|
45
|
-
children: null,
|
|
46
|
-
headerTitle: null,
|
|
47
|
-
footerContent: null,
|
|
48
|
-
};
|
|
49
|
-
|
|
50
|
-
beforeEach(() => {
|
|
51
|
-
component = mount(<Drawer {...props} />);
|
|
52
|
-
});
|
|
53
|
-
|
|
54
|
-
afterEach(() => {
|
|
55
|
-
jest.clearAllMocks();
|
|
56
|
-
component.unmount();
|
|
57
|
-
});
|
|
58
|
-
|
|
59
|
-
it('renders drawer header if title is provided', () => {
|
|
60
|
-
expect(component.find('.np-drawer-header--title')).toHaveLength(0);
|
|
61
|
-
component.setProps({ headerTitle: 'A title' });
|
|
62
|
-
expect(component.find(Title)).toHaveLength(1);
|
|
63
|
-
expect(component.find(Title).props().children).toBe('A title');
|
|
64
|
-
});
|
|
65
|
-
|
|
66
|
-
it('renders header with or without borders', () => {
|
|
67
|
-
expect(component.find('.np-drawer-header--withborder')).toHaveLength(0);
|
|
68
|
-
component.setProps({ headerTitle: 'A title' });
|
|
69
|
-
expect(component.find('.np-drawer-header--withborder')).toHaveLength(1);
|
|
70
|
-
});
|
|
71
|
-
|
|
72
|
-
it('renders content if children are provided', () => {
|
|
73
|
-
expect(component.find('.np-drawer-content')).toHaveLength(0);
|
|
74
|
-
component.setProps({ children: 'SomeChildren' });
|
|
75
|
-
expect(component.find('.np-drawer-content')).toHaveLength(1);
|
|
76
|
-
});
|
|
77
|
-
|
|
78
|
-
it('renders drawer footer if footerContent is provided', () => {
|
|
79
|
-
expect(component.find('.np-drawer-footer')).toHaveLength(0);
|
|
80
|
-
component.setProps({ footerContent: 'SomeContent' });
|
|
81
|
-
expect(component.find('.np-drawer-footer')).toHaveLength(1);
|
|
82
|
-
});
|
|
83
|
-
|
|
84
|
-
it('passes onUnmount to Dimmer onExited prop', () => {
|
|
85
|
-
const onUnmount = jest.fn();
|
|
86
|
-
component.setProps({ onUnmount });
|
|
87
|
-
component.setProps({ open: true });
|
|
88
|
-
expect(component.find('Dimmer').prop('onExited')).toBe(onUnmount);
|
|
89
|
-
});
|
|
90
|
-
|
|
91
|
-
it('calls onUnmount when the component unmounts', () => {
|
|
92
|
-
const onUnmount = jest.fn();
|
|
93
|
-
component.setProps({ onUnmount });
|
|
94
|
-
component.setProps({ open: true });
|
|
95
|
-
expect(onUnmount).not.toHaveBeenCalled();
|
|
96
|
-
jest.runAllTimers();
|
|
97
|
-
component.setProps({ open: false });
|
|
98
|
-
component.find('Dimmer').prop('onExited')();
|
|
99
|
-
expect(onUnmount).toHaveBeenCalledTimes(1);
|
|
100
|
-
});
|
|
101
|
-
});
|
|
@@ -1,55 +0,0 @@
|
|
|
1
|
-
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
|
2
|
-
|
|
3
|
-
exports[`Drawer doesn't render content when closed 1`] = `<div />`;
|
|
4
|
-
|
|
5
|
-
exports[`Drawer renders content when open 1`] = `
|
|
6
|
-
<div>
|
|
7
|
-
<div
|
|
8
|
-
class="dimmer"
|
|
9
|
-
>
|
|
10
|
-
<div
|
|
11
|
-
class="sliding-panel"
|
|
12
|
-
>
|
|
13
|
-
<div
|
|
14
|
-
aria-modal="true"
|
|
15
|
-
class="np-drawer"
|
|
16
|
-
role="dialog"
|
|
17
|
-
>
|
|
18
|
-
<div
|
|
19
|
-
class="np-drawer-header"
|
|
20
|
-
>
|
|
21
|
-
<button
|
|
22
|
-
aria-label="Close"
|
|
23
|
-
class="np-close-button close btn-link text-no-decoration np-close-button--large"
|
|
24
|
-
type="button"
|
|
25
|
-
>
|
|
26
|
-
<span
|
|
27
|
-
class="tw-icon tw-icon-cross "
|
|
28
|
-
data-testid="cross-icon"
|
|
29
|
-
>
|
|
30
|
-
<svg
|
|
31
|
-
aria-hidden="true"
|
|
32
|
-
fill="currentColor"
|
|
33
|
-
focusable="false"
|
|
34
|
-
height="24"
|
|
35
|
-
role="none"
|
|
36
|
-
viewBox="0 0 24 24"
|
|
37
|
-
width="24"
|
|
38
|
-
>
|
|
39
|
-
<path
|
|
40
|
-
d="m19.629 5.915-1.2-1.2-6.257 6.257-6.258-6.257-1.2 1.2 6.258 6.257-6.258 6.257 1.2 1.2 6.258-6.257 6.257 6.257 1.2-1.2-6.258-6.257 6.258-6.257Z"
|
|
41
|
-
/>
|
|
42
|
-
</svg>
|
|
43
|
-
</span>
|
|
44
|
-
</button>
|
|
45
|
-
</div>
|
|
46
|
-
<div
|
|
47
|
-
class="np-drawer-content"
|
|
48
|
-
>
|
|
49
|
-
content
|
|
50
|
-
</div>
|
|
51
|
-
</div>
|
|
52
|
-
</div>
|
|
53
|
-
</div>
|
|
54
|
-
</div>
|
|
55
|
-
`;
|