@transferwise/components 46.57.1 → 46.58.1
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/i18n/tr.json +1 -1
- package/build/i18n/tr.json.js +1 -1
- package/build/i18n/tr.json.mjs +1 -1
- package/build/index.js +2 -0
- package/build/index.js.map +1 -1
- package/build/index.mjs +1 -0
- package/build/index.mjs.map +1 -1
- package/build/inlineAlert/InlineAlert.js +3 -1
- package/build/inlineAlert/InlineAlert.js.map +1 -1
- package/build/inlineAlert/InlineAlert.mjs +3 -1
- package/build/inlineAlert/InlineAlert.mjs.map +1 -1
- package/build/moneyInput/MoneyInput.js +8 -3
- package/build/moneyInput/MoneyInput.js.map +1 -1
- package/build/moneyInput/MoneyInput.mjs +8 -3
- package/build/moneyInput/MoneyInput.mjs.map +1 -1
- package/build/types/index.d.ts +5 -0
- package/build/types/index.d.ts.map +1 -1
- package/build/types/moneyInput/MoneyInput.d.ts +7 -3
- package/build/types/moneyInput/MoneyInput.d.ts.map +1 -1
- package/build/types/withId/index.d.ts +3 -0
- package/build/types/withId/index.d.ts.map +1 -0
- package/build/types/withId/story/source.d.ts +2 -0
- package/build/types/withId/story/source.d.ts.map +1 -0
- package/build/types/withId/withId.d.ts +17 -0
- package/build/types/withId/withId.d.ts.map +1 -0
- package/build/withId/withId.js +19 -0
- package/build/withId/withId.js.map +1 -0
- package/build/withId/withId.mjs +17 -0
- package/build/withId/withId.mjs.map +1 -0
- package/package.json +3 -3
- package/src/i18n/tr.json +1 -1
- package/src/index.ts +6 -0
- package/src/inlineAlert/InlineAlert.story.tsx +10 -23
- package/src/inlineAlert/InlineAlert.tsx +1 -1
- package/src/moneyInput/MoneyInput.spec.js +19 -6
- package/src/moneyInput/MoneyInput.story.tsx +8 -9
- package/src/moneyInput/MoneyInput.tsx +8 -5
- package/src/radioGroup/RadioGroup.story.tsx +70 -69
- package/src/withId/index.ts +2 -0
- package/src/withId/story/source.tsx +22 -0
- package/src/withId/withId.docs.mdx +33 -0
- package/src/withId/withId.spec.tsx +28 -0
- package/src/withId/withId.story.tsx +41 -0
- package/src/withId/withId.tsx +27 -0
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { WrappedComponentProps } from 'react-intl';
|
|
2
|
-
import { SizeLarge, SizeMedium, SizeSmall } from '../common
|
|
2
|
+
import { SizeLarge, SizeMedium, SizeSmall } from '../common';
|
|
3
3
|
import { WithInputAttributesProps } from '../inputs/contexts';
|
|
4
4
|
import { SelectInputProps } from '../inputs/SelectInput';
|
|
5
5
|
export interface CurrencyOptionItem {
|
|
@@ -39,8 +39,12 @@ export interface MoneyInputProps extends WrappedComponentProps {
|
|
|
39
39
|
selectProps?: Partial<SelectInputProps<CurrencyOptionItem>>;
|
|
40
40
|
}
|
|
41
41
|
type MoneyInputPropsWithInputAttributes = MoneyInputProps & Partial<WithInputAttributesProps>;
|
|
42
|
-
declare const _default: import("react").FC<import("react-intl").WithIntlProps<Omit<MoneyInputPropsWithInputAttributes, "inputAttributes"
|
|
43
|
-
|
|
42
|
+
declare const _default: import("react").FC<import("react-intl").WithIntlProps<Omit<MoneyInputPropsWithInputAttributes, "inputAttributes"> & {
|
|
43
|
+
id?: string;
|
|
44
|
+
}>> & {
|
|
45
|
+
WrappedComponent: import("react").ComponentType<Omit<MoneyInputPropsWithInputAttributes, "inputAttributes"> & {
|
|
46
|
+
id?: string;
|
|
47
|
+
}>;
|
|
44
48
|
};
|
|
45
49
|
export default _default;
|
|
46
50
|
//# sourceMappingURL=MoneyInput.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"MoneyInput.d.ts","sourceRoot":"","sources":["../../../src/moneyInput/MoneyInput.tsx"],"names":[],"mappings":"AAIA,OAAO,EAAc,qBAAqB,EAAE,MAAM,YAAY,CAAC;
|
|
1
|
+
{"version":3,"file":"MoneyInput.d.ts","sourceRoot":"","sources":["../../../src/moneyInput/MoneyInput.tsx"],"names":[],"mappings":"AAIA,OAAO,EAAc,qBAAqB,EAAE,MAAM,YAAY,CAAC;AAE/D,OAAO,EAAoB,SAAS,EAAE,UAAU,EAAE,SAAS,EAAE,MAAM,WAAW,CAAC;AAC/E,OAAO,EAAuB,wBAAwB,EAAE,MAAM,oBAAoB,CAAC;AAEnF,OAAO,EAKL,gBAAgB,EACjB,MAAM,uBAAuB,CAAC;AAO/B,MAAM,WAAW,kBAAkB;IACjC,MAAM,CAAC,EAAE,KAAK,CAAC;IACf,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,EAAE,MAAM,CAAC;IACjB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB;AAED,MAAM,WAAW,kBAAkB;IACjC,MAAM,EAAE,MAAM,CAAC;CAChB;AAED,MAAM,MAAM,YAAY,GAAG,kBAAkB,GAAG,kBAAkB,CAAC;AA0CnE,MAAM,WAAW,eAAgB,SAAQ,qBAAqB;IAC5D,EAAE,CAAC,EAAE,MAAM,CAAC;IACZ,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAC3B,UAAU,EAAE,SAAS,YAAY,EAAE,CAAC;IACpC,gBAAgB,EAAE,kBAAkB,CAAC;IACrC,gBAAgB,CAAC,EAAE,CAAC,KAAK,EAAE,kBAAkB,KAAK,IAAI,CAAC;IACvD,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC;IACtB,IAAI,CAAC,EAAE,SAAS,GAAG,UAAU,GAAG,SAAS,CAAC;IAC1C,cAAc,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI,KAAK,IAAI,CAAC;IAChD,KAAK,CAAC,EAAE,KAAK,CAAC,SAAS,CAAC;IACxB,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAC3B;;OAEG;IACH,cAAc,CAAC,EAAE,CAAC,KAAK,EAAE;QAAE,WAAW,EAAE,MAAM,CAAC;QAAC,eAAe,EAAE,YAAY,EAAE,CAAA;KAAE,KAAK,IAAI,CAAC;IAC3F,iBAAiB,CAAC,EAAE,KAAK,CAAC,SAAS,CAAC;IACpC,cAAc,CAAC,EAAE,MAAM,IAAI,CAAC;IAC5B,UAAU,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACpC,WAAW,CAAC,EAAE,OAAO,CAAC,gBAAgB,CAAC,kBAAkB,CAAC,CAAC,CAAC;CAC7D;AAED,KAAK,kCAAkC,GAAG,eAAe,GAAG,OAAO,CAAC,wBAAwB,CAAC,CAAC;;;;;;;;AA0Y9F,wBAA2F"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/withId/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,UAAU,CAAC;AACnC,YAAY,EAAE,WAAW,EAAE,MAAM,UAAU,CAAC"}
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
export declare const withIdSource = "\nimport { withId, Button, type WithIdProps } from '@transferwise/components';\n\ntype DescribedButtonProps = { id?: string };\ntype DescribedButtonWithIdProps = WithIdProps<DescribedButtonProps>;\n\nfunction DescribedButton({ id }: DescribedButtonWithIdProps) {\n return (\n <>\n <Button aria-describedby={id}>Continue</Button>\n\n <p id={id} className=\"text-xs-center m-t-2\">\n Enter an amount in either GBP or PLN\n <br />\n This paragraph has id of <code>{id}</code>\n </p>\n </>\n );\n}\n\nexport default withId<DescribedButtonProps>(DescribedButton);\n";
|
|
2
|
+
//# sourceMappingURL=source.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"source.d.ts","sourceRoot":"","sources":["../../../../src/withId/story/source.tsx"],"names":[],"mappings":"AAAA,eAAO,MAAM,YAAY,imBAqBxB,CAAC"}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { ComponentType } from 'react';
|
|
2
|
+
type ChildProps<Props> = Props & {
|
|
3
|
+
id?: string;
|
|
4
|
+
};
|
|
5
|
+
export type WithIdProps<Props> = Props & {
|
|
6
|
+
id: string;
|
|
7
|
+
};
|
|
8
|
+
/**
|
|
9
|
+
* @internal
|
|
10
|
+
* @param {ReactNode} WrappedComponent
|
|
11
|
+
*/
|
|
12
|
+
export default function withId<Props extends object>(WrappedComponent: ComponentType<WithIdProps<Props>>): {
|
|
13
|
+
(props: ChildProps<Props>): import("react").JSX.Element;
|
|
14
|
+
displayName: string;
|
|
15
|
+
};
|
|
16
|
+
export {};
|
|
17
|
+
//# sourceMappingURL=withId.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"withId.d.ts","sourceRoot":"","sources":["../../../src/withId/withId.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAS,aAAa,EAAE,MAAM,OAAO,CAAC;AAE7C,KAAK,UAAU,CAAC,KAAK,IAAI,KAAK,GAAG;IAC/B,EAAE,CAAC,EAAE,MAAM,CAAC;CACb,CAAC;AAEF,MAAM,MAAM,WAAW,CAAC,KAAK,IAAI,KAAK,GAAG;IACvC,EAAE,EAAE,MAAM,CAAC;CACZ,CAAC;AAEF;;;GAGG;AACH,MAAM,CAAC,OAAO,UAAU,MAAM,CAAC,KAAK,SAAS,MAAM,EACjD,gBAAgB,EAAE,aAAa,CAAC,WAAW,CAAC,KAAK,CAAC,CAAC;YAEnB,UAAU,CAAC,KAAK,CAAC;;EASlD"}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
var React = require('react');
|
|
4
|
+
var jsxRuntime = require('react/jsx-runtime');
|
|
5
|
+
|
|
6
|
+
function withId(WrappedComponent) {
|
|
7
|
+
function WithIdComponent(props) {
|
|
8
|
+
const id = React.useId();
|
|
9
|
+
return /*#__PURE__*/jsxRuntime.jsx(WrappedComponent, {
|
|
10
|
+
...props,
|
|
11
|
+
id: props.id || id
|
|
12
|
+
});
|
|
13
|
+
}
|
|
14
|
+
WithIdComponent.displayName = `withId(${WrappedComponent.displayName || WrappedComponent.name || 'Component'})`;
|
|
15
|
+
return WithIdComponent;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
module.exports = withId;
|
|
19
|
+
//# sourceMappingURL=withId.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"withId.js","sources":["../../src/withId/withId.tsx"],"sourcesContent":["import { useId, ComponentType } from 'react';\n\ntype ChildProps<Props> = Props & {\n id?: string;\n};\n\nexport type WithIdProps<Props> = Props & {\n id: string;\n};\n\n/**\n * @internal\n * @param {ReactNode} WrappedComponent\n */\nexport default function withId<Props extends object>(\n WrappedComponent: ComponentType<WithIdProps<Props>>,\n) {\n function WithIdComponent(props: ChildProps<Props>) {\n const id = useId();\n\n return <WrappedComponent {...props} id={props.id || id} />;\n }\n\n WithIdComponent.displayName = `withId(${WrappedComponent.displayName || WrappedComponent.name || 'Component'})`;\n\n return WithIdComponent;\n}\n"],"names":["withId","WrappedComponent","WithIdComponent","props","id","useId","_jsx","displayName","name"],"mappings":";;;;;AAcwB,SAAAA,MAAMA,CAC5BC,gBAAmD,EAAA;EAEnD,SAASC,eAAeA,CAACC,KAAwB,EAAA;AAC/C,IAAA,MAAMC,EAAE,GAAGC,WAAK,EAAE,CAAA;IAElB,oBAAOC,cAAA,CAACL,gBAAgB,EAAA;AAAA,MAAA,GAAKE,KAAK;AAAEC,MAAAA,EAAE,EAAED,KAAK,CAACC,EAAE,IAAIA,EAAAA;AAAG,MAAG,CAAA;AAC5D,GAAA;AAEAF,EAAAA,eAAe,CAACK,WAAW,GAAG,CAAA,OAAA,EAAUN,gBAAgB,CAACM,WAAW,IAAIN,gBAAgB,CAACO,IAAI,IAAI,WAAW,CAAG,CAAA,CAAA,CAAA;AAE/G,EAAA,OAAON,eAAe,CAAA;AACxB;;;;"}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { useId } from 'react';
|
|
2
|
+
import { jsx } from 'react/jsx-runtime';
|
|
3
|
+
|
|
4
|
+
function withId(WrappedComponent) {
|
|
5
|
+
function WithIdComponent(props) {
|
|
6
|
+
const id = useId();
|
|
7
|
+
return /*#__PURE__*/jsx(WrappedComponent, {
|
|
8
|
+
...props,
|
|
9
|
+
id: props.id || id
|
|
10
|
+
});
|
|
11
|
+
}
|
|
12
|
+
WithIdComponent.displayName = `withId(${WrappedComponent.displayName || WrappedComponent.name || 'Component'})`;
|
|
13
|
+
return WithIdComponent;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
export { withId as default };
|
|
17
|
+
//# sourceMappingURL=withId.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"withId.mjs","sources":["../../src/withId/withId.tsx"],"sourcesContent":["import { useId, ComponentType } from 'react';\n\ntype ChildProps<Props> = Props & {\n id?: string;\n};\n\nexport type WithIdProps<Props> = Props & {\n id: string;\n};\n\n/**\n * @internal\n * @param {ReactNode} WrappedComponent\n */\nexport default function withId<Props extends object>(\n WrappedComponent: ComponentType<WithIdProps<Props>>,\n) {\n function WithIdComponent(props: ChildProps<Props>) {\n const id = useId();\n\n return <WrappedComponent {...props} id={props.id || id} />;\n }\n\n WithIdComponent.displayName = `withId(${WrappedComponent.displayName || WrappedComponent.name || 'Component'})`;\n\n return WithIdComponent;\n}\n"],"names":["withId","WrappedComponent","WithIdComponent","props","id","useId","_jsx","displayName","name"],"mappings":";;;AAcwB,SAAAA,MAAMA,CAC5BC,gBAAmD,EAAA;EAEnD,SAASC,eAAeA,CAACC,KAAwB,EAAA;AAC/C,IAAA,MAAMC,EAAE,GAAGC,KAAK,EAAE,CAAA;IAElB,oBAAOC,GAAA,CAACL,gBAAgB,EAAA;AAAA,MAAA,GAAKE,KAAK;AAAEC,MAAAA,EAAE,EAAED,KAAK,CAACC,EAAE,IAAIA,EAAAA;AAAG,MAAG,CAAA;AAC5D,GAAA;AAEAF,EAAAA,eAAe,CAACK,WAAW,GAAG,CAAA,OAAA,EAAUN,gBAAgB,CAACM,WAAW,IAAIN,gBAAgB,CAACO,IAAI,IAAI,WAAW,CAAG,CAAA,CAAA,CAAA;AAE/G,EAAA,OAAON,eAAe,CAAA;AACxB;;;;"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@transferwise/components",
|
|
3
|
-
"version": "46.
|
|
3
|
+
"version": "46.58.1",
|
|
4
4
|
"description": "Neptune React components",
|
|
5
5
|
"license": "Apache-2.0",
|
|
6
6
|
"repository": {
|
|
@@ -93,8 +93,8 @@
|
|
|
93
93
|
"rollup-preserve-directives": "^1.1.1",
|
|
94
94
|
"storybook": "^8.2.2",
|
|
95
95
|
"@transferwise/less-config": "3.1.0",
|
|
96
|
-
"@
|
|
97
|
-
"@
|
|
96
|
+
"@transferwise/neptune-css": "14.13.4",
|
|
97
|
+
"@wise/components-theming": "1.6.0"
|
|
98
98
|
},
|
|
99
99
|
"peerDependencies": {
|
|
100
100
|
"@transferwise/icons": "^3.7.0",
|
package/src/i18n/tr.json
CHANGED
|
@@ -18,7 +18,7 @@
|
|
|
18
18
|
"neptune.DateLookup.year": "yıl",
|
|
19
19
|
"neptune.FlowNavigation.back": "önceki adıma dön",
|
|
20
20
|
"neptune.Info.ariaLabel": "Daha fazla bilgi",
|
|
21
|
-
"neptune.Label.optional": "(
|
|
21
|
+
"neptune.Label.optional": "(İsteğe bağlı)",
|
|
22
22
|
"neptune.Link.opensInNewTab": "(yeni sekmede açılır)",
|
|
23
23
|
"neptune.MoneyInput.Select.placeholder": "Bir seçenek seçin...",
|
|
24
24
|
"neptune.PhoneNumberInput.SelectInput.placeholder": "Bir seçenek seçin...",
|
package/src/index.ts
CHANGED
|
@@ -89,6 +89,7 @@ export type { TooltipProps } from './tooltip';
|
|
|
89
89
|
export type { TypeaheadOption, TypeaheadProps } from './typeahead';
|
|
90
90
|
export type { UploadProps } from './upload';
|
|
91
91
|
export type { UploadError, UploadResponse, UploadedFile } from './uploadInput/types';
|
|
92
|
+
export type { WithIdProps } from './withId';
|
|
92
93
|
|
|
93
94
|
/**
|
|
94
95
|
* Components
|
|
@@ -244,3 +245,8 @@ export {
|
|
|
244
245
|
* Translations
|
|
245
246
|
*/
|
|
246
247
|
export { default as translations } from './i18n';
|
|
248
|
+
|
|
249
|
+
/**
|
|
250
|
+
* HoCs
|
|
251
|
+
*/
|
|
252
|
+
export { default as withId } from './withId';
|
|
@@ -1,10 +1,8 @@
|
|
|
1
|
-
import { select, text } from '@storybook/addon-knobs';
|
|
2
1
|
import { Meta } from '@storybook/react';
|
|
3
2
|
|
|
4
|
-
import { Sentiment } from '../common';
|
|
5
|
-
|
|
6
3
|
import InlineAlert, { InlineAlertProps } from './InlineAlert';
|
|
7
|
-
import { lorem40 } from '../test-utils';
|
|
4
|
+
import { lorem10, lorem40 } from '../test-utils';
|
|
5
|
+
import Link from '../link';
|
|
8
6
|
|
|
9
7
|
export default {
|
|
10
8
|
component: InlineAlert,
|
|
@@ -12,23 +10,6 @@ export default {
|
|
|
12
10
|
} as Meta<InlineAlertProps>;
|
|
13
11
|
|
|
14
12
|
export const Basic = () => {
|
|
15
|
-
const type = select(
|
|
16
|
-
'type',
|
|
17
|
-
[
|
|
18
|
-
Sentiment.POSITIVE,
|
|
19
|
-
Sentiment.NEGATIVE,
|
|
20
|
-
Sentiment.NEUTRAL,
|
|
21
|
-
Sentiment.WARNING,
|
|
22
|
-
Sentiment.PENDING,
|
|
23
|
-
Sentiment.ERROR,
|
|
24
|
-
Sentiment.INFO,
|
|
25
|
-
Sentiment.SUCCESS,
|
|
26
|
-
],
|
|
27
|
-
Sentiment.WARNING,
|
|
28
|
-
);
|
|
29
|
-
|
|
30
|
-
const message = text('message', 'Please enter a password over 5 characters');
|
|
31
|
-
|
|
32
13
|
return (
|
|
33
14
|
<>
|
|
34
15
|
<p>
|
|
@@ -36,8 +17,14 @@ export const Basic = () => {
|
|
|
36
17
|
control validation, info messaging please use <code>Field</code> component
|
|
37
18
|
<pre>{'<Field sentiment={..} message={..}>'}</pre>
|
|
38
19
|
</p>
|
|
39
|
-
<InlineAlert type=
|
|
40
|
-
|
|
20
|
+
<InlineAlert type="neutral">
|
|
21
|
+
You have <Link href="#">20.22 EUR</Link> available in <strong>My savings</strong>
|
|
22
|
+
</InlineAlert>
|
|
23
|
+
<InlineAlert type="warning">
|
|
24
|
+
You have <Link href="#">20.22 EUR</Link> available in <strong>My savings</strong>
|
|
25
|
+
</InlineAlert>
|
|
26
|
+
<InlineAlert type="warning">{lorem10}</InlineAlert>
|
|
27
|
+
<InlineAlert type="negative">{lorem10}</InlineAlert>
|
|
41
28
|
<InlineAlert type="positive">{lorem40}</InlineAlert>
|
|
42
29
|
</>
|
|
43
30
|
);
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { shallow } from 'enzyme';
|
|
2
|
+
import { render, screen } from '@testing-library/react';
|
|
2
3
|
|
|
3
4
|
import { MoneyInput, Title, Input, SelectInput } from '..';
|
|
4
5
|
import { mockMatchMedia, mockResizeObserver } from '../test-utils';
|
|
@@ -87,7 +88,9 @@ describe('Money Input', () => {
|
|
|
87
88
|
onAmountChange: jest.fn(),
|
|
88
89
|
onCurrencyChange: jest.fn(),
|
|
89
90
|
};
|
|
90
|
-
component = shallow(<MoneyInput {...props} />)
|
|
91
|
+
component = shallow(<MoneyInput {...props} />)
|
|
92
|
+
.dive()
|
|
93
|
+
.dive();
|
|
91
94
|
jest.clearAllMocks();
|
|
92
95
|
});
|
|
93
96
|
|
|
@@ -207,10 +210,10 @@ describe('Money Input', () => {
|
|
|
207
210
|
]);
|
|
208
211
|
});
|
|
209
212
|
|
|
210
|
-
it('renders Select component with
|
|
213
|
+
it('renders Select component with generated id when id is not provided', () => {
|
|
211
214
|
const select = component.find('SelectInput');
|
|
212
215
|
|
|
213
|
-
expect(select.prop('id')).
|
|
216
|
+
expect(select.prop('id')).toBeTruthy();
|
|
214
217
|
});
|
|
215
218
|
|
|
216
219
|
it('shows the currently active currency as active and hides its note', () => {
|
|
@@ -570,9 +573,7 @@ describe('Money Input', () => {
|
|
|
570
573
|
);
|
|
571
574
|
|
|
572
575
|
it('passes the id given to the input element', () => {
|
|
573
|
-
expect(amountInput().prop('id')).toBeUndefined();
|
|
574
576
|
component.setProps({ id: 'some-id' });
|
|
575
|
-
|
|
576
577
|
expect(amountInput().prop('id')).toBe('some-id');
|
|
577
578
|
});
|
|
578
579
|
|
|
@@ -804,7 +805,9 @@ describe('Money Input', () => {
|
|
|
804
805
|
}}
|
|
805
806
|
{...props}
|
|
806
807
|
/>,
|
|
807
|
-
)
|
|
808
|
+
)
|
|
809
|
+
.dive()
|
|
810
|
+
.dive();
|
|
808
811
|
});
|
|
809
812
|
|
|
810
813
|
it('renders Select component with expected props', () => {
|
|
@@ -815,4 +818,14 @@ describe('Money Input', () => {
|
|
|
815
818
|
});
|
|
816
819
|
});
|
|
817
820
|
});
|
|
821
|
+
|
|
822
|
+
describe('withId', () => {
|
|
823
|
+
it('should guarantee id and connect the input with the selected currency', () => {
|
|
824
|
+
render(<MoneyInput {...props} />);
|
|
825
|
+
const input = screen.getByRole('textbox');
|
|
826
|
+
const button = screen.getByRole('combobox');
|
|
827
|
+
expect(input.getAttribute('id')).toBeTruthy();
|
|
828
|
+
expect(input).toHaveAttribute('aria-describedby', button.getAttribute('id'));
|
|
829
|
+
});
|
|
830
|
+
});
|
|
818
831
|
});
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { Meta, StoryObj } from '@storybook/react';
|
|
2
|
-
import {
|
|
2
|
+
import { within, userEvent } from '@storybook/test';
|
|
3
3
|
import { Lock } from '@transferwise/icons';
|
|
4
4
|
import { useState } from 'react';
|
|
5
5
|
|
|
@@ -9,14 +9,13 @@ import { Field } from '../field/Field';
|
|
|
9
9
|
export default {
|
|
10
10
|
component: MoneyInput,
|
|
11
11
|
title: 'Forms/MoneyInput',
|
|
12
|
-
render: (args)
|
|
13
|
-
// eslint-disable-next-line react-hooks/rules-of-hooks
|
|
12
|
+
render: function Render(args) {
|
|
14
13
|
const [selectedCurrency, setSelectedCurrency] = useState(args.selectedCurrency);
|
|
15
14
|
|
|
16
15
|
const handleOnCurrencyChange = (value: CurrencyOptionItem) => setSelectedCurrency(value);
|
|
17
16
|
|
|
18
17
|
return (
|
|
19
|
-
<Field
|
|
18
|
+
<Field label="Editable money input label" required>
|
|
20
19
|
<MoneyInput
|
|
21
20
|
{...args}
|
|
22
21
|
selectedCurrency={selectedCurrency}
|
|
@@ -26,8 +25,8 @@ export default {
|
|
|
26
25
|
);
|
|
27
26
|
},
|
|
28
27
|
args: {
|
|
29
|
-
id: 'money-input',
|
|
30
28
|
amount: 1000,
|
|
29
|
+
id: 'moneyInput',
|
|
31
30
|
onAmountChange: () => {},
|
|
32
31
|
onCurrencyChange: () => {},
|
|
33
32
|
},
|
|
@@ -61,28 +60,28 @@ const exampleCurrency = {
|
|
|
61
60
|
hkd: {
|
|
62
61
|
value: 'HKD',
|
|
63
62
|
label: 'HKD',
|
|
64
|
-
note: 'Hong Kong',
|
|
63
|
+
note: 'Hong Kong dollar',
|
|
65
64
|
currency: 'hkd',
|
|
66
65
|
searchable: 'Hong Kong, Saudi Arabia',
|
|
67
66
|
},
|
|
68
67
|
aud: {
|
|
69
68
|
value: 'AUD',
|
|
70
69
|
label: 'AUD',
|
|
71
|
-
note: '
|
|
70
|
+
note: 'Australian dollar',
|
|
72
71
|
currency: 'aud',
|
|
73
72
|
searchable: 'Kenguru',
|
|
74
73
|
},
|
|
75
74
|
cny: {
|
|
76
75
|
value: 'CNY',
|
|
77
76
|
label: 'CNY',
|
|
78
|
-
note: '
|
|
77
|
+
note: 'Chinese yuan',
|
|
79
78
|
currency: 'cny',
|
|
80
79
|
searchable: 'China',
|
|
81
80
|
},
|
|
82
81
|
jpy: {
|
|
83
82
|
value: 'JPY',
|
|
84
83
|
label: 'JPY',
|
|
85
|
-
note: '
|
|
84
|
+
note: 'Japanese yen',
|
|
86
85
|
currency: 'jpy',
|
|
87
86
|
searchable: 'Japan',
|
|
88
87
|
},
|
|
@@ -4,8 +4,7 @@ import { clsx } from 'clsx';
|
|
|
4
4
|
import { Component } from 'react';
|
|
5
5
|
import { injectIntl, WrappedComponentProps } from 'react-intl';
|
|
6
6
|
|
|
7
|
-
import { Typography } from '../common';
|
|
8
|
-
import { Size, SizeLarge, SizeMedium, SizeSmall } from '../common/propsValues/size';
|
|
7
|
+
import { Typography, Size, SizeLarge, SizeMedium, SizeSmall } from '../common';
|
|
9
8
|
import { withInputAttributes, WithInputAttributesProps } from '../inputs/contexts';
|
|
10
9
|
import { Input } from '../inputs/Input';
|
|
11
10
|
import {
|
|
@@ -19,6 +18,7 @@ import Title from '../title';
|
|
|
19
18
|
|
|
20
19
|
import messages from './MoneyInput.messages';
|
|
21
20
|
import { formatAmount, parseAmount } from './currencyFormatting';
|
|
21
|
+
import withId from '../withId';
|
|
22
22
|
|
|
23
23
|
export interface CurrencyOptionItem {
|
|
24
24
|
header?: never;
|
|
@@ -288,7 +288,6 @@ class MoneyInput extends Component<MoneyInputPropsWithInputAttributes, MoneyInpu
|
|
|
288
288
|
selectProps,
|
|
289
289
|
} = this.props;
|
|
290
290
|
const ariaLabelledBy = ariaLabelledByProp ?? inputAttributes?.['aria-labelledby'];
|
|
291
|
-
|
|
292
291
|
const selectOptions = this.getSelectOptions();
|
|
293
292
|
|
|
294
293
|
const hasSingleCurrency = () => {
|
|
@@ -314,8 +313,9 @@ class MoneyInput extends Component<MoneyInputPropsWithInputAttributes, MoneyInpu
|
|
|
314
313
|
};
|
|
315
314
|
|
|
316
315
|
const isFixedCurrency = (!this.state.searchQuery && hasSingleCurrency()) || !onCurrencyChange;
|
|
317
|
-
|
|
318
316
|
const disabled = !this.props.onAmountChange;
|
|
317
|
+
const selectedCurrencyElementId = `${amountInputId}SelectedCurrency`;
|
|
318
|
+
|
|
319
319
|
return (
|
|
320
320
|
<div
|
|
321
321
|
role="group"
|
|
@@ -338,6 +338,7 @@ class MoneyInput extends Component<MoneyInputPropsWithInputAttributes, MoneyInpu
|
|
|
338
338
|
locale: this.state.locale,
|
|
339
339
|
})}
|
|
340
340
|
autoComplete="off"
|
|
341
|
+
aria-describedby={selectedCurrencyElementId}
|
|
341
342
|
onKeyDown={this.handleKeyDown}
|
|
342
343
|
onChange={this.onAmountChange}
|
|
343
344
|
onFocus={this.onAmountFocus}
|
|
@@ -363,6 +364,7 @@ class MoneyInput extends Component<MoneyInputPropsWithInputAttributes, MoneyInpu
|
|
|
363
364
|
this.style('tw-money-input__fixed-currency'),
|
|
364
365
|
disabled ? this.style('disabled') : '',
|
|
365
366
|
)}
|
|
367
|
+
id={selectedCurrencyElementId}
|
|
366
368
|
>
|
|
367
369
|
{(size === 'lg' || size === 'md') && (
|
|
368
370
|
<span className={clsx(this.style('money-input-currency-flag'), this.style('m-r-2'))}>
|
|
@@ -385,6 +387,7 @@ class MoneyInput extends Component<MoneyInputPropsWithInputAttributes, MoneyInpu
|
|
|
385
387
|
)}
|
|
386
388
|
>
|
|
387
389
|
<SelectInput
|
|
390
|
+
id={selectedCurrencyElementId}
|
|
388
391
|
items={selectOptions}
|
|
389
392
|
value={selectedCurrency}
|
|
390
393
|
compareValues="currency"
|
|
@@ -488,4 +491,4 @@ function sortOptionsLabelsToFirst(options: readonly CurrencyOptionItem[], query:
|
|
|
488
491
|
});
|
|
489
492
|
}
|
|
490
493
|
|
|
491
|
-
export default injectIntl(withInputAttributes(MoneyInput, { nonLabelable: true }));
|
|
494
|
+
export default injectIntl(withId(withInputAttributes(MoneyInput, { nonLabelable: true })));
|
|
@@ -1,81 +1,82 @@
|
|
|
1
|
-
import { action } from '@storybook/addon-actions';
|
|
2
|
-
import { boolean } from '@storybook/addon-knobs';
|
|
3
1
|
import { Flag } from '@wise/art';
|
|
4
2
|
|
|
5
3
|
import Avatar, { AvatarType } from '../avatar';
|
|
6
4
|
|
|
7
|
-
import RadioGroup from './RadioGroup';
|
|
5
|
+
import RadioGroup, { RadioGroupProps, RadioGroupRadio } from './RadioGroup';
|
|
8
6
|
import { Field } from '../field/Field';
|
|
7
|
+
import { Meta, StoryObj } from '@storybook/react';
|
|
8
|
+
import { fn } from '@storybook/test';
|
|
9
|
+
import { useState } from 'react';
|
|
9
10
|
|
|
10
|
-
|
|
11
|
+
const meta = {
|
|
11
12
|
component: RadioGroup,
|
|
12
13
|
title: 'Forms/RadioGroup',
|
|
13
|
-
}
|
|
14
|
+
} satisfies Meta<typeof RadioGroup>;
|
|
14
15
|
|
|
15
|
-
export
|
|
16
|
-
|
|
17
|
-
const hasError = boolean('hasError', false);
|
|
16
|
+
export default meta;
|
|
17
|
+
type Story<T extends string | number = string> = StoryObj<RadioGroupProps<T>>;
|
|
18
18
|
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
19
|
+
export const Basic = {
|
|
20
|
+
args: {
|
|
21
|
+
selectedValue: 'radio-2',
|
|
22
|
+
name: 'radio-group',
|
|
23
|
+
radios: [
|
|
24
|
+
{
|
|
25
|
+
value: 'radio-1',
|
|
26
|
+
label: 'Radio1',
|
|
27
|
+
secondary: 'Secondary line 1',
|
|
28
|
+
disabled: false,
|
|
29
|
+
},
|
|
30
|
+
{
|
|
31
|
+
value: 'radio-2',
|
|
32
|
+
label: 'Radio2',
|
|
33
|
+
disabled: false,
|
|
34
|
+
},
|
|
35
|
+
{
|
|
36
|
+
value: 'radio-3',
|
|
37
|
+
label: 'Radio3',
|
|
38
|
+
secondary: 'Secondary line 3',
|
|
39
|
+
disabled: true,
|
|
40
|
+
},
|
|
41
|
+
],
|
|
42
|
+
onChange: fn(),
|
|
43
|
+
},
|
|
44
|
+
} satisfies Story;
|
|
24
45
|
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
avatar,
|
|
43
|
-
},
|
|
44
|
-
{
|
|
45
|
-
value: 'radio-3',
|
|
46
|
-
label: 'Radio3',
|
|
47
|
-
secondary: 'Secondary line 3',
|
|
48
|
-
disabled: true,
|
|
49
|
-
avatar,
|
|
50
|
-
},
|
|
51
|
-
]}
|
|
52
|
-
onChange={(v) => action(v)}
|
|
53
|
-
/>
|
|
54
|
-
</div>
|
|
55
|
-
);
|
|
56
|
-
};
|
|
46
|
+
export const WithAvatars = {
|
|
47
|
+
...Basic,
|
|
48
|
+
args: {
|
|
49
|
+
...Basic.args,
|
|
50
|
+
radios: Basic.args.radios.map(
|
|
51
|
+
(radio) =>
|
|
52
|
+
({
|
|
53
|
+
...radio,
|
|
54
|
+
avatar: (
|
|
55
|
+
<Avatar type={AvatarType.THUMBNAIL}>
|
|
56
|
+
<Flag code="NZD" />
|
|
57
|
+
</Avatar>
|
|
58
|
+
),
|
|
59
|
+
}) satisfies RadioGroupRadio,
|
|
60
|
+
),
|
|
61
|
+
},
|
|
62
|
+
} satisfies Story;
|
|
57
63
|
|
|
58
|
-
export const
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
onChange={(v) => action(v)}
|
|
78
|
-
/>
|
|
79
|
-
</Field>
|
|
80
|
-
);
|
|
81
|
-
};
|
|
64
|
+
export const WithinField = {
|
|
65
|
+
...Basic,
|
|
66
|
+
render: function Render(args) {
|
|
67
|
+
const [selectedValue, setSelectedValue] = useState('radio-2');
|
|
68
|
+
const hasError = selectedValue === 'radio-2';
|
|
69
|
+
return (
|
|
70
|
+
<Field
|
|
71
|
+
{...(hasError
|
|
72
|
+
? {
|
|
73
|
+
message: 'Something went wrong',
|
|
74
|
+
sentiment: 'negative',
|
|
75
|
+
}
|
|
76
|
+
: undefined)}
|
|
77
|
+
>
|
|
78
|
+
<RadioGroup {...args} selectedValue={selectedValue} onChange={setSelectedValue} />
|
|
79
|
+
</Field>
|
|
80
|
+
);
|
|
81
|
+
},
|
|
82
|
+
} satisfies Story;
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
export const withIdSource = `
|
|
2
|
+
import { withId, Button, type WithIdProps } from '@transferwise/components';
|
|
3
|
+
|
|
4
|
+
type DescribedButtonProps = { id?: string };
|
|
5
|
+
type DescribedButtonWithIdProps = WithIdProps<DescribedButtonProps>;
|
|
6
|
+
|
|
7
|
+
function DescribedButton({ id }: DescribedButtonWithIdProps) {
|
|
8
|
+
return (
|
|
9
|
+
<>
|
|
10
|
+
<Button aria-describedby={id}>Continue</Button>
|
|
11
|
+
|
|
12
|
+
<p id={id} className="text-xs-center m-t-2">
|
|
13
|
+
Enter an amount in either GBP or PLN
|
|
14
|
+
<br />
|
|
15
|
+
This paragraph has id of <code>{id}</code>
|
|
16
|
+
</p>
|
|
17
|
+
</>
|
|
18
|
+
);
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
export default withId<DescribedButtonProps>(DescribedButton);
|
|
22
|
+
`;
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import { Meta, Canvas, Source } from '@storybook/blocks';
|
|
2
|
+
import { WithoutId, WithCustomId, WithEmptyId } from './withId.story';
|
|
3
|
+
import { withIdSource } from './story/source';
|
|
4
|
+
|
|
5
|
+
<Meta title="HoCs/withId" />
|
|
6
|
+
|
|
7
|
+
# withId
|
|
8
|
+
|
|
9
|
+
This Higher Order Component injects an SSR-friendly `id` prop to any given component. It's especially useful for class-based components where you need to connect a number of elements via aria attributes, yet `useId` hook is unavailable.
|
|
10
|
+
|
|
11
|
+
> **Please note:** this component will be eventually deprecated as we move away from the class components to function components, so use with care.
|
|
12
|
+
|
|
13
|
+
## Usage
|
|
14
|
+
|
|
15
|
+
Given a dummy `DescribedButtonProps` component, when wrapped in the `widthId` HoC…
|
|
16
|
+
|
|
17
|
+
<Source code={withIdSource} dark />
|
|
18
|
+
|
|
19
|
+
…it will be automatically provided with a generated `id` prop…
|
|
20
|
+
|
|
21
|
+
<Canvas of={WithoutId} language="tsx" />
|
|
22
|
+
|
|
23
|
+
…but it will also respect a custom `id`, if provided.
|
|
24
|
+
|
|
25
|
+
<Canvas of={WithCustomId} language="tsx" />
|
|
26
|
+
|
|
27
|
+
### Empty strings
|
|
28
|
+
|
|
29
|
+
The HTML spec considers [empty 'id' attributes as invalid](https://html.spec.whatwg.org/multipage/dom.html#the-id-attribute), and given that the main purpose of this HoC is to offer cross-element connectivity for accessibility purposes, any falsy value provided to the `id` prop for the wrapped component would most likely cause a fault.
|
|
30
|
+
|
|
31
|
+
Because of that, all falsy `id` prop values will be overridden by this HoC.
|
|
32
|
+
|
|
33
|
+
<Canvas of={WithEmptyId} language="tsx" />
|