@openleaf-editor/plugins-table 0.1.0-beta.1 → 0.1.0-beta.3

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/dist/index.js CHANGED
@@ -12,8 +12,8 @@
12
12
  *
13
13
  * So everyone gets tables that read and write correctly, for about a kilobyte.
14
14
  * What is opt-in is the weight: cell selection, column resizing, the row and
15
- * column commands, and the toolbar controls -- 12.5 KB gzipped that a site
16
- * forbidding tables has no reason to download.
15
+ * column commands, property dialogs, the insert grid, the context menu, and the
16
+ * toolbar controls.
17
17
  *
18
18
  * ## Loading it
19
19
  *
@@ -25,7 +25,7 @@
25
25
  * ```
26
26
  *
27
27
  * The second bundle shares the first one's ProseMirror runtime rather than
28
- * carrying its own copy, which is what keeps it 12.5 KB instead of ~200 KB.
28
+ * carrying its own copy.
29
29
  *
30
30
  * Or as a module:
31
31
  *
@@ -34,12 +34,21 @@
34
34
  * installTableEditing()
35
35
  * ```
36
36
  */
37
- import { canInsert, isNodeActive, registerEditorPlugin } from '@openleaf-editor/core';
38
- import { registerIcons, registerToolbarItem } from '@openleaf-editor/ui';
37
+ import { registerEditorPlugin } from '@openleaf-editor/core';
38
+ import { registerIcons, registerStyles, registerToolbarItem } from '@openleaf-editor/ui';
39
+ import { columnResizing, deleteTable, mergeCells, splitCell, tableEditing, TableView, } from 'prosemirror-tables';
40
+ import { addColumnAfter, addColumnBefore, addRowAfter, addRowBefore, colgroupSyncPlugin, deleteColumn, deleteRow, inTable, insertTable, toggleHeaderRow, } from './commands.js';
41
+ import { openCaptionDialog, openCellProperties, openRowProperties, openTableProperties } from './dialogs.js';
42
+ import { buildInsertGrid } from './grid.js';
39
43
  import { TABLE_ICON_PATHS } from './icons.js';
