@transferwise/components 0.0.0-experimental-4c79cff → 0.0.0-experimental-3d434b1

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 (184) hide show
  1. package/build/avatarLayout/AvatarLayout.js +10 -4
  2. package/build/avatarLayout/AvatarLayout.js.map +1 -1
  3. package/build/avatarLayout/AvatarLayout.mjs +10 -4
  4. package/build/avatarLayout/AvatarLayout.mjs.map +1 -1
  5. package/build/button/Button.js +82 -79
  6. package/build/button/Button.js.map +1 -1
  7. package/build/button/Button.mjs +83 -80
  8. package/build/button/Button.mjs.map +1 -1
  9. package/build/button/Button.resolver.js +74 -0
  10. package/build/button/Button.resolver.js.map +1 -0
  11. package/build/button/Button.resolver.mjs +72 -0
  12. package/build/button/Button.resolver.mjs.map +1 -0
  13. package/build/button/LegacyButton.js +114 -0
  14. package/build/button/LegacyButton.js.map +1 -0
  15. package/build/button/LegacyButton.mjs +112 -0
  16. package/build/button/LegacyButton.mjs.map +1 -0
  17. package/build/criticalBanner/CriticalCommsBanner.js +2 -2
  18. package/build/criticalBanner/CriticalCommsBanner.js.map +1 -1
  19. package/build/criticalBanner/CriticalCommsBanner.mjs +1 -1
  20. package/build/header/Header.js +2 -2
  21. package/build/header/Header.js.map +1 -1
  22. package/build/header/Header.mjs +1 -1
  23. package/build/i18n/ja.json +0 -1
  24. package/build/i18n/ja.json.js +0 -1
  25. package/build/i18n/ja.json.js.map +1 -1
  26. package/build/i18n/ja.json.mjs +0 -1
  27. package/build/i18n/ja.json.mjs.map +1 -1
  28. package/build/i18n/pt.json +0 -1
  29. package/build/i18n/pt.json.js +0 -1
  30. package/build/i18n/pt.json.js.map +1 -1
  31. package/build/i18n/pt.json.mjs +0 -1
  32. package/build/i18n/pt.json.mjs.map +1 -1
  33. package/build/i18n/ru.json +0 -1
  34. package/build/i18n/ru.json.js +0 -1
  35. package/build/i18n/ru.json.js.map +1 -1
  36. package/build/i18n/ru.json.mjs +0 -1
  37. package/build/i18n/ru.json.mjs.map +1 -1
  38. package/build/i18n/zh-HK.json +0 -1
  39. package/build/i18n/zh-HK.json.js +0 -1
  40. package/build/i18n/zh-HK.json.js.map +1 -1
  41. package/build/i18n/zh-HK.json.mjs +0 -1
  42. package/build/i18n/zh-HK.json.mjs.map +1 -1
  43. package/build/index.js +2 -4
  44. package/build/index.js.map +1 -1
  45. package/build/index.mjs +1 -2
  46. package/build/index.mjs.map +1 -1
  47. package/build/link/Link.js +8 -3
  48. package/build/link/Link.js.map +1 -1
  49. package/build/link/Link.mjs +8 -3
  50. package/build/link/Link.mjs.map +1 -1
  51. package/build/main.css +227 -13
  52. package/build/nudge/Nudge.js.map +1 -1
  53. package/build/nudge/Nudge.mjs.map +1 -1
  54. package/build/primitives/PrimitiveAnchor/src/PrimitiveAnchor.js +2 -4
  55. package/build/primitives/PrimitiveAnchor/src/PrimitiveAnchor.js.map +1 -1
  56. package/build/primitives/PrimitiveAnchor/src/PrimitiveAnchor.mjs +2 -4
  57. package/build/primitives/PrimitiveAnchor/src/PrimitiveAnchor.mjs.map +1 -1
  58. package/build/primitives/PrimitiveButton/src/PrimitiveButton.js +3 -5
  59. package/build/primitives/PrimitiveButton/src/PrimitiveButton.js.map +1 -1
  60. package/build/primitives/PrimitiveButton/src/PrimitiveButton.mjs +3 -5
  61. package/build/primitives/PrimitiveButton/src/PrimitiveButton.mjs.map +1 -1
  62. package/build/select/Select.js +2 -2
  63. package/build/select/Select.js.map +1 -1
  64. package/build/select/Select.mjs +1 -1
  65. package/build/styles/avatarLayout/AvatarLayout.css +12 -2
  66. package/build/styles/button/Button.css +207 -15
  67. package/build/styles/button/Button.vars.css +46 -0
  68. package/build/styles/button/LegacyButton.css +23 -0
  69. package/build/styles/main.css +227 -13
  70. package/build/styles/nudge/Nudge.css +0 -11
  71. package/build/types/avatarLayout/AvatarLayout.d.ts.map +1 -1
  72. package/build/types/button/Button.d.ts +2 -23
  73. package/build/types/button/Button.d.ts.map +1 -1
  74. package/build/types/button/Button.resolver.d.ts +33 -0
  75. package/build/types/button/Button.resolver.d.ts.map +1 -0
  76. package/build/types/button/Button.types.d.ts +57 -0
  77. package/build/types/button/Button.types.d.ts.map +1 -0
  78. package/build/types/button/LegacyButton.d.ts +30 -0
  79. package/build/types/button/LegacyButton.d.ts.map +1 -0
  80. package/build/types/button/index.d.ts +2 -2
  81. package/build/types/button/index.d.ts.map +1 -1
  82. package/build/types/index.d.ts +0 -2
  83. package/build/types/index.d.ts.map +1 -1
  84. package/build/types/link/Link.d.ts +2 -2
  85. package/build/types/link/Link.d.ts.map +1 -1
  86. package/build/types/nudge/Nudge.d.ts +1 -1
  87. package/build/types/nudge/Nudge.d.ts.map +1 -1
  88. package/build/types/primitives/PrimitiveAnchor/src/PrimitiveAnchor.d.ts.map +1 -1
  89. package/build/types/primitives/PrimitiveAnchor/src/PrimitiveAnchor.types.d.ts +6 -2
  90. package/build/types/primitives/PrimitiveAnchor/src/PrimitiveAnchor.types.d.ts.map +1 -1
  91. package/build/types/primitives/PrimitiveButton/src/PrimitiveButton.d.ts.map +1 -1
  92. package/build/types/test-utils/story-config.d.ts +1 -1
  93. package/build/types/test-utils/story-config.d.ts.map +1 -1
  94. package/build/types/uploadInput/uploadButton/getAllowedFileTypes.d.ts.map +1 -1
  95. package/build/upload/steps/completeStep/completeStep.js +2 -2
  96. package/build/upload/steps/completeStep/completeStep.js.map +1 -1
  97. package/build/upload/steps/completeStep/completeStep.mjs +1 -1
  98. package/build/upload/steps/processingStep/processingStep.js +2 -2
  99. package/build/upload/steps/processingStep/processingStep.js.map +1 -1
  100. package/build/upload/steps/processingStep/processingStep.mjs +1 -1
  101. package/build/uploadInput/UploadInput.js +3 -3
  102. package/build/uploadInput/UploadInput.js.map +1 -1
  103. package/build/uploadInput/UploadInput.mjs +1 -1
  104. package/build/uploadInput/uploadButton/getAllowedFileTypes.js +3 -23
  105. package/build/uploadInput/uploadButton/getAllowedFileTypes.js.map +1 -1
  106. package/build/uploadInput/uploadButton/getAllowedFileTypes.mjs +3 -23
  107. package/build/uploadInput/uploadButton/getAllowedFileTypes.mjs.map +1 -1
  108. package/package.json +5 -5
  109. package/src/alert/Alert.tests.story.tsx +1 -1
  110. package/src/avatarLayout/AvatarLayout.css +12 -2
  111. package/src/avatarLayout/AvatarLayout.less +19 -2
  112. package/src/avatarLayout/AvatarLayout.tsx +10 -3
  113. package/src/button/Button.accessibility.docs.mdx +92 -0
  114. package/src/button/Button.css +207 -15
  115. package/src/button/Button.less +214 -14
  116. package/src/button/Button.resolver.tsx +73 -0
  117. package/src/button/Button.spec.tsx +188 -224
  118. package/src/button/Button.story.tsx +696 -134
  119. package/src/button/Button.tests.story.tsx +27 -0
  120. package/src/button/Button.tsx +95 -131
  121. package/src/button/Button.types.ts +82 -0
  122. package/src/button/Button.vars.css +46 -0
  123. package/src/button/Button.vars.less +60 -0
  124. package/src/button/LegacyButton.css +23 -0
  125. package/src/button/LegacyButton.less +24 -0
  126. package/src/button/LegacyButton.spec.tsx +147 -0
  127. package/src/button/LegacyButton.story.tsx +220 -0
  128. package/src/button/LegacyButton.tsx +160 -0
  129. package/src/button/index.ts +2 -3
  130. package/src/drawer/Drawer.rtl.spec.tsx +59 -0
  131. package/src/drawer/Drawer.spec.js +101 -0
  132. package/src/drawer/__snapshots__/Drawer.rtl.spec.tsx.snap +55 -0
  133. package/src/field/Field.story.tsx +1 -1
  134. package/src/flowNavigation/__snapshots__/FlowNavigation.spec.js.snap +1 -2
  135. package/src/i18n/ja.json +0 -1
  136. package/src/i18n/pt.json +0 -1
  137. package/src/i18n/ru.json +0 -1
  138. package/src/i18n/zh-HK.json +0 -1
  139. package/src/index.ts +0 -12
  140. package/src/inputs/SelectInput.story.tsx +1 -1
  141. package/src/label/Label.story.tsx +1 -1
  142. package/src/link/Link.tsx +15 -6
  143. package/src/main.css +227 -13
  144. package/src/main.less +1 -0
  145. package/src/nudge/Nudge.css +0 -11
  146. package/src/nudge/Nudge.less +0 -3
  147. package/src/nudge/Nudge.story.tsx +0 -10
  148. package/src/nudge/Nudge.tsx +1 -2
  149. package/src/primitives/PrimitiveAnchor/src/PrimitiveAnchor.tsx +2 -8
  150. package/src/primitives/PrimitiveAnchor/src/PrimitiveAnchor.types.ts +7 -2
  151. package/src/primitives/PrimitiveAnchor/test/PrimitiveAnchor.spec.tsx +1 -3
  152. package/src/primitives/PrimitiveButton/src/PrimitiveButton.tsx +4 -12
  153. package/src/primitives/PrimitiveButton/test/PrimitiveButton.spec.tsx +16 -13
  154. package/src/test-utils/Parameters.d.ts +9 -1
  155. package/src/test-utils/story-config.ts +10 -1
  156. package/src/uploadInput/UploadInput.tests.story.tsx +5 -5
  157. package/src/uploadInput/uploadButton/getAllowedFileTypes.spec.ts +0 -12
  158. package/src/uploadInput/uploadButton/getAllowedFileTypes.ts +7 -33
  159. package/build/table/Table.js +0 -166
  160. package/build/table/Table.js.map +0 -1
  161. package/build/table/Table.messages.js +0 -24
  162. package/build/table/Table.messages.js.map +0 -1
  163. package/build/table/Table.messages.mjs +0 -22
  164. package/build/table/Table.messages.mjs.map +0 -1
  165. package/build/table/Table.mjs +0 -164
  166. package/build/table/Table.mjs.map +0 -1
  167. package/build/table/TableCell.js +0 -86
  168. package/build/table/TableCell.js.map +0 -1
  169. package/build/table/TableCell.mjs +0 -84
  170. package/build/table/TableCell.mjs.map +0 -1
  171. package/build/table/TableHeader.js +0 -57
  172. package/build/table/TableHeader.js.map +0 -1
  173. package/build/table/TableHeader.mjs +0 -55
  174. package/build/table/TableHeader.mjs.map +0 -1
  175. package/build/table/TableRow.js +0 -85
  176. package/build/table/TableRow.js.map +0 -1
  177. package/build/table/TableRow.mjs +0 -83
  178. package/build/table/TableRow.mjs.map +0 -1
  179. package/build/table/TableStatusText.js +0 -54
  180. package/build/table/TableStatusText.js.map +0 -1
  181. package/build/table/TableStatusText.mjs +0 -52
  182. package/build/table/TableStatusText.mjs.map +0 -1
  183. package/src/button/__snapshots__/Button.spec.tsx.snap +0 -309
  184. package/src/drawer/Drawer.spec.tsx +0 -93
