@contentful/field-editor-markdown 1.2.1 → 1.3.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 (136) hide show
  1. package/dist/cjs/MarkdownActions.js +235 -0
  2. package/dist/cjs/MarkdownEditor.js +180 -0
  3. package/dist/cjs/__fixtures__/FakeSdk.js +183 -0
  4. package/dist/cjs/__fixtures__/asset/index.js +37 -0
  5. package/dist/cjs/__fixtures__/content-type/index.js +16 -0
  6. package/dist/cjs/__fixtures__/entry/index.js +33 -0
  7. package/dist/cjs/__fixtures__/fixtures.js +71 -0
  8. package/dist/cjs/__fixtures__/locale/index.js +40 -0
  9. package/dist/cjs/__fixtures__/space/index.js +16 -0
  10. package/dist/cjs/codemirrorImports.js +9 -0
  11. package/dist/cjs/components/HeadingSelector.js +66 -0
  12. package/dist/cjs/components/InsertLinkSelector.js +86 -0
  13. package/dist/cjs/components/MarkdownBottomBar.js +111 -0
  14. package/dist/cjs/components/MarkdownConstraints.js +79 -0
  15. package/dist/cjs/components/MarkdownPreview.js +249 -0
  16. package/dist/cjs/components/MarkdownTabs.js +128 -0
  17. package/dist/cjs/components/MarkdownTextarea/CodeMirrorWrapper.js +383 -0
  18. package/dist/cjs/components/MarkdownTextarea/MarkdownCommands.js +233 -0
  19. package/dist/cjs/components/MarkdownTextarea/MarkdownTextarea.js +190 -0
  20. package/dist/cjs/components/MarkdownTextarea/createMarkdownEditor.js +101 -0
  21. package/dist/cjs/components/MarkdownToolbar.js +367 -0
  22. package/dist/cjs/components/icons.js +193 -0
  23. package/dist/cjs/dialogs/CheatsheetModalDialog.js +239 -0
  24. package/dist/cjs/dialogs/ConfirmInsertAssetModalDialog.js +94 -0
  25. package/dist/cjs/dialogs/EmdebExternalContentDialog.js +202 -0
  26. package/dist/cjs/dialogs/InsertLinkModalDialog.js +149 -0
  27. package/dist/cjs/dialogs/InsertTableModalDialog.js +140 -0
  28. package/dist/cjs/dialogs/SpecialCharacterModalDialog.js +146 -0
  29. package/dist/cjs/dialogs/ZenModeModalDialog.js +257 -0
  30. package/dist/cjs/dialogs/openMarkdownDialog.js +121 -0
  31. package/dist/cjs/dialogs/renderMarkdownDialog.js +108 -0
  32. package/dist/cjs/index.js +29 -0
  33. package/dist/cjs/types.js +20 -0
  34. package/dist/cjs/utils/insertAssetLinks.js +122 -0
  35. package/dist/cjs/utils/insertAssetLinks.spec.js +22 -0
  36. package/dist/cjs/utils/isValidUrl.js +22 -0
  37. package/dist/cjs/utils/linkOrganizer.js +187 -0
  38. package/dist/cjs/utils/linkOrganizer.spec.js +96 -0
  39. package/dist/cjs/utils/replaceMailtoAmp.js +15 -0
  40. package/dist/cjs/utils/replaceMailtoAmp.spec.js +22 -0
  41. package/dist/cjs/utils/specialCharacters.js +228 -0
  42. package/dist/cjs/utils/userAgent.js +28 -0
  43. package/dist/esm/MarkdownActions.js +186 -0
  44. package/dist/esm/MarkdownEditor.js +118 -0
  45. package/dist/esm/__fixtures__/FakeSdk.js +173 -0
  46. package/dist/esm/__fixtures__/asset/index.js +6 -0
  47. package/dist/esm/__fixtures__/content-type/index.js +2 -0
  48. package/dist/esm/__fixtures__/entry/index.js +5 -0
  49. package/dist/esm/__fixtures__/fixtures.js +6 -0
  50. package/dist/esm/__fixtures__/locale/index.js +15 -0
  51. package/dist/esm/__fixtures__/space/index.js +2 -0
  52. package/dist/esm/codemirrorImports.js +5 -0
  53. package/dist/esm/components/HeadingSelector.js +17 -0
  54. package/dist/esm/components/InsertLinkSelector.js +37 -0
  55. package/dist/esm/components/MarkdownBottomBar.js +46 -0
  56. package/dist/esm/components/MarkdownConstraints.js +25 -0
  57. package/dist/esm/components/MarkdownPreview.js +195 -0
  58. package/dist/esm/components/MarkdownTabs.js +74 -0
  59. package/dist/esm/components/MarkdownTextarea/CodeMirrorWrapper.js +329 -0
  60. package/dist/esm/components/MarkdownTextarea/MarkdownCommands.js +218 -0
  61. package/dist/esm/components/MarkdownTextarea/MarkdownTextarea.js +136 -0
  62. package/dist/esm/components/MarkdownTextarea/createMarkdownEditor.js +52 -0
  63. package/dist/esm/components/MarkdownToolbar.js +302 -0
  64. package/dist/esm/components/icons.js +112 -0
  65. package/dist/esm/dialogs/CheatsheetModalDialog.js +177 -0
  66. package/dist/esm/dialogs/ConfirmInsertAssetModalDialog.js +37 -0
  67. package/dist/esm/dialogs/EmdebExternalContentDialog.js +140 -0
  68. package/dist/esm/dialogs/InsertLinkModalDialog.js +92 -0
  69. package/dist/esm/dialogs/InsertTableModalDialog.js +78 -0
  70. package/dist/esm/dialogs/SpecialCharacterModalDialog.js +84 -0
  71. package/dist/esm/dialogs/ZenModeModalDialog.js +195 -0
  72. package/dist/esm/dialogs/openMarkdownDialog.js +72 -0
  73. package/dist/esm/dialogs/renderMarkdownDialog.js +59 -0
  74. package/dist/esm/index.js +5 -0
  75. package/dist/esm/types.js +10 -0
  76. package/dist/esm/utils/insertAssetLinks.js +99 -0
  77. package/dist/esm/utils/insertAssetLinks.spec.js +18 -0
  78. package/dist/esm/utils/isValidUrl.js +4 -0
  79. package/dist/esm/utils/linkOrganizer.js +152 -0
  80. package/dist/esm/utils/linkOrganizer.spec.js +53 -0
  81. package/dist/esm/utils/replaceMailtoAmp.js +5 -0
  82. package/dist/esm/utils/replaceMailtoAmp.spec.js +18 -0
  83. package/dist/esm/utils/specialCharacters.js +218 -0
  84. package/dist/esm/utils/userAgent.js +13 -0
  85. package/dist/{MarkdownActions.d.ts → types/MarkdownActions.d.ts} +38 -38
  86. package/dist/{MarkdownEditor.d.ts → types/MarkdownEditor.d.ts} +22 -22
  87. package/dist/types/__fixtures__/FakeSdk.d.ts +8 -0
  88. package/dist/types/__fixtures__/asset/index.d.ts +6 -0
  89. package/dist/types/__fixtures__/content-type/index.d.ts +2 -0
  90. package/dist/types/__fixtures__/entry/index.d.ts +5 -0
  91. package/dist/types/__fixtures__/fixtures.d.ts +6 -0
  92. package/dist/types/__fixtures__/locale/index.d.ts +42 -0
  93. package/dist/types/__fixtures__/space/index.d.ts +2 -0
  94. package/dist/{codemirrorImports.d.ts → types/codemirrorImports.d.ts} +5 -5
  95. package/dist/{components → types/components}/HeadingSelector.d.ts +7 -7
  96. package/dist/{components → types/components}/InsertLinkSelector.d.ts +9 -9
  97. package/dist/{components → types/components}/MarkdownBottomBar.d.ts +11 -11
  98. package/dist/{components → types/components}/MarkdownConstraints.d.ts +6 -6
  99. package/dist/{components → types/components}/MarkdownPreview.d.ts +14 -14
  100. package/dist/{components → types/components}/MarkdownTabs.d.ts +8 -8
  101. package/dist/{components → types/components}/MarkdownTextarea/CodeMirrorWrapper.d.ts +58 -58
  102. package/dist/{components → types/components}/MarkdownTextarea/MarkdownCommands.d.ts +33 -33
  103. package/dist/{components → types/components}/MarkdownTextarea/MarkdownTextarea.d.ts +17 -17
  104. package/dist/{components → types/components}/MarkdownTextarea/createMarkdownEditor.d.ts +55 -55
  105. package/dist/{components → types/components}/MarkdownToolbar.d.ts +12 -12
  106. package/dist/types/components/icons.d.ts +18 -0
  107. package/dist/{dialogs → types/dialogs}/CheatsheetModalDialog.d.ts +4 -4
  108. package/dist/{dialogs → types/dialogs}/ConfirmInsertAssetModalDialog.d.ts +23 -23
  109. package/dist/{dialogs → types/dialogs}/EmdebExternalContentDialog.d.ts +9 -9
  110. package/dist/{dialogs → types/dialogs}/InsertLinkModalDialog.d.ts +17 -17
  111. package/dist/{dialogs → types/dialogs}/InsertTableModalDialog.d.ts +13 -13
  112. package/dist/{dialogs → types/dialogs}/SpecialCharacterModalDialog.d.ts +9 -9
  113. package/dist/{dialogs → types/dialogs}/ZenModeModalDialog.d.ts +24 -24
  114. package/dist/{dialogs → types/dialogs}/openMarkdownDialog.d.ts +5 -5
  115. package/dist/{dialogs → types/dialogs}/renderMarkdownDialog.d.ts +8 -8
  116. package/dist/{index.d.ts → types/index.d.ts} +5 -5
  117. package/dist/{types.d.ts → types/types.d.ts} +75 -75
  118. package/dist/{utils → types/utils}/insertAssetLinks.d.ts +29 -29
  119. package/dist/types/utils/insertAssetLinks.spec.d.ts +1 -0
  120. package/dist/{utils → types/utils}/isValidUrl.d.ts +2 -2
  121. package/dist/{utils → types/utils}/linkOrganizer.d.ts +6 -6
  122. package/dist/types/utils/linkOrganizer.spec.d.ts +1 -0
  123. package/dist/{utils → types/utils}/replaceMailtoAmp.d.ts +1 -1
  124. package/dist/types/utils/replaceMailtoAmp.spec.d.ts +1 -0
  125. package/dist/{utils → types/utils}/specialCharacters.d.ts +4 -4
  126. package/dist/{utils → types/utils}/userAgent.d.ts +1 -1
  127. package/package.json +25 -11
  128. package/CHANGELOG.md +0 -314
  129. package/dist/components/icons.d.ts +0 -18
  130. package/dist/field-editor-markdown.cjs.development.js +0 -3609
  131. package/dist/field-editor-markdown.cjs.development.js.map +0 -1
  132. package/dist/field-editor-markdown.cjs.production.min.js +0 -216
  133. package/dist/field-editor-markdown.cjs.production.min.js.map +0 -1
  134. package/dist/field-editor-markdown.esm.js +0 -3599
  135. package/dist/field-editor-markdown.esm.js.map +0 -1
  136. package/dist/index.js +0 -8
