@transferwise/components 0.0.0-experimental-be73f56 → 0.0.0-experimental-f304e2c

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 (106) hide show
  1. package/build/dateLookup/dateTrigger/DateTrigger.js +8 -4
  2. package/build/dateLookup/dateTrigger/DateTrigger.js.map +1 -1
  3. package/build/dateLookup/dateTrigger/DateTrigger.mjs +8 -4
  4. package/build/dateLookup/dateTrigger/DateTrigger.mjs.map +1 -1
  5. package/build/field/Field.js +13 -3
  6. package/build/field/Field.js.map +1 -1
  7. package/build/field/Field.mjs +13 -3
  8. package/build/field/Field.mjs.map +1 -1
  9. package/build/i18n/en.json +3 -2
  10. package/build/i18n/en.json.js +3 -2
  11. package/build/i18n/en.json.js.map +1 -1
  12. package/build/i18n/en.json.mjs +3 -2
  13. package/build/i18n/en.json.mjs.map +1 -1
  14. package/build/inlineAlert/InlineAlert.js +4 -6
  15. package/build/inlineAlert/InlineAlert.js.map +1 -1
  16. package/build/inlineAlert/InlineAlert.mjs +4 -6
  17. package/build/inlineAlert/InlineAlert.mjs.map +1 -1
  18. package/build/label/Label.js +29 -1
  19. package/build/label/Label.js.map +1 -1
  20. package/build/label/Label.messages.js +15 -0
  21. package/build/label/Label.messages.js.map +1 -0
  22. package/build/label/Label.messages.mjs +13 -0
  23. package/build/label/Label.messages.mjs.map +1 -0
  24. package/build/label/Label.mjs +30 -2
  25. package/build/label/Label.mjs.map +1 -1
  26. package/build/main.css +4 -14
  27. package/build/styles/dateLookup/dateTrigger/DateTrigger.css +0 -8
  28. package/build/styles/field/Field.css +4 -0
  29. package/build/styles/main.css +4 -14
  30. package/build/styles/upload/Upload.css +0 -6
  31. package/build/types/dateLookup/dateTrigger/DateTrigger.d.ts.map +1 -1
  32. package/build/types/field/Field.d.ts +4 -2
  33. package/build/types/field/Field.d.ts.map +1 -1
  34. package/build/types/index.d.ts +1 -1
  35. package/build/types/index.d.ts.map +1 -1
  36. package/build/types/inlineAlert/InlineAlert.d.ts.map +1 -1
  37. package/build/types/label/Label.d.ts +10 -1
  38. package/build/types/label/Label.d.ts.map +1 -1
  39. package/build/types/label/Label.messages.d.ts +12 -0
  40. package/build/types/label/Label.messages.d.ts.map +1 -0
  41. package/build/types/label/index.d.ts +3 -0
  42. package/build/types/label/index.d.ts.map +1 -0
  43. package/build/types/upload/Upload.d.ts +0 -1
  44. package/build/types/upload/Upload.d.ts.map +1 -1
  45. package/build/types/upload/Upload.messages.d.ts +0 -4
  46. package/build/types/upload/Upload.messages.d.ts.map +1 -1
  47. package/build/types/upload/steps/completeStep/completeStep.d.ts +3 -1
  48. package/build/types/upload/steps/completeStep/completeStep.d.ts.map +1 -1
  49. package/build/types/upload/steps/uploadImageStep/uploadImageStep.d.ts +0 -1
  50. package/build/types/upload/steps/uploadImageStep/uploadImageStep.d.ts.map +1 -1
  51. package/build/upload/Upload.js +12 -26
  52. package/build/upload/Upload.js.map +1 -1
  53. package/build/upload/Upload.messages.js +0 -3
  54. package/build/upload/Upload.messages.js.map +1 -1
  55. package/build/upload/Upload.messages.mjs +0 -3
  56. package/build/upload/Upload.messages.mjs.map +1 -1
  57. package/build/upload/Upload.mjs +12 -26
  58. package/build/upload/Upload.mjs.map +1 -1
  59. package/build/upload/steps/completeStep/completeStep.js +30 -15
  60. package/build/upload/steps/completeStep/completeStep.js.map +1 -1
  61. package/build/upload/steps/completeStep/completeStep.mjs +31 -16
  62. package/build/upload/steps/completeStep/completeStep.mjs.map +1 -1
  63. package/build/upload/steps/uploadImageStep/uploadImageStep.js +32 -56
  64. package/build/upload/steps/uploadImageStep/uploadImageStep.js.map +1 -1
  65. package/build/upload/steps/uploadImageStep/uploadImageStep.mjs +32 -56
  66. package/build/upload/steps/uploadImageStep/uploadImageStep.mjs.map +1 -1
  67. package/package.json +3 -3
  68. package/src/dateInput/DateInput.tests.story.tsx +7 -31
  69. package/src/dateLookup/DateLookup.rtl.spec.tsx +1 -1
  70. package/src/dateLookup/dateTrigger/DateTrigger.css +0 -8
  71. package/src/dateLookup/dateTrigger/DateTrigger.less +0 -8
  72. package/src/dateLookup/dateTrigger/DateTrigger.spec.js +1 -1
  73. package/src/dateLookup/dateTrigger/DateTrigger.tsx +9 -4
  74. package/src/field/Field.css +4 -0
  75. package/src/field/Field.less +5 -0
  76. package/src/field/Field.spec.tsx +3 -3
  77. package/src/field/Field.story.tsx +106 -7
  78. package/src/field/Field.tsx +12 -6
  79. package/src/i18n/en.json +3 -2
  80. package/src/index.ts +1 -1
  81. package/src/inlineAlert/InlineAlert.story.tsx +8 -72
  82. package/src/inlineAlert/InlineAlert.tsx +5 -3
  83. package/src/inputs/InputGroup.spec.tsx +1 -1
  84. package/src/inputs/SearchInput.spec.tsx +1 -1
  85. package/src/inputs/SelectInput.spec.tsx +1 -1
  86. package/src/label/Label.messages.tsx +12 -0
  87. package/src/label/Label.story.tsx +19 -25
  88. package/src/label/Label.tsx +38 -2
  89. package/src/label/index.ts +2 -0
  90. package/src/main.css +4 -14
  91. package/src/main.less +1 -0
  92. package/src/moneyInput/MoneyInput.story.tsx +0 -2
  93. package/src/radioGroup/RadioGroup.rtl.spec.tsx +1 -1
  94. package/src/select/Select.rtl.spec.tsx +1 -1
  95. package/src/switch/Switch.spec.tsx +1 -1
  96. package/src/upload/Upload.css +0 -6
  97. package/src/upload/Upload.less +0 -5
  98. package/src/upload/Upload.messages.ts +0 -4
  99. package/src/upload/Upload.spec.js +7 -8
  100. package/src/upload/Upload.story.tsx +0 -18
  101. package/src/upload/Upload.tsx +20 -39
  102. package/src/upload/steps/completeStep/completeStep.spec.js +9 -0
  103. package/src/upload/steps/completeStep/completeStep.tsx +29 -14
  104. package/src/upload/steps/uploadImageStep/uploadImageStep.spec.js +0 -12
  105. package/src/upload/steps/uploadImageStep/uploadImageStep.tsx +24 -43
  106. package/src/field/Field.tests.story.tsx +0 -33
