@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/README.md +98 -0
- package/dist/commands.d.ts +119 -0
- package/dist/commands.d.ts.map +1 -0
- package/dist/commands.js +754 -0
- package/dist/commands.js.map +1 -0
- package/dist/dialogs.d.ts +14 -0
- package/dist/dialogs.d.ts.map +1 -0
- package/dist/dialogs.js +159 -0
- package/dist/dialogs.js.map +1 -0
- package/dist/grid.d.ts +15 -0
- package/dist/grid.d.ts.map +1 -0
- package/dist/grid.js +230 -0
- package/dist/grid.js.map +1 -0
- package/dist/icons.d.ts.map +1 -1
- package/dist/icons.js +4 -0
- package/dist/icons.js.map +1 -1
- package/dist/index.d.ts +8 -21
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +112 -106
- package/dist/index.js.map +1 -1
- package/dist/menu.d.ts +23 -0
- package/dist/menu.d.ts.map +1 -0
- package/dist/menu.js +275 -0
- package/dist/menu.js.map +1 -0
- package/dist/styles.d.ts +9 -0
- package/dist/styles.d.ts.map +1 -0
- package/dist/styles.js +93 -0
- package/dist/styles.js.map +1 -0
- package/package.json +15 -7
package/README.md
ADDED
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
# @openleaf-editor/plugins-table
|
|
2
|
+
|
|
3
|
+
Opt-in table editing: cell selection, column resizing, property dialogs,
|
|
4
|
+
captions, an insert grid, a context menu, and the row and column commands.
|
|
5
|
+
|
|
6
|
+
> **Editor output is untrusted input.** Whatever the editor produces — and
|
|
7
|
+
> whatever a user pasted into it — must be sanitized **on your server** before it
|
|
8
|
+
> is stored or rendered as HTML. Client-side sanitization is a user-experience
|
|
9
|
+
> feature, not a security control: anything the editor strips can be put back
|
|
10
|
+
> with developer tools, because the editor runs under the user's control.
|
|
11
|
+
>
|
|
12
|
+
> [`@openleaf-editor/sanitize`](https://github.com/PeytonNowlin/openleaf/tree/main/packages/sanitize) ships the
|
|
13
|
+
> canonical allowlist as data and generates configuration for DOMPurify, Python
|
|
14
|
+
> `bleach` and PHP HTMLPurifier from it, so client and server enforce the same
|
|
15
|
+
> rules. Read [SECURITY.md](https://github.com/PeytonNowlin/openleaf/blob/main/SECURITY.md) before you ship.
|
|
16
|
+
|
|
17
|
+
## Install
|
|
18
|
+
|
|
19
|
+
```sh
|
|
20
|
+
npm install @openleaf-editor/plugins-table@beta
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
Keep every `@openleaf-editor/*` package on the same version. They pin each other
|
|
24
|
+
exactly, so mixing versions installs two copies of the schema and the toolbar
|
|
25
|
+
registry -- and a node built by one is not a node type the other accepts.
|
|
26
|
+
|
|
27
|
+
## Use it
|
|
28
|
+
|
|
29
|
+
With a bundler:
|
|
30
|
+
|
|
31
|
+
```ts
|
|
32
|
+
import { installTableEditing } from '@openleaf-editor/plugins-table'
|
|
33
|
+
installTableEditing()
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
With a script tag, load it after the core bundle -- it borrows the first one's
|
|
37
|
+
ProseMirror runtime rather than shipping a second copy:
|
|
38
|
+
|
|
39
|
+
```html
|
|
40
|
+
<script src="/js/openleaf.min.js"></script>
|
|
41
|
+
<script src="/js/openleaf-tables.min.js"></script>
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
Then name the controls you want in the `toolbar` attribute. Installing the
|
|
45
|
+
plugin registers capability; it does not rearrange your toolbar.
|
|
46
|
+
|
|
47
|
+
## The schema is not in here
|
|
48
|
+
|
|
49
|
+
Table node types live in [`@openleaf-editor/core`](../core), and that was not the
|
|
50
|
+
original plan. The fidelity harness changed it: without them a `<table>` in stored
|
|
51
|
+
content is claimed by the preservation layer and becomes an opaque, uneditable
|
|
52
|
+
card. Faithful, and useless.
|
|
53
|
+
|
|
54
|
+
So the split falls at the editing machinery instead. Every deployment reads and
|
|
55
|
+
writes tables; only the ones that want table *editing* download this.
|
|
56
|
+
|
|
57
|
+
## Captions and colgroup
|
|
58
|
+
|
|
59
|
+
Both round-trip byte-for-byte, as furniture attributes on the table node rather
|
|
60
|
+
than child nodes. They render but are not editable in place: a caption has to be a
|
|
61
|
+
child node for that, and `prosemirror-tables` derives its cell map from
|
|
62
|
+
`table.childCount`, so it needs an upstream fix first. The caption dialog is how
|
|
63
|
+
you change one meanwhile.
|
|
64
|
+
|
|
65
|
+
Inserting or deleting a column reindexes a stored `<colgroup>` with the cells.
|
|
66
|
+
Without that, every remaining column inherited the previous `<col>`'s width and
|
|
67
|
+
class. Column resize still patches widths onto the same elements, so the two
|
|
68
|
+
paths do not fight.
|
|
69
|
+
|
|
70
|
+
## License
|
|
71
|
+
|
|
72
|
+
Apache-2.0.
|
|
73
|
+
|
|
74
|
+
## Toolbar item ids
|
|
75
|
+
|
|
76
|
+
Installing registers the controls; it does not rearrange a custom toolbar. Name
|
|
77
|
+
the ones you want in the element's `toolbar` attribute:
|
|
78
|
+
|
|
79
|
+
| Id | Control |
|
|
80
|
+
| --- | --- |
|
|
81
|
+
| `insertTable` | Insert-table grid |
|
|
82
|
+
| `tableProperties` | Table properties dialog |
|
|
83
|
+
| `rowProperties` | Row properties dialog |
|
|
84
|
+
| `cellProperties` | Cell properties dialog |
|
|
85
|
+
| `tableCaption` | Caption dialog |
|
|
86
|
+
| `addRowBefore`, `addRowAfter`, `deleteRow` | Row commands. They keep `headerRows` / `footerRows` in step so `<thead>` and `<tfoot>` stay on the header and footer rows the author actually has. |
|
|
87
|
+
| `addColumnBefore`, `addColumnAfter`, `deleteColumn` | Column commands |
|
|
88
|
+
| `mergeCells`, `splitCell` | Cell merge and split |
|
|
89
|
+
| `toggleHeaderRow` | Promote or demote the header row |
|
|
90
|
+
| `deleteTable` | Delete the whole table |
|
|
91
|
+
|
|
92
|
+
```html
|
|
93
|
+
<openleaf-editor for="body"
|
|
94
|
+
toolbar="bold italic | insertTable tableProperties | source">
|
|
95
|
+
</openleaf-editor>
|
|
96
|
+
```
|
|
97
|
+
|
|
98
|
+
An id nothing has registered logs a warning rather than being skipped silently.
|
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Table commands that are not already in `prosemirror-tables`.
|
|
3
|
+
*
|
|
4
|
+
* Property edits, caption/colgroup, nested insert and vertical alignment live
|
|
5
|
+
* here so a test can apply them without standing up a toolbar. Column insert and
|
|
6
|
+
* delete also reindex the stored colgroup here: the upstream commands only move
|
|
7
|
+
* cells, and `colgroupFromCellWidths` never runs unless a cell already has
|
|
8
|
+
* `colwidth`.
|
|
9
|
+
*/
|
|
10
|
+
import type { Node, ResolvedPos } from 'prosemirror-model';
|
|
11
|
+
import type { Command, EditorState } from 'prosemirror-state';
|
|
12
|
+
import { Plugin } from 'prosemirror-state';
|
|
13
|
+
export declare function inTable(state: EditorState): boolean;
|
|
14
|
+
export declare function findRole($pos: ResolvedPos, role: 'table' | 'row' | 'cell' | 'header_cell'): {
|
|
15
|
+
node: Node;
|
|
16
|
+
pos: number;
|
|
17
|
+
depth: number;
|
|
18
|
+
} | null;
|
|
19
|
+
export declare function findTable($pos: ResolvedPos): {
|
|
20
|
+
node: Node;
|
|
21
|
+
pos: number;
|
|
22
|
+
depth: number;
|
|
23
|
+
} | null;
|
|
24
|
+
export declare function findRow($pos: ResolvedPos): {
|
|
25
|
+
node: Node;
|
|
26
|
+
pos: number;
|
|
27
|
+
depth: number;
|
|
28
|
+
} | null;
|
|
29
|
+
export declare function findCell($pos: ResolvedPos): {
|
|
30
|
+
node: Node;
|
|
31
|
+
pos: number;
|
|
32
|
+
depth: number;
|
|
33
|
+
} | null;
|
|
34
|
+
export declare function insertTable(rows?: number, cols?: number): Command;
|
|
35
|
+
export declare function withCellScope(command: Command): Command;
|
|
36
|
+
export declare const addColumnAfter: Command;
|
|
37
|
+
export declare const addColumnBefore: Command;
|
|
38
|
+
export declare const deleteColumn: Command;
|
|
39
|
+
export declare const addRowAfter: Command;
|
|
40
|
+
export declare const addRowBefore: Command;
|
|
41
|
+
export declare const deleteRow: Command;
|
|
42
|
+
export declare const toggleHeaderRow: Command;
|
|
43
|
+
export declare function selectedCellPositions(state: EditorState): number[];
|
|
44
|
+
/**
|
|
45
|
+
* Patch declarations onto a style attribute, validating every value written.
|
|
46
|
+
*
|
|
47
|
+
* The validation is here rather than in each caller because this is the choke
|
|
48
|
+
* point: a value reaches the stored style attribute only through this function,
|
|
49
|
+
* and `serializeDeclarations` joins on `;`, so an unchecked value carrying one
|
|
50
|
+
* becomes extra declarations. `padding: 0;position:fixed;inset:0` is a
|
|
51
|
+
* page-covering overlay, written from a property dialog and saved.
|
|
52
|
+
*
|
|
53
|
+
* `safeTableStyleValue` is core's own parse-path validator, so a dialog cannot
|
|
54
|
+
* disagree with the schema about what an acceptable value is.
|
|
55
|
+
*/
|
|
56
|
+
export declare function mergeStyle(existing: string | null | undefined, patch: Record<string, string | null>): string | null;
|
|
57
|
+
/** A style value the schema will keep, or null. For a dialog's commit step. */
|
|
58
|
+
export declare function styleValueOrNull(property: string, value: string | undefined): string | null;
|
|
59
|
+
export declare function setTableAttrs(attrs: Record<string, unknown>): Command;
|
|
60
|
+
export declare function setRowAttrs(attrs: Record<string, unknown>): Command;
|
|
61
|
+
export declare function setCellAttrs(attrs: Record<string, unknown>): Command;
|
|
62
|
+
export declare function setCellVerticalAlign(value: string | null): Command;
|
|
63
|
+
export declare function captionTextFromHtml(html: string | null | undefined): string;
|
|
64
|
+
export declare function captionHtmlFromText(text: string, previous: string | null | undefined): string | null;
|
|
65
|
+
export declare function setTableCaption(text: string): Command;
|
|
66
|
+
export declare function colgroupHtmlFromWidths(widths: Array<string | null | undefined>): string | null;
|
|
67
|
+
/**
|
|
68
|
+
* Column widths, one per column.
|
|
69
|
+
*
|
|
70
|
+
* `span` is honoured: `<col span="2" width="120">` sets two columns to 120, not
|
|
71
|
+
* one. Reading the elements positionally would report the second column as
|
|
72
|
+
* having no width, and then saving would write that back.
|
|
73
|
+
*/
|
|
74
|
+
export declare function widthsFromColgroup(html: string | null | undefined, columns: number): string[];
|
|
75
|
+
/**
|
|
76
|
+
* Write widths into an existing colgroup rather than replacing it.
|
|
77
|
+
*
|
|
78
|
+
* Inherited markup carries more than widths -- `<colgroup class="layout">`,
|
|
79
|
+
* `<col span="2">`, whatever else a previous CMS wrote -- and the table
|
|
80
|
+
* properties dialog saves the whole table, so rebuilding the colgroup from
|
|
81
|
+
* widths alone dropped all of it on a save that changed nothing else.
|
|
82
|
+
*
|
|
83
|
+
* An unchanged set of widths returns the stored markup untouched, so saving the
|
|
84
|
+
* dialog is genuinely a no-op. When a width does change, the existing elements
|
|
85
|
+
* are patched: a spanned `<col>` keeps its span while its columns still agree,
|
|
86
|
+
* and is split into one `<col>` per column -- carrying its other attributes --
|
|
87
|
+
* only when they no longer do.
|
|
88
|
+
*/
|
|
89
|
+
export declare function colgroupHtmlWithWidths(existing: string | null | undefined, widths: Array<string | null | undefined>): string | null;
|
|
90
|
+
/**
|
|
91
|
+
* Insert a bare `<col>` so columns after `at` keep the `<col>` they already had.
|
|
92
|
+
*
|
|
93
|
+
* A spanned element that covers `at` is split around the insertion rather than
|
|
94
|
+
* widened: the new column must not inherit the neighbour's class or width, which
|
|
95
|
+
* is the same shift insert-without-a-patch produced for unspanned columns.
|
|
96
|
+
*/
|
|
97
|
+
export declare function colgroupHtmlInsertColumn(existing: string | null | undefined, at: number): string | null;
|
|
98
|
+
/**
|
|
99
|
+
* Drop the `<col>` covering column `at`, or decrement its `span` when it covers
|
|
100
|
+
* more than one column.
|
|
101
|
+
*/
|
|
102
|
+
export declare function colgroupHtmlDeleteColumn(existing: string | null | undefined, at: number): string | null;
|
|
103
|
+
export declare function setTableColgroup(widths: Array<string | null | undefined>): Command;
|
|
104
|
+
/**
|
|
105
|
+
* Keep `<colgroup>` in lockstep with column resizing.
|
|
106
|
+
*
|
|
107
|
+
* `prosemirror-tables` writes `colwidth` onto cells. That is enough for the
|
|
108
|
+
* editor; it is not enough for stored HTML, whose column widths live on
|
|
109
|
+
* `<col>`. Updating the furniture attribute after a resize is what makes
|
|
110
|
+
* colgroup a first-class editing feature rather than a round-trip souvenir.
|
|
111
|
+
*
|
|
112
|
+
* Authored colgroups that are not the product of a resize are left alone:
|
|
113
|
+
* inventing `<col>` elements for a table that never had widths would change
|
|
114
|
+
* markup we had no reason to touch.
|
|
115
|
+
*/
|
|
116
|
+
export declare function colgroupSyncPlugin(): Plugin;
|
|
117
|
+
export declare function emptyToNull(value: string | undefined): string | null;
|
|
118
|
+
export declare function colorOrNull(value: string | undefined): string | null;
|
|
119
|
+
//# sourceMappingURL=commands.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"commands.d.ts","sourceRoot":"","sources":["../src/commands.ts"],"names":[],"mappings":"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"}
|