@@ -1,3599 +0,0 @@
1
- import 'codemirror/mode/markdown/markdown';
2
- import 'codemirror/mode/xml/xml';
3
- import 'codemirror/addon/edit/continuelist';
4
- import 'codemirror/addon/mode/overlay';
5
- import 'codemirror/addon/display/autorefresh';
6
- import React, { useRef, useState, useEffect } from 'react';
7
- import tokens from '@contentful/f36-tokens';
8
- import { ConstraintsUtils, CharCounter, CharValidation, FieldConnector, ModalDialogLauncher } from '@contentful/field-editor-shared';
9
- import { css, cx } from 'emotion';
10
- import { Paragraph, TextLink, Menu, Button, Tooltip, IconButton, Flex, ModalContent, Heading, EntityList, ModalControls, Form, FormControl, TextInput, Radio, Checkbox, Text } from '@contentful/f36-components';
11
- import DOMPurify from 'dompurify';
12
- import Markdown from 'markdown-to-jsx';
13
- import CodeMirror from 'codemirror';
14
- import 'codemirror/addon/edit/matchbrackets';
15
- import throttle from 'lodash-es/throttle';
16
- import transform from 'lodash-es/transform';
17
- import get from 'lodash-es/get';
18
- import max from 'lodash-es/max';
19
- import min from 'lodash-es/min';
20
- import range from 'lodash-es/range';
21
- import times from 'lodash-es/times';
22
- import repeat from 'lodash-es/repeat';
23
- import { AssetIcon, ChevronDownIcon, MoreHorizontalIcon, HeadingIcon, FormatBoldIcon, FormatItalicIcon, QuoteIcon, ListBulletedIcon, ListNumberedIcon, LinkIcon, CodeIcon, HorizontalRuleIcon, ChevronRightIcon, ChevronLeftIcon } from '@contentful/f36-icons';
24
- import inRange from 'lodash-es/inRange';
25
- import isObject from 'lodash-es/isObject';
26
- import extend from 'lodash-es/extend';
27
- import isString from 'lodash-es/isString';
28
- import isFinite from 'lodash-es/isFinite';
29
- import forEach from 'lodash-es/forEach';
30
-
31
- const styles = {
32
- root: /*#__PURE__*/css({
33
- display: 'flex',
34
- justifyContent: 'space-between',
35
- background: tokens.gray100,
36
- border: `1px solid ${tokens.gray400}`,
37
- borderBottomLeftRadius: tokens.borderRadiusSmall,
38
- borderBottomRightRadius: tokens.borderRadiusSmall,
39
- padding: `${tokens.spacingXs} ${tokens.spacingS}`
40
- }),
41
- help: /*#__PURE__*/css({
42
- color: tokens.gray700,
43
- fontSize: tokens.fontSizeS,
44
- button: {
45
- fontSize: tokens.fontSizeS,
46
- lineHeight: 'inherit'
47
- }
48
- })
49
- };
50
- function MarkdownHelp(props) {
51
- return React.createElement(Paragraph, {
52
- marginBottom: "none",
53
- className: styles.help
54
- }, "Format your text like a pro with the", ' ', React.createElement(TextLink, {
55
- as: "button",
56
- testId: "open-markdown-cheatsheet-button",
57
- onClick: () => {
58
- props.onClick();
59
- }
60
- }, "markdown cheatsheet"), ".");
61
- }
62
- function MarkdownBottomBar(props) {
63
- return React.createElement("div", {
64
- className: styles.root
65
- }, props.children);
66
- }
67
-
68
- const styles$1 = {
69
- root: /*#__PURE__*/css({
70
- display: 'flex',
71
- justifyContent: 'space-between',
72
- fontSize: tokens.fontSizeM,
73
- marginTop: tokens.spacingXs,
74
- color: tokens.gray700
75
- })
76
- };
77
- function MarkdownConstraints(props) {
78
- const constraints = ConstraintsUtils.fromFieldValidations(props.sdk.field.validations, props.sdk.field.type);
79
- const checkConstraint = ConstraintsUtils.makeChecker(constraints);
80
- return React.createElement("div", {
81
- className: styles$1.root
82
- }, React.createElement(CharCounter, {
83
- value: props.value,
84
- checkConstraint: checkConstraint
85
- }), React.createElement(CharValidation, {
86
- constraints: constraints
87
- }));
88
- }
89
-
90
- // This code will replace '&' with '&' only inside the href attribute of the mailto link.
91
- // Otherwise the mailto link will not work correctly
92
- const replaceMailtoAmp = string => {
93
- return string.replace(/href="mailto:[^"]*&/g, function (match) {
94
- return match.replace(/&/g, '&');
95
- });
96
- };
97
-
98
- const styles$2 = {
99
- root: css`
100
- border: 1px solid ${tokens.gray400};
101
- border-width: 0 1px;
102
- word-wrap: break-word;
103
- overflow-wrap: break-word;
104
- min-height: 300px;
105
- padding: ${tokens.spacingL};
106
- font-size: ${tokens.fontSizeM};
107
- font-family: ${tokens.fontStackPrimary};
108
- line-height: ${tokens.lineHeightDefault};
109
- color: ${tokens.gray700};
110
- white-space: pre-line;
111
-
112
- h1,
113
- h2,
114
- h3,
115
- h4,
116
- h5,
117
- h6 {
118
- margin-top: ${tokens.spacingL};
119
- margin-bottom: ${tokens.spacingM};
120
- color: ${tokens.gray900};
121
- }
122
-
123
- h1:first-child,
124
- h2:first-child,
125
- h3:first-child,
126
- h4:first-child,
127
- h5:first-child,
128
- h6:first-child {
129
- margin-top: 0;
130
- }
131
-
132
- h1 {
133
- font-size: 1.9em;
134
- }
135
- h2 {
136
- font-size: 1.75em;
137
- }
138
- h3 {
139
- font-size: 1.6em;
140
- }
141
- h4 {
142
- font-size: 1.45em;
143
- }
144
- h5 {
145
- font-size: 1.3em;
146
- }
147
- h6 {
148
- font-size: 1.15em;
149
- }
150
-
151
- p {
152
- margin-top: 0;
153
- margin-bottom: ${tokens.spacingM};
154
- }
155
-
156
- ul,
157
- ol {
158
- margin: ${tokens.spacingS} 0;
159
- padding-left: ${tokens.spacingM};
160
- }
161
- ul > li {
162
- list-style-type: disc;
163
- margin-bottom: 0;
164
- }
165
-
166
- ol > li {
167
- list-style-type: decimal;
168
- margin-bottom: 0;
169
- }
170
-
171
- table {
172
- table-layout: fixed;
173
- border-right-width: 0;
174
- border-bottom-width: 0;
175
- width: 80%;
176
- margin: ${tokens.spacingM} auto;
177
- border-spacing: 0;
178
- border-collapse: collapse;
179
- border: 1px solid ${tokens.gray300};
180
- }
181
-
182
- table th,
183
- table td {
184
- padding: 5px;
185
- border-left-width: 0;
186
- border-top-width: 0;
187
- }
188
-
189
- table th {
190
- background: ${tokens.gray200};
191
- }
192
-
193
- table td {
194
- border: 1px solid ${tokens.gray300};
195
- }
196
-
197
- a {
198
- color: ${tokens.blue500};
199
- }
200
-
201
- hr {
202
- margin-top: ${tokens.spacingL};
203
- margin-bottom: ${tokens.spacingL};
204
- height: 1px;
205
- background-color: ${tokens.gray300};
206
- border: none;
207
- }
208
-
209
- blockquote {
210
- border-left: 4px solid ${tokens.gray200};
211
- padding-left: ${tokens.spacingL};
212
- margin: 0;
213
- margin-top: ${tokens.spacingM};
214
- font-style: italic;
215
- }
216
-
217
- img {
218
- margin: ${tokens.spacingM} auto;
219
- display: block;
220
- max-width: 80%;
221
- max-height: 250px;
222
- }
223
-
224
- pre code {
225
- font-size: ${tokens.fontSizeS};
226
- font-family: ${tokens.fontStackMonospace};
227
- }
228
-
229
- .embedly-card {
230
- margin: ${tokens.spacingM} auto;
231
- display: block;
232
- }
233
- `,
234
- framed: /*#__PURE__*/css({
235
- height: '100%',
236
- maxHeight: '500px',
237
- overflowY: 'auto'
238
- }),
239
- zen: /*#__PURE__*/css({
240
- maxWidth: '650px',
241
- margin: '0 auto',
242
- border: 'none !important'
243
- }),
244
- rtl: /*#__PURE__*/css({
245
- direction: 'rtl'
246
- })
247
- };
248
-
249
- function MarkdownLink(props) {
250
- const {
251
- Embedly,
252
- children,
253
- ...rest
254
- } = props;
255
-
256
- if (props.className === 'embedly-card' && Embedly) {
257
- return React.createElement(Embedly, {
258
- url: props.href
259
- });
260
- }
261
-
262
- return React.createElement("a", { ...rest,
263
- target: "_blank",
264
- rel: "noopener noreferrer"
265
- }, children);
266
- }
267
-
268
- const MarkdownPreview = /*#__PURE__*/React.memo(props => {
269
- var _props$previewCompone;
270
-
271
- const className = cx(styles$2.root, props.minHeight !== undefined ? css({
272
- minHeight: props.minHeight
273
- }) : undefined, props.mode === 'default' ? styles$2.framed : styles$2.zen, props.direction === 'rtl' ? styles$2.rtl : undefined); // See the list of allowed Tags here:
274
- // https://github.com/cure53/DOMPurify/blob/main/src/tags.js#L3-L121
275
-
276
- const cleanHTML = React.useMemo(() => {
277
- return replaceMailtoAmp(DOMPurify.sanitize(props.value));
278
- }, [props.value]);
279
- return React.createElement("div", {
280
- className: className,
281
- "data-test-id": "markdown-preview"
282
- }, React.createElement(Markdown, {
283
- options: {
284
- overrides: {
285
- a: {
286
- // eslint-disable-next-line -- TODO: describe this disable @typescript-eslint/no-explicit-any
287
- component: MarkdownLink,
288
- props: {
289
- Embedly: (_props$previewCompone = props.previewComponents) == null ? void 0 : _props$previewCompone.embedly
290
- }
291
- }
292
- }
293
- }
294
- }, cleanHTML));
295
- });
296
- MarkdownPreview.displayName = 'MarkdownPreview';
297
-
298
- const styles$3 = {
299
- root: /*#__PURE__*/css({
300
- display: 'flex',
301
- zIndex: 10,
302
- flexDirection: 'row',
303
- justifyContent: 'flex-end',
304
- overflow: 'hidden',
305
- marginBottom: '-1px',
306
- fontSize: tokens.fontSizeM
307
- }),
308
- tab: /*#__PURE__*/css({
309
- cursor: 'pointer',
310
- color: tokens.gray700,
311
- padding: tokens.spacingXs,
312
- minWidth: '70px',
313
- border: `1px solid ${tokens.gray400}`,
314
- borderTopLeftRadius: tokens.borderRadiusSmall,
315
- borderTopRightRadius: tokens.borderRadiusSmall,
316
- marginLeft: tokens.spacingXs,
317
- textAlign: 'center',
318
- backgroundColor: tokens.gray100,
319
- borderBottomColor: tokens.gray100,
320
- outline: 'none',
321
- '&:focus': {
322
- boxShadow: tokens.boxShadowHeavy
323
- },
324
- transition: `all ${tokens.transitionEasingDefault} ${tokens.transitionDurationShort}`
325
- }),
326
- inactiveTab: /*#__PURE__*/css({
327
- background: tokens.gray200,
328
- borderBottomColor: tokens.gray400,
329
- '&:hover': {
330
- background: tokens.gray300
331
- }
332
- })
333
- };
334
-
335
- function MarkdownTabItem(props) {
336
- return React.createElement("div", {
337
- className: cx(styles$3.tab, {
338
- [styles$3.inactiveTab]: props.isActive === false
339
- }),
340
- onClick: () => {
341
- props.onSelect(props.name);
342
- },
343
- onKeyDown: e => {
344
- if (e.keyCode === 13) {
345
- props.onSelect(props.name);
346
- }
347
- },
348
- tabIndex: 0,
349
- role: "tab",
350
- "aria-controls": props.name,
351
- "aria-selected": props.isActive === true,
352
- "data-test-id": props.testId
353
- }, props.children);
354
- }
355
-
356
- function MarkdownTabs(props) {
357
- return React.createElement("div", {
358
- className: styles$3.root
359
- }, React.createElement(MarkdownTabItem, {
360
- name: "editor",
361
- onSelect: props.onSelect,
362
- isActive: props.active === 'editor',
363
- testId: "markdown-tab-md"
364
- }, "Editor"), React.createElement(MarkdownTabItem, {
365
- name: "preview",
366
- onSelect: props.onSelect,
367
- isActive: props.active === 'preview',
368
- testId: "markdown-tab-preview"
369
- }, "Preview"));
370
- }
371
-
372
- const userAgent = /*#__PURE__*/get(window, 'navigator.userAgent', '');
373
- const platform = /*#__PURE__*/get(window, 'navigator.platform', '');
374
- let ctrlKey = 'Ctrl';
375
- const tests = {
376
- // eslint-disable-next-line -- TODO: describe this disable @typescript-eslint/ban-ts-comment
377
- // @ts-ignore ignore missing MSStream
378
- ios: /*#__PURE__*/ /(iphone os|ipad|iphone|ipod)/i.test(userAgent) && !window.MSStream
379
- };
380
-
381
- if (tests.ios || /mac(68k|ppc|intel)/i.test(platform)) {
382
- ctrlKey = 'Cmd';
383
- }
384
-
385
- function getCtrlKey() {
386
- return ctrlKey;
387
- }
388
-
389
- /* eslint-disable @typescript-eslint/no-use-before-define, @typescript-eslint/no-explicit-any */
390
-
391
- function stripUnit(value) {
392
- if (typeof value !== 'string') return value;
393
- const cssRegex = /^([+-]?(?:\d+|\d*\.\d+))([a-z]*|%)$/;
394
- const matchedValue = value.match(cssRegex);
395
-
396
- if (!matchedValue) {
397
- throw new Error("Couldn't match unit in given string");
398
- }
399
-
400
- return parseFloat(value);
401
- }
402
-
403
- function create(host, options) {
404
- const {
405
- direction,
406
- fixedHeight,
407
- height,
408
- readOnly
409
- } = options || {}; // Set to true if `setValue()` has been called. This is to prevent
410
- // undoing the initial content.
411
-
412
- let initializedWithValue = false;
413
- const LF = '\n';
414
- const EDITOR_SIZE = {
415
- min: height ? stripUnit(height) : 300,
416
- max: 500,
417
- shift: 50
418
- };
419
- const cm = CodeMirror(host, {
420
- direction,
421
- readOnly,
422
- mode: 'markdown',
423
- lineNumbers: false,
424
- undoDepth: 200,
425
- matchBrackets: true,
426
- lineWrapping: true,
427
- // When `lineSeparator === null` the document will be split
428
- // on CRLFs as well as lone CRs and LFs. A single LF will
429
- // be used as line separator in all output
430
- lineSeparator: null,
431
- theme: 'elegant',
432
- tabSize: 2,
433
- indentWithTabs: false,
434
- indentUnit: 2,
435
- autoRefresh: true,
436
- spellcheck: true,
437
- inputStyle: 'contenteditable'
438
- });
439
- cm.setSize('100%', EDITOR_SIZE.min);
440
-
441
- if (!fixedHeight) {
442
- cm.on('change', throttle(assureHeight, 150));
443
- }
444
-
445
- cm.setOption('extraKeys', {
446
- Tab: function () {
447
- replaceSelectedText(getIndentation());
448
- },
449
- Enter: 'newlineAndIndentContinueMarkdownList',
450
- Esc: () => {
451
- cm.getInputField().blur();
452
- }
453
- });
454
- /**
455
- * @description
456
- * Custom API for a CodeMirror instance.
457
- *
458
- * An instance wraps a CodeMirror instance and provides a custom interface
459
- * on top of CodeMirror.
460
- */
461
-
462
- return {
463
- destroy,
464
- disable,
465
- enable,
466
- attachEvent,
467
- addKeyShortcuts,
468
- setValue,
469
- cmd,
470
- moveToLineBeginning,
471
- moveIfNotEmpty,
472
- restoreCursor,
473
- moveToLineEnd,
474
- usePrimarySelection,
475
- focus,
476
- select,
477
- selectBackwards,
478
- selectAll: () => cm.execCommand('selectAll'),
479
- extendSelectionBy,
480
- insertAtCursor,
481
- insertAtLineBeginning,
482
- wrapSelection,
483
- removeFromLineBeginning,
484
- removeSelectedText,
485
- replaceSelectedText,
486
- getCursor,
487
- setCursor,
488
- getSelection,
489
- getLine,
490
- isLineEmpty,
491
- getSelectedText,
492
- getSelectionLength,
493
- getCurrentLine,
494
- getCurrentLineNumber,
495
- getCurrentCharacter,
496
- getCurrentLineLength,
497
- lineStartsWith,
498
- getIndentation,
499
- getNl,
500
- getValue,
501
- getLinesCount,
502
- getHistorySize,
503
- setReadOnly: value => cm.setOption('readOnly', value),
504
- getHistory: () => cm.getHistory(),
505
- setHistory: history => cm.setHistory(history),
506
- setFullsize: () => {
507
- cm.setSize('100%', '100%');
508
- cm.refresh();
509
- },
510
- refresh: () => cm.refresh()
511
- };
512
-
513
- function destroy() {
514
- // @ts-expect-error
515
- cm.toTextArea();
516
- }
517
-
518
- function disable() {
519
- cm.setOption('readOnly', 'nocursor');
520
- }
521
-
522
- function enable() {
523
- cm.setOption('readOnly', false);
524
- }
525
-
526
- function assureHeight() {
527
- const current = cm.heightAtLine(cm.lastLine(), 'local') + EDITOR_SIZE.shift;
528
- let next = current;
529
-
530
- if (current < EDITOR_SIZE.min) {
531
- next = EDITOR_SIZE.min;
532
- }
533
-
534
- if (current > EDITOR_SIZE.max) {
535
- next = EDITOR_SIZE.max;
536
- }
537
-
538
- cm.setSize('100%', next);
539
- }
540
-
541
- function attachEvent(name, fn, throttleInterval) {
542
- if (throttleInterval) {
543
- fn = throttle(fn, throttleInterval);
544
- }
545
-
546
- cm.on(name, fn);
547
- }
548
-
549
- function addKeyShortcuts(map) {
550
- const ctrlKey = getCtrlKey();
551
- cm.addKeyMap(transform(map, (acc, value, key) => {
552
- // eslint-disable-next-line -- TODO: describe this disable
553
- // @ts-ignore
554
- acc[ctrlKey + '-' + key] = value;
555
- }, {}));
556
- }
557
- /**
558
- * low-level editor manipulation functions
559
- */
560
-
561
- /**
562
- * @description
563
- * Sets the content of the editor while preserving the cursor
564
- * position.
565
- *
566
- * If called for the first time it will not record the change in
567
- * the history.
568
- */
569
-
570
-
571
- function setValue(value) {
572
- value = value || '';
573
-
574
- if (getValue() === value) {
575
- return;
576
- } // set value, but save cursor position first
577
- // position will be restored, but w/o focus (third arg)
578
-
579
-
580
- const line = getCurrentLineNumber();
581
- const ch = getCurrentCharacter();
582
- cm.setValue(value);
583
- restoreCursor(ch, line, true); // We do not want to record the initial population in the
584
- // history. Otherwise it would always be possible to revert to
585
- // the empty string.
586
-
587
- if (!initializedWithValue) {
588
- cm.clearHistory();
589
- initializedWithValue = true;
590
- }
591
- }
592
-
593
- function cmd(name) {
594
- cm.execCommand(name);
595
- cm.focus();
596
- }
597
-
598
- function moveToLineBeginning(lineNumber) {
599
- cm.setCursor({
600
- line: defaultToCurrentLineNumber(lineNumber),
601
- ch: 0
602
- });
603
- cm.focus();
604
- }
605
- /**
606
- * @description
607
- * Insert a new line below the cursor and move to the beginning of
608
- * that line.
609
- *
610
- * Only do this if the editor has content and we are not already on
611
- * the last line.
612
- *
613
- * TODO rename this
614
- */
615
-
616
-
617
- function moveIfNotEmpty() {
618
- if (getCurrentLineLength() < 1) {
619
- return;
620
- }
621
-
622
- const next = getCurrentLineNumber() + 1;
623
-
624
- if (cm.lastLine() < next) {
625
- moveToLineEnd();
626
- insertAtCursor(getNl());
627
- }
628
-
629
- moveToLineBeginning(next);
630
- }
631
-
632
- function restoreCursor(character, lineNumber, noFocus) {
633
- cm.setCursor(defaultToCurrentLineNumber(lineNumber), character, {
634
- scroll: !noFocus
635
- });
636
-
637
- if (!noFocus) {
638
- cm.focus();
639
- }
640
- }
641
-
642
- function moveToLineEnd(lineNumber) {
643
- cm.setCursor({
644
- line: defaultToCurrentLineNumber(lineNumber),
645
- ch: getCurrentLineLength()
646
- });
647
- cm.focus();
648
- }
649
-
650
- function defaultToCurrentLineNumber(lineNumber) {
651
- if (lineNumber === 0 || lineNumber !== undefined && lineNumber > 0) {
652
- return lineNumber;
653
- }
654
-
655
- return getCurrentLineNumber();
656
- }
657
-
658
- function usePrimarySelection() {
659
- cmd('singleSelection');
660
- }
661
-
662
- function focus() {
663
- cm.focus();
664
- }
665
-
666
- function select(from, to) {
667
- cm.setSelection(from, to);
668
- cm.focus();
669
- }
670
-
671
- function selectBackwards(skip, len) {
672
- select(getPos(-skip - len), getPos(-skip));
673
-
674
- function getPos(modifier) {
675
- return {
676
- line: getCurrentLineNumber(),
677
- ch: getCurrentCharacter() + modifier
678
- };
679
- }
680
- }
681
-
682
- function extendSelectionBy(modifier) {
683
- select(getPos('anchor', 0), getPos('head', modifier));
684
-
685
- function getPos(prop, modifier) {
686
- const selection = getSelection();
687
-
688
- if (!selection) {
689
- return {
690
- line: 0,
691
- ch: 0
692
- };
693
- }
694
-
695
- return {
696
- line: selection[prop].line,
697
- ch: selection[prop].ch + modifier
698
- };
699
- }
700
- }
701
-
702
- function insertAtCursor(text) {
703
- cm.replaceRange(text, cm.getCursor());
704
- cm.focus();
705
- }
706
-
707
- function insertAtLineBeginning(text) {
708
- const initialCh = getCurrentCharacter();
709
- moveToLineBeginning();
710
- insertAtCursor(text);
711
- restoreCursor(initialCh + text.length);
712
- cm.focus();
713
- }
714
-
715
- function wrapSelection(wrapper) {
716
- const replacement = wrapper + getSelectedText() + wrapper;
717
- const selection = getSelection();
718
-
719
- if (selection) {
720
- cm.replaceRange(replacement, selection.anchor, selection == null ? void 0 : selection.head);
721
- cm.focus();
722
- }
723
- }
724
-
725
- function removeFromLineBeginning(charCount) {
726
- const lineNumber = getCurrentLineNumber();
727
- cm.replaceRange('', {
728
- line: lineNumber,
729
- ch: 0
730
- }, {
731
- line: lineNumber,
732
- ch: charCount
733
- });
734
- cm.focus();
735
- }
736
-
737
- function removeSelectedText() {
738
- cm.replaceSelection('');
739
- cm.focus();
740
- }
741
- /**
742
- * @description
743
- * Replace the selected text with the given string.
744
- *
745
- * If nothing is selected it will insert the text at the current
746
- * cursor position
747
- *
748
- * The optional `select` parameter controls what will be selected
749
- * afters wards. By default the cursor will be at the end of the
750
- * inserted text. You can pass 'around' to select the inserted
751
- * text.
752
- */
753
-
754
-
755
- function replaceSelectedText(replacement, select) {
756
- cm.replaceSelection(replacement, select);
757
- cm.focus();
758
- }
759
- /**
760
- * low-level editor get/check functions
761
- */
762
-
763
-
764
- function getCursor() {
765
- return cm.getCursor();
766
- }
767
-
768
- function setCursor(cursor) {
769
- cm.setCursor(cursor);
770
- }
771
-
772
- function getSelection() {
773
- const selections = cm.listSelections();
774
-
775
- if (!cm.somethingSelected() || !selections || selections.length < 1) {
776
- return null;
777
- }
778
-
779
- return selections[0];
780
- }
781
-
782
- function getLine(lineNumber) {
783
- return cm.getLine(lineNumber) || '';
784
- }
785
-
786
- function isLineEmpty(lineNumber) {
787
- const n = defaultToCurrentLineNumber(lineNumber);
788
- return n > -1 && getLine(n).length < 1 && n < cm.lineCount();
789
- }
790
-
791
- function getLinesCount() {
792
- return cm.lineCount();
793
- }
794
-
795
- function getSelectedText() {
796
- return getSelection() ? cm.getSelection() : '';
797
- }
798
-
799
- function getSelectionLength() {
800
- return getSelectedText().length;
801
- }
802
-
803
- function getCurrentLine() {
804
- return getLine(getCurrentLineNumber());
805
- }
806
-
807
- function getCurrentLineNumber() {
808
- return cm.getCursor().line;
809
- }
810
-
811
- function getCurrentCharacter() {
812
- return cm.getCursor().ch;
813
- }
814
-
815
- function getCurrentLineLength() {
816
- return getCurrentLine().length;
817
- }
818
-
819
- function lineStartsWith(text) {
820
- return getCurrentLine().startsWith(text);
821
- }
822
-
823
- function getIndentation() {
824
- return repeat(' ', cm.getOption('indentUnit') ?? 0);
825
- }
826
-
827
- function getNl(n = 1) {
828
- if (n < 1) {
829
- return '';
830
- }
831
-
832
- return repeat(LF, n);
833
- }
834
-
835
- function getValue() {
836
- return cm.getValue() || '';
837
- }
838
-
839
- function getHistorySize(which) {
840
- const history = cm.historySize();
841
- return which ? history[which] : history;
842
- }
843
-
844
- function repeat(what, n) {
845
- return new Array(n + 1).join(what);
846
- }
847
- }
848
-
849
- /* eslint-disable @typescript-eslint/no-use-before-define */
850
-
851
- function createPrefixToggleFn(prefix) {
852
- return editor => {
853
- if (editor.lineStartsWith(prefix)) {
854
- editor.removeFromLineBeginning(prefix.length);
855
- } else {
856
- editor.insertAtLineBeginning(prefix);
857
- }
858
- };
859
- }
860
- /**
861
- * Wraps the current selection with a marker.
862
- *
863
- * If nothing is selected it inserts the given text wrapped in the
864
- * marker and selects the inner text
865
- *
866
- * Used b the `bold`, `italic`, and `strike` commands.
867
- */
868
-
869
-
870
- function wrapSelection(editor, marker, emptyText) {
871
- return () => {
872
- editor.usePrimarySelection(); // there's a selection - wrap it with inline marker
873
-
874
- if (editor.getSelection()) {
875
- const selectedText = editor.getSelectedText();
876
-
877
- if (selectedText.startsWith(marker) && selectedText.endsWith(marker)) {
878
- const markerLength = marker.length;
879
- const textWithoutMarker = selectedText.slice(markerLength, selectedText.length - markerLength);
880
- editor.replaceSelectedText(textWithoutMarker);
881
- } else {
882
- editor.wrapSelection(marker);
883
- }
884
- } else {
885
- // no selection - insert sample text and select it
886
- editor.insertAtCursor(marker + emptyText + marker);
887
- editor.selectBackwards(marker.length, emptyText.length);
888
- }
889
- };
890
- }
891
-
892
- const HEADER_CHAR = '#';
893
- const quoteToggleFn = /*#__PURE__*/createPrefixToggleFn('> ');
894
- const codeToggleFn = /*#__PURE__*/createPrefixToggleFn(' ');
895
- /**
896
- * @description
897
- * A collection of commands used by the user bound to a
898
- * CodeMirrorWrapper instance.
899
- *
900
- * The command collection only depends on the wrapper instance and is
901
- * used by UI from code mirror stuff.
902
- */
903
-
904
- function create$1(editor) {
905
- return {
906
- bold: wrapSelection(editor, '__', 'text in bold'),
907
- italic: wrapSelection(editor, '*', 'text in italic'),
908
- strike: wrapSelection(editor, '~~', 'striked out'),
909
- quote: modifySelection(editor, quoteToggleFn),
910
- code: modifySelection(editor, codeToggleFn),
911
- link,
912
- h1: toggleHeader(editor, 1),
913
- h2: toggleHeader(editor, 2),
914
- h3: toggleHeader(editor, 3),
915
- ul: modifySelection(editor, ulToggleFn, true),
916
- ol: modifySelection(editor, olToggleFn, true),
917
- undo: function () {
918
- editor.cmd('undo');
919
- },
920
- redo: function () {
921
- editor.cmd('redo');
922
- },
923
- hr,
924
- indent,
925
- dedent,
926
- table
927
- };
928
- /**
929
- * @description
930
- * Insert a line with `---` below the cursor.
931
- */
932
-
933
- function hr() {
934
- editor.moveIfNotEmpty();
935
- const nl = editor.getNl();
936
- const markup = nl + '---' + nl + nl;
937
- editor.insertAtCursor(markup);
938
- }
939
- /**
940
- * @description
941
- * Indent the current line.
942
- */
943
-
944
-
945
- function indent() {
946
- editor.insertAtLineBeginning(editor.getIndentation());
947
- }
948
- /**
949
- * @description
950
- * Dedent the current line.
951
- */
952
-
953
-
954
- function dedent() {
955
- const indentation = editor.getIndentation();
956
-
957
- if (editor.lineStartsWith(indentation)) {
958
- editor.removeFromLineBeginning(indentation.length);
959
- }
960
- }
961
- /**
962
- * @description
963
- * Insert a markdown table template in a new line.
964
- */
965
-
966
-
967
- function table(config) {
968
- const nl = editor.getNl();
969
- editor.moveIfNotEmpty();
970
- editor.insertAtCursor(nl);
971
- const line = editor.getCurrentLineNumber();
972
- editor.insertAtCursor(tableTemplate(config.rows, config.cols).join(nl));
973
- editor.insertAtCursor(nl + nl);
974
- editor.restoreCursor(2, line);
975
- }
976
- /**
977
- * @description
978
- * Inserts or replaces the current selection with a markdown link
979
- */
980
-
981
-
982
- function link(url, text, title) {
983
- editor.usePrimarySelection();
984
- const linkTitle = title ? ' "' + title + '"' : '';
985
- const link = text ? '[' + text + '](' + url + linkTitle + ')' : '<' + url + '>';
986
- editor.replaceSelectedText(link, 'around');
987
- }
988
- }
989
- /**
990
- * For each line in the selection move to that line and call
991
- * `toggleFn` with the 1-based index of the line in the selection.
992
- *
993
- * If there is no selection we just call `toggleFn(editor)`.
994
- */
995
-
996
- function modifySelection(editor, toggleFn, isList) {
997
- return () => {
998
- editor.usePrimarySelection();
999
- const selection = editor.getSelection();
1000
-
1001
- if (selection) {
1002
- // there's a selection - toggle list bullet for each line
1003
- // listNumber is 1, 2, 3... and can be used as ol bullet
1004
- forLineIn(selection, (lineNumber, listNumber) => {
1005
- // TODO move this into forLineIn
1006
- editor.moveToLineBeginning(lineNumber);
1007
- toggleFn(editor, listNumber);
1008
- });
1009
- editor.moveToLineEnd();
1010
- } else {
1011
- // there's no selection - just toggle line prefix
1012
- // but if adding list, add whitespace before and after list
1013
- if (isList && !getListNumber(editor) && !editor.lineStartsWith('- ')) {
1014
- prepareListWhitespace(editor);
1015
- }
1016
-
1017
- toggleFn(editor);
1018
- }
1019
- };
1020
- }
1021
- /**
1022
- * Calls callback for each line number that is in the selection
1023
- *
1024
- * The second argument is the 1-based index of the iteration.
1025
- *
1026
- * @param {CodeMirror.Selection} selection
1027
- * param {function(number)} cb
1028
- */
1029
-
1030
-
1031
- function forLineIn(selection, cb) {
1032
- // anchor/head depend on selection direction, so min & max have to be used
1033
- const lines = [selection.anchor.line, selection.head.line];
1034
- const maxNumber = max(lines);
1035
- const minNumber = min(lines);
1036
- const lineRange = range(minNumber || 0, maxNumber !== undefined ? maxNumber + 1 : undefined);
1037
- lineRange.forEach((lineNumber, i) => {
1038
- cb(lineNumber, i + 1);
1039
- });
1040
- }
1041
-
1042
- function prepareListWhitespace(editor) {
1043
- const line = editor.getCurrentLineNumber();
1044
- const isCurrentLineEmpty = editor.isLineEmpty(line);
1045
- const isPrevLineEmpty = line > 0 ? editor.isLineEmpty(line - 1) : false;
1046
- const isNextLineEmpty = line < editor.getLinesCount() - 1 ? editor.isLineEmpty(line + 1) : true;
1047
- let linesToInsert = isCurrentLineEmpty ? 2 : 4;
1048
-
1049
- if (isPrevLineEmpty) {
1050
- linesToInsert = linesToInsert - 1;
1051
- }
1052
-
1053
- if (isNextLineEmpty) {
1054
- linesToInsert = linesToInsert - 1;
1055
- }
1056
-
1057
- editor.moveToLineEnd();
1058
- editor.insertAtCursor(editor.getNl(linesToInsert));
1059
- editor.restoreCursor(0, isCurrentLineEmpty ? line : line + 2);
1060
- }
1061
-
1062
- function getListNumber(editor) {
1063
- const result = editor.getCurrentLine().match(/^(\d+\. )/);
1064
- return result ? result[1] : null;
1065
- }
1066
-
1067
- function ulToggleFn(editor) {
1068
- if (editor.lineStartsWith('- ')) {
1069
- editor.removeFromLineBeginning(2);
1070
- } else {
1071
- const listNumber = getListNumber(editor);
1072
-
1073
- if (listNumber) {
1074
- editor.removeFromLineBeginning(listNumber.length);
1075
- }
1076
-
1077
- editor.insertAtLineBeginning('- ');
1078
- }
1079
- }
1080
-
1081
- function olToggleFn(editor, n) {
1082
- const listNumber = getListNumber(editor);
1083
-
1084
- if (listNumber) {
1085
- editor.removeFromLineBeginning(listNumber.length);
1086
- } else {
1087
- if (editor.lineStartsWith('- ')) {
1088
- editor.removeFromLineBeginning(2);
1089
- }
1090
-
1091
- editor.insertAtLineBeginning((n || 1) + '. ');
1092
- }
1093
- }
1094
- /**
1095
- * From a table layout specification build a Markdown table template.
1096
- *
1097
- * Returns the lines as an array.
1098
- * Used by the `table()` command
1099
- *
1100
- * @param {object} config
1101
- * @param {number} rows
1102
- * @param {number} cols
1103
- * @returns {string[]}
1104
- */
1105
-
1106
-
1107
- function tableTemplate(nrows, ncols) {
1108
- const cellWidth = new Array(11);
1109
- const cell = ' ' + cellWidth.join(' ') + ' |';
1110
- const separatorCell = ' ' + cellWidth.join('-') + ' |';
1111
- let baseRow = '|';
1112
- let separatorRow = '|';
1113
- times(ncols, () => {
1114
- baseRow += cell;
1115
- separatorRow += separatorCell;
1116
- });
1117
- const bodyRows = range(nrows).map(() => baseRow.replace(/\| {5}/g, '| Cell'));
1118
- const headerRow = baseRow.replace(/\| {7}/g, '| Header');
1119
- return [headerRow, separatorRow].concat(bodyRows);
1120
- }
1121
- /**
1122
- * Toggles the header prefix for a given level on the current line.
1123
- *
1124
- * - Removes a header when one of the same level is
1125
- * - Replaces the header if there is one of a different level
1126
- * - Otherwise inserts the header
1127
- */
1128
-
1129
-
1130
- function toggleHeader(editor, level) {
1131
- return () => {
1132
- const initialCh = editor.getCurrentCharacter();
1133
- const currentHeader = selectHeader(editor);
1134
- const prefix = repeat(HEADER_CHAR, level); // there's no header at the current line - create one
1135
-
1136
- if (!currentHeader) {
1137
- editor.moveToLineBeginning();
1138
- editor.insertAtCursor(prefix + ' ');
1139
- editor.restoreCursor(initialCh + prefix.length + 1);
1140
- return;
1141
- } // there's exactly the same header - remove one
1142
-
1143
-
1144
- if (editor.getSelectedText() === prefix) {
1145
- editor.extendSelectionBy(1);
1146
- const removedCh = editor.getSelectionLength();
1147
- editor.removeSelectedText();
1148
- editor.restoreCursor(initialCh - removedCh);
1149
- return;
1150
- } // there's another header at the current line - replace
1151
-
1152
-
1153
- const diff = prefix.length - editor.getSelectionLength();
1154
- editor.replaceSelectedText(prefix);
1155
- editor.restoreCursor(initialCh + diff);
1156
- };
1157
- }
1158
- /**
1159
- * On the current line select a Markdown header prefix. That is the
1160
- * string at the beginning of the line that consists of up to six `#`.
1161
- *
1162
- * If the selection was successful return the selected string.
1163
- */
1164
-
1165
-
1166
- function selectHeader(editor) {
1167
- const result = editor.getCurrentLine().match(/^( {0,3})(#{1,6}) /);
1168
-
1169
- if (!result) {
1170
- return null;
1171
- }
1172
-
1173
- const indentation = result[1];
1174
- const header = result[2];
1175
- editor.select(getPos(0), getPos(header.length));
1176
- return editor.getSelection();
1177
-
1178
- function getPos(modifier) {
1179
- return {
1180
- line: editor.getCurrentLineNumber(),
1181
- ch: indentation.length + modifier
1182
- };
1183
- }
1184
- }
1185
-
1186
- /* eslint-disable @typescript-eslint/no-explicit-any */
1187
- function createMarkdownEditor(host, options) {
1188
- const editor = create(host, options);
1189
-
1190
- function wrapChange(fn) {
1191
- return (e, ch) => {
1192
- fn(editor.getValue(), e, ch);
1193
- };
1194
- }
1195
-
1196
- const api = {
1197
- actions: create$1(editor),
1198
- history: {
1199
- hasUndo: function () {
1200
- return editor.getHistorySize('undo') > 0;
1201
- },
1202
- hasRedo: function () {
1203
- return editor.getHistorySize('redo') > 0;
1204
- }
1205
- },
1206
- events: {
1207
- onScroll: function (fn) {
1208
- editor.attachEvent('scroll', fn, 150);
1209
- },
1210
- onChange: function (fn) {
1211
- editor.attachEvent('change', wrapChange(fn), 0);
1212
- },
1213
- onPaste: function (fn) {
1214
- editor.attachEvent('paste', fn, 0);
1215
- }
1216
- },
1217
- insert: editor.insertAtCursor,
1218
- focus: editor.focus,
1219
- getContent: editor.getValue,
1220
- destroy: editor.destroy,
1221
- setContent: editor.setValue,
1222
- getSelectedText: editor.getSelectedText,
1223
- usePrimarySelection: editor.usePrimarySelection,
1224
- setReadOnly: editor.setReadOnly,
1225
- selectBackwards: editor.selectBackwards,
1226
- getCursor: editor.getCursor,
1227
- setCursor: editor.setCursor,
1228
- clear: () => editor.setValue(''),
1229
- selectAll: editor.selectAll,
1230
- setFullsize: editor.setFullsize,
1231
- refresh: editor.refresh
1232
- };
1233
- editor.addKeyShortcuts({
1234
- B: api.actions.bold,
1235
- I: api.actions.italic
1236
- });
1237
- return api;
1238
- }
1239
-
1240
- const styles$4 = {
1241
- root: css`
1242
- border: 1px solid ${tokens.gray400};
1243
- border-width: 0 1px;
1244
- overflow-y: auto;
1245
- height: auto;
1246
- min-height: 300px;
1247
-
1248
- .CodeMirror {
1249
- height: auto;
1250
- line-height: ${tokens.lineHeightDefault};
1251
- }
1252
- .CodeMirror-lines {
1253
- color: ${tokens.gray700};
1254
- padding: ${tokens.spacingL};
1255
- }
1256
- .CodeMirror-code {
1257
- font-family: ${tokens.fontStackMonospace};
1258
- font-size: ${tokens.fontSizeM};
1259
- }
1260
- .CodeMirror-scroll {
1261
- min-height: '6rem';
1262
- }
1263
-
1264
- .cm-header {
1265
- color: ${tokens.gray900};
1266
- }
1267
- span.cm-variable-2 {
1268
- color: ${tokens.gray700};
1269
- }
1270
- .cm-header-1 {
1271
- font-size: 1.9em;
1272
- }
1273
- .cm-header-2 {
1274
- font-size: 1.75em;
1275
- }
1276
- .cm-header-3 {
1277
- font-size: 1.6em;
1278
- }
1279
- .cm-header-4 {
1280
- font-size: 1.45em;
1281
- }
1282
- .cm-header-5 {
1283
- font-size: 1.3em;
1284
- }
1285
- .cm-header-6 {
1286
- font-size: 1.15em;
1287
- }
1288
-
1289
- span.cm-tag,
1290
- span.cm-string,
1291
- span.cm-attribute {
1292
- color: ${tokens.red600};
1293
- }
1294
- span.cm-string {
1295
- text-decoration: none !important;
1296
- }
1297
- span.cm-quote,
1298
- span.cm-comment {
1299
- color: ${tokens.gray600};
1300
- }
1301
- span.cm-link,
1302
- span.cm-url {
1303
- color: ${tokens.blue500} !important;
1304
- }
1305
- span.cm-link {
1306
- text-decoration: underline;
1307
- }
1308
- `,
1309
- framed: /*#__PURE__*/css({
1310
- '.CodeMirror': {
1311
- maxHeight: '500px'
1312
- }
1313
- }),
1314
- zen: /*#__PURE__*/css({
1315
- border: 'none !important',
1316
- '.CodeMirror-lines': {
1317
- maxWidth: '650px',
1318
- margin: '0 auto'
1319
- }
1320
- }),
1321
- disabled: css`
1322
- .CodeMirror {
1323
- background: ${tokens.gray100};
1324
- cursor: 'not-allowed';
1325
- }
1326
- .CodeMirror-cursors {
1327
- visibility: hidden !important;
1328
- }
1329
- .CodeMirror-scroll,
1330
- .CodeMirror-sizer,
1331
- .CodeMirror-lines {
1332
- cursor: not-allowed;
1333
- }
1334
- `
1335
- };
1336
- const MarkdownTextarea = /*#__PURE__*/React.memo(props => {
1337
- const hostRef = useRef(null);
1338
- const [editor, setEditor] = useState(null);
1339
- useEffect(() => {
1340
- if (hostRef.current) {
1341
- setEditor(createMarkdownEditor(hostRef.current, Object.assign({}, {
1342
- direction: props.direction,
1343
- readOnly: true
1344
- }, props.mode === 'zen' ? {
1345
- fixedHeight: true,
1346
- height: '100%'
1347
- } : {}, props.minHeight !== undefined ? {
1348
- height: props.minHeight
1349
- } : {})));
1350
- } // eslint-disable-next-line react-hooks/exhaustive-deps -- TODO: Evaluate the dependencies
1351
-
1352
- }, []);
1353
- useEffect(() => {
1354
- if (editor) {
1355
- props.onReady(editor);
1356
- } // eslint-disable-next-line react-hooks/exhaustive-deps -- TODO: Evaluate the dependencies
1357
-
1358
- }, [editor]);
1359
- const className = cx(styles$4.root, props.minHeight !== undefined ? css({
1360
- minHeight: props.minHeight
1361
- }) : undefined, props.mode === 'default' ? styles$4.framed : styles$4.zen, props.disabled && styles$4.disabled);
1362
- return React.createElement("div", {
1363
- className: className,
1364
- ref: hostRef,
1365
- "data-test-id": "markdown-textarea",
1366
- style: {
1367
- display: props.visible ? 'block' : 'none'
1368
- }
1369
- });
1370
- });
1371
- MarkdownTextarea.displayName = 'MarkdownTextarea';
1372
-
1373
- const HeadingSelector = props => {
1374
- const handleMenuClick = heading => {
1375
- props.onSelect(heading);
1376
- };
1377
-
1378
- return React.createElement(Menu, null, React.createElement(Menu.Trigger, null, props.children), React.createElement(Menu.List, null, React.createElement(Menu.Item, {
1379
- testId: "markdown-action-button-heading-h1",
1380
- onClick: () => handleMenuClick('h1')
1381
- }, "Heading 1"), React.createElement(Menu.Item, {
1382
- testId: "markdown-action-button-heading-h2",
1383
- onClick: () => handleMenuClick('h2')
1384
- }, "Heading 2"), React.createElement(Menu.Item, {
1385
- testId: "markdown-action-button-heading-h3",
1386
- onClick: () => handleMenuClick('h3')
1387
- }, "Heading 3")));
1388
- };
1389
-
1390
- const srOnly = /*#__PURE__*/css({
1391
- position: 'absolute',
1392
- width: '1px',
1393
- height: '1px',
1394
- padding: '0',
1395
- margin: '-1px',
1396
- overflow: 'hidden',
1397
- clip: 'rect(0, 0, 0, 0)',
1398
- border: '0'
1399
- });
1400
- const Zen = ({
1401
- label,
1402
- ...rest
1403
- }) => React.createElement("svg", {
1404
- width: 14,
1405
- height: 14,
1406
- viewBox: "0 0 1792 1792",
1407
- ...rest
1408
- }, React.createElement("path", {
1409
- d: "M1411 541l-355 355 355 355 144-144q29-31 70-14 39 17 39 59v448q0 26-19 45t-45 19h-448q-42 0-59-40-17-39 14-69l144-144-355-355-355 355 144 144q31 30 14 69-17 40-59 40H192q-26 0-45-19t-19-45v-448q0-42 40-59 39-17 69 14l144 144 355-355-355-355-144 144q-19 19-45 19-12 0-24-5-40-17-40-59V192q0-26 19-45t45-19h448q42 0 59 40 17 39-14 69L541 381l355 355 355-355-144-144q-31-30-14-69 17-40 59-40h448q26 0 45 19t19 45v448q0 42-39 59-13 5-25 5-26 0-45-19z"
1410
- }), React.createElement("span", {
1411
- className: srOnly
1412
- }, label));
1413
- const Strikethrough = ({
1414
- label,
1415
- ...rest
1416
- }) => React.createElement("svg", {
1417
- width: 14,
1418
- height: 14,
1419
- viewBox: "0 0 1792 1792",
1420
- ...rest
1421
- }, React.createElement("path", {
1422
- d: "M1760 896q14 0 23 9t9 23v64q0 14-9 23t-23 9H32q-14 0-23-9t-9-23v-64q0-14 9-23t23-9h1728zM483 832q-28-35-51-80-48-98-48-188 0-181 134-309 133-127 393-127 50 0 167 19 66 12 177 48 10 38 21 118 14 123 14 183 0 18-5 45l-12 3-84-6-14-2q-50-149-103-205-88-91-210-91-114 0-182 59-67 58-67 146 0 73 66 140t279 129q69 20 173 66 58 28 95 52H483zm507 256h411q7 39 7 92 0 111-41 212-23 56-71 104-37 35-109 81-80 48-153 66-80 21-203 21-114 0-195-23l-140-40q-57-16-72-28-8-8-8-22v-13q0-108-2-156-1-30 0-68l2-37v-44l102-2q15 34 30 71t22.5 56 12.5 27q35 57 80 94 43 36 105 57 59 22 132 22 64 0 139-27 77-26 122-86 47-61 47-129 0-84-81-157-34-29-137-71z"
1423
- }), React.createElement("span", {
1424
- className: srOnly
1425
- }, label));
1426
- const Indent = ({
1427
- label,
1428
- ...rest
1429
- }) => React.createElement("svg", {
1430
- width: 14,
1431
- height: 14,
1432
- viewBox: "0 0 1792 1792",
1433
- ...rest
1434
- }, React.createElement("path", {
1435
- d: "M352 832q0 14-9 23L55 1143q-9 9-23 9-13 0-22.5-9.5T0 1120V544q0-13 9.5-22.5T32 512q14 0 23 9l288 288q9 9 9 23zm1440 480v192q0 13-9.5 22.5t-22.5 9.5H32q-13 0-22.5-9.5T0 1504v-192q0-13 9.5-22.5T32 1280h1728q13 0 22.5 9.5t9.5 22.5zm0-384v192q0 13-9.5 22.5t-22.5 9.5H672q-13 0-22.5-9.5T640 1120V928q0-13 9.5-22.5T672 896h1088q13 0 22.5 9.5t9.5 22.5zm0-384v192q0 13-9.5 22.5T1760 768H672q-13 0-22.5-9.5T640 736V544q0-13 9.5-22.5T672 512h1088q13 0 22.5 9.5t9.5 22.5zm0-384v192q0 13-9.5 22.5T1760 384H32q-13 0-22.5-9.5T0 352V160q0-13 9.5-22.5T32 128h1728q13 0 22.5 9.5t9.5 22.5z"
1436
- }), React.createElement("span", {
1437
- className: srOnly
1438
- }, label));
1439
- const Dedent = ({
1440
- label,
1441
- ...rest
1442
- }) => React.createElement("svg", {
1443
- width: 14,
1444
- height: 14,
1445
- viewBox: "0 0 1792 1792",
1446
- ...rest
1447
- }, React.createElement("path", {
1448
- d: "M384 544v576q0 13-9.5 22.5T352 1152q-14 0-23-9L41 855q-9-9-9-23t9-23l288-288q9-9 23-9 13 0 22.5 9.5T384 544zm1408 768v192q0 13-9.5 22.5t-22.5 9.5H32q-13 0-22.5-9.5T0 1504v-192q0-13 9.5-22.5T32 1280h1728q13 0 22.5 9.5t9.5 22.5zm0-384v192q0 13-9.5 22.5t-22.5 9.5H672q-13 0-22.5-9.5T640 1120V928q0-13 9.5-22.5T672 896h1088q13 0 22.5 9.5t9.5 22.5zm0-384v192q0 13-9.5 22.5T1760 768H672q-13 0-22.5-9.5T640 736V544q0-13 9.5-22.5T672 512h1088q13 0 22.5 9.5t9.5 22.5zm0-384v192q0 13-9.5 22.5T1760 384H32q-13 0-22.5-9.5T0 352V160q0-13 9.5-22.5T32 128h1728q13 0 22.5 9.5t9.5 22.5z"
1449
- }), React.createElement("span", {
1450
- className: srOnly
1451
- }, label));
1452
- const Cubes = ({
1453
- label,
1454
- ...rest
1455
- }) => React.createElement("svg", {
1456
- width: 18,
1457
- height: 14,
1458
- viewBox: "0 0 2304 1792",
1459
- ...rest
1460
- }, React.createElement("path", {
1461
- d: "M640 1632l384-192v-314l-384 164v342zm-64-454l404-173-404-173-404 173zm1088 454l384-192v-314l-384 164v342zm-64-454l404-173-404-173-404 173zm-448-293l384-165V454l-384 164v267zm-64-379l441-189-441-189-441 189zm1088 518v416q0 36-19 67t-52 47l-448 224q-25 14-57 14t-57-14l-448-224q-4-2-7-4-2 2-7 4l-448 224q-25 14-57 14t-57-14L71 1554q-33-16-52-47t-19-67v-416q0-38 21.5-70T78 906l434-186V320q0-38 21.5-70t56.5-48l448-192q23-10 50-10t50 10l448 192q35 16 56.5 48t21.5 70v400l434 186q36 16 57 48t21 70z"
1462
- }), React.createElement("span", {
1463
- className: srOnly
1464
- }, label));
1465
- const Table = ({
1466
- label,
1467
- ...rest
1468
- }) => React.createElement("svg", {
1469
- width: 14,
1470
- height: 14,
1471
- viewBox: "0 0 1792 1792",
1472
- ...rest
1473
- }, React.createElement("path", {
1474
- d: "M576 1376v-192q0-14-9-23t-23-9H224q-14 0-23 9t-9 23v192q0 14 9 23t23 9h320q14 0 23-9t9-23zm0-384V800q0-14-9-23t-23-9H224q-14 0-23 9t-9 23v192q0 14 9 23t23 9h320q14 0 23-9t9-23zm512 384v-192q0-14-9-23t-23-9H736q-14 0-23 9t-9 23v192q0 14 9 23t23 9h320q14 0 23-9t9-23zM576 608V416q0-14-9-23t-23-9H224q-14 0-23 9t-9 23v192q0 14 9 23t23 9h320q14 0 23-9t9-23zm512 384V800q0-14-9-23t-23-9H736q-14 0-23 9t-9 23v192q0 14 9 23t23 9h320q14 0 23-9t9-23zm512 384v-192q0-14-9-23t-23-9h-320q-14 0-23 9t-9 23v192q0 14 9 23t23 9h320q14 0 23-9t9-23zm-512-768V416q0-14-9-23t-23-9H736q-14 0-23 9t-9 23v192q0 14 9 23t23 9h320q14 0 23-9t9-23zm512 384V800q0-14-9-23t-23-9h-320q-14 0-23 9t-9 23v192q0 14 9 23t23 9h320q14 0 23-9t9-23zm0-384V416q0-14-9-23t-23-9h-320q-14 0-23 9t-9 23v192q0 14 9 23t23 9h320q14 0 23-9t9-23zm128-320v1088q0 66-47 113t-113 47H224q-66 0-113-47t-47-113V288q0-66 47-113t113-47h1344q66 0 113 47t47 113z"
1475
- }), React.createElement("span", {
1476
- className: srOnly
1477
- }, label));
1478
- const SpecialChar = ({
1479
- label,
1480
- ...rest
1481
- }) => React.createElement("svg", {
1482
- width: 14,
1483
- height: 14,
1484
- viewBox: "0 0 1792 1792",
1485
- ...rest
1486
- }, React.createElement("path", {
1487
- d: "M1360 1307l35 159q3 12-3 22.5t-17 14.5l-5 1q-4 2-10.5 3.5t-16 4.5-21.5 5.5-25.5 5-30 5-33.5 4.5-36.5 3-38.5 1q-234 0-409-130.5T511 1054h-95q-13 0-22.5-9.5T384 1022V909q0-13 9.5-22.5T416 877h66q-2-57 1-105h-67q-14 0-23-9t-9-23V626q0-14 9-23t23-9h98q67-210 243.5-338T1158 128q102 0 194 23 11 3 20 15 6 11 3 24l-43 159q-3 13-14 19.5t-24 2.5l-4-1q-4-1-11.5-2.5L1261 364l-22.5-3.5-26-3-29-2.5-29.5-1q-126 0-226 64T778 594h468q16 0 25 12 10 12 7 26l-24 114q-5 26-32 26H734q-3 37 0 105h459q15 0 25 12 9 12 6 27l-24 112q-2 11-11 18.5t-20 7.5H782q48 117 149.5 185.5T1160 1308q18 0 36-1.5t33.5-3.5 29.5-4.5 24.5-5 18.5-4.5l12-3 5-2q13-5 26 2 12 7 15 21z"
1488
- }), React.createElement("span", {
1489
- className: srOnly
1490
- }, label));
1491
- const OrgLinks = ({
1492
- label,
1493
- ...rest
1494
- }) => React.createElement("svg", {
1495
- width: 14,
1496
- height: 14,
1497
- viewBox: "0 0 1792 1792",
1498
- ...rest
1499
- }, React.createElement("path", {
1500
- d: "M1792 1248v320q0 40-28 68t-68 28h-320q-40 0-68-28t-28-68v-320q0-40 28-68t68-28h96V960H960v192h96q40 0 68 28t28 68v320q0 40-28 68t-68 28H736q-40 0-68-28t-28-68v-320q0-40 28-68t68-28h96V960H320v192h96q40 0 68 28t28 68v320q0 40-28 68t-68 28H96q-40 0-68-28t-28-68v-320q0-40 28-68t68-28h96V960q0-52 38-90t90-38h512V640h-96q-40 0-68-28t-28-68V224q0-40 28-68t68-28h320q40 0 68 28t28 68v320q0 40-28 68t-68 28h-96v192h512q52 0 90 38t38 90v192h96q40 0 68 28t28 68z"
1501
- }), React.createElement("span", {
1502
- className: srOnly
1503
- }, label));
1504
- const Undo = ({
1505
- label,
1506
- ...rest
1507
- }) => React.createElement("svg", {
1508
- width: 14,
1509
- height: 14,
1510
- viewBox: "0 0 1792 1792",
1511
- ...rest
1512
- }, React.createElement("path", {
1513
- d: "M1664 896q0 156-61 298t-164 245-245 164-298 61q-172 0-327-72.5T305 1387q-7-10-6.5-22.5t8.5-20.5l137-138q10-9 25-9 16 2 23 12 73 95 179 147t225 52q104 0 198.5-40.5T1258 1258t109.5-163.5T1408 896t-40.5-198.5T1258 534t-163.5-109.5T896 384q-98 0-188 35.5T548 521l137 138q31 30 14 69-17 40-59 40H192q-26 0-45-19t-19-45V256q0-42 40-59 39-17 69 14l130 129q107-101 244.5-156.5T896 128q156 0 298 61t245 164 164 245 61 298z"
1514
- }), React.createElement("span", {
1515
- className: srOnly
1516
- }, label));
1517
- const Redo = ({
1518
- label,
1519
- ...rest
1520
- }) => React.createElement("svg", {
1521
- width: 14,
1522
- height: 14,
1523
- viewBox: "0 0 1792 1792",
1524
- ...rest
1525
- }, React.createElement("path", {
1526
- d: "M1664 256v448q0 26-19 45t-45 19h-448q-42 0-59-40-17-39 14-69l138-138q-148-137-349-137-104 0-198.5 40.5T534 534 424.5 697.5 384 896t40.5 198.5T534 1258t163.5 109.5T896 1408q119 0 225-52t179-147q7-10 23-12 15 0 25 9l137 138q9 8 9.5 20.5t-7.5 22.5q-109 132-264 204.5T896 1664q-156 0-298-61t-245-164-164-245-61-298 61-298 164-245 245-164 298-61q147 0 284.5 55.5T1425 340l130-129q29-31 70-14 39 17 39 59z"
1527
- }), React.createElement("span", {
1528
- className: srOnly
1529
- }, label));
1530
-
1531
- const InsertLinkSelector = props => {
1532
- if (props.canAddNew) {
1533
- return React.createElement(MultipleMediaContextMenu, { ...props
1534
- });
1535
- } else {
1536
- return React.createElement(Button, {
1537
- isDisabled: props.disabled,
1538
- startIcon: React.createElement(AssetIcon, null),
1539
- testId: "markdownEditor.linkExistingAssets",
1540
- size: "small",
1541
- variant: "secondary",
1542
- onClick: () => {
1543
- props.onSelectExisting();
1544
- }
1545
- }, "Insert media");
1546
- }
1547
- };
1548
-
1549
- const MultipleMediaContextMenu = props => {
1550
- return React.createElement(Menu, {
1551
- placement: "bottom-end"
1552
- }, React.createElement(Menu.Trigger, null, React.createElement(Button, {
1553
- endIcon: React.createElement(ChevronDownIcon, null),
1554
- isDisabled: props.disabled,
1555
- startIcon: React.createElement(AssetIcon, null),
1556
- testId: "markdownEditor.insertMediaDropdownTrigger",
1557
- size: "small",
1558
- variant: "secondary"
1559
- }, "Insert media")), React.createElement(Menu.List, null, React.createElement(Menu.Item, {
1560
- testId: "markdownEditor.uploadAssetsAndLink",
1561
- onClick: () => props.onAddNew()
1562
- }, "Add new media and link"), React.createElement(Menu.Item, {
1563
- testId: "markdownEditor.linkExistingAssets",
1564
- onClick: () => props.onSelectExisting()
1565
- }, "Link existing media")));
1566
- };
1567
-
1568
- /* eslint-disable react/prop-types */
1569
- const styles$5 = {
1570
- root: /*#__PURE__*/css({
1571
- position: 'relative',
1572
- zIndex: /*#__PURE__*/Number(tokens.zIndexWorkbenchHeader),
1573
- border: `1px solid ${tokens.gray400}`,
1574
- backgroundColor: tokens.gray100,
1575
- padding: tokens.spacingXs,
1576
- borderTopLeftRadius: tokens.borderRadiusSmall,
1577
- overflow: 'hidden'
1578
- }),
1579
- button: /*#__PURE__*/css({
1580
- height: '30px',
1581
- width: '36px',
1582
- marginLeft: tokens.spacing2Xs,
1583
- marginRight: tokens.spacing2Xs
1584
- }),
1585
- icon: /*#__PURE__*/css({
1586
- fill: tokens.gray700,
1587
- verticalAlign: 'middle'
1588
- }),
1589
- zenButton: /*#__PURE__*/css({
1590
- marginLeft: tokens.spacingXs
1591
- }),
1592
- zenButtonPressed: /*#__PURE__*/css({
1593
- backgroundColor: tokens.gray400
1594
- }),
1595
- tooltip: /*#__PURE__*/css({
1596
- zIndex: /*#__PURE__*/Number(tokens.zIndexTooltip)
1597
- })
1598
- };
1599
- const ToolbarButton = /*#__PURE__*/React.forwardRef((props, ref) => {
1600
- const {
1601
- tooltip,
1602
- onClick,
1603
- children,
1604
- className,
1605
- variant = 'transparent',
1606
- tooltipPlace = 'top',
1607
- isDisabled = false,
1608
- ...otherProps
1609
- } = props;
1610
- return React.createElement(Tooltip, {
1611
- className: styles$5.tooltip,
1612
- placement: tooltipPlace,
1613
- content: tooltip
1614
- }, React.createElement(IconButton, { ...otherProps,
1615
- ref: ref,
1616
- className: cx(styles$5.button, className),
1617
- isDisabled: isDisabled,
1618
- onClick: onClick,
1619
- variant: variant,
1620
- size: "small",
1621
- icon: children,
1622
- "aria-label": tooltip
1623
- }));
1624
- });
1625
- ToolbarButton.displayName = 'ToolbarButton';
1626
-
1627
- function MainButtons(props) {
1628
- const tooltipPlace = props.mode === 'zen' ? 'bottom' : 'top';
1629
- return React.createElement(React.Fragment, null, React.createElement(HeadingSelector, {
1630
- onSelect: heading => {
1631
- if (heading && props.actions.headings[heading]) {
1632
- props.actions.headings[heading]();
1633
- }
1634
- }
1635
- }, React.createElement(ToolbarButton, {
1636
- isDisabled: props.disabled,
1637
- testId: "markdown-action-button-heading",
1638
- tooltip: "Headings",
1639
- tooltipPlace: tooltipPlace
1640
- }, React.createElement(HeadingIcon, {
1641
- "aria-label": "Headings",
1642
- className: styles$5.icon
1643
- }))), React.createElement(ToolbarButton, {
1644
- isDisabled: props.disabled,
1645
- testId: "markdown-action-button-bold",
1646
- tooltip: "Bold",
1647
- tooltipPlace: tooltipPlace,
1648
- onClick: props.actions.simple.bold
1649
- }, React.createElement(FormatBoldIcon, {
1650
- "aria-label": "Bold",
1651
- className: styles$5.icon
1652
- })), React.createElement(ToolbarButton, {
1653
- isDisabled: props.disabled,
1654
- testId: "markdown-action-button-italic",
1655
- tooltip: "Italic",
1656
- tooltipPlace: tooltipPlace,
1657
- onClick: props.actions.simple.italic
1658
- }, React.createElement(FormatItalicIcon, {
1659
- "aria-label": "Italic",
1660
- className: styles$5.icon
1661
- })), React.createElement(ToolbarButton, {
1662
- isDisabled: props.disabled,
1663
- testId: "markdown-action-button-quote",
1664
- tooltip: "Quote",
1665
- tooltipPlace: tooltipPlace,
1666
- onClick: props.actions.simple.quote
1667
- }, React.createElement(QuoteIcon, {
1668
- "aria-label": "Quote",
1669
- className: styles$5.icon
1670
- })), React.createElement(ToolbarButton, {
1671
- isDisabled: props.disabled,
1672
- testId: "markdown-action-button-ul",
1673
- tooltip: "Unordered list",
1674
- tooltipPlace: tooltipPlace,
1675
- onClick: props.actions.simple.ul
1676
- }, React.createElement(ListBulletedIcon, {
1677
- "aria-label": "Unordered list",
1678
- className: styles$5.icon
1679
- })), React.createElement(ToolbarButton, {
1680
- isDisabled: props.disabled,
1681
- testId: "markdown-action-button-ol",
1682
- tooltip: "Ordered list",
1683
- tooltipPlace: tooltipPlace,
1684
- onClick: props.actions.simple.ol
1685
- }, React.createElement(ListNumberedIcon, {
1686
- "aria-label": "Ordered list",
1687
- className: styles$5.icon
1688
- })), React.createElement(ToolbarButton, {
1689
- isDisabled: props.disabled,
1690
- testId: "markdown-action-button-link",
1691
- tooltip: "Link",
1692
- tooltipPlace: tooltipPlace,
1693
- onClick: props.actions.insertLink
1694
- }, React.createElement(LinkIcon, {
1695
- "aria-label": "Link",
1696
- className: styles$5.icon
1697
- })));
1698
- }
1699
-
1700
- function AdditionalButtons(props) {
1701
- const tooltipPlace = props.mode === 'zen' ? 'bottom' : 'top';
1702
- return React.createElement(React.Fragment, null, React.createElement(ToolbarButton, {
1703
- isDisabled: props.disabled,
1704
- testId: "markdown-action-button-strike",
1705
- tooltip: "Strike out",
1706
- tooltipPlace: tooltipPlace,
1707
- onClick: props.actions.simple.strike
1708
- }, React.createElement(Strikethrough, {
1709
- label: "Strike out",
1710
- className: styles$5.icon
1711
- })), React.createElement(ToolbarButton, {
1712
- isDisabled: props.disabled,
1713
- testId: "markdown-action-button-code",
1714
- tooltip: "Code block",
1715
- tooltipPlace: tooltipPlace,
1716
- onClick: props.actions.simple.code
1717
- }, React.createElement(CodeIcon, {
1718
- "aria-label": "Code block",
1719
- className: styles$5.icon
1720
- })), React.createElement(ToolbarButton, {
1721
- isDisabled: props.disabled,
1722
- testId: "markdown-action-button-hr",
1723
- tooltip: "Horizontal rule",
1724
- tooltipPlace: tooltipPlace,
1725
- onClick: props.actions.simple.hr
1726
- }, React.createElement(HorizontalRuleIcon, {
1727
- "aria-label": "Horizontal rule",
1728
- className: styles$5.icon
1729
- })), React.createElement(ToolbarButton, {
1730
- isDisabled: props.disabled,
1731
- testId: "markdown-action-button-indent",
1732
- tooltip: "Increase indentation",
1733
- tooltipPlace: tooltipPlace,
1734
- onClick: props.actions.simple.indent
1735
- }, React.createElement(Indent, {
1736
- label: "Increase indentation",
1737
- className: styles$5.icon
1738
- })), React.createElement(ToolbarButton, {
1739
- isDisabled: props.disabled,
1740
- testId: "markdown-action-button-dedent",
1741
- tooltip: "Decrease indentation",
1742
- tooltipPlace: tooltipPlace,
1743
- onClick: props.actions.simple.dedent
1744
- }, React.createElement(Dedent, {
1745
- label: "Decrease indentation",
1746
- className: styles$5.icon
1747
- })), React.createElement(ToolbarButton, {
1748
- isDisabled: props.disabled,
1749
- testId: "markdown-action-button-embed",
1750
- tooltip: "Embed external content",
1751
- tooltipPlace: tooltipPlace,
1752
- onClick: props.actions.embedExternalContent
1753
- }, React.createElement(Cubes, {
1754
- label: "Embed external content",
1755
- className: styles$5.icon
1756
- })), React.createElement(ToolbarButton, {
1757
- isDisabled: props.disabled,
1758
- testId: "markdown-action-button-table",
1759
- tooltip: "Insert table",
1760
- tooltipPlace: tooltipPlace,
1761
- onClick: props.actions.insertTable
1762
- }, React.createElement(Table, {
1763
- label: "Insert table",
1764
- className: styles$5.icon
1765
- })), React.createElement(ToolbarButton, {
1766
- isDisabled: props.disabled,
1767
- testId: "markdown-action-button-special",
1768
- tooltip: "Insert special character",
1769
- tooltipPlace: tooltipPlace,
1770
- onClick: props.actions.insertSpecialCharacter
1771
- }, React.createElement(SpecialChar, {
1772
- label: "Insert special character",
1773
- className: styles$5.icon
1774
- })), React.createElement(ToolbarButton, {
1775
- isDisabled: props.disabled,
1776
- testId: "markdown-action-button-organizeLinks",
1777
- tooltip: "Organize links",
1778
- tooltipPlace: tooltipPlace,
1779
- onClick: props.actions.organizeLinks
1780
- }, React.createElement(OrgLinks, {
1781
- label: "Organize links",
1782
- className: styles$5.icon
1783
- })), React.createElement(ToolbarButton, {
1784
- isDisabled: props.disabled,
1785
- testId: "markdown-action-button-undo",
1786
- tooltip: "Undo",
1787
- tooltipPlace: tooltipPlace,
1788
- onClick: props.actions.history.undo
1789
- }, React.createElement(Undo, {
1790
- label: "Undo",
1791
- className: styles$5.icon
1792
- })), React.createElement(ToolbarButton, {
1793
- isDisabled: props.disabled,
1794
- testId: "markdown-action-button-redo",
1795
- tooltip: "Redo",
1796
- tooltipPlace: tooltipPlace,
1797
- onClick: props.actions.history.redo
1798
- }, React.createElement(Redo, {
1799
- label: "Redo",
1800
- className: styles$5.icon
1801
- })));
1802
- }
1803
-
1804
- function DefaultMarkdownToolbar(props) {
1805
- const [showAdditional, setShowAdditional] = React.useState(false);
1806
- return React.createElement("div", {
1807
- className: styles$5.root
1808
- }, React.createElement(Flex, {
1809
- justifyContent: "space-between",
1810
- flexWrap: "wrap"
1811
- }, React.createElement(Flex, {
1812
- flexWrap: "wrap"
1813
- }, React.createElement(MainButtons, { ...props
1814
- }), React.createElement(ToolbarButton, {
1815
- isDisabled: props.disabled,
1816
- testId: "markdown-action-button-toggle-additional",
1817
- tooltip: showAdditional ? 'Hide additional actions' : 'More actions',
1818
- onClick: () => {
1819
- setShowAdditional(!showAdditional);
1820
- }
1821
- }, React.createElement(MoreHorizontalIcon, {
1822
- className: styles$5.icon
1823
- }))), React.createElement(Flex, null, React.createElement(InsertLinkSelector, {
1824
- disabled: props.disabled,
1825
- onSelectExisting: props.actions.linkExistingMedia,
1826
- onAddNew: props.actions.addNewMedia,
1827
- canAddNew: props.canUploadAssets
1828
- }), React.createElement(ToolbarButton, {
1829
- isDisabled: props.disabled,
1830
- testId: "markdown-action-button-zen",
1831
- variant: "secondary",
1832
- onClick: props.actions.openZenMode,
1833
- className: styles$5.zenButton,
1834
- tooltip: "Expand"
1835
- }, React.createElement(Zen, {
1836
- label: "Expand",
1837
- className: styles$5.icon
1838
- })))), showAdditional && React.createElement(Flex, {
1839
- justifyContent: "space-between",
1840
- marginTop: "spacingXs"
1841
- }, React.createElement(Flex, null, React.createElement(AdditionalButtons, { ...props
1842
- }))));
1843
- }
1844
- function ZenMarkdownToolbar(props) {
1845
- return React.createElement("div", {
1846
- className: styles$5.root
1847
- }, React.createElement(Flex, {
1848
- justifyContent: "space-between"
1849
- }, React.createElement(Flex, null, React.createElement(MainButtons, { ...props
1850
- }), React.createElement(AdditionalButtons, { ...props
1851
- })), React.createElement(Flex, null, React.createElement(InsertLinkSelector, {
1852
- disabled: props.disabled,
1853
- onSelectExisting: props.actions.linkExistingMedia,
1854
- onAddNew: props.actions.addNewMedia,
1855
- canAddNew: props.canUploadAssets
1856
- }), React.createElement(IconButton, {
1857
- testId: "markdown-action-button-zen-close",
1858
- variant: "secondary",
1859
- size: "small",
1860
- className: cx(styles$5.zenButton, styles$5.zenButtonPressed),
1861
- onClick: () => {
1862
- props.actions.closeZenMode();
1863
- },
1864
- icon: React.createElement(Zen, {
1865
- label: "Collapse",
1866
- className: styles$5.icon
1867
- }),
1868
- "aria-label": "Collapse"
1869
- }))));
1870
- }
1871
- const MarkdownToolbar = /*#__PURE__*/React.memo(props => {
1872
- if (props.mode === 'zen') {
1873
- return React.createElement(ZenMarkdownToolbar, { ...props
1874
- });
1875
- }
1876
-
1877
- return React.createElement(DefaultMarkdownToolbar, { ...props
1878
- });
1879
- });
1880
- MarkdownToolbar.displayName = 'MarkdownToolbar';
1881
-
1882
- var MarkdownDialogType;
1883
-
1884
- (function (MarkdownDialogType) {
1885
- MarkdownDialogType["cheatsheet"] = "markdown-cheatsheet";
1886
- MarkdownDialogType["insertLink"] = "markdown-insertLink";
1887
- MarkdownDialogType["insertSpecialCharacter"] = "markdown-insertSpecialCharacter";
1888
- MarkdownDialogType["insertTable"] = "markdown-insertTable";
1889
- MarkdownDialogType["embedExternalContent"] = "markdown-embedExternalContent";
1890
- MarkdownDialogType["confirmInsertAsset"] = "markdown-confirmInsertAsset";
1891
- MarkdownDialogType["zenMode"] = "markdown-zenMode";
1892
- })(MarkdownDialogType || (MarkdownDialogType = {}));
1893
-
1894
- const styles$6 = {
1895
- flexColumnContainer: /*#__PURE__*/css({
1896
- display: 'flex',
1897
- flexWrap: 'nowrap'
1898
- }),
1899
- flexColumn: /*#__PURE__*/css({
1900
- flexGrow: 1
1901
- }),
1902
- verticalDivider: /*#__PURE__*/css({
1903
- borderRight: `1px solid ${tokens.gray500}`,
1904
- paddingRight: tokens.spacing3Xl,
1905
- marginRight: tokens.spacing2Xl
1906
- }),
1907
- preview: /*#__PURE__*/css({
1908
- display: 'inline-block',
1909
- paddingRight: tokens.spacingL,
1910
- width: '50%'
1911
- }),
1912
- unOrderedListPreview: /*#__PURE__*/css({
1913
- listStyleType: 'disc',
1914
- marginLeft: tokens.spacingS
1915
- }),
1916
- orderedListPreview: /*#__PURE__*/css({
1917
- listStyleType: 'decimal',
1918
- marginLeft: tokens.spacingS
1919
- }),
1920
- markup: /*#__PURE__*/css({
1921
- display: 'inline-block',
1922
- color: tokens.gray600,
1923
- paddingLeft: tokens.spacingL,
1924
- width: '50%'
1925
- }),
1926
- h1: /*#__PURE__*/css({
1927
- fontSize: tokens.fontSize2Xl
1928
- }),
1929
- h2: /*#__PURE__*/css({
1930
- fontSize: tokens.fontSizeXl
1931
- }),
1932
- h3: /*#__PURE__*/css({
1933
- fontSize: tokens.fontSizeL
1934
- }),
1935
- helpItem: /*#__PURE__*/css({
1936
- marginBottom: tokens.spacingS,
1937
- display: 'flex',
1938
- alignItems: 'flex-end',
1939
- height: tokens.spacingXl
1940
- }),
1941
- helpLink: /*#__PURE__*/css({
1942
- margin: 'auto'
1943
- }),
1944
- flexRowContainer: /*#__PURE__*/css({
1945
- display: 'flex',
1946
- width: '100%',
1947
- justifyContent: 'center',
1948
- marginTop: tokens.spacingXl
1949
- })
1950
- };
1951
- const CheatsheetModalDialog = () => {
1952
- return React.createElement(ModalContent, {
1953
- testId: "markdown-cheatsheet-dialog-content"
1954
- }, React.createElement("div", {
1955
- className: styles$6.flexColumnContainer
1956
- }, React.createElement("div", {
1957
- className: cx(styles$6.flexColumn, styles$6.verticalDivider)
1958
- }, React.createElement("div", {
1959
- className: styles$6.helpItem
1960
- }, React.createElement(Heading, {
1961
- marginBottom: "none",
1962
- as: "h1",
1963
- className: cx(styles$6.preview, styles$6.h1)
1964
- }, "H1"), React.createElement("div", {
1965
- className: styles$6.markup
1966
- }, "# heading")), React.createElement("div", {
1967
- className: styles$6.helpItem
1968
- }, React.createElement(Heading, {
1969
- marginBottom: "none",
1970
- as: "h2",
1971
- className: cx(styles$6.preview, styles$6.h2)
1972
- }, "H2"), React.createElement("div", {
1973
- className: styles$6.markup
1974
- }, "## heading")), React.createElement("div", {
1975
- className: styles$6.helpItem
1976
- }, React.createElement(Heading, {
1977
- marginBottom: "none",
1978
- as: "h3",
1979
- className: cx(styles$6.preview, styles$6.h3)
1980
- }, "H3"), React.createElement("div", {
1981
- className: styles$6.markup
1982
- }, "### heading")), React.createElement("div", {
1983
- className: styles$6.helpItem
1984
- }, React.createElement("strong", {
1985
- className: styles$6.preview
1986
- }, "bold"), React.createElement("div", {
1987
- className: styles$6.markup
1988
- }, "__text__")), React.createElement("div", {
1989
- className: styles$6.helpItem
1990
- }, React.createElement("em", {
1991
- className: styles$6.preview
1992
- }, "italic"), React.createElement("div", {
1993
- className: styles$6.markup
1994
- }, "*text*")), React.createElement("div", {
1995
- className: styles$6.helpItem
1996
- }, React.createElement("div", {
1997
- className: styles$6.preview
1998
- }, "strikethrough"), React.createElement("div", {
1999
- className: styles$6.markup
2000
- }, "~~text~~")), React.createElement("div", {
2001
- className: styles$6.helpItem
2002
- }, React.createElement(TextLink, {
2003
- as: "button",
2004
- className: styles$6.preview
2005
- }, "Link"), React.createElement("div", {
2006
- className: styles$6.markup
2007
- }, "[text](url)"))), React.createElement("div", {
2008
- className: styles$6.flexColumn
2009
- }, React.createElement("div", {
2010
- className: styles$6.helpItem
2011
- }, React.createElement("div", {
2012
- className: styles$6.preview
2013
- }, "Image"), React.createElement("div", {
2014
- className: styles$6.markup
2015
- }, "![alt-text](url)")), React.createElement("div", {
2016
- className: styles$6.helpItem
2017
- }, React.createElement("div", {
2018
- className: styles$6.preview
2019
- }, "Unordered list"), React.createElement("div", {
2020
- className: styles$6.markup
2021
- }, "* list item")), React.createElement("div", {
2022
- className: styles$6.helpItem
2023
- }, React.createElement("div", {
2024
- className: styles$6.preview
2025
- }, React.createElement("div", null, "Ordered list")), React.createElement("div", {
2026
- className: styles$6.markup
2027
- }, "1. list item")), React.createElement("div", {
2028
- className: styles$6.helpItem
2029
- }, React.createElement("div", {
2030
- className: styles$6.preview
2031
- }, React.createElement("div", null, "Blockquote")), React.createElement("div", {
2032
- className: styles$6.markup
2033
- }, "> quote")), React.createElement("div", {
2034
- className: styles$6.helpItem
2035
- }, React.createElement("div", {
2036
- className: styles$6.preview
2037
- }, "code span"), React.createElement("div", {
2038
- className: styles$6.markup
2039
- }, "`code here`")), React.createElement("div", {
2040
- className: styles$6.helpItem
2041
- }, React.createElement("div", {
2042
- className: styles$6.preview
2043
- }, "code block"), React.createElement("div", {
2044
- className: styles$6.markup
2045
- }, "```code here```")))), React.createElement("div", {
2046
- className: styles$6.flexRowContainer
2047
- }, React.createElement(TextLink, {
2048
- className: styles$6.helpLink,
2049
- href: "https://help.github.com/en/github/writing-on-github/basic-writing-and-formatting-syntax",
2050
- target: "_blank",
2051
- rel: "noopener noreferrer"
2052
- }, "View the full GitHub-flavored Markdown syntax help (opens in a new window)")));
2053
- };
2054
- const openCheatsheetModal = dialogs => {
2055
- return dialogs.openCurrent({
2056
- title: 'Markdown formatting help',
2057
- width: 'large',
2058
- minHeight: '415px',
2059
- shouldCloseOnEscapePress: true,
2060
- shouldCloseOnOverlayClick: true,
2061
- parameters: {
2062
- type: MarkdownDialogType.cheatsheet
2063
- }
2064
- });
2065
- };
2066
-
2067
- const ConfirmInsertAssetModalDialog = ({
2068
- onClose,
2069
- assets,
2070
- locale
2071
- }) => {
2072
- const localesNumber = assets.length;
2073
- return React.createElement(React.Fragment, null, React.createElement(ModalContent, {
2074
- testId: "confirm-insert-asset"
2075
- }, React.createElement(Paragraph, null, localesNumber === 1 ? `Link asset with missing file for locale ${locale}` : `Link assets with missing files for locale ${locale}`), React.createElement(Paragraph, null, localesNumber === 1 ? 'Do you want to link to the file in its fallback locale?' : 'Do you want to link to the files in their fallback locales?'), React.createElement(EntityList, null, assets.map(({
2076
- title,
2077
- description,
2078
- thumbnailUrl,
2079
- thumbnailAltText
2080
- }) => React.createElement(EntityList.Item, {
2081
- key: thumbnailUrl,
2082
- title: title,
2083
- thumbnailUrl: `${thumbnailUrl}?w=46&h=46&fit=thumb`,
2084
- thumbnailAltText: thumbnailAltText,
2085
- description: description
2086
- })))), React.createElement(ModalControls, null, React.createElement(Button, {
2087
- onClick: () => onClose(false),
2088
- variant: "secondary",
2089
- size: "small"
2090
- }, "Cancel"), React.createElement(Button, {
2091
- testId: "confirm-insert-asset",
2092
- onClick: () => onClose(true),
2093
- variant: "positive",
2094
- size: "small"
2095
- }, "Confirm")));
2096
- };
2097
- const openConfirmInsertAsset = (dialogs, options) => {
2098
- return dialogs.openCurrent({
2099
- title: 'Confirm using fallback assets',
2100
- width: 'medium',
2101
- minHeight: '270px',
2102
- shouldCloseOnEscapePress: true,
2103
- shouldCloseOnOverlayClick: true,
2104
- parameters: {
2105
- type: MarkdownDialogType.confirmInsertAsset,
2106
- ...options
2107
- }
2108
- });
2109
- };
2110
-
2111
- const urlRegex = /^(ftp|http|https):\/\/(\w+:{0,1}\w*@)?(\S+)(:[0-9]+)?(\/|\/([\w#!:.?+=&%@!\-/]))?$/;
2112
- function isValidUrl(value) {
2113
- return urlRegex.test(value);
2114
- }
2115
-
2116
- const styles$7 = {
2117
- widthFiledGroup: /*#__PURE__*/css({
2118
- display: 'flex',
2119
- flexWrap: 'nowrap',
2120
- alignItems: 'flex-start'
2121
- }),
2122
- radioButtonGroup: /*#__PURE__*/css({
2123
- display: 'inline-flex',
2124
- alignItems: 'flex-start',
2125
- paddingTop: tokens.spacingXl
2126
- }),
2127
- radioButton: /*#__PURE__*/css({
2128
- marginLeft: tokens.spacingM
2129
- })
2130
- };
2131
-
2132
- const makeEmbedlyLink = ({
2133
- url,
2134
- width,
2135
- selectedUnit,
2136
- attachSocial
2137
- }) => {
2138
- const s = {
2139
- percent: '%',
2140
- px: 'px'
2141
- };
2142
- return ['<a href="' + url + '" class="embedly-card" ', 'data-card-width="' + width + s[selectedUnit] + '" ', 'data-card-controls="' + (attachSocial ? '1' : '0') + '"', '>Embedded content: ' + url + '</a>'].join('');
2143
- };
2144
-
2145
- const isWidthValid = (width, unit) => unit === 'percent' ? width <= 100 : true;
2146
-
2147
- const EmbedExternalContentModal = ({
2148
- onClose
2149
- }) => {
2150
- const mainInputRef = useRef(null);
2151
- const [url, setUrl] = useState('https://');
2152
- const [selectedUnit, setUnit] = useState('percent');
2153
- const [urlIsValid, setUrlValidity] = useState(true);
2154
- const [width, setWidth] = useState('100');
2155
- const [attachSocial, setAttachSocial] = useState(false);
2156
- useEffect(() => {
2157
- var _mainInputRef$current;
2158
-
2159
- if ((_mainInputRef$current = mainInputRef.current) != null && _mainInputRef$current.focus) {
2160
- mainInputRef.current.focus();
2161
- }
2162
- }, [mainInputRef]);
2163
- return React.createElement(React.Fragment, null, React.createElement(ModalContent, {
2164
- testId: "embed-external-dialog"
2165
- }, React.createElement(Form, null, React.createElement(FormControl, {
2166
- id: "external-link-url-field",
2167
- isRequired: true,
2168
- isInvalid: !urlIsValid
2169
- }, React.createElement(FormControl.Label, null, "Content URL"), React.createElement(TextInput, {
2170
- name: "external-link-url",
2171
- value: url,
2172
- onChange: e => {
2173
- const value = e.target.value;
2174
- setUrl(value);
2175
- setUrlValidity(isValidUrl(value));
2176
- },
2177
- testId: "external-link-url-field",
2178
- placeholder: "https://example.com",
2179
- ref: mainInputRef
2180
- }), React.createElement(FormControl.HelpText, null, "Include protocol (e.g. https://)"), !urlIsValid && React.createElement(FormControl.ValidationMessage, null, "URL is invalid")), React.createElement(TextLink, {
2181
- href: "http://embed.ly/providers",
2182
- target: "_blank",
2183
- rel: "noopener noreferrer"
2184
- }, "Supported sources"), React.createElement("div", {
2185
- className: styles$7.widthFiledGroup
2186
- }, React.createElement(FormControl, {
2187
- id: "embedded-content-width",
2188
- isRequired: true,
2189
- isInvalid: !isWidthValid(Number(width), selectedUnit)
2190
- }, React.createElement(FormControl.Label, null, "Width"), React.createElement(TextInput, {
2191
- value: width,
2192
- name: "embedded-content-width",
2193
- testId: "embedded-content-width",
2194
- type: "number",
2195
- width: "small",
2196
- onChange: e => setWidth(e.target.value)
2197
- }), !isWidthValid(Number(width), selectedUnit) && React.createElement(FormControl.ValidationMessage, null, "Should be equal or less then 100")), React.createElement("div", {
2198
- className: styles$7.radioButtonGroup
2199
- }, React.createElement(Radio, {
2200
- id: "unit-option-percent",
2201
- value: "percent",
2202
- isChecked: selectedUnit === 'percent',
2203
- onChange: () => setUnit('percent'),
2204
- className: styles$7.radioButton
2205
- }, "percent"), React.createElement(Radio, {
2206
- id: "unit-option-pixels",
2207
- value: "pixels",
2208
- isChecked: selectedUnit === 'px',
2209
- onChange: () => setUnit('px'),
2210
- className: styles$7.radioButton
2211
- }, "pixels"))), React.createElement(Checkbox, {
2212
- id: "attach-social-checkbox",
2213
- name: "attach-social-checkbox",
2214
- value: "Yes",
2215
- isChecked: attachSocial,
2216
- onChange: () => setAttachSocial(!attachSocial),
2217
- testId: "attach-social-checkbox"
2218
- }, "Attach social sharing links to this element"), React.createElement(Text, {
2219
- as: "p",
2220
- fontColor: "gray500",
2221
- marginTop: "spacingXs"
2222
- }, "To enable this embedded content in your application make sure to add the\u00A0", React.createElement(TextLink, {
2223
- href: "http://embed.ly/docs/products/cards",
2224
- target: "_blank",
2225
- rel: "noopener noreferrer"
2226
- }, "Embedly's platform.js"), "\u00A0on your development environment"))), React.createElement(ModalControls, null, React.createElement(Button, {
2227
- testId: "emded-external-cancel",
2228
- onClick: () => onClose(false),
2229
- variant: "secondary",
2230
- size: "small"
2231
- }, "Cancel"), React.createElement(Button, {
2232
- testId: "embed-external-confirm",
2233
- onClick: () => onClose(makeEmbedlyLink({
2234
- url,
2235
- width: Number(width),
2236
- selectedUnit,
2237
- attachSocial
2238
- })),
2239
- variant: "positive",
2240
- size: "small"
2241
- }, "Insert")));
2242
- };
2243
- const openEmbedExternalContentDialog = dialogs => {
2244
- return dialogs.openCurrent({
2245
- title: 'Embed external content',
2246
- width: 'large',
2247
- minHeight: '435px',
2248
- shouldCloseOnEscapePress: true,
2249
- shouldCloseOnOverlayClick: true,
2250
- parameters: {
2251
- type: MarkdownDialogType.embedExternalContent
2252
- }
2253
- });
2254
- };
2255
-
2256
- const InsertLinkModal = ({
2257
- selectedText,
2258
- onClose
2259
- }) => {
2260
- const mainInputRef = useRef(null);
2261
- const [text, setText] = useState(selectedText || '');
2262
- const [url, setUrl] = useState('');
2263
- const [touched, setTouched] = useState(false);
2264
- const [title, setTitle] = useState('');
2265
-
2266
- const onInsert = values => onClose(values);
2267
-
2268
- const urlIsValid = isValidUrl(url);
2269
- useEffect(() => {
2270
- var _mainInputRef$current;
2271
-
2272
- if (mainInputRef != null && (_mainInputRef$current = mainInputRef.current) != null && _mainInputRef$current.focus) {
2273
- mainInputRef.current.focus();
2274
- }
2275
- }, [mainInputRef]);
2276
- return React.createElement(React.Fragment, null, React.createElement(ModalContent, {
2277
- testId: "insert-link-modal"
2278
- }, React.createElement(Form, {
2279
- onSubmit: () => onInsert({
2280
- url,
2281
- text,
2282
- title
2283
- })
2284
- }, React.createElement(FormControl, {
2285
- id: "link-text-field",
2286
- isDisabled: Boolean(selectedText)
2287
- }, React.createElement(FormControl.Label, null, "Link text"), React.createElement(TextInput, {
2288
- name: "link-text",
2289
- value: text,
2290
- onChange: e => {
2291
- setText(e.target.value);
2292
- },
2293
- testId: "link-text-field"
2294
- })), React.createElement(FormControl, {
2295
- id: "target-url-field",
2296
- isInvalid: touched && !urlIsValid
2297
- }, React.createElement(FormControl.Label, null, "Target URL"), React.createElement(TextInput, {
2298
- name: "target-url",
2299
- value: url,
2300
- onChange: e => {
2301
- setUrl(e.target.value);
2302
- setTouched(true);
2303
- },
2304
- placeholder: "https://",
2305
- maxLength: 2100,
2306
- testId: "target-url-field",
2307
- ref: mainInputRef
2308
- }), React.createElement(FormControl.HelpText, null, "Include protocol (e.g. https://)"), touched && !urlIsValid && React.createElement(FormControl.ValidationMessage, null, "Invalid URL")), React.createElement(FormControl, {
2309
- id: "link-title-field"
2310
- }, React.createElement(FormControl.Label, null, "Link title"), React.createElement(TextInput, {
2311
- name: "link-title",
2312
- value: title,
2313
- onChange: e => {
2314
- setTitle(e.target.value);
2315
- },
2316
- testId: "link-title-field"
2317
- }), React.createElement(FormControl.HelpText, null, "Extra link information, usually shown as a tooltip on mouse hover")))), React.createElement(ModalControls, null, React.createElement(Button, {
2318
- testId: "insert-link-cancel",
2319
- onClick: () => onClose(false),
2320
- variant: "secondary",
2321
- size: "small"
2322
- }, "Cancel"), React.createElement(Button, {
2323
- testId: "insert-link-confirm",
2324
- onClick: () => {
2325
- onInsert({
2326
- url,
2327
- text,
2328
- title
2329
- });
2330
- },
2331
- isDisabled: !urlIsValid,
2332
- variant: "positive",
2333
- size: "small"
2334
- }, "Insert")));
2335
- };
2336
- const openInsertLinkDialog = (dialogs, params) => {
2337
- return dialogs.openCurrent({
2338
- title: 'Insert link',
2339
- width: 'large',
2340
- minHeight: '410px',
2341
- shouldCloseOnEscapePress: true,
2342
- shouldCloseOnOverlayClick: true,
2343
- parameters: {
2344
- type: MarkdownDialogType.insertLink,
2345
- ...params
2346
- }
2347
- });
2348
- };
2349
-
2350
- const InsertTableModal = ({
2351
- onClose
2352
- }) => {
2353
- const mainInputRef = useRef(null);
2354
- const [rows, setRows] = useState(2);
2355
- const [cols, setColumns] = useState(1);
2356
- const rowsAreValid = inRange(rows, 2, 100);
2357
- const colsAreValid = inRange(cols, 1, 100);
2358
- useEffect(() => {
2359
- var _mainInputRef$current;
2360
-
2361
- if ((_mainInputRef$current = mainInputRef.current) != null && _mainInputRef$current.focus) {
2362
- mainInputRef.current.focus();
2363
- }
2364
- }, [mainInputRef]);
2365
- return React.createElement(React.Fragment, null, React.createElement(ModalContent, {
2366
- testId: "insert-table-modal"
2367
- }, React.createElement(Form, null, React.createElement(FormControl, {
2368
- id: "insert-table-rows-number-field",
2369
- isRequired: true,
2370
- isInvalid: !rowsAreValid
2371
- }, React.createElement(FormControl.Label, null, "Number of rows"), React.createElement(TextInput, {
2372
- name: "rows",
2373
- value: rows.toString(),
2374
- onChange: e => setRows(Number(e.target.value)),
2375
- testId: "insert-table-rows-number-field",
2376
- min: 2,
2377
- max: 100,
2378
- pattern: "[1-9][0-9]*",
2379
- type: "number",
2380
- width: "small",
2381
- autoComplete: "off",
2382
- ref: mainInputRef
2383
- }), !rowsAreValid && React.createElement(FormControl.ValidationMessage, null, "Should be between 2 and 100")), React.createElement(FormControl, {
2384
- id: "insert-table-columns-number-field",
2385
- isRequired: true,
2386
- isInvalid: !colsAreValid
2387
- }, React.createElement(FormControl.Label, null, "Number of columns"), React.createElement(TextInput, {
2388
- name: "columns",
2389
- value: cols.toString(),
2390
- onChange: e => setColumns(Number(e.target.value)),
2391
- testId: "insert-table-columns-number-field",
2392
- min: 1,
2393
- max: 100,
2394
- pattern: "[1-9][0-9]*",
2395
- type: "number",
2396
- width: "small",
2397
- autoComplete: "off"
2398
- }), !colsAreValid && React.createElement(FormControl.ValidationMessage, null, "Should be between 1 and 100")))), React.createElement(ModalControls, null, React.createElement(Button, {
2399
- testId: "insert-table-cancel",
2400
- onClick: () => onClose(false),
2401
- variant: "secondary",
2402
- size: "small"
2403
- }, "Cancel"), React.createElement(Button, {
2404
- testId: "insert-table-confirm",
2405
- onClick: () => onClose({
2406
- rows,
2407
- cols
2408
- }),
2409
- variant: "positive",
2410
- size: "small",
2411
- isDisabled: !rowsAreValid || !colsAreValid
2412
- }, "Insert")));
2413
- };
2414
- const openInsertTableDialog = dialogs => {
2415
- return dialogs.openCurrent({
2416
- title: 'Insert table',
2417
- width: 'medium',
2418
- minHeight: '260px',
2419
- shouldCloseOnEscapePress: true,
2420
- shouldCloseOnOverlayClick: true,
2421
- parameters: {
2422
- type: MarkdownDialogType.insertTable
2423
- }
2424
- });
2425
- };
2426
-
2427
- const specialCharacters = [{
2428
- code: 180,
2429
- desc: 'acute accent'
2430
- }, {
2431
- code: 38,
2432
- desc: 'ampersand'
2433
- }, {
2434
- code: 166,
2435
- desc: 'broken vertical bar'
2436
- }, {
2437
- code: 8226,
2438
- desc: 'bullet'
2439
- }, {
2440
- code: 184,
2441
- desc: 'cedilla'
2442
- }, {
2443
- code: 162,
2444
- desc: 'cent'
2445
- }, {
2446
- code: 169,
2447
- desc: 'copyright'
2448
- }, {
2449
- code: 176,
2450
- desc: 'degree'
2451
- }, {
2452
- code: 247,
2453
- desc: 'division'
2454
- }, {
2455
- code: 189,
2456
- desc: 'fraction half'
2457
- }, {
2458
- code: 188,
2459
- desc: 'fraction quarter'
2460
- }, {
2461
- code: 190,
2462
- desc: 'fraction three quarters'
2463
- }, {
2464
- code: 62,
2465
- desc: 'greater than'
2466
- }, {
2467
- code: 161,
2468
- desc: 'inverted exclamation mark'
2469
- }, {
2470
- code: 191,
2471
- desc: 'inverted question mark'
2472
- }, {
2473
- code: 171,
2474
- desc: 'left-pointing double angle quotation mark'
2475
- }, {
2476
- code: 60,
2477
- desc: 'less than'
2478
- }, {
2479
- code: 175,
2480
- desc: 'macron'
2481
- }, {
2482
- code: 181,
2483
- desc: 'micro'
2484
- }, {
2485
- code: 160,
2486
- desc: 'non-breaking space'
2487
- }, {
2488
- code: 172,
2489
- desc: 'not'
2490
- }, {
2491
- code: 182,
2492
- desc: 'paragraph'
2493
- }, {
2494
- code: 177,
2495
- desc: 'plus-minus'
2496
- }, {
2497
- code: 34,
2498
- desc: 'quotation mark'
2499
- }, {
2500
- code: 174,
2501
- desc: 'registered'
2502
- }, {
2503
- code: 187,
2504
- desc: 'right-pointing double angle quotation mark'
2505
- }, {
2506
- code: 167,
2507
- desc: 'section'
2508
- }, {
2509
- code: 168,
2510
- desc: 'umlaut/diaeresis'
2511
- }, {
2512
- code: 215,
2513
- desc: 'multiplication'
2514
- }, {
2515
- code: 8482,
2516
- desc: 'trade mark'
2517
- }, {
2518
- code: 8364,
2519
- desc: 'euro'
2520
- }, {
2521
- code: 163,
2522
- desc: 'pound'
2523
- }, {
2524
- code: 165,
2525
- desc: 'yen'
2526
- }, {
2527
- code: 8222,
2528
- desc: 'double low-9 quotation mark'
2529
- }, {
2530
- code: 710,
2531
- desc: 'modifier circumflex accent'
2532
- }, {
2533
- code: 8224,
2534
- desc: 'dagger'
2535
- }, {
2536
- code: 8225,
2537
- desc: 'double dagger'
2538
- }, {
2539
- code: 8230,
2540
- desc: 'horizontal ellipsis'
2541
- }, {
2542
- code: 8220,
2543
- desc: 'left double quotation mark'
2544
- }, {
2545
- code: 8249,
2546
- desc: 'single left-pointing angle quotation mark'
2547
- }, {
2548
- code: 8216,
2549
- desc: 'left single quotation mark'
2550
- }, {
2551
- code: 183,
2552
- desc: 'middle dot'
2553
- }, {
2554
- code: 8212,
2555
- desc: 'em dash'
2556
- }, {
2557
- code: 8211,
2558
- desc: 'en dash'
2559
- }, {
2560
- code: 8240,
2561
- desc: 'per mille'
2562
- }, {
2563
- code: 8250,
2564
- desc: 'single right-pointing angle quotation mark'
2565
- }, {
2566
- code: 8217,
2567
- desc: 'right single quotation mark'
2568
- }, {
2569
- code: 8218,
2570
- desc: 'single low-9 quotation mark'
2571
- }, {
2572
- code: 170,
2573
- desc: 'feminine ordinal indicator'
2574
- }, {
2575
- code: 186,
2576
- desc: 'masculine ordinal indicator'
2577
- }, {
2578
- code: 8221,
2579
- desc: 'right double quotation mark'
2580
- }, {
2581
- code: 732,
2582
- desc: 'small tilde'
2583
- }, {
2584
- code: 9829,
2585
- desc: 'black heart'
2586
- }, {
2587
- code: 9830,
2588
- desc: 'diamond'
2589
- }];
2590
-
2591
- const styles$8 = {
2592
- buttonPanel: /*#__PURE__*/css({
2593
- display: 'flex',
2594
- flexWrap: 'wrap'
2595
- }),
2596
- charButton: /*#__PURE__*/css({
2597
- border: `1px solid ${tokens.gray500}`,
2598
- width: '4.1rem',
2599
- height: '4.1rem',
2600
- fontSize: tokens.fontSizeXl,
2601
- marginTop: tokens.spacing2Xs,
2602
- marginRight: tokens.spacing2Xs
2603
- }),
2604
- selectedCharButton: /*#__PURE__*/css({
2605
- backgroundColor: tokens.gray100
2606
- }),
2607
- tooltip: /*#__PURE__*/css({
2608
- zIndex: 1000
2609
- }),
2610
- button: /*#__PURE__*/css({
2611
- marginTop: tokens.spacingM,
2612
- marginRight: tokens.spacingS
2613
- })
2614
- };
2615
- const SpecialCharacterModalDialog = ({
2616
- onClose
2617
- }) => {
2618
- const [selectedCharacter, setSelectedCharacter] = useState(specialCharacters[0]);
2619
- return React.createElement(React.Fragment, null, React.createElement(ModalContent, {
2620
- testId: "insert-special-character-modal"
2621
- }, React.createElement(Flex, {
2622
- flexDirection: "column",
2623
- alignItems: "center"
2624
- }, React.createElement(Text, {
2625
- as: "div",
2626
- lineHeight: "lineHeight3Xl",
2627
- fontSize: "fontSize3Xl",
2628
- marginBottom: "spacingS"
2629
- }, String.fromCharCode(selectedCharacter.code)), React.createElement(Text, {
2630
- as: "div",
2631
- marginBottom: "spacingS"
2632
- }, selectedCharacter.desc)), React.createElement("div", {
2633
- className: styles$8.buttonPanel
2634
- }, specialCharacters.map(char => React.createElement("div", {
2635
- key: char.code
2636
- }, React.createElement(Tooltip, {
2637
- className: styles$8.tooltip,
2638
- content: char.desc
2639
- }, React.createElement(Button, {
2640
- testId: "special-character-button",
2641
- isActive: char.code === selectedCharacter.code,
2642
- className: styles$8.charButton,
2643
- variant: "transparent",
2644
- onClick: () => setSelectedCharacter(char)
2645
- }, String.fromCharCode(char.code))))))), React.createElement(ModalControls, null, React.createElement(Button, {
2646
- testId: "insert-character-cancel",
2647
- className: styles$8.button,
2648
- onClick: () => onClose(false),
2649
- variant: "secondary",
2650
- size: "small"
2651
- }, "Cancel"), React.createElement(Button, {
2652
- className: styles$8.button,
2653
- testId: "insert-character-confirm",
2654
- onClick: () => onClose(String.fromCharCode(selectedCharacter.code)),
2655
- variant: "positive",
2656
- size: "small"
2657
- }, "Insert selected")));
2658
- };
2659
- const openInsertSpecialCharacter = dialogs => {
2660
- return dialogs.openCurrent({
2661
- title: 'Insert special character',
2662
- width: 'large',
2663
- minHeight: '600px',
2664
- shouldCloseOnEscapePress: true,
2665
- shouldCloseOnOverlayClick: true,
2666
- parameters: {
2667
- type: MarkdownDialogType.insertSpecialCharacter
2668
- }
2669
- });
2670
- };
2671
-
2672
- const styles$9 = {
2673
- root: /*#__PURE__*/css({
2674
- position: 'fixed',
2675
- left: 0,
2676
- right: 0,
2677
- top: 0,
2678
- bottom: 0
2679
- }),
2680
- topSplit: /*#__PURE__*/css({
2681
- position: 'fixed',
2682
- top: 0,
2683
- height: '48px',
2684
- left: 0,
2685
- right: 0
2686
- }),
2687
- bottomSplit: /*#__PURE__*/css({
2688
- position: 'fixed',
2689
- bottom: 0,
2690
- left: 0,
2691
- right: 0,
2692
- height: '36px'
2693
- }),
2694
- editorSplit: /*#__PURE__*/css({
2695
- width: '50%',
2696
- position: 'fixed',
2697
- top: '48px',
2698
- left: 0,
2699
- bottom: '36px',
2700
- overflowX: 'hidden',
2701
- overflowY: 'scroll'
2702
- }),
2703
- editorSplitFullscreen: /*#__PURE__*/css({
2704
- left: 0,
2705
- right: 0,
2706
- width: '100%'
2707
- }),
2708
- previewSplit: /*#__PURE__*/css({
2709
- width: '50%',
2710
- position: 'fixed',
2711
- top: '48px',
2712
- right: 0,
2713
- bottom: '36px',
2714
- overflowX: 'hidden',
2715
- overflowY: 'scroll'
2716
- }),
2717
- separator: /*#__PURE__*/css({
2718
- position: 'fixed',
2719
- top: '48px',
2720
- bottom: '36px',
2721
- width: '1px',
2722
- background: tokens.gray400,
2723
- left: '50%'
2724
- }),
2725
- button: /*#__PURE__*/css({
2726
- position: 'fixed',
2727
- cursor: 'pointer',
2728
- zIndex: 105,
2729
- top: '49%',
2730
- height: '30px',
2731
- backgroundColor: tokens.gray100,
2732
- border: `1px solid ${tokens.gray400}`,
2733
- padding: 0
2734
- }),
2735
- hideButton: /*#__PURE__*/css({
2736
- left: '50%'
2737
- }),
2738
- showButton: /*#__PURE__*/css({
2739
- right: 0,
2740
- borderRightWidth: 0
2741
- }),
2742
- icon: /*#__PURE__*/css({
2743
- verticalAlign: 'middle'
2744
- })
2745
- };
2746
- const ZenModeModalDialog = props => {
2747
- const [currentValue, setCurrentValue] = React.useState(props.initialValue ?? '');
2748
- const [showPreview, setShowPreview] = React.useState(true);
2749
- const [editor, setEditor] = React.useState(null);
2750
- React.useEffect(() => {
2751
- var _props$sdk, _props$sdk$window;
2752
-
2753
- // eslint-disable-next-line -- TODO: describe this disable @typescript-eslint/no-explicit-any
2754
- (_props$sdk = props.sdk) == null ? void 0 : (_props$sdk$window = _props$sdk.window) == null ? void 0 : _props$sdk$window.updateHeight('100%'); // eslint-disable-next-line react-hooks/exhaustive-deps -- TODO: Evaluate the dependencies
2755
- }, []); // refresh editor right after dialog is opened to avoid disappearing effect
2756
-
2757
- React.useEffect(() => {
2758
- setTimeout(() => {
2759
- editor == null ? void 0 : editor.setFullsize();
2760
- editor == null ? void 0 : editor.refresh();
2761
- }, 150);
2762
- }, [editor]);
2763
- const actions = React.useMemo(() => {
2764
- return createMarkdownActions({
2765
- sdk: props.sdk,
2766
- editor,
2767
- locale: props.locale
2768
- }); // eslint-disable-next-line react-hooks/exhaustive-deps -- TODO: Evaluate the dependencies
2769
- }, [editor]);
2770
-
2771
- actions.closeZenMode = () => {
2772
- props.onClose({
2773
- value: currentValue,
2774
- cursor: editor == null ? void 0 : editor.getCursor()
2775
- });
2776
- };
2777
-
2778
- const direction = props.sdk.locales.direction[props.locale] ?? 'ltr';
2779
- return React.createElement("div", {
2780
- className: styles$9.root,
2781
- "data-test-id": "zen-mode-markdown-editor"
2782
- }, React.createElement("div", {
2783
- className: styles$9.topSplit
2784
- }, React.createElement(MarkdownToolbar, {
2785
- mode: "zen",
2786
- disabled: false,
2787
- canUploadAssets: false,
2788
- actions: actions
2789
- })), React.createElement("div", {
2790
- className: cx(styles$9.editorSplit, {
2791
- [styles$9.editorSplitFullscreen]: showPreview === false
2792
- })
2793
- }, React.createElement(MarkdownTextarea, {
2794
- mode: "zen",
2795
- visible: true,
2796
- disabled: false,
2797
- direction: direction,
2798
- onReady: editor => {
2799
- editor.setContent(props.initialValue ?? '');
2800
- editor.setReadOnly(false);
2801
- setEditor(editor);
2802
- editor.focus();
2803
- editor.events.onChange(value => {
2804
- setCurrentValue(value);
2805
- props.saveValueToSDK(value);
2806
- });
2807
- }
2808
- })), showPreview && React.createElement("div", {
2809
- className: styles$9.previewSplit
2810
- }, React.createElement(MarkdownPreview, {
2811
- direction: direction,
2812
- mode: "zen",
2813
- value: currentValue,
2814
- previewComponents: props.previewComponents
2815
- })), showPreview && React.createElement("div", {
2816
- className: styles$9.separator
2817
- }), showPreview && React.createElement("button", {
2818
- className: cx(styles$9.button, styles$9.hideButton),
2819
- "aria-label": "Hide preview",
2820
- onClick: () => {
2821
- setShowPreview(false);
2822
- }
2823
- }, React.createElement(ChevronRightIcon, {
2824
- variant: "muted",
2825
- size: "tiny",
2826
- className: styles$9.icon
2827
- })), !showPreview && React.createElement("button", {
2828
- className: cx(styles$9.button, styles$9.showButton),
2829
- "aria-label": "Show preview",
2830
- onClick: () => {
2831
- setShowPreview(true);
2832
- }
2833
- }, React.createElement(ChevronLeftIcon, {
2834
- variant: "muted",
2835
- size: "tiny",
2836
- className: styles$9.icon
2837
- })), React.createElement("div", {
2838
- className: styles$9.bottomSplit
2839
- }, React.createElement(MarkdownBottomBar, null, React.createElement(MarkdownHelp, {
2840
- onClick: () => {
2841
- openCheatsheetModal(props.sdk.dialogs);
2842
- }
2843
- }))));
2844
- };
2845
- const openZenMode = (dialogs, options) => {
2846
- return dialogs.openCurrent({
2847
- width: 'zen',
2848
- shouldCloseOnEscapePress: false,
2849
- minHeight: '100vh',
2850
- shouldCloseOnOverlayClick: false,
2851
- parameters: {
2852
- type: MarkdownDialogType.zenMode,
2853
- initialValue: options.initialValue,
2854
- locale: options.locale
2855
- }
2856
- });
2857
- };
2858
-
2859
- function normalizeWhiteSpace(str) {
2860
- if (str) {
2861
- return str.trim().replace(/\s{2,}/g, ' ');
2862
- } else {
2863
- return str;
2864
- }
2865
- }
2866
-
2867
- function removeExtension(str) {
2868
- return str.replace(/\.\w+$/g, '');
2869
- }
2870
-
2871
- function fileNameToTitle(str) {
2872
- return normalizeWhiteSpace(removeExtension(str).replace(/_/g, ' '));
2873
- }
2874
-
2875
- function replaceAssetDomain(fileUrl) {
2876
- const assetDomainMap = {
2877
- images: 'images.ctfassets.net',
2878
- assets: 'assets.ctfassets.net',
2879
- downloads: 'downloads.ctfassets.net',
2880
- videos: 'videos.ctfassets.net'
2881
- };
2882
- return fileUrl.replace(/(images|assets|downloads|videos).contentful.com/, (_, p1) => {
2883
- return assetDomainMap[p1];
2884
- });
2885
- }
2886
-
2887
- function makeAssetLink(asset, {
2888
- localeCode,
2889
- fallbackCode,
2890
- defaultLocaleCode
2891
- }) {
2892
- const localizedFile = get(asset, ['fields', 'file', localeCode]);
2893
- const fallbackFile = fallbackCode ? get(asset, ['fields', 'file', fallbackCode]) : null;
2894
- const defaultFile = get(asset, ['fields', 'file', defaultLocaleCode]);
2895
- const file = localizedFile || fallbackFile || defaultFile;
2896
-
2897
- if (isObject(file) && file.url) {
2898
- const title = get(asset, ['fields', 'title', localeCode]) || get(asset, ['fields', 'title', fallbackCode || '']) || get(asset, ['fields', 'title', defaultLocaleCode]) || fileNameToTitle(file.fileName);
2899
- const fileUrl = replaceAssetDomain(file.url);
2900
- return {
2901
- title,
2902
- asset,
2903
- url: fileUrl,
2904
- // is normally localized and we should not warn about this file
2905
- isLocalized: Boolean(localizedFile),
2906
- // was fallback value used
2907
- // if it was not localized normally, and we did not used a fallback
2908
- // it means we used a default locale - we filter empty values
2909
- isFallback: Boolean(fallbackFile),
2910
- // todo: tranform using fromHostname
2911
- asMarkdown: `![${title}](${fileUrl})`
2912
- };
2913
- } else {
2914
- return null;
2915
- }
2916
- }
2917
-
2918
- async function insertAssetLinks(assets, locales) {
2919
- // check whether do we have some assets, which don't have
2920
- // a version in this field's locale
2921
- const otherLocales = assets.filter(asset => {
2922
- return !get(asset, ['fields', 'file', locales.localeCode]);
2923
- });
2924
- const linksWithMeta = assets.map(asset => makeAssetLink(asset, locales)) // remove empty links
2925
- .filter(asset => asset !== null); // if there have values from fallback/default locales, we need to
2926
- // provide user a warning so we show him modal
2927
-
2928
- if (otherLocales.length > 0) {
2929
- const fallbackAssets = linksWithMeta // we don't want to warn about normally localized files
2930
- .filter(({
2931
- isLocalized
2932
- }) => !isLocalized).map(({
2933
- title,
2934
- isFallback,
2935
- asset
2936
- }) => {
2937
- const code = isFallback ? locales.fallbackCode : locales.defaultLocaleCode;
2938
- return {
2939
- title,
2940
- thumbnailUrl: asset.fields.file[code].url,
2941
- thumbnailAltText: title,
2942
- description: isFallback ? `Fallback locale (${code})` : `Default locale (${code})`,
2943
- asset: asset
2944
- };
2945
- });
2946
- return {
2947
- fallbacks: fallbackAssets,
2948
- links: linksWithMeta
2949
- };
2950
- }
2951
-
2952
- return {
2953
- links: linksWithMeta
2954
- };
2955
- }
2956
-
2957
- /* eslint-disable @typescript-eslint/no-use-before-define, @typescript-eslint/no-explicit-any */
2958
-
2959
- function extractTitle(title) {
2960
- title = title || '';
2961
- title = title.replace(/^ *('|"|\()*/, '');
2962
- title = title.replace(/('|"|\))* *$/, '');
2963
- return title;
2964
- }
2965
-
2966
- function head(text) {
2967
- return text.split(' ').shift();
2968
- }
2969
-
2970
- function tail(text) {
2971
- const segments = text.split(' ');
2972
- segments.shift();
2973
- return segments.join(' ');
2974
- }
2975
-
2976
- const PROCESSORS = {
2977
- inline: function (match) {
2978
- return {
2979
- match: match[0],
2980
- text: match[1],
2981
- href: head(match[2]),
2982
- title: extractTitle(tail(match[2]))
2983
- };
2984
- },
2985
- ref: function (match) {
2986
- return {
2987
- match: match[0],
2988
- text: match[1],
2989
- id: match[2]
2990
- };
2991
- },
2992
- label: function (match) {
2993
- return {
2994
- match: match[0],
2995
- id: match[1],
2996
- href: head(match[2]),
2997
- title: extractTitle(tail(match[2]))
2998
- };
2999
- }
3000
- };
3001
- const REGEXS = {
3002
- inline: /\[([^\r\n[\]]+)]\(([^\r\n)]+)\)/,
3003
- ref: /\[([^\r\n[\]]+)] ?\[([^\r\n[\]]+)]/,
3004
- label: /^ {0,3}\[([^\r\n[\]]+)]:\s+(.+)$/
3005
- };
3006
- const findInline = /*#__PURE__*/makeFinder('inline');
3007
- const findRefs = /*#__PURE__*/makeFinder('ref');
3008
- const findLabels = /*#__PURE__*/makeFinder('label');
3009
- function convertInlineToRef(text) {
3010
- let id = findMaxLabelId(text);
3011
- forEach(findInline(text), inline => {
3012
- id += 1;
3013
- text = text.replace(inline.match, buildRef(inline, id));
3014
- text += '\n' + buildLabel(inline, id);
3015
- });
3016
- return text;
3017
- }
3018
-
3019
- function mergeLabels(text) {
3020
- const byHref = {};
3021
- const byOldId = {};
3022
- forEach(findLabels(text), label => {
3023
- const alreadyAdded = byHref[label.href];
3024
- const current = extend({}, label);
3025
-
3026
- if (!alreadyAdded) {
3027
- byHref[current.href] = current;
3028
- } else if (hasTitle(current) && !hasTitle(alreadyAdded)) {
3029
- alreadyAdded.title = current.title;
3030
- }
3031
-
3032
- byOldId[current.id] = alreadyAdded || current;
3033
- });
3034
- return {
3035
- byHref: byHref,
3036
- byOldId: byOldId
3037
- };
3038
- }
3039
-
3040
- function rewriteRefs(text) {
3041
- const merged = mergeLabels(text);
3042
- const hrefToRefId = {};
3043
- const labels = [];
3044
- const rewrites = [];
3045
- let i = 1; // 1. compose list of labels with new ids, in order
3046
-
3047
- forEach(findRefs(text), ref => {
3048
- const oldLabel = merged.byOldId[ref.id];
3049
-
3050
- if (!oldLabel) {
3051
- return;
3052
- }
3053
-
3054
- const href = oldLabel.href;
3055
- let newRefId = hrefToRefId[href];
3056
-
3057
- if (!newRefId) {
3058
- hrefToRefId[href] = newRefId = i;
3059
- i += 1;
3060
- labels.push(extend({
3061
- newId: newRefId
3062
- }, oldLabel));
3063
- } // 1b. prepare rewrites to be applied, with new label ids
3064
-
3065
-
3066
- rewrites.push(extend({
3067
- newId: newRefId
3068
- }, ref));
3069
- }); // 2. remove all labels!
3070
-
3071
- forEach(findLabels(text), label => {
3072
- text = text.replace(label.match, '');
3073
- }); // 3. remove whitespace from the end of text
3074
-
3075
- text = text.replace(/[\r\n\s]*$/, '');
3076
- text += '\n\n'; // 4. apply rewrites
3077
-
3078
- forEach(rewrites, ref => {
3079
- text = text.replace(ref.match, buildRef(ref, ref.newId));
3080
- }); // 5. print new labels at the end of text
3081
-
3082
- forEach(labels, label => {
3083
- text += '\n' + buildLabel(label, label.newId);
3084
- });
3085
- return text;
3086
- }
3087
- /**
3088
- * Finding stuff
3089
- */
3090
-
3091
- function makeFinder(type) {
3092
- return text => findAll(text, type).map(PROCESSORS[type]);
3093
- }
3094
-
3095
- function findMaxLabelId(textOrLabels) {
3096
- if (isString(textOrLabels)) {
3097
- textOrLabels = findLabels(textOrLabels);
3098
- }
3099
-
3100
- const ids = textOrLabels.map(x => x.id).map(x => parseInt(x, 10)).filter(x => isFinite(x) && x > 0);
3101
- return ids.length > 0 ? max(ids) || 0 : 0;
3102
- }
3103
-
3104
- function findAll(text, type) {
3105
- const flags = 'g' + (type === 'label' ? 'm' : '');
3106
- const matches = [];
3107
- const re = new RegExp(REGEXS[type].source, flags);
3108
- let found = re.exec(text);
3109
-
3110
- while (found) {
3111
- matches.push(found);
3112
- re.lastIndex = found.index + found[0].length;
3113
- found = re.exec(text);
3114
- }
3115
-
3116
- return matches;
3117
- }
3118
- /**
3119
- * Other utilities
3120
- */
3121
-
3122
-
3123
- function hasTitle(link) {
3124
- return isObject(link) && isString(link.title) && link.title.length > 0;
3125
- }
3126
-
3127
- function buildLabel(link, id) {
3128
- let markup = '[' + id + ']: ' + link.href;
3129
-
3130
- if (hasTitle(link)) {
3131
- markup += ' "' + link.title + '"';
3132
- }
3133
-
3134
- return markup;
3135
- }
3136
-
3137
- function buildRef(link, id) {
3138
- return '[' + link.text + '][' + id + ']';
3139
- }
3140
-
3141
- function createMarkdownActions(props) {
3142
- const {
3143
- sdk,
3144
- editor,
3145
- locale
3146
- } = props; // eslint-disable-next-line -- TODO: describe this disable @typescript-eslint/ban-types
3147
-
3148
- const insertAssetsWithConfirmation = async assets => {
3149
- if (assets) {
3150
- const {
3151
- links,
3152
- fallbacks
3153
- } = await insertAssetLinks(assets, {
3154
- localeCode: locale,
3155
- defaultLocaleCode: sdk.locales.default,
3156
- fallbackCode: sdk.locales.fallbacks[locale]
3157
- });
3158
-
3159
- if (links && links.length > 0) {
3160
- if (fallbacks) {
3161
- const insertAnyway = await openConfirmInsertAsset(sdk.dialogs, {
3162
- locale: locale,
3163
- assets: fallbacks
3164
- });
3165
-
3166
- if (!insertAnyway) {
3167
- throw Error('User decided to not use fallbacks');
3168
- }
3169
- }
3170
-
3171
- return links.map(link => link.asMarkdown).join('\n\n');
3172
- }
3173
- }
3174
-
3175
- return '';
3176
- };
3177
-
3178
- return {
3179
- headings: {
3180
- h1: () => {
3181
- editor == null ? void 0 : editor.actions.h1();
3182
- },
3183
- h2: () => {
3184
- editor == null ? void 0 : editor.actions.h2();
3185
- },
3186
- h3: () => {
3187
- editor == null ? void 0 : editor.actions.h3();
3188
- }
3189
- },
3190
- simple: {
3191
- italic: () => {
3192
- editor == null ? void 0 : editor.actions.italic();
3193
- },
3194
- bold: () => {
3195
- editor == null ? void 0 : editor.actions.bold();
3196
- },
3197
- quote: () => {
3198
- editor == null ? void 0 : editor.actions.quote();
3199
- },
3200
- ol: () => {
3201
- editor == null ? void 0 : editor.actions.ol();
3202
- },
3203
- ul: () => {
3204
- editor == null ? void 0 : editor.actions.ul();
3205
- },
3206
- strike: () => {
3207
- editor == null ? void 0 : editor.actions.strike();
3208
- },
3209
- code: () => {
3210
- editor == null ? void 0 : editor.actions.code();
3211
- },
3212
- hr: () => {
3213
- editor == null ? void 0 : editor.actions.hr();
3214
- },
3215
- indent: () => {
3216
- editor == null ? void 0 : editor.actions.indent();
3217
- },
3218
- dedent: () => {
3219
- editor == null ? void 0 : editor.actions.dedent();
3220
- }
3221
- },
3222
- history: {
3223
- undo: () => {
3224
- editor == null ? void 0 : editor.actions.undo();
3225
- },
3226
- redo: () => {
3227
- editor == null ? void 0 : editor.actions.redo();
3228
- }
3229
- },
3230
- insertLink: async () => {
3231
- if (!editor) {
3232
- return;
3233
- }
3234
-
3235
- editor.usePrimarySelection();
3236
- const selectedText = editor.getSelectedText();
3237
- const result = await openInsertLinkDialog(sdk.dialogs, {
3238
- selectedText
3239
- });
3240
-
3241
- if (result) {
3242
- editor.actions.link(result.url, selectedText || result.text, result.title);
3243
- }
3244
- },
3245
- insertSpecialCharacter: async () => {
3246
- if (!editor) {
3247
- return;
3248
- }
3249
-
3250
- const result = await openInsertSpecialCharacter(sdk.dialogs);
3251
-
3252
- if (result) {
3253
- editor.insert(result);
3254
- }
3255
- },
3256
- insertTable: async () => {
3257
- if (!editor) {
3258
- return;
3259
- }
3260
-
3261
- const result = await openInsertTableDialog(sdk.dialogs);
3262
-
3263
- if (result) {
3264
- editor.actions.table(result);
3265
- }
3266
- },
3267
- organizeLinks: () => {
3268
- if (!editor) {
3269
- return;
3270
- }
3271
-
3272
- let text = editor.getContent();
3273
-
3274
- if (!text) {
3275
- return;
3276
- }
3277
-
3278
- text = convertInlineToRef(text);
3279
- text = rewriteRefs(text);
3280
- editor.setContent(text);
3281
- sdk.notifier.success('All your links are now references at the bottom of your document.');
3282
- },
3283
- embedExternalContent: async () => {
3284
- if (!editor) {
3285
- return;
3286
- }
3287
-
3288
- const result = await openEmbedExternalContentDialog(sdk.dialogs);
3289
-
3290
- if (result) {
3291
- editor.insert(result);
3292
- }
3293
- },
3294
- addNewMedia: async () => {
3295
- if (!editor) {
3296
- return;
3297
- }
3298
-
3299
- try {
3300
- const {
3301
- entity: asset
3302
- } = await sdk.navigator.openNewAsset({
3303
- slideIn: {
3304
- waitForClose: true
3305
- }
3306
- }); // eslint-disable-line -- TODO: describe this disable @typescript-eslint/no-explicit-any
3307
-
3308
- const markdownLinks = await insertAssetsWithConfirmation([asset]);
3309
- editor.insert(markdownLinks);
3310
- } finally {
3311
- editor.focus();
3312
- }
3313
- },
3314
- linkExistingMedia: async () => {
3315
- if (!editor) {
3316
- return;
3317
- }
3318
-
3319
- try {
3320
- const assets = await sdk.dialogs.selectMultipleAssets({
3321
- locale: locale
3322
- });
3323
- const markdownLinks = await insertAssetsWithConfirmation(assets);
3324
- editor.insert(markdownLinks);
3325
- } finally {
3326
- editor.focus();
3327
- }
3328
- },
3329
- openZenMode: async () => {
3330
- if (!editor) {
3331
- return;
3332
- }
3333
-
3334
- const result = await openZenMode(sdk.dialogs, {
3335
- initialValue: editor.getContent(),
3336
- locale: props.locale
3337
- });
3338
- editor.setContent(result.value);
3339
-
3340
- if (result.cursor) {
3341
- editor.setCursor(result.cursor);
3342
- }
3343
-
3344
- editor.focus();
3345
- },
3346
- closeZenMode: () => {// do nothing
3347
- // this method is overwritten in dialog app
3348
- }
3349
- };
3350
- }
3351
-
3352
- const styles$a = {
3353
- container: /*#__PURE__*/css({
3354
- display: 'flex',
3355
- flexDirection: 'column',
3356
- fontFamily: tokens.fontStackPrimary
3357
- })
3358
- };
3359
- function MarkdownEditor(props) {
3360
- const [currentValue, setCurrentValue] = React.useState(props.initialValue ?? '');
3361
- const [selectedTab, setSelectedTab] = React.useState('editor');
3362
- const [editor, setEditor] = React.useState(null);
3363
- const [canUploadAssets, setCanUploadAssets] = React.useState(false);
3364
- React.useEffect(() => {
3365
- if (editor && props.onReady) {
3366
- props.onReady(editor); // fix: http://codemirror.977696.n3.nabble.com/codemirror-content-not-visible-in-bootstrap-modal-td4026988.html
3367
-
3368
- setTimeout(() => {
3369
- editor.refresh();
3370
- }, 1);
3371
- } // eslint-disable-next-line react-hooks/exhaustive-deps -- TODO: Evaluate the dependencies
3372
-
3373
- }, [editor]);
3374
- React.useEffect(() => {
3375
- props.sdk.access.can('create', 'Asset').then(value => {
3376
- setCanUploadAssets(value);
3377
- }); // eslint-disable-next-line react-hooks/exhaustive-deps -- TODO: Evaluate the dependencies
3378
- }, []);
3379
- React.useEffect(() => {
3380
- if (editor) {
3381
- editor.setReadOnly(props.disabled);
3382
- }
3383
- }, [editor, props.disabled]);
3384
- const isActionDisabled = editor === null || props.disabled || selectedTab !== 'editor';
3385
- const direction = props.sdk.locales.direction[props.sdk.field.locale] ?? 'ltr';
3386
- const actions = React.useMemo(() => {
3387
- return createMarkdownActions({
3388
- sdk: props.sdk,
3389
- editor,
3390
- locale: props.sdk.field.locale
3391
- }); // eslint-disable-next-line react-hooks/exhaustive-deps -- TODO: Evaluate the dependencies
3392
- }, [editor]);
3393
- const openMarkdownHelp = React.useCallback(() => {
3394
- openCheatsheetModal(props.sdk.dialogs); // eslint-disable-next-line react-hooks/exhaustive-deps -- TODO: Evaluate the dependencies
3395
- }, []);
3396
- return React.createElement("div", {
3397
- className: styles$a.container,
3398
- "data-test-id": "markdown-editor"
3399
- }, React.createElement(MarkdownTabs, {
3400
- active: selectedTab,
3401
- onSelect: tab => {
3402
- setSelectedTab(tab);
3403
- }
3404
- }), React.createElement(MarkdownToolbar, {
3405
- mode: "default",
3406
- disabled: isActionDisabled,
3407
- canUploadAssets: canUploadAssets,
3408
- actions: actions
3409
- }), React.createElement(MarkdownTextarea, {
3410
- minHeight: props.minHeight,
3411
- mode: "default",
3412
- visible: selectedTab === 'editor',
3413
- disabled: isActionDisabled,
3414
- direction: direction,
3415
- onReady: editor => {
3416
- editor.setContent(props.initialValue ?? '');
3417
- editor.setReadOnly(props.disabled);
3418
- setEditor(editor);
3419
- editor.events.onChange(value => {
3420
- // Trim empty lines
3421
- const trimmedValue = value.replace(/^\s+$/gm, '');
3422
- props.saveValueToSDK(trimmedValue);
3423
- setCurrentValue(value);
3424
- });
3425
- }
3426
- }), selectedTab === 'preview' && React.createElement(MarkdownPreview, {
3427
- direction: direction,
3428
- minHeight: props.minHeight,
3429
- mode: "default",
3430
- value: currentValue,
3431
- previewComponents: props.previewComponents
3432
- }), React.createElement(MarkdownBottomBar, null, React.createElement(MarkdownHelp, {
3433
- onClick: openMarkdownHelp
3434
- })), React.createElement(MarkdownConstraints, {
3435
- sdk: props.sdk,
3436
- value: currentValue
3437
- }));
3438
- }
3439
- function MarkdownEditorConnected(props) {
3440
- return React.createElement(FieldConnector, {
3441
- throttle: 300,
3442
- field: props.sdk.field,
3443
- isInitiallyDisabled: props.isInitiallyDisabled
3444
- }, ({
3445
- value,
3446
- disabled,
3447
- setValue,
3448
- externalReset
3449
- }) => {
3450
- // on external change reset component completely and init with initial value again
3451
- return React.createElement(MarkdownEditor, { ...props,
3452
- key: `markdown-editor-${externalReset}`,
3453
- initialValue: value,
3454
- disabled: disabled,
3455
- saveValueToSDK: setValue
3456
- });
3457
- });
3458
- }
3459
-
3460
- const openMarkdownDialog = (sdk, previewComponents) => options => {
3461
- var _options$parameters, _options$parameters2, _options$parameters3, _options$parameters4, _options$parameters5, _options$parameters6, _options$parameters7;
3462
-
3463
- if (((_options$parameters = options.parameters) == null ? void 0 : _options$parameters.type) === MarkdownDialogType.cheatsheet) {
3464
- return ModalDialogLauncher.openDialog(options, () => {
3465
- return React.createElement(CheatsheetModalDialog, null);
3466
- });
3467
- } else if (((_options$parameters2 = options.parameters) == null ? void 0 : _options$parameters2.type) === MarkdownDialogType.insertLink) {
3468
- const selectedText = options.parameters.selectedText;
3469
- return ModalDialogLauncher.openDialog(options, ({
3470
- onClose
3471
- }) => {
3472
- return React.createElement(InsertLinkModal, {
3473
- selectedText: selectedText,
3474
- onClose: onClose
3475
- });
3476
- });
3477
- } else if (((_options$parameters3 = options.parameters) == null ? void 0 : _options$parameters3.type) === MarkdownDialogType.insertSpecialCharacter) {
3478
- return ModalDialogLauncher.openDialog(options, ({
3479
- onClose
3480
- }) => {
3481
- return React.createElement(SpecialCharacterModalDialog, {
3482
- onClose: onClose
3483
- });
3484
- });
3485
- } else if (((_options$parameters4 = options.parameters) == null ? void 0 : _options$parameters4.type) === MarkdownDialogType.insertTable) {
3486
- return ModalDialogLauncher.openDialog(options, ({
3487
- onClose
3488
- }) => {
3489
- return React.createElement(InsertTableModal, {
3490
- onClose: onClose
3491
- });
3492
- });
3493
- } else if (((_options$parameters5 = options.parameters) == null ? void 0 : _options$parameters5.type) === MarkdownDialogType.embedExternalContent) {
3494
- return ModalDialogLauncher.openDialog(options, ({
3495
- onClose
3496
- }) => {
3497
- return React.createElement(EmbedExternalContentModal, {
3498
- onClose: onClose
3499
- });
3500
- });
3501
- } else if (((_options$parameters6 = options.parameters) == null ? void 0 : _options$parameters6.type) === MarkdownDialogType.confirmInsertAsset) {
3502
- const locale = options.parameters.locale;
3503
- const assets = options.parameters.assets;
3504
- return ModalDialogLauncher.openDialog(options, ({
3505
- onClose
3506
- }) => {
3507
- return React.createElement(ConfirmInsertAssetModalDialog, {
3508
- onClose: onClose,
3509
- locale: locale,
3510
- assets: assets
3511
- });
3512
- });
3513
- } else if (((_options$parameters7 = options.parameters) == null ? void 0 : _options$parameters7.type) === MarkdownDialogType.zenMode) {
3514
- const initialValue = options.parameters.initialValue;
3515
- const locale = options.parameters.locale;
3516
- return ModalDialogLauncher.openDialog(options, ({
3517
- onClose
3518
- }) => {
3519
- return React.createElement(ZenModeModalDialog, {
3520
- saveValueToSDK: value => {
3521
- var _sdk$field2;
3522
-
3523
- if (value) {
3524
- var _sdk$field;
3525
-
3526
- return sdk == null ? void 0 : (_sdk$field = sdk.field) == null ? void 0 : _sdk$field.setValue(value);
3527
- }
3528
-
3529
- return sdk == null ? void 0 : (_sdk$field2 = sdk.field) == null ? void 0 : _sdk$field2.removeValue();
3530
- },
3531
- onClose: onClose,
3532
- initialValue: initialValue,
3533
- locale: locale,
3534
- sdk: sdk,
3535
- previewComponents: previewComponents
3536
- });
3537
- });
3538
- }
3539
-
3540
- return Promise.reject();
3541
- };
3542
-
3543
- const renderMarkdownDialog = sdk => {
3544
- const parameters = sdk.parameters.invocation;
3545
-
3546
- if (parameters.type === MarkdownDialogType.cheatsheet) {
3547
- sdk.window.startAutoResizer();
3548
- return React.createElement(CheatsheetModalDialog, null);
3549
- } else if (parameters.type === MarkdownDialogType.insertLink) {
3550
- const selectedText = parameters.selectedText;
3551
- sdk.window.startAutoResizer();
3552
- return React.createElement(InsertLinkModal, {
3553
- selectedText: selectedText,
3554
- onClose: sdk.close
3555
- });
3556
- } else if (parameters.type === MarkdownDialogType.insertSpecialCharacter) {
3557
- sdk.window.startAutoResizer();
3558
- return React.createElement(SpecialCharacterModalDialog, {
3559
- onClose: sdk.close
3560
- });
3561
- } else if (parameters.type === MarkdownDialogType.insertTable) {
3562
- sdk.window.startAutoResizer();
3563
- return React.createElement(InsertTableModal, {
3564
- onClose: sdk.close
3565
- });
3566
- } else if (parameters.type === MarkdownDialogType.embedExternalContent) {
3567
- sdk.window.startAutoResizer();
3568
- return React.createElement(EmbedExternalContentModal, {
3569
- onClose: sdk.close
3570
- });
3571
- } else if (parameters.type === MarkdownDialogType.confirmInsertAsset) {
3572
- const locale = parameters.locale;
3573
- const assets = parameters.assets;
3574
- sdk.window.startAutoResizer();
3575
- return React.createElement(ConfirmInsertAssetModalDialog, {
3576
- onClose: sdk.close,
3577
- locale: locale,
3578
- assets: assets
3579
- });
3580
- } else if (parameters.type === MarkdownDialogType.zenMode) {
3581
- const locale = parameters.locale;
3582
- const initialValue = parameters.initialValue; // eslint-disable-next-line -- TODO: describe this disable @typescript-eslint/no-explicit-any
3583
-
3584
- sdk.window.updateHeight('100%');
3585
- return React.createElement(ZenModeModalDialog, {
3586
- onClose: sdk.close,
3587
- saveValueToSDK: () => {// don't save changes in dialog mode
3588
- },
3589
- initialValue: initialValue,
3590
- locale: locale,
3591
- sdk: sdk
3592
- });
3593
- }
3594
-
3595
- return React.createElement("div", null);
3596
- };
3597
-
3598
- export { MarkdownEditorConnected as MarkdownEditor, MarkdownPreview, openMarkdownDialog, renderMarkdownDialog };
3599
- //# sourceMappingURL=field-editor-markdown.esm.js.map