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.
- package/LICENSE +21 -0
- package/README.md +169 -0
- package/dist/clipboard/drop.d.ts +17 -0
- package/dist/clipboard/htmlParser.d.ts +18 -0
- package/dist/clipboard/htmlSerializer.d.ts +9 -0
- package/dist/commands/imageCommands.d.ts +32 -0
- package/dist/commands/insertCommands.d.ts +33 -0
- package/dist/commands/listCommands.d.ts +19 -0
- package/dist/commands/markCommands.d.ts +21 -0
- package/dist/commands/navigationCommands.d.ts +27 -0
- package/dist/commands/structuralCommands.d.ts +22 -0
- package/dist/commands/textCommands.d.ts +18 -0
- package/dist/controller/history.d.ts +31 -0
- package/dist/controller/navigation.d.ts +18 -0
- package/dist/controller/selection.d.ts +25 -0
- package/dist/controller/wordBoundary.d.ts +25 -0
- package/dist/createEditor.d.ts +252 -0
- package/dist/dom/anchorMap.d.ts +27 -0
- package/dist/index.d.ts +34 -0
- package/dist/index.js +7833 -0
- package/dist/index.js.map +72 -0
- package/dist/input/keymap.d.ts +47 -0
- package/dist/input/mobile.d.ts +13 -0
- package/dist/input/nativeInput.d.ts +27 -0
- package/dist/markdown/serialize.d.ts +2 -0
- package/dist/model/blockText.d.ts +42 -0
- package/dist/model/cellAccess.d.ts +2 -0
- package/dist/model/doc.d.ts +45 -0
- package/dist/model/fractional.d.ts +57 -0
- package/dist/model/rebalance.d.ts +12 -0
- package/dist/model/types.d.ts +133 -0
- package/dist/plugin/anchorCodec.d.ts +18 -0
- package/dist/plugin/atomic.d.ts +2 -0
- package/dist/plugin/builtin.d.ts +10 -0
- package/dist/plugin/decorations.d.ts +35 -0
- package/dist/plugin/htmlCodec.d.ts +8 -0
- package/dist/plugin/keymapMatch.d.ts +2 -0
- package/dist/plugin/registry.d.ts +29 -0
- package/dist/plugin/runsAt.d.ts +9 -0
- package/dist/plugin/serializeCodec.d.ts +6 -0
- package/dist/plugin/triggers.d.ts +33 -0
- package/dist/plugin/types.d.ts +188 -0
- package/dist/plugins/add-block/index.d.ts +17 -0
- package/dist/plugins/calendar/index.d.ts +7 -0
- package/dist/plugins/calendar/view.d.ts +29 -0
- package/dist/plugins/cells/codecs.d.ts +6 -0
- package/dist/plugins/cells/commands.d.ts +5 -0
- package/dist/plugins/cells/controls.d.ts +3 -0
- package/dist/plugins/cells/htmlCodec.d.ts +6 -0
- package/dist/plugins/cells/index.d.ts +3 -0
- package/dist/plugins/cells/views.d.ts +27 -0
- package/dist/plugins/drag-handle/index.d.ts +6 -0
- package/dist/plugins/infinite-scroll/index.d.ts +44 -0
- package/dist/plugins/md-shortcuts/index.d.ts +2 -0
- package/dist/plugins/search/engine.d.ts +33 -0
- package/dist/plugins/search/highlight.d.ts +13 -0
- package/dist/plugins/search/index.d.ts +5 -0
- package/dist/plugins/search/navigate.d.ts +15 -0
- package/dist/plugins/search/styles.d.ts +1 -0
- package/dist/plugins/search/types.d.ts +73 -0
- package/dist/plugins/search/ui.d.ts +2 -0
- package/dist/plugins/slash/index.d.ts +12 -0
- package/dist/plugins/slash/items.d.ts +21 -0
- package/dist/plugins/slash/menu.d.ts +17 -0
- package/dist/plugins/styles.css +233 -0
- package/dist/render/DocView.d.ts +7 -0
- package/dist/render/InlineRunsView.d.ts +7 -0
- package/dist/render/blocks/CodeBlockView.d.ts +7 -0
- package/dist/render/blocks/HeadingView.d.ts +7 -0
- package/dist/render/blocks/ImageView.d.ts +8 -0
- package/dist/render/blocks/ListItemView.d.ts +7 -0
- package/dist/render/blocks/ParagraphView.d.ts +7 -0
- package/dist/virtual/VirtualDoc.d.ts +28 -0
- package/dist/virtual/heightIndex.d.ts +36 -0
- 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,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,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
|
+
}
|