@@ -1,26 +1,6 @@
1
- const parseFileType = fileType => {
2
- if (fileType?.includes('.')) {
3
- return fileType.replace('.', '').toUpperCase();
4
- }
5
- const mimeType = fileType?.split('/');
6
- if (mimeType?.length > 1) {
7
- let parsedType = mimeType[1];
8
- if (parsedType.toLocaleLowerCase() === 'jpeg') {
9
- parsedType = 'jpg, '.concat(parsedType).toUpperCase();
10
- }
11
- return parsedType.toUpperCase();
12
- }
13
- return fileType;
14
- };
15
- const getAllowedFileTypes = fileTypes => fileTypes.map(fileType => {
16
- const splittedFileTypes = fileType?.split(',');
17
- if (splittedFileTypes?.length > 1) {
18
- // If `fileType` contains `format` and `mime` types, remove mime types, proceed only with format types
19
- return splittedFileTypes.filter(splittedFileType => !splittedFileType?.includes('/')).map(splittedFileType => parseFileType(splittedFileType)).join(', ');
20
- }
21
- // If `fileType` contains only `format` or `mime` type, parse the type
22
- return parseFileType(fileType);
23
- });
1
+ const getAllowedFileTypes = fileTypes => fileTypes.map(fileTypeDefinition => fileTypeDefinition.split(',').filter(extension => !extension.includes('/')) // Filter out mime types
2
+ .map(extension => extension.replace('.', '').toUpperCase()) // Remove dot and convert extensions to uppercase to be displayed in the instructions
3
+ .join(', '));
24
4
 
