@jackuait/blok 0.10.7 → 0.10.9

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.
Files changed (49) hide show
  1. package/dist/blok.mjs +2 -2
  2. package/dist/chunks/{blok-oWXfRfnM.mjs → blok-DbRn9adY.mjs} +2681 -2238
  3. package/dist/chunks/{constants-BQ1-lyZI.mjs → constants-C9lsSOXl.mjs} +4 -3
  4. package/dist/chunks/{core-C942GvJO.mjs → core-B7mxBIHA.mjs} +1 -1
  5. package/dist/chunks/{engine-javascript-Dd6ViPCH.mjs → engine-javascript-Bmmg8uL9.mjs} +1 -1
  6. package/dist/chunks/{i18next-loader-CIXsptng.mjs → i18next-loader-453gJdot.mjs} +1 -1
  7. package/dist/chunks/{tools-MuBQQyZ-.mjs → tools-D0W3_dlA.mjs} +504 -499
  8. package/dist/full.mjs +3 -3
  9. package/dist/react.mjs +3 -3
  10. package/dist/tools.mjs +2 -2
  11. package/package.json +3 -6
  12. package/src/components/block/index.ts +36 -0
  13. package/src/components/blocks.ts +191 -5
  14. package/src/components/modules/api/blocks.ts +20 -5
  15. package/src/components/modules/blockEvents/composers/keyboardNavigation.ts +17 -6
  16. package/src/components/modules/blockManager/blockManager.ts +364 -23
  17. package/src/components/modules/blockManager/hierarchy.ts +164 -8
  18. package/src/components/modules/blockManager/operations.ts +223 -26
  19. package/src/components/modules/blockManager/types.ts +13 -1
  20. package/src/components/modules/blockManager/yjs-sync.ts +48 -3
  21. package/src/components/modules/drag/DragController.ts +209 -8
  22. package/src/components/modules/drag/operations/DragOperations.ts +153 -20
  23. package/src/components/modules/paste/handlers/base.ts +48 -20
  24. package/src/components/modules/paste/handlers/blok-data-handler.ts +184 -44
  25. package/src/components/modules/paste/index.ts +20 -0
  26. package/src/components/modules/renderer.ts +9 -1
  27. package/src/components/modules/saver.ts +75 -5
  28. package/src/components/modules/toolbar/index.ts +41 -60
  29. package/src/components/modules/uiControllers/controllers/keyboard.ts +20 -0
  30. package/src/components/modules/yjs/block-observer.ts +87 -23
  31. package/src/components/modules/yjs/document-store.ts +37 -11
  32. package/src/components/modules/yjs/index.ts +83 -7
  33. package/src/components/modules/yjs/types.ts +35 -2
  34. package/src/components/modules/yjs/undo-history.ts +116 -5
  35. package/src/components/utils/data-model-transform.ts +247 -35
  36. package/src/components/utils/hierarchy-invariant.ts +137 -0
  37. package/src/markdown/markdown-handler.ts +9 -2
  38. package/src/styles/main.css +5 -0
  39. package/src/tools/callout/constants.ts +0 -1
  40. package/src/tools/callout/dom-builder.ts +1 -11
  41. package/src/tools/callout/index.ts +0 -6
  42. package/src/tools/header/index.ts +14 -1
  43. package/src/tools/table/table-operations.ts +9 -4
  44. package/src/tools/toggle/constants.ts +2 -1
  45. package/src/tools/toggle/dom-builder.ts +7 -0
  46. package/src/tools/toggle/index.ts +14 -1
  47. package/src/tools/toggle/toggle-lifecycle.ts +24 -0
  48. /package/dist/chunks/{lightweight-i18n-DTYoSr_o.mjs → lightweight-i18n-DSjG0iTr.mjs} +0 -0
  49. /package/dist/chunks/{objectWithoutProperties-D0XxKB4n.mjs → objectWithoutProperties-Dci1-l7D.mjs} +0 -0
@@ -6,14 +6,12 @@ import {
6
6
  WRAPPER_STYLES,
7
7
  EMOJI_BUTTON_STYLES,
8
8
  CHILDREN_STYLES,
9
- DRAG_ZONE_STYLES,
10
9
  } from './constants';
