@milkdown/preset-commonmark 5.5.0 → 6.0.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 (84) hide show
  1. package/README.md +5 -4
  2. package/lib/index.d.ts +34 -1
  3. package/lib/index.d.ts.map +1 -0
  4. package/lib/index.es.js +283 -523
  5. package/lib/index.es.js.map +1 -1
  6. package/lib/{src/mark → mark}/code-inline.d.ts +1 -1
  7. package/lib/mark/code-inline.d.ts.map +1 -0
  8. package/lib/{src/mark → mark}/em.d.ts +1 -1
  9. package/lib/mark/em.d.ts.map +1 -0
  10. package/lib/mark/index.d.ts +6 -0
  11. package/lib/mark/index.d.ts.map +1 -0
  12. package/lib/{src/mark → mark}/link.d.ts +7 -1
  13. package/lib/mark/link.d.ts.map +1 -0
  14. package/lib/{src/mark → mark}/strong.d.ts +1 -1
  15. package/lib/mark/strong.d.ts.map +1 -0
  16. package/lib/{src/node → node}/blockquote.d.ts +1 -1
  17. package/lib/node/blockquote.d.ts.map +1 -0
  18. package/lib/{src/node → node}/bullet-list.d.ts +1 -1
  19. package/lib/node/bullet-list.d.ts.map +1 -0
  20. package/lib/{src/node → node}/code-fence.d.ts +1 -1
  21. package/lib/node/code-fence.d.ts.map +1 -0
  22. package/lib/{src/node → node}/doc.d.ts +1 -1
  23. package/lib/node/doc.d.ts.map +1 -0
  24. package/lib/{src/node → node}/hardbreak.d.ts +1 -1
  25. package/lib/node/hardbreak.d.ts.map +1 -0
  26. package/lib/{src/node → node}/heading.d.ts +1 -1
  27. package/lib/node/heading.d.ts.map +1 -0
  28. package/lib/{src/node → node}/hr.d.ts +1 -1
  29. package/lib/node/hr.d.ts.map +1 -0
  30. package/lib/{src/node → node}/image.d.ts +5 -5
  31. package/lib/node/image.d.ts.map +1 -0
  32. package/lib/{src/node → node}/index.d.ts +2 -2
  33. package/lib/node/index.d.ts.map +1 -0
  34. package/lib/{src/node → node}/list-item.d.ts +1 -1
  35. package/lib/node/list-item.d.ts.map +1 -0
  36. package/lib/{src/node → node}/ordered-list.d.ts +1 -1
  37. package/lib/node/ordered-list.d.ts.map +1 -0
  38. package/lib/{src/node → node}/paragraph.d.ts +1 -1
  39. package/lib/node/paragraph.d.ts.map +1 -0
  40. package/lib/{src/node → node}/text.d.ts +1 -1
  41. package/lib/node/text.d.ts.map +1 -0
  42. package/lib/{src/plugin → plugin}/filter-html.d.ts +0 -0
  43. package/lib/plugin/filter-html.d.ts.map +1 -0
  44. package/lib/plugin/index.d.ts +2 -0
  45. package/lib/plugin/index.d.ts.map +1 -0
  46. package/lib/{src/supported-keys.d.ts → supported-keys.d.ts} +0 -0
  47. package/lib/supported-keys.d.ts.map +1 -0
  48. package/package.json +33 -10
  49. package/src/mark/code-inline.ts +1 -12
  50. package/src/mark/link.ts +93 -18
  51. package/src/mark/strong.ts +1 -7
  52. package/src/node/blockquote.ts +1 -14
  53. package/src/node/code-fence.ts +94 -184
  54. package/src/node/heading.ts +1 -41
  55. package/src/node/hr.ts +1 -8
  56. package/src/node/image.ts +81 -232
  57. package/src/node/list-item.ts +34 -53
  58. package/src/node/paragraph.ts +1 -9
  59. package/lib/src/index.d.ts +0 -34
  60. package/lib/src/index.d.ts.map +0 -1
  61. package/lib/src/mark/code-inline.d.ts.map +0 -1
  62. package/lib/src/mark/em.d.ts.map +0 -1
  63. package/lib/src/mark/index.d.ts +0 -6
  64. package/lib/src/mark/index.d.ts.map +0 -1
  65. package/lib/src/mark/link.d.ts.map +0 -1
  66. package/lib/src/mark/strong.d.ts.map +0 -1
  67. package/lib/src/node/blockquote.d.ts.map +0 -1
  68. package/lib/src/node/bullet-list.d.ts.map +0 -1
  69. package/lib/src/node/code-fence.d.ts.map +0 -1
  70. package/lib/src/node/doc.d.ts.map +0 -1
  71. package/lib/src/node/hardbreak.d.ts.map +0 -1
  72. package/lib/src/node/heading.d.ts.map +0 -1
  73. package/lib/src/node/hr.d.ts.map +0 -1
  74. package/lib/src/node/image.d.ts.map +0 -1
  75. package/lib/src/node/index.d.ts.map +0 -1
  76. package/lib/src/node/list-item.d.ts.map +0 -1
  77. package/lib/src/node/ordered-list.d.ts.map +0 -1
  78. package/lib/src/node/paragraph.d.ts.map +0 -1
  79. package/lib/src/node/text.d.ts.map +0 -1
  80. package/lib/src/plugin/filter-html.d.ts.map +0 -1
  81. package/lib/src/plugin/index.d.ts +0 -2
  82. package/lib/src/plugin/index.d.ts.map +0 -1
  83. package/lib/src/supported-keys.d.ts.map +0 -1
  84. package/lib/src/types.d.ts +0 -5
