@reiwuzen/blocky 1.0.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/README.md +250 -0
- package/dist/engine/content.d.ts +46 -0
- package/dist/engine/content.d.ts.map +1 -0
- package/dist/engine/content.js +317 -0
- package/dist/engine/content.js.map +1 -0
- package/dist/engine/format.d.ts +26 -0
- package/dist/engine/format.d.ts.map +1 -0
- package/dist/engine/format.js +116 -0
- package/dist/engine/format.js.map +1 -0
- package/dist/engine/history.d.ts +35 -0
- package/dist/engine/history.d.ts.map +1 -0
- package/dist/engine/history.js +62 -0
- package/dist/engine/history.js.map +1 -0
- package/dist/engine/serializer.d.ts +46 -0
- package/dist/engine/serializer.d.ts.map +1 -0
- package/dist/engine/serializer.js +205 -0
- package/dist/engine/serializer.js.map +1 -0
- package/dist/engine/transform.d.ts +47 -0
- package/dist/engine/transform.d.ts.map +1 -0
- package/dist/engine/transform.js +195 -0
- package/dist/engine/transform.js.map +1 -0
- package/dist/index.d.ts +9 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +13 -0
- package/dist/index.js.map +1 -0
- package/dist/types/block.d.ts +44 -0
- package/dist/types/block.d.ts.map +1 -0
- package/dist/types/block.js +2 -0
- package/dist/types/block.js.map +1 -0
- package/dist/types/editor.d.ts +1 -0
- package/dist/types/editor.d.ts.map +1 -0
- package/dist/types/editor.js +2 -0
- package/dist/types/editor.js.map +1 -0
- package/dist/utils/block.d.ts +32 -0
- package/dist/utils/block.d.ts.map +1 -0
- package/dist/utils/block.js +97 -0
- package/dist/utils/block.js.map +1 -0
- package/package.json +43 -0
|
@@ -0,0 +1,195 @@
|
|
|
1
|
+
import { Result } from '@reiwuzen/result';
|
|
2
|
+
// ─── Trigger map ───────────────────────────────────────────────────────────────
|
|
3
|
+
const TRIGGERS = {
|
|
4
|
+
"-": "bullet",
|
|
5
|
+
"1.": "number",
|
|
6
|
+
"[]": "todo",
|
|
7
|
+
"#": "heading1",
|
|
8
|
+
"##": "heading2",
|
|
9
|
+
"###": "heading3",
|
|
10
|
+
};
|
|
11
|
+
// ─── Helpers ───────────────────────────────────────────────────────────────────
|
|
12
|
+
function getRawText(block) {
|
|
13
|
+
const first = block.content[0];
|
|
14
|
+
if (!first || first.type !== "text")
|
|
15
|
+
return "";
|
|
16
|
+
return first.text;
|
|
17
|
+
}
|
|
18
|
+
function stripPrefix(block, prefix) {
|
|
19
|
+
const first = block.content[0];
|
|
20
|
+
if (!first || first.type !== "text")
|
|
21
|
+
return block.content;
|
|
22
|
+
const stripped = first.text.slice(prefix.length + 1); // +1 for the space
|
|
23
|
+
if (stripped.length === 0)
|
|
24
|
+
return [];
|
|
25
|
+
return [{ ...first, text: stripped }, ...block.content.slice(1)];
|
|
26
|
+
}
|
|
27
|
+
function buildMeta(type) {
|
|
28
|
+
switch (type) {
|
|
29
|
+
case "bullet":
|
|
30
|
+
case "number":
|
|
31
|
+
case "todo": return { depth: 0 };
|
|
32
|
+
case "heading1":
|
|
33
|
+
case "heading2":
|
|
34
|
+
case "heading3": return {};
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
// ─── Core ──────────────────────────────────────────────────────────────────────
|
|
38
|
+
/**
|
|
39
|
+
* Call this when a space is typed.
|
|
40
|
+
*
|
|
41
|
+
* Guards (returns converted=false if any fail):
|
|
42
|
+
* 1. block.type must be "paragraph"
|
|
43
|
+
* 2. cursorOffset must be ≤ trigger.length + 1
|
|
44
|
+
* — ensures the space was typed right after the trigger at position 0
|
|
45
|
+
* — blocks mid-text spaces like "hello - " from converting
|
|
46
|
+
* 3. text must start with a known trigger prefix
|
|
47
|
+
*/
|
|
48
|
+
export function applyMarkdownTransform(block, cursorOffset) {
|
|
49
|
+
// Guard 1 — only paragraph blocks
|
|
50
|
+
if (block.type !== "paragraph")
|
|
51
|
+
return Result.Ok({ block, converted: false });
|
|
52
|
+
const text = getRawText(block);
|
|
53
|
+
// Guard 2 — find trigger first, then validate cursor is right after it
|
|
54
|
+
// Sort longest first so ### beats ## beats #
|
|
55
|
+
const match = Object.keys(TRIGGERS)
|
|
56
|
+
.sort((a, b) => b.length - a.length)
|
|
57
|
+
.find((trigger) => text === trigger || text.startsWith(trigger + " "));
|
|
58
|
+
if (!match)
|
|
59
|
+
return Result.Ok({ block, converted: false });
|
|
60
|
+
// Guard 3 — cursor must be positioned right after "trigger + space"
|
|
61
|
+
// e.g. "## My Title" → match="##", valid cursor range is 0..3
|
|
62
|
+
// "hello ## Title" would never match since trigger must be at start
|
|
63
|
+
const triggerEnd = match.length + 1; // +1 for the space
|
|
64
|
+
if (cursorOffset < triggerEnd)
|
|
65
|
+
return Result.Ok({ block, converted: false });
|
|
66
|
+
const targetType = TRIGGERS[match];
|
|
67
|
+
const strippedContent = stripPrefix(block, match);
|
|
68
|
+
const converted = {
|
|
69
|
+
id: block.id,
|
|
70
|
+
type: targetType,
|
|
71
|
+
content: strippedContent,
|
|
72
|
+
meta: buildMeta(targetType),
|
|
73
|
+
};
|
|
74
|
+
return Result.Ok({ block: converted, converted: true });
|
|
75
|
+
}
|
|
76
|
+
// ─── changeBlockType ───────────────────────────────────────────────────────────
|
|
77
|
+
/**
|
|
78
|
+
* Convert a block to a new type while preserving content as much as possible.
|
|
79
|
+
*
|
|
80
|
+
* rich → rich keep content as-is, update type + meta
|
|
81
|
+
* rich → code strip all formatting, concat all text → [CodeNode]
|
|
82
|
+
* rich → equation strip all formatting, concat all text → [EquationNode]
|
|
83
|
+
* code → rich single TextNode with code.text
|
|
84
|
+
* equation → rich single TextNode with equation.latex
|
|
85
|
+
* code → equation [EquationNode] with code.text as latex
|
|
86
|
+
* equation → code [CodeNode] with equation.latex as text
|
|
87
|
+
*/
|
|
88
|
+
export function changeBlockType(block, targetType) {
|
|
89
|
+
if (block.type === targetType)
|
|
90
|
+
return Result.Ok(block);
|
|
91
|
+
const content = deriveContent(block, targetType);
|
|
92
|
+
const meta = buildMetaForTarget(targetType);
|
|
93
|
+
return Result.Ok({
|
|
94
|
+
id: block.id,
|
|
95
|
+
type: targetType,
|
|
96
|
+
content,
|
|
97
|
+
meta,
|
|
98
|
+
});
|
|
99
|
+
}
|
|
100
|
+
/** Concat all readable text out of any block's content */
|
|
101
|
+
function extractText(block) {
|
|
102
|
+
if (block.type === "code")
|
|
103
|
+
return block.content[0].text;
|
|
104
|
+
if (block.type === "equation")
|
|
105
|
+
return block.content[0].latex;
|
|
106
|
+
// rich block — concat text from all nodes, ignore inline code/eq
|
|
107
|
+
return block.content
|
|
108
|
+
.map((n) => {
|
|
109
|
+
if (n.type === "text")
|
|
110
|
+
return n.text;
|
|
111
|
+
if (n.type === "code")
|
|
112
|
+
return n.text;
|
|
113
|
+
if (n.type === "equation")
|
|
114
|
+
return n.latex;
|
|
115
|
+
return "";
|
|
116
|
+
})
|
|
117
|
+
.join("");
|
|
118
|
+
}
|
|
119
|
+
function deriveContent(block, targetType) {
|
|
120
|
+
const text = extractText(block);
|
|
121
|
+
// → code
|
|
122
|
+
if (targetType === "code")
|
|
123
|
+
return [{ type: "code", text }];
|
|
124
|
+
// → equation
|
|
125
|
+
if (targetType === "equation")
|
|
126
|
+
return [{ type: "equation", latex: text }];
|
|
127
|
+
// → rich block
|
|
128
|
+
if (block.type === "code" || block.type === "equation") {
|
|
129
|
+
// single clean TextNode, no formatters
|
|
130
|
+
return text.length ? [{ type: "text", text }] : [];
|
|
131
|
+
}
|
|
132
|
+
// rich → rich — keep content as-is
|
|
133
|
+
return block.content;
|
|
134
|
+
}
|
|
135
|
+
function buildMetaForTarget(targetType) {
|
|
136
|
+
switch (targetType) {
|
|
137
|
+
case "bullet":
|
|
138
|
+
case "number":
|
|
139
|
+
case "todo": return { depth: 0 };
|
|
140
|
+
case "heading1":
|
|
141
|
+
case "heading2":
|
|
142
|
+
case "heading3":
|
|
143
|
+
case "paragraph":
|
|
144
|
+
case "code":
|
|
145
|
+
case "equation": return {};
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
// ─── toggleTodo ────────────────────────────────────────────────────────────────
|
|
149
|
+
/**
|
|
150
|
+
* Toggle the checked state of a todo block.
|
|
151
|
+
* checked: undefined → checked: true → checked: undefined (cycle)
|
|
152
|
+
*/
|
|
153
|
+
export function toggleTodo(block) {
|
|
154
|
+
if (block.type !== "todo")
|
|
155
|
+
return Result.Err(`toggleTodo expects a "todo" block, got "${block.type}"`);
|
|
156
|
+
const todo = block;
|
|
157
|
+
const checked = todo.meta.checked ? undefined : true;
|
|
158
|
+
const meta = checked
|
|
159
|
+
? { ...todo.meta, checked }
|
|
160
|
+
: (({ checked: _, ...rest }) => rest)(todo.meta);
|
|
161
|
+
return Result.Ok({ ...todo, meta });
|
|
162
|
+
}
|
|
163
|
+
const MAX_DEPTH = 6;
|
|
164
|
+
function isIndentable(block) {
|
|
165
|
+
return block.type === "bullet" || block.type === "number" || block.type === "todo";
|
|
166
|
+
}
|
|
167
|
+
/**
|
|
168
|
+
* Increase the depth of a bullet, number, or todo block by 1.
|
|
169
|
+
* Max depth is 6. Returns Err if block type is not indentable.
|
|
170
|
+
*/
|
|
171
|
+
export function indentBlock(block) {
|
|
172
|
+
if (!isIndentable(block))
|
|
173
|
+
return Result.Err(`indentBlock only supports bullet, number, todo — got "${block.type}"`);
|
|
174
|
+
if (block.meta.depth >= MAX_DEPTH)
|
|
175
|
+
return Result.Err(`already at max depth (${MAX_DEPTH})`);
|
|
176
|
+
return Result.Ok({
|
|
177
|
+
...block,
|
|
178
|
+
meta: { ...block.meta, depth: block.meta.depth + 1 },
|
|
179
|
+
});
|
|
180
|
+
}
|
|
181
|
+
/**
|
|
182
|
+
* Decrease the depth of a bullet, number, or todo block by 1.
|
|
183
|
+
* Min depth is 0. Returns Err if block type is not indentable or already at 0.
|
|
184
|
+
*/
|
|
185
|
+
export function outdentBlock(block) {
|
|
186
|
+
if (!isIndentable(block))
|
|
187
|
+
return Result.Err(`outdentBlock only supports bullet, number, todo — got "${block.type}"`);
|
|
188
|
+
if (block.meta.depth <= 0)
|
|
189
|
+
return Result.Err(`already at min depth (0)`);
|
|
190
|
+
return Result.Ok({
|
|
191
|
+
...block,
|
|
192
|
+
meta: { ...block.meta, depth: block.meta.depth - 1 },
|
|
193
|
+
});
|
|
194
|
+
}
|
|
195
|
+
//# sourceMappingURL=transform.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"transform.js","sourceRoot":"","sources":["../../src/engine/transform.ts"],"names":[],"mappings":"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"}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
export { insertAt, deleteLastChar, deleteRange, replaceRange, splitBlock, mergeBlocks } from "./engine/content";
|
|
2
|
+
export { formatNodes, toggleBold, toggleItalic, toggleUnderline, toggleStrikethrough, toggleHighlight, toggleColor, setLink, removeLink, mergeAdjacentNodes } from "./engine/format";
|
|
3
|
+
export { applyMarkdownTransform, changeBlockType, toggleTodo, indentBlock, outdentBlock } from "./engine/transform";
|
|
4
|
+
export { serialize, deserialize, serializeNodes, deserializeNodes, toPlainText, toMarkdown } from "./engine/serializer";
|
|
5
|
+
export { createHistory, push, undo, redo, canUndo, canRedo, currentBlocks } from "./engine/history";
|
|
6
|
+
export type { History, HistoryEntry } from "./engine/history";
|
|
7
|
+
export { generateId, createBlock, insertBlockAfter, deleteBlock, duplicateBlock, moveBlock } from "./utils/block";
|
|
8
|
+
export type { Node, Block, BlockContent, BlockMeta, BlockType, AnyBlock } from "./types/block";
|
|
9
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,QAAQ,EAAE,cAAc,EAAE,WAAW,EAAE,YAAY,EAAE,UAAU,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAC;AAGhH,OAAO,EAAE,WAAW,EAAE,UAAU,EAAE,YAAY,EAAE,eAAe,EAAE,mBAAmB,EAAE,eAAe,EAAE,WAAW,EAAE,OAAO,EAAE,UAAU,EAAE,kBAAkB,EAAE,MAAM,iBAAiB,CAAC;AAGrL,OAAO,EAAE,sBAAsB,EAAE,eAAe,EAAE,UAAU,EAAE,WAAW,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAGpH,OAAO,EAAE,SAAS,EAAE,WAAW,EAAE,cAAc,EAAE,gBAAgB,EAAE,WAAW,EAAE,UAAU,EAAE,MAAM,qBAAqB,CAAC;AAGxH,OAAO,EAAE,aAAa,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,OAAO,EAAE,OAAO,EAAE,aAAa,EAAE,MAAM,kBAAkB,CAAC;AACpG,YAAY,EAAE,OAAO,EAAE,YAAY,EAAE,MAAM,kBAAkB,CAAC;AAG9D,OAAO,EAAE,UAAU,EAAE,WAAW,EAAE,gBAAgB,EAAE,WAAW,EAAE,cAAc,EAAE,SAAS,EAAE,MAAM,eAAe,CAAC;AAGlH,YAAY,EAAE,IAAI,EAAE,KAAK,EAAE,YAAY,EAAE,SAAS,EAAE,SAAS,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAC"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
// ─── Content ───────────────────────────────────────────────────────────────────
|
|
2
|
+
export { insertAt, deleteLastChar, deleteRange, replaceRange, splitBlock, mergeBlocks } from "./engine/content";
|
|
3
|
+
// ─── Format ────────────────────────────────────────────────────────────────────
|
|
4
|
+
export { formatNodes, toggleBold, toggleItalic, toggleUnderline, toggleStrikethrough, toggleHighlight, toggleColor, setLink, removeLink, mergeAdjacentNodes } from "./engine/format";
|
|
5
|
+
// ─── Transform ─────────────────────────────────────────────────────────────────
|
|
6
|
+
export { applyMarkdownTransform, changeBlockType, toggleTodo, indentBlock, outdentBlock } from "./engine/transform";
|
|
7
|
+
// ─── Serializer ────────────────────────────────────────────────────────────────
|
|
8
|
+
export { serialize, deserialize, serializeNodes, deserializeNodes, toPlainText, toMarkdown } from "./engine/serializer";
|
|
9
|
+
// ─── History ───────────────────────────────────────────────────────────────────
|
|
10
|
+
export { createHistory, push, undo, redo, canUndo, canRedo, currentBlocks } from "./engine/history";
|
|
11
|
+
// ─── Utils ─────────────────────────────────────────────────────────────────────
|
|
12
|
+
export { generateId, createBlock, insertBlockAfter, deleteBlock, duplicateBlock, moveBlock } from "./utils/block";
|
|
13
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,kFAAkF;AAClF,OAAO,EAAE,QAAQ,EAAE,cAAc,EAAE,WAAW,EAAE,YAAY,EAAE,UAAU,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAC;AAEhH,kFAAkF;AAClF,OAAO,EAAE,WAAW,EAAE,UAAU,EAAE,YAAY,EAAE,eAAe,EAAE,mBAAmB,EAAE,eAAe,EAAE,WAAW,EAAE,OAAO,EAAE,UAAU,EAAE,kBAAkB,EAAE,MAAM,iBAAiB,CAAC;AAErL,kFAAkF;AAClF,OAAO,EAAE,sBAAsB,EAAE,eAAe,EAAE,UAAU,EAAE,WAAW,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAEpH,kFAAkF;AAClF,OAAO,EAAE,SAAS,EAAE,WAAW,EAAE,cAAc,EAAE,gBAAgB,EAAE,WAAW,EAAE,UAAU,EAAE,MAAM,qBAAqB,CAAC;AAExH,kFAAkF;AAClF,OAAO,EAAE,aAAa,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,OAAO,EAAE,OAAO,EAAE,aAAa,EAAE,MAAM,kBAAkB,CAAC;AAGpG,kFAAkF;AAClF,OAAO,EAAE,UAAU,EAAE,WAAW,EAAE,gBAAgB,EAAE,WAAW,EAAE,cAAc,EAAE,SAAS,EAAE,MAAM,eAAe,CAAC"}
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
export type BlockType = "paragraph" | "heading1" | "heading2" | "heading3" | "bullet" | "number" | "todo" | "equation" | "code";
|
|
2
|
+
export type Node = {
|
|
3
|
+
type: "text";
|
|
4
|
+
text: string;
|
|
5
|
+
highlighted?: "yellow" | "green";
|
|
6
|
+
color?: "red" | 'blue' | 'green';
|
|
7
|
+
bold?: true;
|
|
8
|
+
italic?: true;
|
|
9
|
+
underline?: true;
|
|
10
|
+
strikethrough?: true;
|
|
11
|
+
link?: string;
|
|
12
|
+
} | {
|
|
13
|
+
type: "code";
|
|
14
|
+
text: string;
|
|
15
|
+
} | {
|
|
16
|
+
type: "equation";
|
|
17
|
+
latex: string;
|
|
18
|
+
};
|
|
19
|
+
export type BlockMeta<T extends BlockType> = T extends "todo" ? {
|
|
20
|
+
checked?: true;
|
|
21
|
+
depth: number;
|
|
22
|
+
} : T extends "bullet" | "number" ? {
|
|
23
|
+
depth: number;
|
|
24
|
+
} : T extends "code" ? {
|
|
25
|
+
language?: string;
|
|
26
|
+
} : Record<string, never>;
|
|
27
|
+
export type BlockContent<T extends BlockType> = T extends "code" ? [Extract<Node, {
|
|
28
|
+
type: "code";
|
|
29
|
+
}>] : T extends "equation" ? [Extract<Node, {
|
|
30
|
+
type: "equation";
|
|
31
|
+
}>] : Node[];
|
|
32
|
+
export type Block<T extends BlockType = BlockType> = {
|
|
33
|
+
id: string;
|
|
34
|
+
type: T;
|
|
35
|
+
meta: BlockMeta<T>;
|
|
36
|
+
content: BlockContent<T>;
|
|
37
|
+
};
|
|
38
|
+
/**
|
|
39
|
+
* Discriminated Union of Block
|
|
40
|
+
*/
|
|
41
|
+
export type AnyBlock = {
|
|
42
|
+
[K in BlockType]: Block<K>;
|
|
43
|
+
}[BlockType];
|
|
44
|
+
//# sourceMappingURL=block.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"block.d.ts","sourceRoot":"","sources":["../../src/types/block.ts"],"names":[],"mappings":"AAAA,MAAM,MAAM,SAAS,GACjB,WAAW,GACX,UAAU,GACV,UAAU,GACV,UAAU,GACV,QAAQ,GACR,QAAQ,GACR,MAAM,GACN,UAAU,GACV,MAAM,CAAC;AAIX,MAAM,MAAM,IAAI,GACZ;IACE,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,CAAC,EAAE,QAAQ,GAAG,OAAO,CAAC;IACjC,KAAK,CAAC,EAAE,KAAK,GAAG,MAAM,GAAG,OAAO,CAAA;IAChC,IAAI,CAAC,EAAE,IAAI,CAAC;IACZ,MAAM,CAAC,EAAE,IAAI,CAAC;IACd,SAAS,CAAC,EAAE,IAAI,CAAC;IACjB,aAAa,CAAC,EAAE,IAAI,CAAC;IACrB,IAAI,CAAC,EAAE,MAAM,CAAC;CACf,GACD;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAE,GAC9B;IAAE,IAAI,EAAE,UAAU,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,CAAC;AAIxC,MAAM,MAAM,SAAS,CAAC,CAAC,SAAS,SAAS,IAAI,CAAC,SAAS,MAAM,GACzD;IAAE,OAAO,CAAC,EAAE,IAAI,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,GACjC,CAAC,SAAS,QAAQ,GAAG,QAAQ,GAC7B;IAAE,KAAK,EAAE,MAAM,CAAA;CAAE,GACjB,CAAC,SAAS,MAAM,GAChB;IAAE,QAAQ,CAAC,EAAE,MAAM,CAAA;CAAE,GACrB,MAAM,CAAC,MAAM,EAAE,KAAK,CAAC,CAAC;AAO1B,MAAM,MAAM,YAAY,CAAC,CAAC,SAAS,SAAS,IAAI,CAAC,SAAS,MAAM,GAC5D,CAAC,OAAO,CAAC,IAAI,EAAE;IAAE,IAAI,EAAE,MAAM,CAAA;CAAE,CAAC,CAAC,GACjC,CAAC,SAAS,UAAU,GACpB,CAAC,OAAO,CAAC,IAAI,EAAE;IAAE,IAAI,EAAE,UAAU,CAAA;CAAE,CAAC,CAAC,GACrC,IAAI,EAAE,CAAC;AAIX,MAAM,MAAM,KAAK,CAAC,CAAC,SAAS,SAAS,GAAG,SAAS,IAAI;IACnD,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,CAAC,CAAC;IACR,IAAI,EAAE,SAAS,CAAC,CAAC,CAAC,CAAC;IACnB,OAAO,EAAE,YAAY,CAAC,CAAC,CAAC,CAAC;CAC1B,CAAC;AAEF;;GAEG;AACH,MAAM,MAAM,QAAQ,GAAG;KAAG,CAAC,IAAI,SAAS,GAAG,KAAK,CAAC,CAAC,CAAC;CAAE,CAAC,SAAS,CAAC,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"block.js","sourceRoot":"","sources":["../../src/types/block.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
//# sourceMappingURL=editor.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"editor.d.ts","sourceRoot":"","sources":["../../src/types/editor.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"editor.js","sourceRoot":"","sources":["../../src/types/editor.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import { Result } from '@reiwuzen/result';
|
|
2
|
+
import type { Block, BlockType, AnyBlock } from '../types/block';
|
|
3
|
+
/**
|
|
4
|
+
* Generate a unique block id.
|
|
5
|
+
* Pass a custom fn to override the default (uuid v7).
|
|
6
|
+
*/
|
|
7
|
+
export declare function generateId(fn?: () => string): string;
|
|
8
|
+
/**
|
|
9
|
+
* Create a new block of the given type with default content and meta.
|
|
10
|
+
* Optionally pass a custom id generator.
|
|
11
|
+
*
|
|
12
|
+
* @param type - the block type to create
|
|
13
|
+
* @param idFn - optional custom id generator (defaults to uuid v7)
|
|
14
|
+
*/
|
|
15
|
+
export declare function createBlock<T extends BlockType>(type: T, idFn?: () => string): Result<Block<T>, unknown>;
|
|
16
|
+
export declare function insertBlockAfter<T extends BlockType>(blocks: AnyBlock[], afterId: string, type: T, idFn?: () => string): Result<{
|
|
17
|
+
blocks: AnyBlock[];
|
|
18
|
+
newId: string;
|
|
19
|
+
}, unknown>;
|
|
20
|
+
export declare function deleteBlock(blocks: AnyBlock[], id: string): {
|
|
21
|
+
blocks: AnyBlock[];
|
|
22
|
+
prevId: string;
|
|
23
|
+
};
|
|
24
|
+
export declare function changeBlockTypeInList<T extends BlockType>(blocks: AnyBlock[], id: string, type: T): AnyBlock[];
|
|
25
|
+
export declare function duplicateBlock(incoming: AnyBlock, newId: string): AnyBlock;
|
|
26
|
+
/**
|
|
27
|
+
* Move a block up or down by one position in the array.
|
|
28
|
+
* Returns the same array unchanged if block is already at the boundary.
|
|
29
|
+
* Returns Err if id not found.
|
|
30
|
+
*/
|
|
31
|
+
export declare function moveBlock(blocks: AnyBlock[], id: string, direction: "up" | "down"): Result<AnyBlock[], string>;
|
|
32
|
+
//# sourceMappingURL=block.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"block.d.ts","sourceRoot":"","sources":["../../src/utils/block.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,kBAAkB,CAAC;AAE1C,OAAO,KAAK,EAAE,KAAK,EAAE,SAAS,EAA2B,QAAQ,EAAE,MAAM,gBAAgB,CAAC;AAI1F;;;GAGG;AACH,wBAAgB,UAAU,CAAC,EAAE,CAAC,EAAE,MAAM,MAAM,GAAG,MAAM,CAEpD;AAgCD;;;;;;GAMG;AACH,wBAAgB,WAAW,CAAC,CAAC,SAAS,SAAS,EAC7C,IAAI,EAAE,CAAC,EACP,IAAI,CAAC,EAAE,MAAM,MAAM,GAClB,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,OAAO,CAAC,CAU3B;AAID,wBAAgB,gBAAgB,CAAC,CAAC,SAAS,SAAS,EAClD,MAAM,EAAE,QAAQ,EAAE,EAClB,OAAO,EAAE,MAAM,EACf,IAAI,EAAE,CAAC,EACP,IAAI,CAAC,EAAE,MAAM,MAAM,GAClB,MAAM,CAAC;IAAE,MAAM,EAAE,QAAQ,EAAE,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,EAAE,OAAO,CAAC,CAOxD;AAED,wBAAgB,WAAW,CACzB,MAAM,EAAE,QAAQ,EAAE,EAClB,EAAE,EAAE,MAAM,GACT;IAAE,MAAM,EAAE,QAAQ,EAAE,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,CAIxC;AAED,wBAAgB,qBAAqB,CAAC,CAAC,SAAS,SAAS,EACvD,MAAM,EAAE,QAAQ,EAAE,EAClB,EAAE,EAAE,MAAM,EACV,IAAI,EAAE,CAAC,GACN,QAAQ,EAAE,CAMZ;AAKD,wBAAgB,cAAc,CAAC,QAAQ,EAAE,QAAQ,EAAE,KAAK,EAAE,MAAM,GAAG,QAAQ,CAE1E;AAID;;;;GAIG;AACH,wBAAgB,SAAS,CACvB,MAAM,EAAE,QAAQ,EAAE,EAClB,EAAE,EAAE,MAAM,EACV,SAAS,EAAE,IAAI,GAAG,MAAM,GACvB,MAAM,CAAC,QAAQ,EAAE,EAAE,MAAM,CAAC,CAiB5B"}
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
import { Result } from '@reiwuzen/result';
|
|
2
|
+
import { v7 } from 'uuid';
|
|
3
|
+
// ─── generateId ────────────────────────────────────────────────────────────────
|
|
4
|
+
/**
|
|
5
|
+
* Generate a unique block id.
|
|
6
|
+
* Pass a custom fn to override the default (uuid v7).
|
|
7
|
+
*/
|
|
8
|
+
export function generateId(fn) {
|
|
9
|
+
return fn ? fn() : v7();
|
|
10
|
+
}
|
|
11
|
+
// ─── Default content per block type ───────────────────────────────────────────
|
|
12
|
+
const defaultContent = {
|
|
13
|
+
paragraph: [],
|
|
14
|
+
heading1: [],
|
|
15
|
+
heading2: [],
|
|
16
|
+
heading3: [],
|
|
17
|
+
bullet: [],
|
|
18
|
+
number: [],
|
|
19
|
+
todo: [],
|
|
20
|
+
code: [{ type: "code", text: "" }],
|
|
21
|
+
equation: [{ type: "equation", latex: "" }],
|
|
22
|
+
};
|
|
23
|
+
// ─── Default meta per block type ──────────────────────────────────────────────
|
|
24
|
+
const defaultMeta = {
|
|
25
|
+
paragraph: {},
|
|
26
|
+
heading1: {},
|
|
27
|
+
heading2: {},
|
|
28
|
+
heading3: {},
|
|
29
|
+
bullet: { depth: 0 },
|
|
30
|
+
number: { depth: 0 },
|
|
31
|
+
todo: { depth: 0 },
|
|
32
|
+
code: {},
|
|
33
|
+
equation: {},
|
|
34
|
+
};
|
|
35
|
+
// ─── createBlock ──────────────────────────────────────────────────────────────
|
|
36
|
+
/**
|
|
37
|
+
* Create a new block of the given type with default content and meta.
|
|
38
|
+
* Optionally pass a custom id generator.
|
|
39
|
+
*
|
|
40
|
+
* @param type - the block type to create
|
|
41
|
+
* @param idFn - optional custom id generator (defaults to uuid v7)
|
|
42
|
+
*/
|
|
43
|
+
export function createBlock(type, idFn) {
|
|
44
|
+
return Result.try(() => {
|
|
45
|
+
const block = {
|
|
46
|
+
id: generateId(idFn),
|
|
47
|
+
type,
|
|
48
|
+
meta: defaultMeta[type],
|
|
49
|
+
content: defaultContent[type],
|
|
50
|
+
};
|
|
51
|
+
return block;
|
|
52
|
+
});
|
|
53
|
+
}
|
|
54
|
+
// ─── Block array helpers ───────────────────────────────────────────────────────
|
|
55
|
+
export function insertBlockAfter(blocks, afterId, type, idFn) {
|
|
56
|
+
return createBlock(type, idFn).map((newBlock) => {
|
|
57
|
+
const index = blocks.findIndex((b) => b.id === afterId);
|
|
58
|
+
const next = [...blocks];
|
|
59
|
+
next.splice(index + 1, 0, newBlock);
|
|
60
|
+
return { blocks: next, newId: newBlock.id };
|
|
61
|
+
});
|
|
62
|
+
}
|
|
63
|
+
export function deleteBlock(blocks, id) {
|
|
64
|
+
var _a, _b, _c, _d;
|
|
65
|
+
const index = blocks.findIndex((b) => b.id === id);
|
|
66
|
+
const prevId = (_d = (_b = (_a = blocks[index - 1]) === null || _a === void 0 ? void 0 : _a.id) !== null && _b !== void 0 ? _b : (_c = blocks[index + 1]) === null || _c === void 0 ? void 0 : _c.id) !== null && _d !== void 0 ? _d : "";
|
|
67
|
+
return { blocks: blocks.filter((b) => b.id !== id), prevId };
|
|
68
|
+
}
|
|
69
|
+
export function changeBlockTypeInList(blocks, id, type) {
|
|
70
|
+
return blocks.map((b) => b.id === id
|
|
71
|
+
? { ...b, type, meta: defaultMeta[type], content: defaultContent[type] }
|
|
72
|
+
: b);
|
|
73
|
+
}
|
|
74
|
+
// ─── duplicateBlock ────────────────────────────────────────────────────────────
|
|
75
|
+
export function duplicateBlock(incoming, newId) {
|
|
76
|
+
return { ...incoming, id: newId };
|
|
77
|
+
}
|
|
78
|
+
// ─── moveBlock ─────────────────────────────────────────────────────────────────
|
|
79
|
+
/**
|
|
80
|
+
* Move a block up or down by one position in the array.
|
|
81
|
+
* Returns the same array unchanged if block is already at the boundary.
|
|
82
|
+
* Returns Err if id not found.
|
|
83
|
+
*/
|
|
84
|
+
export function moveBlock(blocks, id, direction) {
|
|
85
|
+
const index = blocks.findIndex((b) => b.id === id);
|
|
86
|
+
if (index === -1)
|
|
87
|
+
return Result.Err(`Block with id "${id}" not found`);
|
|
88
|
+
if (direction === "up" && index === 0)
|
|
89
|
+
return Result.Ok([...blocks]); // already at top
|
|
90
|
+
if (direction === "down" && index === blocks.length - 1)
|
|
91
|
+
return Result.Ok([...blocks]); // already at bottom
|
|
92
|
+
const next = [...blocks];
|
|
93
|
+
const swapIndex = direction === "up" ? index - 1 : index + 1;
|
|
94
|
+
[next[index], next[swapIndex]] = [next[swapIndex], next[index]];
|
|
95
|
+
return Result.Ok(next);
|
|
96
|
+
}
|
|
97
|
+
//# sourceMappingURL=block.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"block.js","sourceRoot":"","sources":["../../src/utils/block.ts"],"names":[],"mappings":"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"}
|
package/package.json
ADDED
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@reiwuzen/blocky",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"description": "Pure TypeScript block editor engine. Headless, framework-agnostic — content mutation, formatting, transforms, serialization, and history.",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"main": "dist/index.js",
|
|
7
|
+
"types": "dist/index.d.ts",
|
|
8
|
+
"files": [
|
|
9
|
+
"dist"
|
|
10
|
+
],
|
|
11
|
+
"scripts": {
|
|
12
|
+
"build": "tsc",
|
|
13
|
+
"dev": "tsc --watch",
|
|
14
|
+
"clean": "rimraf dist",
|
|
15
|
+
"test": "tsx tests/test.ts"
|
|
16
|
+
},
|
|
17
|
+
"keywords": [
|
|
18
|
+
"block-editor",
|
|
19
|
+
"headless-editor",
|
|
20
|
+
"block-based",
|
|
21
|
+
"rich-text",
|
|
22
|
+
"editor-engine",
|
|
23
|
+
"editor-core",
|
|
24
|
+
"typescript"
|
|
25
|
+
],
|
|
26
|
+
"author": "Rei WuZen",
|
|
27
|
+
"license": "ISC",
|
|
28
|
+
"dependencies": {
|
|
29
|
+
"@reiwuzen/result": "^1.0.1",
|
|
30
|
+
"uuid": "^13.0.0"
|
|
31
|
+
},
|
|
32
|
+
"devDependencies": {
|
|
33
|
+
"rimraf": "^6.0.1",
|
|
34
|
+
"tsx": "^4.19.3",
|
|
35
|
+
"typescript": "^5.9.3"
|
|
36
|
+
},
|
|
37
|
+
"exports": {
|
|
38
|
+
".": {
|
|
39
|
+
"import": "./dist/index.js",
|
|
40
|
+
"types": "./dist/index.d.ts"
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
}
|