@reiwuzen/blocky 1.2.0 → 1.3.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/dist/index.cjs CHANGED
@@ -29,6 +29,7 @@ __export(index_exports, {
29
29
  canUndo: () => canUndo,
30
30
  changeBlockType: () => changeBlockType,
31
31
  createBlock: () => createBlock,
32
+ createBlockAfter: () => createBlockAfter,
32
33
  createHistory: () => createHistory,
33
34
  currentBlocks: () => currentBlocks,
34
35
  deleteBlock: () => deleteBlock,
@@ -37,6 +38,7 @@ __export(index_exports, {
37
38
  deserialize: () => deserialize,
38
39
  deserializeNodes: () => deserializeNodes,
39
40
  duplicateBlock: () => duplicateBlock,
41
+ duplicateBlockAfter: () => duplicateBlockAfter,
40
42
  flatToPosition: () => flatToPosition,
41
43
  flatToSelection: () => flatToSelection,
42
44
  formatNodes: () => formatNodes,
@@ -109,12 +111,28 @@ function createBlock(type, idFn) {
109
111
  return block;
110
112
  });
111
113
  }
112
- function insertBlockAfter(blocks, afterId, type, idFn) {
113
- return createBlock(type, idFn).map((newBlock) => {
114
+ function createBlockAfter(blocks, afterId, type, idFn) {
115
+ return createBlock(type, idFn).andThen((newBlock) => {
114
116
  const index = blocks.findIndex((b) => b.id === afterId);
117
+ if (index === -1) return import_result.Result.Err(`[BlockNotFound]: ${afterId}`);
115
118
  const next = [...blocks];
116
119
  next.splice(index + 1, 0, newBlock);
117
- return { blocks: next, newId: newBlock.id };
120
+ return import_result.Result.Ok({ blocks: next, newId: newBlock.id });
121
+ });
122
+ }
123
+ function insertBlockAfter(blocks, afterId, insertBlock) {
124
+ const targetBlockIndex = blocks.findIndex((b) => b.id === afterId);
125
+ if (targetBlockIndex === -1) {
126
+ return import_result.Result.Err(`No block found with id: ${afterId}`);
127
+ }
128
+ const newBlocks = [
129
+ ...blocks.slice(0, targetBlockIndex + 1),
130
+ insertBlock,
131
+ ...blocks.slice(targetBlockIndex + 1)
132
+ ];
133
+ return import_result.Result.Ok({
134
+ blocks: newBlocks,
135
+ newFocusId: insertBlock.id
118
136
  });
119
137
  }
120
138
  function deleteBlock(blocks, id) {
@@ -122,8 +140,19 @@ function deleteBlock(blocks, id) {
122
140
  const prevId = blocks[index - 1]?.id ?? blocks[index + 1]?.id ?? "";
123
141
  return { blocks: blocks.filter((b) => b.id !== id), prevId };
124
142
  }
125
- function duplicateBlock(incoming, newId) {
126
- return { ...incoming, id: newId };
143
+ function duplicateBlock(incoming, newId = crypto.randomUUID()) {
144
+ return {
145
+ ...incoming,
146
+ id: newId,
147
+ meta: { ...incoming.meta },
148
+ content: incoming.content.map((node) => ({ ...node }))
149
+ };
150
+ }
151
+ function duplicateBlockAfter(blocks, id, newId) {
152
+ const targetBlock = blocks.find((b) => b.id === id);
153
+ if (targetBlock == null) return import_result.Result.Err(`[BlockNotFound]: ${id}`);
154
+ const dup = duplicateBlock(targetBlock, newId);
155
+ return insertBlockAfter(blocks, id, dup);
127
156
  }
128
157
  function moveBlock(blocks, id, direction) {
129
158
  const index = blocks.findIndex((b) => b.id === id);
@@ -913,6 +942,7 @@ function blockReplaceRange(block, startNodeIndex, startOffset, endNodeIndex, end
913
942
  canUndo,
914
943
  changeBlockType,
915
944
  createBlock,
945
+ createBlockAfter,
916
946
  createHistory,
917
947
  currentBlocks,
918
948
  deleteBlock,
@@ -921,6 +951,7 @@ function blockReplaceRange(block, startNodeIndex, startOffset, endNodeIndex, end
921
951
  deserialize,
922
952
  deserializeNodes,
923
953
  duplicateBlock,
954
+ duplicateBlockAfter,
924
955
  flatToPosition,
925
956
  flatToSelection,
926
957
  formatNodes,
package/dist/index.d.cts CHANGED
@@ -278,15 +278,23 @@ declare function generateId(fn?: () => string): string;
278
278
  * @param idFn - optional custom id generator (defaults to uuid v7)
279
279
  */
280
280
  declare function createBlock<T extends BlockType>(type: T, idFn?: () => string): Result<Block<T>, unknown>;
281
- declare function insertBlockAfter<T extends BlockType>(blocks: AnyBlock[], afterId: string, type: T, idFn?: () => string): Result<{
281
+ declare function createBlockAfter<T extends BlockType>(blocks: AnyBlock[], afterId: string, type: T, idFn?: () => string): Result<{
282
282
  blocks: AnyBlock[];
283
283
  newId: string;
284
284
  }, unknown>;
285
+ declare function insertBlockAfter(blocks: AnyBlock[], afterId: string, insertBlock: AnyBlock): Result<{
286
+ blocks: AnyBlock[];
287
+ newFocusId: string;
288
+ }, unknown>;
285
289
  declare function deleteBlock(blocks: AnyBlock[], id: string): {
286
290
  blocks: AnyBlock[];
287
291
  prevId: string;
288
292
  };
289
- declare function duplicateBlock(incoming: AnyBlock, newId: string): AnyBlock;
293
+ declare function duplicateBlock(incoming: AnyBlock, newId?: string): AnyBlock;
294
+ declare function duplicateBlockAfter(blocks: AnyBlock[], id: string, newId?: string): Result<{
295
+ blocks: AnyBlock[];
296
+ newFocusId: string;
297
+ }, unknown>;
290
298
  /**
291
299
  * Move a block up or down by one position in the array.
292
300
  * Returns the same array unchanged if block is already at the boundary.
@@ -303,4 +311,4 @@ declare function blockDeleteLastChar(block: AnyBlock): Result<AnyBlock>;
303
311
  declare function blockDeleteRange(block: AnyBlock, startNodeIndex: number, startOffset: number, endNodeIndex: number, endOffset: number): Result<AnyBlock>;
304
312
  declare function blockReplaceRange(block: AnyBlock, startNodeIndex: number, startOffset: number, endNodeIndex: number, endOffset: number, incoming: Node): Result<AnyBlock>;
305
313
 
306
- export { type AnyBlock, type Block, type BlockContent, type BlockMeta, type BlockType, type History, type HistoryEntry, type Node, type NodeSelection, applyMarkdownTransform, blockDeleteLastChar, blockDeleteRange, blockInsertAt, blockReplaceRange, canRedo, canUndo, changeBlockType, createBlock, createHistory, currentBlocks, deleteBlock, deleteLastChar, deleteRange, deserialize, deserializeNodes, duplicateBlock, flatToPosition, flatToSelection, formatNodes, generateId, indentBlock, insertAt, insertBlockAfter, mergeAdjacentNodes, mergeBlocks, moveBlock, outdentBlock, positionToFlat, push, redo, removeLink, replaceRange, serialize, serializeNodes, setLink, splitBlock, toMarkdown, toPlainText, toggleBold, toggleColor, toggleHighlight, toggleItalic, toggleStrikethrough, toggleTodo, toggleUnderline, undo };
314
+ export { type AnyBlock, type Block, type BlockContent, type BlockMeta, type BlockType, type History, type HistoryEntry, type Node, type NodeSelection, applyMarkdownTransform, blockDeleteLastChar, blockDeleteRange, blockInsertAt, blockReplaceRange, canRedo, canUndo, changeBlockType, createBlock, createBlockAfter, createHistory, currentBlocks, deleteBlock, deleteLastChar, deleteRange, deserialize, deserializeNodes, duplicateBlock, duplicateBlockAfter, flatToPosition, flatToSelection, formatNodes, generateId, indentBlock, insertAt, insertBlockAfter, mergeAdjacentNodes, mergeBlocks, moveBlock, outdentBlock, positionToFlat, push, redo, removeLink, replaceRange, serialize, serializeNodes, setLink, splitBlock, toMarkdown, toPlainText, toggleBold, toggleColor, toggleHighlight, toggleItalic, toggleStrikethrough, toggleTodo, toggleUnderline, undo };
package/dist/index.d.ts CHANGED
@@ -278,15 +278,23 @@ declare function generateId(fn?: () => string): string;
278
278
  * @param idFn - optional custom id generator (defaults to uuid v7)
279
279
  */
280
280
  declare function createBlock<T extends BlockType>(type: T, idFn?: () => string): Result<Block<T>, unknown>;
281
- declare function insertBlockAfter<T extends BlockType>(blocks: AnyBlock[], afterId: string, type: T, idFn?: () => string): Result<{
281
+ declare function createBlockAfter<T extends BlockType>(blocks: AnyBlock[], afterId: string, type: T, idFn?: () => string): Result<{
282
282
  blocks: AnyBlock[];
283
283
  newId: string;
284
284
  }, unknown>;
285
+ declare function insertBlockAfter(blocks: AnyBlock[], afterId: string, insertBlock: AnyBlock): Result<{
286
+ blocks: AnyBlock[];
287
+ newFocusId: string;
288
+ }, unknown>;
285
289
  declare function deleteBlock(blocks: AnyBlock[], id: string): {
286
290
  blocks: AnyBlock[];
287
291
  prevId: string;
288
292
  };
289
- declare function duplicateBlock(incoming: AnyBlock, newId: string): AnyBlock;
293
+ declare function duplicateBlock(incoming: AnyBlock, newId?: string): AnyBlock;
294
+ declare function duplicateBlockAfter(blocks: AnyBlock[], id: string, newId?: string): Result<{
295
+ blocks: AnyBlock[];
296
+ newFocusId: string;
297
+ }, unknown>;
290
298
  /**
291
299
  * Move a block up or down by one position in the array.
292
300
  * Returns the same array unchanged if block is already at the boundary.
@@ -303,4 +311,4 @@ declare function blockDeleteLastChar(block: AnyBlock): Result<AnyBlock>;
303
311
  declare function blockDeleteRange(block: AnyBlock, startNodeIndex: number, startOffset: number, endNodeIndex: number, endOffset: number): Result<AnyBlock>;
304
312
  declare function blockReplaceRange(block: AnyBlock, startNodeIndex: number, startOffset: number, endNodeIndex: number, endOffset: number, incoming: Node): Result<AnyBlock>;
305
313
 
306
- export { type AnyBlock, type Block, type BlockContent, type BlockMeta, type BlockType, type History, type HistoryEntry, type Node, type NodeSelection, applyMarkdownTransform, blockDeleteLastChar, blockDeleteRange, blockInsertAt, blockReplaceRange, canRedo, canUndo, changeBlockType, createBlock, createHistory, currentBlocks, deleteBlock, deleteLastChar, deleteRange, deserialize, deserializeNodes, duplicateBlock, flatToPosition, flatToSelection, formatNodes, generateId, indentBlock, insertAt, insertBlockAfter, mergeAdjacentNodes, mergeBlocks, moveBlock, outdentBlock, positionToFlat, push, redo, removeLink, replaceRange, serialize, serializeNodes, setLink, splitBlock, toMarkdown, toPlainText, toggleBold, toggleColor, toggleHighlight, toggleItalic, toggleStrikethrough, toggleTodo, toggleUnderline, undo };
314
+ export { type AnyBlock, type Block, type BlockContent, type BlockMeta, type BlockType, type History, type HistoryEntry, type Node, type NodeSelection, applyMarkdownTransform, blockDeleteLastChar, blockDeleteRange, blockInsertAt, blockReplaceRange, canRedo, canUndo, changeBlockType, createBlock, createBlockAfter, createHistory, currentBlocks, deleteBlock, deleteLastChar, deleteRange, deserialize, deserializeNodes, duplicateBlock, duplicateBlockAfter, flatToPosition, flatToSelection, formatNodes, generateId, indentBlock, insertAt, insertBlockAfter, mergeAdjacentNodes, mergeBlocks, moveBlock, outdentBlock, positionToFlat, push, redo, removeLink, replaceRange, serialize, serializeNodes, setLink, splitBlock, toMarkdown, toPlainText, toggleBold, toggleColor, toggleHighlight, toggleItalic, toggleStrikethrough, toggleTodo, toggleUnderline, undo };
package/dist/index.js CHANGED
@@ -37,12 +37,28 @@ function createBlock(type, idFn) {
37
37
  return block;
38
38
  });
39
39
  }
40
- function insertBlockAfter(blocks, afterId, type, idFn) {
41
- return createBlock(type, idFn).map((newBlock) => {
40
+ function createBlockAfter(blocks, afterId, type, idFn) {
41
+ return createBlock(type, idFn).andThen((newBlock) => {
42
42
  const index = blocks.findIndex((b) => b.id === afterId);
43
+ if (index === -1) return Result.Err(`[BlockNotFound]: ${afterId}`);
43
44
  const next = [...blocks];
44
45
  next.splice(index + 1, 0, newBlock);
45
- return { blocks: next, newId: newBlock.id };
46
+ return Result.Ok({ blocks: next, newId: newBlock.id });
47
+ });
48
+ }
49
+ function insertBlockAfter(blocks, afterId, insertBlock) {
50
+ const targetBlockIndex = blocks.findIndex((b) => b.id === afterId);
51
+ if (targetBlockIndex === -1) {
52
+ return Result.Err(`No block found with id: ${afterId}`);
53
+ }
54
+ const newBlocks = [
55
+ ...blocks.slice(0, targetBlockIndex + 1),
56
+ insertBlock,
57
+ ...blocks.slice(targetBlockIndex + 1)
58
+ ];
59
+ return Result.Ok({
60
+ blocks: newBlocks,
61
+ newFocusId: insertBlock.id
46
62
  });
47
63
  }
48
64
  function deleteBlock(blocks, id) {
@@ -50,8 +66,19 @@ function deleteBlock(blocks, id) {
50
66
  const prevId = blocks[index - 1]?.id ?? blocks[index + 1]?.id ?? "";
51
67
  return { blocks: blocks.filter((b) => b.id !== id), prevId };
52
68
  }
53
- function duplicateBlock(incoming, newId) {
54
- return { ...incoming, id: newId };
69
+ function duplicateBlock(incoming, newId = crypto.randomUUID()) {
70
+ return {
71
+ ...incoming,
72
+ id: newId,
73
+ meta: { ...incoming.meta },
74
+ content: incoming.content.map((node) => ({ ...node }))
75
+ };
76
+ }
77
+ function duplicateBlockAfter(blocks, id, newId) {
78
+ const targetBlock = blocks.find((b) => b.id === id);
79
+ if (targetBlock == null) return Result.Err(`[BlockNotFound]: ${id}`);
80
+ const dup = duplicateBlock(targetBlock, newId);
81
+ return insertBlockAfter(blocks, id, dup);
55
82
  }
56
83
  function moveBlock(blocks, id, direction) {
57
84
  const index = blocks.findIndex((b) => b.id === id);
@@ -840,6 +867,7 @@ export {
840
867
  canUndo,
841
868
  changeBlockType,
842
869
  createBlock,
870
+ createBlockAfter,
843
871
  createHistory,
844
872
  currentBlocks,
845
873
  deleteBlock,
@@ -848,6 +876,7 @@ export {
848
876
  deserialize,
849
877
  deserializeNodes,
850
878
  duplicateBlock,
879
+ duplicateBlockAfter,
851
880
  flatToPosition,
852
881
  flatToSelection,
853
882
  formatNodes,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@reiwuzen/blocky",
3
- "version": "1.2.0",
3
+ "version": "1.3.0",
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",