@milkdown/preset-gfm 5.3.0 → 5.3.4

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 (66) hide show
  1. package/lib/index.d.ts +1 -36
  2. package/lib/index.es.js +768 -17
  3. package/lib/index.es.js.map +1 -1
  4. package/lib/src/auto-link.d.ts +2 -0
  5. package/lib/src/auto-link.d.ts.map +1 -0
  6. package/lib/src/index.d.ts +36 -0
  7. package/lib/src/index.d.ts.map +1 -0
  8. package/lib/{strike-through.d.ts → src/strike-through.d.ts} +1 -1
  9. package/lib/src/strike-through.d.ts.map +1 -0
  10. package/lib/{supported-keys.d.ts → src/supported-keys.d.ts} +0 -0
  11. package/lib/src/supported-keys.d.ts.map +1 -0
  12. package/lib/src/table/command.d.ts +3 -0
  13. package/lib/src/table/command.d.ts.map +1 -0
  14. package/lib/src/table/index.d.ts +10 -0
  15. package/lib/src/table/index.d.ts.map +1 -0
  16. package/lib/src/table/nodes/index.d.ts +32 -0
  17. package/lib/src/table/nodes/index.d.ts.map +1 -0
  18. package/lib/src/table/nodes/schema.d.ts +2 -0
  19. package/lib/src/table/nodes/schema.d.ts.map +1 -0
  20. package/lib/src/table/nodes/style.d.ts +3 -0
  21. package/lib/src/table/nodes/style.d.ts.map +1 -0
  22. package/lib/src/table/operator-plugin/actions.d.ts +19 -0
  23. package/lib/src/table/operator-plugin/actions.d.ts.map +1 -0
  24. package/lib/src/table/operator-plugin/calc-pos.d.ts +3 -0
  25. package/lib/src/table/operator-plugin/calc-pos.d.ts.map +1 -0
  26. package/lib/src/table/operator-plugin/constant.d.ts +6 -0
  27. package/lib/src/table/operator-plugin/constant.d.ts.map +1 -0
  28. package/lib/src/table/operator-plugin/helper.d.ts +6 -0
  29. package/lib/src/table/operator-plugin/helper.d.ts.map +1 -0
  30. package/lib/src/table/operator-plugin/index.d.ts +6 -0
  31. package/lib/src/table/operator-plugin/index.d.ts.map +1 -0
  32. package/lib/src/table/operator-plugin/style.d.ts +3 -0
  33. package/lib/src/table/operator-plugin/style.d.ts.map +1 -0
  34. package/lib/src/table/operator-plugin/widget.d.ts +8 -0
  35. package/lib/src/table/operator-plugin/widget.d.ts.map +1 -0
  36. package/lib/src/table/utils.d.ts +19 -0
  37. package/lib/src/table/utils.d.ts.map +1 -0
  38. package/lib/{task-list-item.d.ts → src/task-list-item.d.ts} +1 -1
  39. package/lib/src/task-list-item.d.ts.map +1 -0
  40. package/package.json +12 -26
  41. package/src/auto-link.ts +4 -9
  42. package/src/index.ts +13 -6
  43. package/src/strike-through.ts +1 -2
  44. package/src/supported-keys.ts +2 -1
  45. package/src/table/command.ts +16 -0
  46. package/src/table/index.ts +13 -0
  47. package/src/table/nodes/index.ts +169 -0
  48. package/src/table/nodes/schema.ts +16 -0
  49. package/src/table/nodes/style.ts +170 -0
  50. package/src/table/operator-plugin/actions.ts +115 -0
  51. package/src/table/operator-plugin/calc-pos.ts +25 -0
  52. package/src/table/operator-plugin/constant.ts +7 -0
  53. package/src/table/operator-plugin/helper.ts +38 -0
  54. package/src/table/operator-plugin/index.ts +98 -0
  55. package/src/table/operator-plugin/style.ts +50 -0
  56. package/src/table/operator-plugin/widget.ts +66 -0
  57. package/src/table/utils.ts +158 -0
  58. package/src/task-list-item.ts +3 -3
  59. package/lib/auto-link.d.ts +0 -16
  60. package/lib/auto-link.d.ts.map +0 -1
  61. package/lib/index.cjs.js +0 -49
  62. package/lib/index.cjs.js.map +0 -1
  63. package/lib/index.d.ts.map +0 -1
  64. package/lib/strike-through.d.ts.map +0 -1
  65. package/lib/supported-keys.d.ts.map +0 -1
  66. package/lib/task-list-item.d.ts.map +0 -1
