@standhigher/puck-page-builder 0.8.1 → 0.10.0
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/README.md +25 -0
- package/dist/{chunk-PUTYZI7B.js → chunk-PFCWXLWN.js} +117 -2
- package/dist/extensions.d.ts +18 -183
- package/dist/extensions.js +15 -3
- package/dist/index.d.ts +199 -9
- package/dist/index.js +484 -132
- package/dist/registry-eNtkEC6o.d.ts +221 -0
- package/dist/renderer.d.ts +1 -1
- package/dist/runtime.d.ts +2 -1
- package/dist/runtime.js +15 -3
- package/package.json +1 -1
- package/src/styles.css +12 -1
package/dist/index.js
CHANGED
|
@@ -3,8 +3,14 @@ import {
|
|
|
3
3
|
ExtensionRegistryError,
|
|
4
4
|
TemplateRegistry,
|
|
5
5
|
createExtensionRegistry,
|
|
6
|
-
createTemplateRegistry
|
|
7
|
-
|
|
6
|
+
createTemplateRegistry,
|
|
7
|
+
maximumBlockInstances,
|
|
8
|
+
mergeBlockPolicies,
|
|
9
|
+
minimumBlockInstances,
|
|
10
|
+
validateBlockPolicy,
|
|
11
|
+
validateFieldValue,
|
|
12
|
+
validatePageDocumentWithRegistry
|
|
13
|
+
} from "./chunk-PFCWXLWN.js";
|
|
8
14
|
import {
|
|
9
15
|
WebRenderer
|
|
10
16
|
} from "./chunk-KYXIXIWK.js";
|
|
@@ -342,7 +348,7 @@ function PropertyPanel({
|
|
|
342
348
|
|
|
343
349
|
// src/editor/shell/PageDocumentEditorShell.tsx
|
|
344
350
|
import { Puck as Puck2, usePuck } from "@puckeditor/core";
|
|
345
|
-
import { Badge as
|
|
351
|
+
import { Badge as Badge3, Banner, Button as Button2, ButtonGroup as ButtonGroup2, InlineStack as InlineStack3, Select as Select2, Text as Text3, TextField } from "@shopify/polaris";
|
|
346
352
|
import { DragHandleIcon as DragHandleIcon2, LayoutSectionIcon as LayoutSectionIcon2, MenuIcon as MenuIcon2, RedoIcon as RedoIcon2, UndoIcon as UndoIcon2 } from "@shopify/polaris-icons";
|
|
347
353
|
import { useCallback as useCallback2, useEffect as useEffect3, useMemo as useMemo2, useRef as useRef4, useState as useState3 } from "react";
|
|
348
354
|
|
|
@@ -462,6 +468,65 @@ function fromEngineData(data, base, registry) {
|
|
|
462
468
|
|
|
463
469
|
// src/editor/context/EditorContext.tsx
|
|
464
470
|
import { createContext, useCallback, useContext, useEffect as useEffect2, useMemo, useReducer, useRef as useRef3, useState as useState2 } from "react";
|
|
471
|
+
|
|
472
|
+
// src/editor/policy.ts
|
|
473
|
+
function operationEnabled(operation, policy, blockPolicy) {
|
|
474
|
+
const key = `allow${operation[0].toUpperCase()}${operation.slice(1)}`;
|
|
475
|
+
return policy?.operations?.[key] !== false && blockPolicy[key] !== false;
|
|
476
|
+
}
|
|
477
|
+
function resolvedBlockPolicy(type, definition, policy) {
|
|
478
|
+
return mergeBlockPolicies(definition?.policy, policy?.blocks?.[type]);
|
|
479
|
+
}
|
|
480
|
+
function blockCount(blocks, type) {
|
|
481
|
+
return blocks.filter((block) => block.type === type).length;
|
|
482
|
+
}
|
|
483
|
+
function canAddBlock(type, blocks, definition, policy) {
|
|
484
|
+
const blockPolicy = resolvedBlockPolicy(type, definition, policy);
|
|
485
|
+
return operationEnabled("add", policy, blockPolicy) && blockCount(blocks, type) < maximumBlockInstances(blockPolicy);
|
|
486
|
+
}
|
|
487
|
+
function canDeleteBlock(block, blocks, definition, policy) {
|
|
488
|
+
if (!block) return false;
|
|
489
|
+
const blockPolicy = resolvedBlockPolicy(block.type, definition, policy);
|
|
490
|
+
return operationEnabled("delete", policy, blockPolicy) && blockCount(blocks, block.type) > minimumBlockInstances(blockPolicy);
|
|
491
|
+
}
|
|
492
|
+
function canDuplicateBlock(block, blocks, definition, policy) {
|
|
493
|
+
if (!block) return false;
|
|
494
|
+
const blockPolicy = resolvedBlockPolicy(block.type, definition, policy);
|
|
495
|
+
return operationEnabled("duplicate", policy, blockPolicy) && canAddBlock(block.type, blocks, definition, policy);
|
|
496
|
+
}
|
|
497
|
+
function canDragBlock(block, definition, policy) {
|
|
498
|
+
if (!block) return false;
|
|
499
|
+
return operationEnabled("drag", policy, resolvedBlockPolicy(block.type, definition, policy));
|
|
500
|
+
}
|
|
501
|
+
function canApplyCanvasDocument(previous, next, getDefinition, policy) {
|
|
502
|
+
const previousById = new Map(previous.blocks.map((block) => [block.id, block]));
|
|
503
|
+
const nextById = new Map(next.blocks.map((block) => [block.id, block]));
|
|
504
|
+
for (const block of next.blocks) {
|
|
505
|
+
const previousBlock = previousById.get(block.id);
|
|
506
|
+
if (previousBlock && previousBlock.type !== block.type) return false;
|
|
507
|
+
}
|
|
508
|
+
for (const block of next.blocks) {
|
|
509
|
+
if (!previousById.has(block.id) && !canAddBlock(block.type, previous.blocks, getDefinition(block.type), policy)) return false;
|
|
510
|
+
}
|
|
511
|
+
for (const block of previous.blocks) {
|
|
512
|
+
if (!nextById.has(block.id) && !canDeleteBlock(block, previous.blocks, getDefinition(block.type), policy)) return false;
|
|
513
|
+
}
|
|
514
|
+
const types = new Set([...previous.blocks, ...next.blocks].map((block) => block.type));
|
|
515
|
+
for (const type of types) {
|
|
516
|
+
const definition = getDefinition(type);
|
|
517
|
+
const blockPolicy = resolvedBlockPolicy(type, definition, policy);
|
|
518
|
+
const nextCount = blockCount(next.blocks, type);
|
|
519
|
+
if (nextCount > maximumBlockInstances(blockPolicy) || nextCount < minimumBlockInstances(blockPolicy)) return false;
|
|
520
|
+
}
|
|
521
|
+
if (previous.blocks.length === next.blocks.length && previous.blocks.every((block) => nextById.has(block.id))) {
|
|
522
|
+
for (let index = 0; index < previous.blocks.length; index += 1) {
|
|
523
|
+
if (previous.blocks[index]?.id !== next.blocks[index]?.id && !canDragBlock(previous.blocks[index], getDefinition(previous.blocks[index].type), policy)) return false;
|
|
524
|
+
}
|
|
525
|
+
}
|
|
526
|
+
return true;
|
|
527
|
+
}
|
|
528
|
+
|
|
529
|
+
// src/editor/context/EditorContext.tsx
|
|
465
530
|
import { jsx as jsx5 } from "react/jsx-runtime";
|
|
466
531
|
function historyReducer(state, action) {
|
|
467
532
|
if (action.type === "select") return { ...state, selectedBlockId: action.id };
|
|
@@ -476,7 +541,7 @@ function historyReducer(state, action) {
|
|
|
476
541
|
if (!next) return state;
|
|
477
542
|
return { ...state, ...next, past: [...state.past, { document: state.document, selectedBlockId: state.selectedBlockId }], future: state.future.slice(1) };
|
|
478
543
|
}
|
|
479
|
-
if (action.type === "saved") return { ...state, savedDocument:
|
|
544
|
+
if (action.type === "saved") return { ...state, savedDocument: action.document };
|
|
480
545
|
const current = { document: state.document, selectedBlockId: state.selectedBlockId };
|
|
481
546
|
return { ...state, document: action.document, selectedBlockId: action.selectedBlockId, past: [...state.past, current], future: [] };
|
|
482
547
|
}
|
|
@@ -494,15 +559,17 @@ function defaultBlock(type, blocks, registry) {
|
|
|
494
559
|
if (!definition) throw new Error(`Unknown PageDocument block type: ${type}`);
|
|
495
560
|
return { id: uniqueBlockId(type, blocks), type, version: definition.version, props: definition.defaultProps, variant: definition.defaultVariant ?? "default", style: {} };
|
|
496
561
|
}
|
|
497
|
-
function EditorProvider({ initialDocument, registry, loadState = "ready", leaveWarning = "You have unsaved changes.", onDocumentChange, children }) {
|
|
562
|
+
function EditorProvider({ initialDocument, registry, policy, loadState = "ready", sessionState = "active", session, sessionMessage, leaveWarning = "You have unsaved changes.", onDocumentChange, children }) {
|
|
498
563
|
const [history, dispatch] = useReducer(historyReducer, initialDocument, (document) => ({ document, selectedBlockId: document.blocks[0]?.id ?? null, past: [], future: [], device: "desktop", savedDocument: document }));
|
|
499
564
|
const historyRef = useRef3(history);
|
|
500
565
|
useEffect2(() => {
|
|
501
566
|
historyRef.current = history;
|
|
502
567
|
}, [history]);
|
|
503
568
|
const [canvasSelectionRequest, setCanvasSelectionRequest] = useState2(null);
|
|
504
|
-
const
|
|
569
|
+
const [pendingDeleteBlockId, setPendingDeleteBlockId] = useState2(null);
|
|
570
|
+
const editable = (loadState === "ready" || loadState === "success") && sessionState === "active";
|
|
505
571
|
const selectedBlock = history.document.blocks.find((block) => block.id === history.selectedBlockId) ?? null;
|
|
572
|
+
const pendingDeleteBlock = history.document.blocks.find((block) => block.id === pendingDeleteBlockId) ?? null;
|
|
506
573
|
const replace = useCallback((document, selectedBlockId) => dispatch({ type: "replace", document, selectedBlockId }), []);
|
|
507
574
|
const requestCanvasSelection = useCallback((id) => {
|
|
508
575
|
if (editable) setCanvasSelectionRequest(id);
|
|
@@ -513,15 +580,23 @@ function EditorProvider({ initialDocument, registry, loadState = "ready", leaveW
|
|
|
513
580
|
}, []);
|
|
514
581
|
const updateFromCanvas = useCallback((document) => {
|
|
515
582
|
const current = historyRef.current;
|
|
516
|
-
if (!editable || JSON.stringify(document) === JSON.stringify(current.document)) return;
|
|
583
|
+
if (!editable || JSON.stringify(document) === JSON.stringify(current.document)) return false;
|
|
584
|
+
if (!canApplyCanvasDocument(current.document, document, (type) => registry?.getBlock(type), policy)) return false;
|
|
517
585
|
replace(document, current.selectedBlockId);
|
|
518
|
-
|
|
586
|
+
return true;
|
|
587
|
+
}, [editable, policy, registry, replace]);
|
|
519
588
|
const updateBlockProps = useCallback((id, props) => {
|
|
520
589
|
if (!editable) return;
|
|
521
590
|
const current = historyRef.current;
|
|
522
591
|
const blocks = current.document.blocks.map((block) => block.id === id ? { ...block, props: { ...block.props, ...props } } : block);
|
|
523
592
|
replace({ ...current.document, blocks }, id);
|
|
524
593
|
}, [editable, replace]);
|
|
594
|
+
const updateBlockPresentation = useCallback((id, presentation) => {
|
|
595
|
+
if (!editable) return;
|
|
596
|
+
const current = historyRef.current;
|
|
597
|
+
const blocks = current.document.blocks.map((block) => block.id === id ? { ...block, ...presentation } : block);
|
|
598
|
+
replace({ ...current.document, blocks }, id);
|
|
599
|
+
}, [editable, replace]);
|
|
525
600
|
useEffect2(() => {
|
|
526
601
|
onDocumentChange?.(history.document);
|
|
527
602
|
}, [history.document, onDocumentChange]);
|
|
@@ -555,27 +630,37 @@ function EditorProvider({ initialDocument, registry, loadState = "ready", leaveW
|
|
|
555
630
|
const actionState = {
|
|
556
631
|
canUndo: editable && history.past.length > 0,
|
|
557
632
|
canRedo: editable && history.future.length > 0,
|
|
558
|
-
canAdd: editable,
|
|
633
|
+
canAdd: editable && ["core.text", "core.image", ...registry?.blocks.map((block) => block.type) ?? []].some((type) => canAddBlock(type, history.document.blocks, registry?.getBlock(type), policy)),
|
|
559
634
|
canEdit: editable && selectedBlock !== null,
|
|
560
|
-
canDelete: editable && selectedBlock
|
|
561
|
-
canDuplicate: editable && selectedBlock
|
|
562
|
-
canReorder: editable && history.document.blocks.length > 1
|
|
635
|
+
canDelete: editable && canDeleteBlock(selectedBlock, history.document.blocks, registry?.getBlock(selectedBlock?.type ?? ""), policy),
|
|
636
|
+
canDuplicate: editable && canDuplicateBlock(selectedBlock, history.document.blocks, registry?.getBlock(selectedBlock?.type ?? ""), policy),
|
|
637
|
+
canReorder: editable && history.document.blocks.length > 1 && canDragBlock(selectedBlock, registry?.getBlock(selectedBlock?.type ?? ""), policy)
|
|
563
638
|
};
|
|
564
639
|
return {
|
|
565
640
|
document: history.document,
|
|
566
641
|
selectedBlockId: history.selectedBlockId,
|
|
567
642
|
selectedBlock,
|
|
643
|
+
pendingDeleteBlock,
|
|
568
644
|
canvasSelectionRequest,
|
|
569
645
|
device: history.device,
|
|
570
646
|
loadState,
|
|
647
|
+
sessionState,
|
|
648
|
+
session,
|
|
649
|
+
sessionMessage,
|
|
650
|
+
isEditable: editable,
|
|
571
651
|
isDirty,
|
|
572
652
|
actionState,
|
|
653
|
+
canAddBlock: (type) => editable && canAddBlock(type, history.document.blocks, registry?.getBlock(type), policy),
|
|
654
|
+
canDragBlock: (id) => {
|
|
655
|
+
const block = history.document.blocks.find((item) => item.id === id);
|
|
656
|
+
return editable && canDragBlock(block, registry?.getBlock(block?.type ?? ""), policy);
|
|
657
|
+
},
|
|
573
658
|
requestCanvasSelection,
|
|
574
659
|
confirmCanvasSelection,
|
|
575
660
|
updateFromCanvas,
|
|
576
661
|
setDevice: (device) => dispatch({ type: "device", device }),
|
|
577
662
|
addBlock: (type, beforeId) => {
|
|
578
|
-
if (!editable) return null;
|
|
663
|
+
if (!editable || !canAddBlock(type, history.document.blocks, registry?.getBlock(type), policy)) return null;
|
|
579
664
|
const block = defaultBlock(type, history.document.blocks, registry);
|
|
580
665
|
const blocks = [...history.document.blocks];
|
|
581
666
|
const targetIndex = beforeId ? blocks.findIndex((item) => item.id === beforeId) : -1;
|
|
@@ -588,7 +673,7 @@ function EditorProvider({ initialDocument, registry, loadState = "ready", leaveW
|
|
|
588
673
|
if (!editable) return;
|
|
589
674
|
const index = history.document.blocks.findIndex((block2) => block2.id === id);
|
|
590
675
|
const source = history.document.blocks[index];
|
|
591
|
-
if (!source) return;
|
|
676
|
+
if (!canDuplicateBlock(source, history.document.blocks, registry?.getBlock(source?.type ?? ""), policy)) return;
|
|
592
677
|
const block = { ...source, id: uniqueBlockId(source.type, history.document.blocks), props: { ...source.props } };
|
|
593
678
|
const blocks = [...history.document.blocks];
|
|
594
679
|
blocks.splice(index + 1, 0, block);
|
|
@@ -597,7 +682,8 @@ function EditorProvider({ initialDocument, registry, loadState = "ready", leaveW
|
|
|
597
682
|
deleteBlock: (id) => {
|
|
598
683
|
if (!editable) return;
|
|
599
684
|
const index = history.document.blocks.findIndex((block) => block.id === id);
|
|
600
|
-
|
|
685
|
+
const source = history.document.blocks[index];
|
|
686
|
+
if (!canDeleteBlock(source, history.document.blocks, registry?.getBlock(source?.type ?? ""), policy)) return;
|
|
601
687
|
const blocks = history.document.blocks.filter((block) => block.id !== id);
|
|
602
688
|
replace({ ...history.document, blocks }, blocks[index]?.id ?? blocks[index - 1]?.id ?? null);
|
|
603
689
|
},
|
|
@@ -605,7 +691,7 @@ function EditorProvider({ initialDocument, registry, loadState = "ready", leaveW
|
|
|
605
691
|
if (!editable) return;
|
|
606
692
|
const from = history.document.blocks.findIndex((block) => block.id === id);
|
|
607
693
|
const to = from + direction;
|
|
608
|
-
if (from < 0 || to < 0 || to >= history.document.blocks.length) return;
|
|
694
|
+
if (from < 0 || to < 0 || to >= history.document.blocks.length || !canDragBlock(history.document.blocks[from], registry?.getBlock(history.document.blocks[from]?.type ?? ""), policy)) return;
|
|
609
695
|
const blocks = [...history.document.blocks];
|
|
610
696
|
[blocks[from], blocks[to]] = [blocks[to], blocks[from]];
|
|
611
697
|
replace({ ...history.document, blocks }, id);
|
|
@@ -615,21 +701,38 @@ function EditorProvider({ initialDocument, registry, loadState = "ready", leaveW
|
|
|
615
701
|
const source = history.document.blocks.find((block) => block.id === id);
|
|
616
702
|
const withoutSource = history.document.blocks.filter((block) => block.id !== id);
|
|
617
703
|
const targetIndex = withoutSource.findIndex((block) => block.id === beforeId);
|
|
618
|
-
if (!source || targetIndex < 0) return;
|
|
704
|
+
if (!source || targetIndex < 0 || !canDragBlock(source, registry?.getBlock(source.type), policy)) return;
|
|
619
705
|
const blocks = [...withoutSource];
|
|
620
706
|
blocks.splice(targetIndex, 0, source);
|
|
621
707
|
replace({ ...history.document, blocks }, id);
|
|
622
708
|
},
|
|
623
709
|
updateBlockProps,
|
|
710
|
+
updateBlockPresentation,
|
|
711
|
+
requestDeleteBlock: (id) => {
|
|
712
|
+
const block = history.document.blocks.find((item) => item.id === id);
|
|
713
|
+
if (editable && canDeleteBlock(block, history.document.blocks, registry?.getBlock(block?.type ?? ""), policy)) setPendingDeleteBlockId(id);
|
|
714
|
+
},
|
|
715
|
+
cancelDeleteBlock: () => setPendingDeleteBlockId(null),
|
|
716
|
+
confirmDeleteBlock: () => {
|
|
717
|
+
if (pendingDeleteBlockId) {
|
|
718
|
+
const id = pendingDeleteBlockId;
|
|
719
|
+
setPendingDeleteBlockId(null);
|
|
720
|
+
const index = history.document.blocks.findIndex((block) => block.id === id);
|
|
721
|
+
const source = history.document.blocks[index];
|
|
722
|
+
if (!canDeleteBlock(source, history.document.blocks, registry?.getBlock(source?.type ?? ""), policy)) return;
|
|
723
|
+
const blocks = history.document.blocks.filter((block) => block.id !== id);
|
|
724
|
+
replace({ ...history.document, blocks }, blocks[index]?.id ?? blocks[index - 1]?.id ?? null);
|
|
725
|
+
}
|
|
726
|
+
},
|
|
624
727
|
undo: () => {
|
|
625
728
|
if (editable) dispatch({ type: "undo" });
|
|
626
729
|
},
|
|
627
730
|
redo: () => {
|
|
628
731
|
if (editable) dispatch({ type: "redo" });
|
|
629
732
|
},
|
|
630
|
-
markSaved: () => dispatch({ type: "saved" })
|
|
733
|
+
markSaved: (document = historyRef.current.document) => dispatch({ type: "saved", document })
|
|
631
734
|
};
|
|
632
|
-
}, [canvasSelectionRequest, confirmCanvasSelection, editable, history, isDirty, loadState, registry, replace, requestCanvasSelection, selectedBlock, updateBlockProps, updateFromCanvas]);
|
|
735
|
+
}, [canvasSelectionRequest, confirmCanvasSelection, editable, history, isDirty, loadState, pendingDeleteBlock, pendingDeleteBlockId, policy, registry, replace, requestCanvasSelection, selectedBlock, session, sessionMessage, sessionState, updateBlockPresentation, updateBlockProps, updateFromCanvas]);
|
|
633
736
|
return /* @__PURE__ */ jsx5(EditorContext.Provider, { value, children });
|
|
634
737
|
}
|
|
635
738
|
function useEditorContext() {
|
|
@@ -638,6 +741,26 @@ function useEditorContext() {
|
|
|
638
741
|
return context;
|
|
639
742
|
}
|
|
640
743
|
|
|
744
|
+
// src/editor/components/PageStatusCard.tsx
|
|
745
|
+
import { Badge as Badge2, InlineStack as InlineStack2, Text as Text2 } from "@shopify/polaris";
|
|
746
|
+
import { jsx as jsx6, jsxs as jsxs4 } from "react/jsx-runtime";
|
|
747
|
+
function PageStatusCard({ status, sessionState }) {
|
|
748
|
+
const publicationTone = status.publicationStatus === "published" ? "success" : "attention";
|
|
749
|
+
const sessionLabel = sessionState === "locked" ? `${status.editingBy ?? "\u5176\u4ED6\u4EBA"}\u6B63\u5728\u7F16\u8F91` : sessionState === "lost" ? "\u7F16\u8F91\u9501\u5DF2\u5931\u6548" : status.editingBy ? `${status.editingBy}\u6B63\u5728\u7F16\u8F91` : void 0;
|
|
750
|
+
return /* @__PURE__ */ jsxs4("div", { className: "pb-page-status-card", "data-testid": "page-status-card", "data-publication-status": status.publicationStatus, "data-session-state": sessionState, children: [
|
|
751
|
+
/* @__PURE__ */ jsxs4(InlineStack2, { gap: "150", blockAlign: "center", wrap: true, children: [
|
|
752
|
+
/* @__PURE__ */ jsx6(Badge2, { tone: publicationTone, children: status.publicationStatus === "published" ? "\u7EBF\u4E0A" : "\u672A\u53D1\u5E03" }),
|
|
753
|
+
status.draftLabel ? /* @__PURE__ */ jsx6(Text2, { as: "span", variant: "bodySm", tone: "subdued", children: status.draftLabel }) : null,
|
|
754
|
+
status.publishedVersionLabel ? /* @__PURE__ */ jsx6(Text2, { as: "span", variant: "bodySm", tone: "subdued", children: status.publishedVersionLabel }) : null,
|
|
755
|
+
sessionLabel ? /* @__PURE__ */ jsx6(Badge2, { tone: sessionState === "lost" ? "critical" : "attention", children: sessionLabel }) : null
|
|
756
|
+
] }),
|
|
757
|
+
status.lastSavedAt ? /* @__PURE__ */ jsxs4(Text2, { as: "p", variant: "bodySm", tone: "subdued", children: [
|
|
758
|
+
"\u6700\u540E\u4FDD\u5B58\uFF1A",
|
|
759
|
+
status.lastSavedAt
|
|
760
|
+
] }) : null
|
|
761
|
+
] });
|
|
762
|
+
}
|
|
763
|
+
|
|
641
764
|
// src/editor/i18n/admin.ts
|
|
642
765
|
var messages = {
|
|
643
766
|
"zh-CN": {
|
|
@@ -649,6 +772,10 @@ var messages = {
|
|
|
649
772
|
redo: "\u6062\u590D",
|
|
650
773
|
duplicate: "\u590D\u5236",
|
|
651
774
|
remove: "\u5220\u9664",
|
|
775
|
+
confirmDeleteTitle: "\u786E\u8BA4\u5220\u9664\u533A\u5757\uFF1F",
|
|
776
|
+
confirmDeleteMessage: "\u5220\u9664\u540E\u53EF\u4F7F\u7528\u64A4\u9500\u6062\u590D\u3002",
|
|
777
|
+
cancel: "\u53D6\u6D88",
|
|
778
|
+
confirm: "\u786E\u8BA4\u5220\u9664",
|
|
652
779
|
moveUp: "\u4E0A\u79FB",
|
|
653
780
|
moveDown: "\u4E0B\u79FB",
|
|
654
781
|
loading: "\u6B63\u5728\u52A0\u8F7D\u7F16\u8F91\u5668\u2026",
|
|
@@ -663,8 +790,21 @@ var messages = {
|
|
|
663
790
|
publish: "\u53D1\u5E03",
|
|
664
791
|
publishing: "\u6B63\u5728\u53D1\u5E03\u2026",
|
|
665
792
|
saveFailed: "\u4FDD\u5B58\u8349\u7A3F\u5931\u8D25",
|
|
793
|
+
retrySave: "\u91CD\u8BD5\u4FDD\u5B58",
|
|
794
|
+
offline: "\u5F53\u524D\u79BB\u7EBF\uFF0C\u6062\u590D\u7F51\u7EDC\u540E\u5C06\u81EA\u52A8\u4FDD\u5B58",
|
|
666
795
|
publishFailed: "\u53D1\u5E03\u5931\u8D25",
|
|
667
796
|
published: "\u5DF2\u53D1\u5E03",
|
|
797
|
+
back: "\u8FD4\u56DE",
|
|
798
|
+
confirmLeaveTitle: "\u79BB\u5F00\u7F16\u8F91\u5668\uFF1F",
|
|
799
|
+
leave: "\u79BB\u5F00",
|
|
800
|
+
zoom: "\u7F29\u653E",
|
|
801
|
+
zoomAuto: "\u81EA\u52A8\u7F29\u653E",
|
|
802
|
+
preview: "\u6B63\u5F0F\u9884\u89C8",
|
|
803
|
+
addToStore: "\u6DFB\u52A0\u5230\u5E97\u94FA",
|
|
804
|
+
acquiringLock: "\u6B63\u5728\u83B7\u53D6\u7F16\u8F91\u9501\u2026",
|
|
805
|
+
locked: "\u8BE5\u9875\u9762\u6B63\u5728\u88AB\u7F16\u8F91",
|
|
806
|
+
lockLost: "\u7F16\u8F91\u9501\u5DF2\u5931\u6548",
|
|
807
|
+
readonly: "\u9875\u9762\u4E3A\u53EA\u8BFB\u72B6\u6001",
|
|
668
808
|
leaveWarning: "\u4F60\u6709\u672A\u4FDD\u5B58\u7684\u66F4\u6539\u3002\u786E\u5B9A\u8981\u79BB\u5F00\u5417\uFF1F",
|
|
669
809
|
selectBlock: "\u9009\u62E9\u4E00\u4E2A\u533A\u5757\u4EE5\u7F16\u8F91\u3002",
|
|
670
810
|
desktop: "\u684C\u9762",
|
|
@@ -680,6 +820,10 @@ var messages = {
|
|
|
680
820
|
redo: "Redo",
|
|
681
821
|
duplicate: "Duplicate",
|
|
682
822
|
remove: "Delete",
|
|
823
|
+
confirmDeleteTitle: "Delete this block?",
|
|
824
|
+
confirmDeleteMessage: "You can restore it with Undo after deleting.",
|
|
825
|
+
cancel: "Cancel",
|
|
826
|
+
confirm: "Delete block",
|
|
683
827
|
moveUp: "Move up",
|
|
684
828
|
moveDown: "Move down",
|
|
685
829
|
loading: "Loading editor\u2026",
|
|
@@ -694,8 +838,21 @@ var messages = {
|
|
|
694
838
|
publish: "Publish",
|
|
695
839
|
publishing: "Publishing\u2026",
|
|
696
840
|
saveFailed: "Could not save draft",
|
|
841
|
+
retrySave: "Retry save",
|
|
842
|
+
offline: "Offline \u2014 changes will save when connection returns",
|
|
697
843
|
publishFailed: "Could not publish",
|
|
698
844
|
published: "Published",
|
|
845
|
+
back: "Back",
|
|
846
|
+
confirmLeaveTitle: "Leave the editor?",
|
|
847
|
+
leave: "Leave",
|
|
848
|
+
zoom: "Zoom",
|
|
849
|
+
zoomAuto: "Auto zoom",
|
|
850
|
+
preview: "Preview",
|
|
851
|
+
addToStore: "Add to store",
|
|
852
|
+
acquiringLock: "Acquiring edit lock\u2026",
|
|
853
|
+
locked: "This page is being edited",
|
|
854
|
+
lockLost: "The edit lock has expired",
|
|
855
|
+
readonly: "This page is read-only",
|
|
699
856
|
leaveWarning: "You have unsaved changes. Are you sure you want to leave?",
|
|
700
857
|
selectBlock: "Select a block to edit it.",
|
|
701
858
|
desktop: "Desktop",
|
|
@@ -718,7 +875,7 @@ function blockIdAtRelativeY(ids, relativeY) {
|
|
|
718
875
|
}
|
|
719
876
|
|
|
720
877
|
// src/editor/shell/PageDocumentEditorShell.tsx
|
|
721
|
-
import { jsx as
|
|
878
|
+
import { Fragment as Fragment2, jsx as jsx7, jsxs as jsxs5 } from "react/jsx-runtime";
|
|
722
879
|
var deviceLabels2 = { desktop: "desktop", tablet: "tablet", mobile: "mobile" };
|
|
723
880
|
function blockLabel(block, registry) {
|
|
724
881
|
return blockTypeLabel(block.type, registry);
|
|
@@ -728,27 +885,143 @@ function blockTypeLabel(type, registry) {
|
|
|
728
885
|
if (type === "core.image") return "\u56FE\u7247";
|
|
729
886
|
return registry?.getBlock(type)?.label ?? type;
|
|
730
887
|
}
|
|
888
|
+
function validateDocumentBlocks(document, registry) {
|
|
889
|
+
return registry ? validatePageDocumentWithRegistry(document, registry) : [];
|
|
890
|
+
}
|
|
891
|
+
function useEditorSession(adapter, pageId) {
|
|
892
|
+
const [managed, setManaged] = useState3(() => adapter ? { state: "acquiring" } : { state: "active" });
|
|
893
|
+
useEffect3(() => {
|
|
894
|
+
let cancelled = false;
|
|
895
|
+
let session;
|
|
896
|
+
let heartbeatTimer;
|
|
897
|
+
const stopHeartbeat = () => {
|
|
898
|
+
if (heartbeatTimer) clearInterval(heartbeatTimer);
|
|
899
|
+
heartbeatTimer = void 0;
|
|
900
|
+
};
|
|
901
|
+
if (!adapter) return;
|
|
902
|
+
void adapter.acquire({ pageId }).then((result) => {
|
|
903
|
+
if (cancelled) return;
|
|
904
|
+
if (result.state !== "active") {
|
|
905
|
+
setManaged({ state: result.state, message: result.message ?? (result.state === "locked" && result.editorName ? `${result.editorName} \u6B63\u5728\u7F16\u8F91` : void 0) });
|
|
906
|
+
return;
|
|
907
|
+
}
|
|
908
|
+
session = result.session;
|
|
909
|
+
setManaged({ state: "active", session });
|
|
910
|
+
if (!adapter.heartbeat) return;
|
|
911
|
+
const heartbeat = () => {
|
|
912
|
+
if (typeof navigator !== "undefined" && !navigator.onLine) return;
|
|
913
|
+
void adapter.heartbeat?.({ pageId, session: result.session }).catch(() => {
|
|
914
|
+
if (!cancelled) {
|
|
915
|
+
stopHeartbeat();
|
|
916
|
+
setManaged({ state: "lost", message: "\u7F16\u8F91\u9501\u5DF2\u5931\u6548\uFF0C\u8BF7\u6062\u590D\u7F51\u7EDC\u540E\u91CD\u65B0\u8FDB\u5165\u7F16\u8F91\u5668\u3002" });
|
|
917
|
+
}
|
|
918
|
+
});
|
|
919
|
+
};
|
|
920
|
+
heartbeatTimer = setInterval(heartbeat, adapter.heartbeatIntervalMs ?? 3e4);
|
|
921
|
+
}).catch(() => {
|
|
922
|
+
if (!cancelled) setManaged({ state: "lost", message: "\u65E0\u6CD5\u83B7\u53D6\u7F16\u8F91\u9501\uFF0C\u8BF7\u7A0D\u540E\u91CD\u8BD5\u3002" });
|
|
923
|
+
});
|
|
924
|
+
return () => {
|
|
925
|
+
cancelled = true;
|
|
926
|
+
stopHeartbeat();
|
|
927
|
+
if (session) void adapter.release?.({ pageId, session });
|
|
928
|
+
};
|
|
929
|
+
}, [adapter, pageId]);
|
|
930
|
+
return managed;
|
|
931
|
+
}
|
|
731
932
|
function PageDocumentEditorShell(props) {
|
|
732
|
-
|
|
933
|
+
const { sessionAdapter, initialDocument, onSessionStateChange } = props;
|
|
934
|
+
const managedSession = useEditorSession(sessionAdapter, initialDocument.pageId);
|
|
935
|
+
useEffect3(() => {
|
|
936
|
+
onSessionStateChange?.(managedSession.state);
|
|
937
|
+
}, [managedSession.state, onSessionStateChange]);
|
|
938
|
+
return /* @__PURE__ */ jsx7(EditorProvider, { initialDocument: props.initialDocument, registry: props.registry, policy: props.policy, loadState: props.loadState, sessionState: managedSession.state, session: managedSession.session, sessionMessage: managedSession.message, leaveWarning: createAdminI18n(props.adminLocale).t("leaveWarning"), onDocumentChange: props.onDocumentChange, children: /* @__PURE__ */ jsx7(PageDocumentEditor, { ...props }) });
|
|
733
939
|
}
|
|
734
|
-
function PageDocumentEditor({ iframe = true, registry, adminLocale, onSave, onPublish }) {
|
|
940
|
+
function PageDocumentEditor({ iframe = true, registry, adminLocale, onSave, onPublish, draftPersistence, draftRevision: initialDraftRevision, autoSave = true, autoSaveDelayMs = 800, publishAction, assetPicker, pageStatus, onBack, onPreview, onAddToStore, deleteConfirmation, availableBlockTypes, appearanceControls = false }) {
|
|
735
941
|
const editor = useEditorContext();
|
|
736
942
|
const [blockView, setBlockView] = useState3("blocks");
|
|
737
943
|
const [draggingLibraryType, setDraggingLibraryType] = useState3(null);
|
|
738
944
|
const canvasFrameRef = useRef4(null);
|
|
739
945
|
const [canvasMutationVersion, setCanvasMutationVersion] = useState3(0);
|
|
946
|
+
const [canvasResetVersion, setCanvasResetVersion] = useState3(0);
|
|
740
947
|
const [request, setRequest] = useState3("idle");
|
|
741
948
|
const [notice, setNotice] = useState3(null);
|
|
949
|
+
const [draftRevision, setDraftRevision] = useState3(initialDraftRevision);
|
|
950
|
+
const [isOnline, setIsOnline] = useState3(() => typeof navigator === "undefined" || navigator.onLine);
|
|
951
|
+
const [saveState, setSaveState] = useState3("saved");
|
|
952
|
+
const [zoom, setZoom] = useState3("auto");
|
|
953
|
+
const [confirmBack, setConfirmBack] = useState3(false);
|
|
742
954
|
const i18n = createAdminI18n(adminLocale);
|
|
743
955
|
const engineData = useMemo2(() => toEngineData(editor.document, registry), [editor.document, registry]);
|
|
744
|
-
const
|
|
956
|
+
const validationIssues = useMemo2(() => validateDocumentBlocks(editor.document, registry), [editor.document, registry]);
|
|
957
|
+
const { confirmCanvasSelection, selectedBlockId, updateBlockProps, updateBlockPresentation } = editor;
|
|
745
958
|
const updateFromCanvasInput = useCallback2((id, props, preserveCanvasValue = false) => {
|
|
746
959
|
if (preserveCanvasValue) setCanvasMutationVersion((version) => version + 1);
|
|
747
960
|
updateBlockProps(id, props);
|
|
748
961
|
}, [updateBlockProps]);
|
|
749
962
|
const config = useMemo2(() => createPageDocumentPuckConfig(confirmCanvasSelection, updateFromCanvasInput, selectedBlockId, registry), [confirmCanvasSelection, registry, selectedBlockId, updateFromCanvasInput]);
|
|
750
|
-
|
|
751
|
-
|
|
963
|
+
useEffect3(() => {
|
|
964
|
+
const online = () => setIsOnline(true);
|
|
965
|
+
const offline = () => setIsOnline(false);
|
|
966
|
+
window.addEventListener("online", online);
|
|
967
|
+
window.addEventListener("offline", offline);
|
|
968
|
+
return () => {
|
|
969
|
+
window.removeEventListener("online", online);
|
|
970
|
+
window.removeEventListener("offline", offline);
|
|
971
|
+
};
|
|
972
|
+
}, []);
|
|
973
|
+
const resolvedSaveState = !isOnline && editor.isDirty ? "offline" : saveState === "offline" && editor.isDirty ? "dirty" : saveState === "saved" && editor.isDirty ? "dirty" : saveState;
|
|
974
|
+
const canPersistDraft = Boolean(draftPersistence || onSave);
|
|
975
|
+
const save = useCallback2(async () => {
|
|
976
|
+
if (!canPersistDraft || request !== "idle" || validationIssues.length > 0) return;
|
|
977
|
+
if (!isOnline) {
|
|
978
|
+
setSaveState("offline");
|
|
979
|
+
return;
|
|
980
|
+
}
|
|
981
|
+
const document = editor.document;
|
|
982
|
+
setRequest("saving");
|
|
983
|
+
setSaveState("saving");
|
|
984
|
+
setNotice(null);
|
|
985
|
+
try {
|
|
986
|
+
const result = draftPersistence ? await draftPersistence.saveDraft({ document, expectedRevision: draftRevision, session: editor.session }) : await onSave?.(document);
|
|
987
|
+
if (result?.revision !== void 0) setDraftRevision(result.revision);
|
|
988
|
+
editor.markSaved(document);
|
|
989
|
+
setSaveState("saved");
|
|
990
|
+
} catch {
|
|
991
|
+
setNotice("saveFailed");
|
|
992
|
+
setSaveState(typeof navigator !== "undefined" && !navigator.onLine ? "offline" : "failed");
|
|
993
|
+
} finally {
|
|
994
|
+
setRequest("idle");
|
|
995
|
+
}
|
|
996
|
+
}, [canPersistDraft, draftPersistence, draftRevision, editor, isOnline, onSave, request, validationIssues.length]);
|
|
997
|
+
useEffect3(() => {
|
|
998
|
+
if (!autoSave || !canPersistDraft || !editor.isDirty || resolvedSaveState !== "dirty" || !isOnline || request !== "idle" || validationIssues.length > 0 || editor.sessionState !== "active") return;
|
|
999
|
+
const timer = window.setTimeout(() => {
|
|
1000
|
+
void save();
|
|
1001
|
+
}, autoSaveDelayMs);
|
|
1002
|
+
return () => window.clearTimeout(timer);
|
|
1003
|
+
}, [autoSave, autoSaveDelayMs, canPersistDraft, editor.isDirty, editor.sessionState, isOnline, request, resolvedSaveState, save, validationIssues.length]);
|
|
1004
|
+
const publish = async () => {
|
|
1005
|
+
if (!publishAction && !onPublish || request !== "idle" || validationIssues.length > 0 || !isOnline) return;
|
|
1006
|
+
const document = editor.document;
|
|
1007
|
+
setRequest("publishing");
|
|
1008
|
+
setNotice(null);
|
|
1009
|
+
try {
|
|
1010
|
+
if (publishAction) await publishAction.publish({ document, expectedRevision: draftRevision, session: editor.session, validationIssues });
|
|
1011
|
+
else await onPublish?.(document);
|
|
1012
|
+
editor.markSaved(document);
|
|
1013
|
+
setSaveState("saved");
|
|
1014
|
+
setNotice("published");
|
|
1015
|
+
} catch {
|
|
1016
|
+
setNotice("publishFailed");
|
|
1017
|
+
} finally {
|
|
1018
|
+
setRequest("idle");
|
|
1019
|
+
}
|
|
1020
|
+
};
|
|
1021
|
+
if (editor.loadState !== "ready" && editor.loadState !== "success") return /* @__PURE__ */ jsx7(EditorStatus, { state: editor.loadState });
|
|
1022
|
+
if (editor.sessionState !== "active") return /* @__PURE__ */ jsx7(EditorSessionStatus, { state: editor.sessionState, message: editor.sessionMessage });
|
|
1023
|
+
const allBlockTypes = ["core.text", "core.image", ...registry?.blocks.map((block) => block.type) ?? []];
|
|
1024
|
+
const blockTypes = availableBlockTypes ? allBlockTypes.filter((type) => availableBlockTypes.includes(type)) : allBlockTypes;
|
|
752
1025
|
const addFromLibrary = (type, beforeId) => {
|
|
753
1026
|
const id = editor.addBlock(type, beforeId);
|
|
754
1027
|
if (id) editor.requestCanvasSelection(id);
|
|
@@ -784,115 +1057,125 @@ function PageDocumentEditor({ iframe = true, registry, adminLocale, onSave, onPu
|
|
|
784
1057
|
event.stopPropagation();
|
|
785
1058
|
setDraggingLibraryType(null);
|
|
786
1059
|
};
|
|
787
|
-
const
|
|
788
|
-
|
|
789
|
-
|
|
790
|
-
|
|
791
|
-
|
|
792
|
-
|
|
793
|
-
|
|
794
|
-
} catch {
|
|
795
|
-
setNotice("saveFailed");
|
|
796
|
-
} finally {
|
|
797
|
-
setRequest("idle");
|
|
798
|
-
}
|
|
799
|
-
};
|
|
800
|
-
const publish = async () => {
|
|
801
|
-
if (!onPublish || request !== "idle") return;
|
|
802
|
-
setRequest("publishing");
|
|
803
|
-
setNotice(null);
|
|
804
|
-
try {
|
|
805
|
-
await onPublish(editor.document);
|
|
806
|
-
editor.markSaved();
|
|
807
|
-
setNotice("published");
|
|
808
|
-
} catch {
|
|
809
|
-
setNotice("publishFailed");
|
|
810
|
-
} finally {
|
|
811
|
-
setRequest("idle");
|
|
812
|
-
}
|
|
1060
|
+
const saveBadgeTone = resolvedSaveState === "failed" ? "critical" : resolvedSaveState === "offline" || resolvedSaveState === "dirty" ? "attention" : "success";
|
|
1061
|
+
const saveBadgeLabel = resolvedSaveState === "saving" ? i18n.t("saving") : resolvedSaveState === "failed" ? i18n.t("saveFailed") : resolvedSaveState === "offline" ? i18n.t("offline") : resolvedSaveState === "dirty" ? i18n.t("unsaved") : i18n.t("saved");
|
|
1062
|
+
const saveButtonLabel = request === "saving" ? i18n.t("saving") : resolvedSaveState === "failed" ? i18n.t("retrySave") : i18n.t("save");
|
|
1063
|
+
const requestBack = () => {
|
|
1064
|
+
if (!onBack) return;
|
|
1065
|
+
if (editor.isDirty || request === "saving") setConfirmBack(true);
|
|
1066
|
+
else onBack();
|
|
813
1067
|
};
|
|
814
|
-
return /* @__PURE__ */
|
|
815
|
-
|
|
816
|
-
|
|
817
|
-
|
|
818
|
-
|
|
819
|
-
|
|
820
|
-
|
|
821
|
-
|
|
822
|
-
|
|
823
|
-
"
|
|
824
|
-
|
|
1068
|
+
return /* @__PURE__ */ jsx7(Puck2, { config, data: engineData, iframe: { enabled: iframe }, onChange: (data) => {
|
|
1069
|
+
if (!editor.updateFromCanvas(fromEngineData(data, editor.document, registry))) setCanvasResetVersion((version) => version + 1);
|
|
1070
|
+
}, children: /* @__PURE__ */ jsxs5(Puck2.Layout, { children: [
|
|
1071
|
+
/* @__PURE__ */ jsx7(CanvasSelectionBridge, { data: engineData, requestedBlockId: editor.canvasSelectionRequest, onCanvasSelected: confirmCanvasSelection, canvasMutationVersion, canvasResetVersion }),
|
|
1072
|
+
/* @__PURE__ */ jsxs5("div", { className: "pb-shell pb-shell--v04", "data-testid": "page-document-editor", "data-page-id": editor.document.pageId, "data-dirty": editor.isDirty, "data-editor-state": editor.loadState, "data-editor-session-state": editor.sessionState, "data-save-state": resolvedSaveState, children: [
|
|
1073
|
+
/* @__PURE__ */ jsx7("header", { className: "pb-header", children: /* @__PURE__ */ jsxs5("div", { className: "pb-header-content", children: [
|
|
1074
|
+
/* @__PURE__ */ jsxs5("div", { className: "pb-header-title-group", children: [
|
|
1075
|
+
onBack ? /* @__PURE__ */ jsx7(Button2, { variant: "tertiary", onClick: requestBack, children: i18n.t("back") }) : null,
|
|
1076
|
+
/* @__PURE__ */ jsxs5("div", { className: "pb-page-title", children: [
|
|
1077
|
+
/* @__PURE__ */ jsx7(Text3, { as: "h1", variant: "headingSm", children: editor.document.settings.seoTitle ?? editor.document.pageId }),
|
|
1078
|
+
/* @__PURE__ */ jsxs5(Text3, { as: "p", variant: "bodySm", tone: "subdued", children: [
|
|
1079
|
+
"PageDocument V",
|
|
1080
|
+
editor.document.schemaVersion,
|
|
1081
|
+
" \xB7 ",
|
|
1082
|
+
editor.document.target
|
|
1083
|
+
] }),
|
|
1084
|
+
pageStatus ? /* @__PURE__ */ jsx7(PageStatusCard, { status: pageStatus, sessionState: editor.sessionState }) : null
|
|
825
1085
|
] })
|
|
826
1086
|
] }),
|
|
827
|
-
/* @__PURE__ */
|
|
828
|
-
/* @__PURE__ */
|
|
829
|
-
/* @__PURE__ */
|
|
830
|
-
|
|
831
|
-
|
|
832
|
-
/* @__PURE__ */
|
|
833
|
-
|
|
1087
|
+
/* @__PURE__ */ jsxs5("div", { className: "pb-header-device-toolbar", children: [
|
|
1088
|
+
/* @__PURE__ */ jsx7(ButtonGroup2, { variant: "segmented", children: Object.keys(deviceLabels2).map((device) => /* @__PURE__ */ jsx7(Button2, { pressed: editor.device === device, onClick: () => editor.setDevice(device), children: i18n.t(deviceLabels2[device]) }, device)) }),
|
|
1089
|
+
/* @__PURE__ */ jsx7("div", { className: "pb-zoom-control", children: /* @__PURE__ */ jsx7(Select2, { label: i18n.t("zoom"), labelHidden: true, options: [{ label: i18n.t("zoomAuto"), value: "auto" }, { label: "50%", value: "50" }, { label: "70%", value: "70" }, { label: "100%", value: "100" }], value: zoom, onChange: (value) => setZoom(value) }) })
|
|
1090
|
+
] }),
|
|
1091
|
+
/* @__PURE__ */ jsx7("div", { className: "pb-header-actions", children: /* @__PURE__ */ jsxs5(InlineStack3, { gap: "150", blockAlign: "center", wrap: false, children: [
|
|
1092
|
+
/* @__PURE__ */ jsx7(Badge3, { tone: saveBadgeTone, children: saveBadgeLabel }),
|
|
1093
|
+
/* @__PURE__ */ jsx7(Button2, { disabled: !canPersistDraft || !editor.isDirty || request !== "idle" || validationIssues.length > 0 || !isOnline, onClick: () => void save(), children: saveButtonLabel }),
|
|
1094
|
+
onPreview ? /* @__PURE__ */ jsx7(Button2, { disabled: request !== "idle" || !isOnline, onClick: () => void onPreview({ document: editor.document, draftRevision, session: editor.session }), children: i18n.t("preview") }) : null,
|
|
1095
|
+
onAddToStore ? /* @__PURE__ */ jsx7(Button2, { disabled: request !== "idle" || pageStatus?.publicationStatus === "unpublished", onClick: () => void onAddToStore({ document: editor.document, session: editor.session }), children: i18n.t("addToStore") }) : null,
|
|
1096
|
+
/* @__PURE__ */ jsx7(Button2, { variant: "primary", disabled: !publishAction && !onPublish || request !== "idle" || validationIssues.length > 0 || !isOnline, onClick: () => void publish(), children: request === "publishing" ? i18n.t("publishing") : i18n.t("publish") }),
|
|
1097
|
+
/* @__PURE__ */ jsx7(Button2, { accessibilityLabel: i18n.t("undo"), icon: UndoIcon2, variant: "tertiary", disabled: !editor.actionState.canUndo, onClick: editor.undo }),
|
|
1098
|
+
/* @__PURE__ */ jsx7(Button2, { accessibilityLabel: i18n.t("redo"), icon: RedoIcon2, variant: "tertiary", disabled: !editor.actionState.canRedo, onClick: editor.redo })
|
|
1099
|
+
] }) })
|
|
834
1100
|
] }) }),
|
|
835
|
-
editor.loadState === "success" ? /* @__PURE__ */
|
|
836
|
-
notice ? /* @__PURE__ */
|
|
837
|
-
/* @__PURE__ */
|
|
838
|
-
|
|
839
|
-
|
|
840
|
-
|
|
1101
|
+
editor.loadState === "success" ? /* @__PURE__ */ jsx7(Banner, { tone: "success", children: i18n.t("success") }) : null,
|
|
1102
|
+
notice ? /* @__PURE__ */ jsx7(Banner, { tone: notice === "published" ? "success" : "critical", children: i18n.t(notice) }) : null,
|
|
1103
|
+
validationIssues.length > 0 ? /* @__PURE__ */ jsx7(Banner, { tone: "critical", title: "\u533A\u5757\u5C5E\u6027\u672A\u901A\u8FC7\u6821\u9A8C", children: /* @__PURE__ */ jsx7("ul", { children: validationIssues.map((issue) => /* @__PURE__ */ jsxs5("li", { children: [
|
|
1104
|
+
issue.path,
|
|
1105
|
+
": ",
|
|
1106
|
+
issue.message
|
|
1107
|
+
] }, `${issue.path}-${issue.message}`)) }) }) : null,
|
|
1108
|
+
/* @__PURE__ */ jsxs5("div", { className: "pb-workspace pb-workspace--document", children: [
|
|
1109
|
+
/* @__PURE__ */ jsxs5("nav", { className: "pb-tool-rail", "aria-label": "\u7F16\u8F91\u5668\u5DE5\u5177", children: [
|
|
1110
|
+
/* @__PURE__ */ jsx7(Button2, { accessibilityLabel: i18n.t("blocks"), icon: LayoutSectionIcon2, pressed: blockView === "blocks", variant: "tertiary", onClick: () => setBlockView("blocks") }),
|
|
1111
|
+
/* @__PURE__ */ jsx7(Button2, { accessibilityLabel: i18n.t("outline"), icon: MenuIcon2, pressed: blockView === "outline", variant: "tertiary", onClick: () => setBlockView("outline") })
|
|
841
1112
|
] }),
|
|
842
|
-
/* @__PURE__ */
|
|
843
|
-
/* @__PURE__ */
|
|
844
|
-
blockView === "blocks" ? /* @__PURE__ */
|
|
1113
|
+
/* @__PURE__ */ jsxs5("aside", { className: "pb-left-panel", "aria-label": "PageDocument \u533A\u5757", children: [
|
|
1114
|
+
/* @__PURE__ */ jsx7(InlineStack3, { align: "space-between", blockAlign: "center", children: /* @__PURE__ */ jsx7(Text3, { as: "h2", variant: "headingSm", children: blockView === "blocks" ? i18n.t("blocks") : i18n.t("outline") }) }),
|
|
1115
|
+
blockView === "blocks" ? /* @__PURE__ */ jsx7("div", { className: "pb-block-list", "data-testid": "blocks-view", "aria-label": "\u533A\u5757\u7C7B\u578B\u5E93", role: "list", onDrop: cancelLibraryDrop, children: blockTypes.map((type) => /* @__PURE__ */ jsxs5("div", { className: `pb-document-block-row pb-document-block-row--library ${editor.selectedBlock?.type === type ? "pb-document-block-row--selected" : ""}`, "data-block-type": type, "data-selected": editor.selectedBlock?.type === type, role: "listitem", draggable: editor.canAddBlock(type), "aria-disabled": !editor.canAddBlock(type), "aria-label": `${blockTypeLabel(type, registry)}\uFF0C\u62D6\u62FD\u81F3\u753B\u5E03\u4EE5\u6DFB\u52A0${editor.selectedBlock?.type === type ? "\uFF0C\u5F53\u524D\u9009\u4E2D\u7C7B\u578B" : ""}`, onDragStart: (event) => {
|
|
1116
|
+
if (!editor.canAddBlock(type)) {
|
|
1117
|
+
event.preventDefault();
|
|
1118
|
+
return;
|
|
1119
|
+
}
|
|
845
1120
|
event.dataTransfer.setData("application/x-page-document-block", type);
|
|
846
1121
|
event.dataTransfer.effectAllowed = "copy";
|
|
847
1122
|
setDraggingLibraryType(type);
|
|
848
1123
|
}, onDragEnd: () => setDraggingLibraryType(null), children: [
|
|
849
|
-
/* @__PURE__ */
|
|
850
|
-
/* @__PURE__ */
|
|
851
|
-
/* @__PURE__ */
|
|
1124
|
+
/* @__PURE__ */ jsxs5("span", { className: "pb-library-block-title", children: [
|
|
1125
|
+
/* @__PURE__ */ jsx7(Text3, { as: "span", variant: "bodySm", fontWeight: "semibold", children: blockTypeLabel(type, registry) }),
|
|
1126
|
+
/* @__PURE__ */ jsx7("span", { className: "pb-library-block-drag-hint", "aria-hidden": "true", children: /* @__PURE__ */ jsx7(DragHandleIcon2, {}) })
|
|
852
1127
|
] }),
|
|
853
|
-
/* @__PURE__ */
|
|
854
|
-
] }, type)) }) : editor.document.blocks.length === 0 ? /* @__PURE__ */
|
|
855
|
-
/* @__PURE__ */
|
|
856
|
-
/* @__PURE__ */
|
|
1128
|
+
/* @__PURE__ */ jsx7(Text3, { as: "span", variant: "bodySm", tone: "subdued", children: type })
|
|
1129
|
+
] }, type)) }) : editor.document.blocks.length === 0 ? /* @__PURE__ */ jsx7(Text3, { as: "p", tone: "subdued", children: i18n.t("empty") }) : /* @__PURE__ */ jsx7("div", { className: "pb-block-list", "data-testid": "outline-view", children: editor.document.blocks.map((block) => /* @__PURE__ */ jsxs5("button", { type: "button", className: `pb-document-block-row pb-document-block-row--library ${block.id === editor.selectedBlockId ? "pb-document-block-row--selected" : ""}`, "aria-pressed": block.id === editor.selectedBlockId, onClick: () => editor.requestCanvasSelection(block.id), children: [
|
|
1130
|
+
/* @__PURE__ */ jsx7(Text3, { as: "span", variant: "bodySm", fontWeight: "semibold", children: blockLabel(block, registry) }),
|
|
1131
|
+
/* @__PURE__ */ jsx7(Text3, { as: "span", variant: "bodySm", tone: "subdued", children: block.id })
|
|
857
1132
|
] }, block.id)) })
|
|
858
1133
|
] }),
|
|
859
|
-
/* @__PURE__ */
|
|
860
|
-
/* @__PURE__ */
|
|
861
|
-
/* @__PURE__ */
|
|
862
|
-
|
|
863
|
-
draggingLibraryType
|
|
864
|
-
|
|
865
|
-
|
|
866
|
-
|
|
867
|
-
|
|
868
|
-
|
|
869
|
-
|
|
870
|
-
|
|
871
|
-
|
|
872
|
-
|
|
873
|
-
|
|
874
|
-
|
|
875
|
-
|
|
1134
|
+
/* @__PURE__ */ jsx7("main", { className: "pb-canvas-area", children: /* @__PURE__ */ jsxs5("div", { className: "pb-canvas-stage", children: [
|
|
1135
|
+
/* @__PURE__ */ jsx7("div", { ref: canvasFrameRef, className: `pb-canvas-frame pb-canvas-frame--${editor.device}${zoom === "auto" ? "" : ` pb-canvas-frame--zoom-${zoom}`}`, "data-device": editor.device, "data-zoom": zoom, children: /* @__PURE__ */ jsx7(Puck2.Preview, {}) }),
|
|
1136
|
+
draggingLibraryType ? /* @__PURE__ */ jsxs5("div", { className: "pb-canvas-drop-target", "data-testid": "canvas-drop-target", role: "region", "aria-label": "\u533A\u5757\u6295\u653E\u533A", onDragOver: (event) => event.preventDefault(), onDrop: dropFromLibrary, children: [
|
|
1137
|
+
"\u677E\u5F00\u4EE5\u6DFB\u52A0 ",
|
|
1138
|
+
blockTypeLabel(draggingLibraryType, registry)
|
|
1139
|
+
] }) : null,
|
|
1140
|
+
editor.selectedBlock ? /* @__PURE__ */ jsxs5("div", { className: "pb-canvas-overlay", "aria-label": `\u5DF2\u9009\u62E9 ${blockLabel(editor.selectedBlock, registry)}`, children: [
|
|
1141
|
+
/* @__PURE__ */ jsx7("span", { children: blockLabel(editor.selectedBlock, registry) }),
|
|
1142
|
+
/* @__PURE__ */ jsx7("span", { children: "Selected" })
|
|
1143
|
+
] }) : null
|
|
1144
|
+
] }) }),
|
|
1145
|
+
/* @__PURE__ */ jsxs5("aside", { className: "pb-right-panel", "aria-label": "PageDocument \u5C5E\u6027", children: [
|
|
1146
|
+
/* @__PURE__ */ jsx7(Text3, { as: "h2", variant: "headingSm", children: i18n.t("properties") }),
|
|
1147
|
+
editor.selectedBlock ? /* @__PURE__ */ jsxs5(Fragment2, { children: [
|
|
1148
|
+
/* @__PURE__ */ jsx7(DocumentInspector, { pageId: editor.document.pageId, assetPicker, block: editor.selectedBlock, registry, disabled: !editor.actionState.canEdit, appearanceControls, onChange: (props) => editor.updateBlockProps(editor.selectedBlock.id, props), onPresentationChange: (presentation) => updateBlockPresentation(editor.selectedBlock.id, presentation) }),
|
|
1149
|
+
/* @__PURE__ */ jsx7(InspectorActions, { block: editor.selectedBlock, canDuplicate: editor.actionState.canDuplicate, canDelete: editor.actionState.canDelete, canMove: editor.actionState.canReorder, canMoveUp: editor.document.blocks[0]?.id !== editor.selectedBlock.id, canMoveDown: editor.document.blocks.at(-1)?.id !== editor.selectedBlock.id, i18n, onDuplicate: () => editor.duplicateBlock(editor.selectedBlock.id), onDelete: () => editor.requestDeleteBlock(editor.selectedBlock.id), onMove: (direction) => editor.moveBlock(editor.selectedBlock.id, direction) })
|
|
1150
|
+
] }) : /* @__PURE__ */ jsx7(Text3, { as: "p", tone: "subdued", children: i18n.t("selectBlock") })
|
|
876
1151
|
] })
|
|
877
|
-
] })
|
|
1152
|
+
] }),
|
|
1153
|
+
editor.pendingDeleteBlock ? /* @__PURE__ */ jsx7(DeleteConfirmation, { block: editor.pendingDeleteBlock, config: deleteConfirmation, i18n, onCancel: editor.cancelDeleteBlock, onConfirm: editor.confirmDeleteBlock }) : null,
|
|
1154
|
+
confirmBack ? /* @__PURE__ */ jsx7(LeaveConfirmation, { i18n, onCancel: () => setConfirmBack(false), onConfirm: () => {
|
|
1155
|
+
setConfirmBack(false);
|
|
1156
|
+
onBack?.();
|
|
1157
|
+
} }) : null
|
|
878
1158
|
] })
|
|
879
1159
|
] }) });
|
|
880
1160
|
}
|
|
881
|
-
function CanvasSelectionBridge({ data, requestedBlockId, onCanvasSelected, canvasMutationVersion }) {
|
|
1161
|
+
function CanvasSelectionBridge({ data, requestedBlockId, onCanvasSelected, canvasMutationVersion, canvasResetVersion }) {
|
|
882
1162
|
const puck = usePuck();
|
|
883
1163
|
const lastSelectedId = useRef4(null);
|
|
884
1164
|
const lastSyncedData = useRef4(null);
|
|
885
1165
|
const lastCanvasMutationVersion = useRef4(0);
|
|
1166
|
+
const lastCanvasResetVersion = useRef4(0);
|
|
886
1167
|
const serializedData = JSON.stringify(data);
|
|
887
1168
|
useEffect3(() => {
|
|
888
|
-
|
|
1169
|
+
const forceReset = canvasResetVersion > lastCanvasResetVersion.current;
|
|
1170
|
+
if (lastSyncedData.current === serializedData && !forceReset) return;
|
|
889
1171
|
lastSyncedData.current = serializedData;
|
|
1172
|
+
if (forceReset) lastCanvasResetVersion.current = canvasResetVersion;
|
|
890
1173
|
if (canvasMutationVersion > lastCanvasMutationVersion.current) {
|
|
891
1174
|
lastCanvasMutationVersion.current = canvasMutationVersion;
|
|
892
1175
|
return;
|
|
893
1176
|
}
|
|
894
1177
|
puck.dispatch({ type: "setData", data });
|
|
895
|
-
}, [canvasMutationVersion, data, puck, serializedData]);
|
|
1178
|
+
}, [canvasMutationVersion, canvasResetVersion, data, puck, serializedData]);
|
|
896
1179
|
useEffect3(() => {
|
|
897
1180
|
if (!requestedBlockId) return;
|
|
898
1181
|
const selector = puck.getSelectorForId(requestedBlockId);
|
|
@@ -911,39 +1194,79 @@ function EditorStatus({ state }) {
|
|
|
911
1194
|
const i18n = createAdminI18n();
|
|
912
1195
|
const tone = state === "error" ? "critical" : state === "disabled" ? "warning" : "info";
|
|
913
1196
|
const message = state === "loading" ? i18n.t("loading") : state === "empty" ? i18n.t("empty") : state === "error" ? i18n.t("error") : i18n.t("disabled");
|
|
914
|
-
return /* @__PURE__ */
|
|
1197
|
+
return /* @__PURE__ */ jsx7("div", { className: "pb-editor-status", "data-testid": "page-document-editor-state", "data-editor-state": state, children: /* @__PURE__ */ jsx7(Banner, { tone, title: message, children: state === "disabled" ? i18n.t("disabled") : message }) });
|
|
1198
|
+
}
|
|
1199
|
+
function EditorSessionStatus({ state, message }) {
|
|
1200
|
+
const i18n = createAdminI18n();
|
|
1201
|
+
const tone = state === "locked" ? "warning" : state === "readonly" ? "info" : "critical";
|
|
1202
|
+
const title = state === "acquiring" ? i18n.t("acquiringLock") : state === "locked" ? i18n.t("locked") : state === "readonly" ? i18n.t("readonly") : i18n.t("lockLost");
|
|
1203
|
+
return /* @__PURE__ */ jsx7("div", { className: "pb-editor-status", "data-testid": "page-document-editor-session-state", "data-editor-session-state": state, children: /* @__PURE__ */ jsx7(Banner, { tone, title, children: message ?? title }) });
|
|
915
1204
|
}
|
|
916
1205
|
function InspectorSection({ title, children, defaultOpen = true }) {
|
|
917
|
-
return /* @__PURE__ */
|
|
918
|
-
/* @__PURE__ */
|
|
919
|
-
/* @__PURE__ */
|
|
920
|
-
/* @__PURE__ */
|
|
1206
|
+
return /* @__PURE__ */ jsxs5("details", { className: "pb-inspector-section", open: defaultOpen, children: [
|
|
1207
|
+
/* @__PURE__ */ jsxs5("summary", { children: [
|
|
1208
|
+
/* @__PURE__ */ jsx7("span", { children: title }),
|
|
1209
|
+
/* @__PURE__ */ jsx7("span", { "aria-hidden": "true", children: "\u2304" })
|
|
921
1210
|
] }),
|
|
922
|
-
/* @__PURE__ */
|
|
1211
|
+
/* @__PURE__ */ jsx7("div", { className: "pb-inspector-section__body", children })
|
|
923
1212
|
] });
|
|
924
1213
|
}
|
|
925
1214
|
function InspectorTextControl({ label, value, control, disabled, onChange }) {
|
|
926
1215
|
const stringValue = typeof value === "string" ? value : "";
|
|
927
|
-
return /* @__PURE__ */
|
|
1216
|
+
if (control === "color") return /* @__PURE__ */ jsx7("input", { "aria-label": label, type: "color", value: /^#[\da-f]{6}$/i.test(stringValue) ? stringValue : "#000000", disabled, onChange: (event) => onChange(event.currentTarget.value) });
|
|
1217
|
+
return /* @__PURE__ */ jsx7(TextField, { label, labelHidden: true, value: stringValue, onChange, autoComplete: "off", disabled, multiline: control === "textarea" ? 4 : false, type: control === "url" ? "url" : "text" });
|
|
928
1218
|
}
|
|
929
1219
|
function InspectorField({ name, field, value, registry, disabled, onChange }) {
|
|
930
1220
|
const label = field.label ?? name;
|
|
1221
|
+
const issues = validateFieldValue(field, value);
|
|
931
1222
|
const Field = registry?.getField(field.field)?.component;
|
|
932
|
-
return /* @__PURE__ */
|
|
933
|
-
/* @__PURE__ */
|
|
934
|
-
/* @__PURE__ */
|
|
935
|
-
field.description ? /* @__PURE__ */
|
|
1223
|
+
return /* @__PURE__ */ jsxs5("div", { className: "pb-inspector-field", "data-control": field.control ?? "custom", children: [
|
|
1224
|
+
/* @__PURE__ */ jsxs5("div", { className: "pb-inspector-field__heading", children: [
|
|
1225
|
+
/* @__PURE__ */ jsx7(Text3, { as: "p", variant: "bodySm", fontWeight: "semibold", children: label }),
|
|
1226
|
+
field.description ? /* @__PURE__ */ jsx7(Text3, { as: "p", variant: "bodySm", tone: "subdued", children: field.description }) : null
|
|
936
1227
|
] }),
|
|
937
|
-
field.control ? /* @__PURE__ */
|
|
1228
|
+
field.control ? /* @__PURE__ */ jsx7(InspectorTextControl, { label, value, control: field.control, disabled, onChange: (next) => onChange(next) }) : Field ? /* @__PURE__ */ jsx7(Field, { value, onChange }) : null,
|
|
1229
|
+
issues.map((issue) => /* @__PURE__ */ jsx7(Text3, { as: "p", variant: "bodySm", tone: "critical", children: issue.message }, issue.message))
|
|
938
1230
|
] });
|
|
939
1231
|
}
|
|
1232
|
+
function InspectorActions({ block, canDuplicate, canDelete, canMove, canMoveUp, canMoveDown, i18n, onDuplicate, onDelete, onMove }) {
|
|
1233
|
+
return /* @__PURE__ */ jsx7("div", { className: "pb-inspector-actions", "aria-label": `Actions for ${block.id}`, children: /* @__PURE__ */ jsxs5(ButtonGroup2, { children: [
|
|
1234
|
+
/* @__PURE__ */ jsx7(Button2, { disabled: !canMove || !canMoveUp, onClick: () => onMove(-1), children: i18n.t("moveUp") }),
|
|
1235
|
+
/* @__PURE__ */ jsx7(Button2, { disabled: !canMove || !canMoveDown, onClick: () => onMove(1), children: i18n.t("moveDown") }),
|
|
1236
|
+
/* @__PURE__ */ jsx7(Button2, { disabled: !canDuplicate, onClick: onDuplicate, children: i18n.t("duplicate") }),
|
|
1237
|
+
/* @__PURE__ */ jsx7(Button2, { disabled: !canDelete, tone: "critical", onClick: onDelete, children: i18n.t("remove") })
|
|
1238
|
+
] }) });
|
|
1239
|
+
}
|
|
1240
|
+
function DeleteConfirmation({ block, config, i18n, onCancel, onConfirm }) {
|
|
1241
|
+
return /* @__PURE__ */ jsx7("div", { className: "pb-delete-confirmation-backdrop", role: "presentation", children: /* @__PURE__ */ jsxs5("section", { className: "pb-delete-confirmation", role: "dialog", "aria-modal": "true", "aria-labelledby": "pb-delete-confirmation-title", children: [
|
|
1242
|
+
/* @__PURE__ */ jsx7(Text3, { as: "h2", variant: "headingMd", id: "pb-delete-confirmation-title", children: config?.title ?? i18n.t("confirmDeleteTitle") }),
|
|
1243
|
+
/* @__PURE__ */ jsx7(Text3, { as: "p", variant: "bodyMd", children: config?.message?.(block) ?? i18n.t("confirmDeleteMessage") }),
|
|
1244
|
+
/* @__PURE__ */ jsxs5(ButtonGroup2, { children: [
|
|
1245
|
+
/* @__PURE__ */ jsx7(Button2, { onClick: onCancel, children: config?.cancelLabel ?? i18n.t("cancel") }),
|
|
1246
|
+
/* @__PURE__ */ jsx7(Button2, { tone: "critical", onClick: onConfirm, children: config?.confirmLabel ?? i18n.t("confirm") })
|
|
1247
|
+
] })
|
|
1248
|
+
] }) });
|
|
1249
|
+
}
|
|
1250
|
+
function LeaveConfirmation({ i18n, onCancel, onConfirm }) {
|
|
1251
|
+
return /* @__PURE__ */ jsx7("div", { className: "pb-delete-confirmation-backdrop", role: "presentation", children: /* @__PURE__ */ jsxs5("section", { className: "pb-delete-confirmation", role: "dialog", "aria-modal": "true", "aria-labelledby": "pb-leave-confirmation-title", children: [
|
|
1252
|
+
/* @__PURE__ */ jsx7(Text3, { as: "h2", variant: "headingMd", id: "pb-leave-confirmation-title", children: i18n.t("confirmLeaveTitle") }),
|
|
1253
|
+
/* @__PURE__ */ jsx7(Text3, { as: "p", variant: "bodyMd", children: i18n.t("leaveWarning") }),
|
|
1254
|
+
/* @__PURE__ */ jsxs5(ButtonGroup2, { children: [
|
|
1255
|
+
/* @__PURE__ */ jsx7(Button2, { onClick: onCancel, children: i18n.t("cancel") }),
|
|
1256
|
+
/* @__PURE__ */ jsx7(Button2, { tone: "critical", onClick: onConfirm, children: i18n.t("leave") })
|
|
1257
|
+
] })
|
|
1258
|
+
] }) });
|
|
1259
|
+
}
|
|
940
1260
|
function inspectorFieldConfig(name, field) {
|
|
941
1261
|
const key = name.toLowerCase();
|
|
942
1262
|
const group = /(?:href|url)/.test(key) ? "Links" : /(?:default|shipment|query|hide)/.test(key) ? "Tracking settings" : /(?:id|variant|theme)/.test(key) ? "Advanced" : "Content";
|
|
943
1263
|
const description = field.description ?? (field.control === "textarea" ? "\u9002\u5408\u8F83\u957F\u6216\u591A\u884C\u7684\u5C55\u793A\u6587\u6848\u3002" : field.control === "url" ? "\u4F7F\u7528\u7AD9\u5185\u76F8\u5BF9\u8DEF\u5F84\u6216 HTTPS \u5730\u5740\u3002" : key.includes("shipment") ? "\u591A\u4E2A\u5305\u88F9\u6807\u7B7E\u4F7F\u7528 | \u5206\u9694\u3002" : key.includes("default") ? "\u4EC5\u7528\u4E8E\u7F16\u8F91\u5668\u548C\u7A7A\u72B6\u6001\u9884\u89C8\u3002" : void 0);
|
|
944
1264
|
return { ...field, group: field.group ?? group, description };
|
|
945
1265
|
}
|
|
946
|
-
|
|
1266
|
+
var appearanceTokens = [["color.primary", "\u4E3B\u8272"], ["color.surface", "\u8868\u9762\u8272"], ["radius", "\u5706\u89D2"], ["spacing", "\u95F4\u8DDD"]];
|
|
1267
|
+
function DocumentInspector({ pageId, assetPicker, block, registry, disabled, appearanceControls, onChange, onPresentationChange }) {
|
|
1268
|
+
const [assetError, setAssetError] = useState3(null);
|
|
1269
|
+
const [selectingAsset, setSelectingAsset] = useState3(false);
|
|
947
1270
|
const definition = registry?.getBlock(block.type);
|
|
948
1271
|
const groupedFields = definition ? Object.entries(definition.fields).reduce((groups, entry) => {
|
|
949
1272
|
const [name, field] = entry;
|
|
@@ -952,21 +1275,43 @@ function DocumentInspector({ block, registry, disabled, onChange }) {
|
|
|
952
1275
|
(groups[group] ??= []).push([name, configuredField]);
|
|
953
1276
|
return groups;
|
|
954
1277
|
}, {}) : {};
|
|
955
|
-
return /* @__PURE__ */
|
|
956
|
-
/* @__PURE__ */
|
|
957
|
-
/* @__PURE__ */
|
|
958
|
-
/* @__PURE__ */
|
|
959
|
-
/* @__PURE__ */
|
|
960
|
-
/* @__PURE__ */
|
|
1278
|
+
return /* @__PURE__ */ jsxs5("div", { className: "pb-inspector", "data-testid": "document-inspector", children: [
|
|
1279
|
+
/* @__PURE__ */ jsxs5("header", { className: "pb-inspector__header", children: [
|
|
1280
|
+
/* @__PURE__ */ jsx7(Badge3, { children: block.type }),
|
|
1281
|
+
/* @__PURE__ */ jsxs5("div", { children: [
|
|
1282
|
+
/* @__PURE__ */ jsx7(Text3, { as: "p", variant: "headingSm", children: blockLabel(block, registry) }),
|
|
1283
|
+
/* @__PURE__ */ jsx7(Text3, { as: "p", variant: "bodySm", tone: "subdued", children: definition?.category ?? "Core block" })
|
|
961
1284
|
] })
|
|
962
1285
|
] }),
|
|
963
|
-
block.type === "core.text" ? /* @__PURE__ */
|
|
964
|
-
block.type === "core.image" ? /* @__PURE__ */
|
|
965
|
-
/* @__PURE__ */
|
|
966
|
-
/* @__PURE__ */
|
|
1286
|
+
block.type === "core.text" ? /* @__PURE__ */ jsx7(InspectorSection, { title: "Content", children: /* @__PURE__ */ jsx7(InspectorField, { name: "content", field: { field: "", label: "\u6587\u672C\u5185\u5BB9", control: "textarea", description: "\u652F\u6301\u8F83\u957F\u7684\u6B63\u6587\u5185\u5BB9\u3002" }, value: block.props.content, registry, disabled, onChange: (content) => onChange({ content }) }) }) : null,
|
|
1287
|
+
block.type === "core.image" ? /* @__PURE__ */ jsxs5(InspectorSection, { title: "Image", children: [
|
|
1288
|
+
/* @__PURE__ */ jsx7(InspectorField, { name: "src", field: { field: "", label: "\u56FE\u7247 URL", control: "url", description: "\u4F7F\u7528 HTTPS \u56FE\u7247\u5730\u5740\u3002" }, value: block.props.src, registry, disabled, onChange: (src) => onChange({ src }) }),
|
|
1289
|
+
/* @__PURE__ */ jsx7(InspectorField, { name: "alt", field: { field: "", label: "\u66FF\u4EE3\u6587\u672C", control: "text", description: "\u7528\u4E8E\u65E0\u969C\u788D\u9605\u8BFB\u548C\u56FE\u7247\u52A0\u8F7D\u5931\u8D25\u573A\u666F\u3002" }, value: block.props.alt, registry, disabled, onChange: (alt) => onChange({ alt }) }),
|
|
1290
|
+
assetPicker ? /* @__PURE__ */ jsxs5(Fragment2, { children: [
|
|
1291
|
+
/* @__PURE__ */ jsx7(Button2, { disabled: disabled || selectingAsset, onClick: () => void (async () => {
|
|
1292
|
+
setSelectingAsset(true);
|
|
1293
|
+
setAssetError(null);
|
|
1294
|
+
try {
|
|
1295
|
+
const asset = await assetPicker.selectAsset({ pageId, blockId: block.id, current: { id: typeof block.props.assetId === "string" ? block.props.assetId : void 0, url: typeof block.props.src === "string" ? block.props.src : void 0, alt: typeof block.props.alt === "string" ? block.props.alt : void 0 } });
|
|
1296
|
+
if (asset) onChange({ ...block.props, assetId: asset.id, src: asset.url, alt: asset.alt ?? (typeof block.props.alt === "string" ? block.props.alt : "") });
|
|
1297
|
+
} catch {
|
|
1298
|
+
setAssetError("\u65E0\u6CD5\u9009\u62E9\u7D20\u6750\uFF0C\u8BF7\u91CD\u8BD5\u3002");
|
|
1299
|
+
} finally {
|
|
1300
|
+
setSelectingAsset(false);
|
|
1301
|
+
}
|
|
1302
|
+
})(), children: selectingAsset ? "\u6B63\u5728\u9009\u62E9\u7D20\u6750\u2026" : "\u9009\u62E9\u7D20\u6750" }),
|
|
1303
|
+
assetError ? /* @__PURE__ */ jsx7(Text3, { as: "p", variant: "bodySm", tone: "critical", children: assetError }) : null
|
|
1304
|
+
] }) : null
|
|
967
1305
|
] }) : null,
|
|
968
|
-
Object.entries(groupedFields).map(([group, fields]) => /* @__PURE__ */
|
|
969
|
-
definition ? /* @__PURE__ */
|
|
1306
|
+
Object.entries(groupedFields).map(([group, fields]) => /* @__PURE__ */ jsx7(InspectorSection, { title: group, defaultOpen: group !== "Advanced", children: fields.map(([name, field]) => /* @__PURE__ */ jsx7(InspectorField, { name, field, value: block.props[name], registry, disabled, onChange: (value) => onChange({ ...block.props, [name]: value }) }, name)) }, group)),
|
|
1307
|
+
appearanceControls && definition?.variants?.length ? /* @__PURE__ */ jsx7(InspectorSection, { title: "\u5916\u89C2", children: /* @__PURE__ */ jsx7(Select2, { label: "\u6837\u5F0F\u53D8\u4F53", options: definition.variants.map((variant) => ({ label: variant.label, value: variant.id })), value: block.variant, disabled, onChange: (variant) => onPresentationChange({ variant, style: block.style }) }) }) : null,
|
|
1308
|
+
appearanceControls && definition ? /* @__PURE__ */ jsx7(InspectorSection, { title: "\u6837\u5F0F\u8986\u76D6", defaultOpen: false, children: appearanceTokens.map(([token, label]) => /* @__PURE__ */ jsx7(TextField, { label, value: block.style[token] ?? "", placeholder: "\u7EE7\u627F\u9875\u9762\u6216\u6A21\u677F\u8BBE\u7F6E", autoComplete: "off", disabled, onChange: (value) => {
|
|
1309
|
+
const style = { ...block.style };
|
|
1310
|
+
if (value.trim()) style[token] = value;
|
|
1311
|
+
else delete style[token];
|
|
1312
|
+
onPresentationChange({ variant: block.variant, style });
|
|
1313
|
+
} }, token)) }) : null,
|
|
1314
|
+
definition ? /* @__PURE__ */ jsx7("p", { className: "pb-inspector__hint", children: "\u753B\u5E03\u4E2D\u5E26\u865A\u7EBF\u8FB9\u6846\u7684\u5185\u5BB9\u53EF\u76F4\u63A5\u7F16\u8F91\u3002" }) : null
|
|
970
1315
|
] });
|
|
971
1316
|
}
|
|
972
1317
|
export {
|
|
@@ -975,6 +1320,7 @@ export {
|
|
|
975
1320
|
ExtensionRegistry,
|
|
976
1321
|
ExtensionRegistryError,
|
|
977
1322
|
PageDocumentEditorShell,
|
|
1323
|
+
PageStatusCard,
|
|
978
1324
|
TemplateRegistry,
|
|
979
1325
|
WebRenderer,
|
|
980
1326
|
createAdminI18n,
|
|
@@ -982,12 +1328,18 @@ export {
|
|
|
982
1328
|
createPageDocument,
|
|
983
1329
|
createTemplateRegistry,
|
|
984
1330
|
fromEngineData,
|
|
1331
|
+
maximumBlockInstances,
|
|
1332
|
+
mergeBlockPolicies,
|
|
985
1333
|
mergeThemeTokens,
|
|
986
1334
|
migratePageDocument,
|
|
1335
|
+
minimumBlockInstances,
|
|
987
1336
|
normalizeThemeTokens,
|
|
988
1337
|
systemThemeTokens,
|
|
989
1338
|
toEngineData,
|
|
990
1339
|
toThemeStyle,
|
|
991
1340
|
useEditorContext,
|
|
992
|
-
|
|
1341
|
+
validateBlockPolicy,
|
|
1342
|
+
validateFieldValue,
|
|
1343
|
+
validatePageDocument,
|
|
1344
|
+
validatePageDocumentWithRegistry
|
|
993
1345
|
};
|