@jackuait/blok 0.6.0-beta.6 → 0.6.0-beta.7

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.
@@ -1,4 +1,4 @@
1
- import { e as i } from "./blok-BOtlKwVO.mjs";
1
+ import { e as i } from "./blok-Bjkxis7j.mjs";
2
2
  const l = async (e, r) => {
3
3
  const n = (await import("./i18next-CugVlwWp.mjs")).default.createInstance(), s = {
4
4
  lng: e,
@@ -1,4 +1,4 @@
1
- import { a2 as s, t as f } from "./inline-tool-convert-UoYdJJic.mjs";
1
+ import { a2 as s, t as f } from "./inline-tool-convert-5DE7c2fi.mjs";
2
2
  const a = {
3
3
  wrapper: s(
4
4
  "fixed z-[2] bottom-5 left-5",
@@ -278,7 +278,7 @@ const d = {
278
278
  DELETE: 46
279
279
  }, Ae = {
280
280
  LEFT: 0
281
- }, Se = 650, Wt = () => "0.6.0-beta.6";
281
+ }, Se = 650, Wt = () => "0.6.0-beta.7";
282
282
  var Vt = /* @__PURE__ */ ((n) => (n.VERBOSE = "VERBOSE", n.INFO = "INFO", n.WARN = "WARN", n.ERROR = "ERROR", n))(Vt || {});
283
283
  const V = (n, t, e = "log", o, s = "color: inherit") => {
284
284
  const i = typeof console == "undefined" ? void 0 : console;
package/dist/full.mjs CHANGED
@@ -12,8 +12,8 @@ var e = (a, l, o) => l in a ? n(a, l, { enumerable: !0, configurable: !0, writab
12
12
  }, r = (a, l) => t(a, c(l));
13
13
  import { Link as p, Italic as f, Bold as I, List as k, Header as u, Paragraph as B } from "./tools.mjs";
14
14
  import { defaultBlockTools as v, defaultInlineTools as A } from "./tools.mjs";
15
- import { B as H, v as P } from "./chunks/blok-BOtlKwVO.mjs";
16
- import { D as _ } from "./chunks/inline-tool-convert-UoYdJJic.mjs";
15
+ import { B as H, v as P } from "./chunks/blok-Bjkxis7j.mjs";
16
+ import { D as _ } from "./chunks/inline-tool-convert-5DE7c2fi.mjs";
17
17
  const m = {
18
18
  paragraph: {
19
19
  class: B,
package/dist/tools.mjs CHANGED
@@ -10,8 +10,8 @@ var Tt = (i, t, e) => t in i ? ke(i, t, { enumerable: !0, configurable: !0, writ
10
10
  Le.call(t, e) && Tt(i, e, t[e]);
11
11
  return i;
12
12
  }, tt = (i, t) => xe(i, Te(t));
13
- import { t as v, D as E, am as Be, an as Ie, _ as Ne, ao as De, ap as He, aq as Pe, ar as _e, as as Oe, at as Me, au as Qt, av as te, aw as ee, o as We, p as Rt, a5 as Lt, a3 as $e, ax as Ge, J as ne, Q as se, P as F, ay as qe, az as Fe, a0 as oe, aA as ze, aB as Ve, aC as Ue, aD as Ke, aE as je, z as H, aF as Xe, aG as Ye, S as et, aH as Ze, l as Je, a8 as Qe } from "./chunks/inline-tool-convert-UoYdJJic.mjs";
14
- import { ab as xo } from "./chunks/inline-tool-convert-UoYdJJic.mjs";
13
+ import { t as v, D as E, am as Be, an as Ie, _ as Ne, ao as De, ap as He, aq as Pe, ar as _e, as as Oe, at as Me, au as Qt, av as te, aw as ee, o as We, p as Rt, a5 as Lt, a3 as $e, ax as Ge, J as ne, Q as se, P as F, ay as qe, az as Fe, a0 as oe, aA as ze, aB as Ve, aC as Ue, aD as Ke, aE as je, z as H, aF as Xe, aG as Ye, S as et, aH as Ze, l as Je, a8 as Qe } from "./chunks/inline-tool-convert-5DE7c2fi.mjs";
14
+ import { ab as xo } from "./chunks/inline-tool-convert-5DE7c2fi.mjs";
15
15
  const ie = (i) => {
16
16
  if (!i || !i.includes("data-blok-fake-background"))
17
17
  return i;
@@ -1824,7 +1824,7 @@ class ds {
1824
1824
  return (r == null ? void 0 : r.offsetHeight) || 30;
1825
1825
  }
1826
1826
  if (this.getNewColumnWidth)
1827
- return this.getNewColumnWidth();
1827
+ return this.getNewColumnWidth() || 100;
1828
1828
  const e = this.grid.querySelector("[data-blok-table-row]");
1829
1829
  if (!e)
1830
1830
  return 100;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@jackuait/blok",
3
- "version": "0.6.0-beta.6",
3
+ "version": "0.6.0-beta.7",
4
4
  "description": "Blok — headless, highly extensible rich text editor built for developers who need to implement a block-based editing experience (similar to Notion) without building it from scratch",
5
5
  "module": "dist/blok.mjs",
6
6
  "types": "./types/index.d.ts",
@@ -140,11 +140,15 @@ export class RectangleSelection extends Module {
140
140
  const pointerX = pageX - scrollLeft;
141
141
 
142
142
  /**
143
- * Check if pointer is within editor's horizontal bounds.
143
+ * Check if pointer is within the content area's horizontal bounds.
144
144
  * This determines whether we should close the toolbar when starting selection.
145
- * Clicks outside the horizontal bounds (to the left or right) should NOT close the toolbar.
145
+ * Clicks outside the content area (to the left or right, in the margin/toolbar zone)
146
+ * should NOT close the toolbar. Use the first block's content element for bounds,
147
+ * falling back to the redactor bounds if no content element exists.
146
148
  */
147
- const withinEditorHorizontally = pointerX >= editorRect.left && pointerX <= editorRect.right;
149
+ const contentElement = redactor.querySelector('[data-blok-testid="block-content"]');
150
+ const contentRect = contentElement ? contentElement.getBoundingClientRect() : editorRect;
151
+ const withinEditorHorizontally = pointerX >= contentRect.left && pointerX <= contentRect.right;
148
152
 
149
153
  const elemWhereSelectionStart = document.elementFromPoint(pageX - scrollLeft, pointerY);
150
154
 
@@ -125,7 +125,9 @@ export class Saver extends Module {
125
125
  const extractedBlocks: OutputData['blocks'] = [];
126
126
 
127
127
  allExtractedData.forEach(({ id, tool, data, tunes, isValid, parentId, contentIds }) => {
128
- if (!isValid) {
128
+ const hasParent = parentId !== undefined && parentId !== null;
129
+
130
+ if (!isValid && !hasParent) {
129
131
  log(`Block «${tool}» skipped because saved data is invalid`);
130
132
 
131
133
  return;
@@ -151,7 +153,6 @@ export class Saver extends Module {
151
153
  }
152
154
 
153
155
  const isTunesEmpty = tunes === undefined || isEmpty(tunes);
154
- const hasParent = parentId !== undefined && parentId !== null;
155
156
  const hasContent = contentIds !== undefined && contentIds.length > 0;
156
157
 
157
158
  const output: OutputData['blocks'][number] = {
@@ -85,6 +85,13 @@ export class Toolbar extends Module<ToolbarNodes> {
85
85
  */
86
86
  private explicitlyClosed: boolean = false;
87
87
 
88
+ /**
89
+ * Flag to track if the current hovered block was resolved from a table cell block.
90
+ * When true, the toolbar suppresses plus button, settings toggler, and
91
+ * prevents overriding the current block when the toolbox opens.
92
+ */
93
+ private hoveredBlockIsFromTableCell: boolean = false;
94
+
88
95
  /**
89
96
  * Toolbox class instance
90
97
  * It will be created in requestIdleCallback so it can be null in some period of time
@@ -215,8 +222,10 @@ export class Toolbar extends Module<ToolbarNodes> {
215
222
 
216
223
  /**
217
224
  * Set current block to cover the case when the Toolbar showed near hovered Block but caret is set to another Block.
225
+ * Skip this when the hovered block was resolved from a table cell, so the toolbox
226
+ * can detect the original cell block and hide restricted tools (e.g., table, header).
218
227
  */
219
- if (this.hoveredBlock) {
228
+ if (this.hoveredBlock && !this.hoveredBlockIsFromTableCell) {
220
229
  this.Blok.BlockManager.currentBlock = this.hoveredBlock;
221
230
  }
222
231
 
@@ -328,11 +337,12 @@ export class Toolbar extends Module<ToolbarNodes> {
328
337
 
329
338
  const targetBlock = this.resolveTableCellBlock(unresolvedBlock);
330
339
 
331
- if (!targetBlock) {
332
- this.close();
333
-
334
- return;
335
- }
340
+ /**
341
+ * Track whether the original block was inside a table cell.
342
+ * When true, the toolbar suppresses plus button and settings toggler,
343
+ * and the toolbox uses the original current block for cell detection.
344
+ */
345
+ this.hoveredBlockIsFromTableCell = targetBlock !== unresolvedBlock;
336
346
 
337
347
  /** Clean up draggable on previous block if any */
338
348
  if (this.hoveredBlock && this.hoveredBlock !== targetBlock) {
@@ -351,6 +361,25 @@ export class Toolbar extends Module<ToolbarNodes> {
351
361
  return;
352
362
  }
353
363
 
364
+ /**
365
+ * Suppress toolbar buttons when the block is inside a table cell.
366
+ * The toolbar still positions itself for toolbox/slash-search purposes,
367
+ * but plus button and settings toggler remain hidden.
368
+ */
369
+ if (this.hoveredBlockIsFromTableCell) {
370
+ plusButton.style.display = 'none';
371
+
372
+ if (settingsToggler) {
373
+ settingsToggler.style.display = 'none';
374
+ }
375
+ } else {
376
+ plusButton.style.display = '';
377
+
378
+ if (settingsToggler) {
379
+ settingsToggler.style.display = '';
380
+ }
381
+ }
382
+
354
383
  const targetBlockHolder = targetBlock.holder;
355
384
  const { isMobile } = this.Blok.UI;
356
385
 
@@ -521,18 +550,24 @@ export class Toolbar extends Module<ToolbarNodes> {
521
550
  * to prevent toolbar from reopening on subsequent block-hovered events
522
551
  */
523
552
  this.hoveredBlock = null;
553
+ this.hoveredBlockIsFromTableCell = false;
524
554
  // Only set explicitlyClosed if not explicitly disabled (e.g., when called from toolbox after block insertion)
525
555
  if (options?.setExplicitlyClosed !== false) {
526
556
  this.explicitlyClosed = true;
527
557
  }
528
558
 
529
559
  /**
530
- * Restore plus button visibility in case it was hidden by other interactions
560
+ * Restore plus button and settings toggler visibility
561
+ * in case they were hidden for table cell blocks
531
562
  */
532
563
  if (this.nodes.plusButton) {
533
564
  this.nodes.plusButton.style.display = '';
534
565
  }
535
566
 
567
+ if (this.nodes.settingsToggler) {
568
+ this.nodes.settingsToggler.style.display = '';
569
+ }
570
+
536
571
  /**
537
572
  * Reset the content offset transform
538
573
  */
@@ -566,9 +601,9 @@ export class Toolbar extends Module<ToolbarNodes> {
566
601
  * Uses the DOM attribute directly to avoid cross-module dependency on the table tool.
567
602
  *
568
603
  * @param block - the block to resolve
569
- * @returns the parent table block if inside a cell, the original block otherwise, or null if resolution fails
604
+ * @returns the parent table block if inside a cell, the original block otherwise
570
605
  */
571
- private resolveTableCellBlock(block: Block): Block | null {
606
+ private resolveTableCellBlock(block: Block): Block {
572
607
  const cellBlocksContainer = block.holder.closest('[data-blok-table-cell-blocks]');
573
608
 
574
609
  if (!cellBlocksContainer) {
@@ -578,10 +613,10 @@ export class Toolbar extends Module<ToolbarNodes> {
578
613
  const tableBlockHolder = cellBlocksContainer.closest('[data-blok-testid="block-wrapper"]');
579
614
 
580
615
  if (!tableBlockHolder) {
581
- return null;
616
+ return block;
582
617
  }
583
618
 
584
- return this.Blok.BlockManager.getBlockByChildNode(tableBlockHolder) ?? null;
619
+ return this.Blok.BlockManager.getBlockByChildNode(tableBlockHolder) ?? block;
585
620
  }
586
621
 
587
622
  /**
@@ -173,12 +173,33 @@ export class PlusButtonHandler {
173
173
  const hoveredBlockIndex = hoveredBlock !== null
174
174
  ? BlockManager.getBlockIndex(hoveredBlock)
175
175
  : BlockManager.currentBlockIndex;
176
- const insertIndex = insertAbove ? hoveredBlockIndex : hoveredBlockIndex + 1;
176
+ const baseInsertIndex = insertAbove ? hoveredBlockIndex : hoveredBlockIndex + 1;
177
+
178
+ // When inserting below, skip past any blocks nested inside another block's
179
+ // DOM (e.g. paragraph blocks inside table cells). The block array may
180
+ // interleave nested blocks from multiple parents, so check whether each
181
+ // block's holder lives inside any block-wrapper ancestor rather than only
182
+ // the hovered block's holder.
183
+ const blocksAfterInsert = BlockManager.blocks.slice(baseInsertIndex);
184
+ const isNested = (block: Block): boolean =>
185
+ block.holder.parentElement?.closest('[data-blok-testid="block-wrapper"]') !== null;
186
+ const firstNonNestedOffset = !insertAbove && hoveredBlock && blocksAfterInsert.length > 0
187
+ ? blocksAfterInsert.findIndex((block) => !isNested(block))
188
+ : 0;
189
+ const insertIndex = baseInsertIndex + (firstNonNestedOffset === -1 ? blocksAfterInsert.length : firstNonNestedOffset);
177
190
 
178
191
  const targetBlock = isEmptyParagraph || startsWithSlash
179
192
  ? hoveredBlock
180
193
  : BlockManager.insertDefaultBlockAtIndex(insertIndex, true);
181
194
 
195
+ // The DOM insertion may place the new block's holder inside a nested
196
+ // container (e.g. a table cell) because the previous block in the array
197
+ // is inside another block's DOM. Move the holder to be a sibling after
198
+ // the hovered block so it becomes a top-level block.
199
+ if (targetBlock !== hoveredBlock && isNested(targetBlock)) {
200
+ hoveredBlock?.holder.after(targetBlock.holder);
201
+ }
202
+
182
203
  // Insert "/" or position caret after existing one
183
204
  if (startsWithSlash) {
184
205
  Caret.setToBlock(targetBlock, Caret.positions.DEFAULT, 1);
@@ -288,7 +288,7 @@ export class TableAddControls {
288
288
  }
289
289
 
290
290
  if (this.getNewColumnWidth) {
291
- return this.getNewColumnWidth();
291
+ return this.getNewColumnWidth() || 100;
292
292
  }
293
293
 
294
294
  const firstRow = this.grid.querySelector('[data-blok-table-row]');