creo-edit 0.1.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.
Files changed (75) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +169 -0
  3. package/dist/clipboard/drop.d.ts +17 -0
  4. package/dist/clipboard/htmlParser.d.ts +18 -0
  5. package/dist/clipboard/htmlSerializer.d.ts +9 -0
  6. package/dist/commands/imageCommands.d.ts +32 -0
  7. package/dist/commands/insertCommands.d.ts +33 -0
  8. package/dist/commands/listCommands.d.ts +19 -0
  9. package/dist/commands/markCommands.d.ts +21 -0
  10. package/dist/commands/navigationCommands.d.ts +27 -0
  11. package/dist/commands/structuralCommands.d.ts +22 -0
  12. package/dist/commands/textCommands.d.ts +18 -0
  13. package/dist/controller/history.d.ts +31 -0
  14. package/dist/controller/navigation.d.ts +18 -0
  15. package/dist/controller/selection.d.ts +25 -0
  16. package/dist/controller/wordBoundary.d.ts +25 -0
  17. package/dist/createEditor.d.ts +252 -0
  18. package/dist/dom/anchorMap.d.ts +27 -0
  19. package/dist/index.d.ts +34 -0
  20. package/dist/index.js +7833 -0
  21. package/dist/index.js.map +72 -0
  22. package/dist/input/keymap.d.ts +47 -0
  23. package/dist/input/mobile.d.ts +13 -0
  24. package/dist/input/nativeInput.d.ts +27 -0
  25. package/dist/markdown/serialize.d.ts +2 -0
  26. package/dist/model/blockText.d.ts +42 -0
  27. package/dist/model/cellAccess.d.ts +2 -0
  28. package/dist/model/doc.d.ts +45 -0
  29. package/dist/model/fractional.d.ts +57 -0
  30. package/dist/model/rebalance.d.ts +12 -0
  31. package/dist/model/types.d.ts +133 -0
  32. package/dist/plugin/anchorCodec.d.ts +18 -0
  33. package/dist/plugin/atomic.d.ts +2 -0
  34. package/dist/plugin/builtin.d.ts +10 -0
  35. package/dist/plugin/decorations.d.ts +35 -0
  36. package/dist/plugin/htmlCodec.d.ts +8 -0
  37. package/dist/plugin/keymapMatch.d.ts +2 -0
  38. package/dist/plugin/registry.d.ts +29 -0
  39. package/dist/plugin/runsAt.d.ts +9 -0
  40. package/dist/plugin/serializeCodec.d.ts +6 -0
  41. package/dist/plugin/triggers.d.ts +33 -0
  42. package/dist/plugin/types.d.ts +188 -0
  43. package/dist/plugins/add-block/index.d.ts +17 -0
  44. package/dist/plugins/calendar/index.d.ts +7 -0
  45. package/dist/plugins/calendar/view.d.ts +29 -0
  46. package/dist/plugins/cells/codecs.d.ts +6 -0
  47. package/dist/plugins/cells/commands.d.ts +5 -0
  48. package/dist/plugins/cells/controls.d.ts +3 -0
  49. package/dist/plugins/cells/htmlCodec.d.ts +6 -0
  50. package/dist/plugins/cells/index.d.ts +3 -0
  51. package/dist/plugins/cells/views.d.ts +27 -0
  52. package/dist/plugins/drag-handle/index.d.ts +6 -0
  53. package/dist/plugins/infinite-scroll/index.d.ts +44 -0
  54. package/dist/plugins/md-shortcuts/index.d.ts +2 -0
  55. package/dist/plugins/search/engine.d.ts +33 -0
  56. package/dist/plugins/search/highlight.d.ts +13 -0
  57. package/dist/plugins/search/index.d.ts +5 -0
  58. package/dist/plugins/search/navigate.d.ts +15 -0
  59. package/dist/plugins/search/styles.d.ts +1 -0
  60. package/dist/plugins/search/types.d.ts +73 -0
  61. package/dist/plugins/search/ui.d.ts +2 -0
  62. package/dist/plugins/slash/index.d.ts +12 -0
  63. package/dist/plugins/slash/items.d.ts +21 -0
  64. package/dist/plugins/slash/menu.d.ts +17 -0
  65. package/dist/plugins/styles.css +233 -0
  66. package/dist/render/DocView.d.ts +7 -0
  67. package/dist/render/InlineRunsView.d.ts +7 -0
  68. package/dist/render/blocks/CodeBlockView.d.ts +7 -0
  69. package/dist/render/blocks/HeadingView.d.ts +7 -0
  70. package/dist/render/blocks/ImageView.d.ts +8 -0
  71. package/dist/render/blocks/ListItemView.d.ts +7 -0
  72. package/dist/render/blocks/ParagraphView.d.ts +7 -0
  73. package/dist/virtual/VirtualDoc.d.ts +28 -0
  74. package/dist/virtual/heightIndex.d.ts +36 -0
  75. package/package.json +53 -0
