@transferwise/components 46.112.0 → 46.113.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.
Files changed (137) hide show
  1. package/build/expressiveMoneyInput/ExpressiveMoneyInput.js +113 -0
  2. package/build/expressiveMoneyInput/ExpressiveMoneyInput.js.map +1 -0
  3. package/build/expressiveMoneyInput/ExpressiveMoneyInput.messages.js +17 -0
  4. package/build/expressiveMoneyInput/ExpressiveMoneyInput.messages.js.map +1 -0
  5. package/build/expressiveMoneyInput/ExpressiveMoneyInput.messages.mjs +13 -0
  6. package/build/expressiveMoneyInput/ExpressiveMoneyInput.messages.mjs.map +1 -0
  7. package/build/expressiveMoneyInput/ExpressiveMoneyInput.mjs +109 -0
  8. package/build/expressiveMoneyInput/ExpressiveMoneyInput.mjs.map +1 -0
  9. package/build/expressiveMoneyInput/amountInput/AmountInput.js +281 -0
  10. package/build/expressiveMoneyInput/amountInput/AmountInput.js.map +1 -0
  11. package/build/expressiveMoneyInput/amountInput/AmountInput.mjs +279 -0
  12. package/build/expressiveMoneyInput/amountInput/AmountInput.mjs.map +1 -0
  13. package/build/expressiveMoneyInput/amountInput/utils.js +87 -0
  14. package/build/expressiveMoneyInput/amountInput/utils.js.map +1 -0
  15. package/build/expressiveMoneyInput/amountInput/utils.mjs +78 -0
  16. package/build/expressiveMoneyInput/amountInput/utils.mjs.map +1 -0
  17. package/build/expressiveMoneyInput/animatedNumber/AnimatedNumber.js +50 -0
  18. package/build/expressiveMoneyInput/animatedNumber/AnimatedNumber.js.map +1 -0
  19. package/build/expressiveMoneyInput/animatedNumber/AnimatedNumber.mjs +48 -0
  20. package/build/expressiveMoneyInput/animatedNumber/AnimatedNumber.mjs.map +1 -0
  21. package/build/expressiveMoneyInput/chevron/Chevron.js +31 -0
  22. package/build/expressiveMoneyInput/chevron/Chevron.js.map +1 -0
  23. package/build/expressiveMoneyInput/chevron/Chevron.mjs +29 -0
  24. package/build/expressiveMoneyInput/chevron/Chevron.mjs.map +1 -0
  25. package/build/expressiveMoneyInput/currencySelector/CurrencySelector.js +160 -0
  26. package/build/expressiveMoneyInput/currencySelector/CurrencySelector.js.map +1 -0
  27. package/build/expressiveMoneyInput/currencySelector/CurrencySelector.mjs +157 -0
  28. package/build/expressiveMoneyInput/currencySelector/CurrencySelector.mjs.map +1 -0
  29. package/build/expressiveMoneyInput/hooks/useFocus.js +37 -0
  30. package/build/expressiveMoneyInput/hooks/useFocus.js.map +1 -0
  31. package/build/expressiveMoneyInput/hooks/useFocus.mjs +35 -0
  32. package/build/expressiveMoneyInput/hooks/useFocus.mjs.map +1 -0
  33. package/build/expressiveMoneyInput/hooks/useInputStyle.js +71 -0
  34. package/build/expressiveMoneyInput/hooks/useInputStyle.js.map +1 -0
  35. package/build/expressiveMoneyInput/hooks/useInputStyle.mjs +69 -0
  36. package/build/expressiveMoneyInput/hooks/useInputStyle.mjs.map +1 -0
  37. package/build/i18n/en.json +2 -0
  38. package/build/i18n/en.json.js +2 -0
  39. package/build/i18n/en.json.js.map +1 -1
  40. package/build/i18n/en.json.mjs +2 -0
  41. package/build/i18n/en.json.mjs.map +1 -1
  42. package/build/index.js +2 -0
  43. package/build/index.js.map +1 -1
  44. package/build/index.mjs +1 -0
  45. package/build/index.mjs.map +1 -1
  46. package/build/listItem/useListItemControl.js +1 -1
  47. package/build/listItem/useListItemControl.js.map +1 -1
  48. package/build/listItem/useListItemControl.mjs +2 -2
  49. package/build/listItem/useListItemControl.mjs.map +1 -1
  50. package/build/listItem/useListItemMedia.js +1 -1
  51. package/build/listItem/useListItemMedia.js.map +1 -1
  52. package/build/listItem/useListItemMedia.mjs +2 -2
  53. package/build/listItem/useListItemMedia.mjs.map +1 -1
  54. package/build/main.css +73 -7
  55. package/build/prompt/InlinePrompt/InlinePrompt.js +7 -0
  56. package/build/prompt/InlinePrompt/InlinePrompt.js.map +1 -1
  57. package/build/prompt/InlinePrompt/InlinePrompt.mjs +8 -1
  58. package/build/prompt/InlinePrompt/InlinePrompt.mjs.map +1 -1
  59. package/build/styles/expressiveMoneyInput/ExpressiveMoneyInput.css +58 -0
  60. package/build/styles/expressiveMoneyInput/amountInput/AmountInput.css +32 -0
  61. package/build/styles/expressiveMoneyInput/chevron/Chevron.css +12 -0
  62. package/build/styles/expressiveMoneyInput/currencySelector/CurrencySelector.css +6 -0
  63. package/build/styles/main.css +73 -7
  64. package/build/styles/moneyInput/MoneyInput.css +8 -0
  65. package/build/styles/prompt/InlinePrompt/InlinePrompt.css +7 -7
  66. package/build/types/expressiveMoneyInput/ExpressiveMoneyInput.d.ts +59 -0
  67. package/build/types/expressiveMoneyInput/ExpressiveMoneyInput.d.ts.map +1 -0
  68. package/build/types/expressiveMoneyInput/ExpressiveMoneyInput.messages.d.ts +12 -0
  69. package/build/types/expressiveMoneyInput/ExpressiveMoneyInput.messages.d.ts.map +1 -0
  70. package/build/types/expressiveMoneyInput/amountInput/AmountInput.d.ts +13 -0
  71. package/build/types/expressiveMoneyInput/amountInput/AmountInput.d.ts.map +1 -0
  72. package/build/types/expressiveMoneyInput/amountInput/utils.d.ts +22 -0
  73. package/build/types/expressiveMoneyInput/amountInput/utils.d.ts.map +1 -0
  74. package/build/types/expressiveMoneyInput/animatedNumber/AnimatedNumber.d.ts +9 -0
  75. package/build/types/expressiveMoneyInput/animatedNumber/AnimatedNumber.d.ts.map +1 -0
  76. package/build/types/expressiveMoneyInput/chevron/Chevron.d.ts +6 -0
  77. package/build/types/expressiveMoneyInput/chevron/Chevron.d.ts.map +1 -0
  78. package/build/types/expressiveMoneyInput/currencySelector/CurrencySelector.d.ts +30 -0
  79. package/build/types/expressiveMoneyInput/currencySelector/CurrencySelector.d.ts.map +1 -0
  80. package/build/types/expressiveMoneyInput/hooks/useFocus.d.ts +7 -0
  81. package/build/types/expressiveMoneyInput/hooks/useFocus.d.ts.map +1 -0
  82. package/build/types/expressiveMoneyInput/hooks/useInputStyle.d.ts +10 -0
  83. package/build/types/expressiveMoneyInput/hooks/useInputStyle.d.ts.map +1 -0
  84. package/build/types/expressiveMoneyInput/hooks/useSelectionRange.d.ts +10 -0
  85. package/build/types/expressiveMoneyInput/hooks/useSelectionRange.d.ts.map +1 -0
  86. package/build/types/expressiveMoneyInput/index.d.ts +3 -0
  87. package/build/types/expressiveMoneyInput/index.d.ts.map +1 -0
  88. package/build/types/index.d.ts +2 -0
  89. package/build/types/index.d.ts.map +1 -1
  90. package/build/types/prompt/InlinePrompt/InlinePrompt.d.ts +3 -2
  91. package/build/types/prompt/InlinePrompt/InlinePrompt.d.ts.map +1 -1
  92. package/build/types/test-utils/index.d.ts +4 -0
  93. package/build/types/test-utils/index.d.ts.map +1 -1
  94. package/build/types/withDisplayFormat/WithDisplayFormat.d.ts.map +1 -1
  95. package/build/withDisplayFormat/WithDisplayFormat.js +0 -1
  96. package/build/withDisplayFormat/WithDisplayFormat.js.map +1 -1
  97. package/build/withDisplayFormat/WithDisplayFormat.mjs +0 -1
  98. package/build/withDisplayFormat/WithDisplayFormat.mjs.map +1 -1
  99. package/package.json +11 -4
  100. package/src/expressiveMoneyInput/ExpressiveMoneyInput.autofocus.docs.mdx +12 -0
  101. package/src/expressiveMoneyInput/ExpressiveMoneyInput.css +58 -0
  102. package/src/expressiveMoneyInput/ExpressiveMoneyInput.less +13 -0
  103. package/src/expressiveMoneyInput/ExpressiveMoneyInput.messages.ts +13 -0
  104. package/src/expressiveMoneyInput/ExpressiveMoneyInput.story.tsx +232 -0
  105. package/src/expressiveMoneyInput/ExpressiveMoneyInput.tsx +156 -0
  106. package/src/expressiveMoneyInput/amountInput/AmountInput.css +32 -0
  107. package/src/expressiveMoneyInput/amountInput/AmountInput.less +43 -0
  108. package/src/expressiveMoneyInput/amountInput/AmountInput.tsx +353 -0
  109. package/src/expressiveMoneyInput/amountInput/utils.spec.ts +114 -0
  110. package/src/expressiveMoneyInput/amountInput/utils.ts +116 -0
  111. package/src/expressiveMoneyInput/animatedNumber/AnimatedNumber.tsx +40 -0
  112. package/src/expressiveMoneyInput/chevron/Chevron.css +12 -0
  113. package/src/expressiveMoneyInput/chevron/Chevron.less +13 -0
  114. package/src/expressiveMoneyInput/chevron/Chevron.tsx +35 -0
  115. package/src/expressiveMoneyInput/currencySelector/CurrencySelector.css +6 -0
  116. package/src/expressiveMoneyInput/currencySelector/CurrencySelector.less +7 -0
  117. package/src/expressiveMoneyInput/currencySelector/CurrencySelector.tsx +220 -0
  118. package/src/expressiveMoneyInput/hooks/useFocus.ts +35 -0
  119. package/src/expressiveMoneyInput/hooks/useInputStyle.ts +85 -0
  120. package/src/expressiveMoneyInput/hooks/useSelectionRange.ts +23 -0
  121. package/src/expressiveMoneyInput/index.ts +2 -0
  122. package/src/i18n/en.json +2 -0
  123. package/src/index.ts +2 -0
  124. package/src/listItem/useListItemControl.tsx +2 -2
  125. package/src/listItem/useListItemMedia.tsx +2 -2
  126. package/src/main.css +73 -7
  127. package/src/main.less +1 -0
  128. package/src/moneyInput/MoneyInput.css +8 -0
  129. package/src/moneyInput/MoneyInput.less +5 -0
  130. package/src/prompt/InlinePrompt/InlinePrompt.css +7 -7
  131. package/src/prompt/InlinePrompt/InlinePrompt.less +7 -7
  132. package/src/prompt/InlinePrompt/InlinePrompt.spec.tsx +6 -0
  133. package/src/prompt/InlinePrompt/InlinePrompt.story.tsx +39 -0
  134. package/src/prompt/InlinePrompt/InlinePrompt.tsx +12 -2
  135. package/src/ssr.spec.tsx +1 -0
  136. package/src/withDisplayFormat/WithDisplayFormat.spec.js +28 -1
  137. package/src/withDisplayFormat/WithDisplayFormat.tsx +0 -1
