@reiwuzen/blocky 1.4.2 → 1.4.4

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
@@ -37,7 +37,6 @@ __export(index_exports, {
37
37
  duplicateBlock: () => duplicateBlock,
38
38
  duplicateBlockAfter: () => duplicateBlockAfter,
39
39
  formatNodes: () => formatNodes,
40
- formatParagraphBlock: () => stripPrefix,
41
40
  generateId: () => generateId,
42
41
  indentBlock: () => indentBlock,
43
42
  insertAt: () => insertAt,
@@ -547,12 +546,13 @@ function replaceRange(block, startNodeIndex, startOffset, endNodeIndex, endOffse
547
546
  // src/engine/transform.ts
548
547
  var import_result4 = require("@reiwuzen/result");
549
548
  var TRIGGERS = {
550
- "-": "bullet",
551
- "1.": "number",
552
- "[]": "todo",
553
- "#": "heading1",
554
- "##": "heading2",
555
- "###": "heading3"
549
+ "-": { type: "bullet", meta: { depth: 0 } },
550
+ "1.": { type: "number", meta: { depth: 0 } },
551
+ "[]": { type: "todo", meta: { depth: 0, checked: false } },
552
+ "[x]": { type: "todo", meta: { depth: 0, checked: true } },
553
+ "#": { type: "heading1" },
554
+ "##": { type: "heading2" },
555
+ "###": { type: "heading3" }
556
556
  };
557
557
  function getRawText(block) {
558
558
  const first = block.content[0];
@@ -567,19 +567,25 @@ function stripPrefix(block, prefix) {
567
567
  return [{ ...first, text: stripped }, ...block.content.slice(1)];
568
568
  }
569
569
  function applyMarkdownTransform(block, cursorOffset) {
570
- if (block.type !== "paragraph") return import_result4.Result.Ok({ block, converted: false });
570
+ if (block.type !== "paragraph")
571
+ return import_result4.Result.Ok({ block, converted: false });
571
572
  const text = getRawText(block);
572
- const match = Object.keys(TRIGGERS).sort((a, b) => b.length - a.length).find((trigger) => text === trigger || text.startsWith(trigger + " "));
573
- if (!match) return import_result4.Result.Ok({ block, converted: false });
574
- const triggerEnd = match.length + 1;
575
- if (cursorOffset < triggerEnd) return import_result4.Result.Ok({ block, converted: false });
576
- const targetType = TRIGGERS[match];
573
+ const match = Object.keys(TRIGGERS).sort((a, b) => b.length - a.length).find((trigger) => text === trigger);
574
+ if (!match)
575
+ return import_result4.Result.Ok({ block, converted: false });
576
+ if (cursorOffset < match.length)
577
+ return import_result4.Result.Ok({ block, converted: false });
578
+ const spec = TRIGGERS[match];
577
579
  const strippedContent = stripPrefix(block, match);
580
+ const baseMeta = buildMetaForTarget(spec.type);
578
581
  const converted = {
579
582
  id: block.id,
580
- type: targetType,
583
+ type: spec.type,
581
584
  content: strippedContent,
582
- meta: buildMetaForTarget(targetType)
585
+ meta: {
586
+ ...baseMeta,
587
+ ...spec.meta ?? {}
588
+ }
583
589
  };
584
590
  return import_result4.Result.Ok({ block: converted, converted: true });
585
591
  }
@@ -895,7 +901,6 @@ var currentBlocks = (history) => history.present.blocks;
895
901
  duplicateBlock,
896
902
  duplicateBlockAfter,
897
903
  formatNodes,
898
- formatParagraphBlock,
899
904
  generateId,
900
905
  indentBlock,
901
906
  insertAt,
package/dist/index.d.cts CHANGED
@@ -118,33 +118,43 @@ type TransformResult = {
118
118
  /** true if the block type was actually changed, false if no trigger matched */
119
119
  converted: boolean;
120
120
  };
121
- declare function stripPrefix(block: Block<"paragraph">, prefix: string): Block<"paragraph">["content"];
122
121
  /**
123
122
  * Attempt to convert a paragraph block into another type based on a
124
123
  * Markdown-style prefix typed by the user.
125
124
  *
126
- * Call this when a **space** is typed inside a paragraph block.
125
+ * This transform is intended to be called by the UI **when the user presses
126
+ * space** inside a paragraph block.
127
127
  *
128
- * Supported triggers (must appear at position 0, immediately before the space):
128
+ * The engine itself does NOT check for the space character — the caller is
129
+ * responsible for invoking this function at the correct time.
129
130
  *
130
- * | Typed | Converts to |
131
- * |----------|-------------|
132
- * | `-` | bullet |
133
- * | `1.` | number |
134
- * | `[]` | todo |
135
- * | `#` | heading1 |
136
- * | `##` | heading2 |
137
- * | `###` | heading3 |
131
+ * Supported triggers (must appear at position 0):
138
132
  *
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)
133
+ * | Typed | Converts to | Meta |
134
+ * |------|---------------|------|
135
+ * | `-` | bullet | `{ depth: 0 }` |
136
+ * | `1.` | number | `{ depth: 0 }` |
137
+ * | `[]` | todo | `{ depth: 0, checked: false }` |
138
+ * | `[x]` | todo | `{ depth: 0, checked: true }` |
139
+ * | `#` | heading1 | default meta |
140
+ * | `##` | heading2 | default meta |
141
+ * | `###` | heading3 | default meta |
145
142
  *
146
- * On success the returned block has the trigger prefix stripped from its
147
- * content and a freshly built `meta` for the target type.
143
+ * Guards returns `{ converted: false }` without mutation if any fail:
144
+ *
145
+ * 1. `block.type` must be `"paragraph"`
146
+ * 2. The paragraph text must exactly match a trigger prefix
147
+ * 3. `cursorOffset` must be ≥ `trigger.length`
148
+ *
149
+ * On success:
150
+ *
151
+ * - The trigger prefix is stripped from the block content
152
+ * - A new block is returned with the target type
153
+ * - `meta` is constructed from:
154
+ *
155
+ * `buildMetaForTarget(type)` + trigger-specific overrides
156
+ *
157
+ * The original block object is never mutated.
148
158
  */
149
159
  declare function applyMarkdownTransform(block: AnyBlock, cursorOffset: number): Result<TransformResult>;
150
160
  /**
@@ -323,4 +333,4 @@ declare function duplicateBlockAfter(blocks: AnyBlock[], id: string, newId?: str
323
333
  */
324
334
  declare function moveBlock(blocks: AnyBlock[], id: string, direction: "up" | "down"): Result<AnyBlock[], string>;
325
335
 
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 };
336
+ 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, 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
@@ -118,33 +118,43 @@ type TransformResult = {
118
118
  /** true if the block type was actually changed, false if no trigger matched */
119
119
  converted: boolean;
120
120
  };
121
- declare function stripPrefix(block: Block<"paragraph">, prefix: string): Block<"paragraph">["content"];
122
121
  /**
123
122
  * Attempt to convert a paragraph block into another type based on a
124
123
  * Markdown-style prefix typed by the user.
125
124
  *
126
- * Call this when a **space** is typed inside a paragraph block.
125
+ * This transform is intended to be called by the UI **when the user presses
126
+ * space** inside a paragraph block.
127
127
  *
128
- * Supported triggers (must appear at position 0, immediately before the space):
128
+ * The engine itself does NOT check for the space character — the caller is
129
+ * responsible for invoking this function at the correct time.
129
130
  *
130
- * | Typed | Converts to |
131
- * |----------|-------------|
132
- * | `-` | bullet |
133
- * | `1.` | number |
134
- * | `[]` | todo |
135
- * | `#` | heading1 |
136
- * | `##` | heading2 |
137
- * | `###` | heading3 |
131
+ * Supported triggers (must appear at position 0):
138
132
  *
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)
133
+ * | Typed | Converts to | Meta |
134
+ * |------|---------------|------|
135
+ * | `-` | bullet | `{ depth: 0 }` |
136
+ * | `1.` | number | `{ depth: 0 }` |
137
+ * | `[]` | todo | `{ depth: 0, checked: false }` |
138
+ * | `[x]` | todo | `{ depth: 0, checked: true }` |
139
+ * | `#` | heading1 | default meta |
140
+ * | `##` | heading2 | default meta |
141
+ * | `###` | heading3 | default meta |
145
142
  *
146
- * On success the returned block has the trigger prefix stripped from its
147
- * content and a freshly built `meta` for the target type.
143
+ * Guards returns `{ converted: false }` without mutation if any fail:
144
+ *
145
+ * 1. `block.type` must be `"paragraph"`
146
+ * 2. The paragraph text must exactly match a trigger prefix
147
+ * 3. `cursorOffset` must be ≥ `trigger.length`
148
+ *
149
+ * On success:
150
+ *
151
+ * - The trigger prefix is stripped from the block content
152
+ * - A new block is returned with the target type
153
+ * - `meta` is constructed from:
154
+ *
155
+ * `buildMetaForTarget(type)` + trigger-specific overrides
156
+ *
157
+ * The original block object is never mutated.
148
158
  */
149
159
  declare function applyMarkdownTransform(block: AnyBlock, cursorOffset: number): Result<TransformResult>;
150
160
  /**
@@ -323,4 +333,4 @@ declare function duplicateBlockAfter(blocks: AnyBlock[], id: string, newId?: str
323
333
  */
324
334
  declare function moveBlock(blocks: AnyBlock[], id: string, direction: "up" | "down"): Result<AnyBlock[], string>;
325
335
 
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 };
336
+ 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, 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
@@ -478,12 +478,13 @@ function replaceRange(block, startNodeIndex, startOffset, endNodeIndex, endOffse
478
478
  // src/engine/transform.ts
479
479
  import { Result as Result4 } from "@reiwuzen/result";
480
480
  var TRIGGERS = {
481
- "-": "bullet",
482
- "1.": "number",
483
- "[]": "todo",
484
- "#": "heading1",
485
- "##": "heading2",
486
- "###": "heading3"
481
+ "-": { type: "bullet", meta: { depth: 0 } },
482
+ "1.": { type: "number", meta: { depth: 0 } },
483
+ "[]": { type: "todo", meta: { depth: 0, checked: false } },
484
+ "[x]": { type: "todo", meta: { depth: 0, checked: true } },
485
+ "#": { type: "heading1" },
486
+ "##": { type: "heading2" },
487
+ "###": { type: "heading3" }
487
488
  };
488
489
  function getRawText(block) {
489
490
  const first = block.content[0];
@@ -498,19 +499,25 @@ function stripPrefix(block, prefix) {
498
499
  return [{ ...first, text: stripped }, ...block.content.slice(1)];
499
500
  }
500
501
  function applyMarkdownTransform(block, cursorOffset) {
501
- if (block.type !== "paragraph") return Result4.Ok({ block, converted: false });
502
+ if (block.type !== "paragraph")
503
+ return Result4.Ok({ block, converted: false });
502
504
  const text = getRawText(block);
503
- const match = Object.keys(TRIGGERS).sort((a, b) => b.length - a.length).find((trigger) => text === trigger || text.startsWith(trigger + " "));
504
- if (!match) return Result4.Ok({ block, converted: false });
505
- const triggerEnd = match.length + 1;
506
- if (cursorOffset < triggerEnd) return Result4.Ok({ block, converted: false });
507
- const targetType = TRIGGERS[match];
505
+ const match = Object.keys(TRIGGERS).sort((a, b) => b.length - a.length).find((trigger) => text === trigger);
506
+ if (!match)
507
+ return Result4.Ok({ block, converted: false });
508
+ if (cursorOffset < match.length)
509
+ return Result4.Ok({ block, converted: false });
510
+ const spec = TRIGGERS[match];
508
511
  const strippedContent = stripPrefix(block, match);
512
+ const baseMeta = buildMetaForTarget(spec.type);
509
513
  const converted = {
510
514
  id: block.id,
511
- type: targetType,
515
+ type: spec.type,
512
516
  content: strippedContent,
513
- meta: buildMetaForTarget(targetType)
517
+ meta: {
518
+ ...baseMeta,
519
+ ...spec.meta ?? {}
520
+ }
514
521
  };
515
522
  return Result4.Ok({ block: converted, converted: true });
516
523
  }
@@ -825,7 +832,6 @@ export {
825
832
  duplicateBlock,
826
833
  duplicateBlockAfter,
827
834
  formatNodes,
828
- stripPrefix as formatParagraphBlock,
829
835
  generateId,
830
836
  indentBlock,
831
837
  insertAt,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@reiwuzen/blocky",
3
- "version": "1.4.2",
3
+ "version": "1.4.4",
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",