25
5
  export { getAllowedFileTypes as default };
26
6
  //# sourceMappingURL=getAllowedFileTypes.mjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"getAllowedFileTypes.mjs","sources":["../../../src/uploadInput/uploadButton/getAllowedFileTypes.ts"],"sourcesContent":["import { FileType } from '../../common';\n\nconst parseFileType = (fileType: string): string => {\n if (fileType?.includes('.')) {\n return fileType.replace('.', '').toUpperCase();\n }\n\n const mimeType = fileType?.split('/');\n if (mimeType?.length > 1) {\n let parsedType = mimeType[1];\n\n if (parsedType.toLocaleLowerCase() === 'jpeg') {\n parsedType = 'jpg, '.concat(parsedType).toUpperCase();\n }\n\n return parsedType.toUpperCase();\n }\n\n return fileType;\n};\n\nconst getAllowedFileTypes = (fileTypes: readonly FileType[] | readonly string[]): string[] =>\n fileTypes.map((fileType: string) => {\n const splittedFileTypes = fileType?.split(',');\n\n if (splittedFileTypes?.length > 1) {\n // If `fileType` contains `format` and `mime` types, remove mime types, proceed only with format types\n return splittedFileTypes\n .filter((splittedFileType: string) => !splittedFileType?.includes('/'))\n .map((splittedFileType: string) => parseFileType(splittedFileType))\n .join(', ');\n }\n\n // If `fileType` contains only `format` or `mime` type, parse the type\n return parseFileType(fileType);\n });\n\nexport default getAllowedFileTypes;\n"],"names":["parseFileType","fileType","includes","replace","toUpperCase","mimeType","split","length","parsedType","toLocaleLowerCase","concat","getAllowedFileTypes","fileTypes","map","splittedFileTypes","filter","splittedFileType","join"],"mappings":"AAEA,MAAMA,aAAa,GAAIC,QAAgB,IAAY;AACjD,EAAA,IAAIA,QAAQ,EAAEC,QAAQ,CAAC,GAAG,CAAC,EAAE;IAC3B,OAAOD,QAAQ,CAACE,OAAO,CAAC,GAAG,EAAE,EAAE,CAAC,CAACC,WAAW,EAAE,CAAA;AAChD,GAAA;AAEA,EAAA,MAAMC,QAAQ,GAAGJ,QAAQ,EAAEK,KAAK,CAAC,GAAG,CAAC,CAAA;AACrC,EAAA,IAAID,QAAQ,EAAEE,MAAM,GAAG,CAAC,EAAE;AACxB,IAAA,IAAIC,UAAU,GAAGH,QAAQ,CAAC,CAAC,CAAC,CAAA;AAE5B,IAAA,IAAIG,UAAU,CAACC,iBAAiB,EAAE,KAAK,MAAM,EAAE;MAC7CD,UAAU,GAAG,OAAO,CAACE,MAAM,CAACF,UAAU,CAAC,CAACJ,WAAW,EAAE,CAAA;AACvD,KAAA;AAEA,IAAA,OAAOI,UAAU,CAACJ,WAAW,EAAE,CAAA;AACjC,GAAA;AAEA,EAAA,OAAOH,QAAQ,CAAA;AACjB,CAAC,CAAA;AAEKU,MAAAA,mBAAmB,GAAIC,SAAkD,IAC7EA,SAAS,CAACC,GAAG,CAAEZ,QAAgB,IAAI;AACjC,EAAA,MAAMa,iBAAiB,GAAGb,QAAQ,EAAEK,KAAK,CAAC,GAAG,CAAC,CAAA;AAE9C,EAAA,IAAIQ,iBAAiB,EAAEP,MAAM,GAAG,CAAC,EAAE;AACjC;AACA,IAAA,OAAOO,iBAAiB,CACrBC,MAAM,CAAEC,gBAAwB,IAAK,CAACA,gBAAgB,EAAEd,QAAQ,CAAC,GAAG,CAAC,CAAC,CACtEW,GAAG,CAAEG,gBAAwB,IAAKhB,aAAa,CAACgB,gBAAgB,CAAC,CAAC,CAClEC,IAAI,CAAC,IAAI,CAAC,CAAA;AACf,GAAA;AAEA;EACA,OAAOjB,aAAa,CAACC,QAAQ,CAAC,CAAA;AAChC,CAAC;;;;"}