40
- import { addColumnAfter as addColumnAfterRaw, addColumnBefore as addColumnBeforeRaw, addRowAfter as addRowAfterRaw, addRowBefore as addRowBeforeRaw, columnResizing, deleteColumn, deleteRow, deleteTable, mergeCells, splitCell, tableEditing, toggleHeaderRow as toggleHeaderRowRaw, } from 'prosemirror-tables';
44
+ import { tableContextMenu } from './menu.js';
45
+ import { TABLE_UI_CSS } from './styles.js';
41
46
  export const TABLE_TOOLBAR_ITEMS = [
42
47
  'insertTable',
48
+ 'tableProperties',
49
+ 'rowProperties',
50
+ 'cellProperties',
51
+ 'tableCaption',
43
52
  'addRowBefore',
44
53
  'addRowAfter',
45
54
  'deleteRow',
@@ -53,112 +62,89 @@ export const TABLE_TOOLBAR_ITEMS = [
53
62
  ];
54
63
  /** A layout string for the default toolbar plus the table controls. */
55
64
  export const TABLE_LAYOUT_SUFFIX = ` | ${TABLE_TOOLBAR_ITEMS.join(' ')}`;
56
- /** Is the selection inside a table? Table commands are useless outside one. */
57
- export function inTable(state) {
58
- return isNodeActive(state, 'table');
59
- }
60
65
  /**
61
- * Insert a table with a header row.
66
+ * `TableView`, plus the caption it does not know about.
62
67
  *
63
- * A header row by default rather than a plain grid: a table without headers is
64
- * an accessibility problem that authors rarely go back and fix, and defaults
65
- * decide what most documents look like.
66
- */
67
- export function insertTable(rows = 3, cols = 3) {
68
- return (state, dispatch) => {
69
- if (!canInsert(state, 'table'))
70
- return false;
71
- if (dispatch) {
72
- // From the state's schema, not an imported singleton: a plugin that
73
- // captured one schema would build nodes the editor's schema rejects.
74
- const cell = state.schema.nodes['table_cell'];
75
- const header = state.schema.nodes['table_header'];
76
- const row = state.schema.nodes['table_row'];
77
- const tableType = state.schema.nodes['table'];
78
- if (!cell || !header || !row || !tableType)
79
- return false;
80
- const headerCells = Array.from({ length: cols }, () => header.createAndFill({ scope: 'col' })).filter((n) => n !== null);
81
- const bodyRows = Array.from({ length: Math.max(0, rows - 1) }, () => row.create(null, Array.from({ length: cols }, () => cell.createAndFill()).filter((n) => n !== null)));
82
- const table = tableType.create(null, [row.create(null, headerCells), ...bodyRows]);
83
- dispatch(state.tr.replaceSelectionWith(table).scrollIntoView());
84
- }
85
- return true;
86
- };
87
- }
88
- /**
89
- * Keep `scope` valid when cells change role.
68
+ * `columnResizing` installs a node view for tables, and that node view builds
69
+ * the element itself: a wrapper div, a `<colgroup>` it owns for resize widths,
70
+ * and a `<tbody>`. It never consults the table node's `toDOM`, so once this
71
+ * bundle loads, the caption core renders is simply absent from the editor.
90
72
  *
91
- * `td` and `th` share an attribute set, so the upstream toggle copies `scope`
92
- * onto a body cell (invalid HTML) and creates header cells without it.
93
- * Inserting a table already writes `scope="col"`; toggling and adding columns
94
- * should not undo that.
73
+ * That produced the worst version of the bug it was meant to fix. Saving still
74
+ * kept the caption -- serialization goes through `toDOM` and never through a
75
+ * node view -- so the caption was invisible while editing and reappeared in the
76
+ * stored HTML. An author would reasonably conclude it had been deleted, and the
77
+ * only way to find out otherwise is to read the database.
78
+ *
79
+ * Only the caption is re-added. The preserved `<colgroup>` markup deliberately
80
+ * is not: this view's own colgroup is what drives column resizing, and a second
81
+ * one would fight it for the same columns. The author's colgroup is still
82
+ * stored and still emitted on save; it is the resize widths that win on screen,
83
+ * which is the same bargain the resizing feature already makes.
95
84
  */
96
- function applyCellScope(tr) {
97
- const header = tr.doc.type.schema.nodes['table_header'];
98
- const cell = tr.doc.type.schema.nodes['table_cell'];
99
- if (!header || !cell)
100
- return tr;
101
- let tablePos = -1;
102
- for (let depth = tr.selection.$from.depth; depth > 0; depth -= 1) {
103
- if (tr.selection.$from.node(depth).type.spec['tableRole'] === 'table') {
104
- tablePos = tr.selection.$from.before(depth);
105
- break;
85
+ class CaptionedTableView extends TableView {
86
+ constructor(node, defaultCellMinWidth) {
87
+ super(node, defaultCellMinWidth);
88
+ this.syncCaption(node);
89
+ }
90
+ update(node) {
91
+ const handled = super.update(node);
92
+ if (handled)
93
+ this.syncCaption(node);
94
+ return handled;
95
+ }
96
+ ignoreMutation(record) {
97
+ // The caption is ours, not content. Without this, ProseMirror treats a
98
+ // change inside it as an edit to the document and tries to re-read it.
99
+ const caption = this.currentCaption();
100
+ if (caption && record.target instanceof Node && caption.contains(record.target))
101
+ return true;
102
+ return super.ignoreMutation(record);
103
+ }
104
+ currentCaption() {
105
+ const first = this.table.firstElementChild;
106
+ return first && first.nodeName === 'CAPTION' ? first : null;
107
+ }
108
+ syncCaption(node) {
109
+ const html = node.attrs['caption'] ?? null;
110
+ const existing = this.currentCaption();
111
+ if (!html) {
112
+ existing?.remove();
113
+ return;
114
+ }
115
+ // Rebuild only when the markup actually changed. Replacing it on every
116
+ // update would discard the DOM under the user's selection on every
117
+ // keystroke inside the table.
118
+ if (existing && existing.getAttribute('data-openleaf-caption') === html)
119
+ return;
120
+ const tpl = document.createElement('template');
121
+ tpl.innerHTML = html;
122
+ const rebuilt = tpl.content.firstElementChild;
123
+ if (!rebuilt || rebuilt.nodeName !== 'CAPTION') {
124
+ existing?.remove();
125
+ return;
106
126
  }
127
+ // Editor-only. The caption is not part of `contentDOM`, so a caret must not
128
+ // enter it. `toDOM` no longer stamps this: clipboard serialization shares
129
+ // that path and would persist the marker. This view never runs on save.
130
+ rebuilt.setAttribute('contenteditable', 'false');
131
+ rebuilt.setAttribute('data-openleaf-caption', html);
132
+ // A caption must be the table's first child for the browser to render it.
133
+ if (existing)
134
+ existing.replaceWith(rebuilt);
135
+ else
136
+ this.table.insertBefore(rebuilt, this.table.firstChild);
107
137
  }
108
- if (tablePos < 0)
109
- return tr;
110
- const table = tr.doc.nodeAt(tablePos);
111
- if (!table)
112
- return tr;
113
- // Walked by row and column rather than as a flat descendant list, because a
114
- // header's scope depends on where it sits. `setNodeMarkup` only changes
115
- // attributes, so every node keeps its size and these positions stay valid.
116
- table.forEach((row, rowOffset, rowIndex) => {
117
- const rowPos = tablePos + 1 + rowOffset;
118
- row.forEach((cellNode, cellOffset, cellIndex) => {
119
- const pos = rowPos + 1 + cellOffset;
120
- if (cellNode.type === cell && cellNode.attrs['scope']) {
121
- tr.setNodeMarkup(pos, undefined, { ...cellNode.attrs, scope: null });
122
- return;
123
- }
124
- if (cellNode.type !== header)
125
- return;
126
- const scope = cellNode.attrs['scope'];
127
- if (scope !== null && scope !== undefined && scope !== '')
128
- return;
129
- // A header in the top row labels a column. A header that opens a later
130
- // row labels that row -- writing "col" there tells a screen reader the
131
- // opposite of the truth, which is worse than the missing scope this
132
- // replaces.
133
- tr.setNodeMarkup(pos, undefined, {
134
- ...cellNode.attrs,
135
- scope: rowIndex === 0 || cellIndex > 0 ? 'col' : 'row',
136
- });
137
- });
138
- });
139
- return tr;
140
- }
141
- function withCellScope(command) {
142
- return (state, dispatch, view) => {
143
- if (!dispatch)
144
- return command(state, undefined, view);
145
- return command(state, (tr) => {
146
- dispatch(applyCellScope(tr));
147
- }, view);
148
- };
149
138
  }
150
- export const addColumnAfter = withCellScope(addColumnAfterRaw);
151
- export const addColumnBefore = withCellScope(addColumnBeforeRaw);
152
- export const addRowAfter = withCellScope(addRowAfterRaw);
153
- export const addRowBefore = withCellScope(addRowBeforeRaw);
154
- export const toggleHeaderRow = withCellScope(toggleHeaderRowRaw);
155
139
  /** The ProseMirror plugins table editing needs. */
156
140
  export function tableEditingPlugins() {
157
141
  return [
158
142
  // Resizing must come first: it reads cell geometry that tableEditing's
159
143
  // selection handling would otherwise have already consumed.
160
- columnResizing(),
144
+ columnResizing({ View: CaptionedTableView }),
161
145
  tableEditing({ allowTableNodeSelection: true }),
146
+ colgroupSyncPlugin(),
147
+ tableContextMenu(),
162
148
  ];
163
149
  }
164
150
  let installed = false;
@@ -173,15 +159,35 @@ export function installTableEditing() {
173
159
  return;
174
160
  installed = true;
175
161
  registerIcons(TABLE_ICON_PATHS);
162
+ registerStyles(TABLE_UI_CSS);
176
163
  registerEditorPlugin(() => tableEditingPlugins());
177
164
  registerToolbarItem({
178
165
  id: 'insertTable',
179
- type: 'button',
180
- kind: 'action',
166
+ type: 'custom',
181
167
  label: 'Insert table',
182
168
  icon: 'table',
183
- command: insertTable(),
169
+ render: (ctx) => buildInsertGrid(ctx),
170
+ isEnabled: (state) => insertTable()(state),
184
171
  });
172
+ const dialogs = [
173
+ ['tableProperties', 'Table properties', 'tableProperties', openTableProperties],
174
+ ['rowProperties', 'Row properties', 'rowProperties', openRowProperties],
175
+ ['cellProperties', 'Cell properties', 'cellProperties', openCellProperties],
176
+ ['tableCaption', 'Table caption', 'tableCaption', openCaptionDialog],
177
+ ];
178
+ for (const [id, label, icon, open] of dialogs) {
179
+ registerToolbarItem({
180
+ id,
181
+ type: 'button',
182
+ kind: 'action',
183
+ label,
184
+ icon,
185
+ run: ({ view, host }) => {
186
+ void open(view, host);
187
+ },
188
+ isEnabled: (state) => inTable(state),
189
+ });
190
+ }
185
191
  const commands = [
186
192
  ['addRowBefore', 'Insert row above', addRowBefore],
187
193
  ['addRowAfter', 'Insert row below', addRowAfter],
@@ -214,12 +220,12 @@ export function installTableEditing() {
214
220
  label,
215
221
  ...(icons[id] ? { icon: icons[id] } : {}),
216
222
  command,
217
- // Every one of these is meaningless outside a table. Reporting them as
218
- // disabled rather than letting them silently no-op is the difference
219
- // between a control that looks broken and one that looks unavailable.
220
223
  isEnabled: (state) => inTable(state) && command(state),
221
224
  });
222
225
  }
223
226
  }
224
- export { deleteColumn, deleteRow, deleteTable, mergeCells, splitCell, } from 'prosemirror-tables';
227
+ export { addColumnAfter, addColumnBefore, addRowAfter, addRowBefore, colgroupHtmlWithWidths, colgroupSyncPlugin, deleteColumn, deleteRow, inTable, insertTable, mergeStyle, setCellAttrs, setCellVerticalAlign, setRowAttrs, setTableAttrs, setTableCaption, setTableColgroup, styleValueOrNull, toggleHeaderRow, widthsFromColgroup, } from './commands.js';
228
+ export { buildInsertGrid, GRID_SIZE } from './grid.js';
229
+ export { tableContextMenu } from './menu.js';
230
+ export { deleteTable, mergeCells, splitCell, } from 'prosemirror-tables';
225
231
  //# sourceMappingURL=index.js.map
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
package/dist/menu.d.ts ADDED
@@ -0,0 +1,23 @@
1
+ /**
2
+ * Table context menu.
3
+ *
4
+ * Right-click (and Shift+F10, which fires `contextmenu`) on a table opens the
5
+ * same commands the toolbar exposes, plus the property dialogs. Authors who
6
+ * live in the document rather than the bar should not have to leave the cell
7
+ * they are editing to add a row.
8
+ *
9
+ * Bound on `view.dom` rather than `handleDOMEvents`, because cell-selection
10
+ * handling in `prosemirror-tables` can swallow the event before a later plugin
11
+ * sees it. A capture listener on the editable surface always runs first.
12
+ *
13
+ * That is also what takes this menu out of ProseMirror's `editable` gate, which
14
+ * is the guard typing, paste, drop and the keymaps get for free -- so read-only
15
+ * has to be checked here explicitly, and it was not. A read-only editor opened
16
+ * this menu with all fourteen entries live and Delete row worked, from the mouse
17
+ * and from Shift+F10. The check is made in three places below rather than one,
18
+ * on purpose: at open time, in the enabled state each item advertises, and again
19
+ * before an item runs.
20
+ */
21
+ import { Plugin } from 'prosemirror-state';
22
+ export declare function tableContextMenu(): Plugin;
23
+ //# sourceMappingURL=menu.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"menu.d.ts","sourceRoot":"","sources":["../src/menu.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;GAmBG;AAGH,OAAO,EAAE,MAAM,EAAiB,MAAM,mBAAmB,CAAA;AAyFzD,wBAAgB,gBAAgB,IAAI,MAAM,CA0LzC"}
package/dist/menu.js ADDED
@@ -0,0 +1,275 @@
1
+ /**
2
+ * Table context menu.
3
+ *
4
+ * Right-click (and Shift+F10, which fires `contextmenu`) on a table opens the
5
+ * same commands the toolbar exposes, plus the property dialogs. Authors who
6
+ * live in the document rather than the bar should not have to leave the cell
7
+ * they are editing to add a row.
8
+ *
9
+ * Bound on `view.dom` rather than `handleDOMEvents`, because cell-selection
10
+ * handling in `prosemirror-tables` can swallow the event before a later plugin
11
+ * sees it. A capture listener on the editable surface always runs first.
12
+ *
13
+ * That is also what takes this menu out of ProseMirror's `editable` gate, which
14
+ * is the guard typing, paste, drop and the keymaps get for free -- so read-only
15
+ * has to be checked here explicitly, and it was not. A read-only editor opened
16
+ * this menu with all fourteen entries live and Delete row worked, from the mouse
17
+ * and from Shift+F10. The check is made in three places below rather than one,
18
+ * on purpose: at open time, in the enabled state each item advertises, and again
19
+ * before an item runs.
20
+ */
21
+ import { Plugin, TextSelection } from 'prosemirror-state';
22
+ import { deleteTable, mergeCells, splitCell } from 'prosemirror-tables';
23
+ import { addColumnAfter, addColumnBefore, addRowAfter, addRowBefore, deleteColumn, deleteRow, findTable, inTable, toggleHeaderRow, } from './commands.js';
24
+ import { openCaptionDialog, openCellProperties, openRowProperties, openTableProperties } from './dialogs.js';
25
+ function commandItem(label, command) {
26
+ return {
27
+ label,
28
+ enabled: (view) => command(view.state),
29
+ run: (view) => {
30
+ command(view.state, view.dispatch, view);
31
+ },
32
+ };
33
+ }
34
+ function groups() {
35
+ return [
36
+ {
37
+ items: [
38
+ commandItem('Insert row above', addRowBefore),
39
+ commandItem('Insert row below', addRowAfter),
40
+ commandItem('Delete row', deleteRow),
41
+ ],
42
+ },
43
+ {
44
+ items: [
45
+ commandItem('Insert column before', addColumnBefore),
46
+ commandItem('Insert column after', addColumnAfter),
47
+ commandItem('Delete column', deleteColumn),
48
+ ],
49
+ },
50
+ {
51
+ items: [
52
+ commandItem('Merge cells', mergeCells),
53
+ commandItem('Split cell', splitCell),
54
+ commandItem('Toggle header row', toggleHeaderRow),
55
+ ],
56
+ },
57
+ {
58
+ items: [
59
+ {
60
+ label: 'Table properties',
61
+ run: (view, host) => {
62
+ void openTableProperties(view, host);
63
+ },
64
+ },
65
+ {
66
+ label: 'Row properties',
67
+ run: (view, host) => {
68
+ void openRowProperties(view, host);
69
+ },
70
+ },
71
+ {
72
+ label: 'Cell properties',
73
+ run: (view, host) => {
74
+ void openCellProperties(view, host);
75
+ },
76
+ },
77
+ {
78
+ label: 'Caption',
79
+ run: (view, host) => {
80
+ void openCaptionDialog(view, host);
81
+ },
82
+ },
83
+ ],
84
+ },
85
+ {
86
+ items: [commandItem('Delete table', deleteTable)],
87
+ },
88
+ ];
89
+ }
90
+ export function tableContextMenu() {
91
+ return new Plugin({
92
+ view(view) {
93
+ let menu = null;
94
+ let open = false;
95
+ const hostFor = () => view.dom.closest('openleaf-editor') ??
96
+ view.dom.parentElement ??
97
+ view.dom;
98
+ /**
99
+ * The gate everything else on this surface is behind.
100
+ *
101
+ * `view.editable` rather than the host's `readonly` attribute, because it
102
+ * is the flag ProseMirror itself consults before running an edit handler
103
+ * and the one `prosemirror-tables`' column resizing checks. The element
104
+ * derives it from the attribute (`editable: () => !hasAttribute(readonly)`)
105
+ * and a view mounted without the custom element can set it directly, so
106
+ * this covers both.
107
+ *
108
+ * Read at each use rather than captured once: it is re-evaluated whenever
109
+ * the attribute changes.
110
+ */
111
+ const isReadonly = () => !view.editable;
112
+ const close = (returnFocus = false) => {
113
+ if (!open || !menu)
114
+ return;
115
+ menu.hidden = true;
116
+ open = false;
117
+ view.dom.ownerDocument.removeEventListener('pointerdown', onPointerDown, true);
118
+ if (returnFocus)
119
+ view.focus();
120
+ };
121
+ const onPointerDown = (event) => {
122
+ const target = event.target;
123
+ if (!(target instanceof Node) || menu?.contains(target))
124
+ return;
125
+ close();
126
+ };
127
+ const fill = () => {
128
+ if (!menu)
129
+ return;
130
+ menu.replaceChildren();
131
+ const doc = menu.ownerDocument;
132
+ for (const group of groups()) {
133
+ const list = doc.createElement('div');
134
+ list.className = 'ol-table-menu-group';
135
+ for (const item of group.items) {
136
+ const button = doc.createElement('button');
137
+ button.type = 'button';
138
+ button.className = 'ol-table-menu-item';
139
+ button.setAttribute('role', 'menuitem');
140
+ button.tabIndex = -1;
141
+ button.textContent = item.label;
142
+ // Nothing here edits a read-only document, so nothing here
143
+ // advertises that it can. Unreachable today, because the menu is
144
+ // never filled while read-only -- kept so a future entry point into
145
+ // the same menu cannot reintroduce the defect.
146
+ const enabled = !isReadonly() && (item.enabled ? item.enabled(view) : true);
147
+ button.setAttribute('aria-disabled', enabled ? 'false' : 'true');
148
+ button.addEventListener('click', () => {
149
+ // `enabled` was computed when the menu was filled, and read-only
150
+ // can arrive after that. Re-asked here so a menu that was
151
+ // legitimately open a moment ago cannot still act.
152
+ if (!enabled || isReadonly())
153
+ return;
154
+ close();
155
+ item.run(view, hostFor());
156
+ });
157
+ list.appendChild(button);
158
+ }
159
+ menu.appendChild(list);
160
+ }
161
+ };
162
+ const showAt = (x, y) => {
163
+ const host = hostFor();
164
+ if (!menu) {
165
+ menu = host.ownerDocument.createElement('div');
166
+ menu.className = 'ol-table-menu';
167
+ menu.setAttribute('role', 'menu');
168
+ menu.setAttribute('aria-label', 'Table');
169
+ host.appendChild(menu);
170
+ }
171
+ fill();
172
+ menu.hidden = false;
173
+ menu.style.position = 'fixed';
174
+ menu.style.left = `${Math.round(x)}px`;
175
+ menu.style.top = `${Math.round(y)}px`;
176
+ open = true;
177
+ view.dom.ownerDocument.addEventListener('pointerdown', onPointerDown, true);
178
+ focusItem(menu.querySelector('button:not([aria-disabled="true"])'));
179
+ };
180
+ const onContextMenu = (event) => {
181
+ if (!(event instanceof MouseEvent))
182
+ return;
183
+ // Before anything else, and before `preventDefault`: a read-only author
184
+ // should get the browser's own menu -- copy, inspect -- not a table
185
+ // editor. Shift+F10 fires `contextmenu` too, so this closes the keyboard
186
+ // route with the same line.
187
+ if (isReadonly())
188
+ return;
189
+ // Every item in this menu acts on `state.selection`, and a secondary
190
+ // click does not always move it -- right-clicking a second table while a
191
+ // cell selection is live in the first leaves the old one in place. Read
192
+ // the position under the pointer and work from that, or Delete table
193
+ // deletes the table the author did not click.
194
+ const at = view.posAtCoords({ left: event.clientX, top: event.clientY });
195
+ if (!at)
196
+ return;
197
+ const $pos = view.state.doc.resolve(at.pos);
198
+ if (!findTable($pos))
199
+ return;
200
+ // Only retargeted when the click lands outside the current selection: a
201
+ // right-click inside a multi-cell selection has to keep it, or "Delete
202
+ // row" would silently narrow to the one row under the pointer.
203
+ const { from, to } = view.state.selection;
204
+ if (at.pos < from || at.pos > to) {
205
+ view.dispatch(view.state.tr.setSelection(TextSelection.near($pos)));
206
+ }
207
+ if (!inTable(view.state))
208
+ return;
209
+ event.preventDefault();
210
+ event.stopPropagation();
211
+ showAt(event.clientX, event.clientY);
212
+ };
213
+ /*
214
+ * Escape, and the arrow keys, bound on the MENU.
215
+ *
216
+ * They were bound on `view.dom`, which never saw them: `showAt` appends
217
+ * the menu to the editor host and moves focus into it, and because the
218
+ * element builds its chrome in the light DOM, `view.dom` is not an
219
+ * ancestor of the menu. Shift+F10 is a documented way in, so that left a
220
+ * widget with an entrance and no exit.
221
+ */
222
+ const items = () => menu ? [...menu.querySelectorAll('[role="menuitem"]')] : [];
223
+ const focusItem = (next) => {
224
+ if (!next)
225
+ return;
226
+ for (const item of items())
227
+ item.tabIndex = item === next ? 0 : -1;
228
+ next.focus();
229
+ };
230
+ const onKeyDown = (event) => {
231
+ if (!open)
232
+ return;
233
+ // Tab out of a popup menu closes it rather than walking through it.
234
+ if (event.key === 'Escape' || event.key === 'Tab') {
235
+ event.preventDefault();
236
+ close(true);
237
+ return;
238
+ }
239
+ const all = items();
240
+ const index = all.indexOf(event.target);
241
+ if (index < 0)
242
+ return;
243
+ if (event.key === 'ArrowDown' || event.key === 'ArrowUp') {
244
+ event.preventDefault();
245
+ const delta = event.key === 'ArrowDown' ? 1 : -1;
246
+ focusItem(all[(index + delta + all.length) % all.length]);
247
+ return;
248
+ }
249
+ if (event.key === 'Home' || event.key === 'End') {
250
+ event.preventDefault();
251
+ focusItem(event.key === 'Home' ? all[0] : all[all.length - 1]);
252
+ }
253
+ };
254
+ view.dom.addEventListener('contextmenu', onContextMenu);
255
+ view.dom.ownerDocument.addEventListener('keydown', onKeyDown, true);
256
+ return {
257
+ update() {
258
+ // Read-only can arrive while the menu is open: the element's
259
+ // `attributeChangedCallback` calls `#applyReadonly`, which calls
260
+ // `view.setProps({})` so the view re-reads `editable` -- and that runs
261
+ // the plugin views. An open menu is dismissed rather than left armed.
262
+ if (isReadonly())
263
+ close();
264
+ },
265
+ destroy() {
266
+ view.dom.removeEventListener('contextmenu', onContextMenu);
267
+ view.dom.ownerDocument.removeEventListener('keydown', onKeyDown, true);
268
+ close();
269
+ menu?.remove();
270
+ },
271
+ };
272
+ },
273
+ });
274
+ }
275
+ //# sourceMappingURL=menu.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"menu.js","sourceRoot":"","sources":["../src/menu.ts"],"names":[],"mappings":"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"}