@@ -1,10 +1,6 @@
1
1
  import { Upload } from '@transferwise/icons';
2
2
  import { PureComponent, createRef } from 'react';
3
- import StatusIcon from '../../../statusIcon/StatusIcon.mjs';
4
- import InlineAlert from '../../../inlineAlert/InlineAlert.mjs';
5
3
  import { jsx, jsxs } from 'react/jsx-runtime';
6
- import { Sentiment } from '../../../common/propsValues/sentiment.mjs';
7
- import { Size } from '../../../common/propsValues/size.mjs';
8
4
 
9
5
  class UploadImageStep extends PureComponent {
10
6
  uploadInputRef = /*#__PURE__*/createRef();
@@ -22,18 +18,6 @@ class UploadImageStep extends PureComponent {
22
18
  usHelpImage,
23
19
  usLabel
24
20
  } = this.props;
25
- const {
26
- errorMessage
27
- } = this.props;
28
- if (errorMessage) {
29
- return /*#__PURE__*/jsx("div", {
30
- className: "d-flex flex-column align-items-center",
31
- children: /*#__PURE__*/jsx(StatusIcon, {
32
- size: Size.LARGE,
33
- sentiment: Sentiment.NEGATIVE
34
- })
35
- });
36
- }
37
21
  if (!usHelpImage) {
38
22
  return /*#__PURE__*/jsx("div", {
39
23
  className: "circle circle-sm circle-inverse p-t-1",
@@ -58,49 +42,41 @@ class UploadImageStep extends PureComponent {
58
42
  usButtonText,
59
43
  usDisabled,
60
44
  usLabel,
61
- usPlaceholder,
62
- errorMessage
45
+ usPlaceholder
63
46
  } = this.props;
64
47
  return /*#__PURE__*/jsx("div", {
65
- className: "droppable-default-card",
66
- "aria-hidden": isComplete,
67
- children: /*#__PURE__*/jsxs("div", {
68
- className: "droppable-card-content",
69
- children: [/*#__PURE__*/jsx("div", {
70
- className: "m-b-3",
71
- children: this.getImage()
72
- }), usLabel && /*#__PURE__*/jsx("h4", {
73
- className: "np-text-title-body m-b-1",
74
- children: usLabel
75
- }), usPlaceholder && /*#__PURE__*/jsx("p", {
76
- className: "np-text-body-large m-b-3",
77
- children: String(usPlaceholder)
78
- }), /*#__PURE__*/jsxs("label", {
79
- className: `btn btn-primary btn-md ${usDisabled ? 'disabled' : ''}`,
80
- children: [usButtonText ? /*#__PURE__*/jsx("span", {
81
- children: usButtonText
82
- }) : /*#__PURE__*/jsx(Upload, {
83
- size: 24,
84
- className: "m-r-0"
85
- }), /*#__PURE__*/jsx("input", {
86
- ref: this.uploadInputRef,
87
- type: "file",
88
- accept: usAccept === '*' ? undefined : usAccept,
89
- className: "tw-droppable-input hidden",
90
- disabled: usDisabled,
91
- name: "file-upload",
92
- onChange: () => this.onManualUpload()
48
+ children: /*#__PURE__*/jsx("div", {
49
+ className: "droppable-default-card",
50
+ "aria-hidden": isComplete,
51
+ children: /*#__PURE__*/jsxs("div", {
52
+ className: "droppable-card-content",
53
+ children: [/*#__PURE__*/jsx("div", {
54
+ className: "m-b-3",
55
+ children: this.getImage()
56
+ }), usLabel && /*#__PURE__*/jsx("h4", {
57
+ className: "np-text-title-body m-b-1",
58
+ children: usLabel
59
+ }), usPlaceholder && /*#__PURE__*/jsx("p", {
60
+ className: "np-text-body-large m-b-3",
61
+ children: String(usPlaceholder)
62
+ }), /*#__PURE__*/jsxs("label", {
63
+ className: `btn btn-primary btn-md ${usDisabled ? 'disabled' : ''}`,
64
+ children: [usButtonText ? /*#__PURE__*/jsx("span", {
65
+ children: usButtonText
66
+ }) : /*#__PURE__*/jsx(Upload, {
67
+ size: 24,
68
+ className: "m-r-0"
69
+ }), /*#__PURE__*/jsx("input", {
70
+ ref: this.uploadInputRef,
71
+ type: "file",
72
+ accept: usAccept === '*' ? undefined : usAccept,
73
+ className: "tw-droppable-input hidden",
74
+ disabled: usDisabled,
75
+ name: "file-upload",
76
+ onChange: () => this.onManualUpload()
77
+ })]
93
78
  })]
94
- }), errorMessage && /*#__PURE__*/jsx("div", {
95
- className: "upload-error-message",
96
- children: /*#__PURE__*/jsx("div", {
97
- className: "m-t-3 has-error",
98
- children: /*#__PURE__*/jsx(InlineAlert, {
99
- type: Sentiment.NEGATIVE,
100
- children: errorMessage
101
- })
102
- })
103
- })]
79
+ })
104
80
  })
105
81
  });
106
82
  }
@@ -1 +1 @@
1
- {"version":3,"file":"uploadImageStep.mjs","sources":["../../../../src/upload/steps/uploadImageStep/uploadImageStep.tsx"],"sourcesContent":["import { Upload as UploadIcon } from '@transferwise/icons';\nimport { createRef, PureComponent } from 'react';\nimport StatusIcon from '../../../statusIcon';\nimport { Sentiment, Size } from '../../../common';\nimport InlineAlert from '../../../inlineAlert';\n\nexport interface UploadImageStepProps {\n fileDropped: (file: File) => void;\n isComplete: boolean;\n usAccept: string;\n usButtonText: string;\n usDisabled: boolean;\n usHelpImage: React.ReactNode;\n usLabel: string;\n usPlaceholder: string;\n errorMessage?: string | string[];\n}\n\nexport default class UploadImageStep extends PureComponent<UploadImageStepProps> {\n uploadInputRef = createRef<HTMLInputElement>();\n\n onManualUpload = () => {\n const { fileDropped } = this.props;\n const file = this.uploadInputRef.current?.files?.[0];\n if (file != null) {\n fileDropped(file);\n }\n };\n\n getImage = () => {\n const { usHelpImage, usLabel } = this.props;\n const { errorMessage } = this.props;\n\n if (errorMessage) {\n return (\n <div className=\"d-flex flex-column align-items-center\">\n <StatusIcon size={Size.LARGE} sentiment={Sentiment.NEGATIVE} />\n </div>\n );\n }\n\n if (!usHelpImage) {\n return (\n <div className=\"circle circle-sm circle-inverse p-t-1\">\n <UploadIcon size={24} />\n </div>\n );\n }\n\n if (typeof usHelpImage === 'string') {\n return <img src={usHelpImage} alt={usLabel} className=\"thumbnail text-xs-center\" />;\n }\n\n return usHelpImage;\n };\n\n render() {\n const { isComplete, usAccept, usButtonText, usDisabled, usLabel, usPlaceholder, errorMessage } =\n this.props;\n\n return (\n <div className=\"droppable-default-card\" aria-hidden={isComplete}>\n <div className=\"droppable-card-content\">\n <div className=\"m-b-3\">{this.getImage()}</div>\n {usLabel && <h4 className=\"np-text-title-body m-b-1\">{usLabel}</h4>}\n {usPlaceholder && <p className=\"np-text-body-large m-b-3\">{String(usPlaceholder)}</p>}\n <label className={`btn btn-primary btn-md ${usDisabled ? 'disabled' : ''}`}>\n {usButtonText ? (\n <span>{usButtonText}</span>\n ) : (\n <UploadIcon size={24} className=\"m-r-0\" />\n )}\n <input\n ref={this.uploadInputRef}\n type=\"file\"\n accept={usAccept === '*' ? undefined : usAccept}\n className=\"tw-droppable-input hidden\"\n disabled={usDisabled}\n name=\"file-upload\"\n onChange={() => this.onManualUpload()}\n />\n </label>\n {errorMessage && (\n <div className=\"upload-error-message\">\n <div className=\"m-t-3 has-error\">\n <InlineAlert type={Sentiment.NEGATIVE}>{errorMessage}</InlineAlert>\n </div>\n </div>\n )}\n </div>\n </div>\n );\n }\n}\n"],"names":["UploadImageStep","PureComponent","uploadInputRef","createRef","onManualUpload","fileDropped","props","file","current","files","getImage","usHelpImage","usLabel","errorMessage","_jsx","className","children","StatusIcon","size","Size","LARGE","sentiment","Sentiment","NEGATIVE","UploadIcon","src","alt","render","isComplete","usAccept","usButtonText","usDisabled","usPlaceholder","_jsxs","String","ref","type","accept","undefined","disabled","name","onChange","InlineAlert"],"mappings":";;;;;;;;AAkBqB,MAAAA,eAAgB,SAAQC,aAAmC,CAAA;EAC9EC,cAAc,gBAAGC,SAAS,EAAoB,CAAA;EAE9CC,cAAc,GAAGA,MAAK;IACpB,MAAM;AAAEC,MAAAA,WAAAA;KAAa,GAAG,IAAI,CAACC,KAAK,CAAA;IAClC,MAAMC,IAAI,GAAG,IAAI,CAACL,cAAc,CAACM,OAAO,EAAEC,KAAK,GAAG,CAAC,CAAC,CAAA;IACpD,IAAIF,IAAI,IAAI,IAAI,EAAE;MAChBF,WAAW,CAACE,IAAI,CAAC,CAAA;AACnB,KAAA;GACD,CAAA;EAEDG,QAAQ,GAAGA,MAAK;IACd,MAAM;MAAEC,WAAW;AAAEC,MAAAA,OAAAA;KAAS,GAAG,IAAI,CAACN,KAAK,CAAA;IAC3C,MAAM;AAAEO,MAAAA,YAAAA;KAAc,GAAG,IAAI,CAACP,KAAK,CAAA;AAEnC,IAAA,IAAIO,YAAY,EAAE;AAChB,MAAA,oBACEC,GAAA,CAAA,KAAA,EAAA;AAAKC,QAAAA,SAAS,EAAC,uCAAuC;QAAAC,QAAA,eACpDF,GAAA,CAACG,UAAU,EAAA;UAACC,IAAI,EAAEC,IAAI,CAACC,KAAM;UAACC,SAAS,EAAEC,SAAS,CAACC,QAAAA;SACrD,CAAA;AAAA,OAAK,CAAC,CAAA;AAEV,KAAA;IAEA,IAAI,CAACZ,WAAW,EAAE;AAChB,MAAA,oBACEG,GAAA,CAAA,KAAA,EAAA;AAAKC,QAAAA,SAAS,EAAC,uCAAuC;QAAAC,QAAA,eACpDF,GAAA,CAACU,MAAU,EAAA;AAACN,UAAAA,IAAI,EAAE,EAAA;SACpB,CAAA;AAAA,OAAK,CAAC,CAAA;AAEV,KAAA;AAEA,IAAA,IAAI,OAAOP,WAAW,KAAK,QAAQ,EAAE;AACnC,MAAA,oBAAOG,GAAA,CAAA,KAAA,EAAA;AAAKW,QAAAA,GAAG,EAAEd,WAAY;AAACe,QAAAA,GAAG,EAAEd,OAAQ;AAACG,QAAAA,SAAS,EAAC,0BAAA;AAA0B,QAAG,CAAA;AACrF,KAAA;AAEA,IAAA,OAAOJ,WAAW,CAAA;GACnB,CAAA;AAEDgB,EAAAA,MAAMA,GAAA;IACJ,MAAM;MAAEC,UAAU;MAAEC,QAAQ;MAAEC,YAAY;MAAEC,UAAU;MAAEnB,OAAO;MAAEoB,aAAa;AAAEnB,MAAAA,YAAAA;KAAc,GAC5F,IAAI,CAACP,KAAK,CAAA;AAEZ,IAAA,oBACEQ,GAAA,CAAA,KAAA,EAAA;AAAKC,MAAAA,SAAS,EAAC,wBAAwB;AAAC,MAAA,aAAA,EAAaa,UAAW;AAAAZ,MAAAA,QAAA,eAC9DiB,IAAA,CAAA,KAAA,EAAA;AAAKlB,QAAAA,SAAS,EAAC,wBAAwB;AAAAC,QAAAA,QAAA,gBACrCF,GAAA,CAAA,KAAA,EAAA;AAAKC,UAAAA,SAAS,EAAC,OAAO;AAAAC,UAAAA,QAAA,EAAE,IAAI,CAACN,QAAQ,EAAA;AAAE,SAAM,CAC7C,EAACE,OAAO,iBAAIE,GAAA,CAAA,IAAA,EAAA;AAAIC,UAAAA,SAAS,EAAC,0BAA0B;AAAAC,UAAAA,QAAA,EAAEJ,OAAAA;AAAO,SAAK,CAAC,EAClEoB,aAAa,iBAAIlB,GAAA,CAAA,GAAA,EAAA;AAAGC,UAAAA,SAAS,EAAC,0BAA0B;UAAAC,QAAA,EAAEkB,MAAM,CAACF,aAAa,CAAA;SAAK,CAAC,eACrFC,IAAA,CAAA,OAAA,EAAA;AAAOlB,UAAAA,SAAS,EAAE,CAA0BgB,uBAAAA,EAAAA,UAAU,GAAG,UAAU,GAAG,EAAE,CAAG,CAAA;UAAAf,QAAA,EAAA,CACxEc,YAAY,gBACXhB,GAAA,CAAA,MAAA,EAAA;AAAAE,YAAAA,QAAA,EAAOc,YAAAA;AAAY,WAAO,CAAC,gBAE3BhB,GAAA,CAACU,MAAU,EAAA;AAACN,YAAAA,IAAI,EAAE,EAAG;AAACH,YAAAA,SAAS,EAAC,OAAA;WAAO,CACxC,eACDD,GAAA,CAAA,OAAA,EAAA;YACEqB,GAAG,EAAE,IAAI,CAACjC,cAAe;AACzBkC,YAAAA,IAAI,EAAC,MAAM;AACXC,YAAAA,MAAM,EAAER,QAAQ,KAAK,GAAG,GAAGS,SAAS,GAAGT,QAAS;AAChDd,YAAAA,SAAS,EAAC,2BAA2B;AACrCwB,YAAAA,QAAQ,EAAER,UAAW;AACrBS,YAAAA,IAAI,EAAC,aAAa;AAClBC,YAAAA,QAAQ,EAAEA,MAAM,IAAI,CAACrC,cAAc,EAAE;AAAC,WAE1C,CAAA,CAAA;AAAA,SAAO,CACP,EAACS,YAAY,iBACXC,GAAA,CAAA,KAAA,EAAA;AAAKC,UAAAA,SAAS,EAAC,sBAAsB;AAAAC,UAAAA,QAAA,eACnCF,GAAA,CAAA,KAAA,EAAA;AAAKC,YAAAA,SAAS,EAAC,iBAAiB;YAAAC,QAAA,eAC9BF,GAAA,CAAC4B,WAAW,EAAA;cAACN,IAAI,EAAEd,SAAS,CAACC,QAAS;AAAAP,cAAAA,QAAA,EAAEH,YAAAA;aAA0B,CAAA;WAC/D,CAAA;AACP,SAAK,CACN,CAAA;OACE,CAAA;AACP,KAAK,CAAC,CAAA;AAEV,GAAA;AACD;;;;"}
1
+ {"version":3,"file":"uploadImageStep.mjs","sources":["../../../../src/upload/steps/uploadImageStep/uploadImageStep.tsx"],"sourcesContent":["import { Upload as UploadIcon } from '@transferwise/icons';\nimport { createRef, PureComponent } from 'react';\n\nexport interface UploadImageStepProps {\n fileDropped: (file: File) => void;\n isComplete: boolean;\n usAccept: string;\n usButtonText: string;\n usDisabled: boolean;\n usHelpImage: React.ReactNode;\n usLabel: string;\n usPlaceholder: string;\n}\n\nexport default class UploadImageStep extends PureComponent<UploadImageStepProps> {\n uploadInputRef = createRef<HTMLInputElement>();\n\n onManualUpload = () => {\n const { fileDropped } = this.props;\n const file = this.uploadInputRef.current?.files?.[0];\n if (file != null) {\n fileDropped(file);\n }\n };\n\n getImage = () => {\n const { usHelpImage, usLabel } = this.props;\n\n if (!usHelpImage) {\n return (\n <div className=\"circle circle-sm circle-inverse p-t-1\">\n <UploadIcon size={24} />\n </div>\n );\n }\n\n if (typeof usHelpImage === 'string') {\n return <img src={usHelpImage} alt={usLabel} className=\"thumbnail text-xs-center\" />;\n }\n\n return usHelpImage;\n };\n\n render() {\n const { isComplete, usAccept, usButtonText, usDisabled, usLabel, usPlaceholder } = this.props;\n\n return (\n <div>\n <div className=\"droppable-default-card\" aria-hidden={isComplete}>\n <div className=\"droppable-card-content\">\n <div className=\"m-b-3\">{this.getImage()}</div>\n {usLabel && <h4 className=\"np-text-title-body m-b-1\">{usLabel}</h4>}\n {usPlaceholder && <p className=\"np-text-body-large m-b-3\">{String(usPlaceholder)}</p>}\n <label className={`btn btn-primary btn-md ${usDisabled ? 'disabled' : ''}`}>\n {usButtonText ? (\n <span>{usButtonText}</span>\n ) : (\n <UploadIcon size={24} className=\"m-r-0\" />\n )}\n <input\n ref={this.uploadInputRef}\n type=\"file\"\n accept={usAccept === '*' ? undefined : usAccept}\n className=\"tw-droppable-input hidden\"\n disabled={usDisabled}\n name=\"file-upload\"\n onChange={() => this.onManualUpload()}\n />\n </label>\n </div>\n </div>\n </div>\n );\n }\n}\n"],"names":["UploadImageStep","PureComponent","uploadInputRef","createRef","onManualUpload","fileDropped","props","file","current","files","getImage","usHelpImage","usLabel","_jsx","className","children","UploadIcon","size","src","alt","render","isComplete","usAccept","usButtonText","usDisabled","usPlaceholder","_jsxs","String","ref","type","accept","undefined","disabled","name","onChange"],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@transferwise/components",
3
- "version": "0.0.0-experimental-be73f56",
3
+ "version": "0.0.0-experimental-f304e2c",
4
4
  "description": "Neptune React components",
5
5
  "license": "Apache-2.0",
6
6
  "repository": {
@@ -93,12 +93,12 @@
93
93
  "rollup-preserve-directives": "^1.1.1",
94
94
  "storybook": "^8.2.2",
95
95
  "@transferwise/less-config": "3.1.0",
96
- "@transferwise/neptune-css": "0.0.0-experimental-be73f56",
96
+ "@transferwise/neptune-css": "0.0.0-experimental-f304e2c",
97
97
  "@wise/components-theming": "1.5.0"
98
98
  },
99
99
  "peerDependencies": {
100
100
  "@transferwise/icons": "^3.7.0",
101
- "@transferwise/neptune-css": "0.0.0-experimental-be73f56",
101
+ "@transferwise/neptune-css": "0.0.0-experimental-f304e2c",
102
102
  "@wise/art": "^2.7.0",
103
103
  "@wise/components-theming": "^1.0.0",
104
104
  "react": ">=18",
@@ -1,7 +1,7 @@
1
1
  import { Meta, StoryObj } from '@storybook/react';
2
2
  import { userEvent, within, fn } from '@storybook/test';
3
3
 
4
- import { DateInput, DateMode, Info, InlineAlert, Title, Typography } from '..';
4
+ import { DateInput, Field, InlineAlert, Label } from '..';
5
5
  import { lorem10, storyConfig } from '../test-utils';
6
6
 
7
7
  import Provider from '../provider/Provider';
@@ -39,43 +39,19 @@ export const WithLabel = {
39
39
  },
40
40
  render: (args) => {
41
41
  const id1 = 'date-input-group-label-1';
42
- const label = 'Date of Birth';
43
42
 
44
43
  return (
45
44
  <>
46
- <Title type={Typography.TITLE_SUBSECTION}>
47
- label (as <code>div</code> element) is linked with <code>DateInput</code> via{' '}
48
- <code>aria-labelledby</code> prop
49
- </Title>
50
- <div className="control-label" id={id1}>
51
- Date of Delivery
52
- </div>
45
+ <Label id={id1}>
46
+ <Label.Optional>Date of Delivery</Label.Optional>
47
+ </Label>
53
48
  <DateInput {...args} aria-labelledby={id1} />
54
49
 
55
50
  <br />
56
51
 
57
- <Title type={Typography.TITLE_SUBSECTION}>
58
- label (as <code>div</code> element) is detached but <code>DateInput</code> has same label
59
- via <code>aria-label</code> attribute
60
- </Title>
61
- <div className="control-label">
62
- {label}{' '}
63
- <Info aria-label="Fast transfer hint" title="Fast transfer hint" content={lorem10} />
64
- </div>
65
- <DateInput {...args} aria-label={label} />
66
-
67
- <br />
68
-
69
- <Title type={Typography.TITLE_SUBSECTION}>
70
- <code>DateInput</code> wrapped in <code>fieldset</code> + using <code>legend</code> as
71
- label (rare use case)
72
- </Title>
73
- <fieldset>
74
- <legend className="control-label">
75
- Expiry Date for Credit Card (example of MONTH_YEAR mode)
76
- </legend>
77
- <DateInput {...args} mode={DateMode.MONTH_YEAR} />
78
- </fieldset>
52
+ <Field label="Date of Delivery">
53
+ <DateInput {...args} />
54
+ </Field>
79
55
  </>
80
56
  );
81
57
  },
@@ -28,7 +28,7 @@ describe('DateLookup', () => {
28
28
  </Field>,
29
29
  );
30
30
  // TODO: Replace with `.toHaveAttribute('aria-haspopup')`
31
- expect(screen.getByLabelText('Date of birth')).toHaveTextContent(
31
+ expect(screen.getByLabelText(/Date of birth/)).toHaveTextContent(
32
32
  initialValue.getFullYear().toString(),
33
33
  );
34
34
  });
@@ -4,18 +4,10 @@
4
4
  white-space: nowrap;
5
5
  width: 100%;
6
6
  }
7
- .np-date-trigger .control-label {
8
- font-weight: 400;
9
- font-weight: var(--font-weight-regular);
10
- }
11
7
  .np-theme-personal .np-date-trigger {
12
8
  padding-left: 16px;
13
9
  padding-left: var(--size-16);
14
10
  }
15
- .np-theme-personal .np-date-trigger .control-label + span {
16
- font-weight: 400;
17
- font-weight: var(--font-weight-regular);
18
- }
19
11
  .clear-btn {
20
12
  transition: color 0.15s ease-in-out;
21
13
  color: #c9cbce;
@@ -7,16 +7,8 @@
7
7
  white-space: nowrap;
8
8
  width: 100%;
9
9
 
10
- .control-label {
11
- font-weight: var(--font-weight-regular);
12
- }
13
-
14
10
  .np-theme-personal & {
15
11
  padding-left: var(--size-16);
16
-
17
- .control-label + span {
18
- font-weight: var(--font-weight-regular);
19
- }
20
12
  }
21
13
  }
22
14
 
@@ -119,5 +119,5 @@ describe('DateTrigger', () => {
119
119
  const button = () => component.find('.np-date-trigger');
120
120
  const clearButton = () => component.find('.clear-btn');
121
121
  const chevron = () => component.find(Chevron);
122
- const label = () => component.find('.control-label');
122
+ const label = () => component.find('.np-date-trigger-label');
123
123
  });
@@ -2,12 +2,13 @@ import { formatDate } from '@transferwise/formatting';
2
2
  import { useIntl } from 'react-intl';
3
3
 
4
4
  import Chevron from '../../chevron';
5
- import { Size, Position, SizeSmall, SizeMedium, SizeLarge } from '../../common';
5
+ import { Size, Position, SizeSmall, SizeMedium, SizeLarge, Typography } from '../../common';
6
6
  import { CloseButton } from '../../common/closeButton/CloseButton';
7
7
 
8
8
  import messages from './DateTrigger.messages';
9
9
  import { useContext } from 'react';
10
10
  import { OverlayIdContext } from '../../provider/overlay/OverlayIdProvider';
11
+ import Body from '../../body';
11
12
 
12
13
  interface DateTriggerProps {
13
14
  selectedDate: Date | null;
@@ -45,15 +46,19 @@ const DateTrigger: React.FC<DateTriggerProps> = ({
45
46
  type="button"
46
47
  onClick={onClick}
47
48
  >
48
- {label && <span className="control-label small m-r-1">{label}</span>}
49
+ {label && (
50
+ <Body as="span" className="np-date-trigger-label m-r-1">
51
+ {label}
52
+ </Body>
53
+ )}
49
54
  {selectedDate ? (
50
- <span className="font-weight-normal">
55
+ <Body as="span" type={Typography.BODY_LARGE}>
51
56
  {formatDate(selectedDate, locale, {
52
57
  day: 'numeric',
53
58
  month: monthFormat,
54
59
  year: 'numeric',
55
60
  })}
56
- </span>
61
+ </Body>
57
62
  ) : (
58
63
  <span
59
64
  className="form-control-placeholder visible-xs-inline visible-sm-inline
@@ -0,0 +1,4 @@
1
+ .np-field-control {
2
+ margin-top: 4px;
3
+ margin-top: var(--size-4);
4
+ }
@@ -0,0 +1,5 @@
1
+ .np-field {
2
+ &-control {
3
+ margin-top: var(--size-4);
4
+ }
5
+ }
@@ -14,7 +14,7 @@ describe('Field', () => {
14
14
  </Field>,
15
15
  );
16
16
 
17
- expect(screen.getByLabelText('Phone number')).toBeInTheDocument();
17
+ expect(screen.getByLabelText(/Phone number/)).toBeInTheDocument();
18
18
  expect(screen.getByRole('textbox')).not.toHaveAttribute('aria-describedby');
19
19
  });
20
20
 
@@ -25,7 +25,7 @@ describe('Field', () => {
25
25
  </Field>,
26
26
  );
27
27
 
28
- const textbox = screen.getByRole('textbox', { description: 'This is help text' });
28
+ const textbox = screen.getByText('This is help text');
29
29
  expect(textbox).toBeInTheDocument();
30
30
  expect(textbox).not.toBeInvalid();
31
31
  });
@@ -50,7 +50,7 @@ describe('Field', () => {
50
50
  );
51
51
 
52
52
  expect(screen.getByRole('textbox', { description: 'This is error text' })).toBeInTheDocument();
53
- expect(screen.queryByText('This is help text')).not.toBeInTheDocument();
53
+ expect(screen.getByText('This is help text')).toBeInTheDocument();
54
54
  });
55
55
 
56
56
  it('avoids triggering button within label inadvertently', async () => {
@@ -1,8 +1,15 @@
1
+ /* eslint-disable jsx-a11y/label-has-associated-control */
1
2
  import { useState } from 'react';
2
3
 
3
4
  import { Input } from '../inputs/Input';
4
5
  import { Field } from './Field';
5
6
  import { Sentiment } from '../common';
7
+ import DateInput from '../dateInput';
8
+ import { fn } from '@storybook/test';
9
+ import { lorem10, lorem40 } from '../test-utils';
10
+ import { TextArea } from '../inputs/TextArea';
11
+ import { SearchInput } from '../inputs/SearchInput';
12
+ import Info from '../info';
6
13
 
7
14
  export default {
8
15
  component: Field,
@@ -13,9 +20,66 @@ export default {
13
20
  export const Basic = () => {
14
21
  const [value, setValue] = useState<string | undefined>('This is some text');
15
22
  return (
16
- <Field label="Phone number">
17
- <Input value={value} onChange={({ target }) => setValue(target.value)} />
18
- </Field>
23
+ <div className="row">
24
+ <div className="col-md-8 col-md-offset-2">
25
+ <Field label="Required Text Input" required>
26
+ <Input value={value} onChange={({ target }) => setValue(target.value)} />
27
+ </Field>
28
+ <Field label="Text Input">
29
+ <Input value={value} onChange={({ target }) => setValue(target.value)} />
30
+ </Field>
31
+ <Field label="Text Input with Description" description="This a field Description">
32
+ <Input value={value} onChange={({ target }) => setValue(target.value)} />
33
+ </Field>
34
+ <Field
35
+ label="Text Input with Validation Error"
36
+ description="This a field Description"
37
+ sentiment={Sentiment.NEGATIVE}
38
+ message="Validation error, please take a look"
39
+ >
40
+ <Input value={value} onChange={({ target }) => setValue(target.value)} />
41
+ </Field>
42
+
43
+ <Field label="Date Of Birth">
44
+ <DateInput onChange={fn} />
45
+ </Field>
46
+
47
+ <Field label="Date Of Birth with Description" description={lorem10}>
48
+ <DateInput onChange={fn} />
49
+ </Field>
50
+
51
+ <Field label="Search business">
52
+ <SearchInput />
53
+ </Field>
54
+
55
+ <Field label="Textarea">
56
+ <TextArea />
57
+ </Field>
58
+
59
+ <Field label="Textarea with Description" description="This a TextArea Description">
60
+ <TextArea />
61
+ </Field>
62
+
63
+ <Field
64
+ label="Textarea with Validation Error"
65
+ description="This a TextArea Description"
66
+ message={lorem10}
67
+ sentiment="negative"
68
+ >
69
+ <TextArea />
70
+ </Field>
71
+
72
+ <Field
73
+ label={
74
+ <>
75
+ Label with Suffix <Info content={lorem40} />
76
+ </>
77
+ }
78
+ >
79
+ <TextArea />
80
+ </Field>
81
+ </div>
82
+ </div>
19
83
  );
20
84
  };
21
85
 
@@ -23,16 +87,51 @@ export const WithStatusMessages = () => {
23
87
  const [value, setValue] = useState<string | undefined>('This is some text');
24
88
  return (
25
89
  <div>
26
- <Field label="Phone number" sentiment={Sentiment.POSITIVE} message="Positive message">
90
+ <Field
91
+ label="Text Input with Positive Message"
92
+ sentiment={Sentiment.POSITIVE}
93
+ message="Positive message"
94
+ >
27
95
  <Input value={value} onChange={({ target }) => setValue(target.value)} />
28
96
  </Field>
29
- <Field label="Phone number" sentiment={Sentiment.WARNING} message="Warning message">
97
+
98
+ <Field
99
+ label="Text Input with Warning Message"
100
+ sentiment={Sentiment.WARNING}
101
+ message="Warning message"
102
+ >
30
103
  <Input value={value} onChange={({ target }) => setValue(target.value)} />
31
104
  </Field>
32
- <Field label="Phone number" sentiment={Sentiment.NEGATIVE} message="This is a required field">
105
+
106
+ <Field
107
+ label="Text Input with Validation Error"
108
+ sentiment={Sentiment.NEGATIVE}
109
+ message="This is a required field"
110
+ >
111
+ <Input value={value} onChange={({ target }) => setValue(target.value)} />
112
+ </Field>
113
+
114
+ {/* instance with deprecated `hint` prop */}
115
+ <Field
116
+ label="Text Input with deprecated `hint` prop"
117
+ hint="This is a helpful message"
118
+ sentiment={Sentiment.NEGATIVE}
119
+ message="Validation error, please take a look"
120
+ >
33
121
  <Input value={value} onChange={({ target }) => setValue(target.value)} />
34
122
  </Field>
35
- <Field label="Phone number" message="This is a helpful message">
123
+
124
+ {/* instance with deprecated `error` & `hint` props */}
125
+ <Field
126
+ label="Text Input with deprecated `error` & `hint` props"
127
+ hint="This is a helpful message"
128
+ error="Validation error, please take a look"
129
+ >
130
+ <Input value={value} onChange={({ target }) => setValue(target.value)} />
131
+ </Field>
132
+
133
+ {/* instance of info via `message` property, this is rare case (e.g MoneyInput) */}
134
+ <Field label="Text Input with Info under the field" message="This is a helpful message">
36
135
  <Input value={value} onChange={({ target }) => setValue(target.value)} />
37
136
  </Field>
38
137
  </div>
@@ -9,16 +9,18 @@ import {
9
9
  InputIdContextProvider,
10
10
  InputInvalidProvider,
11
11
  } from '../inputs/contexts';
12
- import { Label } from '../label/Label';
12
+ import { Label } from '../label';
13
13
 
14
14
  export type FieldProps = {
15
15
  /** `null` disables auto-generating the `id` attribute, falling back to nesting-based label association over setting `htmlFor` explicitly. */
16
16
  id?: string | null;
17
17
  /** Should be specified unless the wrapped control has its own labeling mechanism, e.g. `Checkbox`. */
18
18
  label?: React.ReactNode;
19
- /** @deprecated use `message` and `type={Sentiment.NEUTRAL}` prop instead */
19
+ required?: boolean;
20
+ /** @deprecated use `description` prop instead */
20
21
  hint?: React.ReactNode;
21
22
  message?: React.ReactNode;
23
+ description?: React.ReactNode;
22
24
  /** @deprecated use `message` and `type={Sentiment.NEGATIVE}` prop instead */
23
25
  error?: React.ReactNode;
24
26
  sentiment?: `${Sentiment.NEGATIVE | Sentiment.NEUTRAL | Sentiment.POSITIVE | Sentiment.WARNING}`;
@@ -29,14 +31,17 @@ export type FieldProps = {
29
31
  export const Field = ({
30
32
  id,
31
33
  label,
34
+ required = false,
32
35
  message: propMessage,
36
+ hint,
37
+ description = hint,
33
38
  sentiment: propType = Sentiment.NEUTRAL,
34
39
  className,
35
40
  children,
36
41
  ...props
37
42
  }: FieldProps) => {
38
43
  const sentiment = props.error ? Sentiment.NEGATIVE : propType;
39
- const message = props.error || props.hint || propMessage;
44
+ const message = propMessage || props.error;
40
45
  const hasError = sentiment === Sentiment.NEGATIVE;
41
46
 
42
47
  const labelId = useId();
@@ -53,7 +58,7 @@ export const Field = ({
53
58
  <InputInvalidProvider value={hasError}>
54
59
  <div
55
60
  className={clsx(
56
- 'form-group d-block',
61
+ 'np-field form-group d-block',
57
62
  {
58
63
  'has-success': sentiment === Sentiment.POSITIVE,
59
64
  'has-warning': sentiment === Sentiment.WARNING,
@@ -65,8 +70,9 @@ export const Field = ({
65
70
  >
66
71
  {label != null ? (
67
72
  <Label id={labelId} htmlFor={inputId}>
68
- {label}
69
- {children}
73
+ {required ? label : <Label.Optional>{label}</Label.Optional>}
74
+ {description && <Label.Description>{description}</Label.Description>}
75
+ <div className="np-field-control">{children}</div>
70
76
  </Label>
71
77
  ) : (
72
78
  children
package/src/i18n/en.json CHANGED
@@ -18,6 +18,7 @@
18
18
  "neptune.DateLookup.year": "year",
19
19
  "neptune.FlowNavigation.back": "back to previous step",
20
20
  "neptune.Info.ariaLabel": "More information",
21
+ "neptune.Label.optional": "(Optional)",
21
22
  "neptune.Link.opensInNewTab": "(opens in new tab)",
22
23
  "neptune.MoneyInput.Select.placeholder": "Select an option...",
23
24
  "neptune.PhoneNumberInput.SelectInput.placeholder": "Select an option...",
@@ -35,7 +36,6 @@
35
36
  "neptune.Upload.csWrongTypeMessage": "File type not supported. Please try again with a different file",
36
37
  "neptune.Upload.psButtonText": "Cancel",
37
38
  "neptune.Upload.psProcessingText": "Uploading...",
38
- "neptune.Upload.retry": "Retry",
39
39
  "neptune.Upload.usButtonText": "Or select a file",
40
40
  "neptune.Upload.usDropMessage": "Drop file to start upload",
41
41
  "neptune.Upload.usPlaceholder": "Drag and drop a file less than {maxSize}MB",
@@ -56,5 +56,6 @@
56
56
  "neptune.UploadItem.uploaded": "Uploaded",
57
57
  "neptune.UploadItem.uploadedFile": "Uploaded file",
58
58
  "neptune.UploadItem.uploading": "Uploading...",
59
- "neptune.UploadItem.uploadingFailed": "Uploading failed"
59
+ "neptune.UploadItem.uploadingFailed": "Uploading failed",
60
+ "neptune.aria.Label.optional": "This field is optional"
60
61
  }
package/src/index.ts CHANGED
@@ -44,7 +44,7 @@ export type {
44
44
  } from './inputs/SelectInput';
45
45
  export type { TextAreaProps } from './inputs/TextArea';
46
46
  export type { InstructionsListProps } from './instructionsList';
47
- export type { LabelProps } from './label/Label';
47
+ export type { LabelProps, LabelOptionalProps, LabelDescriptionProps } from './label/Label';
48
48
  export type { LoaderProps } from './loader';
49
49
  export type { MarkdownProps } from './markdown';
50
50
  export type { ModalProps } from './modal';