1
+ {"version":3,"file":"getAllowedFileTypes.mjs","sources":["../../../src/uploadInput/uploadButton/getAllowedFileTypes.ts"],"sourcesContent":["import { FileType } from '../../common';\n\nconst getAllowedFileTypes = (fileTypes: readonly FileType[] | readonly string[]): string[] =>\n fileTypes.map((fileTypeDefinition: string) =>\n fileTypeDefinition\n .split(',')\n .filter((extension) => !extension.includes('/')) // Filter out mime types\n .map((extension) => extension.replace('.', '').toUpperCase()) // Remove dot and convert extensions to uppercase to be displayed in the instructions\n .join(', '),\n );\n\nexport default getAllowedFileTypes;\n"],"names":["getAllowedFileTypes","fileTypes","map","fileTypeDefinition","split","filter","extension","includes","replace","toUpperCase","join"],"mappings":"AAEA,MAAMA,mBAAmB,GAAIC,SAAkD,IAC7EA,SAAS,CAACC,GAAG,CAAEC,kBAA0B,IACvCA,kBAAkB,CACfC,KAAK,CAAC,GAAG,CAAC,CACVC,MAAM,CAAEC,SAAS,IAAK,CAACA,SAAS,CAACC,QAAQ,CAAC,GAAG,CAAC,CAAC;AAAC,CAChDL,GAAG,CAAEI,SAAS,IAAKA,SAAS,CAACE,OAAO,CAAC,GAAG,EAAE,EAAE,CAAC,CAACC,WAAW,EAAE,CAAC;AAAC,CAC7DC,IAAI,CAAC,IAAI,CAAC;;;;"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@transferwise/components",
3
- "version": "0.0.0-experimental-4c79cff",
3
+ "version": "0.0.0-experimental-3d434b1",
4
4
  "description": "Neptune React components",
5
5
  "license": "Apache-2.0",
6
6
  "repository": {
@@ -91,13 +91,13 @@
91
91
  "rollup": "^4.18.1",
92
92
  "rollup-preserve-directives": "^1.1.1",
93
93
  "storybook": "^8.2.2",
94
- "@transferwise/less-config": "3.1.0",
95
- "@transferwise/neptune-css": "14.20.1",
96
- "@wise/components-theming": "1.6.1"
94
+ "@transferwise/neptune-css": "0.0.0-experimental-3d434b1",
95
+ "@wise/components-theming": "1.6.1",
96
+ "@transferwise/less-config": "3.1.0"
97
97
  },
98
98
  "peerDependencies": {
99
99
  "@transferwise/icons": "^3.13.1",
100
- "@transferwise/neptune-css": "^14.9.6",
100
+ "@transferwise/neptune-css": "0.0.0-experimental-3d434b1",
101
101
  "@wise/art": "^2.16",
102
102
  "@wise/components-theming": "^1.0.0",
103
103
  "react": ">=18",
@@ -5,7 +5,7 @@ import { Button, Field, SelectInput, Sentiment } from '..';
5
5
  import Alert, { type AlertProps } from './Alert';
6
6
 
7
7
  const meta = {
8
- title: 'Feedback/Alert/tests',
8
+ title: 'Feedback/Alert/Tests',
9
9
  component: Alert,
10
10
  argTypes: {},
11
11
  args: {
@@ -11,13 +11,20 @@
11
11
  -webkit-mask-image: radial-gradient(circle at bottom calc(100% - var(--np-avatar-size) - var(--np-avatar-offset)) right calc(100% - var(--np-avatar-size) - var(--np-avatar-offset)), transparent 0, transparent calc(var(--np-avatar-size) / 2 + 2px), black 0);
12
12
  mask-image: radial-gradient(circle at bottom calc(100% - var(--np-avatar-size) - var(--np-avatar-offset)) right calc(100% - var(--np-avatar-size) - var(--np-avatar-offset)), transparent 0, transparent calc(var(--np-avatar-size) / 2 + 2px), black 0);
13
13
  }
14
+ [dir="rtl"] .np-avatar-layout-diagonal-mask {
15
+ -webkit-mask-image: radial-gradient(circle at bottom calc(100% - var(--np-avatar-size) - var(--np-avatar-offset)) left calc(100% - var(--np-avatar-size) - var(--np-avatar-offset)), transparent 0, transparent calc(var(--np-avatar-size) / 2 + 2px), black 0);
16
+ mask-image: radial-gradient(circle at bottom calc(100% - var(--np-avatar-size) - var(--np-avatar-offset)) left calc(100% - var(--np-avatar-size) - var(--np-avatar-offset)), transparent 0, transparent calc(var(--np-avatar-size) / 2 + 2px), black 0);
17
+ }
14
18
  .np-avatar-layout-diagonal-child {
15
19
  margin-left: calc(var(--np-avatar-layout-size) - var(--np-avatar-size) * 2);
16
20
  margin-top: calc(var(--np-avatar-layout-size) - var(--np-avatar-size));
17
21
  }
22
+ [dir="rtl"] .np-avatar-layout-diagonal-child {
23
+ margin-left: 0;
24
+ margin-right: calc(var(--np-avatar-layout-size) - var(--np-avatar-size) * 2);
25
+ }
18
26
  .np-avatar-layout-horizontal {
19
- width: calc(var(--np-avatar-size) * var(--np-avatar-avatars-count) - (var(--np-avatar-offset) * (var(--np-avatar-avatars-count) - 1)));
20
- width: calc(var(--np-avatar-size) * var(--np-avatar-avatars-count) - calc(var(--np-avatar-offset) * calc(var(--np-avatar-avatars-count) - 1)));
27
+ width: calc(var(--np-avatar-size) * 2 - var(--np-avatar-offset));
21
28
  height: var(--np-avatar-layout-size);
22
29
  }
23
30
  .np-avatar-layout-horizontal-mask {
@@ -29,3 +36,6 @@
29
36
  .np-avatar-layout-horizontal-child {
30
37
  margin-left: calc(var(--np-avatar-offset) * -1);
31
38
  }
39
+ [dir="rtl"] .np-avatar-layout-horizontal-child {
40
+ margin-right: calc(var(--np-avatar-offset) * -1);
41
+ }
@@ -13,16 +13,29 @@
13
13
  transparent 0,
14
14
  transparent calc(var(--np-avatar-size) / 2 + 2px),
15
15
  black 0);
16
+
17
+ :dir(rtl) & {
18
+ mask-image:
19
+ radial-gradient(circle at bottom calc(100% - var(--np-avatar-size) - var(--np-avatar-offset)) left calc(100% - var(--np-avatar-size) - var(--np-avatar-offset)),
20
+ transparent 0,
21
+ transparent calc(var(--np-avatar-size) / 2 + 2px),
22
+ black 0);
23
+ }
16
24
  }
17
25
 
18
26
  &-child {
19
27
  margin-left: calc(var(--np-avatar-layout-size) - var(--np-avatar-size) * 2);
20
28
  margin-top: calc(var(--np-avatar-layout-size) - var(--np-avatar-size));
29
+
30
+ :dir(rtl) & {
31
+ margin-left: 0;
32
+ margin-right: calc(var(--np-avatar-layout-size) - var(--np-avatar-size) * 2);
33
+ }
21
34
  }
22
35
  }
23
36
 
24
37
  &-horizontal {
25
- width: calc(var(--np-avatar-size) * var(--np-avatar-avatars-count) - calc(var(--np-avatar-offset) * calc(var(--np-avatar-avatars-count) - 1)));
38
+ width: calc(var(--np-avatar-size) * 2 - var(--np-avatar-offset));
26
39
  height: var(--np-avatar-layout-size);
27
40
 
28
41
  &-mask {
@@ -34,6 +47,10 @@
34
47
 
35
48
  &-child {
36
49
  margin-left: calc(var(--np-avatar-offset) * -1);
50
+
51
+ :dir(rtl) & {
52
+ margin-right: calc(var(--np-avatar-offset) * -1);
53
+ }
37
54
  }
38
55
  }
39
- }
56
+ }
@@ -1,5 +1,6 @@
1
1
  import { clsx } from 'clsx';