@@ -0,0 +1,113 @@
1
+ 'use strict';
2
+
3
+ Object.defineProperty(exports, '__esModule', { value: true });
4
+
5
+ var Body = require('../body/Body.js');
6
+ var Label = require('../label/Label.js');
7
+ var clsx = require('clsx');
8
+ var framerMotion = require('framer-motion');
9
+ var React = require('react');
10
+ var CurrencySelector = require('./currencySelector/CurrencySelector.js');
11
+ var AmountInput = require('./amountInput/AmountInput.js');
12
+ var Chevron = require('./chevron/Chevron.js');
13
+ var InlinePrompt = require('../prompt/InlinePrompt/InlinePrompt.js');
14
+ var jsxRuntime = require('react/jsx-runtime');
15
+
16
+ function ExpressiveMoneyInput({
17
+ label,
18
+ currency,
19
+ currencySelector = {
20
+ options: []
21
+ },
22
+ amount,
23
+ onAmountChange,
24
+ className,
25
+ inlinePrompt,
26
+ showChevron,
27
+ autoFocus,
28
+ loading,
29
+ onFocusChange
30
+ }) {
31
+ const inputId = React.useId();
32
+ const labelId = React.useId();
33
+ const customAlertId = React.useId();
34
+ const currencyId = React.useId();
35
+ return /*#__PURE__*/jsxRuntime.jsxs("div", {
36
+ className: clsx.clsx('wds-expressive-money-input', className),
37
+ children: [/*#__PURE__*/jsxRuntime.jsx(Label.Label, {
38
+ id: labelId,
39
+ htmlFor: inputId,
40
+ className: clsx.clsx('m-b-1', 'font-weight-normal'),
41
+ children: label
42
+ }), /*#__PURE__*/jsxRuntime.jsxs("div", {
43
+ className: clsx.clsx('d-flex'),
44
+ role: "group",
45
+ "aria-labelledby": labelId,
46
+ ...(inlinePrompt ? {
47
+ 'aria-describedby': customAlertId
48
+ } : {}),
49
+ children: [/*#__PURE__*/jsxRuntime.jsx("div", {
50
+ className: "wds-expressive-money-input-currency-selector",
51
+ children: currencySelector.customRender?.({
52
+ id: currencyId,
53
+ labelId
54
+ }) ?? /*#__PURE__*/jsxRuntime.jsx(CurrencySelector.CurrencySelector, {
55
+ id: currencyId,
56
+ labelId: labelId,
57
+ currency: currency,
58
+ ...currencySelector
59
+ })
60
+ }), /*#__PURE__*/jsxRuntime.jsx(AmountInput.AmountInput, {
61
+ id: inputId,
62
+ describedById: currencyId,
63
+ amount: amount,
64
+ currency: currency
65
+ // eslint-disable-next-line jsx-a11y/no-autofocus
66
+ ,
67
+ autoFocus: autoFocus,
68
+ loading: loading,
69
+ onChange: onAmountChange,
70
+ onFocusChange: onFocusChange
71
+ }), /*#__PURE__*/jsxRuntime.jsx("div", {
72
+ className: clsx.clsx('d-flex align-items-center', 'wds-expressive-money-input-chevron'),
73
+ children: /*#__PURE__*/jsxRuntime.jsx(Chevron.Chevron, {
74
+ shouldShow: Boolean(showChevron)
75
+ })
76
+ })]
77
+ }), /*#__PURE__*/jsxRuntime.jsx(framerMotion.AnimatePresence, {
78
+ initial: false,
79
+ children: inlinePrompt && /*#__PURE__*/jsxRuntime.jsx("div", {
80
+ className: clsx.clsx('d-flex justify-content-end', inlinePrompt && 'm-t-1'),
81
+ children: /*#__PURE__*/jsxRuntime.jsx(framerMotion.motion.div, {
82
+ initial: {
83
+ opacity: 0,
84
+ height: 0
85
+ },
86
+ animate: {
87
+ opacity: 1,
88
+ height: 'auto',
89
+ transition: {
90
+ delay: 0.75,
91
+ duration: 0.3
92
+ }
93
+ },
94
+ exit: {
95
+ opacity: 0,
96
+ height: 0
97
+ },
98
+ children: inlinePrompt.sentiment && Object.keys(inlinePrompt.sentiment).length > 0 ? /*#__PURE__*/jsxRuntime.jsx(InlinePrompt.InlinePrompt, {
99
+ id: customAlertId,
100
+ media: inlinePrompt.media,
101
+ sentiment: inlinePrompt.sentiment,
102
+ children: inlinePrompt.message
103
+ }) : /*#__PURE__*/jsxRuntime.jsx(Body.default, {
104
+ children: inlinePrompt.message
105
+ })
106
+ }, customAlertId)
107
+ })
108
+ })]
109
+ });
110
+ }
111
+
112
+ exports.default = ExpressiveMoneyInput;
113
+ //# sourceMappingURL=ExpressiveMoneyInput.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ExpressiveMoneyInput.js","sources":["../../src/expressiveMoneyInput/ExpressiveMoneyInput.tsx"],"sourcesContent":["import Body from '../body';\nimport { Label } from '../label/Label';\nimport { clsx } from 'clsx';\nimport { AnimatePresence, motion } from 'framer-motion';\nimport { useId, type ReactNode } from 'react';\n\nimport {\n type Props as CurrencySelectorProps,\n CurrencySelector,\n} from './currencySelector/CurrencySelector';\nimport { CommonProps } from '../common';\nimport { AmountInput } from './amountInput/AmountInput';\nimport { Chevron } from './chevron/Chevron';\nimport { InlinePrompt, type InlinePromptProps } from '../prompt/InlinePrompt';\n\ntype AmountType = number | null;\nexport type CurrencyType = string;\n\ntype DefaultCurrencySelectorInstanceType = Pick<\n CurrencySelectorProps,\n 'addons' | 'options' | 'onChange' | 'onOpen' | 'onSearchChange'\n>;\ntype CustomCurrencySelectorInstanceType = {\n customRender?: (props: { id: string; labelId: string }) => ReactNode;\n};\ntype CurrencySelectorType = DefaultCurrencySelectorInstanceType &\n CustomCurrencySelectorInstanceType;\n\nexport type Props = {\n label?: ReactNode;\n currencySelector?: CurrencySelectorType;\n amount?: AmountType;\n /**\n * The currency code, e.g. `USD`, `EUR`, `GBP`, etc. Governs the flag rendered in the currency selector.\n */\n currency: CurrencyType;\n inlinePrompt?: {\n sentiment?: InlinePromptProps['sentiment'];\n message: InlinePromptProps['children'];\n media?: InlinePromptProps['media'];\n };\n showChevron?: boolean;\n /**\n * If set, it auto-focuses the amount input upon component mount.<br />\n * ⚠️ **Use with caution**, as it may impact user experience and\n * fail [WCAG 2.4.3 requirements](https://www.w3.org/WAI/WCAG21/Understanding/focus-order.html)\n */\n autoFocus?: boolean;\n /**\n * Dims the input to indicate a loading state. Does not disable it.\n */\n loading?: boolean;\n onAmountChange: (amount: AmountType) => void;\n onFocusChange?: (focused: boolean) => void;\n} & CommonProps;\n\n/**\n * This component has been kindly contributed by our friends at the `Send` team 🎉.\n *\n * Some patterns and implementation details used in this component may differ\n * from what's commonly used in the Design System. The overall build and QA was managed\n * by the contributing team directly, and such did not follow a typical DS lifecycle.\n *\n * While we house this component and will help facilitate its future iterations,\n * direct contributions by consuming product teams are highly encouraged.\n *\n * > ⚠️ **Prerequisite:** <br />The component depends on the\n * [framer-motion](https://www.npmjs.com/package/framer-motion) package, which has been\n * deliberately excluded from the Design System bundle and kept as an opt-in only.\n * **Make sure to add it to your project dependencies.**\n */\nexport default function ExpressiveMoneyInput({\n label,\n currency,\n currencySelector = { options: [] } as DefaultCurrencySelectorInstanceType,\n amount,\n onAmountChange,\n className,\n inlinePrompt,\n showChevron,\n autoFocus,\n loading,\n onFocusChange,\n}: Props) {\n const inputId = useId();\n const labelId = useId();\n const customAlertId = useId();\n const currencyId = useId();\n\n return (\n <div className={clsx('wds-expressive-money-input', className)}>\n <Label id={labelId} htmlFor={inputId} className={clsx('m-b-1', 'font-weight-normal')}>\n {label}\n </Label>\n <div\n className={clsx('d-flex')}\n role=\"group\"\n aria-labelledby={labelId}\n {...(inlinePrompt ? { 'aria-describedby': customAlertId } : {})}\n >\n <div className=\"wds-expressive-money-input-currency-selector\">\n {currencySelector.customRender?.({ id: currencyId, labelId }) ?? (\n <CurrencySelector\n id={currencyId}\n labelId={labelId}\n currency={currency}\n {...currencySelector}\n />\n )}\n </div>\n <AmountInput\n id={inputId}\n describedById={currencyId}\n amount={amount}\n currency={currency}\n // eslint-disable-next-line jsx-a11y/no-autofocus\n autoFocus={autoFocus}\n loading={loading}\n onChange={onAmountChange}\n onFocusChange={onFocusChange}\n />\n <div className={clsx('d-flex align-items-center', 'wds-expressive-money-input-chevron')}>\n <Chevron shouldShow={Boolean(showChevron)} />\n </div>\n </div>\n <AnimatePresence initial={false}>\n {inlinePrompt && (\n <div className={clsx('d-flex justify-content-end', inlinePrompt && 'm-t-1')}>\n <motion.div\n key={customAlertId}\n initial={{ opacity: 0, height: 0 }}\n animate={{\n opacity: 1,\n height: 'auto',\n transition: { delay: 0.75, duration: 0.3 },\n }}\n exit={{ opacity: 0, height: 0 }}\n >\n {inlinePrompt.sentiment && Object.keys(inlinePrompt.sentiment).length > 0 ? (\n <InlinePrompt\n id={customAlertId}\n media={inlinePrompt.media}\n sentiment={inlinePrompt.sentiment}\n >\n {inlinePrompt.message}\n </InlinePrompt>\n ) : (\n <Body>{inlinePrompt.message}</Body>\n )}\n </motion.div>\n </div>\n )}\n </AnimatePresence>\n </div>\n );\n}\n"],"names":["ExpressiveMoneyInput","label","currency","currencySelector","options","amount","onAmountChange","className","inlinePrompt","showChevron","autoFocus","loading","onFocusChange","inputId","useId","labelId","customAlertId","currencyId","_jsxs","clsx","children","_jsx","Label","id","htmlFor","role","customRender","CurrencySelector","AmountInput","describedById","onChange","Chevron","shouldShow","Boolean","AnimatePresence","initial","motion","div","opacity","height","animate","transition","delay","duration","exit","sentiment","Object","keys","length","InlinePrompt","media","message","Body"],"mappings":"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"}
@@ -0,0 +1,17 @@
1
+ 'use strict';
2
+
3
+ Object.defineProperty(exports, '__esModule', { value: true });
4
+
5
+ var reactIntl = require('react-intl');
6
+
7
+ var messages = reactIntl.defineMessages({
8
+ currencySelectorSearchPlaceholder: {
9
+ id: "neptune.ExpressiveMoneyInput.currency.search.placeholder"
10
+ },
11
+ currencySelectorSelectCurrency: {
12
+ id: "neptune.ExpressiveMoneyInput.currency.select.currency"
13
+ }
14
+ });
15
+
16
+ exports.default = messages;
17
+ //# sourceMappingURL=ExpressiveMoneyInput.messages.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ExpressiveMoneyInput.messages.js","sources":["../../src/expressiveMoneyInput/ExpressiveMoneyInput.messages.ts"],"sourcesContent":["import { defineMessages } from 'react-intl';\n\nexport default defineMessages({\n currencySelectorSearchPlaceholder: {\n id: 'neptune.ExpressiveMoneyInput.currency.search.placeholder',\n defaultMessage: 'Type a currency / country',\n },\n\n currencySelectorSelectCurrency: {\n id: 'neptune.ExpressiveMoneyInput.currency.select.currency',\n defaultMessage: 'Select currency',\n },\n});\n"],"names":["defineMessages","currencySelectorSearchPlaceholder","id","currencySelectorSelectCurrency"],"mappings":";;;;;;AAEA,eAAeA,wBAAc,CAAC;AAC5BC,EAAAA,iCAAiC,EAAE;IACjCC,EAAE,EAAA;GAEH;AAEDC,EAAAA,8BAA8B,EAAE;IAC9BD,EAAE,EAAA;AAEH;AACF,CAAA,CAAC;;;;"}
@@ -0,0 +1,13 @@
1
+ import { defineMessages } from 'react-intl';
2
+
3
+ var messages = defineMessages({
4
+ currencySelectorSearchPlaceholder: {
5
+ id: "neptune.ExpressiveMoneyInput.currency.search.placeholder"
6
+ },
7
+ currencySelectorSelectCurrency: {
8
+ id: "neptune.ExpressiveMoneyInput.currency.select.currency"
9
+ }
10
+ });
11
+
12
+ export { messages as default };
13
+ //# sourceMappingURL=ExpressiveMoneyInput.messages.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ExpressiveMoneyInput.messages.mjs","sources":["../../src/expressiveMoneyInput/ExpressiveMoneyInput.messages.ts"],"sourcesContent":["import { defineMessages } from 'react-intl';\n\nexport default defineMessages({\n currencySelectorSearchPlaceholder: {\n id: 'neptune.ExpressiveMoneyInput.currency.search.placeholder',\n defaultMessage: 'Type a currency / country',\n },\n\n currencySelectorSelectCurrency: {\n id: 'neptune.ExpressiveMoneyInput.currency.select.currency',\n defaultMessage: 'Select currency',\n },\n});\n"],"names":["defineMessages","currencySelectorSearchPlaceholder","id","currencySelectorSelectCurrency"],"mappings":";;AAEA,eAAeA,cAAc,CAAC;AAC5BC,EAAAA,iCAAiC,EAAE;IACjCC,EAAE,EAAA;GAEH;AAEDC,EAAAA,8BAA8B,EAAE;IAC9BD,EAAE,EAAA;AAEH;AACF,CAAA,CAAC;;;;"}
@@ -0,0 +1,109 @@
1
+ import Body from '../body/Body.mjs';
2
+ import { Label as LabelNamespace } from '../label/Label.mjs';
3
+ import { clsx } from 'clsx';
4
+ import { AnimatePresence, motion } from 'framer-motion';
5
+ import { useId } from 'react';
6
+ import { CurrencySelector } from './currencySelector/CurrencySelector.mjs';
7
+ import { AmountInput } from './amountInput/AmountInput.mjs';
8
+ import { Chevron } from './chevron/Chevron.mjs';
9
+ import { InlinePrompt } from '../prompt/InlinePrompt/InlinePrompt.mjs';
10
+ import { jsxs, jsx } from 'react/jsx-runtime';
11
+
12
+ function ExpressiveMoneyInput({
13
+ label,
14
+ currency,
15
+ currencySelector = {
16
+ options: []
17
+ },
18
+ amount,
19
+ onAmountChange,
20
+ className,
21
+ inlinePrompt,
22
+ showChevron,
23
+ autoFocus,
24
+ loading,
25
+ onFocusChange
26
+ }) {
27
+ const inputId = useId();
28
+ const labelId = useId();
29
+ const customAlertId = useId();
30
+ const currencyId = useId();
31
+ return /*#__PURE__*/jsxs("div", {
32
+ className: clsx('wds-expressive-money-input', className),
33
+ children: [/*#__PURE__*/jsx(LabelNamespace, {
34
+ id: labelId,
35
+ htmlFor: inputId,
36
+ className: clsx('m-b-1', 'font-weight-normal'),
37
+ children: label
38
+ }), /*#__PURE__*/jsxs("div", {
39
+ className: clsx('d-flex'),
40
+ role: "group",
41
+ "aria-labelledby": labelId,
42
+ ...(inlinePrompt ? {
43
+ 'aria-describedby': customAlertId
44
+ } : {}),
45
+ children: [/*#__PURE__*/jsx("div", {
46
+ className: "wds-expressive-money-input-currency-selector",
47
+ children: currencySelector.customRender?.({
48
+ id: currencyId,
49
+ labelId
50
+ }) ?? /*#__PURE__*/jsx(CurrencySelector, {
51
+ id: currencyId,
52
+ labelId: labelId,
53
+ currency: currency,
54
+ ...currencySelector
55
+ })
56
+ }), /*#__PURE__*/jsx(AmountInput, {
57
+ id: inputId,
58
+ describedById: currencyId,
59
+ amount: amount,
60
+ currency: currency
61
+ // eslint-disable-next-line jsx-a11y/no-autofocus
62
+ ,
63
+ autoFocus: autoFocus,
64
+ loading: loading,
65
+ onChange: onAmountChange,
66
+ onFocusChange: onFocusChange
67
+ }), /*#__PURE__*/jsx("div", {
68
+ className: clsx('d-flex align-items-center', 'wds-expressive-money-input-chevron'),
69
+ children: /*#__PURE__*/jsx(Chevron, {
70
+ shouldShow: Boolean(showChevron)
71
+ })
72
+ })]
73
+ }), /*#__PURE__*/jsx(AnimatePresence, {
74
+ initial: false,
75
+ children: inlinePrompt && /*#__PURE__*/jsx("div", {
76
+ className: clsx('d-flex justify-content-end', inlinePrompt && 'm-t-1'),
77
+ children: /*#__PURE__*/jsx(motion.div, {
78
+ initial: {
79
+ opacity: 0,
80
+ height: 0
81
+ },
82
+ animate: {
83
+ opacity: 1,
84
+ height: 'auto',
85
+ transition: {
86
+ delay: 0.75,
87
+ duration: 0.3
88
+ }
89
+ },
90
+ exit: {
91
+ opacity: 0,
92
+ height: 0
93
+ },
94
+ children: inlinePrompt.sentiment && Object.keys(inlinePrompt.sentiment).length > 0 ? /*#__PURE__*/jsx(InlinePrompt, {
95
+ id: customAlertId,
96
+ media: inlinePrompt.media,
97
+ sentiment: inlinePrompt.sentiment,
98
+ children: inlinePrompt.message
99
+ }) : /*#__PURE__*/jsx(Body, {
100
+ children: inlinePrompt.message
101
+ })
102
+ }, customAlertId)
103
+ })
104
+ })]
105
+ });
106
+ }
107
+
108
+ export { ExpressiveMoneyInput as default };
109
+ //# sourceMappingURL=ExpressiveMoneyInput.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ExpressiveMoneyInput.mjs","sources":["../../src/expressiveMoneyInput/ExpressiveMoneyInput.tsx"],"sourcesContent":["import Body from '../body';\nimport { Label } from '../label/Label';\nimport { clsx } from 'clsx';\nimport { AnimatePresence, motion } from 'framer-motion';\nimport { useId, type ReactNode } from 'react';\n\nimport {\n type Props as CurrencySelectorProps,\n CurrencySelector,\n} from './currencySelector/CurrencySelector';\nimport { CommonProps } from '../common';\nimport { AmountInput } from './amountInput/AmountInput';\nimport { Chevron } from './chevron/Chevron';\nimport { InlinePrompt, type InlinePromptProps } from '../prompt/InlinePrompt';\n\ntype AmountType = number | null;\nexport type CurrencyType = string;\n\ntype DefaultCurrencySelectorInstanceType = Pick<\n CurrencySelectorProps,\n 'addons' | 'options' | 'onChange' | 'onOpen' | 'onSearchChange'\n>;\ntype CustomCurrencySelectorInstanceType = {\n customRender?: (props: { id: string; labelId: string }) => ReactNode;\n};\ntype CurrencySelectorType = DefaultCurrencySelectorInstanceType &\n CustomCurrencySelectorInstanceType;\n\nexport type Props = {\n label?: ReactNode;\n currencySelector?: CurrencySelectorType;\n amount?: AmountType;\n /**\n * The currency code, e.g. `USD`, `EUR`, `GBP`, etc. Governs the flag rendered in the currency selector.\n */\n currency: CurrencyType;\n inlinePrompt?: {\n sentiment?: InlinePromptProps['sentiment'];\n message: InlinePromptProps['children'];\n media?: InlinePromptProps['media'];\n };\n showChevron?: boolean;\n /**\n * If set, it auto-focuses the amount input upon component mount.<br />\n * ⚠️ **Use with caution**, as it may impact user experience and\n * fail [WCAG 2.4.3 requirements](https://www.w3.org/WAI/WCAG21/Understanding/focus-order.html)\n */\n autoFocus?: boolean;\n /**\n * Dims the input to indicate a loading state. Does not disable it.\n */\n loading?: boolean;\n onAmountChange: (amount: AmountType) => void;\n onFocusChange?: (focused: boolean) => void;\n} & CommonProps;\n\n/**\n * This component has been kindly contributed by our friends at the `Send` team 🎉.\n *\n * Some patterns and implementation details used in this component may differ\n * from what's commonly used in the Design System. The overall build and QA was managed\n * by the contributing team directly, and such did not follow a typical DS lifecycle.\n *\n * While we house this component and will help facilitate its future iterations,\n * direct contributions by consuming product teams are highly encouraged.\n *\n * > ⚠️ **Prerequisite:** <br />The component depends on the\n * [framer-motion](https://www.npmjs.com/package/framer-motion) package, which has been\n * deliberately excluded from the Design System bundle and kept as an opt-in only.\n * **Make sure to add it to your project dependencies.**\n */\nexport default function ExpressiveMoneyInput({\n label,\n currency,\n currencySelector = { options: [] } as DefaultCurrencySelectorInstanceType,\n amount,\n onAmountChange,\n className,\n inlinePrompt,\n showChevron,\n autoFocus,\n loading,\n onFocusChange,\n}: Props) {\n const inputId = useId();\n const labelId = useId();\n const customAlertId = useId();\n const currencyId = useId();\n\n return (\n <div className={clsx('wds-expressive-money-input', className)}>\n <Label id={labelId} htmlFor={inputId} className={clsx('m-b-1', 'font-weight-normal')}>\n {label}\n </Label>\n <div\n className={clsx('d-flex')}\n role=\"group\"\n aria-labelledby={labelId}\n {...(inlinePrompt ? { 'aria-describedby': customAlertId } : {})}\n >\n <div className=\"wds-expressive-money-input-currency-selector\">\n {currencySelector.customRender?.({ id: currencyId, labelId }) ?? (\n <CurrencySelector\n id={currencyId}\n labelId={labelId}\n currency={currency}\n {...currencySelector}\n />\n )}\n </div>\n <AmountInput\n id={inputId}\n describedById={currencyId}\n amount={amount}\n currency={currency}\n // eslint-disable-next-line jsx-a11y/no-autofocus\n autoFocus={autoFocus}\n loading={loading}\n onChange={onAmountChange}\n onFocusChange={onFocusChange}\n />\n <div className={clsx('d-flex align-items-center', 'wds-expressive-money-input-chevron')}>\n <Chevron shouldShow={Boolean(showChevron)} />\n </div>\n </div>\n <AnimatePresence initial={false}>\n {inlinePrompt && (\n <div className={clsx('d-flex justify-content-end', inlinePrompt && 'm-t-1')}>\n <motion.div\n key={customAlertId}\n initial={{ opacity: 0, height: 0 }}\n animate={{\n opacity: 1,\n height: 'auto',\n transition: { delay: 0.75, duration: 0.3 },\n }}\n exit={{ opacity: 0, height: 0 }}\n >\n {inlinePrompt.sentiment && Object.keys(inlinePrompt.sentiment).length > 0 ? (\n <InlinePrompt\n id={customAlertId}\n media={inlinePrompt.media}\n sentiment={inlinePrompt.sentiment}\n >\n {inlinePrompt.message}\n </InlinePrompt>\n ) : (\n <Body>{inlinePrompt.message}</Body>\n )}\n </motion.div>\n </div>\n )}\n </AnimatePresence>\n </div>\n );\n}\n"],"names":["ExpressiveMoneyInput","label","currency","currencySelector","options","amount","onAmountChange","className","inlinePrompt","showChevron","autoFocus","loading","onFocusChange","inputId","useId","labelId","customAlertId","currencyId","_jsxs","clsx","children","_jsx","Label","id","htmlFor","role","customRender","CurrencySelector","AmountInput","describedById","onChange","Chevron","shouldShow","Boolean","AnimatePresence","initial","motion","div","opacity","height","animate","transition","delay","duration","exit","sentiment","Object","keys","length","InlinePrompt","media","message","Body"],"mappings":"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"}
@@ -0,0 +1,281 @@
1
+ 'use strict';
2
+
3
+ var formatting = require('@transferwise/formatting');
4
+ var clsx = require('clsx');
5
+ var framerMotion = require('framer-motion');
6
+ var React = require('react');
7
+ var reactIntl = require('react-intl');
8
+ var AnimatedNumber = require('../animatedNumber/AnimatedNumber.js');
9
+ var useFocus = require('../hooks/useFocus.js');
10
+ var useInputStyle = require('../hooks/useInputStyle.js');
11
+ var utils = require('./utils.js');
12
+ var jsxRuntime = require('react/jsx-runtime');
13
+
14
+ const AmountInput = ({
15
+ id,
16
+ describedById,
17
+ amount,
18
+ currency,
19
+ autoFocus,
20
+ onChange,
21
+ onFocusChange,
22
+ loading
23
+ }) => {
24
+ const intl = reactIntl.useIntl();
25
+ const {
26
+ focus,
27
+ setFocus,
28
+ visualFocus,
29
+ setVisualFocus
30
+ } = useFocus.useFocus();
31
+ const [value, setValue] = React.useState(amount ? utils.getFormattedString({
32
+ value: amount,
33
+ currency,
34
+ locale: intl.locale
35
+ }) : '');
36
+ const numericValue = React.useMemo(() => {
37
+ return utils.getUnformattedNumber({
38
+ value,
39
+ currency,
40
+ locale: intl.locale
41
+ });
42
+ }, [value, currency, intl.locale]);
43
+ const valueWithFullDecimals = React.useMemo(() => {
44
+ return utils.getFormattedString({
45
+ value: numericValue ?? 0,
46
+ currency,
47
+ locale: intl.locale,
48
+ alwaysShowDecimals: true
49
+ });
50
+ }, [numericValue, currency, intl.locale]);
51
+ const ref = React.useRef(null);
52
+ React.useEffect(() => {
53
+ if (autoFocus) {
54
+ ref.current?.focus();
55
+ }
56
+ }, []);
57
+ const placeholder = getPlaceholder(currency, intl.locale);
58
+ const groupSeparator = utils.getGroupSeparator(currency, intl.locale);
59
+ const decimalSeparator = utils.getDecimalSeparator(currency, intl.locale);
60
+ const maxDecimalCount = utils.getDecimalCount(currency, intl.locale);
61
+ const decimalPart = getDecimalPart(value, decimalSeparator);
62
+ const decimalMode = decimalSeparator && value.includes(decimalSeparator);
63
+ React.useEffect(() => {
64
+ if (!focus) {
65
+ setValue(amount ? utils.getFormattedString({
66
+ value: amount,
67
+ currency,
68
+ locale: intl.locale
69
+ }) : '');
70
+ }
71
+ // eslint-disable-next-line react-hooks/exhaustive-deps
72
+ }, [amount]);
73
+ React.useEffect(() => {
74
+ onFocusChange?.(visualFocus);
75
+ }, [visualFocus]);
76
+ const shouldReformatAfterUserInput = newValue => {
77
+ // don't reformat if formatting would wipe out user's input
78
+ if (reformatValue(newValue) === '') {
79
+ return false;
80
+ }
81
+ const endsWithDecimalSeparator = decimalSeparator && newValue.endsWith(decimalSeparator);
82
+ const endsWithGroupSeparator = groupSeparator && newValue.endsWith(groupSeparator);
83
+ // if the user has entered a seperator to the end, formatting would delete it
84
+ if (endsWithDecimalSeparator || endsWithGroupSeparator) {
85
+ return false;
86
+ }
87
+ const containsDecimalSeparator = decimalSeparator && newValue.includes(decimalSeparator);
88
+ if (containsDecimalSeparator) {
89
+ const enteredDecimalsCount = utils.getEnteredDecimalsCount(newValue, decimalSeparator);
90
+ // don't reformat until user has entered all the allowed decimals
91
+ // for example, we don't want 1.1 to be reformatted to 1.10 immediately
92
+ if (enteredDecimalsCount < maxDecimalCount) {
93
+ return false;
94
+ }
95
+ }
96
+ return true;
97
+ };
98
+ const reformatValue = newValue => {
99
+ const unformattedValue = utils.getUnformattedNumber({
100
+ value: newValue,
101
+ currency,
102
+ locale: intl.locale
103
+ });
104
+ const formattedValue = unformattedValue ? utils.getFormattedString({
105
+ value: unformattedValue,
106
+ currency,
107
+ locale: intl.locale
108
+ }) : '';
109
+ return formattedValue;
110
+ };
111
+ const handleChange = newValue => {
112
+ const oldCursorPosition = ref.current?.selectionStart ?? 0;
113
+ const newFormattedString = shouldReformatAfterUserInput(newValue) ? reformatValue(newValue) : newValue;
114
+ setValue(newFormattedString);
115
+ const newNumber = utils.getUnformattedNumber({
116
+ value: newFormattedString,
117
+ currency,
118
+ locale: intl.locale
119
+ });
120
+ if (newNumber !== numericValue) {
121
+ if (numericValue || newNumber) {
122
+ onChange(newNumber);
123
+ }
124
+ }
125
+ const newCursorPosition = oldCursorPosition + (newFormattedString.length - newValue.length);
126
+ requestAnimationFrame(() => {
127
+ ref?.current?.setSelectionRange(newCursorPosition, newCursorPosition);
128
+ });
129
+ };
130
+ const handlePaste = e => {
131
+ e.preventDefault();
132
+ const clipboardData = e.clipboardData?.getData('text/plain');
133
+ if (!clipboardData) {
134
+ return;
135
+ }
136
+ // need to sanitise the pasted value otherwise other validation logic will ignore the input entirely
137
+ const sanitisedValue = reformatValue(clipboardData);
138
+ handleChange(sanitisedValue);
139
+ };
140
+ const handleBlur = () => {
141
+ setFocus(false);
142
+ setValue(reformatValue(value));
143
+ };
144
+ const handleBackspace = e => {
145
+ const input = e.target;
146
+ // using the updated selection range after the backspace key has been processed, instead of the current selection range in state
147
+ const {
148
+ value: currentValue,
149
+ selectionStart,
150
+ selectionEnd
151
+ } = input;
152
+ if (selectionStart === selectionEnd && selectionStart && selectionStart > 0) {
153
+ const charBeforeCursor = currentValue[selectionStart - 1];
154
+ // if the user deletes a thousands separator, remove the digit before it as well
155
+ if (charBeforeCursor === groupSeparator) {
156
+ e.preventDefault();
157
+ const beforeCursor = currentValue.slice(0, selectionStart - 2);
158
+ const afterCursor = currentValue.slice(selectionStart);
159
+ const newValue = `${beforeCursor}${afterCursor}`;
160
+ input.setSelectionRange(beforeCursor.length, beforeCursor.length);
161
+ handleChange(newValue);
162
+ }
163
+ }
164
+ };
165
+ const handleKeyDown = e => {
166
+ setFocus(true);
167
+ if (!utils.isAllowedInputKey(e)) {
168
+ e.preventDefault();
169
+ }
170
+ if (e.key === 'Backspace') {
171
+ handleBackspace(e);
172
+ }
173
+ };
174
+ const isAllowedInput = e => {
175
+ const hasMultipleDecimalSeparators = decimalSeparator && e.target.value.split(decimalSeparator).length > 2;
176
+ if (hasMultipleDecimalSeparators) {
177
+ return false;
178
+ }
179
+ const newNumericValue = utils.getUnformattedNumber({
180
+ value: e.target.value,
181
+ currency,
182
+ locale: intl.locale
183
+ });
184
+ const maxLength = Number.MAX_SAFE_INTEGER.toString().length;
185
+ if (String(newNumericValue).length > maxLength) {
186
+ return false;
187
+ }
188
+ return true;
189
+ };
190
+ const addonContent = React.useMemo(() => {
191
+ // because we're using a separate "addon" element for the placeholder decimals, there is a possibility that the input itself will become scrollable
192
+ // and the decimals will appear on top of the input. Safest thing to do is to just hide the addon if there is not enough room
193
+ if (utils.isInputPossiblyOverflowing({
194
+ ref,
195
+ value
196
+ })) {
197
+ return null;
198
+ }
199
+ if (!decimalSeparator || !value) {
200
+ return null;
201
+ }
202
+ // if the user has typed a decimal separator, show the full decimal part as a placeholder
203
+ // this returns a string even if there is no content, typing should replace the placeholder immediately without animation
204
+ // otherwise there is an ugly animation when going from 1.23 to 1.2 due to AnimatePresence
205
+ if (focus && decimalMode) {
206
+ // reuse getDecimalPart
207
+ const fullDecimalPart = getDecimalPart(valueWithFullDecimals, decimalSeparator);
208
+ // show only the characters that are not already displayed by the input
209
+ return fullDecimalPart?.slice(decimalPart?.length);
210
+ }
211
+ // in unfocused state, always show the full decimal part unless the user has already entered decimals
212
+ if (!focus && !decimalMode) {
213
+ const [_, decimalPlaceholder] = placeholder.split(decimalSeparator);
214
+ return decimalSeparator + decimalPlaceholder;
215
+ }
216
+ return null;
217
+ }, [decimalMode, decimalPart?.length, decimalSeparator, focus, placeholder, value, valueWithFullDecimals]);
218
+ const style = useInputStyle.useInputStyle({
219
+ // whenever decimals are shown, we need to account for the full decimal part for the font size calculation
220
+ value: addonContent ? valueWithFullDecimals : value,
221
+ focus: visualFocus,
222
+ inputElement: ref.current,
223
+ loading
224
+ });
225
+ return /*#__PURE__*/jsxRuntime.jsx("div", {
226
+ className: "wds-amount-input-container",
227
+ children: /*#__PURE__*/jsxRuntime.jsxs("div", {
228
+ className: clsx.clsx('wds-amount-input-input-container', 'np-text-display-large'),
229
+ style: style,
230
+ children: [/*#__PURE__*/jsxRuntime.jsx("input", {
231
+ ref: ref,
232
+ className: "wds-amount-input-input",
233
+ id: id,
234
+ autoComplete: "off",
235
+ inputMode: "decimal",
236
+ value: value,
237
+ type: "text",
238
+ placeholder: placeholder,
239
+ "aria-describedby": describedById
240
+ /* without this, the input tries to keep an aspect ratio and doesn't respect CSS width rules */,
241
+ size: 1,
242
+ onChange: e => {
243
+ if (isAllowedInput(e)) {
244
+ handleChange(e.target.value);
245
+ }
246
+ },
247
+ onBlurCapture: () => handleBlur(),
248
+ onPaste: e => handlePaste(e),
249
+ onFocus: () => {
250
+ setFocus(true);
251
+ },
252
+ onBlur: () => {
253
+ setTimeout(() => setVisualFocus(false), 30);
254
+ },
255
+ onKeyDown: e => handleKeyDown(e)
256
+ }), /*#__PURE__*/jsxRuntime.jsx(framerMotion.AnimatePresence, {
257
+ initial: false,
258
+ children: addonContent !== null && /*#__PURE__*/jsxRuntime.jsx(AnimatedNumber.AnimatedNumber, {
259
+ className: clsx.clsx('wds-amount-input-placeholder', visualFocus && 'wds-amount-input-placeholder-focus'),
260
+ onClick: () => ref.current?.focus(),
261
+ children: addonContent
262
+ })
263
+ })]
264
+ })
265
+ });
266
+ };
267
+ const getPlaceholder = (currency, locale) => {
268
+ return formatting.formatAmount(0, currency, locale, {
269
+ alwaysShowDecimals: true
270
+ });
271
+ };
272
+ const getDecimalPart = (value, decimalSeparator) => {
273
+ if (!value || !decimalSeparator) {
274
+ return undefined;
275
+ }
276
+ const [_, decimalPart] = value.split(decimalSeparator);
277
+ return decimalPart ?? undefined;
278
+ };
279
+
280
+ exports.AmountInput = AmountInput;
281
+ //# sourceMappingURL=AmountInput.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"AmountInput.js","sources":["../../../src/expressiveMoneyInput/amountInput/AmountInput.tsx"],"sourcesContent":["import { formatAmount } from '@transferwise/formatting';\nimport { clsx } from 'clsx';\nimport { AnimatePresence } from 'framer-motion';\nimport { type ChangeEvent, type KeyboardEvent, useEffect, useMemo, useRef, useState } from 'react';\nimport { useIntl } from 'react-intl';\n\nimport { Props as ExpressiveMoneyInputProps } from '../ExpressiveMoneyInput';\nimport { AnimatedNumber } from '../animatedNumber/AnimatedNumber';\nimport { useFocus } from '../hooks/useFocus';\nimport { useInputStyle } from '../hooks/useInputStyle';\nimport {\n getDecimalCount,\n getDecimalSeparator,\n getEnteredDecimalsCount,\n getFormattedString,\n getGroupSeparator,\n getUnformattedNumber,\n isAllowedInputKey,\n isInputPossiblyOverflowing,\n} from './utils';\n\ntype Props = {\n id: string;\n describedById?: string;\n amount?: number | null;\n currency: string;\n autoFocus?: boolean;\n onChange: (amount: number | null) => void;\n onFocusChange?: (focused: boolean) => void;\n} & Pick<ExpressiveMoneyInputProps, 'loading'>;\n\nexport const AmountInput = ({\n id,\n describedById,\n amount,\n currency,\n autoFocus,\n onChange,\n onFocusChange,\n loading,\n}: Props) => {\n const intl = useIntl();\n const { focus, setFocus, visualFocus, setVisualFocus } = useFocus();\n\n const [value, setValue] = useState<string>(\n amount\n ? getFormattedString({\n value: amount,\n currency,\n locale: intl.locale,\n })\n : '',\n );\n const numericValue = useMemo(() => {\n return getUnformattedNumber({\n value,\n currency,\n locale: intl.locale,\n });\n }, [value, currency, intl.locale]);\n\n const valueWithFullDecimals = useMemo(() => {\n return getFormattedString({\n value: numericValue ?? 0,\n currency,\n locale: intl.locale,\n alwaysShowDecimals: true,\n });\n }, [numericValue, currency, intl.locale]);\n\n const ref = useRef<HTMLInputElement>(null);\n\n useEffect(() => {\n if (autoFocus) {\n ref.current?.focus();\n }\n }, []);\n\n const placeholder = getPlaceholder(currency, intl.locale);\n const groupSeparator = getGroupSeparator(currency, intl.locale);\n const decimalSeparator = getDecimalSeparator(currency, intl.locale);\n const maxDecimalCount = getDecimalCount(currency, intl.locale);\n\n const decimalPart = getDecimalPart(value, decimalSeparator);\n const decimalMode = decimalSeparator && value.includes(decimalSeparator);\n\n useEffect(() => {\n if (!focus) {\n setValue(\n amount\n ? getFormattedString({\n value: amount,\n currency,\n locale: intl.locale,\n })\n : '',\n );\n }\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [amount]);\n\n useEffect(() => {\n onFocusChange?.(visualFocus);\n }, [visualFocus]);\n\n const shouldReformatAfterUserInput = (newValue: string) => {\n // don't reformat if formatting would wipe out user's input\n if (reformatValue(newValue) === '') {\n return false;\n }\n\n const endsWithDecimalSeparator = decimalSeparator && newValue.endsWith(decimalSeparator);\n const endsWithGroupSeparator = groupSeparator && newValue.endsWith(groupSeparator);\n\n // if the user has entered a seperator to the end, formatting would delete it\n if (endsWithDecimalSeparator || endsWithGroupSeparator) {\n return false;\n }\n\n const containsDecimalSeparator = decimalSeparator && newValue.includes(decimalSeparator);\n\n if (containsDecimalSeparator) {\n const enteredDecimalsCount = getEnteredDecimalsCount(newValue, decimalSeparator);\n // don't reformat until user has entered all the allowed decimals\n // for example, we don't want 1.1 to be reformatted to 1.10 immediately\n if (enteredDecimalsCount < maxDecimalCount) {\n return false;\n }\n }\n\n return true;\n };\n\n const reformatValue = (newValue: string) => {\n const unformattedValue = getUnformattedNumber({\n value: newValue,\n currency,\n locale: intl.locale,\n });\n const formattedValue = unformattedValue\n ? getFormattedString({\n value: unformattedValue,\n currency,\n locale: intl.locale,\n })\n : '';\n return formattedValue;\n };\n\n const handleChange = (newValue: string) => {\n const oldCursorPosition = ref.current?.selectionStart ?? 0;\n\n const newFormattedString = shouldReformatAfterUserInput(newValue)\n ? reformatValue(newValue)\n : newValue;\n setValue(newFormattedString);\n\n const newNumber = getUnformattedNumber({\n value: newFormattedString,\n currency,\n locale: intl.locale,\n });\n\n if (newNumber !== numericValue) {\n if (numericValue || newNumber) {\n onChange(newNumber);\n }\n }\n\n const newCursorPosition = oldCursorPosition + (newFormattedString.length - newValue.length);\n requestAnimationFrame(() => {\n ref?.current?.setSelectionRange(newCursorPosition, newCursorPosition);\n });\n };\n\n const handlePaste = (e: React.ClipboardEvent<HTMLInputElement>) => {\n e.preventDefault();\n\n const clipboardData = e.clipboardData?.getData('text/plain');\n if (!clipboardData) {\n return;\n }\n\n // need to sanitise the pasted value otherwise other validation logic will ignore the input entirely\n const sanitisedValue = reformatValue(clipboardData);\n\n handleChange(sanitisedValue);\n };\n\n const handleBlur = () => {\n setFocus(false);\n setValue(reformatValue(value));\n };\n\n const handleBackspace = (e: KeyboardEvent<HTMLInputElement>) => {\n const input = e.target as HTMLInputElement;\n // using the updated selection range after the backspace key has been processed, instead of the current selection range in state\n const { value: currentValue, selectionStart, selectionEnd } = input;\n\n if (selectionStart === selectionEnd && selectionStart && selectionStart > 0) {\n const charBeforeCursor = currentValue[selectionStart - 1];\n\n // if the user deletes a thousands separator, remove the digit before it as well\n if (charBeforeCursor === groupSeparator) {\n e.preventDefault();\n const beforeCursor = currentValue.slice(0, selectionStart - 2);\n const afterCursor = currentValue.slice(selectionStart);\n const newValue = `${beforeCursor}${afterCursor}`;\n input.setSelectionRange(beforeCursor.length, beforeCursor.length);\n handleChange(newValue);\n }\n }\n };\n\n const handleKeyDown = (e: KeyboardEvent<HTMLInputElement>) => {\n setFocus(true);\n if (!isAllowedInputKey(e)) {\n e.preventDefault();\n }\n\n if (e.key === 'Backspace') {\n handleBackspace(e);\n }\n };\n\n const isAllowedInput = (e: ChangeEvent<HTMLInputElement>) => {\n const hasMultipleDecimalSeparators =\n decimalSeparator && e.target.value.split(decimalSeparator).length > 2;\n if (hasMultipleDecimalSeparators) {\n return false;\n }\n\n const newNumericValue = getUnformattedNumber({\n value: e.target.value,\n currency,\n locale: intl.locale,\n });\n const maxLength = Number.MAX_SAFE_INTEGER.toString().length;\n if (String(newNumericValue).length > maxLength) {\n return false;\n }\n\n return true;\n };\n\n const addonContent = useMemo((): string | null | undefined => {\n // because we're using a separate \"addon\" element for the placeholder decimals, there is a possibility that the input itself will become scrollable\n // and the decimals will appear on top of the input. Safest thing to do is to just hide the addon if there is not enough room\n if (isInputPossiblyOverflowing({ ref, value })) {\n return null;\n }\n if (!decimalSeparator || !value) {\n return null;\n }\n\n // if the user has typed a decimal separator, show the full decimal part as a placeholder\n // this returns a string even if there is no content, typing should replace the placeholder immediately without animation\n // otherwise there is an ugly animation when going from 1.23 to 1.2 due to AnimatePresence\n if (focus && decimalMode) {\n // reuse getDecimalPart\n const fullDecimalPart = getDecimalPart(valueWithFullDecimals, decimalSeparator);\n // show only the characters that are not already displayed by the input\n return fullDecimalPart?.slice(decimalPart?.length);\n }\n\n // in unfocused state, always show the full decimal part unless the user has already entered decimals\n if (!focus && !decimalMode) {\n const [_, decimalPlaceholder] = placeholder.split(decimalSeparator);\n return decimalSeparator + decimalPlaceholder;\n }\n\n return null;\n }, [\n decimalMode,\n decimalPart?.length,\n decimalSeparator,\n focus,\n placeholder,\n value,\n valueWithFullDecimals,\n ]);\n\n const style = useInputStyle({\n // whenever decimals are shown, we need to account for the full decimal part for the font size calculation\n value: addonContent ? valueWithFullDecimals : value,\n focus: visualFocus,\n inputElement: ref.current,\n loading,\n });\n\n return (\n <div className=\"wds-amount-input-container\">\n <div\n className={clsx('wds-amount-input-input-container', 'np-text-display-large')}\n style={style}\n >\n <input\n ref={ref}\n className=\"wds-amount-input-input\"\n id={id}\n autoComplete=\"off\"\n inputMode=\"decimal\"\n value={value}\n type=\"text\"\n placeholder={placeholder}\n aria-describedby={describedById}\n /* without this, the input tries to keep an aspect ratio and doesn't respect CSS width rules */\n size={1}\n onChange={(e) => {\n if (isAllowedInput(e)) {\n handleChange(e.target.value);\n }\n }}\n onBlurCapture={() => handleBlur()}\n onPaste={(e) => handlePaste(e)}\n onFocus={() => {\n setFocus(true);\n }}\n onBlur={() => {\n setTimeout(() => setVisualFocus(false), 30);\n }}\n onKeyDown={(e) => handleKeyDown(e)}\n />\n <AnimatePresence initial={false}>\n {addonContent !== null && (\n <AnimatedNumber\n className={clsx(\n 'wds-amount-input-placeholder',\n visualFocus && 'wds-amount-input-placeholder-focus',\n )}\n onClick={() => ref.current?.focus()}\n >\n {addonContent}\n </AnimatedNumber>\n )}\n </AnimatePresence>\n </div>\n </div>\n );\n};\n\nconst getPlaceholder = (currency: string, locale: string) => {\n return formatAmount(0, currency, locale, { alwaysShowDecimals: true });\n};\n\nconst getDecimalPart = (value: string, decimalSeparator: string | null) => {\n if (!value || !decimalSeparator) {\n return undefined;\n }\n\n const [_, decimalPart] = value.split(decimalSeparator);\n return decimalPart ?? undefined;\n};\n"],"names":["AmountInput","id","describedById","amount","currency","autoFocus","onChange","onFocusChange","loading","intl","useIntl","focus","setFocus","visualFocus","setVisualFocus","useFocus","value","setValue","useState","getFormattedString","locale","numericValue","useMemo","getUnformattedNumber","valueWithFullDecimals","alwaysShowDecimals","ref","useRef","useEffect","current","placeholder","getPlaceholder","groupSeparator","getGroupSeparator","decimalSeparator","getDecimalSeparator","maxDecimalCount","getDecimalCount","decimalPart","getDecimalPart","decimalMode","includes","shouldReformatAfterUserInput","newValue","reformatValue","endsWithDecimalSeparator","endsWith","endsWithGroupSeparator","containsDecimalSeparator","enteredDecimalsCount","getEnteredDecimalsCount","unformattedValue","formattedValue","handleChange","oldCursorPosition","selectionStart","newFormattedString","newNumber","newCursorPosition","length","requestAnimationFrame","setSelectionRange","handlePaste","e","preventDefault","clipboardData","getData","sanitisedValue","handleBlur","handleBackspace","input","target","currentValue","selectionEnd","charBeforeCursor","beforeCursor","slice","afterCursor","handleKeyDown","isAllowedInputKey","key","isAllowedInput","hasMultipleDecimalSeparators","split","newNumericValue","maxLength","Number","MAX_SAFE_INTEGER","toString","String","addonContent","isInputPossiblyOverflowing","fullDecimalPart","_","decimalPlaceholder","style","useInputStyle","inputElement","_jsx","className","children","_jsxs","clsx","autoComplete","inputMode","type","size","onBlurCapture","onPaste","onFocus","onBlur","setTimeout","onKeyDown","AnimatePresence","initial","AnimatedNumber","onClick","formatAmount","undefined"],"mappings":"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"}