@standhigher/puck-page-builder 0.12.5 → 0.12.7
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.d.ts +1 -1
- package/dist/index.js +544 -268
- package/package.json +1 -1
- package/src/styles.css +24 -7
package/dist/index.js
CHANGED
|
@@ -260,13 +260,7 @@ function EditorShell({ initialState, iframe = true }) {
|
|
|
260
260
|
] }),
|
|
261
261
|
/* @__PURE__ */ jsxs2("main", { className: "pb-canvas-area", children: [
|
|
262
262
|
/* @__PURE__ */ jsx2(CanvasToolbar, { device: state.device, zoom: state.zoom, onDevice: (device) => update({ device }), onZoom: (zoom) => update({ zoom }) }),
|
|
263
|
-
/* @__PURE__ */
|
|
264
|
-
/* @__PURE__ */ jsx2("div", { className: `pb-canvas-frame pb-canvas-frame--${state.device} pb-canvas-frame--zoom-${state.zoom}`, "data-device": state.device, "data-zoom": state.zoom, children: /* @__PURE__ */ jsx2(Puck.Preview, {}) }),
|
|
265
|
-
selectedBlock ? /* @__PURE__ */ jsxs2("div", { className: "pb-canvas-overlay", "aria-label": `\u5DF2\u9009\u62E9 ${selectedBlock.label}`, children: [
|
|
266
|
-
/* @__PURE__ */ jsx2("span", { children: selectedBlock.label }),
|
|
267
|
-
/* @__PURE__ */ jsx2("span", { children: "Selected" })
|
|
268
|
-
] }) : null
|
|
269
|
-
] }),
|
|
263
|
+
/* @__PURE__ */ jsx2("div", { className: "pb-canvas-stage", children: /* @__PURE__ */ jsx2("div", { className: `pb-canvas-frame pb-canvas-frame--${state.device} pb-canvas-frame--zoom-${state.zoom}`, "data-device": state.device, "data-zoom": state.zoom, children: /* @__PURE__ */ jsx2(Puck.Preview, {}) }) }),
|
|
270
264
|
!state.isLeftRailOpen || !state.isRightPanelOpen ? /* @__PURE__ */ jsxs2("div", { className: "pb-collapsed-actions", children: [
|
|
271
265
|
!state.isLeftRailOpen ? /* @__PURE__ */ jsx2(Button, { onClick: () => update({ isLeftRailOpen: true }), children: "\u6253\u5F00\u533A\u5757\u9762\u677F" }) : null,
|
|
272
266
|
!state.isRightPanelOpen ? /* @__PURE__ */ jsx2(Button, { onClick: () => update({ isRightPanelOpen: true }), children: "\u6253\u5F00\u5C5E\u6027\u9762\u677F" }) : null
|
|
@@ -353,22 +347,72 @@ function PropertyPanel({
|
|
|
353
347
|
import { Puck as Puck2, usePuck } from "@puckeditor/core";
|
|
354
348
|
import { Badge as Badge3, Banner, Button as Button2, ButtonGroup as ButtonGroup2, Frame, InlineStack as InlineStack3, Select as Select2, Text as Text3, TextField, Toast } from "@shopify/polaris";
|
|
355
349
|
import { DragHandleIcon as DragHandleIcon2, LayoutSectionIcon as LayoutSectionIcon2, MenuIcon as MenuIcon2, ProductIcon, RedoIcon as RedoIcon2, UndoIcon as UndoIcon2, XIcon as XIcon2 } from "@shopify/polaris-icons";
|
|
356
|
-
import { useCallback as useCallback2, useEffect as
|
|
350
|
+
import { useCallback as useCallback2, useEffect as useEffect4, useLayoutEffect, useMemo as useMemo2, useRef as useRef5, useState as useState4 } from "react";
|
|
357
351
|
|
|
358
|
-
// src/adapters/puck/canvas-
|
|
352
|
+
// src/adapters/puck/use-canvas-editing.ts
|
|
359
353
|
import { registerOverlayPortal } from "@puckeditor/core";
|
|
360
354
|
import { useEffect, useRef as useRef2 } from "react";
|
|
355
|
+
var editingControlSelector = "input, textarea, select, button, a[href], [contenteditable]:not([contenteditable=false]), [role=textbox]";
|
|
356
|
+
function useCanvasEditing(active) {
|
|
357
|
+
const ref = useRef2(null);
|
|
358
|
+
useEffect(() => {
|
|
359
|
+
const root = ref.current;
|
|
360
|
+
if (!active || !root) return;
|
|
361
|
+
const cleanupPortal = registerOverlayPortal(root, { disableDragOnFocus: false });
|
|
362
|
+
const protectEditingControl = (event) => {
|
|
363
|
+
const target = event.target;
|
|
364
|
+
const control = typeof target?.closest === "function" ? target.closest(editingControlSelector) : null;
|
|
365
|
+
if (control && root.contains(control)) event.stopPropagation();
|
|
366
|
+
};
|
|
367
|
+
root.addEventListener("pointerdown", protectEditingControl, { capture: true });
|
|
368
|
+
return () => {
|
|
369
|
+
root.removeEventListener("pointerdown", protectEditingControl, { capture: true });
|
|
370
|
+
cleanupPortal?.();
|
|
371
|
+
};
|
|
372
|
+
}, [active]);
|
|
373
|
+
return ref;
|
|
374
|
+
}
|
|
375
|
+
|
|
376
|
+
// src/adapters/puck/canvas-extension-block.tsx
|
|
361
377
|
import { jsx as jsx3 } from "react/jsx-runtime";
|
|
362
|
-
function CanvasExtensionBlock({ active, children, label, onSelect }) {
|
|
363
|
-
const editorRef =
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
378
|
+
function CanvasExtensionBlock({ active, blockId, children, label, onSelect }) {
|
|
379
|
+
const editorRef = useCanvasEditing(active);
|
|
380
|
+
return /* @__PURE__ */ jsx3("div", { ref: editorRef, className: "pb-document-canvas__extension", "data-page-document-block-id": blockId, "aria-label": "Select " + label + " in canvas", role: "group", tabIndex: 0, onClick: onSelect, onKeyDown: (event) => {
|
|
381
|
+
if (event.target === event.currentTarget && (event.key === "Enter" || event.key === " ")) {
|
|
382
|
+
event.preventDefault();
|
|
383
|
+
onSelect();
|
|
384
|
+
}
|
|
367
385
|
}, children });
|
|
368
386
|
}
|
|
369
387
|
|
|
388
|
+
// src/adapters/puck/canvas-core-blocks.tsx
|
|
389
|
+
import { jsx as jsx4, jsxs as jsxs3 } from "react/jsx-runtime";
|
|
390
|
+
function CanvasTextBlock({ id, content, editable, onSelect, onPropsChange }) {
|
|
391
|
+
const ref = useCanvasEditing(editable);
|
|
392
|
+
return /* @__PURE__ */ jsx4("section", { ref, className: "pb-document-canvas__text", "data-page-document-block-id": id, "aria-label": "Select Text in canvas", role: "button", tabIndex: 0, onClick: () => onSelect(id), onKeyDown: (event) => {
|
|
393
|
+
if (event.target === event.currentTarget && (event.key === "Enter" || event.key === " ")) {
|
|
394
|
+
event.preventDefault();
|
|
395
|
+
onSelect(id);
|
|
396
|
+
}
|
|
397
|
+
}, children: /* @__PURE__ */ jsx4("p", { contentEditable: editable, suppressContentEditableWarning: true, onInput: (event) => {
|
|
398
|
+
if (editable) onPropsChange(id, { content: event.currentTarget.textContent ?? "" }, true);
|
|
399
|
+
}, children: content }) });
|
|
400
|
+
}
|
|
401
|
+
function CanvasImageBlock({ id, src, alt, editable, onSelect, onPropsChange }) {
|
|
402
|
+
const ref = useCanvasEditing(editable);
|
|
403
|
+
return /* @__PURE__ */ jsxs3("figure", { ref, className: "pb-document-canvas__image", "data-page-document-block-id": id, "aria-label": "Select Image in canvas", role: "button", tabIndex: 0, onClick: () => onSelect(id), onKeyDown: (event) => {
|
|
404
|
+
if (event.target === event.currentTarget && (event.key === "Enter" || event.key === " ")) {
|
|
405
|
+
event.preventDefault();
|
|
406
|
+
onSelect(id);
|
|
407
|
+
}
|
|
408
|
+
}, children: [
|
|
409
|
+
/* @__PURE__ */ jsx4("img", { src, alt }),
|
|
410
|
+
editable ? /* @__PURE__ */ jsx4("input", { "aria-label": "\u753B\u5E03\u56FE\u7247 URL", value: src, onChange: (event) => onPropsChange(id, { src: event.currentTarget.value }, true), onClick: (event) => event.stopPropagation() }) : null
|
|
411
|
+
] });
|
|
412
|
+
}
|
|
413
|
+
|
|
370
414
|
// src/adapters/puck/page-document-config.tsx
|
|
371
|
-
import { Fragment, jsx as
|
|
415
|
+
import { Fragment, jsx as jsx5, jsxs as jsxs4 } from "react/jsx-runtime";
|
|
372
416
|
function withBlockPermissions(component, type, resolvePermissions) {
|
|
373
417
|
if (!resolvePermissions) return component;
|
|
374
418
|
return {
|
|
@@ -386,11 +430,11 @@ function withBlockPermissions(component, type, resolvePermissions) {
|
|
|
386
430
|
function canvasFieldFallback({ block, props, registry, onPropsChange }) {
|
|
387
431
|
const fields = Object.entries(block.fields);
|
|
388
432
|
if (!fields.length) return null;
|
|
389
|
-
return /* @__PURE__ */
|
|
433
|
+
return /* @__PURE__ */ jsx5("div", { "aria-label": "Edit " + block.label + " values in canvas", onClick: (event) => event.stopPropagation(), style: { display: "grid", gap: 8, marginTop: 12, padding: 12, border: "1px dashed #94a3b8", borderRadius: 6, background: "#f8fafc" }, children: fields.map(([name, field]) => {
|
|
390
434
|
const Field = registry?.getField(field.field)?.component;
|
|
391
|
-
return Field ? /* @__PURE__ */
|
|
435
|
+
return Field ? /* @__PURE__ */ jsxs4("label", { style: { display: "grid", gap: 4, fontSize: 12, fontWeight: 600 }, children: [
|
|
392
436
|
field.label ?? name,
|
|
393
|
-
/* @__PURE__ */
|
|
437
|
+
/* @__PURE__ */ jsx5(Field, { value: props[name], onChange: (value) => onPropsChange({ [name]: value }) })
|
|
394
438
|
] }, name) : null;
|
|
395
439
|
}) });
|
|
396
440
|
}
|
|
@@ -403,8 +447,8 @@ function createPageDocumentPuckConfig(onSelect, onPropsChange, selectedBlockId,
|
|
|
403
447
|
const id = typeof props.id === "string" ? props.id : `unknown-${block.type}`;
|
|
404
448
|
const EditorRenderer = block.render.editor;
|
|
405
449
|
const active = id === selectedBlockId;
|
|
406
|
-
return /* @__PURE__ */
|
|
407
|
-
/* @__PURE__ */
|
|
450
|
+
return /* @__PURE__ */ jsx5(CanvasExtensionBlock, { active, blockId: id, label: block.label, onSelect: () => onSelect(id), children: EditorRenderer ? /* @__PURE__ */ jsx5(EditorRenderer, { ...props, blockId: id, selected: active, onPropsChange: (next) => onPropsChange(id, next) }) : /* @__PURE__ */ jsxs4(Fragment, { children: [
|
|
451
|
+
/* @__PURE__ */ jsx5(BlockRenderer, { ...props }),
|
|
408
452
|
active ? canvasFieldFallback({ block, props, registry, onPropsChange: (next) => onPropsChange(id, next) }) : null
|
|
409
453
|
] }) });
|
|
410
454
|
}
|
|
@@ -417,11 +461,7 @@ function createPageDocumentPuckConfig(onSelect, onPropsChange, selectedBlockId,
|
|
|
417
461
|
const id = typeof props.id === "string" ? props.id : "unknown-text";
|
|
418
462
|
const content = typeof props.content === "string" ? props.content : "";
|
|
419
463
|
const editable = id === selectedBlockId;
|
|
420
|
-
return /* @__PURE__ */
|
|
421
|
-
if (event.key === "Enter" || event.key === " ") onSelect(id);
|
|
422
|
-
}, children: /* @__PURE__ */ jsx4("p", { contentEditable: editable, suppressContentEditableWarning: true, onInput: (event) => {
|
|
423
|
-
if (editable) onPropsChange(id, { content: event.currentTarget.textContent ?? "" }, true);
|
|
424
|
-
}, children: content }) });
|
|
464
|
+
return /* @__PURE__ */ jsx5(CanvasTextBlock, { id, content, editable, onSelect, onPropsChange });
|
|
425
465
|
}
|
|
426
466
|
}, "core.text", resolveBlockPermissions),
|
|
427
467
|
Image: withBlockPermissions({
|
|
@@ -430,12 +470,7 @@ function createPageDocumentPuckConfig(onSelect, onPropsChange, selectedBlockId,
|
|
|
430
470
|
const src = typeof props.src === "string" ? props.src : "";
|
|
431
471
|
const alt = typeof props.alt === "string" ? props.alt : "";
|
|
432
472
|
const editable = id === selectedBlockId;
|
|
433
|
-
return /* @__PURE__ */
|
|
434
|
-
if (event.key === "Enter" || event.key === " ") onSelect(id);
|
|
435
|
-
}, children: [
|
|
436
|
-
/* @__PURE__ */ jsx4("img", { src, alt }),
|
|
437
|
-
editable ? /* @__PURE__ */ jsx4("input", { "aria-label": "\u753B\u5E03\u56FE\u7247 URL", value: src, onChange: (event) => onPropsChange(id, { src: event.currentTarget.value }, true), onClick: (event) => event.stopPropagation() }) : null
|
|
438
|
-
] });
|
|
473
|
+
return /* @__PURE__ */ jsx5(CanvasImageBlock, { id, src, alt, editable, onSelect, onPropsChange });
|
|
439
474
|
}
|
|
440
475
|
}, "core.image", resolveBlockPermissions),
|
|
441
476
|
...extensionComponents
|
|
@@ -454,10 +489,10 @@ function toEngineBlock(block, registry) {
|
|
|
454
489
|
if (!type) throw new Error(`V0.2 \u4E0D\u652F\u6301\u8F6C\u6362\u533A\u5757\u7C7B\u578B\uFF1A${block.type}`);
|
|
455
490
|
return { type, props: { id: block.id, ...block.props } };
|
|
456
491
|
}
|
|
457
|
-
function toEngineData(
|
|
492
|
+
function toEngineData(document2, registry) {
|
|
458
493
|
return {
|
|
459
|
-
root: { props: { ...
|
|
460
|
-
content:
|
|
494
|
+
root: { props: { ...document2.root } },
|
|
495
|
+
content: document2.blocks.map((block) => toEngineBlock(block, registry))
|
|
461
496
|
};
|
|
462
497
|
}
|
|
463
498
|
function fromEngineData(data, base, registry) {
|
|
@@ -544,7 +579,7 @@ function canApplyCanvasDocument(previous, next, getDefinition, policy) {
|
|
|
544
579
|
}
|
|
545
580
|
|
|
546
581
|
// src/editor/context/EditorContext.tsx
|
|
547
|
-
import { jsx as
|
|
582
|
+
import { jsx as jsx6 } from "react/jsx-runtime";
|
|
548
583
|
function historyReducer(state, action) {
|
|
549
584
|
if (action.type === "select") return { ...state, selectedBlockId: action.id };
|
|
550
585
|
if (action.type === "device") return { ...state, device: action.device };
|
|
@@ -577,7 +612,7 @@ function defaultBlock(type, blocks, registry) {
|
|
|
577
612
|
return { id: uniqueBlockId(type, blocks), type, version: definition.version, props: definition.defaultProps, variant: definition.defaultVariant ?? "default", style: {} };
|
|
578
613
|
}
|
|
579
614
|
function EditorProvider({ initialDocument, registry, policy, loadState = "ready", sessionState = "active", session, sessionMessage, leaveWarning = "You have unsaved changes.", onDocumentChange, children }) {
|
|
580
|
-
const [history, dispatch] = useReducer(historyReducer, initialDocument, (
|
|
615
|
+
const [history, dispatch] = useReducer(historyReducer, initialDocument, (document2) => ({ document: document2, selectedBlockId: document2.blocks[0]?.id ?? null, past: [], future: [], device: "desktop", savedDocument: document2 }));
|
|
581
616
|
const historyRef = useRef3(history);
|
|
582
617
|
useEffect2(() => {
|
|
583
618
|
historyRef.current = history;
|
|
@@ -587,7 +622,7 @@ function EditorProvider({ initialDocument, registry, policy, loadState = "ready"
|
|
|
587
622
|
const editable = (loadState === "ready" || loadState === "success") && sessionState === "active";
|
|
588
623
|
const selectedBlock = history.document.blocks.find((block) => block.id === history.selectedBlockId) ?? null;
|
|
589
624
|
const pendingDeleteBlock = history.document.blocks.find((block) => block.id === pendingDeleteBlockId) ?? null;
|
|
590
|
-
const replace = useCallback((
|
|
625
|
+
const replace = useCallback((document2, selectedBlockId) => dispatch({ type: "replace", document: document2, selectedBlockId }), []);
|
|
591
626
|
const requestCanvasSelection = useCallback((id) => {
|
|
592
627
|
if (editable) setCanvasSelectionRequest(id);
|
|
593
628
|
}, [editable]);
|
|
@@ -595,11 +630,11 @@ function EditorProvider({ initialDocument, registry, policy, loadState = "ready"
|
|
|
595
630
|
setCanvasSelectionRequest(null);
|
|
596
631
|
dispatch({ type: "select", id });
|
|
597
632
|
}, []);
|
|
598
|
-
const updateFromCanvas = useCallback((
|
|
633
|
+
const updateFromCanvas = useCallback((document2) => {
|
|
599
634
|
const current = historyRef.current;
|
|
600
|
-
if (!editable || JSON.stringify(
|
|
601
|
-
if (!canApplyCanvasDocument(current.document,
|
|
602
|
-
replace(
|
|
635
|
+
if (!editable || JSON.stringify(document2) === JSON.stringify(current.document)) return false;
|
|
636
|
+
if (!canApplyCanvasDocument(current.document, document2, (type) => registry?.getBlock(type), policy)) return false;
|
|
637
|
+
replace(document2, current.selectedBlockId);
|
|
603
638
|
return true;
|
|
604
639
|
}, [editable, policy, registry, replace]);
|
|
605
640
|
const updateBlockProps = useCallback((id, props) => {
|
|
@@ -724,11 +759,17 @@ function EditorProvider({ initialDocument, registry, policy, loadState = "ready"
|
|
|
724
759
|
reorderBlock: (id, beforeId) => {
|
|
725
760
|
if (!editable || id === beforeId) return;
|
|
726
761
|
const source = history.document.blocks.find((block) => block.id === id);
|
|
762
|
+
if (!source || !canDragBlock(source, registry?.getBlock(source.type), policy)) return;
|
|
727
763
|
const withoutSource = history.document.blocks.filter((block) => block.id !== id);
|
|
728
|
-
const targetIndex = withoutSource.findIndex((block) => block.id === beforeId);
|
|
729
|
-
if (!source || targetIndex < 0 || !canDragBlock(source, registry?.getBlock(source.type), policy)) return;
|
|
730
764
|
const blocks = [...withoutSource];
|
|
731
|
-
|
|
765
|
+
if (beforeId) {
|
|
766
|
+
const targetIndex = withoutSource.findIndex((block) => block.id === beforeId);
|
|
767
|
+
if (targetIndex < 0) return;
|
|
768
|
+
blocks.splice(targetIndex, 0, source);
|
|
769
|
+
} else {
|
|
770
|
+
blocks.push(source);
|
|
771
|
+
}
|
|
772
|
+
if (blocks.every((block, index) => block.id === history.document.blocks[index]?.id)) return;
|
|
732
773
|
replace({ ...history.document, blocks }, id);
|
|
733
774
|
},
|
|
734
775
|
updateBlockProps,
|
|
@@ -755,10 +796,10 @@ function EditorProvider({ initialDocument, registry, policy, loadState = "ready"
|
|
|
755
796
|
redo: () => {
|
|
756
797
|
if (editable) dispatch({ type: "redo" });
|
|
757
798
|
},
|
|
758
|
-
markSaved: (
|
|
799
|
+
markSaved: (document2 = historyRef.current.document) => dispatch({ type: "saved", document: document2 })
|
|
759
800
|
};
|
|
760
801
|
}, [canvasSelectionRequest, confirmCanvasSelection, editable, history, isDirty, loadState, pendingDeleteBlock, pendingDeleteBlockId, policy, registry, replace, requestCanvasSelection, selectedBlock, session, sessionMessage, sessionState, updateBlockPresentation, updateBlockProps, updateFromCanvas]);
|
|
761
|
-
return /* @__PURE__ */
|
|
802
|
+
return /* @__PURE__ */ jsx6(EditorContext.Provider, { value, children });
|
|
762
803
|
}
|
|
763
804
|
function useEditorContext() {
|
|
764
805
|
const context = useContext(EditorContext);
|
|
@@ -768,18 +809,18 @@ function useEditorContext() {
|
|
|
768
809
|
|
|
769
810
|
// src/editor/components/PageStatusCard.tsx
|
|
770
811
|
import { Badge as Badge2, InlineStack as InlineStack2, Text as Text2 } from "@shopify/polaris";
|
|
771
|
-
import { jsx as
|
|
812
|
+
import { jsx as jsx7, jsxs as jsxs5 } from "react/jsx-runtime";
|
|
772
813
|
function PageStatusCard({ status, sessionState }) {
|
|
773
814
|
const publicationTone = status.publicationStatus === "published" ? "success" : "attention";
|
|
774
815
|
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;
|
|
775
|
-
return /* @__PURE__ */
|
|
776
|
-
/* @__PURE__ */
|
|
777
|
-
/* @__PURE__ */
|
|
778
|
-
status.draftLabel ? /* @__PURE__ */
|
|
779
|
-
status.publishedVersionLabel ? /* @__PURE__ */
|
|
780
|
-
sessionLabel ? /* @__PURE__ */
|
|
816
|
+
return /* @__PURE__ */ jsxs5("div", { className: "pb-page-status-card", "data-testid": "page-status-card", "data-publication-status": status.publicationStatus, "data-session-state": sessionState, children: [
|
|
817
|
+
/* @__PURE__ */ jsxs5(InlineStack2, { gap: "150", blockAlign: "center", wrap: true, children: [
|
|
818
|
+
/* @__PURE__ */ jsx7(Badge2, { tone: publicationTone, children: status.publicationStatus === "published" ? "\u7EBF\u4E0A" : "\u672A\u53D1\u5E03" }),
|
|
819
|
+
status.draftLabel ? /* @__PURE__ */ jsx7(Text2, { as: "span", variant: "bodySm", tone: "subdued", children: status.draftLabel }) : null,
|
|
820
|
+
status.publishedVersionLabel ? /* @__PURE__ */ jsx7(Text2, { as: "span", variant: "bodySm", tone: "subdued", children: status.publishedVersionLabel }) : null,
|
|
821
|
+
sessionLabel ? /* @__PURE__ */ jsx7(Badge2, { tone: sessionState === "lost" ? "critical" : "attention", children: sessionLabel }) : null
|
|
781
822
|
] }),
|
|
782
|
-
status.lastSavedAt ? /* @__PURE__ */
|
|
823
|
+
status.lastSavedAt ? /* @__PURE__ */ jsxs5(Text2, { as: "p", variant: "bodySm", tone: "subdued", children: [
|
|
783
824
|
"\u6700\u540E\u4FDD\u5B58\uFF1A",
|
|
784
825
|
status.lastSavedAt
|
|
785
826
|
] }) : null
|
|
@@ -924,17 +965,220 @@ function createAdminI18n(locale) {
|
|
|
924
965
|
return { locale: resolvedLocale, t: (key) => messages[resolvedLocale][key] };
|
|
925
966
|
}
|
|
926
967
|
|
|
968
|
+
// src/editor/shell/CanvasLibraryDropTarget.tsx
|
|
969
|
+
import { useEffect as useEffect3, useRef as useRef4, useState as useState3 } from "react";
|
|
970
|
+
|
|
927
971
|
// src/editor/shell/drop-position.ts
|
|
928
972
|
function nearestBlockIdAtY(blocks, y) {
|
|
929
973
|
return blocks.find((block) => y < block.top + block.height / 2)?.id;
|
|
930
974
|
}
|
|
931
|
-
function
|
|
932
|
-
const
|
|
933
|
-
|
|
975
|
+
function libraryTypesInDocumentOrder(blockTypes, blocks) {
|
|
976
|
+
const allowed = new Set(blockTypes);
|
|
977
|
+
const seen = /* @__PURE__ */ new Set();
|
|
978
|
+
const ordered = [];
|
|
979
|
+
for (const block of blocks) {
|
|
980
|
+
if (!allowed.has(block.type) || seen.has(block.type)) continue;
|
|
981
|
+
ordered.push(block.type);
|
|
982
|
+
seen.add(block.type);
|
|
983
|
+
}
|
|
984
|
+
for (const type of blockTypes) {
|
|
985
|
+
if (!seen.has(type)) ordered.push(type);
|
|
986
|
+
}
|
|
987
|
+
return ordered;
|
|
988
|
+
}
|
|
989
|
+
function dropPlacement(clientY, top, height) {
|
|
990
|
+
if (height <= 0) return "before";
|
|
991
|
+
return clientY < top + height / 2 ? "before" : "after";
|
|
992
|
+
}
|
|
993
|
+
function beforeIdAfterPlacement(blockIds, targetId, placement) {
|
|
994
|
+
if (placement === "before") return targetId;
|
|
995
|
+
const index = blockIds.indexOf(targetId);
|
|
996
|
+
return index < 0 ? targetId : blockIds[index + 1];
|
|
997
|
+
}
|
|
998
|
+
|
|
999
|
+
// src/editor/shell/CanvasLibraryDropTarget.tsx
|
|
1000
|
+
import { jsx as jsx8, jsxs as jsxs6 } from "react/jsx-runtime";
|
|
1001
|
+
function uniqueBlocks(blocks) {
|
|
1002
|
+
const seen = /* @__PURE__ */ new Set();
|
|
1003
|
+
return blocks.filter((block) => !seen.has(block.id) && seen.add(block.id));
|
|
1004
|
+
}
|
|
1005
|
+
function scrollableAncestors(start) {
|
|
1006
|
+
const result = [];
|
|
1007
|
+
let node = start;
|
|
1008
|
+
while (node) {
|
|
1009
|
+
const style = window.getComputedStyle(node);
|
|
1010
|
+
if (["auto", "scroll", "overlay"].includes(style.overflowY) && node.scrollHeight > node.clientHeight) result.push(node);
|
|
1011
|
+
node = node.parentElement;
|
|
1012
|
+
}
|
|
1013
|
+
return result;
|
|
1014
|
+
}
|
|
1015
|
+
function scrollDelta(pointerY, rect, elapsedMs) {
|
|
1016
|
+
const top = Math.max(0, rect.top);
|
|
1017
|
+
const bottom = Math.min(window.innerHeight, rect.bottom);
|
|
1018
|
+
const height = bottom - top;
|
|
1019
|
+
if (height <= 0 || pointerY < top || pointerY > bottom) return 0;
|
|
1020
|
+
const edge = Math.min(96, Math.max(36, height * 0.24));
|
|
1021
|
+
const speed = 900;
|
|
1022
|
+
if (pointerY < top + edge) return -speed * Math.min(1, (top + edge - pointerY) / edge) * elapsedMs / 1e3;
|
|
1023
|
+
if (pointerY > bottom - edge) return speed * Math.min(1, (pointerY - (bottom - edge)) / edge) * elapsedMs / 1e3;
|
|
1024
|
+
return 0;
|
|
1025
|
+
}
|
|
1026
|
+
function scrollElement(element, delta) {
|
|
1027
|
+
const canScroll = delta < 0 ? element.scrollTop > 0 : element.scrollTop < element.scrollHeight - element.clientHeight;
|
|
1028
|
+
if (!delta || !canScroll) return false;
|
|
1029
|
+
if (typeof element.scrollBy === "function") element.scrollBy({ top: delta, behavior: "auto" });
|
|
1030
|
+
else element.scrollTop += delta;
|
|
1031
|
+
return true;
|
|
1032
|
+
}
|
|
1033
|
+
function CanvasLibraryDropTarget({ frameRef, blocks, label, onDrop, onCancel, adminLocale }) {
|
|
1034
|
+
const targetRef = useRef4(null);
|
|
1035
|
+
const latestPreview = useRef4(null);
|
|
1036
|
+
const dragging = useRef4(false);
|
|
1037
|
+
const completed = useRef4(false);
|
|
1038
|
+
const pointerY = useRef4(0);
|
|
1039
|
+
const animationFrame = useRef4(null);
|
|
1040
|
+
const lastFrameTime = useRef4(null);
|
|
1041
|
+
const callbacks = useRef4({ onDrop, onCancel });
|
|
1042
|
+
useEffect3(() => {
|
|
1043
|
+
callbacks.current = { onDrop, onCancel };
|
|
1044
|
+
}, [onDrop, onCancel]);
|
|
1045
|
+
const orderedBlocks = uniqueBlocks(blocks);
|
|
1046
|
+
const [preview, setPreview] = useState3(null);
|
|
1047
|
+
const english = adminLocale?.toLowerCase().startsWith("en") ?? false;
|
|
1048
|
+
const stopAutoScroll = () => {
|
|
1049
|
+
if (animationFrame.current !== null) window.cancelAnimationFrame(animationFrame.current);
|
|
1050
|
+
animationFrame.current = null;
|
|
1051
|
+
lastFrameTime.current = null;
|
|
1052
|
+
};
|
|
1053
|
+
const clear = (cancel) => {
|
|
1054
|
+
stopAutoScroll();
|
|
1055
|
+
dragging.current = false;
|
|
1056
|
+
latestPreview.current = null;
|
|
1057
|
+
setPreview(null);
|
|
1058
|
+
if (cancel) {
|
|
1059
|
+
completed.current = true;
|
|
1060
|
+
callbacks.current.onCancel();
|
|
1061
|
+
}
|
|
1062
|
+
};
|
|
1063
|
+
const calculatePreview = (clientY) => {
|
|
1064
|
+
const target = targetRef.current;
|
|
1065
|
+
const frame = frameRef.current;
|
|
1066
|
+
if (!target || !frame) return null;
|
|
1067
|
+
const targetRect = target.getBoundingClientRect();
|
|
1068
|
+
const frameRect = frame.getBoundingClientRect();
|
|
1069
|
+
const iframe = frame.querySelector("iframe");
|
|
1070
|
+
const iframeDocument = iframe?.contentDocument;
|
|
1071
|
+
const root = iframeDocument ?? frame;
|
|
1072
|
+
const allowed = new Set(orderedBlocks.map((block) => block.id));
|
|
1073
|
+
const byId = /* @__PURE__ */ new Map();
|
|
1074
|
+
const iframeRect = iframeDocument ? iframe?.getBoundingClientRect() : void 0;
|
|
1075
|
+
const scaleY = iframe && iframeRect && iframeRect.height > 0 && iframe.clientHeight > 0 ? iframeRect.height / iframe.clientHeight : 1;
|
|
1076
|
+
const elements = Array.from(root.querySelectorAll("[data-page-document-block-id], [data-puck-dnd]"));
|
|
1077
|
+
for (const element of elements) {
|
|
1078
|
+
const id = element.dataset.pageDocumentBlockId ?? element.dataset.puckDnd;
|
|
1079
|
+
if (!id || !allowed.has(id) || byId.has(id) || element.closest('[aria-hidden="true"], [class*="DragOverlay"]')) continue;
|
|
1080
|
+
const rect = element.getBoundingClientRect();
|
|
1081
|
+
byId.set(id, { id, top: iframeRect ? iframeRect.top + rect.top * scaleY : rect.top, height: iframeRect ? rect.height * scaleY : rect.height });
|
|
1082
|
+
}
|
|
1083
|
+
const candidates = orderedBlocks.flatMap((block) => byId.get(block.id) ?? []);
|
|
1084
|
+
const beforeId = nearestBlockIdAtY(candidates, clientY);
|
|
1085
|
+
const markerCandidate = beforeId ? candidates.find((candidate) => candidate.id === beforeId) : candidates.at(-1);
|
|
1086
|
+
const markerViewportTop = markerCandidate ? beforeId ? markerCandidate.top : markerCandidate.top + markerCandidate.height : Math.min(frameRect.bottom, Math.max(frameRect.top, clientY));
|
|
1087
|
+
return { beforeId, markerTop: Math.max(0, markerViewportTop - targetRect.top), markerLeft: Math.max(0, frameRect.left - targetRect.left), markerWidth: frameRect.width };
|
|
1088
|
+
};
|
|
1089
|
+
const updatePreview = (clientY) => {
|
|
1090
|
+
pointerY.current = clientY;
|
|
1091
|
+
const next = calculatePreview(clientY);
|
|
1092
|
+
const previous = latestPreview.current;
|
|
1093
|
+
latestPreview.current = next;
|
|
1094
|
+
if (previous?.beforeId !== next?.beforeId || previous?.markerTop !== next?.markerTop || previous?.markerLeft !== next?.markerLeft || previous?.markerWidth !== next?.markerWidth) setPreview(next);
|
|
1095
|
+
};
|
|
1096
|
+
const autoScroll = (timestamp) => {
|
|
1097
|
+
if (!dragging.current) return;
|
|
1098
|
+
const elapsedMs = Math.min(64, Math.max(0, timestamp - (lastFrameTime.current ?? timestamp)));
|
|
1099
|
+
lastFrameTime.current = timestamp;
|
|
1100
|
+
const stage = targetRef.current?.parentElement;
|
|
1101
|
+
if (stage) {
|
|
1102
|
+
let scrolled = false;
|
|
1103
|
+
for (const ancestor of scrollableAncestors(stage)) {
|
|
1104
|
+
const delta = scrollDelta(pointerY.current, ancestor.getBoundingClientRect(), elapsedMs);
|
|
1105
|
+
if (scrollElement(ancestor, delta)) {
|
|
1106
|
+
scrolled = true;
|
|
1107
|
+
break;
|
|
1108
|
+
}
|
|
1109
|
+
}
|
|
1110
|
+
const documentScroller = document.scrollingElement;
|
|
1111
|
+
if (!scrolled && documentScroller) {
|
|
1112
|
+
const viewport = new DOMRect(0, 0, window.innerWidth, window.innerHeight);
|
|
1113
|
+
scrollElement(documentScroller, scrollDelta(pointerY.current, viewport, elapsedMs));
|
|
1114
|
+
}
|
|
1115
|
+
updatePreview(pointerY.current);
|
|
1116
|
+
}
|
|
1117
|
+
animationFrame.current = window.requestAnimationFrame(autoScroll);
|
|
1118
|
+
};
|
|
1119
|
+
const startAutoScroll = () => {
|
|
1120
|
+
if (animationFrame.current === null) animationFrame.current = window.requestAnimationFrame(autoScroll);
|
|
1121
|
+
};
|
|
1122
|
+
useEffect3(() => {
|
|
1123
|
+
const cancelOutside = (event) => {
|
|
1124
|
+
if (event.type === "drop" && targetRef.current?.contains(event.target)) return;
|
|
1125
|
+
if (!completed.current) clear(true);
|
|
1126
|
+
};
|
|
1127
|
+
const onKeyDown = (event) => {
|
|
1128
|
+
if (event.key === "Escape" && !completed.current) clear(true);
|
|
1129
|
+
};
|
|
1130
|
+
document.addEventListener("keydown", onKeyDown);
|
|
1131
|
+
document.addEventListener("dragend", cancelOutside, true);
|
|
1132
|
+
document.addEventListener("drop", cancelOutside, true);
|
|
1133
|
+
return () => {
|
|
1134
|
+
document.removeEventListener("keydown", onKeyDown);
|
|
1135
|
+
document.removeEventListener("dragend", cancelOutside, true);
|
|
1136
|
+
document.removeEventListener("drop", cancelOutside, true);
|
|
1137
|
+
stopAutoScroll();
|
|
1138
|
+
};
|
|
1139
|
+
}, []);
|
|
1140
|
+
const handleDragOver = (event) => {
|
|
1141
|
+
event.preventDefault();
|
|
1142
|
+
event.stopPropagation();
|
|
1143
|
+
event.dataTransfer.dropEffect = "copy";
|
|
1144
|
+
completed.current = false;
|
|
1145
|
+
dragging.current = true;
|
|
1146
|
+
updatePreview(event.clientY);
|
|
1147
|
+
startAutoScroll();
|
|
1148
|
+
};
|
|
1149
|
+
const handleDragLeave = (event) => {
|
|
1150
|
+
if (!event.relatedTarget || !event.currentTarget.contains(event.relatedTarget)) clear(false);
|
|
1151
|
+
};
|
|
1152
|
+
const handleDrop = (event) => {
|
|
1153
|
+
event.preventDefault();
|
|
1154
|
+
event.stopPropagation();
|
|
1155
|
+
const next = latestPreview.current ?? calculatePreview(event.clientY);
|
|
1156
|
+
completed.current = true;
|
|
1157
|
+
clear(false);
|
|
1158
|
+
callbacks.current.onDrop(next?.beforeId);
|
|
1159
|
+
};
|
|
1160
|
+
const position = preview?.beforeId ? orderedBlocks.findIndex((block) => block.id === preview.beforeId) + 1 : orderedBlocks.length + 1;
|
|
1161
|
+
const hint = english ? `Release to add ${label}${preview ? ` \xB7 position ${position}` : ""}` : `\u677E\u5F00\u4EE5\u6DFB\u52A0 ${label}${preview ? ` \xB7 \u7B2C ${position} \u4E2A\u4F4D\u7F6E` : ""}`;
|
|
1162
|
+
const style = { position: "absolute", inset: 0, zIndex: 2 };
|
|
1163
|
+
const markerLabel = english ? `Position ${position}` : `\u7B2C ${position} \u4E2A\u4F4D\u7F6E`;
|
|
1164
|
+
return /* @__PURE__ */ jsxs6("div", { ref: targetRef, className: "pb-canvas-drop-target", "data-testid": "canvas-drop-target", role: "region", "aria-label": english ? "Block drop area" : "\u533A\u5757\u6295\u653E\u533A", style, onDragOver: handleDragOver, onDragLeave: handleDragLeave, onDrop: handleDrop, children: [
|
|
1165
|
+
/* @__PURE__ */ jsx8("span", { className: "pb-canvas-drop-target__hint", "aria-live": "polite", children: hint }),
|
|
1166
|
+
preview ? /* @__PURE__ */ jsx8("span", { className: "pb-canvas-drop-marker", "aria-hidden": "true", style: { top: preview.markerTop, left: preview.markerLeft, width: preview.markerWidth }, children: /* @__PURE__ */ jsx8("span", { className: "pb-canvas-drop-marker__label", children: markerLabel }) }) : null
|
|
1167
|
+
] });
|
|
934
1168
|
}
|
|
935
1169
|
|
|
936
1170
|
// src/editor/shell/PageDocumentEditorShell.tsx
|
|
937
|
-
import { Fragment as Fragment2, jsx as
|
|
1171
|
+
import { Fragment as Fragment2, jsx as jsx9, jsxs as jsxs7 } from "react/jsx-runtime";
|
|
1172
|
+
function scrollCanvasBlockIntoView(blockId, frame) {
|
|
1173
|
+
const selector = `[data-page-document-block-id="${CSS.escape(blockId)}"]`;
|
|
1174
|
+
const scroll = () => {
|
|
1175
|
+
const iframe = frame?.querySelector("iframe");
|
|
1176
|
+
const element = iframe?.contentDocument?.querySelector(selector) ?? document.querySelector(selector);
|
|
1177
|
+
element?.scrollIntoView({ block: "start", inline: "nearest" });
|
|
1178
|
+
};
|
|
1179
|
+
if (typeof requestAnimationFrame === "function") requestAnimationFrame(scroll);
|
|
1180
|
+
else scroll();
|
|
1181
|
+
}
|
|
938
1182
|
var deviceLabels2 = { desktop: "desktop", tablet: "tablet", mobile: "mobile" };
|
|
939
1183
|
function blockLabel(block, registry) {
|
|
940
1184
|
return blockTypeLabel(block.type, registry);
|
|
@@ -944,12 +1188,12 @@ function blockTypeLabel(type, registry) {
|
|
|
944
1188
|
if (type === "core.image") return "\u56FE\u7247";
|
|
945
1189
|
return registry?.getBlock(type)?.label ?? type;
|
|
946
1190
|
}
|
|
947
|
-
function validateDocumentBlocks(
|
|
948
|
-
return registry ? validatePageDocumentWithRegistry(
|
|
1191
|
+
function validateDocumentBlocks(document2, registry) {
|
|
1192
|
+
return registry ? validatePageDocumentWithRegistry(document2, registry) : [];
|
|
949
1193
|
}
|
|
950
1194
|
function useEditorSession(adapter, pageId) {
|
|
951
|
-
const [managed, setManaged] =
|
|
952
|
-
|
|
1195
|
+
const [managed, setManaged] = useState4(() => adapter ? { state: "acquiring" } : { state: "active" });
|
|
1196
|
+
useEffect4(() => {
|
|
953
1197
|
let cancelled = false;
|
|
954
1198
|
let session;
|
|
955
1199
|
let heartbeatTimer;
|
|
@@ -991,31 +1235,34 @@ function useEditorSession(adapter, pageId) {
|
|
|
991
1235
|
function PageDocumentEditorShell(props) {
|
|
992
1236
|
const { sessionAdapter, initialDocument, onSessionStateChange } = props;
|
|
993
1237
|
const managedSession = useEditorSession(sessionAdapter, initialDocument.pageId);
|
|
994
|
-
|
|
1238
|
+
useEffect4(() => {
|
|
995
1239
|
onSessionStateChange?.(managedSession.state);
|
|
996
1240
|
}, [managedSession.state, onSessionStateChange]);
|
|
997
|
-
return /* @__PURE__ */
|
|
1241
|
+
return /* @__PURE__ */ jsx9(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__ */ jsx9(PageDocumentEditor, { ...props }) });
|
|
998
1242
|
}
|
|
999
1243
|
function PageDocumentEditor({ iframe = false, registry, adminLocale, onSave, onPublish, draftPersistence, draftRevision: initialDraftRevision, autoSave = true, autoSaveDelayMs = 800, publishAction, assetPicker, inspectorSettings, productPicker, pageStatus, onBack, onHistory, onPreview, onAddToStore, deleteConfirmation, availableBlockTypes, appearanceControls = false }) {
|
|
1000
1244
|
const editor = useEditorContext();
|
|
1001
|
-
const editorRef =
|
|
1245
|
+
const editorRef = useRef5(editor);
|
|
1002
1246
|
useLayoutEffect(() => {
|
|
1003
1247
|
editorRef.current = editor;
|
|
1004
1248
|
}, [editor]);
|
|
1005
|
-
const [blockView, setBlockView] =
|
|
1006
|
-
const [leftRailOpen, setLeftRailOpen] =
|
|
1007
|
-
const [rightPanelOpen, setRightPanelOpen] =
|
|
1008
|
-
const [draggingLibraryType, setDraggingLibraryType] =
|
|
1009
|
-
const
|
|
1010
|
-
const
|
|
1011
|
-
const [
|
|
1012
|
-
const
|
|
1013
|
-
const [
|
|
1014
|
-
const [
|
|
1015
|
-
const [
|
|
1016
|
-
const [
|
|
1017
|
-
const [
|
|
1018
|
-
const [
|
|
1249
|
+
const [blockView, setBlockView] = useState4("blocks");
|
|
1250
|
+
const [leftRailOpen, setLeftRailOpen] = useState4(true);
|
|
1251
|
+
const [rightPanelOpen, setRightPanelOpen] = useState4(true);
|
|
1252
|
+
const [draggingLibraryType, setDraggingLibraryType] = useState4(null);
|
|
1253
|
+
const [draggingBlockId, setDraggingBlockId] = useState4(null);
|
|
1254
|
+
const draggingBlockIdRef = useRef5(null);
|
|
1255
|
+
const [dropTarget, setDropTarget] = useState4(null);
|
|
1256
|
+
const canvasFrameRef = useRef5(null);
|
|
1257
|
+
const [canvasMutationVersion, setCanvasMutationVersion] = useState4(0);
|
|
1258
|
+
const [canvasResetVersion, setCanvasResetVersion] = useState4(0);
|
|
1259
|
+
const [request, setRequest] = useState4("idle");
|
|
1260
|
+
const [notice, setNotice] = useState4(null);
|
|
1261
|
+
const [draftRevision, setDraftRevision] = useState4(initialDraftRevision);
|
|
1262
|
+
const [isOnline, setIsOnline] = useState4(() => typeof navigator === "undefined" || navigator.onLine);
|
|
1263
|
+
const [saveState, setSaveState] = useState4("saved");
|
|
1264
|
+
const [zoom, setZoom] = useState4("auto");
|
|
1265
|
+
const [confirmBack, setConfirmBack] = useState4(false);
|
|
1019
1266
|
const i18n = createAdminI18n(adminLocale);
|
|
1020
1267
|
const engineData = useMemo2(() => toEngineData(editor.document, registry), [editor.document, registry]);
|
|
1021
1268
|
const canvasThemeStyle = useMemo2(() => {
|
|
@@ -1036,7 +1283,7 @@ function PageDocumentEditor({ iframe = false, registry, adminLocale, onSave, onP
|
|
|
1036
1283
|
insert: editorRef.current.canAddBlock(type)
|
|
1037
1284
|
}), []);
|
|
1038
1285
|
const config = useMemo2(() => createPageDocumentPuckConfig(confirmCanvasSelection, updateFromCanvasInput, selectedBlockId, registry, resolveBlockPermissions), [confirmCanvasSelection, registry, resolveBlockPermissions, selectedBlockId, updateFromCanvasInput]);
|
|
1039
|
-
|
|
1286
|
+
useEffect4(() => {
|
|
1040
1287
|
const online = () => setIsOnline(true);
|
|
1041
1288
|
const offline = () => setIsOnline(false);
|
|
1042
1289
|
window.addEventListener("online", online);
|
|
@@ -1054,14 +1301,14 @@ function PageDocumentEditor({ iframe = false, registry, adminLocale, onSave, onP
|
|
|
1054
1301
|
setSaveState("offline");
|
|
1055
1302
|
return;
|
|
1056
1303
|
}
|
|
1057
|
-
const
|
|
1304
|
+
const document2 = editor.document;
|
|
1058
1305
|
setRequest("saving");
|
|
1059
1306
|
setSaveState("saving");
|
|
1060
1307
|
setNotice(null);
|
|
1061
1308
|
try {
|
|
1062
|
-
const result = draftPersistence ? await draftPersistence.saveDraft({ document, expectedRevision: draftRevision, session: editor.session }) : await onSave?.(
|
|
1309
|
+
const result = draftPersistence ? await draftPersistence.saveDraft({ document: document2, expectedRevision: draftRevision, session: editor.session }) : await onSave?.(document2);
|
|
1063
1310
|
if (result?.revision !== void 0) setDraftRevision(result.revision);
|
|
1064
|
-
editor.markSaved(
|
|
1311
|
+
editor.markSaved(document2);
|
|
1065
1312
|
setSaveState("saved");
|
|
1066
1313
|
} catch {
|
|
1067
1314
|
setNotice("saveFailed");
|
|
@@ -1070,7 +1317,7 @@ function PageDocumentEditor({ iframe = false, registry, adminLocale, onSave, onP
|
|
|
1070
1317
|
setRequest("idle");
|
|
1071
1318
|
}
|
|
1072
1319
|
}, [canPersistDraft, draftPersistence, draftRevision, editor, isOnline, onSave, request, validationIssues.length]);
|
|
1073
|
-
|
|
1320
|
+
useEffect4(() => {
|
|
1074
1321
|
if (!autoSave || !canPersistDraft || !editor.isDirty || resolvedSaveState !== "dirty" && resolvedSaveState !== "failed" || !isOnline || request !== "idle" || validationIssues.length > 0 || editor.sessionState !== "active") return;
|
|
1075
1322
|
const timer = window.setTimeout(() => {
|
|
1076
1323
|
void save();
|
|
@@ -1079,13 +1326,13 @@ function PageDocumentEditor({ iframe = false, registry, adminLocale, onSave, onP
|
|
|
1079
1326
|
}, [autoSave, autoSaveDelayMs, canPersistDraft, editor.isDirty, editor.sessionState, isOnline, request, resolvedSaveState, save, validationIssues.length]);
|
|
1080
1327
|
const publish = async () => {
|
|
1081
1328
|
if (!publishAction && !onPublish || request !== "idle" || validationIssues.length > 0 || !isOnline) return;
|
|
1082
|
-
const
|
|
1329
|
+
const document2 = editor.document;
|
|
1083
1330
|
setRequest("publishing");
|
|
1084
1331
|
setNotice(null);
|
|
1085
1332
|
try {
|
|
1086
|
-
if (publishAction) await publishAction.publish({ document, expectedRevision: draftRevision, session: editor.session, validationIssues });
|
|
1087
|
-
else await onPublish?.(
|
|
1088
|
-
editor.markSaved(
|
|
1333
|
+
if (publishAction) await publishAction.publish({ document: document2, expectedRevision: draftRevision, session: editor.session, validationIssues });
|
|
1334
|
+
else await onPublish?.(document2);
|
|
1335
|
+
editor.markSaved(document2);
|
|
1089
1336
|
setSaveState("saved");
|
|
1090
1337
|
setNotice("published");
|
|
1091
1338
|
} catch {
|
|
@@ -1094,44 +1341,31 @@ function PageDocumentEditor({ iframe = false, registry, adminLocale, onSave, onP
|
|
|
1094
1341
|
setRequest("idle");
|
|
1095
1342
|
}
|
|
1096
1343
|
};
|
|
1097
|
-
if (editor.loadState !== "ready" && editor.loadState !== "success") return /* @__PURE__ */
|
|
1098
|
-
if (editor.sessionState !== "active") return /* @__PURE__ */
|
|
1344
|
+
if (editor.loadState !== "ready" && editor.loadState !== "success") return /* @__PURE__ */ jsx9(EditorStatus, { state: editor.loadState });
|
|
1345
|
+
if (editor.sessionState !== "active") return /* @__PURE__ */ jsx9(EditorSessionStatus, { state: editor.sessionState, message: editor.sessionMessage });
|
|
1099
1346
|
const allBlockTypes = ["core.text", "core.image", ...registry?.blocks.map((block) => block.type) ?? []];
|
|
1100
1347
|
const blockTypes = availableBlockTypes ? allBlockTypes.filter((type) => availableBlockTypes.includes(type)) : allBlockTypes;
|
|
1348
|
+
const orderedBlockTypes = libraryTypesInDocumentOrder(blockTypes, editor.document.blocks);
|
|
1101
1349
|
const addFromLibrary = (type, beforeId) => {
|
|
1102
1350
|
const id = editor.addBlock(type, beforeId);
|
|
1103
1351
|
if (id) editor.requestCanvasSelection(id);
|
|
1104
1352
|
};
|
|
1105
|
-
const
|
|
1106
|
-
|
|
1107
|
-
if (!frame) return void 0;
|
|
1108
|
-
const iframe2 = frame.querySelector("iframe");
|
|
1109
|
-
const root = iframe2?.contentDocument ?? frame;
|
|
1110
|
-
const offsetTop = iframe2?.getBoundingClientRect().top ?? 0;
|
|
1111
|
-
const elements = Array.from(root.querySelectorAll("[data-page-document-block-id]"));
|
|
1112
|
-
const puckElements = elements.length > 0 ? elements : Array.from(root.querySelectorAll("[data-puck-dnd]"));
|
|
1113
|
-
const blockElements = puckElements.length > 0 ? puckElements : Array.from(window.document.querySelectorAll("[data-page-document-block-id], [data-puck-dnd]"));
|
|
1114
|
-
const candidates = blockElements.map((element) => ({
|
|
1115
|
-
id: element.dataset.pageDocumentBlockId ?? element.dataset.puckDnd,
|
|
1116
|
-
top: element.getBoundingClientRect().top,
|
|
1117
|
-
height: element.getBoundingClientRect().height
|
|
1118
|
-
})).filter((item) => typeof item.id === "string");
|
|
1119
|
-
const nearestId = nearestBlockIdAtY(candidates, clientY - offsetTop);
|
|
1120
|
-
if (nearestId || candidates.length > 0) return nearestId;
|
|
1121
|
-
const rect = frame.getBoundingClientRect();
|
|
1122
|
-
if (rect.height <= 0) return void 0;
|
|
1123
|
-
return blockIdAtRelativeY(editor.document.blocks.map((block) => block.id), (clientY - rect.top) / rect.height);
|
|
1124
|
-
};
|
|
1125
|
-
const dropFromLibrary = (event) => {
|
|
1126
|
-
event.preventDefault();
|
|
1127
|
-
const type = event.dataTransfer.getData("application/x-page-document-block") || draggingLibraryType;
|
|
1128
|
-
if (type && blockTypes.includes(type)) addFromLibrary(type, getDropBeforeId(event.clientY));
|
|
1353
|
+
const clearLibraryDrag = () => {
|
|
1354
|
+
draggingBlockIdRef.current = null;
|
|
1129
1355
|
setDraggingLibraryType(null);
|
|
1356
|
+
setDraggingBlockId(null);
|
|
1357
|
+
setDropTarget(null);
|
|
1130
1358
|
};
|
|
1131
1359
|
const cancelLibraryDrop = (event) => {
|
|
1132
1360
|
event.preventDefault();
|
|
1133
1361
|
event.stopPropagation();
|
|
1134
|
-
|
|
1362
|
+
clearLibraryDrag();
|
|
1363
|
+
};
|
|
1364
|
+
const applyListReorder = (sourceId, targetId, edge) => {
|
|
1365
|
+
const beforeId = beforeIdAfterPlacement(editorRef.current.document.blocks.map((block) => block.id), targetId, edge);
|
|
1366
|
+
editorRef.current.reorderBlock(sourceId, beforeId);
|
|
1367
|
+
editorRef.current.requestCanvasSelection(sourceId);
|
|
1368
|
+
scrollCanvasBlockIntoView(sourceId, canvasFrameRef.current);
|
|
1135
1369
|
};
|
|
1136
1370
|
const saveBadgeTone = resolvedSaveState === "failed" ? "critical" : resolvedSaveState === "offline" || resolvedSaveState === "dirty" ? "attention" : "success";
|
|
1137
1371
|
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");
|
|
@@ -1141,123 +1375,164 @@ function PageDocumentEditor({ iframe = false, registry, adminLocale, onSave, onP
|
|
|
1141
1375
|
else onBack();
|
|
1142
1376
|
};
|
|
1143
1377
|
const dismissPublishedNotice = () => setNotice((current) => current === "published" ? null : current);
|
|
1144
|
-
return /* @__PURE__ */
|
|
1145
|
-
/* @__PURE__ */
|
|
1378
|
+
return /* @__PURE__ */ jsxs7(Fragment2, { children: [
|
|
1379
|
+
/* @__PURE__ */ jsx9(Puck2, { config, data: engineData, iframe: { enabled: iframe }, dnd: { behavior: "static" }, overrides: { actionBar: CanvasSelectionActionBar }, onChange: (data) => {
|
|
1146
1380
|
if (!editor.updateFromCanvas(fromEngineData(data, editor.document, registry))) setCanvasResetVersion((version) => version + 1);
|
|
1147
|
-
}, children: /* @__PURE__ */
|
|
1148
|
-
/* @__PURE__ */
|
|
1149
|
-
/* @__PURE__ */
|
|
1150
|
-
/* @__PURE__ */
|
|
1151
|
-
/* @__PURE__ */
|
|
1152
|
-
onBack ? /* @__PURE__ */
|
|
1153
|
-
/* @__PURE__ */
|
|
1154
|
-
/* @__PURE__ */
|
|
1155
|
-
pageStatus ? /* @__PURE__ */
|
|
1381
|
+
}, children: /* @__PURE__ */ jsxs7(Puck2.Layout, { children: [
|
|
1382
|
+
/* @__PURE__ */ jsx9(CanvasSelectionBridge, { data: engineData, requestedBlockId: editor.canvasSelectionRequest, onCanvasSelected: confirmCanvasSelection, canvasMutationVersion, canvasResetVersion, permissionsVersion: `${editor.isEditable}:${editor.document.blocks.map((block) => `${block.id}:${block.type}`).join("|")}` }),
|
|
1383
|
+
/* @__PURE__ */ jsxs7("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, "data-left-panel": leftRailOpen ? "open" : "closed", "data-right-panel": rightPanelOpen ? "open" : "closed", children: [
|
|
1384
|
+
/* @__PURE__ */ jsx9("header", { className: "pb-header", children: /* @__PURE__ */ jsxs7("div", { className: "pb-header-content", children: [
|
|
1385
|
+
/* @__PURE__ */ jsxs7("div", { className: "pb-header-title-group", children: [
|
|
1386
|
+
onBack ? /* @__PURE__ */ jsx9(Button2, { variant: "tertiary", onClick: requestBack, children: i18n.t("back") }) : null,
|
|
1387
|
+
/* @__PURE__ */ jsxs7("div", { className: "pb-page-title", children: [
|
|
1388
|
+
/* @__PURE__ */ jsx9(Text3, { as: "h1", variant: "headingSm", children: editor.document.settings.seoTitle ?? editor.document.pageId }),
|
|
1389
|
+
pageStatus ? /* @__PURE__ */ jsx9(PageStatusCard, { status: pageStatus, sessionState: editor.sessionState }) : null
|
|
1156
1390
|
] })
|
|
1157
1391
|
] }),
|
|
1158
|
-
/* @__PURE__ */
|
|
1159
|
-
/* @__PURE__ */
|
|
1160
|
-
/* @__PURE__ */
|
|
1392
|
+
/* @__PURE__ */ jsx9("div", { className: "pb-header-controls", children: /* @__PURE__ */ jsxs7("div", { className: "pb-header-device-toolbar", children: [
|
|
1393
|
+
/* @__PURE__ */ jsx9(ButtonGroup2, { variant: "segmented", children: Object.keys(deviceLabels2).map((device) => /* @__PURE__ */ jsx9(Button2, { pressed: editor.device === device, onClick: () => editor.setDevice(device), children: i18n.t(deviceLabels2[device]) }, device)) }),
|
|
1394
|
+
/* @__PURE__ */ jsx9("div", { className: "pb-zoom-control", children: /* @__PURE__ */ jsx9(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) }) })
|
|
1161
1395
|
] }) }),
|
|
1162
|
-
/* @__PURE__ */
|
|
1163
|
-
/* @__PURE__ */
|
|
1164
|
-
/* @__PURE__ */
|
|
1165
|
-
resolvedSaveState === "saved" ? null : /* @__PURE__ */
|
|
1166
|
-
onHistory ? /* @__PURE__ */
|
|
1167
|
-
onPreview ? /* @__PURE__ */
|
|
1168
|
-
onAddToStore ? /* @__PURE__ */
|
|
1169
|
-
/* @__PURE__ */
|
|
1396
|
+
/* @__PURE__ */ jsx9("div", { className: "pb-header-actions", children: /* @__PURE__ */ jsxs7(InlineStack3, { gap: "150", blockAlign: "center", wrap: true, children: [
|
|
1397
|
+
/* @__PURE__ */ jsx9(Button2, { accessibilityLabel: i18n.t("undo"), icon: UndoIcon2, variant: "tertiary", disabled: !editor.actionState.canUndo, onClick: editor.undo }),
|
|
1398
|
+
/* @__PURE__ */ jsx9(Button2, { accessibilityLabel: i18n.t("redo"), icon: RedoIcon2, variant: "tertiary", disabled: !editor.actionState.canRedo, onClick: editor.redo }),
|
|
1399
|
+
resolvedSaveState === "saved" ? null : /* @__PURE__ */ jsx9(Badge3, { tone: saveBadgeTone, children: saveBadgeLabel }),
|
|
1400
|
+
onHistory ? /* @__PURE__ */ jsx9("span", { "data-editor-history": "", children: /* @__PURE__ */ jsx9(Button2, { disabled: request !== "idle", onClick: () => onHistory({ document: editor.document, draftRevision, session: editor.session }), children: i18n.t("history") }) }) : null,
|
|
1401
|
+
onPreview ? /* @__PURE__ */ jsx9(Button2, { disabled: request !== "idle" || !isOnline, onClick: () => void onPreview({ document: editor.document, draftRevision, session: editor.session }), children: i18n.t("preview") }) : null,
|
|
1402
|
+
onAddToStore ? /* @__PURE__ */ jsx9(Button2, { disabled: request !== "idle" || pageStatus?.publicationStatus === "unpublished", onClick: () => void onAddToStore({ document: editor.document, session: editor.session }), children: i18n.t("addToStore") }) : null,
|
|
1403
|
+
/* @__PURE__ */ jsx9(Button2, { variant: "primary", disabled: !publishAction && !onPublish || request !== "idle" || validationIssues.length > 0 || !isOnline, onClick: () => void publish(), children: request === "publishing" ? i18n.t("publishing") : i18n.t("publish") })
|
|
1170
1404
|
] }) })
|
|
1171
1405
|
] }) }),
|
|
1172
|
-
editor.loadState === "success" ? /* @__PURE__ */
|
|
1173
|
-
notice && notice !== "published" ? /* @__PURE__ */
|
|
1174
|
-
validationIssues.length > 0 ? /* @__PURE__ */
|
|
1406
|
+
editor.loadState === "success" ? /* @__PURE__ */ jsx9(Banner, { tone: "success", children: i18n.t("success") }) : null,
|
|
1407
|
+
notice && notice !== "published" ? /* @__PURE__ */ jsx9("div", { className: `pb-editor-notice pb-editor-notice--${notice}`, "data-testid": "editor-notice", "data-notice": notice, children: /* @__PURE__ */ jsx9(Banner, { tone: "critical", children: i18n.t(notice) }) }) : null,
|
|
1408
|
+
validationIssues.length > 0 ? /* @__PURE__ */ jsx9(Banner, { tone: "critical", title: "\u533A\u5757\u5C5E\u6027\u672A\u901A\u8FC7\u6821\u9A8C", children: /* @__PURE__ */ jsx9("ul", { children: validationIssues.map((issue) => /* @__PURE__ */ jsxs7("li", { children: [
|
|
1175
1409
|
issue.path,
|
|
1176
1410
|
": ",
|
|
1177
1411
|
issue.message
|
|
1178
1412
|
] }, `${issue.path}-${issue.message}`)) }) }) : null,
|
|
1179
|
-
/* @__PURE__ */
|
|
1180
|
-
/* @__PURE__ */
|
|
1181
|
-
/* @__PURE__ */
|
|
1413
|
+
/* @__PURE__ */ jsxs7("div", { className: `pb-workspace pb-workspace--document${leftRailOpen ? "" : " pb-workspace--left-closed"}${rightPanelOpen ? "" : " pb-workspace--right-closed"}`, "data-left-panel": leftRailOpen ? "open" : "closed", "data-right-panel": rightPanelOpen ? "open" : "closed", children: [
|
|
1414
|
+
/* @__PURE__ */ jsxs7("nav", { className: "pb-tool-rail", "aria-label": "\u7F16\u8F91\u5668\u5DE5\u5177", children: [
|
|
1415
|
+
/* @__PURE__ */ jsx9(Button2, { accessibilityLabel: i18n.t("blocks"), icon: LayoutSectionIcon2, pressed: blockView === "blocks" && leftRailOpen, variant: "tertiary", onClick: () => {
|
|
1182
1416
|
setBlockView("blocks");
|
|
1183
1417
|
setLeftRailOpen(true);
|
|
1184
1418
|
} }),
|
|
1185
|
-
/* @__PURE__ */
|
|
1419
|
+
/* @__PURE__ */ jsx9(Button2, { accessibilityLabel: i18n.t("outline"), icon: MenuIcon2, pressed: blockView === "outline" && leftRailOpen, variant: "tertiary", onClick: () => {
|
|
1186
1420
|
setBlockView("outline");
|
|
1187
1421
|
setLeftRailOpen(true);
|
|
1188
1422
|
} })
|
|
1189
1423
|
] }),
|
|
1190
|
-
/* @__PURE__ */
|
|
1191
|
-
/* @__PURE__ */
|
|
1192
|
-
/* @__PURE__ */
|
|
1193
|
-
/* @__PURE__ */
|
|
1424
|
+
/* @__PURE__ */ jsxs7("aside", { className: `pb-left-panel${leftRailOpen ? "" : " pb-panel--closed"}`, "aria-label": "PageDocument \u533A\u5757", children: [
|
|
1425
|
+
/* @__PURE__ */ jsxs7(InlineStack3, { align: "space-between", blockAlign: "center", children: [
|
|
1426
|
+
/* @__PURE__ */ jsx9(Text3, { as: "h2", variant: "headingSm", children: blockView === "blocks" ? i18n.t("blocks") : i18n.t("outline") }),
|
|
1427
|
+
/* @__PURE__ */ jsx9(Button2, { accessibilityLabel: i18n.t("collapseLeft"), icon: XIcon2, variant: "tertiary", onClick: () => setLeftRailOpen(false) })
|
|
1194
1428
|
] }),
|
|
1195
|
-
blockView === "blocks" ? /* @__PURE__ */
|
|
1196
|
-
|
|
1429
|
+
blockView === "blocks" ? /* @__PURE__ */ jsx9("div", { className: "pb-block-list", "data-testid": "blocks-view", "aria-label": "\u533A\u5757\u7C7B\u578B\u5E93", role: "list", onDrop: cancelLibraryDrop, children: orderedBlockTypes.map((type) => {
|
|
1430
|
+
const instance = editor.document.blocks.find((item) => item.type === type);
|
|
1431
|
+
const canAdd = editor.canAddBlock(type);
|
|
1432
|
+
const canReorder = Boolean(instance && editor.canDragBlock(instance.id));
|
|
1433
|
+
const draggable = canAdd || canReorder;
|
|
1434
|
+
const selected = editor.selectedBlock?.type === type;
|
|
1435
|
+
const dropEdge = draggingBlockId && instance && dropTarget?.id === instance.id ? dropTarget.edge : void 0;
|
|
1436
|
+
const actionHint = canReorder && canAdd ? "\uFF0C\u62D6\u62FD\u6392\u5E8F\uFF0C\u6216\u62D6\u62FD\u81F3\u753B\u5E03\u4EE5\u6DFB\u52A0" : canReorder ? "\uFF0C\u62D6\u62FD\u6392\u5E8F" : canAdd ? "\uFF0C\u62D6\u62FD\u81F3\u753B\u5E03\u4EE5\u6DFB\u52A0" : "";
|
|
1437
|
+
return /* @__PURE__ */ jsxs7("div", { className: `pb-document-block-row pb-document-block-row--library${selected ? " pb-document-block-row--selected" : ""}${draggingBlockId === instance?.id ? " pb-document-block-row--dragging" : ""}${dropEdge === "before" ? " pb-document-block-row--drop-before" : ""}${dropEdge === "after" ? " pb-document-block-row--drop-after" : ""}`, "data-block-type": type, "data-selected": selected, "data-drop-edge": dropEdge, role: "listitem", draggable, "aria-disabled": !draggable, "aria-label": `${blockTypeLabel(type, registry)}${actionHint}${selected ? "\uFF0C\u5F53\u524D\u9009\u4E2D\u7C7B\u578B" : ""}`, onClick: () => {
|
|
1438
|
+
if (!instance) return;
|
|
1439
|
+
editor.requestCanvasSelection(instance.id);
|
|
1440
|
+
scrollCanvasBlockIntoView(instance.id, canvasFrameRef.current);
|
|
1441
|
+
}, onDragStart: (event) => {
|
|
1442
|
+
if (!draggable) {
|
|
1443
|
+
event.preventDefault();
|
|
1444
|
+
return;
|
|
1445
|
+
}
|
|
1446
|
+
event.dataTransfer.setData("application/x-page-document-block", type);
|
|
1447
|
+
if (instance && canReorder) {
|
|
1448
|
+
event.dataTransfer.setData("application/x-page-document-block-id", instance.id);
|
|
1449
|
+
event.dataTransfer.effectAllowed = canAdd ? "copyMove" : "move";
|
|
1450
|
+
draggingBlockIdRef.current = instance.id;
|
|
1451
|
+
setDraggingBlockId(instance.id);
|
|
1452
|
+
} else event.dataTransfer.effectAllowed = "copy";
|
|
1453
|
+
if (canAdd) setDraggingLibraryType(type);
|
|
1454
|
+
}, onDragOver: (event) => {
|
|
1455
|
+
const sourceId = draggingBlockIdRef.current;
|
|
1456
|
+
if (!sourceId || !instance || sourceId === instance.id) return;
|
|
1457
|
+
event.preventDefault();
|
|
1458
|
+
event.stopPropagation();
|
|
1459
|
+
event.dataTransfer.dropEffect = "move";
|
|
1460
|
+
const rect = event.currentTarget.getBoundingClientRect();
|
|
1461
|
+
setDropTarget({ id: instance.id, edge: dropPlacement(event.clientY, rect.top, rect.height) });
|
|
1462
|
+
}, onDragLeave: (event) => {
|
|
1463
|
+
if (instance && !event.currentTarget.contains(event.relatedTarget)) setDropTarget((current) => current?.id === instance.id ? null : current);
|
|
1464
|
+
}, onDrop: (event) => {
|
|
1465
|
+
const sourceId = draggingBlockIdRef.current;
|
|
1466
|
+
if (!sourceId || !instance || sourceId === instance.id) return;
|
|
1197
1467
|
event.preventDefault();
|
|
1198
|
-
|
|
1199
|
-
|
|
1200
|
-
|
|
1201
|
-
|
|
1202
|
-
|
|
1203
|
-
|
|
1204
|
-
|
|
1205
|
-
|
|
1206
|
-
|
|
1207
|
-
|
|
1208
|
-
|
|
1209
|
-
|
|
1210
|
-
|
|
1211
|
-
|
|
1468
|
+
event.stopPropagation();
|
|
1469
|
+
const rect = event.currentTarget.getBoundingClientRect();
|
|
1470
|
+
applyListReorder(sourceId, instance.id, dropPlacement(event.clientY, rect.top, rect.height));
|
|
1471
|
+
clearLibraryDrag();
|
|
1472
|
+
}, onDragEnd: clearLibraryDrag, children: [
|
|
1473
|
+
/* @__PURE__ */ jsxs7("span", { className: "pb-library-block-title", children: [
|
|
1474
|
+
/* @__PURE__ */ jsx9(Text3, { as: "span", variant: "bodySm", fontWeight: "semibold", children: blockTypeLabel(type, registry) }),
|
|
1475
|
+
/* @__PURE__ */ jsx9("span", { className: "pb-library-block-drag-hint", "aria-hidden": "true", children: /* @__PURE__ */ jsx9(DragHandleIcon2, {}) })
|
|
1476
|
+
] }),
|
|
1477
|
+
/* @__PURE__ */ jsx9(Text3, { as: "span", variant: "bodySm", tone: "subdued", children: type })
|
|
1478
|
+
] }, type);
|
|
1479
|
+
}) }) : editor.document.blocks.length === 0 ? /* @__PURE__ */ jsx9(Text3, { as: "p", tone: "subdued", children: i18n.t("empty") }) : /* @__PURE__ */ jsx9("div", { className: "pb-block-list", "data-testid": "outline-view", children: editor.document.blocks.map((block) => /* @__PURE__ */ jsxs7("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: () => {
|
|
1480
|
+
editor.requestCanvasSelection(block.id);
|
|
1481
|
+
scrollCanvasBlockIntoView(block.id, canvasFrameRef.current);
|
|
1482
|
+
}, children: [
|
|
1483
|
+
/* @__PURE__ */ jsx9(Text3, { as: "span", variant: "bodySm", fontWeight: "semibold", children: blockLabel(block, registry) }),
|
|
1484
|
+
/* @__PURE__ */ jsx9(Text3, { as: "span", variant: "bodySm", tone: "subdued", children: block.id })
|
|
1212
1485
|
] }, block.id)) })
|
|
1213
1486
|
] }),
|
|
1214
|
-
/* @__PURE__ */
|
|
1215
|
-
/* @__PURE__ */
|
|
1216
|
-
/* @__PURE__ */
|
|
1217
|
-
draggingLibraryType ? /* @__PURE__ */
|
|
1218
|
-
|
|
1219
|
-
|
|
1220
|
-
|
|
1221
|
-
editor.selectedBlock ? /* @__PURE__ */ jsxs5("div", { className: "pb-canvas-overlay", "aria-label": `\u5DF2\u9009\u62E9 ${blockLabel(editor.selectedBlock, registry)}`, children: [
|
|
1222
|
-
/* @__PURE__ */ jsx7("span", { children: blockLabel(editor.selectedBlock, registry) }),
|
|
1223
|
-
/* @__PURE__ */ jsx7("span", { children: "Selected" })
|
|
1224
|
-
] }) : null
|
|
1487
|
+
/* @__PURE__ */ jsxs7("main", { className: "pb-canvas-area", children: [
|
|
1488
|
+
/* @__PURE__ */ jsxs7("div", { className: "pb-canvas-stage", children: [
|
|
1489
|
+
/* @__PURE__ */ jsx9("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, style: canvasThemeStyle, children: /* @__PURE__ */ jsx9(Puck2.Preview, {}) }),
|
|
1490
|
+
draggingLibraryType ? /* @__PURE__ */ jsx9(CanvasLibraryDropTarget, { frameRef: canvasFrameRef, blocks: editor.document.blocks.map((block) => ({ id: block.id, label: blockLabel(block, registry) })), label: blockTypeLabel(draggingLibraryType, registry), adminLocale, onDrop: (beforeId) => {
|
|
1491
|
+
addFromLibrary(draggingLibraryType, beforeId);
|
|
1492
|
+
setDraggingLibraryType(null);
|
|
1493
|
+
}, onCancel: () => setDraggingLibraryType(null) }) : null
|
|
1225
1494
|
] }),
|
|
1226
|
-
!leftRailOpen || !rightPanelOpen ? /* @__PURE__ */
|
|
1227
|
-
!leftRailOpen ? /* @__PURE__ */
|
|
1228
|
-
!rightPanelOpen ? /* @__PURE__ */
|
|
1495
|
+
!leftRailOpen || !rightPanelOpen ? /* @__PURE__ */ jsxs7("div", { className: "pb-collapsed-actions", children: [
|
|
1496
|
+
!leftRailOpen ? /* @__PURE__ */ jsx9(Button2, { onClick: () => setLeftRailOpen(true), children: i18n.t("expandLeft") }) : null,
|
|
1497
|
+
!rightPanelOpen ? /* @__PURE__ */ jsx9(Button2, { onClick: () => setRightPanelOpen(true), children: i18n.t("expandRight") }) : null
|
|
1229
1498
|
] }) : null
|
|
1230
1499
|
] }),
|
|
1231
|
-
/* @__PURE__ */
|
|
1232
|
-
/* @__PURE__ */
|
|
1233
|
-
/* @__PURE__ */
|
|
1234
|
-
/* @__PURE__ */
|
|
1500
|
+
/* @__PURE__ */ jsxs7("aside", { className: `pb-right-panel${rightPanelOpen ? "" : " pb-panel--closed"}`, "aria-label": "PageDocument \u5C5E\u6027", children: [
|
|
1501
|
+
/* @__PURE__ */ jsxs7(InlineStack3, { align: "space-between", blockAlign: "center", children: [
|
|
1502
|
+
/* @__PURE__ */ jsx9(Text3, { as: "h2", variant: "headingSm", children: i18n.t("properties") }),
|
|
1503
|
+
/* @__PURE__ */ jsx9(Button2, { accessibilityLabel: i18n.t("collapseRight"), icon: XIcon2, variant: "tertiary", onClick: () => setRightPanelOpen(false) })
|
|
1235
1504
|
] }),
|
|
1236
|
-
editor.selectedBlock ? /* @__PURE__ */
|
|
1237
|
-
/* @__PURE__ */
|
|
1238
|
-
/* @__PURE__ */
|
|
1239
|
-
] }) : /* @__PURE__ */
|
|
1505
|
+
editor.selectedBlock ? /* @__PURE__ */ jsxs7(Fragment2, { children: [
|
|
1506
|
+
/* @__PURE__ */ jsx9(DocumentInspector, { settings: inspectorSettings?.[editor.selectedBlock.id] ?? inspectorSettings?.[editor.selectedBlock.type], pageId: editor.document.pageId, assetPicker, productPicker, i18n, block: editor.selectedBlock, registry, disabled: !editor.actionState.canEdit, appearanceControls, onChange: (props) => editor.updateBlockProps(editor.selectedBlock.id, props), onPresentationChange: (presentation) => updateBlockPresentation(editor.selectedBlock.id, presentation) }, editor.selectedBlock.id),
|
|
1507
|
+
/* @__PURE__ */ jsx9(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) })
|
|
1508
|
+
] }) : /* @__PURE__ */ jsx9(Text3, { as: "p", tone: "subdued", children: i18n.t("selectBlock") })
|
|
1240
1509
|
] })
|
|
1241
1510
|
] }),
|
|
1242
|
-
editor.pendingDeleteBlock ? /* @__PURE__ */
|
|
1243
|
-
confirmBack ? /* @__PURE__ */
|
|
1511
|
+
editor.pendingDeleteBlock ? /* @__PURE__ */ jsx9(DeleteConfirmation, { block: editor.pendingDeleteBlock, config: deleteConfirmation, i18n, onCancel: editor.cancelDeleteBlock, onConfirm: editor.confirmDeleteBlock }) : null,
|
|
1512
|
+
confirmBack ? /* @__PURE__ */ jsx9(LeaveConfirmation, { i18n, onCancel: () => setConfirmBack(false), onConfirm: () => {
|
|
1244
1513
|
setConfirmBack(false);
|
|
1245
1514
|
onBack?.();
|
|
1246
1515
|
} }) : null
|
|
1247
1516
|
] })
|
|
1248
1517
|
] }) }),
|
|
1249
|
-
/* @__PURE__ */
|
|
1518
|
+
/* @__PURE__ */ jsx9("div", { className: "pb-toast-host", ...notice === "published" ? { "data-testid": "editor-notice", "data-notice": "published" } : {}, children: /* @__PURE__ */ jsx9(Frame, { children: notice === "published" ? /* @__PURE__ */ jsx9(Toast, { content: i18n.t("publishSuccessTitle"), onDismiss: dismissPublishedNotice }) : null }) })
|
|
1250
1519
|
] });
|
|
1251
1520
|
}
|
|
1521
|
+
function CanvasSelectionActionBar({ label, children, parentAction }) {
|
|
1522
|
+
void label;
|
|
1523
|
+
void children;
|
|
1524
|
+
void parentAction;
|
|
1525
|
+
return /* @__PURE__ */ jsx9(Fragment2, {});
|
|
1526
|
+
}
|
|
1252
1527
|
function CanvasSelectionBridge({ data, requestedBlockId, onCanvasSelected, canvasMutationVersion, canvasResetVersion, permissionsVersion }) {
|
|
1253
1528
|
const puck = usePuck();
|
|
1254
|
-
const lastSelectedId =
|
|
1255
|
-
const lastSyncedData =
|
|
1256
|
-
const lastCanvasMutationVersion =
|
|
1257
|
-
const lastCanvasResetVersion =
|
|
1529
|
+
const lastSelectedId = useRef5(null);
|
|
1530
|
+
const lastSyncedData = useRef5(null);
|
|
1531
|
+
const lastCanvasMutationVersion = useRef5(0);
|
|
1532
|
+
const lastCanvasResetVersion = useRef5(0);
|
|
1258
1533
|
const serializedData = JSON.stringify(data);
|
|
1259
1534
|
const refreshPermissions = puck.refreshPermissions;
|
|
1260
|
-
|
|
1535
|
+
useEffect4(() => {
|
|
1261
1536
|
const forceReset = canvasResetVersion > lastCanvasResetVersion.current;
|
|
1262
1537
|
if (lastSyncedData.current === serializedData && !forceReset) return;
|
|
1263
1538
|
lastSyncedData.current = serializedData;
|
|
@@ -1268,16 +1543,17 @@ function CanvasSelectionBridge({ data, requestedBlockId, onCanvasSelected, canva
|
|
|
1268
1543
|
}
|
|
1269
1544
|
puck.dispatch({ type: "setData", data });
|
|
1270
1545
|
}, [canvasMutationVersion, canvasResetVersion, data, puck, serializedData]);
|
|
1271
|
-
|
|
1546
|
+
useEffect4(() => {
|
|
1272
1547
|
refreshPermissions?.({}, true);
|
|
1273
1548
|
}, [permissionsVersion, refreshPermissions]);
|
|
1274
|
-
|
|
1549
|
+
useEffect4(() => {
|
|
1275
1550
|
if (!requestedBlockId) return;
|
|
1276
1551
|
const selector = puck.getSelectorForId(requestedBlockId);
|
|
1277
1552
|
if (selector) puck.dispatch({ type: "setUi", ui: { itemSelector: selector } });
|
|
1553
|
+
scrollCanvasBlockIntoView(requestedBlockId);
|
|
1278
1554
|
}, [puck, requestedBlockId]);
|
|
1279
1555
|
const selectedId = typeof puck.selectedItem?.props.id === "string" ? puck.selectedItem.props.id : null;
|
|
1280
|
-
|
|
1556
|
+
useEffect4(() => {
|
|
1281
1557
|
if (selectedId && lastSelectedId.current !== selectedId) {
|
|
1282
1558
|
lastSelectedId.current = selectedId;
|
|
1283
1559
|
onCanvasSelected(selectedId);
|
|
@@ -1289,32 +1565,32 @@ function EditorStatus({ state }) {
|
|
|
1289
1565
|
const i18n = createAdminI18n();
|
|
1290
1566
|
const tone = state === "error" ? "critical" : state === "disabled" ? "warning" : "info";
|
|
1291
1567
|
const message = state === "loading" ? i18n.t("loading") : state === "empty" ? i18n.t("empty") : state === "error" ? i18n.t("error") : i18n.t("disabled");
|
|
1292
|
-
return /* @__PURE__ */
|
|
1568
|
+
return /* @__PURE__ */ jsx9("div", { className: "pb-editor-status", "data-testid": "page-document-editor-state", "data-editor-state": state, children: /* @__PURE__ */ jsx9(Banner, { tone, title: message, children: state === "disabled" ? i18n.t("disabled") : message }) });
|
|
1293
1569
|
}
|
|
1294
1570
|
function EditorSessionStatus({ state, message }) {
|
|
1295
1571
|
const i18n = createAdminI18n();
|
|
1296
1572
|
const tone = state === "locked" ? "warning" : state === "readonly" ? "info" : "critical";
|
|
1297
1573
|
const title = state === "acquiring" ? i18n.t("acquiringLock") : state === "locked" ? i18n.t("locked") : state === "readonly" ? i18n.t("readonly") : i18n.t("lockLost");
|
|
1298
|
-
return /* @__PURE__ */
|
|
1574
|
+
return /* @__PURE__ */ jsx9("div", { className: "pb-editor-status", "data-testid": "page-document-editor-session-state", "data-editor-session-state": state, children: /* @__PURE__ */ jsx9(Banner, { tone, title, children: message ?? title }) });
|
|
1299
1575
|
}
|
|
1300
1576
|
function InspectorSection({ title, children, defaultOpen = true }) {
|
|
1301
|
-
return /* @__PURE__ */
|
|
1302
|
-
/* @__PURE__ */
|
|
1303
|
-
/* @__PURE__ */
|
|
1304
|
-
/* @__PURE__ */
|
|
1577
|
+
return /* @__PURE__ */ jsxs7("details", { className: "pb-inspector-section", open: defaultOpen, children: [
|
|
1578
|
+
/* @__PURE__ */ jsxs7("summary", { children: [
|
|
1579
|
+
/* @__PURE__ */ jsx9("span", { children: title }),
|
|
1580
|
+
/* @__PURE__ */ jsx9("span", { "aria-hidden": "true", children: "\u2304" })
|
|
1305
1581
|
] }),
|
|
1306
|
-
/* @__PURE__ */
|
|
1582
|
+
/* @__PURE__ */ jsx9("div", { className: "pb-inspector-section__body", children })
|
|
1307
1583
|
] });
|
|
1308
1584
|
}
|
|
1309
1585
|
function InspectorTextControl({ label, value, control, maxLength, disabled, onChange }) {
|
|
1310
1586
|
const stringValue = typeof value === "string" ? value : "";
|
|
1311
|
-
if (control === "color") return /* @__PURE__ */
|
|
1587
|
+
if (control === "color") return /* @__PURE__ */ jsx9("input", { "aria-label": label, type: "color", value: /^#[\da-f]{6}$/i.test(stringValue) ? stringValue : "#000000", disabled, onChange: (event) => onChange(event.currentTarget.value) });
|
|
1312
1588
|
const length = Array.from(stringValue).length;
|
|
1313
|
-
const field = /* @__PURE__ */
|
|
1589
|
+
const field = /* @__PURE__ */ jsx9(TextField, { label, labelHidden: true, value: stringValue, onChange: (next) => onChange(maxLength === void 0 ? next : Array.from(next).slice(0, maxLength).join("")), autoComplete: "off", disabled, multiline: control === "textarea" ? 4 : false, type: control === "url" ? "url" : "text", maxLength });
|
|
1314
1590
|
if (maxLength === void 0) return field;
|
|
1315
|
-
return /* @__PURE__ */
|
|
1591
|
+
return /* @__PURE__ */ jsxs7("div", { className: "pb-inspector-field__limited", children: [
|
|
1316
1592
|
field,
|
|
1317
|
-
/* @__PURE__ */
|
|
1593
|
+
/* @__PURE__ */ jsxs7("span", { className: "pb-inspector-field__limit", "aria-label": `Limit ${maxLength}`, children: [
|
|
1318
1594
|
length,
|
|
1319
1595
|
"/",
|
|
1320
1596
|
maxLength
|
|
@@ -1322,20 +1598,20 @@ function InspectorTextControl({ label, value, control, maxLength, disabled, onCh
|
|
|
1322
1598
|
] });
|
|
1323
1599
|
}
|
|
1324
1600
|
function InspectorAssetControl({ value, disabled, picker, pageId, blockId, i18n, onChange }) {
|
|
1325
|
-
const [busy, setBusy] =
|
|
1326
|
-
const [error, setError] =
|
|
1327
|
-
const active =
|
|
1328
|
-
|
|
1601
|
+
const [busy, setBusy] = useState4(false);
|
|
1602
|
+
const [error, setError] = useState4(null);
|
|
1603
|
+
const active = useRef5(true);
|
|
1604
|
+
useEffect4(() => {
|
|
1329
1605
|
active.current = !disabled;
|
|
1330
1606
|
return () => {
|
|
1331
1607
|
active.current = false;
|
|
1332
1608
|
};
|
|
1333
1609
|
}, [disabled]);
|
|
1334
1610
|
const url = typeof value === "string" && validateFieldValue({ field: "", control: "asset" }, value).length === 0 ? value : "";
|
|
1335
|
-
return /* @__PURE__ */
|
|
1336
|
-
url ? /* @__PURE__ */
|
|
1337
|
-
url ? /* @__PURE__ */
|
|
1338
|
-
/* @__PURE__ */
|
|
1611
|
+
return /* @__PURE__ */ jsxs7("div", { className: "pb-asset-picker", "data-testid": "asset-picker", children: [
|
|
1612
|
+
url ? /* @__PURE__ */ jsx9("img", { src: url, alt: "", className: "pb-asset-picker__preview" }) : /* @__PURE__ */ jsx9(Text3, { as: "p", variant: "bodySm", tone: "subdued", children: i18n.t("emptyAsset") }),
|
|
1613
|
+
url ? /* @__PURE__ */ jsx9(Button2, { fullWidth: true, variant: "tertiary", disabled: disabled || busy, onClick: () => onChange(""), children: i18n.t("removeAsset") }) : null,
|
|
1614
|
+
/* @__PURE__ */ jsx9(Button2, { fullWidth: true, disabled: disabled || busy || !picker, onClick: () => void (async () => {
|
|
1339
1615
|
if (!picker) return;
|
|
1340
1616
|
setBusy(true);
|
|
1341
1617
|
setError(null);
|
|
@@ -1351,20 +1627,20 @@ function InspectorAssetControl({ value, disabled, picker, pageId, blockId, i18n,
|
|
|
1351
1627
|
setBusy(false);
|
|
1352
1628
|
}
|
|
1353
1629
|
})(), children: busy ? i18n.t("selectingAsset") : i18n.t("selectAsset") }),
|
|
1354
|
-
error ? /* @__PURE__ */
|
|
1630
|
+
error ? /* @__PURE__ */ jsx9(Text3, { as: "p", variant: "bodySm", tone: "critical", children: error }) : null
|
|
1355
1631
|
] });
|
|
1356
1632
|
}
|
|
1357
1633
|
function InspectorProductsControl({ value, disabled, picker, pageId, blockId, i18n, onChange }) {
|
|
1358
1634
|
const products = parseProductReferences(value);
|
|
1359
|
-
const [busy, setBusy] =
|
|
1360
|
-
const [error, setError] =
|
|
1635
|
+
const [busy, setBusy] = useState4(false);
|
|
1636
|
+
const [error, setError] = useState4(null);
|
|
1361
1637
|
const preview = products.slice(0, 4);
|
|
1362
|
-
return /* @__PURE__ */
|
|
1363
|
-
/* @__PURE__ */
|
|
1364
|
-
preview.length ? /* @__PURE__ */
|
|
1365
|
-
/* @__PURE__ */
|
|
1638
|
+
return /* @__PURE__ */ jsxs7("div", { className: "pb-product-picker", "data-testid": "product-picker", children: [
|
|
1639
|
+
/* @__PURE__ */ jsxs7("div", { className: "pb-product-picker__summary", children: [
|
|
1640
|
+
preview.length ? /* @__PURE__ */ jsx9("span", { className: "pb-product-picker__thumbs", "aria-hidden": "true", children: preview.map((product, index) => /* @__PURE__ */ jsx9("span", { className: "pb-product-picker__thumb", style: { zIndex: preview.length - index }, children: product.imageUrl ? /* @__PURE__ */ jsx9("img", { src: product.imageUrl, alt: "" }) : /* @__PURE__ */ jsx9("span", { className: "pb-product-picker__thumb-fallback" }) }, product.id)) }) : null,
|
|
1641
|
+
/* @__PURE__ */ jsx9(Text3, { as: "p", variant: "bodySm", children: products.length ? `${products.length} ${i18n.t("productCountSuffix")}` : i18n.t("emptyProducts") })
|
|
1366
1642
|
] }),
|
|
1367
|
-
/* @__PURE__ */
|
|
1643
|
+
/* @__PURE__ */ jsx9(Button2, { fullWidth: true, icon: ProductIcon, variant: "secondary", disabled: disabled || busy || !picker, onClick: () => void (async () => {
|
|
1368
1644
|
if (!picker) return;
|
|
1369
1645
|
setBusy(true);
|
|
1370
1646
|
setError(null);
|
|
@@ -1377,50 +1653,50 @@ function InspectorProductsControl({ value, disabled, picker, pageId, blockId, i1
|
|
|
1377
1653
|
setBusy(false);
|
|
1378
1654
|
}
|
|
1379
1655
|
})(), children: busy ? i18n.t("selectingProducts") : i18n.t("selectProducts") }),
|
|
1380
|
-
error ? /* @__PURE__ */
|
|
1656
|
+
error ? /* @__PURE__ */ jsx9(Text3, { as: "p", variant: "bodySm", tone: "critical", children: error }) : null
|
|
1381
1657
|
] });
|
|
1382
1658
|
}
|
|
1383
1659
|
function InspectorField({ name, field, value, registry, disabled, assetPicker, productPicker, pageId, blockId, i18n, onChange }) {
|
|
1384
1660
|
const label = field.label ?? name;
|
|
1385
1661
|
const issues = validateFieldValue(field, value);
|
|
1386
1662
|
const Field = registry?.getField(field.field)?.component;
|
|
1387
|
-
return /* @__PURE__ */
|
|
1388
|
-
/* @__PURE__ */
|
|
1389
|
-
/* @__PURE__ */
|
|
1390
|
-
field.description ? /* @__PURE__ */
|
|
1663
|
+
return /* @__PURE__ */ jsxs7("div", { className: "pb-inspector-field", "data-control": field.control ?? "custom", children: [
|
|
1664
|
+
/* @__PURE__ */ jsxs7("div", { className: "pb-inspector-field__heading", children: [
|
|
1665
|
+
/* @__PURE__ */ jsx9(Text3, { as: "p", variant: "bodySm", fontWeight: "semibold", children: label }),
|
|
1666
|
+
field.description ? /* @__PURE__ */ jsx9(Text3, { as: "p", variant: "bodySm", tone: "subdued", children: field.description }) : null
|
|
1391
1667
|
] }),
|
|
1392
|
-
field.control === "products" ? /* @__PURE__ */
|
|
1393
|
-
issues.map((issue) => /* @__PURE__ */
|
|
1668
|
+
field.control === "products" ? /* @__PURE__ */ jsx9(InspectorProductsControl, { value, disabled, picker: productPicker, pageId, blockId, i18n, onChange }) : field.control === "asset" ? /* @__PURE__ */ jsx9(InspectorAssetControl, { value, disabled, picker: assetPicker, pageId, blockId, i18n, onChange }) : field.control ? /* @__PURE__ */ jsx9(InspectorTextControl, { label, value, control: field.control, maxLength: field.validation?.maxLength, disabled, onChange: (next) => onChange(next) }) : Field ? /* @__PURE__ */ jsx9(Field, { value, onChange }) : null,
|
|
1669
|
+
issues.map((issue) => /* @__PURE__ */ jsx9(Text3, { as: "p", variant: "bodySm", tone: "critical", children: issue.message }, issue.message))
|
|
1394
1670
|
] });
|
|
1395
1671
|
}
|
|
1396
1672
|
function InspectorActions({ block, canDuplicate, canDelete, canMove, canMoveUp, canMoveDown, i18n, onDuplicate, onDelete, onMove }) {
|
|
1397
|
-
return /* @__PURE__ */
|
|
1398
|
-
/* @__PURE__ */
|
|
1399
|
-
/* @__PURE__ */
|
|
1400
|
-
/* @__PURE__ */
|
|
1401
|
-
/* @__PURE__ */
|
|
1402
|
-
/* @__PURE__ */
|
|
1673
|
+
return /* @__PURE__ */ jsxs7("div", { className: "pb-inspector-actions", "aria-label": `Actions for ${block.id}`, children: [
|
|
1674
|
+
/* @__PURE__ */ jsxs7(ButtonGroup2, { children: [
|
|
1675
|
+
/* @__PURE__ */ jsx9(Button2, { disabled: !canMove || !canMoveUp, onClick: () => onMove(-1), children: i18n.t("moveUp") }),
|
|
1676
|
+
/* @__PURE__ */ jsx9(Button2, { disabled: !canMove || !canMoveDown, onClick: () => onMove(1), children: i18n.t("moveDown") }),
|
|
1677
|
+
/* @__PURE__ */ jsx9(Button2, { disabled: !canDuplicate, accessibilityLabel: canDuplicate ? i18n.t("duplicate") : i18n.t("duplicateUnavailable"), onClick: onDuplicate, children: i18n.t("duplicate") }),
|
|
1678
|
+
/* @__PURE__ */ jsx9(Button2, { disabled: !canDelete, tone: "critical", onClick: onDelete, children: i18n.t("remove") })
|
|
1403
1679
|
] }),
|
|
1404
|
-
!canDuplicate ? /* @__PURE__ */
|
|
1680
|
+
!canDuplicate ? /* @__PURE__ */ jsx9(Text3, { as: "p", variant: "bodySm", tone: "subdued", children: i18n.t("duplicateUnavailable") }) : null
|
|
1405
1681
|
] });
|
|
1406
1682
|
}
|
|
1407
1683
|
function DeleteConfirmation({ block, config, i18n, onCancel, onConfirm }) {
|
|
1408
|
-
return /* @__PURE__ */
|
|
1409
|
-
/* @__PURE__ */
|
|
1410
|
-
/* @__PURE__ */
|
|
1411
|
-
/* @__PURE__ */
|
|
1412
|
-
/* @__PURE__ */
|
|
1413
|
-
/* @__PURE__ */
|
|
1684
|
+
return /* @__PURE__ */ jsx9("div", { className: "pb-delete-confirmation-backdrop", role: "presentation", children: /* @__PURE__ */ jsxs7("section", { className: "pb-delete-confirmation", role: "dialog", "aria-modal": "true", "aria-labelledby": "pb-delete-confirmation-title", children: [
|
|
1685
|
+
/* @__PURE__ */ jsx9(Text3, { as: "h2", variant: "headingMd", id: "pb-delete-confirmation-title", children: config?.title ?? i18n.t("confirmDeleteTitle") }),
|
|
1686
|
+
/* @__PURE__ */ jsx9(Text3, { as: "p", variant: "bodyMd", children: config?.message?.(block) ?? i18n.t("confirmDeleteMessage") }),
|
|
1687
|
+
/* @__PURE__ */ jsxs7(ButtonGroup2, { children: [
|
|
1688
|
+
/* @__PURE__ */ jsx9(Button2, { onClick: onCancel, children: config?.cancelLabel ?? i18n.t("cancel") }),
|
|
1689
|
+
/* @__PURE__ */ jsx9(Button2, { tone: "critical", onClick: onConfirm, children: config?.confirmLabel ?? i18n.t("confirm") })
|
|
1414
1690
|
] })
|
|
1415
1691
|
] }) });
|
|
1416
1692
|
}
|
|
1417
1693
|
function LeaveConfirmation({ i18n, onCancel, onConfirm }) {
|
|
1418
|
-
return /* @__PURE__ */
|
|
1419
|
-
/* @__PURE__ */
|
|
1420
|
-
/* @__PURE__ */
|
|
1421
|
-
/* @__PURE__ */
|
|
1422
|
-
/* @__PURE__ */
|
|
1423
|
-
/* @__PURE__ */
|
|
1694
|
+
return /* @__PURE__ */ jsx9("div", { className: "pb-delete-confirmation-backdrop", role: "presentation", children: /* @__PURE__ */ jsxs7("section", { className: "pb-delete-confirmation", role: "dialog", "aria-modal": "true", "aria-labelledby": "pb-leave-confirmation-title", children: [
|
|
1695
|
+
/* @__PURE__ */ jsx9(Text3, { as: "h2", variant: "headingMd", id: "pb-leave-confirmation-title", children: i18n.t("confirmLeaveTitle") }),
|
|
1696
|
+
/* @__PURE__ */ jsx9(Text3, { as: "p", variant: "bodyMd", children: i18n.t("leaveWarning") }),
|
|
1697
|
+
/* @__PURE__ */ jsxs7(ButtonGroup2, { children: [
|
|
1698
|
+
/* @__PURE__ */ jsx9(Button2, { onClick: onCancel, children: i18n.t("cancel") }),
|
|
1699
|
+
/* @__PURE__ */ jsx9(Button2, { tone: "critical", onClick: onConfirm, children: i18n.t("leave") })
|
|
1424
1700
|
] })
|
|
1425
1701
|
] }) });
|
|
1426
1702
|
}
|
|
@@ -1432,8 +1708,8 @@ function inspectorFieldConfig(name, field) {
|
|
|
1432
1708
|
}
|
|
1433
1709
|
var appearanceTokens = [["color.primary", "\u4E3B\u8272"], ["color.surface", "\u8868\u9762\u8272"], ["radius", "\u5706\u89D2"], ["spacing", "\u95F4\u8DDD"]];
|
|
1434
1710
|
function DocumentInspector({ settings, pageId, assetPicker, productPicker, i18n, block, registry, disabled, appearanceControls, onChange, onPresentationChange }) {
|
|
1435
|
-
const [assetError, setAssetError] =
|
|
1436
|
-
const [selectingAsset, setSelectingAsset] =
|
|
1711
|
+
const [assetError, setAssetError] = useState4(null);
|
|
1712
|
+
const [selectingAsset, setSelectingAsset] = useState4(false);
|
|
1437
1713
|
const definition = registry?.getBlock(block.type);
|
|
1438
1714
|
const groupedFields = definition ? Object.entries(definition.fields).reduce((groups, entry) => {
|
|
1439
1715
|
const [name, field] = entry;
|
|
@@ -1442,20 +1718,20 @@ function DocumentInspector({ settings, pageId, assetPicker, productPicker, i18n,
|
|
|
1442
1718
|
(groups[group] ??= []).push([name, configuredField]);
|
|
1443
1719
|
return groups;
|
|
1444
1720
|
}, {}) : {};
|
|
1445
|
-
return /* @__PURE__ */
|
|
1446
|
-
/* @__PURE__ */
|
|
1447
|
-
/* @__PURE__ */
|
|
1448
|
-
/* @__PURE__ */
|
|
1449
|
-
/* @__PURE__ */
|
|
1450
|
-
/* @__PURE__ */
|
|
1721
|
+
return /* @__PURE__ */ jsxs7("div", { className: "pb-inspector", "data-testid": "document-inspector", children: [
|
|
1722
|
+
/* @__PURE__ */ jsxs7("header", { className: "pb-inspector__header", children: [
|
|
1723
|
+
/* @__PURE__ */ jsx9(Badge3, { children: block.type }),
|
|
1724
|
+
/* @__PURE__ */ jsxs7("div", { children: [
|
|
1725
|
+
/* @__PURE__ */ jsx9(Text3, { as: "p", variant: "headingSm", children: blockLabel(block, registry) }),
|
|
1726
|
+
/* @__PURE__ */ jsx9(Text3, { as: "p", variant: "bodySm", tone: "subdued", children: definition?.category ?? "Core block" })
|
|
1451
1727
|
] })
|
|
1452
1728
|
] }),
|
|
1453
|
-
block.type === "core.text" ? /* @__PURE__ */
|
|
1454
|
-
block.type === "core.image" ? /* @__PURE__ */
|
|
1455
|
-
/* @__PURE__ */
|
|
1456
|
-
/* @__PURE__ */
|
|
1457
|
-
assetPicker ? /* @__PURE__ */
|
|
1458
|
-
/* @__PURE__ */
|
|
1729
|
+
block.type === "core.text" ? /* @__PURE__ */ jsx9(InspectorSection, { title: "Content", children: /* @__PURE__ */ jsx9(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, productPicker, pageId, blockId: block.id, i18n, onChange: (content) => onChange({ content }) }) }) : null,
|
|
1730
|
+
block.type === "core.image" ? /* @__PURE__ */ jsxs7(InspectorSection, { title: "Image", children: [
|
|
1731
|
+
/* @__PURE__ */ jsx9(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, productPicker, pageId, blockId: block.id, i18n, onChange: (src) => onChange({ src }) }),
|
|
1732
|
+
/* @__PURE__ */ jsx9(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, productPicker, pageId, blockId: block.id, i18n, onChange: (alt) => onChange({ alt }) }),
|
|
1733
|
+
assetPicker ? /* @__PURE__ */ jsxs7(Fragment2, { children: [
|
|
1734
|
+
/* @__PURE__ */ jsx9(Button2, { disabled: disabled || selectingAsset, onClick: () => void (async () => {
|
|
1459
1735
|
setSelectingAsset(true);
|
|
1460
1736
|
setAssetError(null);
|
|
1461
1737
|
try {
|
|
@@ -1467,13 +1743,13 @@ function DocumentInspector({ settings, pageId, assetPicker, productPicker, i18n,
|
|
|
1467
1743
|
setSelectingAsset(false);
|
|
1468
1744
|
}
|
|
1469
1745
|
})(), children: selectingAsset ? "\u6B63\u5728\u9009\u62E9\u7D20\u6750\u2026" : "\u9009\u62E9\u7D20\u6750" }),
|
|
1470
|
-
assetError ? /* @__PURE__ */
|
|
1746
|
+
assetError ? /* @__PURE__ */ jsx9(Text3, { as: "p", variant: "bodySm", tone: "critical", children: assetError }) : null
|
|
1471
1747
|
] }) : null
|
|
1472
1748
|
] }) : null,
|
|
1473
|
-
Object.entries(groupedFields).map(([group, fields]) => /* @__PURE__ */
|
|
1749
|
+
Object.entries(groupedFields).map(([group, fields]) => /* @__PURE__ */ jsx9(InspectorSection, { title: group, defaultOpen: group !== "Advanced", children: fields.map(([name, field]) => /* @__PURE__ */ jsx9(InspectorField, { name, field, value: field.persist === false ? settings?.values[name] : block.props[name], registry, disabled: disabled || field.persist === false && (!settings || Boolean(settings.disabled)), assetPicker, productPicker, pageId, blockId: block.id, i18n, onChange: (value) => field.persist === false ? settings?.onChange(name, value) : onChange({ [name]: value }) }, name)) }, group)),
|
|
1474
1750
|
Object.values(definition?.fields ?? {}).some((field) => field.persist === false) ? settings?.footer : null,
|
|
1475
|
-
appearanceControls && definition?.variants?.length ? /* @__PURE__ */
|
|
1476
|
-
appearanceControls && definition ? /* @__PURE__ */
|
|
1751
|
+
appearanceControls && definition?.variants?.length ? /* @__PURE__ */ jsx9(InspectorSection, { title: "\u5916\u89C2", children: /* @__PURE__ */ jsx9(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,
|
|
1752
|
+
appearanceControls && definition ? /* @__PURE__ */ jsx9(InspectorSection, { title: "\u6837\u5F0F\u8986\u76D6", defaultOpen: false, children: appearanceTokens.map(([token, label]) => /* @__PURE__ */ jsx9(TextField, { label, value: block.style[token] ?? "", placeholder: "\u7EE7\u627F\u9875\u9762\u6216\u6A21\u677F\u8BBE\u7F6E", autoComplete: "off", disabled, onChange: (value) => {
|
|
1477
1753
|
const style = { ...block.style };
|
|
1478
1754
|
if (value.trim()) style[token] = value;
|
|
1479
1755
|
else delete style[token];
|