@transferwise/components 46.155.1 → 46.157.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (264) hide show
  1. package/build/Calendar/Calendar.constants.js +10 -0
  2. package/build/Calendar/Calendar.constants.js.map +1 -0
  3. package/build/Calendar/Calendar.constants.mjs +8 -0
  4. package/build/Calendar/Calendar.constants.mjs.map +1 -0
  5. package/build/Calendar/Calendar.js +121 -17
  6. package/build/Calendar/Calendar.js.map +1 -1
  7. package/build/Calendar/Calendar.messages.js +12 -0
  8. package/build/Calendar/Calendar.messages.js.map +1 -1
  9. package/build/Calendar/Calendar.messages.mjs +12 -0
  10. package/build/Calendar/Calendar.messages.mjs.map +1 -1
  11. package/build/Calendar/Calendar.mjs +122 -18
  12. package/build/Calendar/Calendar.mjs.map +1 -1
  13. package/build/Calendar/DateHeader/DateHeader.js +5 -1
  14. package/build/Calendar/DateHeader/DateHeader.js.map +1 -1
  15. package/build/Calendar/DateHeader/DateHeader.mjs +5 -1
  16. package/build/Calendar/DateHeader/DateHeader.mjs.map +1 -1
  17. package/build/Calendar/DayCalendar/DayCalendar.js +20 -2
  18. package/build/Calendar/DayCalendar/DayCalendar.js.map +1 -1
  19. package/build/Calendar/DayCalendar/DayCalendar.mjs +20 -2
  20. package/build/Calendar/DayCalendar/DayCalendar.mjs.map +1 -1
  21. package/build/Calendar/DayCalendar/Table/DayCalendarTable.js +60 -19
  22. package/build/Calendar/DayCalendar/Table/DayCalendarTable.js.map +1 -1
  23. package/build/Calendar/DayCalendar/Table/DayCalendarTable.mjs +60 -19
  24. package/build/Calendar/DayCalendar/Table/DayCalendarTable.mjs.map +1 -1
  25. package/build/Calendar/MonthCalendar/MonthCalendar.js +6 -0
  26. package/build/Calendar/MonthCalendar/MonthCalendar.js.map +1 -1
  27. package/build/Calendar/MonthCalendar/MonthCalendar.mjs +6 -0
  28. package/build/Calendar/MonthCalendar/MonthCalendar.mjs.map +1 -1
  29. package/build/Calendar/MonthCalendar/Table/MonthCalendarTable.js +8 -3
  30. package/build/Calendar/MonthCalendar/Table/MonthCalendarTable.js.map +1 -1
  31. package/build/Calendar/MonthCalendar/Table/MonthCalendarTable.mjs +8 -3
  32. package/build/Calendar/MonthCalendar/Table/MonthCalendarTable.mjs.map +1 -1
  33. package/build/Calendar/TableLink/TableLink.js +95 -0
  34. package/build/Calendar/TableLink/TableLink.js.map +1 -0
  35. package/build/Calendar/TableLink/TableLink.mjs +91 -0
  36. package/build/Calendar/TableLink/TableLink.mjs.map +1 -0
  37. package/build/Calendar/YearCalendar/Table/YearCalendarTable.js +8 -3
  38. package/build/Calendar/YearCalendar/Table/YearCalendarTable.js.map +1 -1
  39. package/build/Calendar/YearCalendar/Table/YearCalendarTable.mjs +8 -3
  40. package/build/Calendar/YearCalendar/Table/YearCalendarTable.mjs.map +1 -1
  41. package/build/Calendar/YearCalendar/YearCalendar.js +7 -0
  42. package/build/Calendar/YearCalendar/YearCalendar.js.map +1 -1
  43. package/build/Calendar/YearCalendar/YearCalendar.mjs +7 -0
  44. package/build/Calendar/YearCalendar/YearCalendar.mjs.map +1 -1
  45. package/build/Calendar/_helpers/clampToDayViewBoundary/clampToDayViewBoundary.js +24 -0
  46. package/build/Calendar/_helpers/clampToDayViewBoundary/clampToDayViewBoundary.js.map +1 -0
  47. package/build/Calendar/_helpers/clampToDayViewBoundary/clampToDayViewBoundary.mjs +22 -0
  48. package/build/Calendar/_helpers/clampToDayViewBoundary/clampToDayViewBoundary.mjs.map +1 -0
  49. package/build/Calendar/_helpers/hasDisabledDatesInMonth/hasDisabledDatesInMonth.js +33 -0
  50. package/build/Calendar/_helpers/hasDisabledDatesInMonth/hasDisabledDatesInMonth.js.map +1 -0
  51. package/build/Calendar/_helpers/hasDisabledDatesInMonth/hasDisabledDatesInMonth.mjs +31 -0
  52. package/build/Calendar/_helpers/hasDisabledDatesInMonth/hasDisabledDatesInMonth.mjs.map +1 -0
  53. package/build/Calendar/_helpers/isDateDisabled/isDateDisabled.js +40 -0
  54. package/build/Calendar/_helpers/isDateDisabled/isDateDisabled.js.map +1 -0
  55. package/build/Calendar/_helpers/isDateDisabled/isDateDisabled.mjs +38 -0
  56. package/build/Calendar/_helpers/isDateDisabled/isDateDisabled.mjs.map +1 -0
  57. package/build/DateLookup/DateLookup.js +20 -9
  58. package/build/DateLookup/DateLookup.js.map +1 -1
  59. package/build/DateLookup/DateLookup.mjs +20 -9
  60. package/build/DateLookup/DateLookup.mjs.map +1 -1
  61. package/build/ExpressiveMoneyInput/CurrencySelector/CurrencySelector.js +3 -5
  62. package/build/ExpressiveMoneyInput/CurrencySelector/CurrencySelector.js.map +1 -1
  63. package/build/ExpressiveMoneyInput/CurrencySelector/CurrencySelector.mjs +3 -5
  64. package/build/ExpressiveMoneyInput/CurrencySelector/CurrencySelector.mjs.map +1 -1
  65. package/build/Inputs/SelectInput/TriggerButton/SelectInputTriggerButton.js.map +1 -1
  66. package/build/Inputs/SelectInput/TriggerButton/SelectInputTriggerButton.mjs.map +1 -1
  67. package/build/Markup/Markup.js +138 -0
  68. package/build/Markup/Markup.js.map +1 -0
  69. package/build/Markup/Markup.mjs +133 -0
  70. package/build/Markup/Markup.mjs.map +1 -0
  71. package/build/Markup/constants.js +21 -0
  72. package/build/Markup/constants.js.map +1 -0
  73. package/build/Markup/constants.mjs +15 -0
  74. package/build/Markup/constants.mjs.map +1 -0
  75. package/build/Markup/utils/parseMarkup.js +263 -0
  76. package/build/Markup/utils/parseMarkup.js.map +1 -0
  77. package/build/Markup/utils/parseMarkup.mjs +258 -0
  78. package/build/Markup/utils/parseMarkup.mjs.map +1 -0
  79. package/build/Markup/utils/sanitise.js +111 -0
  80. package/build/Markup/utils/sanitise.js.map +1 -0
  81. package/build/Markup/utils/sanitise.mjs +108 -0
  82. package/build/Markup/utils/sanitise.mjs.map +1 -0
  83. package/build/Typeahead/Typeahead.js +53 -27
  84. package/build/Typeahead/Typeahead.js.map +1 -1
  85. package/build/Typeahead/Typeahead.messages.js +3 -0
  86. package/build/Typeahead/Typeahead.messages.js.map +1 -1
  87. package/build/Typeahead/Typeahead.messages.mjs +3 -0
  88. package/build/Typeahead/Typeahead.messages.mjs.map +1 -1
  89. package/build/Typeahead/Typeahead.mjs +53 -27
  90. package/build/Typeahead/Typeahead.mjs.map +1 -1
  91. package/build/Typeahead/TypeaheadInput/TypeaheadInput.js +2 -2
  92. package/build/Typeahead/TypeaheadInput/TypeaheadInput.js.map +1 -1
  93. package/build/Typeahead/TypeaheadInput/TypeaheadInput.mjs +2 -2
  94. package/build/Typeahead/TypeaheadInput/TypeaheadInput.mjs.map +1 -1
  95. package/build/Typeahead/TypeaheadOption/TypeaheadOption.js +3 -1
  96. package/build/Typeahead/TypeaheadOption/TypeaheadOption.js.map +1 -1
  97. package/build/Typeahead/TypeaheadOption/TypeaheadOption.mjs +3 -1
  98. package/build/Typeahead/TypeaheadOption/TypeaheadOption.mjs.map +1 -1
  99. package/build/i18n/en.json +5 -0
  100. package/build/i18n/en.json.js +5 -0
  101. package/build/i18n/en.json.js.map +1 -1
  102. package/build/i18n/en.json.mjs +5 -0
  103. package/build/i18n/en.json.mjs.map +1 -1
  104. package/build/i18n/hu.json +1 -1
  105. package/build/i18n/hu.json.js +1 -1
  106. package/build/i18n/hu.json.mjs +1 -1
  107. package/build/index.js +4 -2
  108. package/build/index.js.map +1 -1
  109. package/build/index.mjs +2 -1
  110. package/build/index.mjs.map +1 -1
  111. package/build/main.css +168 -43
  112. package/build/styles/Calendar/Calendar.css +112 -37
  113. package/build/styles/Calendar/TableLink/TableLink.css +115 -0
  114. package/build/styles/Markup/Markup.css +28 -0
  115. package/build/styles/Markup/_stories/Vulnerability/Vulnerability.css +69 -0
  116. package/build/styles/Typeahead/Typeahead.css +4 -0
  117. package/build/styles/Typeahead/TypeaheadOption/TypeaheadOption.css +5 -0
  118. package/build/styles/main.css +168 -43
  119. package/build/types/Calendar/Calendar.constants.d.ts +2 -0
  120. package/build/types/Calendar/Calendar.constants.d.ts.map +1 -0
  121. package/build/types/Calendar/Calendar.d.ts +16 -3
  122. package/build/types/Calendar/Calendar.d.ts.map +1 -1
  123. package/build/types/Calendar/Calendar.messages.d.ts +20 -0
  124. package/build/types/Calendar/Calendar.messages.d.ts.map +1 -1
  125. package/build/types/Calendar/Calendar.types.d.ts +32 -0
  126. package/build/types/Calendar/Calendar.types.d.ts.map +1 -0
  127. package/build/types/Calendar/DateHeader/DateHeader.d.ts +2 -0
  128. package/build/types/Calendar/DateHeader/DateHeader.d.ts.map +1 -1
  129. package/build/types/Calendar/DayCalendar/DayCalendar.d.ts +7 -1
  130. package/build/types/Calendar/DayCalendar/DayCalendar.d.ts.map +1 -1
  131. package/build/types/Calendar/DayCalendar/Table/DayCalendarTable.d.ts +6 -0
  132. package/build/types/Calendar/DayCalendar/Table/DayCalendarTable.d.ts.map +1 -1
  133. package/build/types/Calendar/MonthCalendar/MonthCalendar.d.ts +1 -0
  134. package/build/types/Calendar/MonthCalendar/MonthCalendar.d.ts.map +1 -1
  135. package/build/types/Calendar/MonthCalendar/Table/MonthCalendarTable.d.ts +2 -1
  136. package/build/types/Calendar/MonthCalendar/Table/MonthCalendarTable.d.ts.map +1 -1
  137. package/build/types/Calendar/{tableLink → TableLink}/TableLink.d.ts +5 -1
  138. package/build/types/Calendar/TableLink/TableLink.d.ts.map +1 -0
  139. package/build/types/Calendar/TableLink/index.d.ts.map +1 -0
  140. package/build/types/Calendar/YearCalendar/Table/YearCalendarTable.d.ts +2 -1
  141. package/build/types/Calendar/YearCalendar/Table/YearCalendarTable.d.ts.map +1 -1
  142. package/build/types/Calendar/YearCalendar/YearCalendar.d.ts +1 -0
  143. package/build/types/Calendar/YearCalendar/YearCalendar.d.ts.map +1 -1
  144. package/build/types/Calendar/_helpers/clampToDayViewBoundary/clampToDayViewBoundary.d.ts +8 -0
  145. package/build/types/Calendar/_helpers/clampToDayViewBoundary/clampToDayViewBoundary.d.ts.map +1 -0
  146. package/build/types/Calendar/_helpers/hasDisabledDatesInMonth/hasDisabledDatesInMonth.d.ts +3 -0
  147. package/build/types/Calendar/_helpers/hasDisabledDatesInMonth/hasDisabledDatesInMonth.d.ts.map +1 -0
  148. package/build/types/Calendar/_helpers/index.d.ts +4 -0
  149. package/build/types/Calendar/_helpers/index.d.ts.map +1 -0
  150. package/build/types/Calendar/_helpers/isDateDisabled/isDateDisabled.d.ts +3 -0
  151. package/build/types/Calendar/_helpers/isDateDisabled/isDateDisabled.d.ts.map +1 -0
  152. package/build/types/Calendar/index.d.ts +1 -0
  153. package/build/types/Calendar/index.d.ts.map +1 -1
  154. package/build/types/DateLookup/DateLookup.d.ts +24 -5
  155. package/build/types/DateLookup/DateLookup.d.ts.map +1 -1
  156. package/build/types/DateLookup/index.d.ts +1 -0
  157. package/build/types/DateLookup/index.d.ts.map +1 -1
  158. package/build/types/ExpressiveMoneyInput/CurrencySelector/CurrencySelector.d.ts +6 -4
  159. package/build/types/ExpressiveMoneyInput/CurrencySelector/CurrencySelector.d.ts.map +1 -1
  160. package/build/types/Inputs/SelectInput/TriggerButton/SelectInputTriggerButton.d.ts +1 -1
  161. package/build/types/Inputs/SelectInput/TriggerButton/SelectInputTriggerButton.d.ts.map +1 -1
  162. package/build/types/Markup/Markup.d.ts +18 -0
  163. package/build/types/Markup/Markup.d.ts.map +1 -0
  164. package/build/types/Markup/Markup.types.d.ts +77 -0
  165. package/build/types/Markup/Markup.types.d.ts.map +1 -0
  166. package/build/types/Markup/_stories/Vulnerability/Vulnerability.d.ts +12 -0
  167. package/build/types/Markup/_stories/Vulnerability/Vulnerability.d.ts.map +1 -0
  168. package/build/types/Markup/constants.d.ts +6 -0
  169. package/build/types/Markup/constants.d.ts.map +1 -0
  170. package/build/types/Markup/index.d.ts +3 -0
  171. package/build/types/Markup/index.d.ts.map +1 -0
  172. package/build/types/Markup/utils/parseMarkup.d.ts +8 -0
  173. package/build/types/Markup/utils/parseMarkup.d.ts.map +1 -0
  174. package/build/types/Markup/utils/sanitise.d.ts +4 -0
  175. package/build/types/Markup/utils/sanitise.d.ts.map +1 -0
  176. package/build/types/Typeahead/Typeahead.d.ts.map +1 -1
  177. package/build/types/Typeahead/Typeahead.messages.d.ts +5 -0
  178. package/build/types/Typeahead/Typeahead.messages.d.ts.map +1 -1
  179. package/build/types/Typeahead/TypeaheadInput/TypeaheadInput.d.ts.map +1 -1
  180. package/build/types/Typeahead/TypeaheadOption/TypeaheadOption.d.ts +1 -0
  181. package/build/types/Typeahead/TypeaheadOption/TypeaheadOption.d.ts.map +1 -1
  182. package/build/types/index.d.ts +5 -2
  183. package/build/types/index.d.ts.map +1 -1
  184. package/build/types/test-utils/index.d.ts +10 -0
  185. package/build/types/test-utils/index.d.ts.map +1 -1
  186. package/package.json +1 -1
  187. package/src/Calendar/Calendar.constants.ts +5 -0
  188. package/src/Calendar/Calendar.css +112 -37
  189. package/src/Calendar/Calendar.disabledDates.test.tsx +610 -0
  190. package/src/Calendar/Calendar.less +5 -35
  191. package/src/Calendar/Calendar.messages.ts +21 -0
  192. package/src/Calendar/Calendar.test.tsx +342 -32
  193. package/src/Calendar/Calendar.tsx +169 -19
  194. package/src/Calendar/Calendar.types.ts +35 -0
  195. package/src/Calendar/DateHeader/DateHeader.tsx +6 -0
  196. package/src/Calendar/DayCalendar/DayCalendar.tsx +39 -1
  197. package/src/Calendar/DayCalendar/Table/DayCalendarTable.tsx +67 -27
  198. package/src/Calendar/MonthCalendar/MonthCalendar.tsx +8 -0
  199. package/src/Calendar/MonthCalendar/Table/MonthCalendarTable.tsx +15 -3
  200. package/src/Calendar/TableLink/TableLink.css +115 -0
  201. package/src/Calendar/TableLink/TableLink.less +68 -0
  202. package/src/Calendar/TableLink/TableLink.tsx +117 -0
  203. package/src/Calendar/YearCalendar/Table/YearCalendarTable.tsx +15 -3
  204. package/src/Calendar/YearCalendar/YearCalendar.tsx +9 -0
  205. package/src/Calendar/_helpers/clampToDayViewBoundary/clampToDayViewBoundary.test.ts +90 -0
  206. package/src/Calendar/_helpers/clampToDayViewBoundary/clampToDayViewBoundary.ts +25 -0
  207. package/src/Calendar/_helpers/hasDisabledDatesInMonth/hasDisabledDatesInMonth.test.ts +98 -0
  208. package/src/Calendar/_helpers/hasDisabledDatesInMonth/hasDisabledDatesInMonth.ts +45 -0
  209. package/src/Calendar/_helpers/index.ts +3 -0
  210. package/src/Calendar/_helpers/isDateDisabled/isDateDisabled.test.ts +169 -0
  211. package/src/Calendar/_helpers/isDateDisabled/isDateDisabled.ts +59 -0
  212. package/src/Calendar/_stories/Calendar.accessibility.docs.mdx +118 -0
  213. package/src/Calendar/_stories/Calendar.story.tsx +144 -4
  214. package/src/Calendar/_stories/Calendar.test.story.tsx +114 -0
  215. package/src/Calendar/index.ts +7 -0
  216. package/src/DateLookup/DateLookup.disabledDates.test.tsx +312 -0
  217. package/src/DateLookup/DateLookup.test.tsx +34 -37
  218. package/src/DateLookup/DateLookup.tsx +37 -13
  219. package/src/DateLookup/_stories/DateLookup.accessibility.docs.mdx +108 -0
  220. package/src/DateLookup/_stories/DateLookup.story.tsx +126 -2
  221. package/src/DateLookup/index.ts +6 -0
  222. package/src/ExpressiveMoneyInput/CurrencySelector/CurrencySelector.tsx +12 -13
  223. package/src/Inputs/SelectInput/SelectInput.test.tsx +37 -0
  224. package/src/Inputs/SelectInput/TriggerButton/SelectInputTriggerButton.tsx +1 -1
  225. package/src/Markup/Markup.css +28 -0
  226. package/src/Markup/Markup.injection.test.tsx +163 -0
  227. package/src/Markup/Markup.less +29 -0
  228. package/src/Markup/Markup.test.tsx +502 -0
  229. package/src/Markup/Markup.tsx +175 -0
  230. package/src/Markup/Markup.types.ts +62 -0
  231. package/src/Markup/_stories/Markup.docs.mdx +75 -0
  232. package/src/Markup/_stories/Markup.security.docs.mdx +343 -0
  233. package/src/Markup/_stories/Markup.story.tsx +266 -0
  234. package/src/Markup/_stories/Vulnerability/Vulnerability.css +69 -0
  235. package/src/Markup/_stories/Vulnerability/Vulnerability.tsx +30 -0
  236. package/src/Markup/constants.ts +23 -0
  237. package/src/Markup/index.ts +2 -0
  238. package/src/Markup/utils/parseMarkup.test.ts +706 -0
  239. package/src/Markup/utils/parseMarkup.ts +265 -0
  240. package/src/Markup/utils/sanitise.test.ts +499 -0
  241. package/src/Markup/utils/sanitise.ts +129 -0
  242. package/src/Typeahead/Typeahead.css +4 -0
  243. package/src/Typeahead/Typeahead.less +2 -0
  244. package/src/Typeahead/Typeahead.messages.ts +5 -0
  245. package/src/Typeahead/Typeahead.test.tsx +80 -3
  246. package/src/Typeahead/Typeahead.tsx +50 -27
  247. package/src/Typeahead/TypeaheadInput/TypeaheadInput.tsx +2 -6
  248. package/src/Typeahead/TypeaheadOption/TypeaheadOption.css +5 -0
  249. package/src/Typeahead/TypeaheadOption/TypeaheadOption.less +9 -0
  250. package/src/Typeahead/TypeaheadOption/TypeaheadOption.tsx +4 -2
  251. package/src/i18n/en.json +4 -0
  252. package/src/i18n/hu.json +1 -1
  253. package/src/index.ts +5 -2
  254. package/src/main.css +168 -43
  255. package/src/main.less +1 -0
  256. package/build/Calendar/tableLink/TableLink.js +0 -61
  257. package/build/Calendar/tableLink/TableLink.js.map +0 -1
  258. package/build/Calendar/tableLink/TableLink.mjs +0 -57
  259. package/build/Calendar/tableLink/TableLink.mjs.map +0 -1
  260. package/build/types/Calendar/tableLink/TableLink.d.ts.map +0 -1
  261. package/build/types/Calendar/tableLink/index.d.ts.map +0 -1
  262. package/src/Calendar/tableLink/TableLink.tsx +0 -77
  263. /package/build/types/Calendar/{tableLink → TableLink}/index.d.ts +0 -0
  264. /package/src/Calendar/{tableLink → TableLink}/index.ts +0 -0
