@milkdown/preset-commonmark 5.3.4 → 5.5.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.
package/src/mark/link.ts CHANGED
@@ -3,8 +3,8 @@ import { createCmd, createCmdKey, schemaCtx } from '@milkdown/core';
3
3
  import { InputRule, Node as ProseNode, TextSelection, toggleMark } from '@milkdown/prose';
4
4
  import { createMark } from '@milkdown/utils';
5
5
 
6
- export const ToggleLink = createCmdKey<string>();
7
- export const ModifyLink = createCmdKey<string>();
6
+ export const ToggleLink = createCmdKey<string>('ToggleLink');
7
+ export const ModifyLink = createCmdKey<string>('ModifyLink');
8
8
  const id = 'link';
9
9
  export const link = createMark((utils) => {
10
10
  const style = utils.getStyle((themeTool, { css }) => {
@@ -44,8 +44,8 @@ export const link = createMark((utils) => {
44
44
  parseMarkdown: {
45
45
  match: (node) => node.type === 'link',
46
46
  runner: (state, node, markType) => {
47
- const url = node.url as string;
48
- const title = node.title as string;
47
+ const url = node['url'] as string;
48
+ const title = node['title'] as string;
49
49
  state.openMark(markType, { href: url, title });
50
50
  state.next(node.children);
51
51
  state.closeMark(markType);
@@ -55,8 +55,8 @@ export const link = createMark((utils) => {
55
55
  match: (mark) => mark.type.name === id,
56
56
  runner: (state, mark) => {
57
57
  state.withMark(mark, 'link', undefined, {
58
- title: mark.attrs.title,
59
- url: mark.attrs.href,
58
+ title: mark.attrs['title'],
59
+ url: mark.attrs['href'],
60
60
  });
61
61
  },
62
62
  },
@@ -7,7 +7,7 @@ import { SupportedKeys } from '../supported-keys';
7
7
 
8
8
  type Keys = SupportedKeys['Bold'];
9
9
  const id = 'strong';
10
- export const ToggleBold = createCmdKey();
10
+ export const ToggleBold = createCmdKey('ToggleBold');
11
11
  export const strong = createMark<Keys>((utils) => {
12
12
  const style = utils.getStyle(
13
13
  (_, { css }) =>
@@ -9,7 +9,7 @@ type Keys = SupportedKeys['Blockquote'];
9
9
 
10
10
  const id = 'blockquote';
11
11
 
12
- export const WrapInBlockquote = createCmdKey();
12
+ export const WrapInBlockquote = createCmdKey('WrapInBlockquote');
13
13
 
14
14
  export const blockquote = createNode<Keys>((utils) => {
15
15
  const style = utils.getStyle(
@@ -7,7 +7,7 @@ import { SupportedKeys } from '../supported-keys';
7
7
 
8
8
  type Keys = SupportedKeys['BulletList'];
9
9
 
10
- export const WrapInBulletList = createCmdKey();
10
+ export const WrapInBulletList = createCmdKey('WrapInBulletList');
11
11
 
12
12
  export const bulletList = createNode<Keys>((utils) => {
13
13
  const id = 'bullet_list';
@@ -29,7 +29,7 @@ const languageOptions = [
29
29
  export const backtickInputRegex = /^```(?<language>[a-z]*)?[\s\n]$/;
30
30
  export const tildeInputRegex = /^~~~(?<language>[a-z]*)?[\s\n]$/;
31
31
 
32
- export const TurnIntoCodeFence = createCmdKey();
32
+ export const TurnIntoCodeFence = createCmdKey('TurnIntoCodeFence');
33
33
 
34
34
  const id = 'fence';
35
35
  export const codeFence = createNode<Keys, { languageList?: string[] }>((utils, options) => {
@@ -136,6 +136,9 @@ export const codeFence = createNode<Keys, { languageList?: string[] }>((utils, o
136
136
  pre {
137
137
  font-family: ${font.code};
138
138
  margin: 0 1.2rem !important;
139
+ white-space: pre;
140
+ overflow: auto;
141
+ ${scrollbar('x')};
139
142
  }
140
143
  `;
141
144
  });
@@ -164,7 +167,7 @@ export const codeFence = createNode<Keys, { languageList?: string[] }>((utils, o
164
167
  if (!(dom instanceof HTMLElement)) {
165
168
  throw new Error('Parse DOM error.');
166
169
  }
167
- return { language: dom.dataset.language };
170
+ return { language: dom.dataset['language'] };
168
171
  },
169
172
  },
170
173
  ],
@@ -172,7 +175,7 @@ export const codeFence = createNode<Keys, { languageList?: string[] }>((utils, o
172
175
  return [
173
176
  'pre',
174
177
  {
175
- 'data-language': node.attrs.language,
178
+ 'data-language': node.attrs['language'],
176
179
  class: utils.getClassName(node.attrs, 'code-fence', style),
177
180
  },
178
181
  ['code', { spellCheck: 'false' }, 0],
@@ -181,8 +184,8 @@ export const codeFence = createNode<Keys, { languageList?: string[] }>((utils, o
181
184
  parseMarkdown: {
182
185
  match: ({ type }) => type === 'code',
183
186
  runner: (state, node, type) => {
184
- const language = node.lang as string;
185
- const value = node.value as string;
187
+ const language = node['lang'] as string;
188
+ const value = node['value'] as string;
186
189
  state.openNode(type, { language });
187
190
  if (value) {
188
191
  state.addText(value);
@@ -194,7 +197,7 @@ export const codeFence = createNode<Keys, { languageList?: string[] }>((utils, o
194
197
  match: (node) => node.type.name === id,
195
198
  runner: (state, node) => {
196
199
  state.addNode('code', undefined, node.content.firstChild?.text || '', {
197
- lang: node.attrs.language,
200
+ lang: node.attrs['language'],
198
201
  });
199
202
  },
200
203
  },
@@ -244,7 +247,7 @@ export const codeFence = createNode<Keys, { languageList?: string[] }>((utils, o
244
247
  view.dispatch(
245
248
  tr.setNodeMarkup(getPos(), undefined, {
246
249
  fold: true,
247
- language: el.dataset.value,
250
+ language: el.dataset['value'],
248
251
  }),
249
252
  );
250
253
  });
@@ -258,19 +261,19 @@ export const codeFence = createNode<Keys, { languageList?: string[] }>((utils, o
258
261
  view.dispatch(
259
262
  tr.setNodeMarkup(getPos(), undefined, {
260
263
  fold: false,
261
- language: container.dataset.language,
264
+ language: container.dataset['language'],
262
265
  }),
263
266
  );
264
267
  });
265
268
  document.addEventListener('mousedown', () => {
266
- if (!view.editable || select.dataset.fold === 'true') return;
269
+ if (!view.editable || select.dataset['fold'] === 'true') return;
267
270
 
268
271
  const { tr } = view.state;
269
272
 
270
273
  view.dispatch(
271
274
  tr.setNodeMarkup(getPos(), undefined, {
272
275
  fold: true,
273
- language: container.dataset.language,
276
+ language: container.dataset['language'],
274
277
  }),
275
278
  );
276
279
  });
@@ -295,9 +298,9 @@ export const codeFence = createNode<Keys, { languageList?: string[] }>((utils, o
295
298
 
296
299
  container.append(selectWrapper, pre);
297
300
  container.setAttribute('class', utils.getClassName(node.attrs, 'code-fence', style));
298
- container.setAttribute('data-language', node.attrs.language);
299
- value.innerText = node.attrs.language || '--';
300
- select.setAttribute('data-fold', node.attrs.fold ? 'true' : 'false');
301
+ container.setAttribute('data-language', node.attrs['language']);
302
+ value.innerText = node.attrs['language'] || '--';
303
+ select.setAttribute('data-fold', node.attrs['fold'] ? 'true' : 'false');
301
304
 
302
305
  return {
303
306
  dom: container,
@@ -305,10 +308,10 @@ export const codeFence = createNode<Keys, { languageList?: string[] }>((utils, o
305
308
  update: (updatedNode) => {
306
309
  if (updatedNode.type.name !== id) return false;
307
310
 
308
- const lang = updatedNode.attrs.language;
309
- container.dataset.language = lang;
311
+ const lang = updatedNode.attrs['language'];
312
+ container.dataset['language'] = lang;
310
313
  value.innerText = lang || '--';
311
- select.setAttribute('data-fold', updatedNode.attrs.fold ? 'true' : 'false');
314
+ select.setAttribute('data-fold', updatedNode.attrs['fold'] ? 'true' : 'false');
312
315
 
313
316
  return true;
314
317
  },
@@ -7,7 +7,7 @@ import { SupportedKeys } from '../supported-keys';
7
7
 
8
8
  type Keys = SupportedKeys['HardBreak'];
9
9
 
10
- export const InsertHardbreak = createCmdKey();
10
+ export const InsertHardbreak = createCmdKey('InsertHardbreak');
11
11
 
12
12
  export const hardbreak = createNode<Keys>((utils) => {
13
13
  return {
@@ -42,10 +42,11 @@ export const hardbreak = createNode<Keys>((utils) => {
42
42
  },
43
43
  prosePlugins: (type) => [
44
44
  new Plugin({
45
- key: new PluginKey('hardbreak-marks'),
45
+ key: new PluginKey('MILKDOWN_PLUGIN_HARDBREAK_MARKS'),
46
46
  appendTransaction: (trs, _oldState, newState) => {
47
47
  if (!trs.length) return;
48
48
  const [tr] = trs;
49
+ if (!tr) return;
49
50
 
50
51
  const [step] = tr.steps;
51
52
 
@@ -1,6 +1,14 @@
1
1
  /* Copyright 2021, Milkdown by Mirone. */
2
- import { createCmd, createCmdKey } from '@milkdown/core';
3
- import { Plugin, PluginKey, setBlockType, textblockTypeInputRule } from '@milkdown/prose';
2
+ import { createCmd, createCmdKey, editorViewCtx } from '@milkdown/core';
3
+ import {
4
+ EditorState,
5
+ Node,
6
+ Plugin,
7
+ PluginKey,
8
+ setBlockType,
9
+ textblockTypeInputRule,
10
+ Transaction,
11
+ } from '@milkdown/prose';
4
12
  import { createNode, createShortcut } from '@milkdown/utils';
5
13
 
6
14
  import { SupportedKeys } from '../supported-keys';
@@ -17,7 +25,7 @@ type Keys =
17
25
  | SupportedKeys['H5']
18
26
  | SupportedKeys['H6'];
19
27
 
20
- export const TurnIntoHeading = createCmdKey<number>();
28
+ export const TurnIntoHeading = createCmdKey<number>('TurnIntoHeading');
21
29
 
22
30
  export const headingPluginKey = new PluginKey('MILKDOWN_PLUGIN_ID');
23
31
 
@@ -85,10 +93,14 @@ export const heading = createNode<Keys>((utils) => {
85
93
  })),
86
94
  toDOM: (node) => {
87
95
  return [
88
- `h${node.attrs.level}`,
96
+ `h${node.attrs['level']}`,
89
97
  {
90
- id: node.attrs.id || node.textContent.split(' ').join('-').toLocaleLowerCase(),
91
- class: utils.getClassName(node.attrs, `heading h${node.attrs.level}`, style(node.attrs.level)),
98
+ 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
+ ),
92
104
  },
93
105
  0,
94
106
  ];
@@ -96,7 +108,7 @@ export const heading = createNode<Keys>((utils) => {
96
108
  parseMarkdown: {
97
109
  match: ({ type }) => type === id,
98
110
  runner: (state, node, type) => {
99
- const depth = node.depth as number;
111
+ const depth = node['depth'] as number;
100
112
  state.openNode(type, { level: depth });
101
113
  state.next(node.children);
102
114
  state.closeNode();
@@ -105,7 +117,7 @@ export const heading = createNode<Keys>((utils) => {
105
117
  toMarkdown: {
106
118
  match: (node) => node.type.name === id,
107
119
  runner: (state, node) => {
108
- state.openNode('heading', undefined, { depth: node.attrs.level });
120
+ state.openNode('heading', undefined, { depth: node.attrs['level'] });
109
121
  state.next(node.content);
110
122
  state.closeNode();
111
123
  },
@@ -126,28 +138,69 @@ export const heading = createNode<Keys>((utils) => {
126
138
  [SupportedKeys.H5]: createShortcut(TurnIntoHeading, 'Mod-Alt-5', 5),
127
139
  [SupportedKeys.H6]: createShortcut(TurnIntoHeading, 'Mod-Alt-6', 6),
128
140
  },
129
- prosePlugins: (type) => [
130
- new Plugin({
131
- key: headingPluginKey,
132
- appendTransaction: (transactions, _, nextState) => {
133
- const tr = nextState.tr;
134
- let modified = false;
135
- if (transactions.some((transaction) => transaction.docChanged)) {
136
- nextState.doc.descendants((node, pos) => {
137
- if (node.type === type) {
138
- const attrs = node.attrs;
139
- tr.setNodeMarkup(pos, undefined, {
140
- ...attrs,
141
- id: node.textContent.split(' ').join('-').toLocaleLowerCase(),
142
- });
143
- modified = true;
144
- }
145
- });
141
+ prosePlugins: (type, ctx) => {
142
+ let lock = false;
143
+ const createId = (node: Node) => {
144
+ return node.textContent
145
+ .replace(/[\p{P}\p{S}]/gu, '')
146
+ .replace(/\s/g, '')
147
+ .trim();
148
+ };
149
+ const walkThrough = (state: EditorState, callback: (tr: Transaction) => void) => {
150
+ const tr = state.tr;
151
+ state.doc.descendants((node, pos) => {
152
+ if (node.type === type && !lock) {
153
+ if (node.textContent.trim().length === 0) {
154
+ return;
155
+ }
156
+ const attrs = node.attrs;
157
+ const id = createId(node);
158
+
159
+ if (attrs['id'] !== id) {
160
+ tr.setMeta(headingPluginKey, true).setNodeMarkup(pos, undefined, {
161
+ ...attrs,
162
+ id,
163
+ });
164
+ }
146
165
  }
166
+ });
167
+ callback(tr);
168
+ };
169
+ return [
170
+ new Plugin({
171
+ key: headingPluginKey,
172
+ props: {
173
+ handleDOMEvents: {
174
+ compositionstart: () => {
175
+ lock = true;
176
+ return false;
177
+ },
178
+ compositionend: () => {
179
+ lock = false;
180
+ const view = ctx.get(editorViewCtx);
181
+ setTimeout(() => {
182
+ walkThrough(view.state, (tr) => view.dispatch(tr));
183
+ }, 0);
184
+ return false;
185
+ },
186
+ },
187
+ },
188
+ appendTransaction: (transactions, _, nextState) => {
189
+ let tr: Transaction | null = null;
147
190
 
148
- return modified ? tr : null;
149
- },
150
- }),
151
- ],
191
+ if (
192
+ transactions.every((transaction) => !transaction.getMeta(headingPluginKey)) &&
193
+ transactions.some((transaction) => transaction.docChanged)
194
+ ) {
195
+ walkThrough(nextState, (t) => {
196
+ tr = t;
197
+ });
198
+ }
199
+
200
+ return tr;
201
+ },
202
+ }),
203
+ ];
204
+ },
152
205
  };
153
206
  });
package/src/node/hr.ts CHANGED
@@ -4,7 +4,7 @@ import { InputRule, Selection } from '@milkdown/prose';
4
4
  import { createNode } from '@milkdown/utils';
5
5
 
6
6
  const id = 'hr';
7
- export const InsertHr = createCmdKey<string>();
7
+ export const InsertHr = createCmdKey<string>('InsertHr');
8
8
  export const hr = createNode((utils) => {
9
9
  const style = utils.getStyle(
10
10
  (themeTool, { css }) => css`
package/src/node/image.ts CHANGED
@@ -4,8 +4,8 @@ import type { Icon } from '@milkdown/design-system';
4
4
  import { findSelectedNodeOfType, InputRule } from '@milkdown/prose';
5
5
  import { createNode } from '@milkdown/utils';
6
6
 
7
- export const ModifyImage = createCmdKey<string>();
8
- export const InsertImage = createCmdKey<string>();
7
+ export const ModifyImage = createCmdKey<string>('ModifyImage');
8
+ export const InsertImage = createCmdKey<string>('InsertImage');
9
9
  const id = 'image';
10
10
  export type ImageOptions = {
11
11
  isBlock: boolean;
@@ -180,8 +180,8 @@ export const image = createNode<string, ImageOptions>((utils, options) => {
180
180
  class: utils.getClassName(
181
181
  node.attrs,
182
182
  id,
183
- node.attrs.failed ? 'failed' : '',
184
- node.attrs.loading ? 'loading' : '',
183
+ node.attrs['failed'] ? 'failed' : '',
184
+ node.attrs['loading'] ? 'loading' : '',
185
185
  style,
186
186
  ),
187
187
  },
@@ -190,9 +190,9 @@ export const image = createNode<string, ImageOptions>((utils, options) => {
190
190
  parseMarkdown: {
191
191
  match: ({ type }) => type === id,
192
192
  runner: (state, node, type) => {
193
- const url = node.url as string;
194
- const alt = node.alt as string;
195
- const title = node.title as string;
193
+ const url = node['url'] as string;
194
+ const alt = node['alt'] as string;
195
+ const title = node['title'] as string;
196
196
  state.addNode(type, {
197
197
  src: url,
198
198
  alt,
@@ -204,9 +204,9 @@ export const image = createNode<string, ImageOptions>((utils, options) => {
204
204
  match: (node) => node.type.name === id,
205
205
  runner: (state, node) => {
206
206
  state.addNode('image', undefined, undefined, {
207
- title: node.attrs.title,
208
- url: node.attrs.src,
209
- alt: node.attrs.alt,
207
+ title: node.attrs['title'],
208
+ url: node.attrs['src'],
209
+ alt: node.attrs['alt'],
210
210
  });
211
211
  },
212
212
  },
@@ -9,9 +9,9 @@ type Keys = SupportedKeys['SinkListItem'] | SupportedKeys['LiftListItem'] | Supp
9
9
 
10
10
  const id = 'list_item';
11
11
 
12
- export const SplitListItem = createCmdKey();
13
- export const SinkListItem = createCmdKey();
14
- export const LiftListItem = createCmdKey();
12
+ export const SplitListItem = createCmdKey('SplitListItem');
13
+ export const SinkListItem = createCmdKey('SinkListItem');
14
+ export const LiftListItem = createCmdKey('LiftListItem');
15
15
 
16
16
  export const listItem = createNode<Keys>((utils) => {
17
17
  const style = utils.getStyle(
@@ -7,7 +7,7 @@ import { SupportedKeys } from '../supported-keys';
7
7
 
8
8
  type Keys = SupportedKeys['OrderedList'];
9
9
 
10
- export const WrapInOrderedList = createCmdKey();
10
+ export const WrapInOrderedList = createCmdKey('WrapInOrderedList');
11
11
 
12
12
  const id = 'ordered_list';
13
13
  export const orderedList = createNode<Keys>((utils) => ({
@@ -34,7 +34,7 @@ export const orderedList = createNode<Keys>((utils) => ({
34
34
  toDOM: (node) => [
35
35
  'ol',
36
36
  {
37
- ...(node.attrs.order === 1 ? {} : node.attrs.order),
37
+ ...(node.attrs['order'] === 1 ? {} : node.attrs['order']),
38
38
  class: utils.getClassName(node.attrs, 'ordered-list'),
39
39
  },
40
40
  0,
@@ -59,7 +59,7 @@ export const orderedList = createNode<Keys>((utils) => ({
59
59
  /^(\d+)\.\s$/,
60
60
  nodeType,
61
61
  (match) => ({ order: Number(match[1]) }),
62
- (match, node) => node.childCount + node.attrs.order === Number(match[1]),
62
+ (match, node) => node.childCount + node.attrs['order'] === Number(match[1]),
63
63
  ),
64
64
  ],
65
65
  commands: (nodeType) => [createCmd(WrapInOrderedList, () => wrapIn(nodeType))],
@@ -7,7 +7,7 @@ import { SupportedKeys } from '../supported-keys';
7
7
 
8
8
  type Keys = SupportedKeys['Text'];
9
9
 
10
- export const TurnIntoText = createCmdKey();
10
+ export const TurnIntoText = createCmdKey('TurnIntoText');
11
11
 
12
12
  const id = 'paragraph';
13
13
  export const paragraph = createNode<Keys>((utils) => {
@@ -33,7 +33,7 @@ export const paragraph = createNode<Keys>((utils) => {
33
33
  if (node.children) {
34
34
  state.next(node.children);
35
35
  } else {
36
- state.addText(node.value as string);
36
+ state.addText(node['value'] as string);
37
37
  }
38
38
  state.closeNode();
39
39
  },
package/src/node/text.ts CHANGED
@@ -8,7 +8,7 @@ export const text = createNode(() => ({
8
8
  parseMarkdown: {
9
9
  match: ({ type }) => type === 'text',
10
10
  runner: (state, node) => {
11
- state.addText(node.value as string);
11
+ state.addText(node['value'] as string);
12
12
  },
13
13
  },
14
14
  toMarkdown: {
@@ -11,10 +11,16 @@ function flatMapWithDepth(ast: Node, fn: (node: Node, index: number, parent: Nod
11
11
  if (isParent(node)) {
12
12
  const out = [];
13
13
  for (let i = 0, n = node.children.length; i < n; i++) {
14
- const xs = transform(node.children[i], i, node);
15
- if (xs) {
16
- for (let j = 0, m = xs.length; j < m; j++) {
17
- out.push(xs[j]);
14
+ const nthChild = node.children[i];
15
+ if (nthChild) {
16
+ const xs = transform(nthChild, i, node);
17
+ if (xs) {
18
+ for (let j = 0, m = xs.length; j < m; j++) {
19
+ const item = xs[j];
20
+ if (item) {
21
+ out.push(item);
22
+ }
23
+ }
18
24
  }
19
25
  }
20
26
  }