package/src/index.ts CHANGED
@@ -1,10 +1,11 @@
1
1
  /* Copyright 2021, Milkdown by Mirone. */
2
- import { tablePlugin } from '@milkdown/plugin-table';
3
2
  import { commands as commonmarkCommands, commonmark } from '@milkdown/preset-commonmark';
4
- import { AtomList } from '@milkdown/utils';
3
+ import { $remark, AtomList } from '@milkdown/utils';
4
+ import remarkGFM from 'remark-gfm';
5
5
 
6
6
  import { urlPlugin } from './auto-link';
7
7
  import { strikeThrough, ToggleStrikeThrough } from './strike-through';
8
+ import { table } from './table';
8
9
  import {
9
10
  LiftTaskListItem,
10
11
  SinkTaskListItem,
@@ -15,7 +16,6 @@ import {
15
16
 
16
17
  export * from './strike-through';
17
18
  export { SupportedKeys } from './supported-keys';
18
- export * from './task-list-item';
19
19
  export {
20
20
  BreakTable,
21
21
  // command
@@ -25,8 +25,8 @@ export {
25
25
  PrevCell,
26
26
  // gather
27
27
  table,
28
- tablePlugin,
29
- } from '@milkdown/plugin-table';
28
+ } from './table';
29
+ export * from './task-list-item';
30
30
  export {
31
31
  blockquote,
32
32
  bulletList,
@@ -70,7 +70,14 @@ export {
70
70
  WrapInOrderedList,
71
71
  } from '@milkdown/preset-commonmark';
72
72
 
73
- export const gfm = AtomList.create([...commonmark, tablePlugin(), urlPlugin(), strikeThrough(), taskListItem()]);
73
+ export const gfm = AtomList.create([
74
+ ...commonmark,
75
+ $remark(() => remarkGFM),
76
+ table(),
77
+ urlPlugin,
78
+ strikeThrough(),
79
+ taskListItem(),
80
+ ]);
74
81
 
75
82
  export const commands = {
76
83
  ...commonmarkCommands,
@@ -1,5 +1,4 @@
1
1
  /* Copyright 2021, Milkdown by Mirone. */
2
- import { css } from '@emotion/css';
3
2
  import { createCmd, createCmdKey } from '@milkdown/core';
4
3
  import { markRule, toggleMark } from '@milkdown/prose';
5
4
  import { createMark, createShortcut } from '@milkdown/utils';
@@ -13,7 +12,7 @@ export const ToggleStrikeThrough = createCmdKey();
13
12
  export const strikeThrough = createMark<Keys>((utils) => {
14
13
  const id = 'strike_through';
15
14
  const style = utils.getStyle(
16
- (themeTool) =>
15
+ (themeTool, { css }) =>
17
16
  css`
18
17
  text-decoration-color: ${themeTool.palette('secondary')};
19
18
  `,
@@ -1,7 +1,8 @@
1
1
  /* Copyright 2021, Milkdown by Mirone. */
2
- import { SupportedKeys as TableKeys } from '@milkdown/plugin-table';
3
2
  import { SupportedKeys as CommonmarkKeys } from '@milkdown/preset-commonmark';
4
3
 
4
+ import { SupportedKeys as TableKeys } from './table';
5
+
5
6
  export const SupportedKeys = {
6
7
  ...CommonmarkKeys,
7
8
  ...TableKeys,
@@ -0,0 +1,16 @@
1
+ /* Copyright 2021, Milkdown by Mirone. */
2
+ import { Command, isInTable, Node, NodeType, Selection } from '@milkdown/prose';
3
+
4
+ export const exitTable =
5
+ (node: NodeType): Command =>
6
+ (state, dispatch) => {
7
+ if (!isInTable(state)) {
8
+ return false;
9
+ }
10
+ const { $head } = state.selection;
11
+ const pos = $head.after();
12
+ const tr = state.tr.replaceWith(pos, pos, node.createAndFill() as Node);
13
+ tr.setSelection(Selection.near(tr.doc.resolve(pos), 1));
14
+ dispatch?.(tr.scrollIntoView());
15
+ return true;
16
+ };
@@ -0,0 +1,13 @@
1
+ /* Copyright 2021, Milkdown by Mirone. */
2
+ import { BreakTable, InsertTable, NextCell, PrevCell } from './nodes';
3
+
4
+ export { BreakTable, InsertTable, NextCell, PrevCell, SupportedKeys, table } from './nodes';
5
+ export { createTable } from './utils';
6
+
7
+ export const commands = {
8
+ NextCell,
9
+ PrevCell,
10
+ BreakTable,
11
+ InsertTable,
12
+ } as const;
13
+ export type Commands = typeof commands;
@@ -0,0 +1,169 @@
1
+ /* Copyright 2021, Milkdown by Mirone. */
2
+ import { createCmd, createCmdKey, MarkdownNode, schemaCtx } from '@milkdown/core';
3
+ import { columnResizing, goToNextCell, InputRule, Selection, tableEditing, TextSelection } from '@milkdown/prose';
4
+ import { createPlugin, createShortcut } from '@milkdown/utils';
5
+
6
+ import { exitTable } from '../command';
7
+ import { operatorPlugin } from '../operator-plugin';
8
+ import { createTable } from '../utils';
9
+ import { schema } from './schema';
10
+ import { injectStyle } from './style';
11
+
12
+ export const SupportedKeys = {
13
+ NextCell: 'NextCell',
14
+ PrevCell: 'PrevCell',
15
+ ExitTable: 'ExitTable',
16
+ } as const;
17
+ export type SupportedKeys = typeof SupportedKeys;
18
+
19
+ type Keys = keyof SupportedKeys;
20
+
21
+ export const PrevCell = createCmdKey();
22
+ export const NextCell = createCmdKey();
23
+ export const BreakTable = createCmdKey();
24
+ export const InsertTable = createCmdKey();
25
+
26
+ export const table = createPlugin<Keys, Record<string, unknown>, keyof typeof schema>((utils) => {
27
+ injectStyle(utils);
28
+ return {
29
+ schema: () => ({
30
+ node: {
31
+ table: {
32
+ ...schema.table,
33
+ parseMarkdown: {
34
+ match: (node) => node.type === 'table',
35
+ runner: (state, node, type) => {
36
+ const align = node.align as (string | null)[];
37
+ const children = (node.children as MarkdownNode[]).map((x, i) => ({
38
+ ...x,
39
+ align,
40
+ isHeader: i === 0,
41
+ }));
42
+ state.openNode(type);
43
+ state.next(children);
44
+ state.closeNode();
45
+ },
46
+ },
47
+ toMarkdown: {
48
+ match: (node) => node.type.name === 'table',
49
+ runner: (state, node) => {
50
+ const firstLine = node.content.firstChild?.content;
51
+ if (!firstLine) return;
52
+
53
+ const align: (string | null)[] = [];
54
+ firstLine.forEach((cell) => {
55
+ align.push(cell.attrs.alignment);
56
+ });
57
+ state.openNode('table', undefined, { align });
58
+ state.next(node.content);
59
+ state.closeNode();
60
+ },
61
+ },
62
+ },
63
+ table_row: {
64
+ ...schema.table_row,
65
+ parseMarkdown: {
66
+ match: (node) => node.type === 'tableRow',
67
+ runner: (state, node, type) => {
68
+ const align = node.align as (string | null)[];
69
+ const children = (node.children as MarkdownNode[]).map((x, i) => ({
70
+ ...x,
71
+ align: align[i],
72
+ isHeader: node.isHeader,
73
+ }));
74
+ state.openNode(type);
75
+ state.next(children);
76
+ state.closeNode();
77
+ },
78
+ },
79
+ toMarkdown: {
80
+ match: (node) => node.type.name === 'table_row',
81
+ runner: (state, node) => {
82
+ state.openNode('tableRow');
83
+ state.next(node.content);
84
+ state.closeNode();
85
+ },
86
+ },
87
+ },
88
+ table_cell: {
89
+ ...schema.table_cell,
90
+ parseMarkdown: {
91
+ match: (node) => node.type === 'tableCell' && !node.isHeader,
92
+ runner: (state, node, type) => {
93
+ const align = node.align as string;
94
+ state
95
+ .openNode(type, { alignment: align })
96
+ .openNode(state.schema.nodes.paragraph)
97
+ .next(node.children)
98
+ .closeNode()
99
+ .closeNode();
100
+ },
101
+ },
102
+ toMarkdown: {
103
+ match: (node) => node.type.name === 'table_cell',
104
+ runner: (state, node) => {
105
+ state.openNode('tableCell').next(node.content).closeNode();
106
+ },
107
+ },
108
+ },
109
+ table_header: {
110
+ ...schema.table_header,
111
+ parseMarkdown: {
112
+ match: (node) => node.type === 'tableCell' && !!node.isHeader,
113
+ runner: (state, node, type) => {
114
+ const align = node.align as string;
115
+ state.openNode(type, { alignment: align });
116
+ state.openNode(state.schema.nodes.paragraph);
117
+ state.next(node.children);
118
+ state.closeNode();
119
+ state.closeNode();
120
+ },
121
+ },
122
+ toMarkdown: {
123
+ match: (node) => node.type.name === 'table_header',
124
+ runner: (state, node) => {
125
+ state.openNode('tableCell');
126
+ state.next(node.content);
127
+ state.closeNode();
128
+ },
129
+ },
130
+ },
131
+ },
132
+ }),
133
+ inputRules: (nodeType, ctx) => [
134
+ new InputRule(/^\|\|\s$/, (state, _match, start, end) => {
135
+ const $start = state.doc.resolve(start);
136
+ if (!$start.node(-1).canReplaceWith($start.index(-1), $start.indexAfter(-1), nodeType.table))
137
+ return null;
138
+
139
+ const tableNode = createTable(ctx.get(schemaCtx));
140
+ const tr = state.tr.replaceRangeWith(start, end, tableNode).scrollIntoView();
141
+ return tr.setSelection(TextSelection.create(tr.doc, start + 3));
142
+ }),
143
+ ],
144
+ commands: (_, ctx) => [
145
+ createCmd(PrevCell, () => goToNextCell(-1)),
146
+ createCmd(NextCell, () => goToNextCell(1)),
147
+ createCmd(BreakTable, () => exitTable(ctx.get(schemaCtx).nodes.paragraph)),
148
+ createCmd(InsertTable, () => (state, dispatch) => {
149
+ const { selection, tr } = state;
150
+ const { from } = selection;
151
+ const table = createTable(ctx.get(schemaCtx));
152
+ const _tr = tr.replaceSelectionWith(table);
153
+ const sel = Selection.findFrom(_tr.doc.resolve(from), 1, true);
154
+ if (sel) {
155
+ dispatch?.(_tr.setSelection(sel));
156
+ }
157
+ return true;
158
+ }),
159
+ ],
160
+ shortcuts: {
161
+ [SupportedKeys.NextCell]: createShortcut(NextCell, 'Mod-]'),
162
+ [SupportedKeys.PrevCell]: createShortcut(PrevCell, 'Mod-['),
163
+ [SupportedKeys.ExitTable]: createShortcut(BreakTable, 'Mod-Enter'),
164
+ },
165
+ prosePlugins: (_, ctx) => {
166
+ return [operatorPlugin(ctx, utils), columnResizing({}), tableEditing()];
167
+ },
168
+ };
169
+ });
@@ -0,0 +1,16 @@
1
+ /* Copyright 2021, Milkdown by Mirone. */
2
+ import { tableNodes as tableNodesSpecCreator } from '@milkdown/prose';
3
+
4
+ export const schema = tableNodesSpecCreator({
5
+ tableGroup: 'block',
6
+ cellContent: 'paragraph',
7
+ cellAttributes: {
8
+ alignment: {
9
+ default: 'left',
10
+ getFromDOM: (dom) => (dom as HTMLElement).style.textAlign || 'left',
11
+ setDOMAttr: (value, attrs) => {
12
+ attrs.style = `text-align: ${value || 'left'}`;
13
+ },
14
+ },
15
+ },
16
+ });
@@ -0,0 +1,170 @@
1
+ /* Copyright 2021, Milkdown by Mirone. */
2
+ import { Emotion } from '@milkdown/design-system';
3
+ import { Utils } from '@milkdown/utils';
4
+
5
+ const proseTableStyle = ({ css }: Emotion) => css`
6
+ /* copy from https://github.com/ProseMirror/prosemirror-tables/blob/master/style/tables.css */
7
+ .ProseMirror .tableWrapper {
8
+ overflow-x: auto;
9
+ }
10
+ .ProseMirror table {
11
+ border-collapse: collapse;
12
+ table-layout: fixed;
13
+ width: 100%;
14
+ overflow: hidden;
15
+ }
16
+ .ProseMirror td,
17
+ .ProseMirror th {
18
+ vertical-align: top;
19
+ box-sizing: border-box;
20
+ position: relative;
21
+ }
22
+ .ProseMirror .column-resize-handle {
23
+ position: absolute;
24
+ right: -2px;
25
+ top: 0;
26
+ bottom: 0;
27
+ width: 4px;
28
+ z-index: 20;
29
+ background-color: #adf;
30
+ pointer-events: none;
31
+ }
32
+ .ProseMirror.resize-cursor {
33
+ cursor: ew-resize;
34
+ cursor: col-resize;
35
+ }
36
+ /* Give selected cells a blue overlay */
37
+ .ProseMirror .selectedCell:after {
38
+ z-index: 2;
39
+ position: absolute;
40
+ content: '';
41
+ left: 0;
42
+ right: 0;
43
+ top: 0;
44
+ bottom: 0;
45
+ background: rgba(200, 200, 255, 0.4);
46
+ pointer-events: none;
47
+ }
48
+ `;
49
+
50
+ export const injectStyle = (utils: Utils) => {
51
+ return utils.getStyle(({ size, palette, mixin }, emotion) => {
52
+ const css = emotion.injectGlobal;
53
+ css`
54
+ ${proseTableStyle(emotion)}
55
+
56
+ .tableWrapper {
57
+ margin: 0 !important;
58
+
59
+ ${mixin.scrollbar?.('x')};
60
+
61
+ width: 100%;
62
+
63
+ table {
64
+ width: calc(100% - 2rem) !important;
65
+ border-radius: ${size.radius};
66
+ box-sizing: border-box;
67
+ margin: 1rem 0 1rem 1rem !important;
68
+ overflow: auto !important;
69
+ * {
70
+ margin: 0 !important;
71
+ box-sizing: border-box;
72
+ font-size: 1rem;
73
+ }
74
+ tr {
75
+ ${mixin.border?.('bottom')};
76
+ }
77
+
78
+ th {
79
+ background: ${palette('background', 0.5)};
80
+ font-weight: 400;
81
+ }
82
+
83
+ th,
84
+ td {
85
+ min-width: 100px;
86
+ ${mixin.border?.()};
87
+ text-align: left;
88
+ position: relative;
89
+ line-height: 3rem;
90
+ box-sizing: border-box;
91
+ height: 3rem;
92
+ }
93
+
94
+ .selectedCell {
95
+ &::after {
96
+ background: ${palette('secondary', 0.38)};
97
+ }
98
+ & ::selection {
99
+ background: transparent;
100
+ }
101
+ }
102
+
103
+ .column-resize-handle {
104
+ background: ${palette('primary')};
105
+ width: ${size.lineWidth};
106
+ }
107
+
108
+ th,
109
+ td {
110
+ padding: 0 1rem;
111
+ p {
112
+ line-height: unset !important;
113
+ }
114
+ }
115
+
116
+ .milkdown-cell-left,
117
+ .milkdown-cell-point,
118
+ .milkdown-cell-top {
119
+ position: absolute;
120
+
121
+ &::after {
122
+ cursor: pointer;
123
+ position: absolute;
124
+ top: 0;
125
+ left: 0;
126
+ height: 100%;
127
+ width: 100%;
128
+ display: block;
129
+ transition: all 0.2s ease-in-out;
130
+ background: ${palette('secondary', 0.12)};
131
+ content: '';
132
+ }
133
+ &:hover::after {
134
+ background: ${palette('secondary', 0.38)};
135
+ }
136
+ }
137
+
138
+ .milkdown-cell-left {
139
+ left: calc(-6px - 0.5rem);
140
+ top: 0;
141
+ bottom: 0;
142
+ width: 0.5rem;
143
+ }
144
+
145
+ .milkdown-cell-top {
146
+ left: 0;
147
+ right: 0;
148
+ top: calc(-6px - 0.5rem);
149
+ height: 0.5rem;
150
+ }
151
+
152
+ .milkdown-cell-point {
153
+ left: calc(-2px - 1rem);
154
+ top: calc(-2px - 1rem);
155
+ width: 1rem;
156
+ height: 1rem;
157
+
158
+ .icon {
159
+ position: absolute;
160
+ top: 0;
161
+ bottom: 0;
162
+ left: 0;
163
+ right: 0;
164
+ }
165
+ }
166
+ }
167
+ }
168
+ `;
169
+ });
170
+ };
@@ -0,0 +1,115 @@
1
+ /* Copyright 2021, Milkdown by Mirone. */
2
+ import { Ctx, themeToolCtx } from '@milkdown/core';
3
+ import {
4
+ addColumnAfter,
5
+ addColumnBefore,
6
+ Command,
7
+ deleteColumn,
8
+ deleteRow,
9
+ deleteTable,
10
+ EditorView,
11
+ isInTable,
12
+ selectedRect,
13
+ setCellAttr,
14
+ } from '@milkdown/prose';
15
+
16
+ import { addRowWithAlignment } from '../utils';
17
+ import { getCellSelection, isFirstRowSelected } from './helper';
18
+
19
+ export type Item = {
20
+ $: HTMLElement;
21
+ command: (e: Event, view: EditorView) => Command;
22
+ disable?: (view: EditorView) => boolean;
23
+ };
24
+
25
+ export enum Action {
26
+ AddColLeft,
27
+ AddColRight,
28
+ AddRowTop,
29
+ AddRowBottom,
30
+ AlignLeft,
31
+ AlignCenter,
32
+ AlignRight,
33
+ Delete,
34
+ }
35
+
36
+ export const createActions: (ctx: Ctx) => Record<Action, Item> = (ctx) => ({
37
+ [Action.AddColLeft]: {
38
+ $: ctx.get(themeToolCtx).slots.icon('leftArrow'),
39
+ command: () => addColumnBefore,
40
+ disable: (view) => !getCellSelection(view).isColSelection(),
41
+ },
42
+ [Action.AddColRight]: {
43
+ $: ctx.get(themeToolCtx).slots.icon('rightArrow'),
44
+ command: () => addColumnAfter,
45
+ disable: (view) => !getCellSelection(view).isColSelection(),
46
+ },
47
+ [Action.AddRowTop]: {
48
+ $: ctx.get(themeToolCtx).slots.icon('upArrow'),
49
+ command: () => (state, dispatch) => {
50
+ if (!isInTable(state)) return false;
51
+ if (dispatch) {
52
+ const rect = selectedRect(state);
53
+ dispatch(addRowWithAlignment(state.tr, rect, rect.top));
54
+ }
55
+ return true;
56
+ },
57
+ disable: (view) =>
58
+ !getCellSelection(view).isRowSelection() ||
59
+ getCellSelection(view).$head.parent.type.name === 'table_header',
60
+ },
61
+ [Action.AddRowBottom]: {
62
+ $: ctx.get(themeToolCtx).slots.icon('downArrow'),
63
+ command: () => (state, dispatch) => {
64
+ if (!isInTable(state)) return false;
65
+ if (dispatch) {
66
+ const rect = selectedRect(state);
67
+ dispatch(addRowWithAlignment(state.tr, rect, rect.bottom));
68
+ }
69
+ return true;
70
+ },
71
+ disable: (view) => !getCellSelection(view).isRowSelection(),
72
+ },
73
+ [Action.AlignLeft]: {
74
+ $: ctx.get(themeToolCtx).slots.icon('alignLeft'),
75
+ command: () => setCellAttr('alignment', 'left'),
76
+ disable: (view) => !getCellSelection(view).isColSelection(),
77
+ },
78
+ [Action.AlignCenter]: {
79
+ $: ctx.get(themeToolCtx).slots.icon('alignCenter'),
80
+ command: () => setCellAttr('alignment', 'center'),
81
+ disable: (view) => !getCellSelection(view).isColSelection(),
82
+ },
83
+ [Action.AlignRight]: {
84
+ $: ctx.get(themeToolCtx).slots.icon('alignRight'),
85
+ command: () => setCellAttr('alignment', 'right'),
86
+ disable: (view) => !getCellSelection(view).isColSelection(),
87
+ },
88
+ [Action.Delete]: {
89
+ $: ctx.get(themeToolCtx).slots.icon('delete'),
90
+ command: (_, view) => {
91
+ const selection = getCellSelection(view);
92
+ const isCol = selection.isColSelection();
93
+ const isRow = selection.isRowSelection();
94
+ if (isCol && isRow) {
95
+ return deleteTable;
96
+ }
97
+
98
+ if (isCol) {
99
+ return deleteColumn;
100
+ }
101
+
102
+ return deleteRow;
103
+ },
104
+ disable: (view) => {
105
+ const selection = getCellSelection(view);
106
+ if (selection.isRowSelection()) {
107
+ if (selection.isColSelection()) {
108
+ return false;
109
+ }
110
+ return isFirstRowSelected(selection);
111
+ }
112
+ return false;
113
+ },
114
+ },
115
+ });
@@ -0,0 +1,25 @@
1
+ /* Copyright 2021, Milkdown by Mirone. */
2
+
3
+ import { calculateNodePosition, CellSelection, EditorView } from '@milkdown/prose';
4
+
5
+ export const calculatePosition = (view: EditorView, dom: HTMLElement) => {
6
+ const { selection } = view.state as unknown as { selection: CellSelection };
7
+ const isCol = selection.isColSelection();
8
+ const isRow = selection.isRowSelection();
9
+
10
+ calculateNodePosition(view, dom, (selected, target, parent) => {
11
+ const $editor = dom.parentElement;
12
+ if (!$editor) {
13
+ throw new Error();
14
+ }
15
+ let left = !isRow
16
+ ? selected.left - parent.left + (selected.width - target.width) / 2
17
+ : selected.left - parent.left - target.width / 2 - 8;
18
+ const top = selected.top - parent.top - target.height - (isCol ? 14 : 0) - 14 + $editor.scrollTop;
19
+
20
+ if (left < 0) {
21
+ left = 0;
22
+ }
23
+ return [top, left];
24
+ });
25
+ };
@@ -0,0 +1,7 @@
1
+ /* Copyright 2021, Milkdown by Mirone. */
2
+
3
+ export enum ToolTipPos {
4
+ Left = 'Left',
5
+ Top = 'Top',
6
+ Point = 'Point',
7
+ }
@@ -0,0 +1,38 @@
1
+ /* Copyright 2021, Milkdown by Mirone. */
2
+ import { CellSelection, EditorView, TableMap } from '@milkdown/prose';
3
+
4
+ import { Item } from './actions';
5
+
6
+ export const getCellSelection = (view: EditorView): CellSelection => view.state.selection as unknown as CellSelection;
7
+
8
+ export const isFirstRowSelected = (selection: CellSelection) => {
9
+ const map = TableMap.get(selection.$anchorCell.node(-1));
10
+ const start = selection.$anchorCell.start(-1);
11
+ const cells = map.cellsInRect({
12
+ left: 0,
13
+ right: map.width,
14
+ top: 0,
15
+ bottom: 1,
16
+ });
17
+ const selectedCells = map.cellsInRect(
18
+ map.rectBetween(selection.$anchorCell.pos - start, selection.$headCell.pos - start),
19
+ );
20
+
21
+ for (let i = 0, count = cells.length; i < count; i++) {
22
+ if (selectedCells.indexOf(cells[i]) === -1) {
23
+ return false;
24
+ }
25
+ }
26
+ return true;
27
+ };
28
+
29
+ export const calculateItem = (actions: Record<string, Item>, view: EditorView) => {
30
+ Object.values(actions).forEach((item) => {
31
+ const disable = item.disable?.(view);
32
+ if (disable) {
33
+ item.$.classList.add('hide');
34
+ return;
35
+ }
36
+ item.$.classList.remove('hide');
37
+ });
38
+ };