2
2
  import AvatarView, { AvatarViewProps } from '../avatarView';
3
+ import { useDirection } from '../common/hooks';
3
4
 
4
5
  type SingleAvatarType = { asset?: AvatarViewProps['children'] } & Omit<
5
6
  AvatarViewProps,
@@ -24,6 +25,7 @@ export default function AvatarLayout({
24
25
  }: Props) {
25
26
  const orientation =
26
27
  size === 16 && orientationProp === 'diagonal' ? 'horizontal' : orientationProp;
28
+ const { isRTL } = useDirection();
27
29
  const isDiagonal = orientation === 'diagonal';
28
30
  const avatarSize = isDiagonal ? DIAGONAL_LAYOUT_STYLE_CONFIG[size]?.avatarSize : size;
29
31
  return avatars.length < 1 ? null : avatars.length === 1 ? (
@@ -38,7 +40,6 @@ export default function AvatarLayout({
38
40
  '--np-avatar-layout-size': `${size}px`,
39
41
  '--np-avatar-size': `${avatarSize}px`,
40
42
  '--np-avatar-offset': `${isDiagonal ? DIAGONAL_LAYOUT_STYLE_CONFIG[size].offset : HORIZONTAL_LAYOUT_OFFSET[size]}px`,
41
- '--np-avatar-avatars-count': avatars.length,
42
43
  }}
43
44
  {...restProps}
44
45
  >
@@ -47,8 +48,14 @@ export default function AvatarLayout({
47
48
  // eslint-disable-next-line react/no-array-index-key
48
49
  key={index}
49
50
  className={clsx(
50
- { [`np-avatar-layout-${orientation}-child`]: index !== 0 },
51
- { [`np-avatar-layout-${orientation}-mask`]: index !== avatars.length - 1 },
51
+ {
52
+ [`np-avatar-layout-${orientation}-child`]:
53
+ !isDiagonal && isRTL ? index !== avatars.length - 1 : index !== 0,
54
+ },
55
+ {
56
+ [`np-avatar-layout-${orientation}-mask`]:
57
+ !isDiagonal && isRTL ? index !== 0 : index !== avatars.length - 1,
58
+ },
52
59
  )}
53
60
  >
54
61
  <AvatarView
@@ -0,0 +1,92 @@
1
+ import { Meta, Canvas, Source } from '@storybook/blocks';
2
+ import { NavigationOption } from '..';
3
+ import { Bulb } from '@transferwise/icons';
4
+ import * as stories from './Button.story';
5
+
6
+ <Meta title="Actions/Button/Accessibility" />
7
+
8
+ # Accessibility
9
+
10
+ Given the `Button` is a widely used and highly sensitive component, there are some instances where care is required to ensure inclusive and accessible experience.
11
+
12
+ <NavigationOption
13
+ media={<Bulb size={24} />}
14
+ title="Design guidance"
15
+ content="Before you start, familiarise yourself with the dedicated accessibility documentation."
16
+ href="https://wise.design/components/button#accessibility"
17
+ />
18
+
19
+ <br />
20
+ <br />
21
+
22
+ ## Anchors
23
+
24
+ While it's technically possible to make the `Button` component render as a link by using `as="a"` on its own, and there are use cases for it, this will not result in a semantic HTML anchor. For that to happen, you should set `href` instead – it will automatically render the component as a semantic anchor.
25
+
26
+ <Source dark code={`
27
+ // ⚠️ use with care
28
+ <Button v2 as="a">Inaccessible anchor</Button>
29
+
30
+ // ✅ semantic link
31
+
32
+ <Button v2 href="https://wise.com">
33
+ Accessible anchor
34
+ </Button>
35
+ <Button v2 href="https://wise.com" as="a">
36
+ Accessible anchor
37
+ </Button>
38
+ `}/>
39
+
40
+ It's also worth noting that HTML links without a valid `href` are not recognised by RTL via `getByRole('link')`.
41
+
42
+ **Additional resources:**
43
+
44
+ 1. [Deque: Anchors must only be used as links with valid URLs or URL fragments](https://dequeuniversity.com/rules/axe-devtools/4.2/href-no-hash)
45
+ 2. [whatwg HTML standard: 4.6.2 Links created by a and area elements](https://html.spec.whatwg.org/multipage/links.html#links-created-by-a-and-area-elements)
46
+
47
+ <br />
48
+
49
+ ## Disabled anchors
50
+
51
+ Technically, there's no such thing as disabled HTML anchor and the `disabled` attribute is not recognised on the `<a />`. While the code shown below works in all major screen readers, should be overall considered a last resort and design teams should be encouraged to use it sporadically and consider alternative flows instead.
52
+
53
+ <Source
54
+ dark
55
+ code={`
56
+ // ⚠️ use with care
57
+ <Button v2 href="https://wise.com" disabled>Emulated disabled anchor</Button>
58
+ `}
59
+ />
60
+
61
+ We're emulating this behaviour by applying a combination of the following:
62
+
63
+ 1. removing `href` attribute to strip out the link's semantics.
64
+ 2. adding `role="link"` to make it recognisable and discoverable by the assistive tech.
65
+ 3. setting `aria-disabled="true"` to inform assistive tech of the component state.
66
+
67
+ **Additional resources:**
68
+
69
+ 1. [Scott O'Hara: Disabling a link](https://www.scottohara.me/blog/2021/05/28/disabled-links.html)
70
+ 2. [CSS-Tricks: How to Disable Links](https://css-tricks.com/how-to-disable-links/)
71
+
72
+ <br />
73
+
74
+ ## Loading state
75
+
76
+ While it might be tempting to use the native, HTML `disabled` attribute for the `loading` state, it would result in a component that is completely invisible to the assistive tech – not focusable and not parsable – entirely inaccessible experience for users relying on such tools.
77
+
78
+ Instead, we're relying on ARIA attributes and roles to ensure the `Button` is focusable, correctly announced as "busy" and offering visual cue different to the disabled state.
79
+
80
+ `Button` instances rendered as HTML anchors, follow the strategy described in the [Disabled anchors](#disabled-anchors) section above.
81
+
82
+ <br />
83
+
84
+ ## Working with addons (accessories)
85
+
86
+ One of the core requirements of accessible experience is that all users have equal access to the same content, no matter how they interact with our products.
87
+
88
+ This becomes troublesome for more complex instances of the `Button` such as those with contentful icons or avatars, e.g. those referring to particular currencies, people or action types.
89
+
90
+ Exposing separate ARIA labels for such addons would likely become problematic due to syntactic differences between different languages and so instead we recommend using simple `aria-label` attribute to describe given components complete content. Please note, that screen readers will use that text over the visible label
91
+
92
+ <Canvas of={stories.AccessibilityAddons} />
@@ -1,23 +1,215 @@
1
- .np-btn {
1
+ .wds-Button {
2
+ --Button-background: var(--color-interactive-accent);
3
+ --Button-background-hover: var(--color-interactive-accent-hover);
4
+ --Button-background-active: var(--color-interactive-accent-active);
5
+ --Button-color: var(--color-interactive-control);
6
+ --Button-border-radius: var(--radius-full);
7
+ --Button-label-gap: var(--size-4);
8
+ --Button-large-padding: var(--size-12) var(--size-16);
9
+ --Button-medium-padding: var(--size-8) var(--size-12);
10
+ --Button-small-padding: calc(var(--size-10) * 0.5) var(--size-12);
11
+ --Button-avatar-border-color: var(--color-border-neutral);
12
+ --Button-transition-duration: 150ms;
13
+ --Button-transition-easing: ease-in-out;
14
+ --Button-secondary-background: var(--color-interactive-neutral);
15
+ --Button-secondary-background-hover: var(--color-interactive-neutral-hover);
16
+ --Button-secondary-background-active: var(--color-interactive-neutral-active);
17
+ --Button-secondary-color: var(--color-interactive-primary);
18
+ --Button-tertiary-background: var(--color-background-neutral);
19
+ --Button-tertiary-background-hover: var(--color-background-neutral-hover);
20
+ --Button-tertiary-background-active: var(--color-background-neutral-active);
21
+ --Button-tertiary-color: var(--color-content-primary);
22
+ --Button-minimal-background: transparent;
23
+ --Button-minimal-background-hover: var(--color-background-screen-hover);
24
+ --Button-minimal-background-active: var(--color-background-screen-active);
25
+ --Button-minimal-color: var(--color-interactive-primary);
26
+ --Button-primary-negative-background: var(--color-sentiment-negative-primary);
27
+ --Button-primary-negative-background-hover: var(--color-sentiment-negative-primary-hover);
28
+ --Button-primary-negative-background-active: var(--color-sentiment-negative-primary-active);
29
+ --Button-primary-negative-color: var(--color-contrast-overlay);
30
+ --Button-secondary-negative-background: var(--color-sentiment-negative-secondary);
31
+ --Button-secondary-negative-background-hover: var(--color-sentiment-negative-secondary-hover);
32
+ --Button-secondary-negative-background-active: var(--color-sentiment-negative-secondary-active);
33
+ --Button-secondary-negative-color: var(--color-sentiment-negative-primary);
34
+ }
35
+ .np-theme-personal--bright-green .wds-Button {
36
+ --Button-primary-negative-color: var(--color-white);
37
+ --Button-secondary-color: var(--color-interactive-control);
38
+ --Button-secondary-negative-color: var(--color-white);
39
+ }
40
+ .np-theme-personal--forest-green .wds-Button {
41
+ --Button-secondary-background: var(--color-interactive-neutral);
42
+ --Button-secondary-negative-background: var(--color-sentiment-negative-primary);
43
+ --Button-secondary-negative-background-hover: var(--color-sentiment-negative-primary-hover);
44
+ --Button-secondary-negative-background-active: var(--color-sentiment-negative-primary-active);
45
+ --Button-secondary-negative-color: var(--color-contrast-overlay);
46
+ }
47
+ /* Button Styles */
48
+ .wds-Button {
49
+ display: inline-flex;
50
+ flex: none;
51
+ width: auto;
52
+ align-items: center;
53
+ justify-content: center;
54
+ vertical-align: middle;
55
+ text-align: center;
56
+ -webkit-text-decoration: none;
57
+ text-decoration: none;
58
+ white-space: nowrap;
59
+ word-wrap: break-word;
60
+ -webkit-appearance: none;
61
+ -moz-appearance: none;
62
+ appearance: none;
63
+ background-color: var(--Button-background);
64
+ border: none;
65
+ border-radius: var(--Button-border-radius);
66
+ color: var(--Button-color);
67
+ cursor: pointer;
68
+ transition: color, background-color var(--Button-transition-duration) var(--Button-transition-easing);
69
+ }
70
+ .wds-Button:hover {
71
+ background-color: var(--Button-background-hover);
72
+ }
73
+ .wds-Button:active {
74
+ background-color: var(--Button-background-active);
75
+ }
76
+ .wds-Button.wds-Button--disabled,
77
+ .wds-Button:disabled {
78
+ filter: none;
79
+ mix-blend-mode: luminosity;
80
+ opacity: 0.45;
81
+ cursor: not-allowed;
82
+ }
83
+ .wds-Button.wds-Button--disabled,
84
+ .wds-Button:disabled,
85
+ .wds-Button.wds-Button--disabled:hover,
86
+ .wds-Button:disabled:hover,
87
+ .wds-Button.wds-Button--disabled:active,
88
+ .wds-Button:disabled:active {
89
+ background-color: var(--Button-background);
90
+ }
91
+ .wds-Button--secondary {
92
+ --Button-background: var(--Button-secondary-background);
93
+ --Button-background-hover: var(--Button-secondary-background-hover);
94
+ --Button-background-active: var(--Button-secondary-background-active);
95
+ --Button-color: var(--Button-secondary-color);
96
+ }
97
+ .wds-Button--tertiary {
98
+ --Button-background: var(--Button-tertiary-background);
99
+ --Button-background-hover: var(--Button-tertiary-background-hover);
100
+ --Button-background-active: var(--Button-tertiary-background-active);
101
+ --Button-color: var(--Button-tertiary-color);
102
+ }
103
+ .wds-Button--tertiary .wds-Button-icon--end {
104
+ color: var(--color-interactive-primary);
105
+ }
106
+ .wds-Button--minimal {
107
+ --Button-background: var(--Button-minimal-background);
108
+ --Button-background-hover: var(--Button-minimal-background-hover);
109
+ --Button-background-active: var(--Button-minimal-background-active);
110
+ --Button-color: var(--Button-minimal-color);
111
+ -webkit-text-decoration: underline;
112
+ text-decoration: underline;
113
+ text-underline-offset: 3px;
114
+ text-decoration-thickness: 1px;
115
+ }
116
+ .wds-Button--negative.wds-Button--primary {
117
+ --Button-background: var(--Button-primary-negative-background);
118
+ --Button-background-hover: var(--Button-primary-negative-background-hover);
119
+ --Button-background-active: var(--Button-primary-negative-background-active);
120
+ --Button-color: var(--Button-primary-negative-color);
121
+ }
122
+ .wds-Button--negative.wds-Button--secondary {
123
+ --Button-background: var(--Button-secondary-negative-background);
124
+ --Button-background-hover: var(--Button-secondary-negative-background-hover);
125
+ --Button-background-active: var(--Button-secondary-negative-background-active);
126
+ --Button-color: var(--Button-secondary-negative-color);
127
+ }
128
+ .wds-Button--large {
129
+ padding: var(--Button-large-padding);
130
+ }
131
+ .wds-Button--medium {
132
+ padding: var(--Button-medium-padding);
133
+ }
134
+ .wds-Button--medium:has(.wds-Button-avatars) {
135
+ padding-inline-start: 8px;
136
+ padding-inline-start: var(--size-8);
137
+ }
138
+ .wds-Button--medium:has(.wds-Button-icon--end) {
139
+ padding-inline-end: 8px;
140
+ padding-inline-end: var(--size-8);
141
+ }
142
+ .wds-Button--medium .wds-Button-icon--start {
143
+ margin-inline-end: var(--Button-label-gap);
144
+ }
145
+ .wds-Button--small {
146
+ padding: var(--Button-small-padding);
147
+ }
148
+ .wds-Button--small:has(.wds-Button-icon--start) {
149
+ padding-inline-start: 8px;
150
+ padding-inline-start: var(--size-8);
151
+ }
152
+ .wds-Button--small:has(.wds-Button-icon--end) {
153
+ padding-inline-end: 8px;
154
+ padding-inline-end: var(--size-8);
155
+ }
156
+ .wds-Button--block {
157
+ width: 100%;
158
+ }
159
+ .wds-Button-avatars {
160
+ display: inline-flex;
161
+ }
162
+ .wds-Button-avatars .np-avatar-view .np-avatar-view-content {
163
+ color: var(--Button-color);
164
+ }
165
+ .wds-Button-icon {
166
+ display: inline-block;
167
+ }
168
+ .wds-Button-content {
2
169
  position: relative;
3
170
  }
4
- .np-btn.np-btn-block > span.btn-loader {
171
+ .wds-Button-content--loading .wds-Button-label,
172
+ .wds-Button-content--loading .wds-Button-media,
173
+ .wds-Button-content--loading .wds-Button-icon {
174
+ visibility: hidden;
175
+ opacity: 0;
176
+ }
177
+ .wds-Button-label {
178
+ display: flex;
179
+ justify-content: center;
180
+ align-items: center;
181
+ gap: var(--Button-label-gap);
182
+ position: relative;
183
+ }
184
+ .wds-Button-loader {
5
185
  position: absolute;
6
- left: 24px;
7
- left: var(--size-24);
186
+ width: 100%;
187
+ height: 100%;
188
+ }
189
+ .wds-Button-loader .process-circle {
190
+ stroke: var(--Button-color);
191
+ }
192
+ /* Avatar border transparency */
193
+ /* dark buttons get 20% transparency, light buttons get 12% */
194
+ .wds-Button-avatars .np-circle {
195
+ --circle-border-color: color-mix(in srgb, var(--Button-color) 20%, transparent);
8
196
  }
9
- [dir="rtl"] .np-btn.np-btn-block > span.btn-loader {
10
- right: 24px;
11
- right: var(--size-24);
12
- left: auto;
13
- left: initial;
197
+ .np-theme-personal:not(.np-theme-personal--dark):not(.np-theme-personal--forest-green):not(.np-theme-personal--bright-green) .wds-Button--secondary.wds-Button--negative .wds-Button-avatars .np-circle,
198
+ .np-theme-personal:not(.np-theme-personal--dark):not(.np-theme-personal--forest-green):not(.np-theme-personal--bright-green) .wds-Button--secondary .wds-Button-avatars .np-circle,
199
+ .np-theme-personal:not(.np-theme-personal--dark):not(.np-theme-personal--forest-green):not(.np-theme-personal--bright-green) .wds-Button--tertiary .wds-Button-avatars .np-circle,
200
+ .np-theme-personal:not(.np-theme-personal--dark):not(.np-theme-personal--forest-green):not(.np-theme-personal--bright-green) .wds-Button--minimal .wds-Button-avatars .np-circle {
201
+ --circle-border-color: color-mix(in srgb, var(--Button-color) 12%, transparent);
14
202
  }
15
- .np-btn.np-btn-xs > span.btn-loader {
16
- background-size: 16px 16px;
203
+ .np-theme-personal--dark .wds-Button--primary .wds-Button-avatars .np-circle,
204
+ .np-theme-personal--dark .wds-Button--primary.wds-Button--negative .wds-Button-avatars .np-circle,
205
+ .np-theme-personal--forest-green .wds-Button--primary .wds-Button-avatars .np-circle,
206
+ .np-theme-personal--forest-green .wds-Button--primary.wds-Button--negative .wds-Button-avatars .np-circle {
207
+ --circle-border-color: color-mix(in srgb, var(--Button-color) 12%, transparent);
17
208
  }
18
- .np-btn.np-btn-xs.btn-block > span.btn-loader {
19
- top: 0;
209
+ .np-theme-personal--bright-green .wds-Button--tertiary .wds-Button-avatars .np-circle,
210
+ .np-theme-personal--bright-green .wds-Button--minimal .wds-Button-avatars .np-circle {
211
+ --circle-border-color: color-mix(in srgb, var(--Button-color) 12%, transparent);
20
212
  }
21
- .np-btn.disabled[class] {
22
- pointer-events: auto;
213
+ [dir="rtl"] .wds-Button .tw-icon-chevron-right,[dir="rtl"] .wds-Button .tw-icon-arrow-right,[dir="rtl"] .wds-Button .tw-icon-chevron-left,[dir="rtl"] .wds-Button .tw-icon-arrow-left,[dir="rtl"] .wds-Button .tw-icon-arrow-diagonal-down,[dir="rtl"] .wds-Button .tw-icon-arrow-diagonal-up,[dir="rtl"] .wds-Button .tw-icon-list,[dir="rtl"] .wds-Button .tw-icon-activity {
214
+ scale: -1 1;
23
215
  }