@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.
- package/dist/blok.mjs +2 -2
- package/dist/chunks/{blok-oWXfRfnM.mjs → blok-DbRn9adY.mjs} +2681 -2238
- package/dist/chunks/{constants-BQ1-lyZI.mjs → constants-C9lsSOXl.mjs} +4 -3
- package/dist/chunks/{core-C942GvJO.mjs → core-B7mxBIHA.mjs} +1 -1
- package/dist/chunks/{engine-javascript-Dd6ViPCH.mjs → engine-javascript-Bmmg8uL9.mjs} +1 -1
- package/dist/chunks/{i18next-loader-CIXsptng.mjs → i18next-loader-453gJdot.mjs} +1 -1
- package/dist/chunks/{tools-MuBQQyZ-.mjs → tools-D0W3_dlA.mjs} +504 -499
- package/dist/full.mjs +3 -3
- package/dist/react.mjs +3 -3
- package/dist/tools.mjs +2 -2
- package/package.json +3 -6
- package/src/components/block/index.ts +36 -0
- package/src/components/blocks.ts +191 -5
- package/src/components/modules/api/blocks.ts +20 -5
- package/src/components/modules/blockEvents/composers/keyboardNavigation.ts +17 -6
- package/src/components/modules/blockManager/blockManager.ts +364 -23
- package/src/components/modules/blockManager/hierarchy.ts +164 -8
- package/src/components/modules/blockManager/operations.ts +223 -26
- package/src/components/modules/blockManager/types.ts +13 -1
- package/src/components/modules/blockManager/yjs-sync.ts +48 -3
- package/src/components/modules/drag/DragController.ts +209 -8
- package/src/components/modules/drag/operations/DragOperations.ts +153 -20
- package/src/components/modules/paste/handlers/base.ts +48 -20
- package/src/components/modules/paste/handlers/blok-data-handler.ts +184 -44
- package/src/components/modules/paste/index.ts +20 -0
- package/src/components/modules/renderer.ts +9 -1
- package/src/components/modules/saver.ts +75 -5
- package/src/components/modules/toolbar/index.ts +41 -60
- package/src/components/modules/uiControllers/controllers/keyboard.ts +20 -0
- package/src/components/modules/yjs/block-observer.ts +87 -23
- package/src/components/modules/yjs/document-store.ts +37 -11
- package/src/components/modules/yjs/index.ts +83 -7
- package/src/components/modules/yjs/types.ts +35 -2
- package/src/components/modules/yjs/undo-history.ts +116 -5
- package/src/components/utils/data-model-transform.ts +247 -35
- package/src/components/utils/hierarchy-invariant.ts +137 -0
- package/src/markdown/markdown-handler.ts +9 -2
- package/src/styles/main.css +5 -0
- package/src/tools/callout/constants.ts +0 -1
- package/src/tools/callout/dom-builder.ts +1 -11
- package/src/tools/callout/index.ts +0 -6
- package/src/tools/header/index.ts +14 -1
- package/src/tools/table/table-operations.ts +9 -4
- package/src/tools/toggle/constants.ts +2 -1
- package/src/tools/toggle/dom-builder.ts +7 -0
- package/src/tools/toggle/index.ts +14 -1
- package/src/tools/toggle/toggle-lifecycle.ts +24 -0
- /package/dist/chunks/{lightweight-i18n-DTYoSr_o.mjs → lightweight-i18n-DSjG0iTr.mjs} +0 -0
- /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
|
-
|
|
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
|
|
330
|
-
//
|
|
331
|
-
//
|
|
332
|
-
|
|
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
|
*/
|
|
File without changes
|
/package/dist/chunks/{objectWithoutProperties-D0XxKB4n.mjs → objectWithoutProperties-Dci1-l7D.mjs}
RENAMED
|
File without changes
|