@drawnagency/primitives 0.1.75 → 0.1.77
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/chunk-2G2S36SY.js +13 -0
- package/dist/{chunk-7T2WQSWF.js → chunk-63BQQNZO.js} +9 -9
- package/dist/chunk-REM2NH7K.js +44 -0
- package/dist/{chunk-U4E6S4PX.js → chunk-RO4E5UJI.js} +53 -39
- package/dist/{chunk-NKVZGPR6.js → chunk-YP7IHMC3.js} +1 -1
- package/dist/collab/provider-registry.d.ts +4 -0
- package/dist/collab/provider-registry.d.ts.map +1 -0
- package/dist/collab/provider-registry.js +9 -0
- package/dist/collab/rebase.d.ts +37 -0
- package/dist/collab/rebase.d.ts.map +1 -0
- package/dist/collab/rebase.js +64 -0
- package/dist/collab/recovery.d.ts +89 -0
- package/dist/collab/recovery.d.ts.map +1 -0
- package/dist/collab/types.d.ts +93 -0
- package/dist/collab/types.d.ts.map +1 -0
- package/dist/collab/types.js +19 -0
- package/dist/components/editor/AudienceIndicator.d.ts +3 -1
- package/dist/components/editor/AudienceIndicator.d.ts.map +1 -1
- package/dist/components/editor/ChildBlockWrapper.d.ts +7 -0
- package/dist/components/editor/ChildBlockWrapper.d.ts.map +1 -1
- package/dist/components/editor/ConflictDialog.d.ts +14 -0
- package/dist/components/editor/ConflictDialog.d.ts.map +1 -0
- package/dist/components/editor/IndicatorPill.d.ts +4 -1
- package/dist/components/editor/IndicatorPill.d.ts.map +1 -1
- package/dist/components/editor/LockBadge.d.ts +7 -0
- package/dist/components/editor/LockBadge.d.ts.map +1 -0
- package/dist/components/editor/PresenceAvatars.d.ts +9 -0
- package/dist/components/editor/PresenceAvatars.d.ts.map +1 -0
- package/dist/components/editor/SectionWrapper.d.ts +1 -1
- package/dist/components/editor/SectionWrapper.d.ts.map +1 -1
- package/dist/components/editor/StatusIndicator.d.ts +3 -1
- package/dist/components/editor/StatusIndicator.d.ts.map +1 -1
- package/dist/components/editor/index.js +92 -44
- package/dist/components/primitives/index.js +3 -3
- package/dist/components/sections/Container/Container.d.ts.map +1 -1
- package/dist/components/sections/brand-guide.js +3 -3
- package/dist/components/sections/register-schemas.js +9 -9
- package/dist/components/sections/register.js +9 -9
- package/dist/components/shell/EditorShell.d.ts +3 -1
- package/dist/components/shell/EditorShell.d.ts.map +1 -1
- package/dist/hooks/useCollabSession.d.ts +23 -0
- package/dist/hooks/useCollabSession.d.ts.map +1 -0
- package/dist/hooks/useEditorPersistence.d.ts +21 -1
- package/dist/hooks/useEditorPersistence.d.ts.map +1 -1
- package/dist/hooks/useEditorPublish.d.ts +39 -2
- package/dist/hooks/useEditorPublish.d.ts.map +1 -1
- package/dist/index.d.ts +2 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +44 -22
- package/dist/lib/dexie.d.ts +12 -0
- package/dist/lib/dexie.d.ts.map +1 -1
- package/dist/lib/dexie.js +27 -0
- package/dist/lib/index.js +12 -12
- package/dist/lib/registry.d.ts +10 -0
- package/dist/lib/registry.d.ts.map +1 -1
- package/dist/schemas/index.js +1 -1
- package/dist/types/database.d.ts +70 -0
- package/dist/types/database.d.ts.map +1 -1
- package/package.json +13 -1
- package/src/collab/provider-registry.ts +14 -0
- package/src/collab/rebase.ts +140 -0
- package/src/collab/recovery.ts +149 -0
- package/src/collab/types.ts +96 -0
- package/src/components/editor/AudienceIndicator.tsx +4 -1
- package/src/components/editor/ChildBlockWrapper.tsx +15 -1
- package/src/components/editor/ConflictDialog.tsx +61 -0
- package/src/components/editor/IndicatorPill.tsx +12 -6
- package/src/components/editor/LockBadge.tsx +31 -0
- package/src/components/editor/PresenceAvatars.tsx +53 -0
- package/src/components/editor/SectionWrapper.tsx +60 -29
- package/src/components/editor/StatusIndicator.tsx +4 -0
- package/src/components/sections/Container/Container.tsx +6 -4
- package/src/components/shell/EditorShell.tsx +561 -18
- package/src/hooks/useCollabSession.ts +220 -0
- package/src/hooks/useEditorPersistence.ts +104 -1
- package/src/hooks/useEditorPublish.ts +205 -63
- package/src/index.ts +2 -0
- package/src/lib/dexie.ts +44 -0
- package/src/lib/registry.ts +8 -0
- package/src/types/database.ts +55 -0
- package/dist/{chunk-Q3T23HVW.js → chunk-B2DLHZKC.js} +4 -4
- package/dist/{chunk-T7MP7ANP.js → chunk-UUCOJL7O.js} +0 -0
- package/dist/{chunk-ZRWGV5O6.js → chunk-XFDEUK37.js} +3 -3
|
@@ -1,15 +1,15 @@
|
|
|
1
|
+
import {
|
|
2
|
+
Checkbox,
|
|
3
|
+
FormLabel,
|
|
4
|
+
Input
|
|
5
|
+
} from "./chunk-5THS4K5D.js";
|
|
1
6
|
import {
|
|
2
7
|
EditableGrid,
|
|
3
8
|
EditablePlainText,
|
|
4
9
|
MediaBlock,
|
|
5
10
|
containerGridClass,
|
|
6
11
|
useEditableCollection
|
|
7
|
-
} from "./chunk-
|
|
8
|
-
import {
|
|
9
|
-
Checkbox,
|
|
10
|
-
FormLabel,
|
|
11
|
-
Input
|
|
12
|
-
} from "./chunk-5THS4K5D.js";
|
|
12
|
+
} from "./chunk-UUCOJL7O.js";
|
|
13
13
|
import {
|
|
14
14
|
AddIcon,
|
|
15
15
|
DeleteIcon,
|
|
@@ -27,13 +27,13 @@ import {
|
|
|
27
27
|
import {
|
|
28
28
|
cn
|
|
29
29
|
} from "./chunk-7EOSDFS3.js";
|
|
30
|
-
import {
|
|
31
|
-
defineSection
|
|
32
|
-
} from "./chunk-VKAGMEKE.js";
|
|
33
30
|
import {
|
|
34
31
|
HexColorSchema,
|
|
35
32
|
SingleMediaReferenceSchema
|
|
36
33
|
} from "./chunk-SWIHUIFT.js";
|
|
34
|
+
import {
|
|
35
|
+
defineSection
|
|
36
|
+
} from "./chunk-VKAGMEKE.js";
|
|
37
37
|
|
|
38
38
|
// src/components/sections/Colors/index.tsx
|
|
39
39
|
import { z as z2 } from "zod";
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
// src/collab/types.ts
|
|
2
|
+
import { z } from "zod";
|
|
3
|
+
var HEARTBEAT_INTERVAL_MS = 15e3;
|
|
4
|
+
var LOCK_STALE_MS = 45e3;
|
|
5
|
+
var CollabPeerSchema = z.object({
|
|
6
|
+
userId: z.string(),
|
|
7
|
+
email: z.string(),
|
|
8
|
+
focusSectionId: z.string().nullable(),
|
|
9
|
+
heldSectionIds: z.array(z.string())
|
|
10
|
+
});
|
|
11
|
+
var SectionUpdateMessageSchema = z.object({
|
|
12
|
+
v: z.literal(1),
|
|
13
|
+
sectionId: z.string(),
|
|
14
|
+
content: z.unknown(),
|
|
15
|
+
userId: z.string()
|
|
16
|
+
});
|
|
17
|
+
var IndexUpdateMessageSchema = z.object({
|
|
18
|
+
v: z.literal(1),
|
|
19
|
+
index: z.unknown(),
|
|
20
|
+
userId: z.string()
|
|
21
|
+
});
|
|
22
|
+
var TakeoverMessageSchema = z.object({
|
|
23
|
+
v: z.literal(1),
|
|
24
|
+
sectionId: z.string(),
|
|
25
|
+
byUserId: z.string(),
|
|
26
|
+
byEmail: z.string()
|
|
27
|
+
});
|
|
28
|
+
var SavedMessageSchema = z.object({
|
|
29
|
+
v: z.literal(1),
|
|
30
|
+
newSha: z.string(),
|
|
31
|
+
changedSectionIds: z.array(z.string()),
|
|
32
|
+
deletedSectionIds: z.array(z.string()),
|
|
33
|
+
source: z.enum(["editor", "api"])
|
|
34
|
+
});
|
|
35
|
+
|
|
36
|
+
export {
|
|
37
|
+
HEARTBEAT_INTERVAL_MS,
|
|
38
|
+
LOCK_STALE_MS,
|
|
39
|
+
CollabPeerSchema,
|
|
40
|
+
SectionUpdateMessageSchema,
|
|
41
|
+
IndexUpdateMessageSchema,
|
|
42
|
+
TakeoverMessageSchema,
|
|
43
|
+
SavedMessageSchema
|
|
44
|
+
};
|
|
@@ -1,25 +1,9 @@
|
|
|
1
|
-
import {
|
|
2
|
-
EditableRichText,
|
|
3
|
-
defineHeadingSection
|
|
4
|
-
} from "./chunk-NKVZGPR6.js";
|
|
5
|
-
import {
|
|
6
|
-
embedUrl
|
|
7
|
-
} from "./chunk-Y4JQGO6G.js";
|
|
8
1
|
import {
|
|
9
2
|
brandGuideSectionDefs,
|
|
10
3
|
pluralize,
|
|
11
4
|
stripHtmlToPlainText,
|
|
12
5
|
truncate
|
|
13
|
-
} from "./chunk-
|
|
14
|
-
import {
|
|
15
|
-
EditablePlainText,
|
|
16
|
-
ImageDropZone,
|
|
17
|
-
MAX_CONTAINER_COLUMNS,
|
|
18
|
-
MediaBlock,
|
|
19
|
-
colSpanClass,
|
|
20
|
-
containerGridClass,
|
|
21
|
-
spacerHiddenClass
|
|
22
|
-
} from "./chunk-T7MP7ANP.js";
|
|
6
|
+
} from "./chunk-63BQQNZO.js";
|
|
23
7
|
import {
|
|
24
8
|
DeleteButton,
|
|
25
9
|
DragHandle,
|
|
@@ -31,11 +15,27 @@ import {
|
|
|
31
15
|
buildBlockDropData,
|
|
32
16
|
canDropBlock,
|
|
33
17
|
isBlockDragData
|
|
34
|
-
} from "./chunk-
|
|
18
|
+
} from "./chunk-B2DLHZKC.js";
|
|
19
|
+
import {
|
|
20
|
+
EditableRichText,
|
|
21
|
+
defineHeadingSection
|
|
22
|
+
} from "./chunk-YP7IHMC3.js";
|
|
23
|
+
import {
|
|
24
|
+
EditablePlainText,
|
|
25
|
+
ImageDropZone,
|
|
26
|
+
MAX_CONTAINER_COLUMNS,
|
|
27
|
+
MediaBlock,
|
|
28
|
+
colSpanClass,
|
|
29
|
+
containerGridClass,
|
|
30
|
+
spacerHiddenClass
|
|
31
|
+
} from "./chunk-UUCOJL7O.js";
|
|
35
32
|
import {
|
|
36
33
|
useMediaLibrary,
|
|
37
34
|
useResolvedMedia
|
|
38
35
|
} from "./chunk-IFHRHV7S.js";
|
|
36
|
+
import {
|
|
37
|
+
embedUrl
|
|
38
|
+
} from "./chunk-Y4JQGO6G.js";
|
|
39
39
|
import {
|
|
40
40
|
DEFAULT_LINK,
|
|
41
41
|
LinkValueSchema
|
|
@@ -49,13 +49,13 @@ import {
|
|
|
49
49
|
import {
|
|
50
50
|
getSectionSchema
|
|
51
51
|
} from "./chunk-TZQPOR5A.js";
|
|
52
|
+
import {
|
|
53
|
+
SingleMediaReferenceSchema
|
|
54
|
+
} from "./chunk-SWIHUIFT.js";
|
|
52
55
|
import {
|
|
53
56
|
defineSection,
|
|
54
57
|
getSection
|
|
55
58
|
} from "./chunk-VKAGMEKE.js";
|
|
56
|
-
import {
|
|
57
|
-
SingleMediaReferenceSchema
|
|
58
|
-
} from "./chunk-SWIHUIFT.js";
|
|
59
59
|
|
|
60
60
|
// src/components/sections/LinkHeading/index.tsx
|
|
61
61
|
import { Heading1 } from "lucide-react";
|
|
@@ -536,6 +536,7 @@ var ChildBlockWrapper = forwardRef(
|
|
|
536
536
|
onDuplicate,
|
|
537
537
|
onColSpanChange,
|
|
538
538
|
onOpenSettings,
|
|
539
|
+
clearSectionChrome,
|
|
539
540
|
children
|
|
540
541
|
}, ref) {
|
|
541
542
|
return /* @__PURE__ */ jsxs4(
|
|
@@ -548,23 +549,33 @@ var ChildBlockWrapper = forwardRef(
|
|
|
548
549
|
"hover:outline hover:outline-2 hover:outline-primary/30"
|
|
549
550
|
),
|
|
550
551
|
children: [
|
|
551
|
-
/* @__PURE__ */ jsxs4(
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
"
|
|
561
|
-
|
|
562
|
-
className: "
|
|
563
|
-
children: /* @__PURE__ */ jsx12(
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
|
|
552
|
+
/* @__PURE__ */ jsxs4(
|
|
553
|
+
"div",
|
|
554
|
+
{
|
|
555
|
+
"data-testid": "child-control-rail",
|
|
556
|
+
className: cn(
|
|
557
|
+
"absolute left-0 -translate-x-full z-20 flex flex-col items-center gap-1 opacity-0 transition-opacity group-hover/childblock:opacity-100 group-focus-within/childblock:opacity-100 pointer-events-none",
|
|
558
|
+
clearSectionChrome ? "top-8 xl:top-0" : "top-0"
|
|
559
|
+
),
|
|
560
|
+
children: [
|
|
561
|
+
/* @__PURE__ */ jsx12("span", { className: "sr-only", children: label }),
|
|
562
|
+
/* @__PURE__ */ jsx12("div", { className: "pointer-events-auto", children: /* @__PURE__ */ jsx12(DragHandle, { ref: dragHandleRef }) }),
|
|
563
|
+
/* @__PURE__ */ jsx12("div", { className: "pointer-events-auto", children: /* @__PURE__ */ jsx12(ColSpanControl, { colSpan, columns, onChange: onColSpanChange }) }),
|
|
564
|
+
hasSettings && onOpenSettings && /* @__PURE__ */ jsx12("div", { className: "pointer-events-auto", children: /* @__PURE__ */ jsx12(SettingsButton, { onClick: onOpenSettings }) }),
|
|
565
|
+
/* @__PURE__ */ jsx12("div", { className: "pointer-events-auto", children: /* @__PURE__ */ jsx12(
|
|
566
|
+
"button",
|
|
567
|
+
{
|
|
568
|
+
type: "button",
|
|
569
|
+
"aria-label": "Duplicate block",
|
|
570
|
+
onClick: onDuplicate,
|
|
571
|
+
className: "cursor-pointer rounded p-1 text-base-contrast-light hover:text-primary",
|
|
572
|
+
children: /* @__PURE__ */ jsx12(CopyPlus, { size: 16 })
|
|
573
|
+
}
|
|
574
|
+
) }),
|
|
575
|
+
/* @__PURE__ */ jsx12("div", { className: "pointer-events-auto", children: /* @__PURE__ */ jsx12(DeleteButton, { onDelete }) })
|
|
576
|
+
]
|
|
577
|
+
}
|
|
578
|
+
),
|
|
568
579
|
closestEdge === "left" && /* @__PURE__ */ jsx12(
|
|
569
580
|
"div",
|
|
570
581
|
{
|
|
@@ -764,6 +775,7 @@ function ContainerChild({
|
|
|
764
775
|
hasSettings,
|
|
765
776
|
mergedOptions,
|
|
766
777
|
isEditMode,
|
|
778
|
+
clearSectionChrome,
|
|
767
779
|
ChildComp,
|
|
768
780
|
onDelete,
|
|
769
781
|
onDuplicate,
|
|
@@ -797,6 +809,7 @@ function ContainerChild({
|
|
|
797
809
|
closestEdge,
|
|
798
810
|
isDragging,
|
|
799
811
|
hasSettings,
|
|
812
|
+
clearSectionChrome,
|
|
800
813
|
dragHandleRef: handleRef,
|
|
801
814
|
onDelete,
|
|
802
815
|
onDuplicate,
|
|
@@ -956,6 +969,7 @@ function Container({ content, isEditMode, onChange, openModal }) {
|
|
|
956
969
|
hasSettings,
|
|
957
970
|
mergedOptions,
|
|
958
971
|
isEditMode,
|
|
972
|
+
clearSectionChrome: index === 0,
|
|
959
973
|
ChildComp: def.component,
|
|
960
974
|
onDelete: () => emit(trimTrailingSpacers(removeChildAt(container, index).container)),
|
|
961
975
|
onDuplicate: () => emit(duplicateChildAt(container, index, newId)),
|
|
@@ -969,7 +983,7 @@ function Container({ content, isEditMode, onChange, openModal }) {
|
|
|
969
983
|
}
|
|
970
984
|
const occupied = occupiedColumns(children, columns);
|
|
971
985
|
const emptyCols = occupied < columns ? columns - occupied : 0;
|
|
972
|
-
return /* @__PURE__ */ jsx13("div", { className: "@container", children: /* @__PURE__ */ jsxs5("div", { className:
|
|
986
|
+
return /* @__PURE__ */ jsx13("div", { className: "@container", children: /* @__PURE__ */ jsxs5("div", { className: gridClass, children: [
|
|
973
987
|
children.map(renderEditChild),
|
|
974
988
|
Array.from({ length: emptyCols }, (_, i) => /* @__PURE__ */ jsx13(
|
|
975
989
|
EmptyColumnCell,
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"provider-registry.d.ts","sourceRoot":"","sources":["../../src/collab/provider-registry.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,SAAS,CAAC;AAK9C,wBAAgB,iBAAiB,CAAC,CAAC,EAAE,cAAc,GAAG,IAAI,GAAG,IAAI,CAEhE;AAED,wBAAgB,iBAAiB,IAAI,cAAc,GAAG,IAAI,CAEzD"}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import type { LoadedSection } from "../lib/loader";
|
|
2
|
+
import type { SiteIndex } from "../schemas/site-config";
|
|
3
|
+
export interface RebaseArgs {
|
|
4
|
+
localSections: LoadedSection[];
|
|
5
|
+
localIndex: SiteIndex;
|
|
6
|
+
localIndexDirty: boolean;
|
|
7
|
+
dirtySectionIds: Set<string>;
|
|
8
|
+
/** Section ids created locally since the last clean baseline (i.e. dirty ids
|
|
9
|
+
* absent from the last-loaded saved-branch index). Callers derive this from
|
|
10
|
+
* the cached clean baseline (Dexie contentCache index), NOT from remoteIndex —
|
|
11
|
+
* remote absence is exactly what this field disambiguates: without it, a
|
|
12
|
+
* locally-added unsaved section is indistinguishable from a section deleted
|
|
13
|
+
* remotely while dirty (both dirty, present locally, absent remotely). */
|
|
14
|
+
locallyAddedIds: Set<string>;
|
|
15
|
+
locallyDeletedIds: Set<string>;
|
|
16
|
+
remoteSections: LoadedSection[];
|
|
17
|
+
remoteIndex: SiteIndex;
|
|
18
|
+
remoteChangedIds: Set<string>;
|
|
19
|
+
}
|
|
20
|
+
export interface RebaseResult {
|
|
21
|
+
sections: LoadedSection[];
|
|
22
|
+
index: SiteIndex;
|
|
23
|
+
conflictIds: string[];
|
|
24
|
+
}
|
|
25
|
+
/** Merge a fresh remote (saved-branch) snapshot under local unsaved work.
|
|
26
|
+
* Remote wins everywhere the local editor has no unsaved edits; dirty local
|
|
27
|
+
* sections are kept verbatim; overlaps are reported as conflicts for the
|
|
28
|
+
* caller's keep-mine/take-theirs dialog. Implements the 5 merge rules from
|
|
29
|
+
* the collaboration spec ("conflict-free by construction under lock
|
|
30
|
+
* discipline").
|
|
31
|
+
*
|
|
32
|
+
* Invariants: inputs are never mutated (the returned index is a fresh
|
|
33
|
+
* structure in both branches), and the result partitions: every section in
|
|
34
|
+
* `sections` is reachable from `index`; a dirty section deleted remotely is
|
|
35
|
+
* kept, re-linked into the index, and reported in `conflictIds`. */
|
|
36
|
+
export declare function rebaseContent(args: RebaseArgs): RebaseResult;
|
|
37
|
+
//# sourceMappingURL=rebase.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"rebase.d.ts","sourceRoot":"","sources":["../../src/collab/rebase.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,eAAe,CAAC;AACnD,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,wBAAwB,CAAC;AAExD,MAAM,WAAW,UAAU;IACzB,aAAa,EAAE,aAAa,EAAE,CAAC;IAC/B,UAAU,EAAE,SAAS,CAAC;IACtB,eAAe,EAAE,OAAO,CAAC;IACzB,eAAe,EAAE,GAAG,CAAC,MAAM,CAAC,CAAC;IAC7B;;;;;+EAK2E;IAC3E,eAAe,EAAE,GAAG,CAAC,MAAM,CAAC,CAAC;IAC7B,iBAAiB,EAAE,GAAG,CAAC,MAAM,CAAC,CAAC;IAC/B,cAAc,EAAE,aAAa,EAAE,CAAC;IAChC,WAAW,EAAE,SAAS,CAAC;IAKvB,gBAAgB,EAAE,GAAG,CAAC,MAAM,CAAC,CAAC;CAC/B;AAED,MAAM,WAAW,YAAY;IAC3B,QAAQ,EAAE,aAAa,EAAE,CAAC;IAC1B,KAAK,EAAE,SAAS,CAAC;IAIjB,WAAW,EAAE,MAAM,EAAE,CAAC;CACvB;AAED;;;;;;;;;;qEAUqE;AACrE,wBAAgB,aAAa,CAAC,IAAI,EAAE,UAAU,GAAG,YAAY,CA2F5D"}
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
import "../chunk-JSBRDJBE.js";
|
|
2
|
+
|
|
3
|
+
// src/collab/rebase.ts
|
|
4
|
+
function rebaseContent(args) {
|
|
5
|
+
const localById = new Map(args.localSections.map((s) => [s.section.id, s]));
|
|
6
|
+
const remoteIds = new Set(args.remoteSections.map((s) => s.section.id));
|
|
7
|
+
const merged = args.remoteSections.filter((s) => !args.locallyDeletedIds.has(s.section.id)).map((s) => args.dirtySectionIds.has(s.section.id) ? localById.get(s.section.id) ?? s : s);
|
|
8
|
+
for (const id of args.dirtySectionIds) {
|
|
9
|
+
if (remoteIds.has(id) || args.locallyDeletedIds.has(id)) continue;
|
|
10
|
+
const local = localById.get(id);
|
|
11
|
+
if (local) merged.push(local);
|
|
12
|
+
}
|
|
13
|
+
const conflictSet = /* @__PURE__ */ new Set();
|
|
14
|
+
for (const id of args.dirtySectionIds) {
|
|
15
|
+
if (args.locallyDeletedIds.has(id)) continue;
|
|
16
|
+
if (args.remoteChangedIds.has(id)) {
|
|
17
|
+
conflictSet.add(id);
|
|
18
|
+
} else if (localById.has(id) && !(id in args.remoteIndex.sections) && !args.locallyAddedIds.has(id)) {
|
|
19
|
+
conflictSet.add(id);
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
const conflictIds = [...conflictSet].sort();
|
|
23
|
+
let index;
|
|
24
|
+
if (!args.localIndexDirty) {
|
|
25
|
+
index = {
|
|
26
|
+
...args.remoteIndex,
|
|
27
|
+
pages: args.remoteIndex.pages.map((p) => ({ ...p, order: [...p.order] })),
|
|
28
|
+
sections: { ...args.remoteIndex.sections }
|
|
29
|
+
};
|
|
30
|
+
} else {
|
|
31
|
+
const localOrderIds = new Set(args.localIndex.pages.flatMap((p) => p.order));
|
|
32
|
+
const pages = args.localIndex.pages.map((p) => ({
|
|
33
|
+
...p,
|
|
34
|
+
order: p.order.filter((id) => id in args.remoteIndex.sections || args.dirtySectionIds.has(id))
|
|
35
|
+
}));
|
|
36
|
+
const sections = {};
|
|
37
|
+
for (const [id, meta] of Object.entries(args.localIndex.sections)) {
|
|
38
|
+
if (id in args.remoteIndex.sections || args.dirtySectionIds.has(id)) sections[id] = meta;
|
|
39
|
+
}
|
|
40
|
+
for (const remotePage of args.remoteIndex.pages) {
|
|
41
|
+
for (const id of remotePage.order) {
|
|
42
|
+
if (localOrderIds.has(id) || args.locallyDeletedIds.has(id)) continue;
|
|
43
|
+
const target = pages.find((p) => p.id === remotePage.id) ?? pages[0];
|
|
44
|
+
if (target && !target.order.includes(id)) target.order.push(id);
|
|
45
|
+
sections[id] = args.remoteIndex.sections[id];
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
index = { ...args.localIndex, pages, sections };
|
|
49
|
+
}
|
|
50
|
+
for (const s of merged) {
|
|
51
|
+
const id = s.section.id;
|
|
52
|
+
if (id in index.sections) continue;
|
|
53
|
+
const meta = args.localIndex.sections[id] ?? s.meta;
|
|
54
|
+
const localPage = args.localIndex.pages.find((p) => p.order.includes(id));
|
|
55
|
+
const target = (localPage && index.pages.find((p) => p.id === localPage.id)) ?? index.pages[0];
|
|
56
|
+
if (!target) continue;
|
|
57
|
+
if (!target.order.includes(id)) target.order.push(id);
|
|
58
|
+
index.sections[id] = meta;
|
|
59
|
+
}
|
|
60
|
+
return { sections: merged, index, conflictIds };
|
|
61
|
+
}
|
|
62
|
+
export {
|
|
63
|
+
rebaseContent
|
|
64
|
+
};
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
import type { LoadedSection } from "../lib/loader";
|
|
2
|
+
import type { Section, SectionContent } from "../schemas/sections";
|
|
3
|
+
import type { SiteIndex } from "../schemas/site-config";
|
|
4
|
+
/** The last CLEAN saved-branch snapshot (no local dirty overlays folded in).
|
|
5
|
+
* Lifecycle: primed by loadContent, re-primed with the committed snapshot on
|
|
6
|
+
* every successful save, and re-primed with the fetched remote snapshot on
|
|
7
|
+
* every recovery — so it is always the editor's last agreed-with-server state. */
|
|
8
|
+
export interface RecoveryBaseline {
|
|
9
|
+
sections: LoadedSection[];
|
|
10
|
+
index: SiteIndex;
|
|
11
|
+
}
|
|
12
|
+
/** Derive rebaseContent's remoteChangedIds + locallyAddedIds from a clean
|
|
13
|
+
* baseline and the freshly fetched remote snapshot.
|
|
14
|
+
*
|
|
15
|
+
* - remoteChangedIds: sections whose content differs between the clean baseline
|
|
16
|
+
* and the fresh remote. The baseline MUST be clean — diffing against the dirty
|
|
17
|
+
* in-memory view would flag every locally-edited section as remote-changed,
|
|
18
|
+
* turning every dirty section into a false conflict.
|
|
19
|
+
* - locallyAddedIds: dirty ids absent from the clean baseline INDEX — sections
|
|
20
|
+
* created locally and never saved. This is what lets rebase distinguish a
|
|
21
|
+
* local add from a section deleted remotely while dirty.
|
|
22
|
+
*
|
|
23
|
+
* Degraded mode (baseline === null — should be unreachable, since every load,
|
|
24
|
+
* save, and recovery re-primes the cache): fail SAFE, not silent. Every dirty
|
|
25
|
+
* section that still exists remotely is flagged remote-changed (forcing the
|
|
26
|
+
* keep-mine/take-theirs dialog instead of a silent local-wins merge), and every
|
|
27
|
+
* dirty section absent remotely is treated as locally added (kept — a true
|
|
28
|
+
* remote-deletion-while-dirty resurrects instead of conflicting, which loses
|
|
29
|
+
* nothing). This is deliberately NOT derived from the published mainIndex: a
|
|
30
|
+
* main-based baseline would silently local-win every dirty section that already
|
|
31
|
+
* exists on main — the exact lost-update this path exists to prevent. */
|
|
32
|
+
export declare function deriveRecoveryInputs({ baseline, remote, dirtyRows, deletedIds }: {
|
|
33
|
+
baseline: RecoveryBaseline | null;
|
|
34
|
+
remote: {
|
|
35
|
+
sections: LoadedSection[];
|
|
36
|
+
index: SiteIndex;
|
|
37
|
+
};
|
|
38
|
+
dirtyRows: {
|
|
39
|
+
sectionId: string;
|
|
40
|
+
}[];
|
|
41
|
+
deletedIds: Set<string>;
|
|
42
|
+
}): {
|
|
43
|
+
remoteChangedIds: Set<string>;
|
|
44
|
+
locallyAddedIds: Set<string>;
|
|
45
|
+
};
|
|
46
|
+
/** Apply the user's keep-mine/take-theirs choices to a rebase result.
|
|
47
|
+
* Pure — inputs are never mutated. For every conflict the LOCAL copy is
|
|
48
|
+
* returned in `preserved` (the caller snapshots it via preserveEdit so no
|
|
49
|
+
* choice is destructive). "theirs" swaps in the remote section — or, when the
|
|
50
|
+
* remote side DELETED it, removes the section AND strips its id from the index
|
|
51
|
+
* (pages' order + sections map); leaving the dangling index ref would make the
|
|
52
|
+
* server's dangling-ref gate reject every later save. `droppedDirtyIds` lists
|
|
53
|
+
* the "theirs" ids whose local dirty rows must be deleted so the retry doesn't
|
|
54
|
+
* re-send the overridden local content. */
|
|
55
|
+
export declare function applyConflictChoices({ merged, remoteSections, choices }: {
|
|
56
|
+
merged: {
|
|
57
|
+
sections: LoadedSection[];
|
|
58
|
+
index: SiteIndex;
|
|
59
|
+
};
|
|
60
|
+
remoteSections: LoadedSection[];
|
|
61
|
+
choices: Record<string, "mine" | "theirs">;
|
|
62
|
+
}): {
|
|
63
|
+
sections: LoadedSection[];
|
|
64
|
+
index: SiteIndex;
|
|
65
|
+
droppedDirtyIds: string[];
|
|
66
|
+
preserved: {
|
|
67
|
+
sectionId: string;
|
|
68
|
+
section: Section;
|
|
69
|
+
}[];
|
|
70
|
+
};
|
|
71
|
+
/** Build the COMMITTED post-save snapshot for re-priming the clean baseline.
|
|
72
|
+
* The committed content is exactly what performSave sent (savedRows), NOT the
|
|
73
|
+
* current view state — edits typed while the request was in flight must not
|
|
74
|
+
* leak into the "clean" baseline (they are still dirty rows and would otherwise
|
|
75
|
+
* read as remote changes on the next recovery). Base = the previous clean
|
|
76
|
+
* baseline when available (post-recovery it is the fetched remote snapshot);
|
|
77
|
+
* fallback = the loaded sections captured at save start. Ids absent from the
|
|
78
|
+
* sent index (deleted this save) are dropped; saved ids absent from the base
|
|
79
|
+
* (locally added) are appended with their meta from the sent index. */
|
|
80
|
+
export declare function buildCommittedBaseline({ baselineSections, fallbackSections, savedRows, sentIndex }: {
|
|
81
|
+
baselineSections: LoadedSection[] | null;
|
|
82
|
+
fallbackSections: LoadedSection[];
|
|
83
|
+
savedRows: {
|
|
84
|
+
sectionId: string;
|
|
85
|
+
content: SectionContent;
|
|
86
|
+
}[];
|
|
87
|
+
sentIndex: SiteIndex;
|
|
88
|
+
}): LoadedSection[];
|
|
89
|
+
//# sourceMappingURL=recovery.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"recovery.d.ts","sourceRoot":"","sources":["../../src/collab/recovery.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,eAAe,CAAC;AACnD,OAAO,KAAK,EAAE,OAAO,EAAE,cAAc,EAAE,MAAM,qBAAqB,CAAC;AACnE,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,wBAAwB,CAAC;AAExD;;;mFAGmF;AACnF,MAAM,WAAW,gBAAgB;IAC/B,QAAQ,EAAE,aAAa,EAAE,CAAC;IAC1B,KAAK,EAAE,SAAS,CAAC;CAClB;AAED;;;;;;;;;;;;;;;;;;;0EAmB0E;AAC1E,wBAAgB,oBAAoB,CAAC,EAAE,QAAQ,EAAE,MAAM,EAAE,SAAS,EAAE,UAAU,EAAE,EAAE;IAChF,QAAQ,EAAE,gBAAgB,GAAG,IAAI,CAAC;IAClC,MAAM,EAAE;QAAE,QAAQ,EAAE,aAAa,EAAE,CAAC;QAAC,KAAK,EAAE,SAAS,CAAA;KAAE,CAAC;IACxD,SAAS,EAAE;QAAE,SAAS,EAAE,MAAM,CAAA;KAAE,EAAE,CAAC;IACnC,UAAU,EAAE,GAAG,CAAC,MAAM,CAAC,CAAC;CACzB,GAAG;IAAE,gBAAgB,EAAE,GAAG,CAAC,MAAM,CAAC,CAAC;IAAC,eAAe,EAAE,GAAG,CAAC,MAAM,CAAC,CAAA;CAAE,CA0BlE;AAED;;;;;;;;4CAQ4C;AAC5C,wBAAgB,oBAAoB,CAAC,EAAE,MAAM,EAAE,cAAc,EAAE,OAAO,EAAE,EAAE;IACxE,MAAM,EAAE;QAAE,QAAQ,EAAE,aAAa,EAAE,CAAC;QAAC,KAAK,EAAE,SAAS,CAAA;KAAE,CAAC;IACxD,cAAc,EAAE,aAAa,EAAE,CAAC;IAChC,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,QAAQ,CAAC,CAAC;CAC5C,GAAG;IACF,QAAQ,EAAE,aAAa,EAAE,CAAC;IAC1B,KAAK,EAAE,SAAS,CAAC;IACjB,eAAe,EAAE,MAAM,EAAE,CAAC;IAC1B,SAAS,EAAE;QAAE,SAAS,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,OAAO,CAAA;KAAE,EAAE,CAAC;CACtD,CA4BA;AAED;;;;;;;;wEAQwE;AACxE,wBAAgB,sBAAsB,CAAC,EAAE,gBAAgB,EAAE,gBAAgB,EAAE,SAAS,EAAE,SAAS,EAAE,EAAE;IACnG,gBAAgB,EAAE,aAAa,EAAE,GAAG,IAAI,CAAC;IACzC,gBAAgB,EAAE,aAAa,EAAE,CAAC;IAClC,SAAS,EAAE;QAAE,SAAS,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,cAAc,CAAA;KAAE,EAAE,CAAC;IAC5D,SAAS,EAAE,SAAS,CAAC;CACtB,GAAG,aAAa,EAAE,CAiBlB"}
|
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
export declare const HEARTBEAT_INTERVAL_MS = 15000;
|
|
3
|
+
export declare const LOCK_STALE_MS = 45000;
|
|
4
|
+
export declare const CollabPeerSchema: z.ZodObject<{
|
|
5
|
+
userId: z.ZodString;
|
|
6
|
+
email: z.ZodString;
|
|
7
|
+
focusSectionId: z.ZodNullable<z.ZodString>;
|
|
8
|
+
heldSectionIds: z.ZodArray<z.ZodString>;
|
|
9
|
+
}, z.core.$strip>;
|
|
10
|
+
export type CollabPeer = z.infer<typeof CollabPeerSchema>;
|
|
11
|
+
export declare const SectionUpdateMessageSchema: z.ZodObject<{
|
|
12
|
+
v: z.ZodLiteral<1>;
|
|
13
|
+
sectionId: z.ZodString;
|
|
14
|
+
content: z.ZodUnknown;
|
|
15
|
+
userId: z.ZodString;
|
|
16
|
+
}, z.core.$strip>;
|
|
17
|
+
export type SectionUpdateMessage = z.infer<typeof SectionUpdateMessageSchema>;
|
|
18
|
+
export declare const IndexUpdateMessageSchema: z.ZodObject<{
|
|
19
|
+
v: z.ZodLiteral<1>;
|
|
20
|
+
index: z.ZodUnknown;
|
|
21
|
+
userId: z.ZodString;
|
|
22
|
+
}, z.core.$strip>;
|
|
23
|
+
export type IndexUpdateMessage = z.infer<typeof IndexUpdateMessageSchema>;
|
|
24
|
+
export declare const TakeoverMessageSchema: z.ZodObject<{
|
|
25
|
+
v: z.ZodLiteral<1>;
|
|
26
|
+
sectionId: z.ZodString;
|
|
27
|
+
byUserId: z.ZodString;
|
|
28
|
+
byEmail: z.ZodString;
|
|
29
|
+
}, z.core.$strip>;
|
|
30
|
+
export type TakeoverMessage = z.infer<typeof TakeoverMessageSchema>;
|
|
31
|
+
export declare const SavedMessageSchema: z.ZodObject<{
|
|
32
|
+
v: z.ZodLiteral<1>;
|
|
33
|
+
newSha: z.ZodString;
|
|
34
|
+
changedSectionIds: z.ZodArray<z.ZodString>;
|
|
35
|
+
deletedSectionIds: z.ZodArray<z.ZodString>;
|
|
36
|
+
source: z.ZodEnum<{
|
|
37
|
+
editor: "editor";
|
|
38
|
+
api: "api";
|
|
39
|
+
}>;
|
|
40
|
+
}, z.core.$strip>;
|
|
41
|
+
export type SavedMessage = z.infer<typeof SavedMessageSchema>;
|
|
42
|
+
export type CollabStatus = "connecting" | "connected" | "offline";
|
|
43
|
+
/** Opaque server-minted connection blob. Provider-specific keys ride along;
|
|
44
|
+
* primitives only reads the three identity fields. */
|
|
45
|
+
export interface CollabBootstrap {
|
|
46
|
+
siteId: string;
|
|
47
|
+
userId: string;
|
|
48
|
+
email: string;
|
|
49
|
+
[key: string]: unknown;
|
|
50
|
+
}
|
|
51
|
+
export interface CollabEvents {
|
|
52
|
+
onPeers(peers: CollabPeer[]): void;
|
|
53
|
+
onSectionUpdate(msg: SectionUpdateMessage): void;
|
|
54
|
+
onIndexUpdate(msg: IndexUpdateMessage): void;
|
|
55
|
+
onTakeover(msg: TakeoverMessage): void;
|
|
56
|
+
onSaved(msg: SavedMessage): void;
|
|
57
|
+
onStatus(status: CollabStatus): void;
|
|
58
|
+
}
|
|
59
|
+
/** A live connection to one site channel. The session owns the held-lock set
|
|
60
|
+
* (heartbeats them every HEARTBEAT_INTERVAL_MS and includes them in its
|
|
61
|
+
* presence payload). acquireLock({steal:true}) also emits the takeover
|
|
62
|
+
* broadcast on success. */
|
|
63
|
+
export interface CollabSession {
|
|
64
|
+
setFocus(sectionId: string | null): void;
|
|
65
|
+
acquireLock(sectionId: string, opts?: {
|
|
66
|
+
steal?: boolean;
|
|
67
|
+
}): Promise<boolean>;
|
|
68
|
+
releaseLocks(sectionIds: string[]): Promise<void>;
|
|
69
|
+
broadcastSectionUpdate(sectionId: string, content: unknown): void;
|
|
70
|
+
broadcastIndexUpdate(index: unknown): void;
|
|
71
|
+
disconnect(): Promise<void>;
|
|
72
|
+
}
|
|
73
|
+
export interface SavedBroadcast {
|
|
74
|
+
newSha: string;
|
|
75
|
+
changedSectionIds: string[];
|
|
76
|
+
deletedSectionIds: string[];
|
|
77
|
+
source: "editor" | "api";
|
|
78
|
+
}
|
|
79
|
+
export interface CollabProvider {
|
|
80
|
+
/** Browser: join the site channel. Resolves null when collaboration is
|
|
81
|
+
* unavailable (no session, join refused) — caller runs solo-mode. */
|
|
82
|
+
connect(bootstrap: CollabBootstrap, events: CollabEvents): Promise<CollabSession | null>;
|
|
83
|
+
/** Server: mint the browser bootstrap for an authenticated editor session,
|
|
84
|
+
* or null when the provider can't support collab (e.g. missing env). */
|
|
85
|
+
getBootstrap(args: {
|
|
86
|
+
siteId: string;
|
|
87
|
+
userId: string;
|
|
88
|
+
email: string;
|
|
89
|
+
}): CollabBootstrap | null;
|
|
90
|
+
/** Server: post-commit fan-out of a successful save to all connected editors. */
|
|
91
|
+
broadcastSaved(siteId: string, event: SavedBroadcast): Promise<void>;
|
|
92
|
+
}
|
|
93
|
+
//# sourceMappingURL=types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/collab/types.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import {
|
|
2
|
+
CollabPeerSchema,
|
|
3
|
+
HEARTBEAT_INTERVAL_MS,
|
|
4
|
+
IndexUpdateMessageSchema,
|
|
5
|
+
LOCK_STALE_MS,
|
|
6
|
+
SavedMessageSchema,
|
|
7
|
+
SectionUpdateMessageSchema,
|
|
8
|
+
TakeoverMessageSchema
|
|
9
|
+
} from "../chunk-REM2NH7K.js";
|
|
10
|
+
import "../chunk-JSBRDJBE.js";
|
|
11
|
+
export {
|
|
12
|
+
CollabPeerSchema,
|
|
13
|
+
HEARTBEAT_INTERVAL_MS,
|
|
14
|
+
IndexUpdateMessageSchema,
|
|
15
|
+
LOCK_STALE_MS,
|
|
16
|
+
SavedMessageSchema,
|
|
17
|
+
SectionUpdateMessageSchema,
|
|
18
|
+
TakeoverMessageSchema
|
|
19
|
+
};
|
|
@@ -3,7 +3,9 @@ interface AudienceIndicatorProps {
|
|
|
3
3
|
access: string[];
|
|
4
4
|
audiences: Audience[];
|
|
5
5
|
onChange: (access: string[]) => void;
|
|
6
|
+
/** Display-only mode — the pill still shows audiences but the picker never opens. */
|
|
7
|
+
disabled?: boolean;
|
|
6
8
|
}
|
|
7
|
-
export declare function AudienceIndicator({ access, audiences, onChange }: AudienceIndicatorProps): import("react/jsx-runtime").JSX.Element;
|
|
9
|
+
export declare function AudienceIndicator({ access, audiences, onChange, disabled }: AudienceIndicatorProps): import("react/jsx-runtime").JSX.Element;
|
|
8
10
|
export {};
|
|
9
11
|
//# sourceMappingURL=AudienceIndicator.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"AudienceIndicator.d.ts","sourceRoot":"","sources":["../../../src/components/editor/AudienceIndicator.tsx"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAC;AAEjD,UAAU,sBAAsB;IAC9B,MAAM,EAAE,MAAM,EAAE,CAAC;IACjB,SAAS,EAAE,QAAQ,EAAE,CAAC;IACtB,QAAQ,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,KAAK,IAAI,CAAC;
|
|
1
|
+
{"version":3,"file":"AudienceIndicator.d.ts","sourceRoot":"","sources":["../../../src/components/editor/AudienceIndicator.tsx"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAC;AAEjD,UAAU,sBAAsB;IAC9B,MAAM,EAAE,MAAM,EAAE,CAAC;IACjB,SAAS,EAAE,QAAQ,EAAE,CAAC;IACtB,QAAQ,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,KAAK,IAAI,CAAC;IACrC,qFAAqF;IACrF,QAAQ,CAAC,EAAE,OAAO,CAAC;CACpB;AAED,wBAAgB,iBAAiB,CAAC,EAAE,MAAM,EAAE,SAAS,EAAE,QAAQ,EAAE,QAAQ,EAAE,EAAE,sBAAsB,2CAmElG"}
|
|
@@ -13,6 +13,13 @@ export interface ChildBlockWrapperProps {
|
|
|
13
13
|
onDuplicate: () => void;
|
|
14
14
|
onColSpanChange: (span: number) => void;
|
|
15
15
|
onOpenSettings?: () => void;
|
|
16
|
+
/**
|
|
17
|
+
* Below xl the parent SECTION's "+" hangs down into the left gutter where this
|
|
18
|
+
* rail starts — set on the container's first cell so the rail (not the cell)
|
|
19
|
+
* shifts down out of the collision. Cells never move: edit-mode layout must
|
|
20
|
+
* match view mode exactly.
|
|
21
|
+
*/
|
|
22
|
+
clearSectionChrome?: boolean;
|
|
16
23
|
children: ReactNode;
|
|
17
24
|
}
|
|
18
25
|
export declare const ChildBlockWrapper: import("react").ForwardRefExoticComponent<ChildBlockWrapperProps & import("react").RefAttributes<HTMLDivElement>>;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ChildBlockWrapper.d.ts","sourceRoot":"","sources":["../../../src/components/editor/ChildBlockWrapper.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAc,KAAK,SAAS,EAAE,KAAK,GAAG,EAAE,MAAM,OAAO,CAAC;AAC7D,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,uDAAuD,CAAC;AAQlF,MAAM,WAAW,sBAAsB;IACrC,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,EAAE,MAAM,CAAC;IAChB,OAAO,EAAE,MAAM,CAAC;IAChB,WAAW,EAAE,IAAI,GAAG,IAAI,CAAC;IACzB,UAAU,EAAE,OAAO,CAAC;IACpB,WAAW,EAAE,OAAO,CAAC;IACrB,6EAA6E;IAC7E,aAAa,CAAC,EAAE,GAAG,CAAC,iBAAiB,CAAC,CAAC;IACvC,QAAQ,EAAE,MAAM,IAAI,CAAC;IACrB,WAAW,EAAE,MAAM,IAAI,CAAC;IACxB,eAAe,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAC;IACxC,cAAc,CAAC,EAAE,MAAM,IAAI,CAAC;IAC5B,QAAQ,EAAE,SAAS,CAAC;CACrB;AAED,eAAO,MAAM,iBAAiB,
|
|
1
|
+
{"version":3,"file":"ChildBlockWrapper.d.ts","sourceRoot":"","sources":["../../../src/components/editor/ChildBlockWrapper.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAc,KAAK,SAAS,EAAE,KAAK,GAAG,EAAE,MAAM,OAAO,CAAC;AAC7D,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,uDAAuD,CAAC;AAQlF,MAAM,WAAW,sBAAsB;IACrC,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,EAAE,MAAM,CAAC;IAChB,OAAO,EAAE,MAAM,CAAC;IAChB,WAAW,EAAE,IAAI,GAAG,IAAI,CAAC;IACzB,UAAU,EAAE,OAAO,CAAC;IACpB,WAAW,EAAE,OAAO,CAAC;IACrB,6EAA6E;IAC7E,aAAa,CAAC,EAAE,GAAG,CAAC,iBAAiB,CAAC,CAAC;IACvC,QAAQ,EAAE,MAAM,IAAI,CAAC;IACrB,WAAW,EAAE,MAAM,IAAI,CAAC;IACxB,eAAe,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAC;IACxC,cAAc,CAAC,EAAE,MAAM,IAAI,CAAC;IAC5B;;;;;OAKG;IACH,kBAAkB,CAAC,EAAE,OAAO,CAAC;IAC7B,QAAQ,EAAE,SAAS,CAAC;CACrB;AAED,eAAO,MAAM,iBAAiB,mHAyF7B,CAAC"}
|