@@ -1,6 +1,6 @@
1
1
  /* Copyright 2021, Milkdown by Mirone. */
2
- import { createCmd, createCmdKey, themeToolCtx } from '@milkdown/core';
3
- import { setBlockType, textblockTypeInputRule } from '@milkdown/prose';
2
+ import { createCmd, createCmdKey, editorViewCtx, ThemeCodeFenceType } from '@milkdown/core';
3
+ import { Fragment, setBlockType, textblockTypeInputRule } from '@milkdown/prose';
4
4
  import { createNode, createShortcut } from '@milkdown/utils';
5
5
 
6
6
  import { SupportedKeys } from '../supported-keys';
@@ -33,119 +33,11 @@ export const TurnIntoCodeFence = createCmdKey('TurnIntoCodeFence');
33
33
 
34
34
  const id = 'fence';
35
35
  export const codeFence = createNode<Keys, { languageList?: string[] }>((utils, options) => {
36
- const style = utils.getStyle(({ palette, mixin, size, font }, { css }) => {
37
- const { shadow, scrollbar, border } = mixin;
38
- const { lineWidth, radius } = size;
39
- return css`
40
- background-color: ${palette('background')};
41
- color: ${palette('neutral')};
42
- font-size: 0.85rem;
43
- padding: 1.2rem 0.4rem 1.4rem;
44
- border-radius: ${radius};
45
- font-family: ${font.typography};
46
-
47
- * {
48
- margin: 0;
49
- }
50
-
51
- .code-fence_select-wrapper {
52
- position: relative;
53
- }
54
-
55
- .code-fence_value {
56
- width: 10.25rem;
57
- box-sizing: border-box;
58
- border-radius: ${size.radius};
59
- margin: 0 1.2rem 1.2rem;
60
- ${border()};
61
- ${shadow()};
62
- cursor: pointer;
63
- background-color: ${palette('surface')};
64
- position: relative;
65
- display: flex;
66
- color: ${palette('neutral', 0.87)};
67
- letter-spacing: 0.5px;
68
- height: 2.625rem;
69
- align-items: center;
70
-
71
- & > .icon {
72
- width: 2.625rem;
73
- height: 100%;
74
- display: flex;
75
- justify-content: center;
76
- align-items: center;
77
- color: ${palette('solid', 0.87)};
78
- border-left: ${lineWidth} solid ${palette('line')};
79
-
80
- text-align: center;
81
- transition: all 0.2s ease-in-out;
82
- &:hover {
83
- background: ${palette('background')};
84
- color: ${palette('primary')};
85
- }
86
- }
87
-
88
- > span:first-child {
89
- padding-left: 1rem;
90
- flex: 1;
91
- font-weight: 500;
92
- }
93
- }
94
-
95
- .code-fence_select-option {
96
- list-style: none;
97
- line-height: 2rem;
98
- padding-left: 1rem;
99
- cursor: pointer;
100
- :hover {
101
- background: ${palette('secondary', 0.12)};
102
- color: ${palette('primary')};
103
- }
104
- }
105
-
106
- .code-fence_select {
107
- &[data-fold='true'] {
108
- display: none;
109
- }
110
-
111
- font-weight: 500;
112
- position: absolute;
113
- z-index: 1;
114
- top: 2.625rem;
115
- box-sizing: border-box;
116
- left: 1.2rem;
117
- padding: 0.5rem 0;
118
- max-height: 16.75rem;
119
- width: 10.25rem;
120
- ${border()};
121
- ${shadow()};
122
- background-color: ${palette('surface')};
123
- border-top: none;
124
- overflow-y: auto;
125
- display: flex;
126
- flex-direction: column;
127
-
128
- ${scrollbar('y')}
129
- }
130
-
131
- code {
132
- line-height: 1.5;
133
- font-family: ${font.code};
134
- }
135
-
136
- pre {
137
- font-family: ${font.code};
138
- margin: 0 1.2rem !important;
139
- white-space: pre;
140
- overflow: auto;
141
- ${scrollbar('x')};
142
- }
143
- `;
144
- });
36
+ const languageList = options?.languageList || languageOptions;
145
37
 
146
38
  return {
147
39
  id,
148
- schema: () => ({
40
+ schema: (ctx) => ({
149
41
  content: 'text*',
150
42
  group: 'block',
151
43
  marks: '',
@@ -160,6 +52,24 @@ export const codeFence = createNode<Keys, { languageList?: string[] }>((utils, o
160
52
  },
161
53
  },
162
54
  parseDOM: [
55
+ {
56
+ tag: 'div.code-fence-container',
57
+ preserveWhitespace: 'full',
58
+ getAttrs: (dom) => {
59
+ if (!(dom instanceof HTMLElement)) {
60
+ throw new Error('Parse DOM error.');
61
+ }
62
+ return { language: dom.querySelector('pre')?.dataset['language'] };
63
+ },
64
+ getContent: (dom, schema) => {
65
+ if (!(dom instanceof HTMLElement)) {
66
+ throw new Error('Parse DOM error.');
67
+ }
68
+ const textNode = schema.text(dom.querySelector('pre')?.textContent ?? '');
69
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
70
+ return Fragment.from<any>(textNode);
71
+ },
72
+ },
163
73
  {
164
74
  tag: 'pre',
165
75
  preserveWhitespace: 'full',
@@ -172,13 +82,54 @@ export const codeFence = createNode<Keys, { languageList?: string[] }>((utils, o
172
82
  },
173
83
  ],
174
84
  toDOM: (node) => {
85
+ const select = document.createElement('select');
86
+ languageList.forEach((lang) => {
87
+ const option = document.createElement('option');
88
+ option.value = lang;
89
+ option.innerText = !lang ? '--' : lang;
90
+ if (lang === node.attrs['language']) {
91
+ option.selected = true;
92
+ }
93
+ select.appendChild(option);
94
+ });
95
+ select.onchange = (e) => {
96
+ const target = e.target;
97
+ if (!(target instanceof HTMLSelectElement)) {
98
+ return;
99
+ }
100
+ const view = ctx.get(editorViewCtx);
101
+ if (!view.editable) {
102
+ target.value = node.attrs['language'];
103
+ return;
104
+ }
105
+
106
+ const { top, left } = target.getBoundingClientRect();
107
+ const result = view.posAtCoords({ top, left });
108
+ if (!result) return;
109
+
110
+ const { tr } = view.state;
111
+
112
+ view.dispatch(
113
+ tr.setNodeMarkup(result.inside, undefined, {
114
+ ...node.attrs,
115
+ language: target.value,
116
+ }),
117
+ );
118
+ };
175
119
  return [
176
- 'pre',
120
+ 'div',
177
121
  {
178
- 'data-language': node.attrs['language'],
179
- class: utils.getClassName(node.attrs, 'code-fence', style),
122
+ class: 'code-fence-container',
180
123
  },
181
- ['code', { spellCheck: 'false' }, 0],
124
+ select,
125
+ [
126
+ 'pre',
127
+ {
128
+ 'data-language': node.attrs['language'],
129
+ class: utils.getClassName(node.attrs, 'code-fence'),
130
+ },
131
+ ['code', { spellCheck: 'false' }, 0],
132
+ ],
182
133
  ];
183
134
  },
184
135
  parseMarkdown: {
@@ -218,103 +169,62 @@ export const codeFence = createNode<Keys, { languageList?: string[] }>((utils, o
218
169
  shortcuts: {
219
170
  [SupportedKeys.CodeFence]: createShortcut(TurnIntoCodeFence, 'Mod-Alt-c'),
220
171
  },
221
- view: (ctx) => (node, view, getPos) => {
222
- const container = document.createElement('div');
223
- const selectWrapper = document.createElement('div');
224
- const select = document.createElement('ul');
225
- const pre = document.createElement('pre');
226
- const code = document.createElement('code');
172
+ view: () => (node, view, getPos) => {
173
+ let currNode = node;
227
174
 
228
- const valueWrapper = document.createElement('div');
229
- valueWrapper.className = 'code-fence_value';
230
- const value = document.createElement('span');
231
- valueWrapper.appendChild(value);
232
- if (view.editable) {
233
- valueWrapper.appendChild(ctx.get(themeToolCtx).slots.icon('downArrow'));
234
- }
235
-
236
- select.className = 'code-fence_select';
237
- select.addEventListener('mousedown', (e) => {
238
- e.preventDefault();
239
- e.stopPropagation();
240
-
241
- if (!view.editable) return;
242
-
243
- const el = e.target;
244
- if (!(el instanceof HTMLLIElement)) return;
175
+ const onSelectLanguage = (language: string) => {
245
176
  const { tr } = view.state;
246
-
247
177
  view.dispatch(
248
178
  tr.setNodeMarkup(getPos(), undefined, {
249
179
  fold: true,
250
- language: el.dataset['value'],
180
+ language,
251
181
  }),
252
182
  );
253
- });
254
- valueWrapper.addEventListener('mousedown', (e) => {
255
- e.preventDefault();
256
- e.stopPropagation();
257
-
258
- if (!view.editable) return;
183
+ };
184
+ const onBlur = () => {
259
185
  const { tr } = view.state;
260
186
 
261
187
  view.dispatch(
262
188
  tr.setNodeMarkup(getPos(), undefined, {
263
- fold: false,
264
- language: container.dataset['language'],
189
+ ...currNode.attrs,
190
+ fold: true,
265
191
  }),
266
192
  );
267
- });
268
- document.addEventListener('mousedown', () => {
269
- if (!view.editable || select.dataset['fold'] === 'true') return;
270
-
193
+ };
194
+ const onFocus = () => {
271
195
  const { tr } = view.state;
272
196
 
273
197
  view.dispatch(
274
198
  tr.setNodeMarkup(getPos(), undefined, {
275
- fold: true,
276
- language: container.dataset['language'],
199
+ ...currNode.attrs,
200
+ fold: false,
277
201
  }),
278
202
  );
279
- });
203
+ };
280
204
 
281
- (options?.languageList || languageOptions).forEach((lang) => {
282
- const option = document.createElement('li');
283
- option.className = 'code-fence_select-option';
284
- option.innerText = lang || '--';
285
- select.appendChild(option);
286
- option.setAttribute('data-value', lang);
205
+ const renderer = utils.themeManager.get<ThemeCodeFenceType>('code-fence', {
206
+ onBlur,
207
+ onFocus,
208
+ onSelectLanguage,
209
+ editable: () => view.editable,
210
+ languageList,
287
211
  });
212
+ if (!renderer) return {};
288
213
 
289
- code.spellcheck = false;
290
- selectWrapper.className = 'code-fence_select-wrapper';
291
- selectWrapper.contentEditable = 'false';
292
- selectWrapper.append(valueWrapper);
293
- selectWrapper.append(select);
294
- pre.append(code);
295
- const codeContent = document.createElement('div');
296
- code.append(codeContent);
297
- codeContent.style.whiteSpace = 'inherit';
298
-
299
- container.append(selectWrapper, pre);
300
- container.setAttribute('class', utils.getClassName(node.attrs, 'code-fence', style));
301
- container.setAttribute('data-language', node.attrs['language']);
302
- value.innerText = node.attrs['language'] || '--';
303
- select.setAttribute('data-fold', node.attrs['fold'] ? 'true' : 'false');
214
+ const { dom, contentDOM, onUpdate, onDestroy } = renderer;
215
+ onUpdate(currNode);
304
216
 
305
217
  return {
306
- dom: container,
307
- contentDOM: codeContent,
218
+ dom,
219
+ contentDOM,
308
220
  update: (updatedNode) => {
309
221
  if (updatedNode.type.name !== id) return false;
310
-
311
- const lang = updatedNode.attrs['language'];
312
- container.dataset['language'] = lang;
313
- value.innerText = lang || '--';
314
- select.setAttribute('data-fold', updatedNode.attrs['fold'] ? 'true' : 'false');
222
+ currNode = updatedNode;
223
+ onUpdate(currNode);
315
224
 
316
225
  return true;
317
226
  },
227
+ destroy: onDestroy,
318
228
  };
319
229
  },
320
230
  };
@@ -32,42 +32,6 @@ export const headingPluginKey = new PluginKey('MILKDOWN_PLUGIN_ID');
32
32
  export const heading = createNode<Keys>((utils) => {
33
33
  const id = 'heading';
34
34
 
35
- const style = (level: number) =>
36
- utils.getStyle((_, { css }) => {
37
- const headingMap: Record<number, string> = {
38
- 1: css`
39
- font-size: 3rem;
40
- line-height: 3.5rem;
41
- `,
42
- 2: css`
43
- font-size: 2.5rem;
44
- line-height: 3rem;
45
- `,
46
- 3: css`
47
- font-size: 2.125rem;
48
- line-height: 2.25rem;
49
- `,
50
- 4: css`
51
- font-size: 1.75rem;
52
- line-height: 2rem;
53
- `,
54
- 5: css`
55
- font-size: 1.5rem;
56
- line-height: 1.5rem;
57
- `,
58
- 6: css`
59
- font-size: 1.25rem;
60
- line-height: 1.25rem;
61
- `,
62
- };
63
-
64
- return css`
65
- ${headingMap[level] || ''}
66
- margin: 2.5rem 0 !important;
67
- font-weight: 400;
68
- `;
69
- });
70
-
71
35
  return {
72
36
  id,
73
37
  schema: () => ({
@@ -96,11 +60,7 @@ export const heading = createNode<Keys>((utils) => {
96
60
  `h${node.attrs['level']}`,
97
61
  {
98
62
  id: node.attrs['id'] || node.textContent.split(' ').join('-').toLocaleLowerCase(),
99
- class: utils.getClassName(
100
- node.attrs,
101
- `heading h${node.attrs['level']}`,
102
- style(node.attrs['level']),
103
- ),
63
+ class: utils.getClassName(node.attrs, `heading h${node.attrs['level']}`),
104
64
  },
105
65
  0,
106
66
  ];
package/src/node/hr.ts CHANGED
@@ -6,19 +6,12 @@ import { createNode } from '@milkdown/utils';
6
6
  const id = 'hr';
7
7
  export const InsertHr = createCmdKey<string>('InsertHr');
8
8
  export const hr = createNode((utils) => {
9
- const style = utils.getStyle(
10
- (themeTool, { css }) => css`
11
- height: ${themeTool.size.lineWidth};
12
- background-color: ${themeTool.palette('line')};
13
- border-width: 0;
14
- `,
15
- );
16
9
  return {
17
10
  id,
18
11
  schema: () => ({
19
12
  group: 'block',
20
13
  parseDOM: [{ tag: 'hr' }],
21
- toDOM: (node) => ['hr', { class: utils.getClassName(node.attrs, id, style) }],
14
+ toDOM: (node) => ['hr', { class: utils.getClassName(node.attrs, id) }],
22
15
  parseMarkdown: {
23
16
  match: ({ type }) => type === 'thematicBreak',
24
17
  runner: (state, _, type) => {