@doxi/core 0.11.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/LICENSE +21 -0
- package/README.md +81 -0
- package/dist/collab/port.d.ts +46 -0
- package/dist/collab/port.d.ts.map +1 -0
- package/dist/collab/port.js +11 -0
- package/dist/collab/port.js.map +1 -0
- package/dist/commands/block-commands.d.ts +62 -0
- package/dist/commands/block-commands.d.ts.map +1 -0
- package/dist/commands/block-commands.js +208 -0
- package/dist/commands/block-commands.js.map +1 -0
- package/dist/commands/command.d.ts +13 -0
- package/dist/commands/command.d.ts.map +1 -0
- package/dist/commands/command.js +13 -0
- package/dist/commands/command.js.map +1 -0
- package/dist/commands/edit-commands.d.ts +5 -0
- package/dist/commands/edit-commands.d.ts.map +1 -0
- package/dist/commands/edit-commands.js +147 -0
- package/dist/commands/edit-commands.js.map +1 -0
- package/dist/commands/image-commands.d.ts +31 -0
- package/dist/commands/image-commands.d.ts.map +1 -0
- package/dist/commands/image-commands.js +130 -0
- package/dist/commands/image-commands.js.map +1 -0
- package/dist/commands/index.d.ts +11 -0
- package/dist/commands/index.d.ts.map +1 -0
- package/dist/commands/index.js +11 -0
- package/dist/commands/index.js.map +1 -0
- package/dist/commands/keymap.d.ts +34 -0
- package/dist/commands/keymap.d.ts.map +1 -0
- package/dist/commands/keymap.js +84 -0
- package/dist/commands/keymap.js.map +1 -0
- package/dist/commands/link-commands.d.ts +54 -0
- package/dist/commands/link-commands.d.ts.map +1 -0
- package/dist/commands/link-commands.js +151 -0
- package/dist/commands/link-commands.js.map +1 -0
- package/dist/commands/list-commands.d.ts +42 -0
- package/dist/commands/list-commands.d.ts.map +1 -0
- package/dist/commands/list-commands.js +316 -0
- package/dist/commands/list-commands.js.map +1 -0
- package/dist/commands/mark-commands.d.ts +53 -0
- package/dist/commands/mark-commands.d.ts.map +1 -0
- package/dist/commands/mark-commands.js +181 -0
- package/dist/commands/mark-commands.js.map +1 -0
- package/dist/commands/selection-commands.d.ts +3 -0
- package/dist/commands/selection-commands.d.ts.map +1 -0
- package/dist/commands/selection-commands.js +11 -0
- package/dist/commands/selection-commands.js.map +1 -0
- package/dist/commands/table-commands.d.ts +109 -0
- package/dist/commands/table-commands.d.ts.map +1 -0
- package/dist/commands/table-commands.js +884 -0
- package/dist/commands/table-commands.js.map +1 -0
- package/dist/history/history.d.ts +40 -0
- package/dist/history/history.d.ts.map +1 -0
- package/dist/history/history.js +139 -0
- package/dist/history/history.js.map +1 -0
- package/dist/history/index.d.ts +2 -0
- package/dist/history/index.d.ts.map +1 -0
- package/dist/history/index.js +2 -0
- package/dist/history/index.js.map +1 -0
- package/dist/html/index.d.ts +3 -0
- package/dist/html/index.d.ts.map +1 -0
- package/dist/html/index.js +3 -0
- package/dist/html/index.js.map +1 -0
- package/dist/html/parse.d.ts +4 -0
- package/dist/html/parse.d.ts.map +1 -0
- package/dist/html/parse.js +0 -0
- package/dist/html/parse.js.map +1 -0
- package/dist/html/serialize.d.ts +4 -0
- package/dist/html/serialize.d.ts.map +1 -0
- package/dist/html/serialize.js +75 -0
- package/dist/html/serialize.js.map +1 -0
- package/dist/index.d.ts +13 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +13 -0
- package/dist/index.js.map +1 -0
- package/dist/layout/index.d.ts +6 -0
- package/dist/layout/index.d.ts.map +1 -0
- package/dist/layout/index.js +6 -0
- package/dist/layout/index.js.map +1 -0
- package/dist/layout/layout-engine.d.ts +20 -0
- package/dist/layout/layout-engine.d.ts.map +1 -0
- package/dist/layout/layout-engine.js +198 -0
- package/dist/layout/layout-engine.js.map +1 -0
- package/dist/layout/measure.d.ts +9 -0
- package/dist/layout/measure.d.ts.map +1 -0
- package/dist/layout/measure.js +37 -0
- package/dist/layout/measure.js.map +1 -0
- package/dist/layout/split-paragraph.d.ts +28 -0
- package/dist/layout/split-paragraph.d.ts.map +1 -0
- package/dist/layout/split-paragraph.js +122 -0
- package/dist/layout/split-paragraph.js.map +1 -0
- package/dist/layout/split-table.d.ts +46 -0
- package/dist/layout/split-table.d.ts.map +1 -0
- package/dist/layout/split-table.js +84 -0
- package/dist/layout/split-table.js.map +1 -0
- package/dist/layout/types.d.ts +73 -0
- package/dist/layout/types.d.ts.map +1 -0
- package/dist/layout/types.js +36 -0
- package/dist/layout/types.js.map +1 -0
- package/dist/layout/widow-orphan.d.ts +15 -0
- package/dist/layout/widow-orphan.d.ts.map +1 -0
- package/dist/layout/widow-orphan.js +14 -0
- package/dist/layout/widow-orphan.js.map +1 -0
- package/dist/model/content-expr.d.ts +32 -0
- package/dist/model/content-expr.d.ts.map +1 -0
- package/dist/model/content-expr.js +106 -0
- package/dist/model/content-expr.js.map +1 -0
- package/dist/model/fragment.d.ts +17 -0
- package/dist/model/fragment.d.ts.map +1 -0
- package/dist/model/fragment.js +44 -0
- package/dist/model/fragment.js.map +1 -0
- package/dist/model/index.d.ts +10 -0
- package/dist/model/index.d.ts.map +1 -0
- package/dist/model/index.js +10 -0
- package/dist/model/index.js.map +1 -0
- package/dist/model/mark.d.ts +35 -0
- package/dist/model/mark.d.ts.map +1 -0
- package/dist/model/mark.js +89 -0
- package/dist/model/mark.js.map +1 -0
- package/dist/model/node-type.d.ts +36 -0
- package/dist/model/node-type.d.ts.map +1 -0
- package/dist/model/node-type.js +14 -0
- package/dist/model/node-type.js.map +1 -0
- package/dist/model/node.d.ts +36 -0
- package/dist/model/node.d.ts.map +1 -0
- package/dist/model/node.js +192 -0
- package/dist/model/node.js.map +1 -0
- package/dist/model/position.d.ts +66 -0
- package/dist/model/position.d.ts.map +1 -0
- package/dist/model/position.js +158 -0
- package/dist/model/position.js.map +1 -0
- package/dist/model/schema.d.ts +28 -0
- package/dist/model/schema.d.ts.map +1 -0
- package/dist/model/schema.js +195 -0
- package/dist/model/schema.js.map +1 -0
- package/dist/model/slice.d.ts +26 -0
- package/dist/model/slice.d.ts.map +1 -0
- package/dist/model/slice.js +56 -0
- package/dist/model/slice.js.map +1 -0
- package/dist/model/table-grid.d.ts +71 -0
- package/dist/model/table-grid.d.ts.map +1 -0
- package/dist/model/table-grid.js +130 -0
- package/dist/model/table-grid.js.map +1 -0
- package/dist/plugin/index.d.ts +3 -0
- package/dist/plugin/index.d.ts.map +1 -0
- package/dist/plugin/index.js +3 -0
- package/dist/plugin/index.js.map +1 -0
- package/dist/plugin/plugin-key.d.ts +13 -0
- package/dist/plugin/plugin-key.d.ts.map +1 -0
- package/dist/plugin/plugin-key.js +13 -0
- package/dist/plugin/plugin-key.js.map +1 -0
- package/dist/plugin/plugin-state.d.ts +2 -0
- package/dist/plugin/plugin-state.d.ts.map +1 -0
- package/dist/plugin/plugin-state.js +3 -0
- package/dist/plugin/plugin-state.js.map +1 -0
- package/dist/plugin/plugin.d.ts +39 -0
- package/dist/plugin/plugin.d.ts.map +1 -0
- package/dist/plugin/plugin.js +10 -0
- package/dist/plugin/plugin.js.map +1 -0
- package/dist/schema/default.d.ts +163 -0
- package/dist/schema/default.d.ts.map +1 -0
- package/dist/schema/default.js +94 -0
- package/dist/schema/default.js.map +1 -0
- package/dist/schema/index.d.ts +2 -0
- package/dist/schema/index.d.ts.map +1 -0
- package/dist/schema/index.js +2 -0
- package/dist/schema/index.js.map +1 -0
- package/dist/serialize/index.d.ts +2 -0
- package/dist/serialize/index.d.ts.map +1 -0
- package/dist/serialize/index.js +2 -0
- package/dist/serialize/index.js.map +1 -0
- package/dist/serialize/json.d.ts +15 -0
- package/dist/serialize/json.d.ts.map +1 -0
- package/dist/serialize/json.js +23 -0
- package/dist/serialize/json.js.map +1 -0
- package/dist/state/all-selection.d.ts +11 -0
- package/dist/state/all-selection.d.ts.map +1 -0
- package/dist/state/all-selection.js +17 -0
- package/dist/state/all-selection.js.map +1 -0
- package/dist/state/cell-selection.d.ts +30 -0
- package/dist/state/cell-selection.d.ts.map +1 -0
- package/dist/state/cell-selection.js +38 -0
- package/dist/state/cell-selection.js.map +1 -0
- package/dist/state/editor-state.d.ts +46 -0
- package/dist/state/editor-state.d.ts.map +1 -0
- package/dist/state/editor-state.js +211 -0
- package/dist/state/editor-state.js.map +1 -0
- package/dist/state/index.d.ts +7 -0
- package/dist/state/index.d.ts.map +1 -0
- package/dist/state/index.js +7 -0
- package/dist/state/index.js.map +1 -0
- package/dist/state/node-selection.d.ts +16 -0
- package/dist/state/node-selection.d.ts.map +1 -0
- package/dist/state/node-selection.js +51 -0
- package/dist/state/node-selection.js.map +1 -0
- package/dist/state/selection.d.ts +29 -0
- package/dist/state/selection.d.ts.map +1 -0
- package/dist/state/selection.js +24 -0
- package/dist/state/selection.js.map +1 -0
- package/dist/state/text-selection.d.ts +10 -0
- package/dist/state/text-selection.d.ts.map +1 -0
- package/dist/state/text-selection.js +26 -0
- package/dist/state/text-selection.js.map +1 -0
- package/dist/transform/attr-step.d.ts +16 -0
- package/dist/transform/attr-step.d.ts.map +1 -0
- package/dist/transform/attr-step.js +98 -0
- package/dist/transform/attr-step.js.map +1 -0
- package/dist/transform/index.d.ts +10 -0
- package/dist/transform/index.d.ts.map +1 -0
- package/dist/transform/index.js +10 -0
- package/dist/transform/index.js.map +1 -0
- package/dist/transform/mapping.d.ts +44 -0
- package/dist/transform/mapping.d.ts.map +1 -0
- package/dist/transform/mapping.js +101 -0
- package/dist/transform/mapping.js.map +1 -0
- package/dist/transform/mark-step.d.ts +27 -0
- package/dist/transform/mark-step.d.ts.map +1 -0
- package/dist/transform/mark-step.js +146 -0
- package/dist/transform/mark-step.js.map +1 -0
- package/dist/transform/replace-around-step.d.ts +35 -0
- package/dist/transform/replace-around-step.d.ts.map +1 -0
- package/dist/transform/replace-around-step.js +144 -0
- package/dist/transform/replace-around-step.js.map +1 -0
- package/dist/transform/replace-step.d.ts +17 -0
- package/dist/transform/replace-step.d.ts.map +1 -0
- package/dist/transform/replace-step.js +72 -0
- package/dist/transform/replace-step.js.map +1 -0
- package/dist/transform/replace.d.ts +18 -0
- package/dist/transform/replace.d.ts.map +1 -0
- package/dist/transform/replace.js +132 -0
- package/dist/transform/replace.js.map +1 -0
- package/dist/transform/set-page-meta-step.d.ts +42 -0
- package/dist/transform/set-page-meta-step.d.ts.map +1 -0
- package/dist/transform/set-page-meta-step.js +75 -0
- package/dist/transform/set-page-meta-step.js.map +1 -0
- package/dist/transform/step.d.ts +34 -0
- package/dist/transform/step.d.ts.map +1 -0
- package/dist/transform/step.js +23 -0
- package/dist/transform/step.js.map +1 -0
- package/dist/transform/transaction.d.ts +20 -0
- package/dist/transform/transaction.d.ts.map +1 -0
- package/dist/transform/transaction.js +38 -0
- package/dist/transform/transaction.js.map +1 -0
- package/dist/version.d.ts +2 -0
- package/dist/version.d.ts.map +1 -0
- package/dist/version.js +5 -0
- package/dist/version.js.map +1 -0
- package/dist/view/cell-drag.d.ts +33 -0
- package/dist/view/cell-drag.d.ts.map +1 -0
- package/dist/view/cell-drag.js +177 -0
- package/dist/view/cell-drag.js.map +1 -0
- package/dist/view/clipboard.d.ts +5 -0
- package/dist/view/clipboard.d.ts.map +1 -0
- package/dist/view/clipboard.js +97 -0
- package/dist/view/clipboard.js.map +1 -0
- package/dist/view/default-renderer.d.ts +3 -0
- package/dist/view/default-renderer.d.ts.map +1 -0
- package/dist/view/default-renderer.js +142 -0
- package/dist/view/default-renderer.js.map +1 -0
- package/dist/view/dom-spec.d.ts +11 -0
- package/dist/view/dom-spec.d.ts.map +1 -0
- package/dist/view/dom-spec.js +32 -0
- package/dist/view/dom-spec.js.map +1 -0
- package/dist/view/editor-view.d.ts +55 -0
- package/dist/view/editor-view.d.ts.map +1 -0
- package/dist/view/editor-view.js +143 -0
- package/dist/view/editor-view.js.map +1 -0
- package/dist/view/image-resize.d.ts +37 -0
- package/dist/view/image-resize.d.ts.map +1 -0
- package/dist/view/image-resize.js +191 -0
- package/dist/view/image-resize.js.map +1 -0
- package/dist/view/index.d.ts +15 -0
- package/dist/view/index.d.ts.map +1 -0
- package/dist/view/index.js +15 -0
- package/dist/view/index.js.map +1 -0
- package/dist/view/input-pipeline.d.ts +24 -0
- package/dist/view/input-pipeline.d.ts.map +1 -0
- package/dist/view/input-pipeline.js +226 -0
- package/dist/view/input-pipeline.js.map +1 -0
- package/dist/view/mutation-observer.d.ts +17 -0
- package/dist/view/mutation-observer.d.ts.map +1 -0
- package/dist/view/mutation-observer.js +62 -0
- package/dist/view/mutation-observer.js.map +1 -0
- package/dist/view/page-slots.d.ts +56 -0
- package/dist/view/page-slots.d.ts.map +1 -0
- package/dist/view/page-slots.js +230 -0
- package/dist/view/page-slots.js.map +1 -0
- package/dist/view/paginator.d.ts +17 -0
- package/dist/view/paginator.d.ts.map +1 -0
- package/dist/view/paginator.js +93 -0
- package/dist/view/paginator.js.map +1 -0
- package/dist/view/print.d.ts +42 -0
- package/dist/view/print.d.ts.map +1 -0
- package/dist/view/print.js +70 -0
- package/dist/view/print.js.map +1 -0
- package/dist/view/reconcile.d.ts +16 -0
- package/dist/view/reconcile.d.ts.map +1 -0
- package/dist/view/reconcile.js +158 -0
- package/dist/view/reconcile.js.map +1 -0
- package/dist/view/renderer.d.ts +31 -0
- package/dist/view/renderer.d.ts.map +1 -0
- package/dist/view/renderer.js +89 -0
- package/dist/view/renderer.js.map +1 -0
- package/dist/view/selection-sync.d.ts +35 -0
- package/dist/view/selection-sync.d.ts.map +1 -0
- package/dist/view/selection-sync.js +324 -0
- package/dist/view/selection-sync.js.map +1 -0
- package/dist/view/table-resize.d.ts +41 -0
- package/dist/view/table-resize.d.ts.map +1 -0
- package/dist/view/table-resize.js +216 -0
- package/dist/view/table-resize.js.map +1 -0
- package/package.json +93 -0
- package/styles/base.css +269 -0
- package/styles/dark.css +36 -0
- package/styles/light.css +13 -0
- package/styles/page.css +93 -0
- package/styles/print-a4.css +87 -0
- package/styles/print.css +88 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Mahbub Hasan
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
# @doxi/core
|
|
2
|
+
|
|
3
|
+
The Doxiva editor engine: schema, transactions, state, view, plugins, commands, layout, and styles. Zero runtime dependencies.
|
|
4
|
+
|
|
5
|
+
> **Status:** v0.10.x preview. The v0.9.x public API surface is the candidate for the v1.0 freeze — see [`STABILITY.md`](../../STABILITY.md).
|
|
6
|
+
|
|
7
|
+
## Install
|
|
8
|
+
|
|
9
|
+
```bash
|
|
10
|
+
pnpm add @doxi/core
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
## Quickstart (vanilla DOM)
|
|
14
|
+
|
|
15
|
+
```ts
|
|
16
|
+
import {
|
|
17
|
+
defaultSchema,
|
|
18
|
+
defaultRenderer,
|
|
19
|
+
EditorState,
|
|
20
|
+
EditorView,
|
|
21
|
+
historyPlugin,
|
|
22
|
+
} from '@doxi/core'
|
|
23
|
+
import '@doxi/core/styles/base.css'
|
|
24
|
+
import '@doxi/core/styles/light.css'
|
|
25
|
+
|
|
26
|
+
const state = EditorState.create({
|
|
27
|
+
schema: defaultSchema,
|
|
28
|
+
plugins: [historyPlugin().plugin],
|
|
29
|
+
})
|
|
30
|
+
|
|
31
|
+
const view = new EditorView({
|
|
32
|
+
mount: document.getElementById('editor')!,
|
|
33
|
+
state,
|
|
34
|
+
renderer: defaultRenderer,
|
|
35
|
+
ariaLabel: 'Document editor',
|
|
36
|
+
})
|
|
37
|
+
|
|
38
|
+
// Dispatch a transaction
|
|
39
|
+
view.dispatch(view.state.tr.insertText('Hello, world.'))
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
## Subpath exports
|
|
43
|
+
|
|
44
|
+
`@doxi/core` exposes layered subpaths so consumers can import only what they need:
|
|
45
|
+
|
|
46
|
+
| Subpath | What's there |
|
|
47
|
+
|---|---|
|
|
48
|
+
| `@doxi/core` | Top-level re-exports of the most common API |
|
|
49
|
+
| `@doxi/core/model` | Schema, nodes, marks, positions, fragments |
|
|
50
|
+
| `@doxi/core/transform` | Transform steps (`ReplaceStep`, `AttrStep`, `SetPageMetaStep`, …) |
|
|
51
|
+
| `@doxi/core/state` | `EditorState`, `Selection`, `TextSelection`, `NodeSelection`, `CellSelection` |
|
|
52
|
+
| `@doxi/core/plugin` | Plugin API and built-ins |
|
|
53
|
+
| `@doxi/core/history` | Undo/redo plugin |
|
|
54
|
+
| `@doxi/core/commands` | Headless commands (text, lists, tables, images, links, page break, …) |
|
|
55
|
+
| `@doxi/core/view` | `EditorView`, input pipeline, decorations, `printDocument`, `setPrintPageSize` |
|
|
56
|
+
| `@doxi/core/layout` | Paginator, page boxes, header/footer slot controller |
|
|
57
|
+
| `@doxi/core/schema` | `defaultSchema` and its node/mark definitions |
|
|
58
|
+
| `@doxi/core/serialize` | JSON ↔ document tree |
|
|
59
|
+
| `@doxi/core/html` | HTML ↔ document tree with paste sanitization |
|
|
60
|
+
| `@doxi/core/collab` | Collaboration port (used by `@doxi/collab`) |
|
|
61
|
+
|
|
62
|
+
## Stylesheets
|
|
63
|
+
|
|
64
|
+
CSS lives under `@doxi/core/styles/`. Import the ones you need:
|
|
65
|
+
|
|
66
|
+
```ts
|
|
67
|
+
import '@doxi/core/styles/base.css' // structural styles (required)
|
|
68
|
+
import '@doxi/core/styles/light.css' // light theme
|
|
69
|
+
import '@doxi/core/styles/dark.css' // dark theme
|
|
70
|
+
import '@doxi/core/styles/page.css' // paginated mode chrome
|
|
71
|
+
import '@doxi/core/styles/print.css' // @media print
|
|
72
|
+
import '@doxi/core/styles/print-a4.css' // optional A4 @page size
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
## Bundle size
|
|
76
|
+
|
|
77
|
+
Tracked per release in [`docs/bundle-budget.md`](../../docs/bundle-budget.md). Run `pnpm bundle-size` from the repo root.
|
|
78
|
+
|
|
79
|
+
## License
|
|
80
|
+
|
|
81
|
+
[MIT](LICENSE)
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @doxi/core/collab — port interface.
|
|
3
|
+
*
|
|
4
|
+
* v0.1 ships only the interface. Implementations arrive at v0.6 in @doxi/collab.
|
|
5
|
+
* The interface enforces three engine-side properties via its types:
|
|
6
|
+
* 1. Every Transaction must be JSON-serializable end-to-end (see TransactionWire).
|
|
7
|
+
* 2. Every Step must round-trip through JSON (see StepWire).
|
|
8
|
+
* 3. The view must accept decoration sets from external sources (RemoteCursor).
|
|
9
|
+
*/
|
|
10
|
+
export interface StepWire {
|
|
11
|
+
readonly kind: string;
|
|
12
|
+
readonly data: Readonly<Record<string, unknown>>;
|
|
13
|
+
}
|
|
14
|
+
export interface SelectionWire {
|
|
15
|
+
readonly anchor: number;
|
|
16
|
+
readonly head: number;
|
|
17
|
+
}
|
|
18
|
+
export interface TransactionWire {
|
|
19
|
+
readonly id: string;
|
|
20
|
+
readonly sourceClientId: string;
|
|
21
|
+
readonly steps: ReadonlyArray<StepWire>;
|
|
22
|
+
readonly selectionAfter: SelectionWire | null;
|
|
23
|
+
}
|
|
24
|
+
export interface RemoteCursor {
|
|
25
|
+
readonly clientId: string;
|
|
26
|
+
readonly clientName?: string;
|
|
27
|
+
readonly color?: string;
|
|
28
|
+
readonly selection: SelectionWire;
|
|
29
|
+
}
|
|
30
|
+
export interface PresencePort {
|
|
31
|
+
setLocalCursor(selection: SelectionWire): void;
|
|
32
|
+
/** Subscribe to remote cursor updates. Returns an unsubscribe function. */
|
|
33
|
+
observeRemoteCursors(callback: (cursors: ReadonlyArray<RemoteCursor>) => void): () => void;
|
|
34
|
+
}
|
|
35
|
+
export interface CollabPort {
|
|
36
|
+
/**
|
|
37
|
+
* Serialize a Transaction for the wire. v0.1 leaves the Transaction parameter
|
|
38
|
+
* typed as `unknown` because Track B (Steps & Transactions) defines the
|
|
39
|
+
* concrete type. Implementations will tighten this signature once Track B
|
|
40
|
+
* lands by augmenting the module.
|
|
41
|
+
*/
|
|
42
|
+
serializeTransaction(transaction: unknown): TransactionWire;
|
|
43
|
+
applyRemoteTransaction(wire: TransactionWire): void;
|
|
44
|
+
readonly presence: PresencePort;
|
|
45
|
+
}
|
|
46
|
+
//# sourceMappingURL=port.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"port.d.ts","sourceRoot":"","sources":["../../src/collab/port.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,MAAM,WAAW,QAAQ;IACvB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAA;IACrB,QAAQ,CAAC,IAAI,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,CAAA;CACjD;AAED,MAAM,WAAW,aAAa;IAC5B,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAA;IACvB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAA;CACtB;AAED,MAAM,WAAW,eAAe;IAC9B,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAA;IACnB,QAAQ,CAAC,cAAc,EAAE,MAAM,CAAA;IAC/B,QAAQ,CAAC,KAAK,EAAE,aAAa,CAAC,QAAQ,CAAC,CAAA;IACvC,QAAQ,CAAC,cAAc,EAAE,aAAa,GAAG,IAAI,CAAA;CAC9C;AAED,MAAM,WAAW,YAAY;IAC3B,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAA;IACzB,QAAQ,CAAC,UAAU,CAAC,EAAE,MAAM,CAAA;IAC5B,QAAQ,CAAC,KAAK,CAAC,EAAE,MAAM,CAAA;IACvB,QAAQ,CAAC,SAAS,EAAE,aAAa,CAAA;CAClC;AAED,MAAM,WAAW,YAAY;IAC3B,cAAc,CAAC,SAAS,EAAE,aAAa,GAAG,IAAI,CAAA;IAC9C,2EAA2E;IAC3E,oBAAoB,CAAC,QAAQ,EAAE,CAAC,OAAO,EAAE,aAAa,CAAC,YAAY,CAAC,KAAK,IAAI,GAAG,MAAM,IAAI,CAAA;CAC3F;AAED,MAAM,WAAW,UAAU;IACzB;;;;;OAKG;IACH,oBAAoB,CAAC,WAAW,EAAE,OAAO,GAAG,eAAe,CAAA;IAC3D,sBAAsB,CAAC,IAAI,EAAE,eAAe,GAAG,IAAI,CAAA;IACnD,QAAQ,CAAC,QAAQ,EAAE,YAAY,CAAA;CAChC"}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @doxi/core/collab — port interface.
|
|
3
|
+
*
|
|
4
|
+
* v0.1 ships only the interface. Implementations arrive at v0.6 in @doxi/collab.
|
|
5
|
+
* The interface enforces three engine-side properties via its types:
|
|
6
|
+
* 1. Every Transaction must be JSON-serializable end-to-end (see TransactionWire).
|
|
7
|
+
* 2. Every Step must round-trip through JSON (see StepWire).
|
|
8
|
+
* 3. The view must accept decoration sets from external sources (RemoteCursor).
|
|
9
|
+
*/
|
|
10
|
+
export {};
|
|
11
|
+
//# sourceMappingURL=port.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"port.js","sourceRoot":"","sources":["../../src/collab/port.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG"}
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
import type { NodeType } from '../model/node-type.js';
|
|
2
|
+
import type { Command } from './command.js';
|
|
3
|
+
/**
|
|
4
|
+
* Convert the top-level block at the cursor to `nodeType` with `attrs`.
|
|
5
|
+
*
|
|
6
|
+
* - If the block is already `nodeType` with matching attrs — no-op.
|
|
7
|
+
* - If the block is already `nodeType` but attrs differ (e.g. switching
|
|
8
|
+
* heading level 1 → 2) — apply minimal AttrSteps (preserves the DOM
|
|
9
|
+
* element in incremental render mode).
|
|
10
|
+
* - If the block is a different type (e.g. paragraph → heading) — replace
|
|
11
|
+
* the block with a fresh node of `nodeType`, preserving the inline
|
|
12
|
+
* content. Attrs the new type shares with the old (e.g. `align`,
|
|
13
|
+
* `lineHeight`) are carried over.
|
|
14
|
+
*
|
|
15
|
+
* Cursor must be inside a top-level block (depth ≥ 1).
|
|
16
|
+
*/
|
|
17
|
+
export declare function setBlockType(nodeType: NodeType, attrs?: Record<string, unknown>): Command;
|
|
18
|
+
/**
|
|
19
|
+
* Generic helper: set one attribute on the depth-1 block (paragraph/heading)
|
|
20
|
+
* containing the current selection. Returns a Command suitable for the toolbar.
|
|
21
|
+
*
|
|
22
|
+
* Used by setAlignment / setLineHeight; also reusable for any future block attr
|
|
23
|
+
* the schema declares (e.g. indent level, gutter color, etc.).
|
|
24
|
+
*/
|
|
25
|
+
export declare function setBlockAttr(attrName: string, value: unknown): Command;
|
|
26
|
+
export type AlignValue = 'left' | 'center' | 'right' | 'justify' | null;
|
|
27
|
+
/** Set the text-align attribute on the block containing the selection. */
|
|
28
|
+
export declare function setAlignment(value: AlignValue): Command;
|
|
29
|
+
/** Set the line-height multiplier on the block containing the selection. */
|
|
30
|
+
export declare function setLineHeight(value: number | null): Command;
|
|
31
|
+
/**
|
|
32
|
+
* Wrap the depth-1 block containing the cursor inside a fresh blockquote of
|
|
33
|
+
* `bqType`. Cursor is preserved at its inline offset — it crosses one extra
|
|
34
|
+
* [open] token (the blockquote's), so the absolute position shifts by +1.
|
|
35
|
+
*
|
|
36
|
+
* - Returns false if cursor depth < 1.
|
|
37
|
+
* - Returns false if any ancestor of the cursor is already a blockquote
|
|
38
|
+
* (we don't stack blockquotes).
|
|
39
|
+
*/
|
|
40
|
+
export declare function wrapInBlockquote(bqType: NodeType): Command;
|
|
41
|
+
/**
|
|
42
|
+
* Insert a new `hrType` block as a sibling immediately after the depth-1
|
|
43
|
+
* block containing the cursor, followed by a fresh empty paragraph. The
|
|
44
|
+
* cursor lands at the start of the trailing paragraph.
|
|
45
|
+
*
|
|
46
|
+
* If `state.schema.nodes.paragraph` is missing, fall back to inserting just
|
|
47
|
+
* the hr (cursor at `rp.after(1)`).
|
|
48
|
+
*
|
|
49
|
+
* - Returns false if cursor depth < 1.
|
|
50
|
+
*/
|
|
51
|
+
export declare function insertHr(hrType: NodeType): Command;
|
|
52
|
+
/**
|
|
53
|
+
* Insert a `page_break` block at the cursor (as a sibling AFTER the current
|
|
54
|
+
* top-level block), followed by a fresh empty paragraph. Cursor lands at
|
|
55
|
+
* the start of the trailing paragraph so the user can immediately type on
|
|
56
|
+
* the new page.
|
|
57
|
+
*
|
|
58
|
+
* Behavior mirrors `insertHr`. Returns false if the schema lacks
|
|
59
|
+
* `page_break` or cursor depth < 1.
|
|
60
|
+
*/
|
|
61
|
+
export declare function insertPageBreak(pbType: NodeType): Command;
|
|
62
|
+
//# sourceMappingURL=block-commands.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"block-commands.d.ts","sourceRoot":"","sources":["../../src/commands/block-commands.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,uBAAuB,CAAA;AAOrD,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,cAAc,CAAA;AAE3C;;;;;;;;;;;;;GAaG;AACH,wBAAgB,YAAY,CAAC,QAAQ,EAAE,QAAQ,EAAE,KAAK,GAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAM,GAAG,OAAO,CA6C7F;AAED;;;;;;GAMG;AACH,wBAAgB,YAAY,CAAC,QAAQ,EAAE,MAAM,EAAE,KAAK,EAAE,OAAO,GAAG,OAAO,CActE;AAED,MAAM,MAAM,UAAU,GAAG,MAAM,GAAG,QAAQ,GAAG,OAAO,GAAG,SAAS,GAAG,IAAI,CAAA;AAEvE,0EAA0E;AAC1E,wBAAgB,YAAY,CAAC,KAAK,EAAE,UAAU,GAAG,OAAO,CAEvD;AAED,4EAA4E;AAC5E,wBAAgB,aAAa,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI,GAAG,OAAO,CAE3D;AAED;;;;;;;;GAQG;AACH,wBAAgB,gBAAgB,CAAC,MAAM,EAAE,QAAQ,GAAG,OAAO,CAsB1D;AAED;;;;;;;;;GASG;AACH,wBAAgB,QAAQ,CAAC,MAAM,EAAE,QAAQ,GAAG,OAAO,CAuBlD;AAED;;;;;;;;GAQG;AACH,wBAAgB,eAAe,CAAC,MAAM,EAAE,QAAQ,GAAG,OAAO,CAoBzD"}
|
|
@@ -0,0 +1,208 @@
|
|
|
1
|
+
import { Fragment } from '../model/fragment.js';
|
|
2
|
+
import { findTopBlockDepth, resolve } from '../model/position.js';
|
|
3
|
+
import { Slice } from '../model/slice.js';
|
|
4
|
+
import { TextSelection } from '../state/text-selection.js';
|
|
5
|
+
import { AttrStep } from '../transform/attr-step.js';
|
|
6
|
+
import { ReplaceStep } from '../transform/replace-step.js';
|
|
7
|
+
/**
|
|
8
|
+
* Convert the top-level block at the cursor to `nodeType` with `attrs`.
|
|
9
|
+
*
|
|
10
|
+
* - If the block is already `nodeType` with matching attrs — no-op.
|
|
11
|
+
* - If the block is already `nodeType` but attrs differ (e.g. switching
|
|
12
|
+
* heading level 1 → 2) — apply minimal AttrSteps (preserves the DOM
|
|
13
|
+
* element in incremental render mode).
|
|
14
|
+
* - If the block is a different type (e.g. paragraph → heading) — replace
|
|
15
|
+
* the block with a fresh node of `nodeType`, preserving the inline
|
|
16
|
+
* content. Attrs the new type shares with the old (e.g. `align`,
|
|
17
|
+
* `lineHeight`) are carried over.
|
|
18
|
+
*
|
|
19
|
+
* Cursor must be inside a top-level block (depth ≥ 1).
|
|
20
|
+
*/
|
|
21
|
+
export function setBlockType(nodeType, attrs = {}) {
|
|
22
|
+
return (state, dispatch) => {
|
|
23
|
+
const { from } = state.selection;
|
|
24
|
+
const rp = resolve(state.doc, from);
|
|
25
|
+
const d = findTopBlockDepth(rp);
|
|
26
|
+
if (d < 1)
|
|
27
|
+
return false;
|
|
28
|
+
const block = rp.node(d);
|
|
29
|
+
const sameType = block.type === nodeType;
|
|
30
|
+
if (sameType && Object.keys(attrs).every((k) => Object.is(block.attrs[k], attrs[k]))) {
|
|
31
|
+
return false;
|
|
32
|
+
}
|
|
33
|
+
if (!dispatch)
|
|
34
|
+
return true;
|
|
35
|
+
if (sameType) {
|
|
36
|
+
let tr = state.tr;
|
|
37
|
+
for (const key of Object.keys(attrs)) {
|
|
38
|
+
if (!Object.is(block.attrs[key], attrs[key])) {
|
|
39
|
+
tr = tr.step(new AttrStep(rp.before(d), key, attrs[key]));
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
if (tr.steps.length === 0)
|
|
43
|
+
return false;
|
|
44
|
+
dispatch(tr);
|
|
45
|
+
return true;
|
|
46
|
+
}
|
|
47
|
+
// Type change — rebuild the block.
|
|
48
|
+
const targetAttrSpec = (nodeType.spec.attrs ?? {});
|
|
49
|
+
const preserved = {};
|
|
50
|
+
for (const key of Object.keys(block.attrs)) {
|
|
51
|
+
if (key in targetAttrSpec)
|
|
52
|
+
preserved[key] = block.attrs[key];
|
|
53
|
+
}
|
|
54
|
+
const finalAttrs = { ...preserved, ...attrs };
|
|
55
|
+
const newBlock = state.schema.node(nodeType.name, finalAttrs, block.content);
|
|
56
|
+
const slice = new Slice(Fragment.from([newBlock]), 0, 0);
|
|
57
|
+
const blockStart = rp.before(d);
|
|
58
|
+
const tr = state.tr.step(new ReplaceStep(blockStart, rp.after(d), slice));
|
|
59
|
+
// Preserve the cursor's offset within the block. Without an explicit
|
|
60
|
+
// selectionOverride, the Replace step collapses positions inside the
|
|
61
|
+
// replaced range to the range start (between blocks), which would make
|
|
62
|
+
// subsequent block-level commands no-op (parent could lose block depth).
|
|
63
|
+
const parentOffset = Math.min(rp.parentOffset, block.content.size);
|
|
64
|
+
const newPos = blockStart + 1 + parentOffset;
|
|
65
|
+
tr.selectionOverride =
|
|
66
|
+
new TextSelection(newPos, newPos);
|
|
67
|
+
dispatch(tr);
|
|
68
|
+
return true;
|
|
69
|
+
};
|
|
70
|
+
}
|
|
71
|
+
/**
|
|
72
|
+
* Generic helper: set one attribute on the depth-1 block (paragraph/heading)
|
|
73
|
+
* containing the current selection. Returns a Command suitable for the toolbar.
|
|
74
|
+
*
|
|
75
|
+
* Used by setAlignment / setLineHeight; also reusable for any future block attr
|
|
76
|
+
* the schema declares (e.g. indent level, gutter color, etc.).
|
|
77
|
+
*/
|
|
78
|
+
export function setBlockAttr(attrName, value) {
|
|
79
|
+
return (state, dispatch) => {
|
|
80
|
+
const { from } = state.selection;
|
|
81
|
+
const rp = resolve(state.doc, from);
|
|
82
|
+
const d = findTopBlockDepth(rp);
|
|
83
|
+
if (d < 1)
|
|
84
|
+
return false;
|
|
85
|
+
const block = rp.node(d);
|
|
86
|
+
if (!(attrName in block.attrs))
|
|
87
|
+
return false;
|
|
88
|
+
if (Object.is(block.attrs[attrName], value))
|
|
89
|
+
return false;
|
|
90
|
+
if (!dispatch)
|
|
91
|
+
return true;
|
|
92
|
+
const tr = state.tr.step(new AttrStep(rp.before(d), attrName, value));
|
|
93
|
+
dispatch(tr);
|
|
94
|
+
return true;
|
|
95
|
+
};
|
|
96
|
+
}
|
|
97
|
+
/** Set the text-align attribute on the block containing the selection. */
|
|
98
|
+
export function setAlignment(value) {
|
|
99
|
+
return setBlockAttr('align', value);
|
|
100
|
+
}
|
|
101
|
+
/** Set the line-height multiplier on the block containing the selection. */
|
|
102
|
+
export function setLineHeight(value) {
|
|
103
|
+
return setBlockAttr('lineHeight', value);
|
|
104
|
+
}
|
|
105
|
+
/**
|
|
106
|
+
* Wrap the depth-1 block containing the cursor inside a fresh blockquote of
|
|
107
|
+
* `bqType`. Cursor is preserved at its inline offset — it crosses one extra
|
|
108
|
+
* [open] token (the blockquote's), so the absolute position shifts by +1.
|
|
109
|
+
*
|
|
110
|
+
* - Returns false if cursor depth < 1.
|
|
111
|
+
* - Returns false if any ancestor of the cursor is already a blockquote
|
|
112
|
+
* (we don't stack blockquotes).
|
|
113
|
+
*/
|
|
114
|
+
export function wrapInBlockquote(bqType) {
|
|
115
|
+
return (state, dispatch) => {
|
|
116
|
+
const { from, to } = state.selection;
|
|
117
|
+
const rp = resolve(state.doc, from);
|
|
118
|
+
const d = findTopBlockDepth(rp);
|
|
119
|
+
if (d < 1)
|
|
120
|
+
return false;
|
|
121
|
+
// Bail if any ancestor at or below depth d is already a blockquote — avoid
|
|
122
|
+
// stacking. (Looking only inside the current block-container; an outer
|
|
123
|
+
// blockquote at depth < d would belong to a different scope.)
|
|
124
|
+
for (let i = rp.depth; i >= d; i--) {
|
|
125
|
+
if (rp.node(i).type === bqType)
|
|
126
|
+
return false;
|
|
127
|
+
}
|
|
128
|
+
if (!dispatch)
|
|
129
|
+
return true;
|
|
130
|
+
const block = rp.node(d);
|
|
131
|
+
const newBq = state.schema.node(bqType.name, null, [block]);
|
|
132
|
+
const slice = new Slice(Fragment.from([newBq]), 0, 0);
|
|
133
|
+
const tr = state.tr.step(new ReplaceStep(rp.before(d), rp.after(d), slice));
|
|
134
|
+
tr.selectionOverride =
|
|
135
|
+
new TextSelection(from + 1, to + 1);
|
|
136
|
+
dispatch(tr);
|
|
137
|
+
return true;
|
|
138
|
+
};
|
|
139
|
+
}
|
|
140
|
+
/**
|
|
141
|
+
* Insert a new `hrType` block as a sibling immediately after the depth-1
|
|
142
|
+
* block containing the cursor, followed by a fresh empty paragraph. The
|
|
143
|
+
* cursor lands at the start of the trailing paragraph.
|
|
144
|
+
*
|
|
145
|
+
* If `state.schema.nodes.paragraph` is missing, fall back to inserting just
|
|
146
|
+
* the hr (cursor at `rp.after(1)`).
|
|
147
|
+
*
|
|
148
|
+
* - Returns false if cursor depth < 1.
|
|
149
|
+
*/
|
|
150
|
+
export function insertHr(hrType) {
|
|
151
|
+
return (state, dispatch) => {
|
|
152
|
+
const rp = resolve(state.doc, state.selection.from);
|
|
153
|
+
const d = findTopBlockDepth(rp);
|
|
154
|
+
if (d < 1)
|
|
155
|
+
return false;
|
|
156
|
+
if (!dispatch)
|
|
157
|
+
return true;
|
|
158
|
+
const insertAt = rp.after(d);
|
|
159
|
+
const hr = state.schema.node(hrType.name, null);
|
|
160
|
+
const paragraphType = state.schema.nodes.paragraph;
|
|
161
|
+
const inserted = paragraphType
|
|
162
|
+
? [hr, state.schema.node(paragraphType.name, null)]
|
|
163
|
+
: [hr];
|
|
164
|
+
const slice = new Slice(Fragment.from(inserted), 0, 0);
|
|
165
|
+
const tr = state.tr.step(new ReplaceStep(insertAt, insertAt, slice));
|
|
166
|
+
// Cursor: at the start of the trailing paragraph's content. The trailing
|
|
167
|
+
// paragraph's [open] sits at `insertAt + hr.nodeSize`; its content starts
|
|
168
|
+
// one position later.
|
|
169
|
+
const cursor = paragraphType ? insertAt + hr.nodeSize + 1 : insertAt;
|
|
170
|
+
tr.selectionOverride =
|
|
171
|
+
new TextSelection(cursor, cursor);
|
|
172
|
+
dispatch(tr);
|
|
173
|
+
return true;
|
|
174
|
+
};
|
|
175
|
+
}
|
|
176
|
+
/**
|
|
177
|
+
* Insert a `page_break` block at the cursor (as a sibling AFTER the current
|
|
178
|
+
* top-level block), followed by a fresh empty paragraph. Cursor lands at
|
|
179
|
+
* the start of the trailing paragraph so the user can immediately type on
|
|
180
|
+
* the new page.
|
|
181
|
+
*
|
|
182
|
+
* Behavior mirrors `insertHr`. Returns false if the schema lacks
|
|
183
|
+
* `page_break` or cursor depth < 1.
|
|
184
|
+
*/
|
|
185
|
+
export function insertPageBreak(pbType) {
|
|
186
|
+
return (state, dispatch) => {
|
|
187
|
+
const rp = resolve(state.doc, state.selection.from);
|
|
188
|
+
if (rp.depth < 1)
|
|
189
|
+
return false;
|
|
190
|
+
if (!dispatch)
|
|
191
|
+
return true;
|
|
192
|
+
const topD = findTopBlockDepth(rp);
|
|
193
|
+
const insertAt = rp.after(topD);
|
|
194
|
+
const pb = state.schema.node(pbType.name, null);
|
|
195
|
+
const paragraphType = state.schema.nodes.paragraph;
|
|
196
|
+
const inserted = paragraphType
|
|
197
|
+
? [pb, state.schema.node(paragraphType.name, null)]
|
|
198
|
+
: [pb];
|
|
199
|
+
const slice = new Slice(Fragment.from(inserted), 0, 0);
|
|
200
|
+
const tr = state.tr.step(new ReplaceStep(insertAt, insertAt, slice));
|
|
201
|
+
const cursor = paragraphType ? insertAt + pb.nodeSize + 1 : insertAt + pb.nodeSize;
|
|
202
|
+
tr.selectionOverride =
|
|
203
|
+
new TextSelection(cursor, cursor);
|
|
204
|
+
dispatch(tr);
|
|
205
|
+
return true;
|
|
206
|
+
};
|
|
207
|
+
}
|
|
208
|
+
//# sourceMappingURL=block-commands.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"block-commands.js","sourceRoot":"","sources":["../../src/commands/block-commands.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import type { EditorState } from '../state/editor-state.js';
|
|
2
|
+
import type { Transaction } from '../transform/transaction.js';
|
|
3
|
+
/**
|
|
4
|
+
* Command — dual-mode operation:
|
|
5
|
+
* - Called WITHOUT dispatch: returns true iff applicable. Pure query.
|
|
6
|
+
* - Called WITH dispatch: returns true iff applied; dispatches a Transaction.
|
|
7
|
+
*/
|
|
8
|
+
export type Command = (state: EditorState, dispatch?: (tr: Transaction) => void) => boolean;
|
|
9
|
+
/**
|
|
10
|
+
* Chain commands. The first one that returns true short-circuits the chain.
|
|
11
|
+
*/
|
|
12
|
+
export declare function chain(...cmds: ReadonlyArray<Command>): Command;
|
|
13
|
+
//# sourceMappingURL=command.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"command.d.ts","sourceRoot":"","sources":["../../src/commands/command.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,0BAA0B,CAAA;AAC3D,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,6BAA6B,CAAA;AAE9D;;;;GAIG;AACH,MAAM,MAAM,OAAO,GAAG,CAAC,KAAK,EAAE,WAAW,EAAE,QAAQ,CAAC,EAAE,CAAC,EAAE,EAAE,WAAW,KAAK,IAAI,KAAK,OAAO,CAAA;AAE3F;;GAEG;AACH,wBAAgB,KAAK,CAAC,GAAG,IAAI,EAAE,aAAa,CAAC,OAAO,CAAC,GAAG,OAAO,CAO9D"}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Chain commands. The first one that returns true short-circuits the chain.
|
|
3
|
+
*/
|
|
4
|
+
export function chain(...cmds) {
|
|
5
|
+
return (state, dispatch) => {
|
|
6
|
+
for (const cmd of cmds) {
|
|
7
|
+
if (cmd(state, dispatch))
|
|
8
|
+
return true;
|
|
9
|
+
}
|
|
10
|
+
return false;
|
|
11
|
+
};
|
|
12
|
+
}
|
|
13
|
+
//# sourceMappingURL=command.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"command.js","sourceRoot":"","sources":["../../src/commands/command.ts"],"names":[],"mappings":"AAUA;;GAEG;AACH,MAAM,UAAU,KAAK,CAAC,GAAG,IAA4B;IACnD,OAAO,CAAC,KAAK,EAAE,QAAQ,EAAE,EAAE;QACzB,KAAK,MAAM,GAAG,IAAI,IAAI,EAAE,CAAC;YACvB,IAAI,GAAG,CAAC,KAAK,EAAE,QAAQ,CAAC;gBAAE,OAAO,IAAI,CAAA;QACvC,CAAC;QACD,OAAO,KAAK,CAAA;IACd,CAAC,CAAA;AACH,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"edit-commands.d.ts","sourceRoot":"","sources":["../../src/commands/edit-commands.ts"],"names":[],"mappings":"AASA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,cAAc,CAAA;AAE3C,eAAO,MAAM,eAAe,EAAE,OA+D7B,CAAA;AAqBD,eAAO,MAAM,YAAY,EAAE,OAsB1B,CAAA;AAED,eAAO,MAAM,UAAU,EAAE,OAuBxB,CAAA"}
|
|
@@ -0,0 +1,147 @@
|
|
|
1
|
+
import { Fragment } from '../model/fragment.js';
|
|
2
|
+
import { DxNode } from '../model/node.js';
|
|
3
|
+
import { findTopBlockDepth, resolve } from '../model/position.js';
|
|
4
|
+
import { Slice } from '../model/slice.js';
|
|
5
|
+
import { tableGrid } from '../model/table-grid.js';
|
|
6
|
+
import { CellSelection } from '../state/cell-selection.js';
|
|
7
|
+
import { TextSelection } from '../state/text-selection.js';
|
|
8
|
+
import { ReplaceStep } from '../transform/replace-step.js';
|
|
9
|
+
export const deleteSelection = (state, dispatch) => {
|
|
10
|
+
if (state.selection instanceof CellSelection) {
|
|
11
|
+
const sel = state.selection;
|
|
12
|
+
// Locate the containing table via the anchor cell's position.
|
|
13
|
+
const located = findTableForCellPos(state.doc, sel.anchorCell);
|
|
14
|
+
if (!located)
|
|
15
|
+
return false;
|
|
16
|
+
if (!dispatch)
|
|
17
|
+
return true;
|
|
18
|
+
const { tableStart, table } = located;
|
|
19
|
+
const grid = tableGrid(table, tableStart);
|
|
20
|
+
const anchor = grid.byPos(sel.anchorCell);
|
|
21
|
+
const head = grid.byPos(sel.headCell);
|
|
22
|
+
if (!anchor || !head)
|
|
23
|
+
return false;
|
|
24
|
+
// Compute the rectangle (extended to include spans of corner cells).
|
|
25
|
+
const r0 = Math.min(anchor.row, head.row);
|
|
26
|
+
const c0 = Math.min(anchor.col, head.col);
|
|
27
|
+
const r1 = Math.max(anchor.row + anchor.rowspan - 1, head.row + head.rowspan - 1);
|
|
28
|
+
const c1 = Math.max(anchor.col + anchor.colspan - 1, head.col + head.colspan - 1);
|
|
29
|
+
// Collect masters whose master coords lie in the rect. Replace each
|
|
30
|
+
// cell's CONTENT with a single empty paragraph, walking in reverse
|
|
31
|
+
// document order so earlier step positions remain valid.
|
|
32
|
+
const cellsInRect = grid.cells
|
|
33
|
+
.filter((c) => c.row >= r0 && c.row <= r1 && c.col >= c0 && c.col <= c1)
|
|
34
|
+
.sort((a, b) => b.pos - a.pos);
|
|
35
|
+
const emptyParagraph = state.schema.node('paragraph', null);
|
|
36
|
+
const emptySlice = new Slice(Fragment.from([emptyParagraph]), 0, 0);
|
|
37
|
+
let tr = state.tr;
|
|
38
|
+
for (const c of cellsInRect) {
|
|
39
|
+
const cellOpen = c.pos;
|
|
40
|
+
const cellNode = c.node;
|
|
41
|
+
// Cell content occupies (cellOpen+1, cellOpen+1+content.size). Replace
|
|
42
|
+
// it with a single empty paragraph.
|
|
43
|
+
const contentStart = cellOpen + 1;
|
|
44
|
+
const contentEnd = contentStart + cellNode.content.size;
|
|
45
|
+
tr = tr.step(new ReplaceStep(contentStart, contentEnd, emptySlice));
|
|
46
|
+
}
|
|
47
|
+
// Cursor target: first inline of the top-left cell (anchor's master if it
|
|
48
|
+
// is the rect's top-left, otherwise the first cell in document order in
|
|
49
|
+
// the rect after the operation). We use the smallest pos cell after the
|
|
50
|
+
// delete; positions of cells don't shift because each replacement keeps
|
|
51
|
+
// the same cell-content size delta (the replaced range may shrink, and
|
|
52
|
+
// earlier cells aren't affected by later ones since we walked in reverse).
|
|
53
|
+
const topLeft = grid.cells
|
|
54
|
+
.filter((c) => c.row >= r0 && c.row <= r1 && c.col >= c0 && c.col <= c1)
|
|
55
|
+
.sort((a, b) => a.pos - b.pos)[0];
|
|
56
|
+
if (topLeft) {
|
|
57
|
+
// After replacement: cell[open] at topLeft.pos, then paragraph[open] at
|
|
58
|
+
// topLeft.pos + 1, content at topLeft.pos + 2.
|
|
59
|
+
;
|
|
60
|
+
tr.selectionOverride =
|
|
61
|
+
new TextSelection(topLeft.pos + 2, topLeft.pos + 2);
|
|
62
|
+
}
|
|
63
|
+
dispatch(tr);
|
|
64
|
+
return true;
|
|
65
|
+
}
|
|
66
|
+
const { from, to } = state.selection;
|
|
67
|
+
if (from === to)
|
|
68
|
+
return false;
|
|
69
|
+
if (!dispatch)
|
|
70
|
+
return true;
|
|
71
|
+
dispatch(state.tr.step(new ReplaceStep(from, to, Slice.empty)));
|
|
72
|
+
return true;
|
|
73
|
+
};
|
|
74
|
+
/** Walk up from a cell's [open] position to find the enclosing table. */
|
|
75
|
+
function findTableForCellPos(doc, cellPos) {
|
|
76
|
+
let rp;
|
|
77
|
+
try {
|
|
78
|
+
rp = resolve(doc, cellPos + 1);
|
|
79
|
+
}
|
|
80
|
+
catch {
|
|
81
|
+
return null;
|
|
82
|
+
}
|
|
83
|
+
for (let d = rp.depth; d >= 1; d--) {
|
|
84
|
+
if (rp.node(d).type.name === 'table') {
|
|
85
|
+
return { tableStart: rp.before(d), table: rp.node(d) };
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
return null;
|
|
89
|
+
}
|
|
90
|
+
export const joinBackward = (state, dispatch) => {
|
|
91
|
+
const { from, to } = state.selection;
|
|
92
|
+
if (from !== to)
|
|
93
|
+
return false;
|
|
94
|
+
const rp = resolve(state.doc, from);
|
|
95
|
+
// Cursor must be at the start of a top-level block's content (parentOffset
|
|
96
|
+
// === 0) AND there must be a previous sibling block at the same level.
|
|
97
|
+
const d = findTopBlockDepth(rp);
|
|
98
|
+
if (d < 1)
|
|
99
|
+
return false;
|
|
100
|
+
// We only join when the cursor sits directly inside the top block (so we
|
|
101
|
+
// know parentOffset of 0 means "at content start of the block"). If the
|
|
102
|
+
// resolved depth is deeper than d (e.g., cursor inside a nested mark/inline
|
|
103
|
+
// wrapper that doesn't exist today, but be defensive), bail.
|
|
104
|
+
if (rp.depth !== d)
|
|
105
|
+
return false;
|
|
106
|
+
if (rp.parentOffset !== 0)
|
|
107
|
+
return false;
|
|
108
|
+
const blockIdx = rp.index(d);
|
|
109
|
+
if (blockIdx <= 0)
|
|
110
|
+
return false;
|
|
111
|
+
// Compute the end-of-content position of the previous sibling block.
|
|
112
|
+
// The previous block's content ends at (its close token - 1) = rp.before(d) - 1.
|
|
113
|
+
const prevEnd = rp.before(d) - 1;
|
|
114
|
+
if (!dispatch)
|
|
115
|
+
return true;
|
|
116
|
+
dispatch(state.tr.step(new ReplaceStep(prevEnd, from, Slice.empty)));
|
|
117
|
+
return true;
|
|
118
|
+
};
|
|
119
|
+
export const splitBlock = (state, dispatch) => {
|
|
120
|
+
const { from, to } = state.selection;
|
|
121
|
+
if (from !== to)
|
|
122
|
+
return false;
|
|
123
|
+
const rp = resolve(state.doc, from);
|
|
124
|
+
const d = findTopBlockDepth(rp);
|
|
125
|
+
if (d < 1)
|
|
126
|
+
return false;
|
|
127
|
+
if (rp.depth !== d)
|
|
128
|
+
return false;
|
|
129
|
+
if (!dispatch)
|
|
130
|
+
return true;
|
|
131
|
+
const block = rp.parent;
|
|
132
|
+
const head = block.cut(0, rp.parentOffset);
|
|
133
|
+
const tail = block.cut(rp.parentOffset, block.content.size);
|
|
134
|
+
const blockStart = rp.before(d);
|
|
135
|
+
const blockEnd = rp.after(d);
|
|
136
|
+
const slice = new Slice(Fragment.from([head, tail]), 0, 0);
|
|
137
|
+
const tr = state.tr.step(new ReplaceStep(blockStart, blockEnd, slice));
|
|
138
|
+
// Place the cursor at the start of the new tail block. The tail block's
|
|
139
|
+
// [open] token sits at: blockStart + head.nodeSize. Its first inside
|
|
140
|
+
// position is one past that.
|
|
141
|
+
const tailStart = blockStart + head.nodeSize + 1;
|
|
142
|
+
tr.selectionOverride =
|
|
143
|
+
new TextSelection(tailStart, tailStart);
|
|
144
|
+
dispatch(tr);
|
|
145
|
+
return true;
|
|
146
|
+
};
|
|
147
|
+
//# sourceMappingURL=edit-commands.js.map
|