@@ -0,0 +1,233 @@
1
+ /* ---------------------------------------------------------------------------
2
+ Default stylesheet for first-party creo-edit plugins.
3
+
4
+ This file ships with the package but is NOT auto-loaded — consumers
5
+ import it explicitly:
6
+
7
+ import "creo-edit/dist/plugins/styles.css";
8
+
9
+ …or copy these rules into their own stylesheet to customize. The plugin
10
+ code only sets the minimum styles required for layout/positioning;
11
+ appearance is fully overridable here.
12
+
13
+ Class reference:
14
+ .creo-slash, .creo-slash-item, .creo-slash-item.is-active,
15
+ .creo-slash-item-title, .creo-slash-item-desc, .creo-slash-empty
16
+ .ce-decorations
17
+ .ce-deco, .ce-deco-{plugin-id}, .ce-deco-layer-{layer}
18
+ .ce-drag-btn, .ce-drag-btn.is-visible, .ce-drag-ghost,
19
+ .ce-drag-indicator
20
+ .ce-add-block-btn, .ce-add-block-btn.is-visible
21
+ --------------------------------------------------------------------------- */
22
+
23
+ /* ============= Slash menu ============= */
24
+ .creo-slash {
25
+ min-width: 240px;
26
+ max-height: 320px;
27
+ overflow-y: auto;
28
+ background: white;
29
+ border: 1px solid #d0d0d0;
30
+ border-radius: 6px;
31
+ box-shadow: 0 6px 20px rgba(0, 0, 0, 0.12);
32
+ padding: 4px;
33
+ font-family: system-ui, -apple-system, BlinkMacSystemFont, sans-serif;
34
+ font-size: 14px;
35
+ color: #1a1a1a;
36
+ }
37
+ .creo-slash-item {
38
+ padding: 6px 10px;
39
+ border-radius: 4px;
40
+ cursor: pointer;
41
+ }
42
+ .creo-slash-item.is-active {
43
+ background: #eef4ff;
44
+ }
45
+ .creo-slash-item-title {
46
+ font-weight: 500;
47
+ }
48
+ .creo-slash-item-desc {
49
+ color: #666;
50
+ font-size: 12px;
51
+ }
52
+ .creo-slash-empty {
53
+ padding: 8px;
54
+ color: #888;
55
+ }
56
+
57
+ /* ============= Decorations layer ============= */
58
+ .ce-decorations {
59
+ /* Functional positioning is set by the manager; nothing else needed. */
60
+ }
61
+
62
+ /* ============= Drag handle ============= */
63
+ .ce-drag-btn {
64
+ display: block;
65
+ width: 100%;
66
+ height: 100%;
67
+ border: none;
68
+ background: transparent;
69
+ color: #aaa;
70
+ font-size: 16px;
71
+ user-select: none;
72
+ opacity: 0;
73
+ transition: opacity 0.1s ease;
74
+ }
75
+ .ce-drag-btn.is-visible {
76
+ opacity: 1;
77
+ }
78
+ .ce-drag-btn:hover {
79
+ color: #555;
80
+ }
81
+ .ce-drag-ghost {
82
+ opacity: 0.85;
83
+ background: white;
84
+ box-shadow: 0 8px 24px rgba(0, 0, 0, 0.18);
85
+ border-radius: 4px;
86
+ transform: rotate(-1deg);
87
+ cursor: grabbing;
88
+ }
89
+ .ce-drag-indicator {
90
+ height: 3px;
91
+ background: #3b82f6;
92
+ border-radius: 2px;
93
+ box-shadow: 0 0 6px rgba(59, 130, 246, 0.6);
94
+ }
95
+ .ce-drag-indicator.is-vertical {
96
+ /* When the indicator marks a side-drop (left/right) the manager sets
97
+ `width` empty and `height` to the block height; we just need a fixed
98
+ bar width to make the line visible. */
99
+ width: 3px;
100
+ height: auto;
101
+ }
102
+
103
+ /* ============= Date marker (atomic block) =============
104
+ Slim one-line non-editable separator block. Used by journal-style
105
+ layouts where the user writes editable content between days. */
106
+ .creo-edit .ce-date-marker {
107
+ display: block;
108
+ padding: 4px 0 6px;
109
+ margin: 12px 0 4px;
110
+ font-family: system-ui, -apple-system, BlinkMacSystemFont, sans-serif;
111
+ font-size: 18px;
112
+ font-weight: 600;
113
+ letter-spacing: -0.01em;
114
+ color: var(--ce-date-marker-fg, #1a1a1a);
115
+ cursor: default;
116
+ user-select: none;
117
+ }
118
+ .creo-edit .ce-date-marker.is-today {
119
+ color: var(--ce-date-marker-today-fg, #b54708);
120
+ }
121
+
122
+ /* ============= Calendar (atomic block) =============
123
+ Renders one row per day; the row matching today's local date gets the
124
+ `is-today` class for accent styling. Outer block uses pointer:default
125
+ because contenteditable=false should not show the I-beam from the
126
+ editor root. */
127
+ .creo-edit .ce-calendar {
128
+ display: block;
129
+ border: 1px solid var(--ce-cal-border, #d6d6d6);
130
+ border-radius: 6px;
131
+ padding: 8px 10px;
132
+ margin: 8px 0;
133
+ font-family: system-ui, -apple-system, BlinkMacSystemFont, sans-serif;
134
+ font-size: 13px;
135
+ cursor: default;
136
+ user-select: none;
137
+ }
138
+ .creo-edit .ce-calendar-header {
139
+ font-weight: 600;
140
+ font-size: 12px;
141
+ text-transform: uppercase;
142
+ letter-spacing: 0.04em;
143
+ color: var(--ce-cal-header, #888);
144
+ margin-bottom: 4px;
145
+ }
146
+ .creo-edit .ce-calendar-row {
147
+ display: flex;
148
+ gap: 12px;
149
+ padding: 4px 6px;
150
+ border-radius: 4px;
151
+ }
152
+ .creo-edit .ce-calendar-row.is-today {
153
+ background: var(--ce-cal-today-bg, #fff7e6);
154
+ color: var(--ce-cal-today-fg, #b54708);
155
+ font-weight: 600;
156
+ }
157
+ .creo-edit .ce-calendar-dow {
158
+ width: 3.5em;
159
+ color: var(--ce-cal-dow, #666);
160
+ }
161
+ .creo-edit .ce-calendar-row.is-today .ce-calendar-dow {
162
+ color: inherit;
163
+ }
164
+ .creo-edit .ce-sr-only {
165
+ position: absolute;
166
+ width: 1px;
167
+ height: 1px;
168
+ padding: 0;
169
+ margin: -1px;
170
+ overflow: hidden;
171
+ clip: rect(0, 0, 0, 0);
172
+ white-space: nowrap;
173
+ border: 0;
174
+ }
175
+
176
+ /* ============= Column line layout =============
177
+ Columns render one .ce-col-line div per visual line so an empty trailing
178
+ line (e.g. right after pressing Enter) still has height for the caret to
179
+ land on. Without `min-height`, a trailing `\n` collapses to zero pixels
180
+ and pressing Enter once appears to do nothing. */
181
+ .creo-edit .ce-col-line {
182
+ display: block;
183
+ min-height: 1.4em;
184
+ }
185
+
186
+ /* ============= Table / columns controls ============= */
187
+ .ce-cells-toolbar {
188
+ display: none;
189
+ flex-direction: row;
190
+ gap: 4px;
191
+ padding: 2px;
192
+ background: white;
193
+ border: 1px solid #d0d0d0;
194
+ border-radius: 6px;
195
+ box-shadow: 0 4px 12px rgba(0, 0, 0, 0.08);
196
+ font-family: system-ui, -apple-system, BlinkMacSystemFont, sans-serif;
197
+ font-size: 12px;
198
+ user-select: none;
199
+ }
200
+ .ce-cells-ctl {
201
+ border: none;
202
+ background: transparent;
203
+ color: #444;
204
+ padding: 4px 8px;
205
+ border-radius: 4px;
206
+ cursor: pointer;
207
+ font-size: 12px;
208
+ white-space: nowrap;
209
+ }
210
+ .ce-cells-ctl:hover {
211
+ background: #eef4ff;
212
+ color: #1a1a1a;
213
+ }
214
+
215
+ /* ============= Add-block button ============= */
216
+ .ce-add-block-btn {
217
+ display: block;
218
+ width: 100%;
219
+ height: 100%;
220
+ border: none;
221
+ background: transparent;
222
+ color: #888;
223
+ font-size: 20px;
224
+ cursor: pointer;
225
+ opacity: 0;
226
+ transition: opacity 0.1s ease;
227
+ }
228
+ .ce-add-block-btn.is-visible {
229
+ opacity: 1;
230
+ }
231
+ .ce-add-block-btn:hover {
232
+ color: #333;
233
+ }
@@ -0,0 +1,7 @@
1
+ import type { DocState } from "../model/types";
2
+ export declare const DocView: (props: {
3
+ doc: DocState;
4
+ } & {
5
+ key?: import("creo").Key;
6
+ ref?: import("creo").Ref<void> | undefined;
7
+ }, slot?: import("creo").SlotContent) => void;
@@ -0,0 +1,7 @@
1
+ import type { InlineRun } from "../model/types";
2
+ export declare const InlineRunsView: (props: {
3
+ runs: InlineRun[];
4
+ } & {
5
+ key?: import("creo").Key;
6
+ ref?: import("creo").Ref<void> | undefined;
7
+ }, slot?: import("creo").SlotContent) => void;
@@ -0,0 +1,7 @@
1
+ import type { CodeBlock } from "../../model/types";
2
+ export declare const CodeBlockView: (props: {
3
+ block: CodeBlock;
4
+ } & {
5
+ key?: import("creo").Key;
6
+ ref?: import("creo").Ref<void> | undefined;
7
+ }, slot?: import("creo").SlotContent) => void;
@@ -0,0 +1,7 @@
1
+ import type { HeadingBlock } from "../../model/types";
2
+ export declare const HeadingView: (props: {
3
+ block: HeadingBlock;
4
+ } & {
5
+ key?: import("creo").Key;
6
+ ref?: import("creo").Ref<void> | undefined;
7
+ }, slot?: import("creo").SlotContent) => void;
@@ -0,0 +1,8 @@
1
+ import type { ImageBlock } from "../../model/types";
2
+ export declare const ImageView: (props: {
3
+ block: ImageBlock;
4
+ selected?: boolean;
5
+ } & {
6
+ key?: import("creo").Key;
7
+ ref?: import("creo").Ref<void> | undefined;
8
+ }, slot?: import("creo").SlotContent) => void;
@@ -0,0 +1,7 @@
1
+ import type { ListItemBlock } from "../../model/types";
2
+ export declare const ListItemView: (props: {
3
+ block: ListItemBlock;
4
+ } & {
5
+ key?: import("creo").Key;
6
+ ref?: import("creo").Ref<void> | undefined;
7
+ }, slot?: import("creo").SlotContent) => void;
@@ -0,0 +1,7 @@
1
+ import type { ParagraphBlock } from "../../model/types";
2
+ export declare const ParagraphView: (props: {
3
+ block: ParagraphBlock;
4
+ } & {
5
+ key?: import("creo").Key;
6
+ ref?: import("creo").Ref<void> | undefined;
7
+ }, slot?: import("creo").SlotContent) => void;
@@ -0,0 +1,28 @@
1
+ import type { Store } from "creo";
2
+ import type { DocState, Selection } from "../model/types";
3
+ /**
4
+ * VirtualDoc — windowed renderer that mounts only the blocks intersecting
5
+ * `[scrollTop − overscan, scrollTop + viewport + overscan]`.
6
+ *
7
+ * - Heights are measured per block via ResizeObserver and pushed into a
8
+ * Fenwick tree (`HeightIndex`) for O(log n) y-position lookups.
9
+ * - Top / bottom spacer divs absorb the off-screen height so the scrollbar
10
+ * behaves as if the whole document is rendered.
11
+ * - The block containing the caret is ALWAYS rendered, even when off-screen.
12
+ * Without this guarantee the caret overlay (which queries DOM) would lose
13
+ * its anchor when the user scrolls away with a selection.
14
+ */
15
+ export type VirtualDocProps = {
16
+ docStore: Store<DocState>;
17
+ selStore: Store<Selection>;
18
+ /** Estimated default height in px for unmeasured blocks. */
19
+ estimatedHeight?: number;
20
+ /** Overscan factor — multiplied by viewport height for top/bottom slack. */
21
+ overscan?: number;
22
+ /** Optional fixed viewport height (else read from window.innerHeight). */
23
+ viewportHeight?: number;
24
+ };
25
+ export declare const VirtualDoc: (props: VirtualDocProps & {
26
+ key?: import("creo").Key;
27
+ ref?: import("creo").Ref<void> | undefined;
28
+ }, slot?: import("creo").SlotContent) => void;
@@ -0,0 +1,36 @@
1
+ /**
2
+ * HeightIndex — a Fenwick (binary indexed) tree over per-block heights so
3
+ * that:
4
+ * - prefix(i) — sum of heights[0..i) in O(log n)
5
+ * - setHeight(i, h) — replace heights[i] with h in O(log n)
6
+ * - findIndexAtY(y) — first i s.t. prefix(i+1) > y in O(log n)
7
+ *
8
+ * Combined with an `estimatedHeight` for unmeasured blocks, this gives us
9
+ * an O(log n) viewport-window resolver for arbitrary scroll positions even
10
+ * before every block has been measured.
11
+ */
12
+ export declare class HeightIndex {
13
+ #private;
14
+ constructor(count: number, estimatedHeight: number);
15
+ get size(): number;
16
+ /** Replace the height at `i` with `h`. O(log n). */
17
+ setHeight(i: number, h: number): void;
18
+ /** Prefix sum of heights for indices [0, i). */
19
+ prefix(i: number): number;
20
+ /** Total height of all blocks. */
21
+ total(): number;
22
+ /**
23
+ * Find the smallest index i such that prefix(i+1) > y. Returns the
24
+ * floor index for y in [0, total()); for y >= total() returns n - 1.
25
+ * For empty trees returns 0 (caller should also check size).
26
+ */
27
+ findIndexAtY(y: number): number;
28
+ /** Append `count` new blocks at the end, all unmeasured. */
29
+ grow(count: number): void;
30
+ /**
31
+ * Resize to exactly `count` blocks. Loses tail measurements when
32
+ * shrinking; preserves them when growing. Always rebuilds the BIT from
33
+ * scratch (cheap — O(n log n) and called rarely).
34
+ */
35
+ resize(count: number): void;
36
+ }
package/package.json ADDED
@@ -0,0 +1,53 @@
1
+ {
2
+ "name": "creo-edit",
3
+ "version": "0.1.0",
4
+ "description": "Row-based rich-text editor framework on a controlled contentEditable, built on Creo. Cursor state separate from document state, CRDT-friendly fractional row ordering, O(1) per-keystroke renders, optional virtualization, first-class mobile.",
5
+ "type": "module",
6
+ "license": "MIT",
7
+ "author": "Nik (xnim.me)",
8
+ "homepage": "https://github.com/xnimorz/creo-editor#readme",
9
+ "repository": {
10
+ "type": "git",
11
+ "url": "git+https://github.com/xnimorz/creo-editor.git"
12
+ },
13
+ "bugs": {
14
+ "url": "https://github.com/xnimorz/creo-editor/issues"
15
+ },
16
+ "keywords": [
17
+ "editor",
18
+ "rich-text",
19
+ "contenteditable",
20
+ "wysiwyg",
21
+ "creo",
22
+ "text-editor",
23
+ "virtualization"
24
+ ],
25
+ "main": "dist/index.js",
26
+ "module": "dist/index.js",
27
+ "types": "dist/index.d.ts",
28
+ "exports": {
29
+ ".": {
30
+ "types": "./dist/index.d.ts",
31
+ "import": "./dist/index.js"
32
+ },
33
+ "./plugins/styles.css": "./dist/plugins/styles.css",
34
+ "./package.json": "./package.json"
35
+ },
36
+ "files": [
37
+ "dist"
38
+ ],
39
+ "scripts": {
40
+ "build": "bun run build.ts",
41
+ "test": "bun test src/",
42
+ "typecheck": "tsc --noEmit -p tsconfig.json"
43
+ },
44
+ "peerDependencies": {
45
+ "creo": ">=0.2.7"
46
+ },
47
+ "devDependencies": {
48
+ "creo": "^0.2.7",
49
+ "typescript": "^5",
50
+ "@types/bun": "latest",
51
+ "happy-dom": "^20.8.4"
52
+ }
53
+ }