11
10
 
12
11
  export interface CalloutDOMRefs {
13
12
  wrapper: HTMLElement;
14
13
  emojiButton: HTMLButtonElement;
15
14
  childContainer: HTMLElement;
16
- dragZone: HTMLElement;
17
15
  }
18
16
 
19
17
  export interface BuildCalloutDOMOptions {
@@ -53,13 +51,5 @@ export function buildCalloutDOM(options: BuildCalloutDOMOptions): CalloutDOMRefs
53
51
  wrapper.appendChild(emojiButton);
54
52
  wrapper.appendChild(childContainer);
55
53
 
56
- // Drag zone — covers left padding area (x=[0,16px]) for drag handle,
57
- // sits behind emoji button so emoji clicks pass through
58
- const dragZone = document.createElement('span');
59
- dragZone.className = DRAG_ZONE_STYLES;
60
- dragZone.style.width = '32px'; // matches pl-8 left padding
61
- dragZone.setAttribute('data-callout-drag-zone', '');
62
- wrapper.prepend(dragZone);
63
-
64
- return { wrapper, emojiButton, childContainer, dragZone };
54
+ return { wrapper, emojiButton, childContainer };
65
55
  }
@@ -66,7 +66,6 @@ export class CalloutTool implements BlockTool {
66
66
  private _dom: CalloutDOMRefs | null = null;
67
67
  private _emojiPicker: EmojiPicker | null = null;
68
68
  private _colorPicker: ColorPickerHandle | null = null;
69
- private _dragZone: HTMLElement | null = null;
70
69
  private blockId?: string;
71
70
 
72
71
  constructor({ data, api, readOnly, block }: BlockToolConstructorOptions<CalloutData, CalloutConfig>) {
@@ -121,7 +120,6 @@ export class CalloutTool implements BlockTool {
121
120
  });
122
121
 
123
122
  this._dom = dom;
124
- this._dragZone = dom.dragZone;
125
123
  this.applyColors();
126
124
 
127
125
  if (!this.readOnly) {
@@ -262,10 +260,6 @@ export class CalloutTool implements BlockTool {
262
260
  }
263
261
  }
264
262
 
265
- public get dragZone(): HTMLElement | null {
266
- return this._dragZone;
267
- }
268
-
269
263
  private syncPickerActiveColors(): void {
270
264
  if (this._colorPicker === null) {
271
265
  return;
@@ -23,7 +23,7 @@ import { PLACEHOLDER_CLASSES, setupPlaceholder } from '../../components/utils/pl
23
23
  import { twMerge } from '../../components/utils/tw';
24
24
  import { BODY_PLACEHOLDER_STYLES, TOGGLE_ATTR } from '../toggle/constants';
25
25
  import { buildArrow } from '../toggle/dom-builder';
26
- import { updateArrowState, updateBodyPlaceholderVisibility, updateChildrenVisibility } from '../toggle/toggle-lifecycle';
26
+ import { updateArrowState, updateBodyPlaceholderVisibility, updateChildrenVisibility, updateToggleEmptyState } from '../toggle/toggle-lifecycle';
27
27
  import { handleHeaderToggleEnter, handleHeaderToggleBackspace } from './header-toggle-keyboard';
28
28
 
29
29
  /**
@@ -764,6 +764,7 @@ export class Header implements BlockTool {
764
764
  */
765
765
  private buildWrapper(): HTMLElement {
766
766
  const wrapper = document.createElement('div');
767
+ wrapper.setAttribute(TOGGLE_ATTR.toggleEmpty, 'true');
767
768
 
768
769
  // Inner row: positioning context for the arrow (only heading height, not children).
769
770
  const headerRow = document.createElement('div');
@@ -799,12 +800,21 @@ export class Header implements BlockTool {
799
800
  // Block DOM mutations inside the children container from triggering the header tool's
800
801
  // didMutated → syncBlockDataToYjs path (same rationale as the toggle list tool).
801
802
  childContainer.setAttribute('data-blok-mutation-free', 'true');
803
+ /**
804
+ * Listen for typing inside child blocks so the empty-state attribute
805
+ * (and the grayish arrow it drives) tracks what the user types in real time.
806
+ */
807
+ childContainer.addEventListener('input', this.handleChildContainerInput);
802
808
  this._childContainerElement = childContainer;
803
809
  wrapper.appendChild(childContainer);
804
810
 
805
811
  return wrapper;
806
812
  }
807
813
 
814
+ private handleChildContainerInput = (): void => {
815
+ updateToggleEmptyState(this._wrapper, this._childContainerElement);
816
+ };
817
+
808
818
  /**
809
819
  * Wrap the heading element in a new wrapper div containing the toggle arrow,
810
820
  * replacing the heading's current position in the DOM.
@@ -814,6 +824,7 @@ export class Header implements BlockTool {
814
824
  const parent = this._element.parentNode;
815
825
 
816
826
  this._wrapper = document.createElement('div');
827
+ this._wrapper.setAttribute(TOGGLE_ATTR.toggleEmpty, 'true');
817
828
 
818
829
  // Inner row: positioning context for the arrow (only heading height, not children).
819
830
  const headerRow = document.createElement('div');
@@ -916,6 +927,8 @@ export class Header implements BlockTool {
916
927
  this._isOpen,
917
928
  this.readOnly
918
929
  );
930
+
931
+ updateToggleEmptyState(this._wrapper, this._childContainerElement);
919
932
  }
920
933
 
921
934
  /**
@@ -326,10 +326,15 @@ export const mountCellBlocksReadOnly = (
326
326
  continue;
327
327
  }
328
328
 
329
- // Skip blocks that don't belong to this table.
330
- // Corrupted data may contain cross-table references; mounting them
331
- // would steal (or clone) DOM nodes from the other table.
332
- if (block.parentId !== _tableBlockId) {
329
+ // Skip blocks whose parentId explicitly points to a DIFFERENT table
330
+ // (corrupted cross-table references). Blocks with null/undefined
331
+ // parentId are accepted: legitimate flat-array data shapes (e.g. the
332
+ // dodopizza article format) reference children by id from
333
+ // `cell.blocks` without setting `parent` on each child, and the
334
+ // Renderer's normalizeTableChildParents pre-step is the primary
335
+ // place that backfills parentId. This guard is defense-in-depth for
336
+ // load paths that bypass the Renderer (Yjs sync, direct insertion).
337
+ if (block.parentId !== null && block.parentId !== undefined && block.parentId !== _tableBlockId) {
333
338
  continue;
334
339
  }
335
340
 
@@ -43,7 +43,7 @@ export const TOGGLE_WRAPPER_STYLES = 'flex items-center';
43
43
  /**
44
44
  * Styles for the toggle arrow button
45
45
  */
46
- export const ARROW_STYLES = 'flex-shrink-0 p-[8px] flex items-center justify-center cursor-pointer select-none rounded can-hover:hover:bg-item-hover-bg transition-colors duration-200 ease-in-out focus-visible:ring-2 focus-visible:ring-blue-500 focus-visible:outline-none';
46
+ export const ARROW_STYLES = 'flex-shrink-0 p-[8px] flex items-center justify-center cursor-pointer select-none rounded can-hover:hover:bg-item-hover-bg transition-colors duration-200 ease-in-out focus-visible:ring-2 focus-visible:ring-blue-500 focus-visible:outline-none in-data-[blok-toggle-empty=true]:text-gray-text';
47
47
 
48
48
  /**
49
49
  * SVG icon for the toggle arrow
@@ -77,4 +77,5 @@ export const TOGGLE_ATTR = {
77
77
  toggleContent: 'data-blok-toggle-content',
78
78
  toggleBodyPlaceholder: 'data-blok-toggle-body-placeholder',
79
79
  toggleChildren: 'data-blok-toggle-children',
80
+ toggleEmpty: 'data-blok-toggle-empty',
80
81
  } as const;
@@ -73,6 +73,13 @@ export const buildToggleItem = (context: ToggleDOMBuilderContext): ToggleBuildRe
73
73
  wrapper.className = BASE_STYLES;
74
74
  wrapper.setAttribute(DATA_ATTR.tool, TOOL_NAME);
75
75
  wrapper.setAttribute(TOGGLE_ATTR.toggleOpen, String(isOpen));
76
+ /**
77
+ * Empty state default: assume no children until the tool syncs real state
78
+ * via updateToggleEmptyState() in its lifecycle methods. This drives the
79
+ * grayish arrow styling applied through the in-data-[blok-toggle-empty=true]
80
+ * Tailwind variant on ARROW_STYLES.
81
+ */
82
+ wrapper.setAttribute(TOGGLE_ATTR.toggleEmpty, 'true');
76
83
 
77
84
  const headerRow = document.createElement('div');
78
85
  headerRow.className = TOGGLE_WRAPPER_STYLES;
@@ -27,7 +27,7 @@ import {
27
27
  import { clean } from '../../components/utils/sanitizer';
28
28
  import { ARIA_LABEL_COLLAPSE_KEY, ARIA_LABEL_EXPAND_KEY, BODY_PLACEHOLDER_KEY, PLACEHOLDER_KEY, TOOL_NAME } from './constants';
29
29
  import { IconToggleList } from '../../components/icons';
30
- import { renderToggleItem, updateArrowState, updateChildrenVisibility, updateBodyPlaceholderVisibility } from './toggle-lifecycle';
30
+ import { renderToggleItem, updateArrowState, updateChildrenVisibility, updateBodyPlaceholderVisibility, updateToggleEmptyState } from './toggle-lifecycle';
31
31
  import { handleToggleEnter, handleToggleBackspace } from './toggle-keyboard';
32
32
  import type { ToggleItemData, ToggleItemConfig } from './types';
33
33
 
@@ -127,9 +127,20 @@ export class ToggleItem implements BlockTool {
127
127
  this._bodyPlaceholderElement = result.bodyPlaceholderElement;
128
128
  this._childContainerElement = result.childContainerElement;
129
129
 
130
+ /**
131
+ * Listen for input events from child blocks so the empty-state attribute
132
+ * (and the grayish arrow it drives) tracks what the user is typing in
133
+ * real time.
134
+ */
135
+ this._childContainerElement.addEventListener('input', this.handleChildContainerInput);
136
+
130
137
  return this._element;
131
138
  }
132
139
 
140
+ private handleChildContainerInput = (): void => {
141
+ updateToggleEmptyState(this._element, this._childContainerElement);
142
+ };
143
+
133
144
  public rendered(): void {
134
145
  this.updateChildrenVisibility();
135
146
  this.updateBodyPlaceholderVisibility();
@@ -322,6 +333,8 @@ export class ToggleItem implements BlockTool {
322
333
  this._isOpen,
323
334
  this.readOnly
324
335
  );
336
+
337
+ updateToggleEmptyState(this._element, this._childContainerElement);
325
338
  }
326
339
 
327
340
  private handleBodyPlaceholderClick(): void {
@@ -13,6 +13,30 @@ import { TOGGLE_ATTR } from './constants';
13
13
  import { buildToggleItem } from './dom-builder';
14
14
  import type { ToggleDOMBuilderContext } from './dom-builder';
15
15
 
16
+ /**
17
+ * Sync the wrapper's data-blok-toggle-empty attribute to reflect whether the
18
+ * toggle's body has any visible text. Reads `textContent` off the child
19
+ * container directly so the state updates live as the user types (or deletes).
20
+ * The attribute drives the grayish arrow styling via the
21
+ * in-data-[blok-toggle-empty=true] Tailwind variant on ARROW_STYLES.
22
+ *
23
+ * @param wrapper - The toggle wrapper element that receives the attribute
24
+ * @param childContainer - The element that hosts the child block holders
25
+ */
26
+ export const updateToggleEmptyState = (
27
+ wrapper: HTMLElement | null,
28
+ childContainer: HTMLElement | null
29
+ ): void => {
30
+ if (wrapper === null) {
31
+ return;
32
+ }
33
+
34
+ const text = childContainer?.textContent ?? '';
35
+ const isEmpty = text.trim() === '';
36
+
37
+ wrapper.setAttribute(TOGGLE_ATTR.toggleEmpty, String(isEmpty));
38
+ };
39
+
16
40
  /**
17
41
  * Context for rendering a toggle item
18
42
  */