@reiwuzen/blocky 1.3.4 → 1.4.2
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/dist/index.cjs +35 -11
- package/dist/index.d.cts +78 -22
- package/dist/index.d.ts +78 -22
- package/dist/index.js +33 -11
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -21,6 +21,7 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
|
|
|
21
21
|
var index_exports = {};
|
|
22
22
|
__export(index_exports, {
|
|
23
23
|
applyMarkdownTransform: () => applyMarkdownTransform,
|
|
24
|
+
areBlocksSame: () => areBlocksSame,
|
|
24
25
|
canRedo: () => canRedo,
|
|
25
26
|
canUndo: () => canUndo,
|
|
26
27
|
changeBlockType: () => changeBlockType,
|
|
@@ -36,6 +37,7 @@ __export(index_exports, {
|
|
|
36
37
|
duplicateBlock: () => duplicateBlock,
|
|
37
38
|
duplicateBlockAfter: () => duplicateBlockAfter,
|
|
38
39
|
formatNodes: () => formatNodes,
|
|
40
|
+
formatParagraphBlock: () => stripPrefix,
|
|
39
41
|
generateId: () => generateId,
|
|
40
42
|
indentBlock: () => indentBlock,
|
|
41
43
|
insertAt: () => insertAt,
|
|
@@ -619,18 +621,15 @@ function buildMetaForTarget(targetType) {
|
|
|
619
621
|
case "number":
|
|
620
622
|
case "todo":
|
|
621
623
|
return { depth: 0 };
|
|
622
|
-
|
|
623
|
-
case "heading2":
|
|
624
|
-
case "heading3":
|
|
625
|
-
case "paragraph":
|
|
626
|
-
case "code":
|
|
627
|
-
case "equation":
|
|
624
|
+
default:
|
|
628
625
|
return {};
|
|
629
626
|
}
|
|
630
627
|
}
|
|
628
|
+
function isList(type) {
|
|
629
|
+
return type === "bullet" || type === "todo" || type === "number";
|
|
630
|
+
}
|
|
631
631
|
function deriveMeta(block, targetType) {
|
|
632
|
-
if (isList(block.type) && isList(targetType))
|
|
633
|
-
return block.meta;
|
|
632
|
+
if (isList(block.type) && isList(targetType)) return block.meta;
|
|
634
633
|
return buildMetaForTarget(targetType);
|
|
635
634
|
}
|
|
636
635
|
function toggleTodo(block) {
|
|
@@ -645,9 +644,6 @@ var MAX_DEPTH = 6;
|
|
|
645
644
|
function isIndentable(block) {
|
|
646
645
|
return block.type === "bullet" || block.type === "number" || block.type === "todo";
|
|
647
646
|
}
|
|
648
|
-
function isList(type) {
|
|
649
|
-
return type === "bullet" || type === "todo" || type === "number";
|
|
650
|
-
}
|
|
651
647
|
function indentBlock(block) {
|
|
652
648
|
if (!isIndentable(block))
|
|
653
649
|
return import_result4.Result.Err(
|
|
@@ -671,6 +667,31 @@ function outdentBlock(block) {
|
|
|
671
667
|
meta: { ...block.meta, depth: block.meta.depth - 1 }
|
|
672
668
|
});
|
|
673
669
|
}
|
|
670
|
+
function areBlocksSame(blocks, withBlocks) {
|
|
671
|
+
if (blocks.length !== withBlocks.length) return false;
|
|
672
|
+
return blocks.every((a, i) => {
|
|
673
|
+
const b = withBlocks[i];
|
|
674
|
+
if (a.type !== b.type) return false;
|
|
675
|
+
if (JSON.stringify(a.meta) !== JSON.stringify(b.meta)) return false;
|
|
676
|
+
if (a.content.length !== b.content.length) return false;
|
|
677
|
+
return a.content.every((an, j) => {
|
|
678
|
+
const bn = b.content[j];
|
|
679
|
+
if (an.type !== bn.type) return false;
|
|
680
|
+
switch (an.type) {
|
|
681
|
+
case "code":
|
|
682
|
+
return an.text === bn.text;
|
|
683
|
+
case "equation":
|
|
684
|
+
return an.latex === bn.latex;
|
|
685
|
+
case "text": {
|
|
686
|
+
const bt = bn;
|
|
687
|
+
return an.text === bt.text && an.bold === bt.bold && an.italic === bt.italic && an.underline === bt.underline && an.strikethrough === bt.strikethrough && an.highlighted === bt.highlighted && an.color === bt.color && an.link === bt.link;
|
|
688
|
+
}
|
|
689
|
+
default:
|
|
690
|
+
return false;
|
|
691
|
+
}
|
|
692
|
+
});
|
|
693
|
+
});
|
|
694
|
+
}
|
|
674
695
|
|
|
675
696
|
// src/engine/serializer.ts
|
|
676
697
|
var import_result5 = require("@reiwuzen/result");
|
|
@@ -769,6 +790,7 @@ function nodesToMarkdown(nodes) {
|
|
|
769
790
|
return nodes.map((n) => {
|
|
770
791
|
if (n.type === "code") return `\`${n.text}\``;
|
|
771
792
|
if (n.type === "equation") return `$${n.latex}$`;
|
|
793
|
+
if (n.type === "ref") return `[${n.label}](${n.href})`;
|
|
772
794
|
let text = n.text;
|
|
773
795
|
if (n.bold) text = `**${text}**`;
|
|
774
796
|
if (n.italic) text = `*${text}*`;
|
|
@@ -857,6 +879,7 @@ var currentBlocks = (history) => history.present.blocks;
|
|
|
857
879
|
// Annotate the CommonJS export names for ESM import in node:
|
|
858
880
|
0 && (module.exports = {
|
|
859
881
|
applyMarkdownTransform,
|
|
882
|
+
areBlocksSame,
|
|
860
883
|
canRedo,
|
|
861
884
|
canUndo,
|
|
862
885
|
changeBlockType,
|
|
@@ -872,6 +895,7 @@ var currentBlocks = (history) => history.present.blocks;
|
|
|
872
895
|
duplicateBlock,
|
|
873
896
|
duplicateBlockAfter,
|
|
874
897
|
formatNodes,
|
|
898
|
+
formatParagraphBlock,
|
|
875
899
|
generateId,
|
|
876
900
|
indentBlock,
|
|
877
901
|
insertAt,
|
package/dist/index.d.cts
CHANGED
|
@@ -5,12 +5,16 @@ type Node = {
|
|
|
5
5
|
type: "text";
|
|
6
6
|
text: string;
|
|
7
7
|
highlighted?: "yellow" | "green";
|
|
8
|
-
color?: "red" |
|
|
8
|
+
color?: "red" | "blue" | "green";
|
|
9
9
|
bold?: true;
|
|
10
10
|
italic?: true;
|
|
11
11
|
underline?: true;
|
|
12
12
|
strikethrough?: true;
|
|
13
13
|
link?: string;
|
|
14
|
+
} | {
|
|
15
|
+
type: "ref";
|
|
16
|
+
href: string;
|
|
17
|
+
label: string;
|
|
14
18
|
} | {
|
|
15
19
|
type: "code";
|
|
16
20
|
text: string;
|
|
@@ -111,47 +115,99 @@ declare const removeLink: (nodes: Node[], sel: NodeSelection) => Result<Node[],
|
|
|
111
115
|
|
|
112
116
|
type TransformResult = {
|
|
113
117
|
block: AnyBlock;
|
|
118
|
+
/** true if the block type was actually changed, false if no trigger matched */
|
|
114
119
|
converted: boolean;
|
|
115
120
|
};
|
|
121
|
+
declare function stripPrefix(block: Block<"paragraph">, prefix: string): Block<"paragraph">["content"];
|
|
116
122
|
/**
|
|
117
|
-
*
|
|
123
|
+
* Attempt to convert a paragraph block into another type based on a
|
|
124
|
+
* Markdown-style prefix typed by the user.
|
|
125
|
+
*
|
|
126
|
+
* Call this when a **space** is typed inside a paragraph block.
|
|
127
|
+
*
|
|
128
|
+
* Supported triggers (must appear at position 0, immediately before the space):
|
|
129
|
+
*
|
|
130
|
+
* | Typed | Converts to |
|
|
131
|
+
* |----------|-------------|
|
|
132
|
+
* | `-` | bullet |
|
|
133
|
+
* | `1.` | number |
|
|
134
|
+
* | `[]` | todo |
|
|
135
|
+
* | `#` | heading1 |
|
|
136
|
+
* | `##` | heading2 |
|
|
137
|
+
* | `###` | heading3 |
|
|
118
138
|
*
|
|
119
|
-
* Guards
|
|
120
|
-
* 1. block.type must be "paragraph"
|
|
121
|
-
* 2.
|
|
122
|
-
*
|
|
123
|
-
*
|
|
124
|
-
*
|
|
139
|
+
* Guards — returns `converted: false` without mutating if any fail:
|
|
140
|
+
* 1. `block.type` must be `"paragraph"`
|
|
141
|
+
* 2. The text must start with a known trigger prefix
|
|
142
|
+
* 3. `cursorOffset` must be ≥ `trigger.length + 1` — ensures the space
|
|
143
|
+
* was typed right after the trigger (blocks mid-text triggers like
|
|
144
|
+
* `"hello - "` from accidentally converting)
|
|
145
|
+
*
|
|
146
|
+
* On success the returned block has the trigger prefix stripped from its
|
|
147
|
+
* content and a freshly built `meta` for the target type.
|
|
125
148
|
*/
|
|
126
149
|
declare function applyMarkdownTransform(block: AnyBlock, cursorOffset: number): Result<TransformResult>;
|
|
127
150
|
/**
|
|
128
|
-
* Convert a block to a new type
|
|
151
|
+
* Convert a block to a new type, preserving content and meta where possible.
|
|
152
|
+
*
|
|
153
|
+
* Content conversion rules:
|
|
129
154
|
*
|
|
130
|
-
*
|
|
131
|
-
*
|
|
132
|
-
* rich
|
|
133
|
-
* code
|
|
134
|
-
* equation
|
|
135
|
-
* code
|
|
136
|
-
* equation
|
|
155
|
+
* | From | To | Content result |
|
|
156
|
+
* |-------------|-------------|----------------------------------------|
|
|
157
|
+
* | rich | rich | kept as-is |
|
|
158
|
+
* | rich | code | all text concatenated → `[CodeNode]` |
|
|
159
|
+
* | rich | equation | all text concatenated → `[EquationNode]`|
|
|
160
|
+
* | code | rich | `code.text` → single `TextNode` |
|
|
161
|
+
* | equation | rich | `equation.latex` → single `TextNode` |
|
|
162
|
+
* | code | equation | `code.text` as `latex` |
|
|
163
|
+
* | equation | code | `equation.latex` as `text` |
|
|
164
|
+
*
|
|
165
|
+
* Meta conversion rules:
|
|
166
|
+
* - list → list : `meta` (including `depth`) is preserved
|
|
167
|
+
* - anything else: fresh default `meta` is built for the target type
|
|
137
168
|
*/
|
|
138
169
|
declare function changeBlockType<T extends BlockType>(block: AnyBlock, targetType: T): Result<Block<T>>;
|
|
139
170
|
/**
|
|
140
171
|
* Toggle the checked state of a todo block.
|
|
141
|
-
*
|
|
172
|
+
*
|
|
173
|
+
* Cycle: `undefined → true → undefined`
|
|
174
|
+
*
|
|
175
|
+
* Returns `Err` if the block is not of type `"todo"`.
|
|
142
176
|
*/
|
|
143
177
|
declare function toggleTodo(block: AnyBlock): Result<Block<"todo">>;
|
|
144
178
|
type IndentableBlock = Block<"bullet"> | Block<"number"> | Block<"todo">;
|
|
145
179
|
/**
|
|
146
|
-
* Increase the depth of a bullet
|
|
147
|
-
*
|
|
180
|
+
* Increase the indentation depth of a list block (`bullet`, `number`, `todo`) by 1.
|
|
181
|
+
*
|
|
182
|
+
* - Maximum depth is `6`.
|
|
183
|
+
* - Returns `Err` if the block type is not indentable or is already at max depth.
|
|
148
184
|
*/
|
|
149
185
|
declare function indentBlock(block: AnyBlock): Result<IndentableBlock>;
|
|
150
186
|
/**
|
|
151
|
-
* Decrease the depth of a bullet
|
|
152
|
-
*
|
|
187
|
+
* Decrease the indentation depth of a list block (`bullet`, `number`, `todo`) by 1.
|
|
188
|
+
*
|
|
189
|
+
* - Minimum depth is `0`.
|
|
190
|
+
* - Returns `Err` if the block type is not indentable or is already at depth 0.
|
|
153
191
|
*/
|
|
154
192
|
declare function outdentBlock(block: AnyBlock): Result<IndentableBlock>;
|
|
193
|
+
/**
|
|
194
|
+
* Deep-equality check between two block arrays.
|
|
195
|
+
*
|
|
196
|
+
* Two arrays are considered the same when:
|
|
197
|
+
* - They have the same length
|
|
198
|
+
* - Every block at the same index has the same `id`, `type`, `meta`, and `content`
|
|
199
|
+
*
|
|
200
|
+
* Content nodes are compared field-by-field. Unknown extra fields on nodes are
|
|
201
|
+
* ignored so the check stays stable across schema additions.
|
|
202
|
+
*
|
|
203
|
+
* Useful for preventing redundant saves or snapshot writes:
|
|
204
|
+
* ```ts
|
|
205
|
+
* if (!areBlocksSame(current, saved)) {
|
|
206
|
+
* await createSnapshot(current);
|
|
207
|
+
* }
|
|
208
|
+
* ```
|
|
209
|
+
*/
|
|
210
|
+
declare function areBlocksSame(blocks: AnyBlock[], withBlocks: AnyBlock[]): boolean;
|
|
155
211
|
|
|
156
212
|
/**
|
|
157
213
|
* Serialize an array of blocks to a JSON string.
|
|
@@ -267,4 +323,4 @@ declare function duplicateBlockAfter(blocks: AnyBlock[], id: string, newId?: str
|
|
|
267
323
|
*/
|
|
268
324
|
declare function moveBlock(blocks: AnyBlock[], id: string, direction: "up" | "down"): Result<AnyBlock[], string>;
|
|
269
325
|
|
|
270
|
-
export { type AnyBlock, type Block, type BlockContent, type BlockMeta, type BlockType, type History, type HistoryEntry, type Node, type NodeSelection, applyMarkdownTransform, canRedo, canUndo, changeBlockType, createBlock, createBlockAfter, createHistory, currentBlocks, deleteBlock, deleteLastChar, deleteRange, deserialize, deserializeNodes, duplicateBlock, duplicateBlockAfter, formatNodes, generateId, indentBlock, insertAt, insertBlockAfter, mergeAdjacentNodes, mergeBlocks, moveBlock, outdentBlock, push, redo, removeLink, replaceRange, serialize, serializeNodes, setLink, splitBlock, toMarkdown, toPlainText, toggleBold, toggleColor, toggleHighlight, toggleItalic, toggleStrikethrough, toggleTodo, toggleUnderline, undo };
|
|
326
|
+
export { type AnyBlock, type Block, type BlockContent, type BlockMeta, type BlockType, type History, type HistoryEntry, type Node, type NodeSelection, applyMarkdownTransform, areBlocksSame, canRedo, canUndo, changeBlockType, createBlock, createBlockAfter, createHistory, currentBlocks, deleteBlock, deleteLastChar, deleteRange, deserialize, deserializeNodes, duplicateBlock, duplicateBlockAfter, formatNodes, stripPrefix as formatParagraphBlock, generateId, indentBlock, insertAt, insertBlockAfter, mergeAdjacentNodes, mergeBlocks, moveBlock, outdentBlock, push, redo, removeLink, replaceRange, serialize, serializeNodes, setLink, splitBlock, toMarkdown, toPlainText, toggleBold, toggleColor, toggleHighlight, toggleItalic, toggleStrikethrough, toggleTodo, toggleUnderline, undo };
|
package/dist/index.d.ts
CHANGED
|
@@ -5,12 +5,16 @@ type Node = {
|
|
|
5
5
|
type: "text";
|
|
6
6
|
text: string;
|
|
7
7
|
highlighted?: "yellow" | "green";
|
|
8
|
-
color?: "red" |
|
|
8
|
+
color?: "red" | "blue" | "green";
|
|
9
9
|
bold?: true;
|
|
10
10
|
italic?: true;
|
|
11
11
|
underline?: true;
|
|
12
12
|
strikethrough?: true;
|
|
13
13
|
link?: string;
|
|
14
|
+
} | {
|
|
15
|
+
type: "ref";
|
|
16
|
+
href: string;
|
|
17
|
+
label: string;
|
|
14
18
|
} | {
|
|
15
19
|
type: "code";
|
|
16
20
|
text: string;
|
|
@@ -111,47 +115,99 @@ declare const removeLink: (nodes: Node[], sel: NodeSelection) => Result<Node[],
|
|
|
111
115
|
|
|
112
116
|
type TransformResult = {
|
|
113
117
|
block: AnyBlock;
|
|
118
|
+
/** true if the block type was actually changed, false if no trigger matched */
|
|
114
119
|
converted: boolean;
|
|
115
120
|
};
|
|
121
|
+
declare function stripPrefix(block: Block<"paragraph">, prefix: string): Block<"paragraph">["content"];
|
|
116
122
|
/**
|
|
117
|
-
*
|
|
123
|
+
* Attempt to convert a paragraph block into another type based on a
|
|
124
|
+
* Markdown-style prefix typed by the user.
|
|
125
|
+
*
|
|
126
|
+
* Call this when a **space** is typed inside a paragraph block.
|
|
127
|
+
*
|
|
128
|
+
* Supported triggers (must appear at position 0, immediately before the space):
|
|
129
|
+
*
|
|
130
|
+
* | Typed | Converts to |
|
|
131
|
+
* |----------|-------------|
|
|
132
|
+
* | `-` | bullet |
|
|
133
|
+
* | `1.` | number |
|
|
134
|
+
* | `[]` | todo |
|
|
135
|
+
* | `#` | heading1 |
|
|
136
|
+
* | `##` | heading2 |
|
|
137
|
+
* | `###` | heading3 |
|
|
118
138
|
*
|
|
119
|
-
* Guards
|
|
120
|
-
* 1. block.type must be "paragraph"
|
|
121
|
-
* 2.
|
|
122
|
-
*
|
|
123
|
-
*
|
|
124
|
-
*
|
|
139
|
+
* Guards — returns `converted: false` without mutating if any fail:
|
|
140
|
+
* 1. `block.type` must be `"paragraph"`
|
|
141
|
+
* 2. The text must start with a known trigger prefix
|
|
142
|
+
* 3. `cursorOffset` must be ≥ `trigger.length + 1` — ensures the space
|
|
143
|
+
* was typed right after the trigger (blocks mid-text triggers like
|
|
144
|
+
* `"hello - "` from accidentally converting)
|
|
145
|
+
*
|
|
146
|
+
* On success the returned block has the trigger prefix stripped from its
|
|
147
|
+
* content and a freshly built `meta` for the target type.
|
|
125
148
|
*/
|
|
126
149
|
declare function applyMarkdownTransform(block: AnyBlock, cursorOffset: number): Result<TransformResult>;
|
|
127
150
|
/**
|
|
128
|
-
* Convert a block to a new type
|
|
151
|
+
* Convert a block to a new type, preserving content and meta where possible.
|
|
152
|
+
*
|
|
153
|
+
* Content conversion rules:
|
|
129
154
|
*
|
|
130
|
-
*
|
|
131
|
-
*
|
|
132
|
-
* rich
|
|
133
|
-
* code
|
|
134
|
-
* equation
|
|
135
|
-
* code
|
|
136
|
-
* equation
|
|
155
|
+
* | From | To | Content result |
|
|
156
|
+
* |-------------|-------------|----------------------------------------|
|
|
157
|
+
* | rich | rich | kept as-is |
|
|
158
|
+
* | rich | code | all text concatenated → `[CodeNode]` |
|
|
159
|
+
* | rich | equation | all text concatenated → `[EquationNode]`|
|
|
160
|
+
* | code | rich | `code.text` → single `TextNode` |
|
|
161
|
+
* | equation | rich | `equation.latex` → single `TextNode` |
|
|
162
|
+
* | code | equation | `code.text` as `latex` |
|
|
163
|
+
* | equation | code | `equation.latex` as `text` |
|
|
164
|
+
*
|
|
165
|
+
* Meta conversion rules:
|
|
166
|
+
* - list → list : `meta` (including `depth`) is preserved
|
|
167
|
+
* - anything else: fresh default `meta` is built for the target type
|
|
137
168
|
*/
|
|
138
169
|
declare function changeBlockType<T extends BlockType>(block: AnyBlock, targetType: T): Result<Block<T>>;
|
|
139
170
|
/**
|
|
140
171
|
* Toggle the checked state of a todo block.
|
|
141
|
-
*
|
|
172
|
+
*
|
|
173
|
+
* Cycle: `undefined → true → undefined`
|
|
174
|
+
*
|
|
175
|
+
* Returns `Err` if the block is not of type `"todo"`.
|
|
142
176
|
*/
|
|
143
177
|
declare function toggleTodo(block: AnyBlock): Result<Block<"todo">>;
|
|
144
178
|
type IndentableBlock = Block<"bullet"> | Block<"number"> | Block<"todo">;
|
|
145
179
|
/**
|
|
146
|
-
* Increase the depth of a bullet
|
|
147
|
-
*
|
|
180
|
+
* Increase the indentation depth of a list block (`bullet`, `number`, `todo`) by 1.
|
|
181
|
+
*
|
|
182
|
+
* - Maximum depth is `6`.
|
|
183
|
+
* - Returns `Err` if the block type is not indentable or is already at max depth.
|
|
148
184
|
*/
|
|
149
185
|
declare function indentBlock(block: AnyBlock): Result<IndentableBlock>;
|
|
150
186
|
/**
|
|
151
|
-
* Decrease the depth of a bullet
|
|
152
|
-
*
|
|
187
|
+
* Decrease the indentation depth of a list block (`bullet`, `number`, `todo`) by 1.
|
|
188
|
+
*
|
|
189
|
+
* - Minimum depth is `0`.
|
|
190
|
+
* - Returns `Err` if the block type is not indentable or is already at depth 0.
|
|
153
191
|
*/
|
|
154
192
|
declare function outdentBlock(block: AnyBlock): Result<IndentableBlock>;
|
|
193
|
+
/**
|
|
194
|
+
* Deep-equality check between two block arrays.
|
|
195
|
+
*
|
|
196
|
+
* Two arrays are considered the same when:
|
|
197
|
+
* - They have the same length
|
|
198
|
+
* - Every block at the same index has the same `id`, `type`, `meta`, and `content`
|
|
199
|
+
*
|
|
200
|
+
* Content nodes are compared field-by-field. Unknown extra fields on nodes are
|
|
201
|
+
* ignored so the check stays stable across schema additions.
|
|
202
|
+
*
|
|
203
|
+
* Useful for preventing redundant saves or snapshot writes:
|
|
204
|
+
* ```ts
|
|
205
|
+
* if (!areBlocksSame(current, saved)) {
|
|
206
|
+
* await createSnapshot(current);
|
|
207
|
+
* }
|
|
208
|
+
* ```
|
|
209
|
+
*/
|
|
210
|
+
declare function areBlocksSame(blocks: AnyBlock[], withBlocks: AnyBlock[]): boolean;
|
|
155
211
|
|
|
156
212
|
/**
|
|
157
213
|
* Serialize an array of blocks to a JSON string.
|
|
@@ -267,4 +323,4 @@ declare function duplicateBlockAfter(blocks: AnyBlock[], id: string, newId?: str
|
|
|
267
323
|
*/
|
|
268
324
|
declare function moveBlock(blocks: AnyBlock[], id: string, direction: "up" | "down"): Result<AnyBlock[], string>;
|
|
269
325
|
|
|
270
|
-
export { type AnyBlock, type Block, type BlockContent, type BlockMeta, type BlockType, type History, type HistoryEntry, type Node, type NodeSelection, applyMarkdownTransform, canRedo, canUndo, changeBlockType, createBlock, createBlockAfter, createHistory, currentBlocks, deleteBlock, deleteLastChar, deleteRange, deserialize, deserializeNodes, duplicateBlock, duplicateBlockAfter, formatNodes, generateId, indentBlock, insertAt, insertBlockAfter, mergeAdjacentNodes, mergeBlocks, moveBlock, outdentBlock, push, redo, removeLink, replaceRange, serialize, serializeNodes, setLink, splitBlock, toMarkdown, toPlainText, toggleBold, toggleColor, toggleHighlight, toggleItalic, toggleStrikethrough, toggleTodo, toggleUnderline, undo };
|
|
326
|
+
export { type AnyBlock, type Block, type BlockContent, type BlockMeta, type BlockType, type History, type HistoryEntry, type Node, type NodeSelection, applyMarkdownTransform, areBlocksSame, canRedo, canUndo, changeBlockType, createBlock, createBlockAfter, createHistory, currentBlocks, deleteBlock, deleteLastChar, deleteRange, deserialize, deserializeNodes, duplicateBlock, duplicateBlockAfter, formatNodes, stripPrefix as formatParagraphBlock, generateId, indentBlock, insertAt, insertBlockAfter, mergeAdjacentNodes, mergeBlocks, moveBlock, outdentBlock, push, redo, removeLink, replaceRange, serialize, serializeNodes, setLink, splitBlock, toMarkdown, toPlainText, toggleBold, toggleColor, toggleHighlight, toggleItalic, toggleStrikethrough, toggleTodo, toggleUnderline, undo };
|
package/dist/index.js
CHANGED
|
@@ -552,18 +552,15 @@ function buildMetaForTarget(targetType) {
|
|
|
552
552
|
case "number":
|
|
553
553
|
case "todo":
|
|
554
554
|
return { depth: 0 };
|
|
555
|
-
|
|
556
|
-
case "heading2":
|
|
557
|
-
case "heading3":
|
|
558
|
-
case "paragraph":
|
|
559
|
-
case "code":
|
|
560
|
-
case "equation":
|
|
555
|
+
default:
|
|
561
556
|
return {};
|
|
562
557
|
}
|
|
563
558
|
}
|
|
559
|
+
function isList(type) {
|
|
560
|
+
return type === "bullet" || type === "todo" || type === "number";
|
|
561
|
+
}
|
|
564
562
|
function deriveMeta(block, targetType) {
|
|
565
|
-
if (isList(block.type) && isList(targetType))
|
|
566
|
-
return block.meta;
|
|
563
|
+
if (isList(block.type) && isList(targetType)) return block.meta;
|
|
567
564
|
return buildMetaForTarget(targetType);
|
|
568
565
|
}
|
|
569
566
|
function toggleTodo(block) {
|
|
@@ -578,9 +575,6 @@ var MAX_DEPTH = 6;
|
|
|
578
575
|
function isIndentable(block) {
|
|
579
576
|
return block.type === "bullet" || block.type === "number" || block.type === "todo";
|
|
580
577
|
}
|
|
581
|
-
function isList(type) {
|
|
582
|
-
return type === "bullet" || type === "todo" || type === "number";
|
|
583
|
-
}
|
|
584
578
|
function indentBlock(block) {
|
|
585
579
|
if (!isIndentable(block))
|
|
586
580
|
return Result4.Err(
|
|
@@ -604,6 +598,31 @@ function outdentBlock(block) {
|
|
|
604
598
|
meta: { ...block.meta, depth: block.meta.depth - 1 }
|
|
605
599
|
});
|
|
606
600
|
}
|
|
601
|
+
function areBlocksSame(blocks, withBlocks) {
|
|
602
|
+
if (blocks.length !== withBlocks.length) return false;
|
|
603
|
+
return blocks.every((a, i) => {
|
|
604
|
+
const b = withBlocks[i];
|
|
605
|
+
if (a.type !== b.type) return false;
|
|
606
|
+
if (JSON.stringify(a.meta) !== JSON.stringify(b.meta)) return false;
|
|
607
|
+
if (a.content.length !== b.content.length) return false;
|
|
608
|
+
return a.content.every((an, j) => {
|
|
609
|
+
const bn = b.content[j];
|
|
610
|
+
if (an.type !== bn.type) return false;
|
|
611
|
+
switch (an.type) {
|
|
612
|
+
case "code":
|
|
613
|
+
return an.text === bn.text;
|
|
614
|
+
case "equation":
|
|
615
|
+
return an.latex === bn.latex;
|
|
616
|
+
case "text": {
|
|
617
|
+
const bt = bn;
|
|
618
|
+
return an.text === bt.text && an.bold === bt.bold && an.italic === bt.italic && an.underline === bt.underline && an.strikethrough === bt.strikethrough && an.highlighted === bt.highlighted && an.color === bt.color && an.link === bt.link;
|
|
619
|
+
}
|
|
620
|
+
default:
|
|
621
|
+
return false;
|
|
622
|
+
}
|
|
623
|
+
});
|
|
624
|
+
});
|
|
625
|
+
}
|
|
607
626
|
|
|
608
627
|
// src/engine/serializer.ts
|
|
609
628
|
import { Result as Result5 } from "@reiwuzen/result";
|
|
@@ -702,6 +721,7 @@ function nodesToMarkdown(nodes) {
|
|
|
702
721
|
return nodes.map((n) => {
|
|
703
722
|
if (n.type === "code") return `\`${n.text}\``;
|
|
704
723
|
if (n.type === "equation") return `$${n.latex}$`;
|
|
724
|
+
if (n.type === "ref") return `[${n.label}](${n.href})`;
|
|
705
725
|
let text = n.text;
|
|
706
726
|
if (n.bold) text = `**${text}**`;
|
|
707
727
|
if (n.italic) text = `*${text}*`;
|
|
@@ -789,6 +809,7 @@ var canRedo = (history) => history.future.length > 0;
|
|
|
789
809
|
var currentBlocks = (history) => history.present.blocks;
|
|
790
810
|
export {
|
|
791
811
|
applyMarkdownTransform,
|
|
812
|
+
areBlocksSame,
|
|
792
813
|
canRedo,
|
|
793
814
|
canUndo,
|
|
794
815
|
changeBlockType,
|
|
@@ -804,6 +825,7 @@ export {
|
|
|
804
825
|
duplicateBlock,
|
|
805
826
|
duplicateBlockAfter,
|
|
806
827
|
formatNodes,
|
|
828
|
+
stripPrefix as formatParagraphBlock,
|
|
807
829
|
generateId,
|
|
808
830
|
indentBlock,
|
|
809
831
|
insertAt,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@reiwuzen/blocky",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.4.2",
|
|
4
4
|
"description": "Pure TypeScript block editor engine. Headless, framework-agnostic — content mutation, formatting, transforms, serialization, and history.",
|
|
5
5
|
"author": "Rei WuZen",
|
|
6
6
|
"license": "ISC",
|