@@ -0,0 +1,266 @@
1
+ import React, { useState } from 'react';
2
+ import { Meta, StoryObj } from '@storybook/react-webpack5';
3
+ import { action } from 'storybook/actions';
4
+
5
+ import {
6
+ createSandboxStory,
7
+ globalScope,
8
+ } from '../../../.storybook/components/sandbox/SandboxEditor';
9
+ import { storySourceWithoutNoise } from '../../../.storybook/helpers';
10
+
11
+ import { Markup } from '../Markup';
12
+ import type { MarkupActionHandler } from '../Markup.types';
13
+
14
+ export default {
15
+ component: Markup,
16
+ title: 'Typography/Markup',
17
+ tags: ['early-access'],
18
+ } satisfies Meta<typeof Markup>;
19
+
20
+ type Story = StoryObj<typeof Markup>;
21
+
22
+ const MARKUP_STRING = `This markup string supports number of tags:
23
+ <important>important</important>,
24
+ <positive>positive</positive>,
25
+ <negative>negative</negative>,
26
+ <strong>strong</strong>,
27
+ <strikethrough accessibilityLabel="old value label">strikethrough with a screen-reader-friendly label</strikethrough>,
28
+ and a <link href="https://wise.com/design">link</link>.
29
+ <paragraph>
30
+ It respects
31
+ line breaks
32
+ and also allows for paragraphs <positive>and nest tags</positive>.
33
+ </paragraph>
34
+ `;
35
+
36
+ export const Playground: Story = {
37
+ args: {
38
+ children: MARKUP_STRING,
39
+ },
40
+ };
41
+
42
+ export const Sandbox = createSandboxStory({
43
+ code: `<Markup>
44
+ {\`${MARKUP_STRING}\`}
45
+ </Markup>`,
46
+ scope: globalScope,
47
+ });
48
+
49
+ /**
50
+ * Renders the design system `Link` component inline. `<a>` is an alias for `<link>`. External
51
+ * links with `target="_blank"` automatically receive a navigate-away icon and `rel="noreferrer"`.
52
+ * */
53
+ export const WithLinks: Story = {
54
+ args: {
55
+ children:
56
+ 'Using "link" tag: <link href="/settings">settings</link>. Using "a" tag: <a href="https://wise.com" target="_blank">our website</a>.',
57
+ },
58
+ };
59
+
60
+ /**
61
+ * Button-mode link using the `action` attribute. The handler is provided via the `actions` prop.
62
+ * If the named action is missing from the map, the link degrades to plain text.
63
+ * */
64
+ export const WithLinksAsButtons = storySourceWithoutNoise<Story>({
65
+ args: {
66
+ children: 'Click <link action="increment">increment</link> to add `1`.',
67
+ },
68
+ render: function Render(args) {
69
+ const [count, setCount] = useState(0);
70
+
71
+ const increment: MarkupActionHandler = (event) => {
72
+ action('Button event')(event);
73
+ setCount((prev) => prev + 1);
74
+ };
75
+
76
+ return (
77
+ <>
78
+ <Markup actions={{ increment }}>{args.children}</Markup>
79
+ <output>{count}</output>
80
+ </>
81
+ );
82
+ },
83
+ });
84
+
85
+ /**
86
+ * `<strong>` renders a `<strong>` element. `<strikethrough>` renders a `<del>` element for
87
+ * struck-through text.
88
+ * */
89
+ export const StrongAndStrikethrough: Story = {
90
+ args: {
91
+ children:
92
+ 'This is <strong>bold</strong> and this is <strikethrough>no longer relevant</strikethrough>.',
93
+ },
94
+ };
95
+
96
+ /**
97
+ * Block-level paragraphs. `<p>` is an alias for `<paragraph>`. Both render a `<p>` element.
98
+ * */
99
+ export const Paragraphs: Story = {
100
+ args: {
101
+ children:
102
+ '<paragraph>First paragraph using the full tag name.</paragraph><p>Second paragraph using the short alias.</p>',
103
+ },
104
+ };
105
+
106
+ /**
107
+ * Tags can nest to arbitrary depth — emphasis wrapping a link, strong inside a paragraph, etc.
108
+ * */
109
+ export const Nested: Story = {
110
+ args: {
111
+ children:
112
+ '<p><important>Read the <a href="/terms">terms and conditions</a> carefully</important></p>',
113
+ },
114
+ };
115
+
116
+ /**
117
+ * Literal newline characters (`\n`) in the string are converted to `<br />` elements.
118
+ * */
119
+ export const Newlines: Story = {
120
+ args: {
121
+ children: 'First line.\nSecond line.\nThird line.',
122
+ },
123
+ };
124
+
125
+ /**
126
+ * Non-string children (JSX, components, numbers) pass through unchanged — no parsing occurs.
127
+ * This lets parent components use Markup as a unified slot for both markup strings and JSX.
128
+ * */
129
+ export const PassThrough: Story = {
130
+ render: () => (
131
+ <Markup>
132
+ <em>
133
+ This JSX is <strong>passed through</strong>
134
+ </em>{' '}
135
+ without parsing.
136
+ </Markup>
137
+ ),
138
+ };
139
+
140
+ /**
141
+ * The wrapper element is automatically chosen based on content: `<span>` for inline-only markup,
142
+ * `<div>` when `<paragraph>` nodes are present (to avoid invalid `<p>` inside `<span>`).
143
+ * The `as` prop overrides auto-detection when you need explicit control.
144
+ * */
145
+ export const WrapperElement: Story = {
146
+ parameters: {
147
+ docs: {
148
+ source: { type: 'dynamic' },
149
+ },
150
+ },
151
+ render: () => (
152
+ <>
153
+ <Markup className="demo-wrapper">
154
+ {'This is <important>inline</important> content — wrapper is a span.'}
155
+ </Markup>
156
+ <Markup className="demo-wrapper">
157
+ {'<p>Block content with a paragraph.</p><p>Second paragraph.</p>'}
158
+ </Markup>
159
+ <Markup as="section" className="demo-wrapper">
160
+ {'<p>Paragraph forced into a section wrapper via the as prop.</p>'}
161
+ </Markup>
162
+ </>
163
+ ),
164
+ };
165
+
166
+ /**
167
+ * Not all semantic tags are announced by screen readers — for example, `<del>` (strikethrough) is
168
+ * often skipped. The `accessibilityLabel` attribute provides extended copy for visually impaired
169
+ * users, ensuring the meaning is conveyed even when the visual styling is not perceived. It is
170
+ * rendered as `aria-label` on the DOM element.
171
+ * */
172
+ export const AccessibilityLabels: Story = {
173
+ args: {
174
+ children: [
175
+ 'Was <strikethrough accessibilityLabel="Previously 50 GBP">£50.00</strikethrough>,',
176
+ 'now <strong accessibilityLabel="New price">£35.00</strong>.',
177
+ '<important accessibilityLabel="Offer ending soon">Limited time offer</important>',
178
+ ].join(' '),
179
+ },
180
+ };
181
+
182
+ /**
183
+ * Use the `data` prop whenever the markup template contains values that originate from
184
+ * user-generated content or external API responses (e.g. recipient names, amounts, dates).
185
+ * This separates trusted template structure from untrusted data content, preventing markup
186
+ * injection attacks.
187
+ *
188
+ * All matched Mustache-style placeholders (`{{key}}`) are replaced (including duplicates) with
189
+ * values from the `data` object. If a key is not found, it will be rendered literally as `{{key}}`.
190
+ * Data values are always rendered as plain text — even if they contain markup tags, those are
191
+ * displayed literally and never parsed into elements.
192
+ * */
193
+ export const DataSubstitution: Story = {
194
+ parameters: {
195
+ docs: {
196
+ source: { type: 'dynamic' },
197
+ },
198
+ },
199
+ render: () => (
200
+ <>
201
+ <Markup data={{ amount: '£35.00', recipient: 'Alice' }}>
202
+ {'You sent <strong>{{amount}}</strong> to {{recipient}}. {{amount}} is now pending.'}
203
+ </Markup>
204
+ <Markup data={{ name: '</strong><link href="https://evil.com">Click here</link><strong>' }}>
205
+ {'Hello, <strong>{{name}}</strong>!'}
206
+ </Markup>
207
+ </>
208
+ ),
209
+ };
210
+
211
+ /**
212
+ * Controls which link destinations are allowed. By default, only root-relative paths
213
+ * and `wise.com` URLs render as links. External domains are blocked.
214
+ *
215
+ * - `"internal"` (default) — `/*` and `https://wise.com/*` only
216
+ * - `"all"` — any href that passes base sanitisation
217
+ * - `"none"` — all href-based links render as plain text
218
+ *
219
+ * The prop is an additional restriction — it never bypasses protocol/host sanitisation.
220
+ * */
221
+ export const AllowLinks: Story = {
222
+ parameters: {
223
+ docs: {
224
+ source: { type: 'dynamic' },
225
+ },
226
+ },
227
+ render: () => (
228
+ <>
229
+ <Markup>
230
+ {
231
+ 'By default only <link href="/settings">internal</link> or <link href="https://wise.com/help">wise.com</link> links are allowed, while all <link href="https://partner.com">external ones</link> are blocked.'
232
+ }
233
+ </Markup>
234
+
235
+ <Markup allowLinks="all">
236
+ {
237
+ 'If set to `all`, every <link href="/settings">internal</link>, <link href="https://wise.com/help">wise.com</link> and <link href="https://partner.com/page">external</link> link will be respected.'
238
+ }
239
+ </Markup>
240
+
241
+ <Markup allowLinks="none">
242
+ {
243
+ 'If set to `none `, every <link href="/settings">internal</link>, <link href="https://wise.com/help">wise.com</link> and <link href="https://partner.com/page">external</link> link will render as plain text.'
244
+ }
245
+ </Markup>
246
+ </>
247
+ ),
248
+ };
249
+
250
+ /**
251
+ * The component applies a strict whitelist of allowed tags and attributes. Malicious or malformed input is rendered as literal text, preventing XSS attacks. [Full list of handled attack vectors](?path=/docs/typography-markup-parser-security--docs)
252
+ * */
253
+ export const MalformedInput: Story = {
254
+ args: {
255
+ children: [
256
+ '<script>alert("xss")</script>',
257
+ '<img src=x onerror="alert(1)">',
258
+ '<iframe src="https://evil.com"></iframe>',
259
+ '<link href="javascript:alert(1)">blocked protocol</link>',
260
+ '<link href="data:text/html,<script>alert(1)</script>">data URI</link>',
261
+ '<a href="vbscript:MsgBox">vbscript</a>',
262
+ '<link onclick="steal()" href="/safe">ignored attribute</link>',
263
+ '<important>this is safe</important>',
264
+ ].join('\n'),
265
+ },
266
+ };
@@ -0,0 +1,69 @@
1
+ .vulnerability {
2
+ display: grid;
3
+ grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
4
+ gap: 4px 16px;
5
+ margin-bottom: 32px;
6
+ }
7
+
8
+ .vulnerability__label {
9
+ font-size: 11px;
10
+ font-weight: 600;
11
+ color: #64748b;
12
+ text-transform: uppercase;
13
+ }
14
+
15
+ .vulnerability__input,
16
+ .vulnerability__output {
17
+ min-height: 1lh;
18
+ max-height: 28lh;
19
+ border: 1px solid #e2e8f0;
20
+ font-family: ui-monospace, SFMono-Regular, Consolas, 'Liberation Mono', Menlo, monospace;
21
+ line-height: 1.5;
22
+ padding: 10px;
23
+ border-radius: 4px;
24
+ overflow-wrap: break-word;
25
+ font-size: 12px;
26
+ }
27
+
28
+ .vulnerability__input {
29
+ width: 100%;
30
+ background: #000000d9;
31
+ color: #ededed;
32
+ field-sizing: content;
33
+ resize: none;
34
+ }
35
+
36
+ .vulnerability__output {
37
+ background: #ffffff;
38
+ overflow-y: auto;
39
+ }
40
+
41
+ .vulnerability__badge {
42
+ display: inline-block;
43
+ padding: 3px 8px;
44
+ border-radius: 3em;
45
+ font-size: 11px;
46
+ line-height: 0.75rem;
47
+ font-weight: 700;
48
+ margin-left: 8px;
49
+ vertical-align: middle;
50
+ text-align: center;
51
+ background-color: var(--badge-bg);
52
+ color: var(--badge-color);
53
+ box-shadow: color-mix(in srgb, var(--badge-color) 10%, transparent) 0 0 0 1px inset;
54
+ }
55
+
56
+ .vulnerability__badge--high {
57
+ --badge-bg: #ffe8ea;
58
+ --badge-color: #f30010;
59
+ }
60
+
61
+ .vulnerability__badge--medium {
62
+ --badge-bg: #fff7cf;
63
+ --badge-color: #51390d;
64
+ }
65
+
66
+ .vulnerability__badge--low {
67
+ --badge-bg: #d7f8ce;
68
+ --badge-color: #00511e;
69
+ }
@@ -0,0 +1,30 @@
1
+ import { Markup } from '../../Markup';
2
+
3
+ import './Vulnerability.css';
4
+
5
+ type Severity = 'High' | 'Medium' | 'Low';
6
+
7
+ interface VulnerabilityProps {
8
+ markup: string;
9
+ }
10
+
11
+ export const Vulnerability = ({ markup }: VulnerabilityProps) => (
12
+ <div className="vulnerability">
13
+ <div className="vulnerability__label">Markup input</div>
14
+ <div className="vulnerability__label">Rendered output</div>
15
+ <textarea readOnly value={markup} className="vulnerability__input" aria-label="Markup input" />
16
+ <div className="vulnerability__output">
17
+ <Markup>{markup}</Markup>
18
+ </div>
19
+ </div>
20
+ );
21
+
22
+ interface BadgeProps {
23
+ severity: Severity;
24
+ }
25
+
26
+ export const Badge = ({ severity }: BadgeProps) => (
27
+ <span className={`vulnerability__badge vulnerability__badge--${severity.toLowerCase()}`}>
28
+ {severity}
29
+ </span>
30
+ );
@@ -0,0 +1,23 @@
1
+ // Only these tags are recognised — anything else is treated as plain text (security allow-list)
2
+ export const ALLOWED_TAGS = [
3
+ 'important',
4
+ 'positive',
5
+ 'negative',
6
+ 'strong',
7
+ 'strikethrough',
8
+ 'paragraph',
9
+ 'p',
10
+ 'link',
11
+ 'a',
12
+ ] as const;
13
+
14
+ export const TAG_ALIASES: Record<string, string> = { p: 'paragraph', a: 'link' };
15
+
16
+ // Maximum recursive nesting before the parser emits tags as literal text (DoS protection)
17
+ export const MAX_NESTING_DEPTH = 32;
18
+
19
+ // Only these link targets are allowed — others are stripped to prevent iframe breakout
20
+ export const ALLOWED_TARGETS = ['_blank', '_self'];
21
+
22
+ // Only these protocols pass href validation — all others are blocked
23
+ export const ALLOWED_PROTOCOLS = ['https:', 'mailto:'];
@@ -0,0 +1,2 @@
1
+ export { default } from './Markup';
2
+ export type { MarkupActionHandler, MarkupActions, MarkupNode, MarkupProps } from './Markup.types';