@standhigher/puck-page-builder 0.12.5 → 0.12.6
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.js +458 -258
- package/package.json +1 -1
- package/src/styles.css +21 -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) => {
|
|
@@ -755,10 +790,10 @@ function EditorProvider({ initialDocument, registry, policy, loadState = "ready"
|
|
|
755
790
|
redo: () => {
|
|
756
791
|
if (editable) dispatch({ type: "redo" });
|
|
757
792
|
},
|
|
758
|
-
markSaved: (
|
|
793
|
+
markSaved: (document2 = historyRef.current.document) => dispatch({ type: "saved", document: document2 })
|
|
759
794
|
};
|
|
760
795
|
}, [canvasSelectionRequest, confirmCanvasSelection, editable, history, isDirty, loadState, pendingDeleteBlock, pendingDeleteBlockId, policy, registry, replace, requestCanvasSelection, selectedBlock, session, sessionMessage, sessionState, updateBlockPresentation, updateBlockProps, updateFromCanvas]);
|
|
761
|
-
return /* @__PURE__ */
|
|
796
|
+
return /* @__PURE__ */ jsx6(EditorContext.Provider, { value, children });
|
|
762
797
|
}
|
|
763
798
|
function useEditorContext() {
|
|
764
799
|
const context = useContext(EditorContext);
|
|
@@ -768,18 +803,18 @@ function useEditorContext() {
|
|
|
768
803
|
|
|
769
804
|
// src/editor/components/PageStatusCard.tsx
|
|
770
805
|
import { Badge as Badge2, InlineStack as InlineStack2, Text as Text2 } from "@shopify/polaris";
|
|
771
|
-
import { jsx as
|
|
806
|
+
import { jsx as jsx7, jsxs as jsxs5 } from "react/jsx-runtime";
|
|
772
807
|
function PageStatusCard({ status, sessionState }) {
|
|
773
808
|
const publicationTone = status.publicationStatus === "published" ? "success" : "attention";
|
|
774
809
|
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__ */
|
|
810
|
+
return /* @__PURE__ */ jsxs5("div", { className: "pb-page-status-card", "data-testid": "page-status-card", "data-publication-status": status.publicationStatus, "data-session-state": sessionState, children: [
|
|
811
|
+
/* @__PURE__ */ jsxs5(InlineStack2, { gap: "150", blockAlign: "center", wrap: true, children: [
|
|
812
|
+
/* @__PURE__ */ jsx7(Badge2, { tone: publicationTone, children: status.publicationStatus === "published" ? "\u7EBF\u4E0A" : "\u672A\u53D1\u5E03" }),
|
|
813
|
+
status.draftLabel ? /* @__PURE__ */ jsx7(Text2, { as: "span", variant: "bodySm", tone: "subdued", children: status.draftLabel }) : null,
|
|
814
|
+
status.publishedVersionLabel ? /* @__PURE__ */ jsx7(Text2, { as: "span", variant: "bodySm", tone: "subdued", children: status.publishedVersionLabel }) : null,
|
|
815
|
+
sessionLabel ? /* @__PURE__ */ jsx7(Badge2, { tone: sessionState === "lost" ? "critical" : "attention", children: sessionLabel }) : null
|
|
781
816
|
] }),
|
|
782
|
-
status.lastSavedAt ? /* @__PURE__ */
|
|
817
|
+
status.lastSavedAt ? /* @__PURE__ */ jsxs5(Text2, { as: "p", variant: "bodySm", tone: "subdued", children: [
|
|
783
818
|
"\u6700\u540E\u4FDD\u5B58\uFF1A",
|
|
784
819
|
status.lastSavedAt
|
|
785
820
|
] }) : null
|
|
@@ -924,17 +959,197 @@ function createAdminI18n(locale) {
|
|
|
924
959
|
return { locale: resolvedLocale, t: (key) => messages[resolvedLocale][key] };
|
|
925
960
|
}
|
|
926
961
|
|
|
962
|
+
// src/editor/shell/CanvasLibraryDropTarget.tsx
|
|
963
|
+
import { useEffect as useEffect3, useRef as useRef4, useState as useState3 } from "react";
|
|
964
|
+
|
|
927
965
|
// src/editor/shell/drop-position.ts
|
|
928
966
|
function nearestBlockIdAtY(blocks, y) {
|
|
929
967
|
return blocks.find((block) => y < block.top + block.height / 2)?.id;
|
|
930
968
|
}
|
|
931
|
-
|
|
932
|
-
|
|
933
|
-
|
|
969
|
+
|
|
970
|
+
// src/editor/shell/CanvasLibraryDropTarget.tsx
|
|
971
|
+
import { jsx as jsx8, jsxs as jsxs6 } from "react/jsx-runtime";
|
|
972
|
+
function uniqueBlocks(blocks) {
|
|
973
|
+
const seen = /* @__PURE__ */ new Set();
|
|
974
|
+
return blocks.filter((block) => !seen.has(block.id) && seen.add(block.id));
|
|
975
|
+
}
|
|
976
|
+
function scrollableAncestors(start) {
|
|
977
|
+
const result = [];
|
|
978
|
+
let node = start;
|
|
979
|
+
while (node) {
|
|
980
|
+
const style = window.getComputedStyle(node);
|
|
981
|
+
if (["auto", "scroll", "overlay"].includes(style.overflowY) && node.scrollHeight > node.clientHeight) result.push(node);
|
|
982
|
+
node = node.parentElement;
|
|
983
|
+
}
|
|
984
|
+
return result;
|
|
985
|
+
}
|
|
986
|
+
function scrollDelta(pointerY, rect, elapsedMs) {
|
|
987
|
+
const top = Math.max(0, rect.top);
|
|
988
|
+
const bottom = Math.min(window.innerHeight, rect.bottom);
|
|
989
|
+
const height = bottom - top;
|
|
990
|
+
if (height <= 0 || pointerY < top || pointerY > bottom) return 0;
|
|
991
|
+
const edge = Math.min(96, Math.max(36, height * 0.24));
|
|
992
|
+
const speed = 900;
|
|
993
|
+
if (pointerY < top + edge) return -speed * Math.min(1, (top + edge - pointerY) / edge) * elapsedMs / 1e3;
|
|
994
|
+
if (pointerY > bottom - edge) return speed * Math.min(1, (pointerY - (bottom - edge)) / edge) * elapsedMs / 1e3;
|
|
995
|
+
return 0;
|
|
996
|
+
}
|
|
997
|
+
function scrollElement(element, delta) {
|
|
998
|
+
const canScroll = delta < 0 ? element.scrollTop > 0 : element.scrollTop < element.scrollHeight - element.clientHeight;
|
|
999
|
+
if (!delta || !canScroll) return false;
|
|
1000
|
+
if (typeof element.scrollBy === "function") element.scrollBy({ top: delta, behavior: "auto" });
|
|
1001
|
+
else element.scrollTop += delta;
|
|
1002
|
+
return true;
|
|
1003
|
+
}
|
|
1004
|
+
function CanvasLibraryDropTarget({ frameRef, blocks, label, onDrop, onCancel, adminLocale }) {
|
|
1005
|
+
const targetRef = useRef4(null);
|
|
1006
|
+
const latestPreview = useRef4(null);
|
|
1007
|
+
const dragging = useRef4(false);
|
|
1008
|
+
const completed = useRef4(false);
|
|
1009
|
+
const pointerY = useRef4(0);
|
|
1010
|
+
const animationFrame = useRef4(null);
|
|
1011
|
+
const lastFrameTime = useRef4(null);
|
|
1012
|
+
const callbacks = useRef4({ onDrop, onCancel });
|
|
1013
|
+
useEffect3(() => {
|
|
1014
|
+
callbacks.current = { onDrop, onCancel };
|
|
1015
|
+
}, [onDrop, onCancel]);
|
|
1016
|
+
const orderedBlocks = uniqueBlocks(blocks);
|
|
1017
|
+
const [preview, setPreview] = useState3(null);
|
|
1018
|
+
const english = adminLocale?.toLowerCase().startsWith("en") ?? false;
|
|
1019
|
+
const stopAutoScroll = () => {
|
|
1020
|
+
if (animationFrame.current !== null) window.cancelAnimationFrame(animationFrame.current);
|
|
1021
|
+
animationFrame.current = null;
|
|
1022
|
+
lastFrameTime.current = null;
|
|
1023
|
+
};
|
|
1024
|
+
const clear = (cancel) => {
|
|
1025
|
+
stopAutoScroll();
|
|
1026
|
+
dragging.current = false;
|
|
1027
|
+
latestPreview.current = null;
|
|
1028
|
+
setPreview(null);
|
|
1029
|
+
if (cancel) {
|
|
1030
|
+
completed.current = true;
|
|
1031
|
+
callbacks.current.onCancel();
|
|
1032
|
+
}
|
|
1033
|
+
};
|
|
1034
|
+
const calculatePreview = (clientY) => {
|
|
1035
|
+
const target = targetRef.current;
|
|
1036
|
+
const frame = frameRef.current;
|
|
1037
|
+
if (!target || !frame) return null;
|
|
1038
|
+
const targetRect = target.getBoundingClientRect();
|
|
1039
|
+
const frameRect = frame.getBoundingClientRect();
|
|
1040
|
+
const iframe = frame.querySelector("iframe");
|
|
1041
|
+
const iframeDocument = iframe?.contentDocument;
|
|
1042
|
+
const root = iframeDocument ?? frame;
|
|
1043
|
+
const allowed = new Set(orderedBlocks.map((block) => block.id));
|
|
1044
|
+
const byId = /* @__PURE__ */ new Map();
|
|
1045
|
+
const iframeRect = iframeDocument ? iframe?.getBoundingClientRect() : void 0;
|
|
1046
|
+
const scaleY = iframe && iframeRect && iframeRect.height > 0 && iframe.clientHeight > 0 ? iframeRect.height / iframe.clientHeight : 1;
|
|
1047
|
+
const elements = Array.from(root.querySelectorAll("[data-page-document-block-id], [data-puck-dnd]"));
|
|
1048
|
+
for (const element of elements) {
|
|
1049
|
+
const id = element.dataset.pageDocumentBlockId ?? element.dataset.puckDnd;
|
|
1050
|
+
if (!id || !allowed.has(id) || byId.has(id) || element.closest('[aria-hidden="true"], [class*="DragOverlay"]')) continue;
|
|
1051
|
+
const rect = element.getBoundingClientRect();
|
|
1052
|
+
byId.set(id, { id, top: iframeRect ? iframeRect.top + rect.top * scaleY : rect.top, height: iframeRect ? rect.height * scaleY : rect.height });
|
|
1053
|
+
}
|
|
1054
|
+
const candidates = orderedBlocks.flatMap((block) => byId.get(block.id) ?? []);
|
|
1055
|
+
const beforeId = nearestBlockIdAtY(candidates, clientY);
|
|
1056
|
+
const markerCandidate = beforeId ? candidates.find((candidate) => candidate.id === beforeId) : candidates.at(-1);
|
|
1057
|
+
const markerViewportTop = markerCandidate ? beforeId ? markerCandidate.top : markerCandidate.top + markerCandidate.height : Math.min(frameRect.bottom, Math.max(frameRect.top, clientY));
|
|
1058
|
+
return { beforeId, markerTop: Math.max(0, markerViewportTop - targetRect.top), markerLeft: Math.max(0, frameRect.left - targetRect.left), markerWidth: frameRect.width };
|
|
1059
|
+
};
|
|
1060
|
+
const updatePreview = (clientY) => {
|
|
1061
|
+
pointerY.current = clientY;
|
|
1062
|
+
const next = calculatePreview(clientY);
|
|
1063
|
+
const previous = latestPreview.current;
|
|
1064
|
+
latestPreview.current = next;
|
|
1065
|
+
if (previous?.beforeId !== next?.beforeId || previous?.markerTop !== next?.markerTop || previous?.markerLeft !== next?.markerLeft || previous?.markerWidth !== next?.markerWidth) setPreview(next);
|
|
1066
|
+
};
|
|
1067
|
+
const autoScroll = (timestamp) => {
|
|
1068
|
+
if (!dragging.current) return;
|
|
1069
|
+
const elapsedMs = Math.min(64, Math.max(0, timestamp - (lastFrameTime.current ?? timestamp)));
|
|
1070
|
+
lastFrameTime.current = timestamp;
|
|
1071
|
+
const stage = targetRef.current?.parentElement;
|
|
1072
|
+
if (stage) {
|
|
1073
|
+
let scrolled = false;
|
|
1074
|
+
for (const ancestor of scrollableAncestors(stage)) {
|
|
1075
|
+
const delta = scrollDelta(pointerY.current, ancestor.getBoundingClientRect(), elapsedMs);
|
|
1076
|
+
if (scrollElement(ancestor, delta)) {
|
|
1077
|
+
scrolled = true;
|
|
1078
|
+
break;
|
|
1079
|
+
}
|
|
1080
|
+
}
|
|
1081
|
+
const documentScroller = document.scrollingElement;
|
|
1082
|
+
if (!scrolled && documentScroller) {
|
|
1083
|
+
const viewport = new DOMRect(0, 0, window.innerWidth, window.innerHeight);
|
|
1084
|
+
scrollElement(documentScroller, scrollDelta(pointerY.current, viewport, elapsedMs));
|
|
1085
|
+
}
|
|
1086
|
+
updatePreview(pointerY.current);
|
|
1087
|
+
}
|
|
1088
|
+
animationFrame.current = window.requestAnimationFrame(autoScroll);
|
|
1089
|
+
};
|
|
1090
|
+
const startAutoScroll = () => {
|
|
1091
|
+
if (animationFrame.current === null) animationFrame.current = window.requestAnimationFrame(autoScroll);
|
|
1092
|
+
};
|
|
1093
|
+
useEffect3(() => {
|
|
1094
|
+
const cancelOutside = (event) => {
|
|
1095
|
+
if (event.type === "drop" && targetRef.current?.contains(event.target)) return;
|
|
1096
|
+
if (!completed.current) clear(true);
|
|
1097
|
+
};
|
|
1098
|
+
const onKeyDown = (event) => {
|
|
1099
|
+
if (event.key === "Escape" && !completed.current) clear(true);
|
|
1100
|
+
};
|
|
1101
|
+
document.addEventListener("keydown", onKeyDown);
|
|
1102
|
+
document.addEventListener("dragend", cancelOutside, true);
|
|
1103
|
+
document.addEventListener("drop", cancelOutside, true);
|
|
1104
|
+
return () => {
|
|
1105
|
+
document.removeEventListener("keydown", onKeyDown);
|
|
1106
|
+
document.removeEventListener("dragend", cancelOutside, true);
|
|
1107
|
+
document.removeEventListener("drop", cancelOutside, true);
|
|
1108
|
+
stopAutoScroll();
|
|
1109
|
+
};
|
|
1110
|
+
}, []);
|
|
1111
|
+
const handleDragOver = (event) => {
|
|
1112
|
+
event.preventDefault();
|
|
1113
|
+
event.stopPropagation();
|
|
1114
|
+
event.dataTransfer.dropEffect = "copy";
|
|
1115
|
+
completed.current = false;
|
|
1116
|
+
dragging.current = true;
|
|
1117
|
+
updatePreview(event.clientY);
|
|
1118
|
+
startAutoScroll();
|
|
1119
|
+
};
|
|
1120
|
+
const handleDragLeave = (event) => {
|
|
1121
|
+
if (!event.relatedTarget || !event.currentTarget.contains(event.relatedTarget)) clear(false);
|
|
1122
|
+
};
|
|
1123
|
+
const handleDrop = (event) => {
|
|
1124
|
+
event.preventDefault();
|
|
1125
|
+
event.stopPropagation();
|
|
1126
|
+
const next = latestPreview.current ?? calculatePreview(event.clientY);
|
|
1127
|
+
completed.current = true;
|
|
1128
|
+
clear(false);
|
|
1129
|
+
callbacks.current.onDrop(next?.beforeId);
|
|
1130
|
+
};
|
|
1131
|
+
const position = preview?.beforeId ? orderedBlocks.findIndex((block) => block.id === preview.beforeId) + 1 : orderedBlocks.length + 1;
|
|
1132
|
+
const hint = english ? `Release to add ${label}${preview ? ` \xB7 position ${position}` : ""}` : `\u677E\u5F00\u4EE5\u6DFB\u52A0 ${label}${preview ? ` \xB7 \u7B2C ${position} \u4E2A\u4F4D\u7F6E` : ""}`;
|
|
1133
|
+
const style = { position: "absolute", inset: 0, zIndex: 2 };
|
|
1134
|
+
const markerLabel = english ? `Position ${position}` : `\u7B2C ${position} \u4E2A\u4F4D\u7F6E`;
|
|
1135
|
+
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: [
|
|
1136
|
+
/* @__PURE__ */ jsx8("span", { className: "pb-canvas-drop-target__hint", "aria-live": "polite", children: hint }),
|
|
1137
|
+
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
|
|
1138
|
+
] });
|
|
934
1139
|
}
|
|
935
1140
|
|
|
936
1141
|
// src/editor/shell/PageDocumentEditorShell.tsx
|
|
937
|
-
import { Fragment as Fragment2, jsx as
|
|
1142
|
+
import { Fragment as Fragment2, jsx as jsx9, jsxs as jsxs7 } from "react/jsx-runtime";
|
|
1143
|
+
function scrollCanvasBlockIntoView(blockId, frame) {
|
|
1144
|
+
const selector = `[data-page-document-block-id="${CSS.escape(blockId)}"]`;
|
|
1145
|
+
const scroll = () => {
|
|
1146
|
+
const iframe = frame?.querySelector("iframe");
|
|
1147
|
+
const element = iframe?.contentDocument?.querySelector(selector) ?? document.querySelector(selector);
|
|
1148
|
+
element?.scrollIntoView({ block: "start", inline: "nearest" });
|
|
1149
|
+
};
|
|
1150
|
+
if (typeof requestAnimationFrame === "function") requestAnimationFrame(scroll);
|
|
1151
|
+
else scroll();
|
|
1152
|
+
}
|
|
938
1153
|
var deviceLabels2 = { desktop: "desktop", tablet: "tablet", mobile: "mobile" };
|
|
939
1154
|
function blockLabel(block, registry) {
|
|
940
1155
|
return blockTypeLabel(block.type, registry);
|
|
@@ -944,12 +1159,12 @@ function blockTypeLabel(type, registry) {
|
|
|
944
1159
|
if (type === "core.image") return "\u56FE\u7247";
|
|
945
1160
|
return registry?.getBlock(type)?.label ?? type;
|
|
946
1161
|
}
|
|
947
|
-
function validateDocumentBlocks(
|
|
948
|
-
return registry ? validatePageDocumentWithRegistry(
|
|
1162
|
+
function validateDocumentBlocks(document2, registry) {
|
|
1163
|
+
return registry ? validatePageDocumentWithRegistry(document2, registry) : [];
|
|
949
1164
|
}
|
|
950
1165
|
function useEditorSession(adapter, pageId) {
|
|
951
|
-
const [managed, setManaged] =
|
|
952
|
-
|
|
1166
|
+
const [managed, setManaged] = useState4(() => adapter ? { state: "acquiring" } : { state: "active" });
|
|
1167
|
+
useEffect4(() => {
|
|
953
1168
|
let cancelled = false;
|
|
954
1169
|
let session;
|
|
955
1170
|
let heartbeatTimer;
|
|
@@ -991,31 +1206,31 @@ function useEditorSession(adapter, pageId) {
|
|
|
991
1206
|
function PageDocumentEditorShell(props) {
|
|
992
1207
|
const { sessionAdapter, initialDocument, onSessionStateChange } = props;
|
|
993
1208
|
const managedSession = useEditorSession(sessionAdapter, initialDocument.pageId);
|
|
994
|
-
|
|
1209
|
+
useEffect4(() => {
|
|
995
1210
|
onSessionStateChange?.(managedSession.state);
|
|
996
1211
|
}, [managedSession.state, onSessionStateChange]);
|
|
997
|
-
return /* @__PURE__ */
|
|
1212
|
+
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
1213
|
}
|
|
999
1214
|
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
1215
|
const editor = useEditorContext();
|
|
1001
|
-
const editorRef =
|
|
1216
|
+
const editorRef = useRef5(editor);
|
|
1002
1217
|
useLayoutEffect(() => {
|
|
1003
1218
|
editorRef.current = editor;
|
|
1004
1219
|
}, [editor]);
|
|
1005
|
-
const [blockView, setBlockView] =
|
|
1006
|
-
const [leftRailOpen, setLeftRailOpen] =
|
|
1007
|
-
const [rightPanelOpen, setRightPanelOpen] =
|
|
1008
|
-
const [draggingLibraryType, setDraggingLibraryType] =
|
|
1009
|
-
const canvasFrameRef =
|
|
1010
|
-
const [canvasMutationVersion, setCanvasMutationVersion] =
|
|
1011
|
-
const [canvasResetVersion, setCanvasResetVersion] =
|
|
1012
|
-
const [request, setRequest] =
|
|
1013
|
-
const [notice, setNotice] =
|
|
1014
|
-
const [draftRevision, setDraftRevision] =
|
|
1015
|
-
const [isOnline, setIsOnline] =
|
|
1016
|
-
const [saveState, setSaveState] =
|
|
1017
|
-
const [zoom, setZoom] =
|
|
1018
|
-
const [confirmBack, setConfirmBack] =
|
|
1220
|
+
const [blockView, setBlockView] = useState4("blocks");
|
|
1221
|
+
const [leftRailOpen, setLeftRailOpen] = useState4(true);
|
|
1222
|
+
const [rightPanelOpen, setRightPanelOpen] = useState4(true);
|
|
1223
|
+
const [draggingLibraryType, setDraggingLibraryType] = useState4(null);
|
|
1224
|
+
const canvasFrameRef = useRef5(null);
|
|
1225
|
+
const [canvasMutationVersion, setCanvasMutationVersion] = useState4(0);
|
|
1226
|
+
const [canvasResetVersion, setCanvasResetVersion] = useState4(0);
|
|
1227
|
+
const [request, setRequest] = useState4("idle");
|
|
1228
|
+
const [notice, setNotice] = useState4(null);
|
|
1229
|
+
const [draftRevision, setDraftRevision] = useState4(initialDraftRevision);
|
|
1230
|
+
const [isOnline, setIsOnline] = useState4(() => typeof navigator === "undefined" || navigator.onLine);
|
|
1231
|
+
const [saveState, setSaveState] = useState4("saved");
|
|
1232
|
+
const [zoom, setZoom] = useState4("auto");
|
|
1233
|
+
const [confirmBack, setConfirmBack] = useState4(false);
|
|
1019
1234
|
const i18n = createAdminI18n(adminLocale);
|
|
1020
1235
|
const engineData = useMemo2(() => toEngineData(editor.document, registry), [editor.document, registry]);
|
|
1021
1236
|
const canvasThemeStyle = useMemo2(() => {
|
|
@@ -1036,7 +1251,7 @@ function PageDocumentEditor({ iframe = false, registry, adminLocale, onSave, onP
|
|
|
1036
1251
|
insert: editorRef.current.canAddBlock(type)
|
|
1037
1252
|
}), []);
|
|
1038
1253
|
const config = useMemo2(() => createPageDocumentPuckConfig(confirmCanvasSelection, updateFromCanvasInput, selectedBlockId, registry, resolveBlockPermissions), [confirmCanvasSelection, registry, resolveBlockPermissions, selectedBlockId, updateFromCanvasInput]);
|
|
1039
|
-
|
|
1254
|
+
useEffect4(() => {
|
|
1040
1255
|
const online = () => setIsOnline(true);
|
|
1041
1256
|
const offline = () => setIsOnline(false);
|
|
1042
1257
|
window.addEventListener("online", online);
|
|
@@ -1054,14 +1269,14 @@ function PageDocumentEditor({ iframe = false, registry, adminLocale, onSave, onP
|
|
|
1054
1269
|
setSaveState("offline");
|
|
1055
1270
|
return;
|
|
1056
1271
|
}
|
|
1057
|
-
const
|
|
1272
|
+
const document2 = editor.document;
|
|
1058
1273
|
setRequest("saving");
|
|
1059
1274
|
setSaveState("saving");
|
|
1060
1275
|
setNotice(null);
|
|
1061
1276
|
try {
|
|
1062
|
-
const result = draftPersistence ? await draftPersistence.saveDraft({ document, expectedRevision: draftRevision, session: editor.session }) : await onSave?.(
|
|
1277
|
+
const result = draftPersistence ? await draftPersistence.saveDraft({ document: document2, expectedRevision: draftRevision, session: editor.session }) : await onSave?.(document2);
|
|
1063
1278
|
if (result?.revision !== void 0) setDraftRevision(result.revision);
|
|
1064
|
-
editor.markSaved(
|
|
1279
|
+
editor.markSaved(document2);
|
|
1065
1280
|
setSaveState("saved");
|
|
1066
1281
|
} catch {
|
|
1067
1282
|
setNotice("saveFailed");
|
|
@@ -1070,7 +1285,7 @@ function PageDocumentEditor({ iframe = false, registry, adminLocale, onSave, onP
|
|
|
1070
1285
|
setRequest("idle");
|
|
1071
1286
|
}
|
|
1072
1287
|
}, [canPersistDraft, draftPersistence, draftRevision, editor, isOnline, onSave, request, validationIssues.length]);
|
|
1073
|
-
|
|
1288
|
+
useEffect4(() => {
|
|
1074
1289
|
if (!autoSave || !canPersistDraft || !editor.isDirty || resolvedSaveState !== "dirty" && resolvedSaveState !== "failed" || !isOnline || request !== "idle" || validationIssues.length > 0 || editor.sessionState !== "active") return;
|
|
1075
1290
|
const timer = window.setTimeout(() => {
|
|
1076
1291
|
void save();
|
|
@@ -1079,13 +1294,13 @@ function PageDocumentEditor({ iframe = false, registry, adminLocale, onSave, onP
|
|
|
1079
1294
|
}, [autoSave, autoSaveDelayMs, canPersistDraft, editor.isDirty, editor.sessionState, isOnline, request, resolvedSaveState, save, validationIssues.length]);
|
|
1080
1295
|
const publish = async () => {
|
|
1081
1296
|
if (!publishAction && !onPublish || request !== "idle" || validationIssues.length > 0 || !isOnline) return;
|
|
1082
|
-
const
|
|
1297
|
+
const document2 = editor.document;
|
|
1083
1298
|
setRequest("publishing");
|
|
1084
1299
|
setNotice(null);
|
|
1085
1300
|
try {
|
|
1086
|
-
if (publishAction) await publishAction.publish({ document, expectedRevision: draftRevision, session: editor.session, validationIssues });
|
|
1087
|
-
else await onPublish?.(
|
|
1088
|
-
editor.markSaved(
|
|
1301
|
+
if (publishAction) await publishAction.publish({ document: document2, expectedRevision: draftRevision, session: editor.session, validationIssues });
|
|
1302
|
+
else await onPublish?.(document2);
|
|
1303
|
+
editor.markSaved(document2);
|
|
1089
1304
|
setSaveState("saved");
|
|
1090
1305
|
setNotice("published");
|
|
1091
1306
|
} catch {
|
|
@@ -1094,40 +1309,14 @@ function PageDocumentEditor({ iframe = false, registry, adminLocale, onSave, onP
|
|
|
1094
1309
|
setRequest("idle");
|
|
1095
1310
|
}
|
|
1096
1311
|
};
|
|
1097
|
-
if (editor.loadState !== "ready" && editor.loadState !== "success") return /* @__PURE__ */
|
|
1098
|
-
if (editor.sessionState !== "active") return /* @__PURE__ */
|
|
1312
|
+
if (editor.loadState !== "ready" && editor.loadState !== "success") return /* @__PURE__ */ jsx9(EditorStatus, { state: editor.loadState });
|
|
1313
|
+
if (editor.sessionState !== "active") return /* @__PURE__ */ jsx9(EditorSessionStatus, { state: editor.sessionState, message: editor.sessionMessage });
|
|
1099
1314
|
const allBlockTypes = ["core.text", "core.image", ...registry?.blocks.map((block) => block.type) ?? []];
|
|
1100
1315
|
const blockTypes = availableBlockTypes ? allBlockTypes.filter((type) => availableBlockTypes.includes(type)) : allBlockTypes;
|
|
1101
1316
|
const addFromLibrary = (type, beforeId) => {
|
|
1102
1317
|
const id = editor.addBlock(type, beforeId);
|
|
1103
1318
|
if (id) editor.requestCanvasSelection(id);
|
|
1104
1319
|
};
|
|
1105
|
-
const getDropBeforeId = (clientY) => {
|
|
1106
|
-
const frame = canvasFrameRef.current;
|
|
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));
|
|
1129
|
-
setDraggingLibraryType(null);
|
|
1130
|
-
};
|
|
1131
1320
|
const cancelLibraryDrop = (event) => {
|
|
1132
1321
|
event.preventDefault();
|
|
1133
1322
|
event.stopPropagation();
|
|
@@ -1141,58 +1330,63 @@ function PageDocumentEditor({ iframe = false, registry, adminLocale, onSave, onP
|
|
|
1141
1330
|
else onBack();
|
|
1142
1331
|
};
|
|
1143
1332
|
const dismissPublishedNotice = () => setNotice((current) => current === "published" ? null : current);
|
|
1144
|
-
return /* @__PURE__ */
|
|
1145
|
-
/* @__PURE__ */
|
|
1333
|
+
return /* @__PURE__ */ jsxs7(Fragment2, { children: [
|
|
1334
|
+
/* @__PURE__ */ jsx9(Puck2, { config, data: engineData, iframe: { enabled: iframe }, dnd: { behavior: "static" }, overrides: { actionBar: CanvasSelectionActionBar }, onChange: (data) => {
|
|
1146
1335
|
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__ */
|
|
1336
|
+
}, children: /* @__PURE__ */ jsxs7(Puck2.Layout, { children: [
|
|
1337
|
+
/* @__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("|")}` }),
|
|
1338
|
+
/* @__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: [
|
|
1339
|
+
/* @__PURE__ */ jsx9("header", { className: "pb-header", children: /* @__PURE__ */ jsxs7("div", { className: "pb-header-content", children: [
|
|
1340
|
+
/* @__PURE__ */ jsxs7("div", { className: "pb-header-title-group", children: [
|
|
1341
|
+
onBack ? /* @__PURE__ */ jsx9(Button2, { variant: "tertiary", onClick: requestBack, children: i18n.t("back") }) : null,
|
|
1342
|
+
/* @__PURE__ */ jsxs7("div", { className: "pb-page-title", children: [
|
|
1343
|
+
/* @__PURE__ */ jsx9(Text3, { as: "h1", variant: "headingSm", children: editor.document.settings.seoTitle ?? editor.document.pageId }),
|
|
1344
|
+
pageStatus ? /* @__PURE__ */ jsx9(PageStatusCard, { status: pageStatus, sessionState: editor.sessionState }) : null
|
|
1156
1345
|
] })
|
|
1157
1346
|
] }),
|
|
1158
|
-
/* @__PURE__ */
|
|
1159
|
-
/* @__PURE__ */
|
|
1160
|
-
/* @__PURE__ */
|
|
1347
|
+
/* @__PURE__ */ jsx9("div", { className: "pb-header-controls", children: /* @__PURE__ */ jsxs7("div", { className: "pb-header-device-toolbar", children: [
|
|
1348
|
+
/* @__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)) }),
|
|
1349
|
+
/* @__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
1350
|
] }) }),
|
|
1162
|
-
/* @__PURE__ */
|
|
1163
|
-
/* @__PURE__ */
|
|
1164
|
-
/* @__PURE__ */
|
|
1165
|
-
resolvedSaveState === "saved" ? null : /* @__PURE__ */
|
|
1166
|
-
onHistory ? /* @__PURE__ */
|
|
1167
|
-
onPreview ? /* @__PURE__ */
|
|
1168
|
-
onAddToStore ? /* @__PURE__ */
|
|
1169
|
-
/* @__PURE__ */
|
|
1351
|
+
/* @__PURE__ */ jsx9("div", { className: "pb-header-actions", children: /* @__PURE__ */ jsxs7(InlineStack3, { gap: "150", blockAlign: "center", wrap: true, children: [
|
|
1352
|
+
/* @__PURE__ */ jsx9(Button2, { accessibilityLabel: i18n.t("undo"), icon: UndoIcon2, variant: "tertiary", disabled: !editor.actionState.canUndo, onClick: editor.undo }),
|
|
1353
|
+
/* @__PURE__ */ jsx9(Button2, { accessibilityLabel: i18n.t("redo"), icon: RedoIcon2, variant: "tertiary", disabled: !editor.actionState.canRedo, onClick: editor.redo }),
|
|
1354
|
+
resolvedSaveState === "saved" ? null : /* @__PURE__ */ jsx9(Badge3, { tone: saveBadgeTone, children: saveBadgeLabel }),
|
|
1355
|
+
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,
|
|
1356
|
+
onPreview ? /* @__PURE__ */ jsx9(Button2, { disabled: request !== "idle" || !isOnline, onClick: () => void onPreview({ document: editor.document, draftRevision, session: editor.session }), children: i18n.t("preview") }) : null,
|
|
1357
|
+
onAddToStore ? /* @__PURE__ */ jsx9(Button2, { disabled: request !== "idle" || pageStatus?.publicationStatus === "unpublished", onClick: () => void onAddToStore({ document: editor.document, session: editor.session }), children: i18n.t("addToStore") }) : null,
|
|
1358
|
+
/* @__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
1359
|
] }) })
|
|
1171
1360
|
] }) }),
|
|
1172
|
-
editor.loadState === "success" ? /* @__PURE__ */
|
|
1173
|
-
notice && notice !== "published" ? /* @__PURE__ */
|
|
1174
|
-
validationIssues.length > 0 ? /* @__PURE__ */
|
|
1361
|
+
editor.loadState === "success" ? /* @__PURE__ */ jsx9(Banner, { tone: "success", children: i18n.t("success") }) : null,
|
|
1362
|
+
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,
|
|
1363
|
+
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
1364
|
issue.path,
|
|
1176
1365
|
": ",
|
|
1177
1366
|
issue.message
|
|
1178
1367
|
] }, `${issue.path}-${issue.message}`)) }) }) : null,
|
|
1179
|
-
/* @__PURE__ */
|
|
1180
|
-
/* @__PURE__ */
|
|
1181
|
-
/* @__PURE__ */
|
|
1368
|
+
/* @__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: [
|
|
1369
|
+
/* @__PURE__ */ jsxs7("nav", { className: "pb-tool-rail", "aria-label": "\u7F16\u8F91\u5668\u5DE5\u5177", children: [
|
|
1370
|
+
/* @__PURE__ */ jsx9(Button2, { accessibilityLabel: i18n.t("blocks"), icon: LayoutSectionIcon2, pressed: blockView === "blocks" && leftRailOpen, variant: "tertiary", onClick: () => {
|
|
1182
1371
|
setBlockView("blocks");
|
|
1183
1372
|
setLeftRailOpen(true);
|
|
1184
1373
|
} }),
|
|
1185
|
-
/* @__PURE__ */
|
|
1374
|
+
/* @__PURE__ */ jsx9(Button2, { accessibilityLabel: i18n.t("outline"), icon: MenuIcon2, pressed: blockView === "outline" && leftRailOpen, variant: "tertiary", onClick: () => {
|
|
1186
1375
|
setBlockView("outline");
|
|
1187
1376
|
setLeftRailOpen(true);
|
|
1188
1377
|
} })
|
|
1189
1378
|
] }),
|
|
1190
|
-
/* @__PURE__ */
|
|
1191
|
-
/* @__PURE__ */
|
|
1192
|
-
/* @__PURE__ */
|
|
1193
|
-
/* @__PURE__ */
|
|
1379
|
+
/* @__PURE__ */ jsxs7("aside", { className: `pb-left-panel${leftRailOpen ? "" : " pb-panel--closed"}`, "aria-label": "PageDocument \u533A\u5757", children: [
|
|
1380
|
+
/* @__PURE__ */ jsxs7(InlineStack3, { align: "space-between", blockAlign: "center", children: [
|
|
1381
|
+
/* @__PURE__ */ jsx9(Text3, { as: "h2", variant: "headingSm", children: blockView === "blocks" ? i18n.t("blocks") : i18n.t("outline") }),
|
|
1382
|
+
/* @__PURE__ */ jsx9(Button2, { accessibilityLabel: i18n.t("collapseLeft"), icon: XIcon2, variant: "tertiary", onClick: () => setLeftRailOpen(false) })
|
|
1194
1383
|
] }),
|
|
1195
|
-
blockView === "blocks" ? /* @__PURE__ */
|
|
1384
|
+
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: blockTypes.map((type) => /* @__PURE__ */ jsxs7("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" : ""}`, onClick: () => {
|
|
1385
|
+
const block = editor.document.blocks.find((item) => item.type === type);
|
|
1386
|
+
if (!block) return;
|
|
1387
|
+
editor.requestCanvasSelection(block.id);
|
|
1388
|
+
scrollCanvasBlockIntoView(block.id, canvasFrameRef.current);
|
|
1389
|
+
}, onDragStart: (event) => {
|
|
1196
1390
|
if (!editor.canAddBlock(type)) {
|
|
1197
1391
|
event.preventDefault();
|
|
1198
1392
|
return;
|
|
@@ -1201,63 +1395,68 @@ function PageDocumentEditor({ iframe = false, registry, adminLocale, onSave, onP
|
|
|
1201
1395
|
event.dataTransfer.effectAllowed = "copy";
|
|
1202
1396
|
setDraggingLibraryType(type);
|
|
1203
1397
|
}, onDragEnd: () => setDraggingLibraryType(null), children: [
|
|
1204
|
-
/* @__PURE__ */
|
|
1205
|
-
/* @__PURE__ */
|
|
1206
|
-
/* @__PURE__ */
|
|
1398
|
+
/* @__PURE__ */ jsxs7("span", { className: "pb-library-block-title", children: [
|
|
1399
|
+
/* @__PURE__ */ jsx9(Text3, { as: "span", variant: "bodySm", fontWeight: "semibold", children: blockTypeLabel(type, registry) }),
|
|
1400
|
+
/* @__PURE__ */ jsx9("span", { className: "pb-library-block-drag-hint", "aria-hidden": "true", children: /* @__PURE__ */ jsx9(DragHandleIcon2, {}) })
|
|
1207
1401
|
] }),
|
|
1208
|
-
/* @__PURE__ */
|
|
1209
|
-
] }, type)) }) : editor.document.blocks.length === 0 ? /* @__PURE__ */
|
|
1210
|
-
|
|
1211
|
-
|
|
1402
|
+
/* @__PURE__ */ jsx9(Text3, { as: "span", variant: "bodySm", tone: "subdued", children: type })
|
|
1403
|
+
] }, type)) }) : 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: () => {
|
|
1404
|
+
editor.requestCanvasSelection(block.id);
|
|
1405
|
+
scrollCanvasBlockIntoView(block.id, canvasFrameRef.current);
|
|
1406
|
+
}, children: [
|
|
1407
|
+
/* @__PURE__ */ jsx9(Text3, { as: "span", variant: "bodySm", fontWeight: "semibold", children: blockLabel(block, registry) }),
|
|
1408
|
+
/* @__PURE__ */ jsx9(Text3, { as: "span", variant: "bodySm", tone: "subdued", children: block.id })
|
|
1212
1409
|
] }, block.id)) })
|
|
1213
1410
|
] }),
|
|
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
|
|
1411
|
+
/* @__PURE__ */ jsxs7("main", { className: "pb-canvas-area", children: [
|
|
1412
|
+
/* @__PURE__ */ jsxs7("div", { className: "pb-canvas-stage", children: [
|
|
1413
|
+
/* @__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, {}) }),
|
|
1414
|
+
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) => {
|
|
1415
|
+
addFromLibrary(draggingLibraryType, beforeId);
|
|
1416
|
+
setDraggingLibraryType(null);
|
|
1417
|
+
}, onCancel: () => setDraggingLibraryType(null) }) : null
|
|
1225
1418
|
] }),
|
|
1226
|
-
!leftRailOpen || !rightPanelOpen ? /* @__PURE__ */
|
|
1227
|
-
!leftRailOpen ? /* @__PURE__ */
|
|
1228
|
-
!rightPanelOpen ? /* @__PURE__ */
|
|
1419
|
+
!leftRailOpen || !rightPanelOpen ? /* @__PURE__ */ jsxs7("div", { className: "pb-collapsed-actions", children: [
|
|
1420
|
+
!leftRailOpen ? /* @__PURE__ */ jsx9(Button2, { onClick: () => setLeftRailOpen(true), children: i18n.t("expandLeft") }) : null,
|
|
1421
|
+
!rightPanelOpen ? /* @__PURE__ */ jsx9(Button2, { onClick: () => setRightPanelOpen(true), children: i18n.t("expandRight") }) : null
|
|
1229
1422
|
] }) : null
|
|
1230
1423
|
] }),
|
|
1231
|
-
/* @__PURE__ */
|
|
1232
|
-
/* @__PURE__ */
|
|
1233
|
-
/* @__PURE__ */
|
|
1234
|
-
/* @__PURE__ */
|
|
1424
|
+
/* @__PURE__ */ jsxs7("aside", { className: `pb-right-panel${rightPanelOpen ? "" : " pb-panel--closed"}`, "aria-label": "PageDocument \u5C5E\u6027", children: [
|
|
1425
|
+
/* @__PURE__ */ jsxs7(InlineStack3, { align: "space-between", blockAlign: "center", children: [
|
|
1426
|
+
/* @__PURE__ */ jsx9(Text3, { as: "h2", variant: "headingSm", children: i18n.t("properties") }),
|
|
1427
|
+
/* @__PURE__ */ jsx9(Button2, { accessibilityLabel: i18n.t("collapseRight"), icon: XIcon2, variant: "tertiary", onClick: () => setRightPanelOpen(false) })
|
|
1235
1428
|
] }),
|
|
1236
|
-
editor.selectedBlock ? /* @__PURE__ */
|
|
1237
|
-
/* @__PURE__ */
|
|
1238
|
-
/* @__PURE__ */
|
|
1239
|
-
] }) : /* @__PURE__ */
|
|
1429
|
+
editor.selectedBlock ? /* @__PURE__ */ jsxs7(Fragment2, { children: [
|
|
1430
|
+
/* @__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),
|
|
1431
|
+
/* @__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) })
|
|
1432
|
+
] }) : /* @__PURE__ */ jsx9(Text3, { as: "p", tone: "subdued", children: i18n.t("selectBlock") })
|
|
1240
1433
|
] })
|
|
1241
1434
|
] }),
|
|
1242
|
-
editor.pendingDeleteBlock ? /* @__PURE__ */
|
|
1243
|
-
confirmBack ? /* @__PURE__ */
|
|
1435
|
+
editor.pendingDeleteBlock ? /* @__PURE__ */ jsx9(DeleteConfirmation, { block: editor.pendingDeleteBlock, config: deleteConfirmation, i18n, onCancel: editor.cancelDeleteBlock, onConfirm: editor.confirmDeleteBlock }) : null,
|
|
1436
|
+
confirmBack ? /* @__PURE__ */ jsx9(LeaveConfirmation, { i18n, onCancel: () => setConfirmBack(false), onConfirm: () => {
|
|
1244
1437
|
setConfirmBack(false);
|
|
1245
1438
|
onBack?.();
|
|
1246
1439
|
} }) : null
|
|
1247
1440
|
] })
|
|
1248
1441
|
] }) }),
|
|
1249
|
-
/* @__PURE__ */
|
|
1442
|
+
/* @__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
1443
|
] });
|
|
1251
1444
|
}
|
|
1445
|
+
function CanvasSelectionActionBar({ label, children, parentAction }) {
|
|
1446
|
+
void label;
|
|
1447
|
+
void children;
|
|
1448
|
+
void parentAction;
|
|
1449
|
+
return /* @__PURE__ */ jsx9(Fragment2, {});
|
|
1450
|
+
}
|
|
1252
1451
|
function CanvasSelectionBridge({ data, requestedBlockId, onCanvasSelected, canvasMutationVersion, canvasResetVersion, permissionsVersion }) {
|
|
1253
1452
|
const puck = usePuck();
|
|
1254
|
-
const lastSelectedId =
|
|
1255
|
-
const lastSyncedData =
|
|
1256
|
-
const lastCanvasMutationVersion =
|
|
1257
|
-
const lastCanvasResetVersion =
|
|
1453
|
+
const lastSelectedId = useRef5(null);
|
|
1454
|
+
const lastSyncedData = useRef5(null);
|
|
1455
|
+
const lastCanvasMutationVersion = useRef5(0);
|
|
1456
|
+
const lastCanvasResetVersion = useRef5(0);
|
|
1258
1457
|
const serializedData = JSON.stringify(data);
|
|
1259
1458
|
const refreshPermissions = puck.refreshPermissions;
|
|
1260
|
-
|
|
1459
|
+
useEffect4(() => {
|
|
1261
1460
|
const forceReset = canvasResetVersion > lastCanvasResetVersion.current;
|
|
1262
1461
|
if (lastSyncedData.current === serializedData && !forceReset) return;
|
|
1263
1462
|
lastSyncedData.current = serializedData;
|
|
@@ -1268,16 +1467,17 @@ function CanvasSelectionBridge({ data, requestedBlockId, onCanvasSelected, canva
|
|
|
1268
1467
|
}
|
|
1269
1468
|
puck.dispatch({ type: "setData", data });
|
|
1270
1469
|
}, [canvasMutationVersion, canvasResetVersion, data, puck, serializedData]);
|
|
1271
|
-
|
|
1470
|
+
useEffect4(() => {
|
|
1272
1471
|
refreshPermissions?.({}, true);
|
|
1273
1472
|
}, [permissionsVersion, refreshPermissions]);
|
|
1274
|
-
|
|
1473
|
+
useEffect4(() => {
|
|
1275
1474
|
if (!requestedBlockId) return;
|
|
1276
1475
|
const selector = puck.getSelectorForId(requestedBlockId);
|
|
1277
1476
|
if (selector) puck.dispatch({ type: "setUi", ui: { itemSelector: selector } });
|
|
1477
|
+
scrollCanvasBlockIntoView(requestedBlockId);
|
|
1278
1478
|
}, [puck, requestedBlockId]);
|
|
1279
1479
|
const selectedId = typeof puck.selectedItem?.props.id === "string" ? puck.selectedItem.props.id : null;
|
|
1280
|
-
|
|
1480
|
+
useEffect4(() => {
|
|
1281
1481
|
if (selectedId && lastSelectedId.current !== selectedId) {
|
|
1282
1482
|
lastSelectedId.current = selectedId;
|
|
1283
1483
|
onCanvasSelected(selectedId);
|
|
@@ -1289,32 +1489,32 @@ function EditorStatus({ state }) {
|
|
|
1289
1489
|
const i18n = createAdminI18n();
|
|
1290
1490
|
const tone = state === "error" ? "critical" : state === "disabled" ? "warning" : "info";
|
|
1291
1491
|
const message = state === "loading" ? i18n.t("loading") : state === "empty" ? i18n.t("empty") : state === "error" ? i18n.t("error") : i18n.t("disabled");
|
|
1292
|
-
return /* @__PURE__ */
|
|
1492
|
+
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
1493
|
}
|
|
1294
1494
|
function EditorSessionStatus({ state, message }) {
|
|
1295
1495
|
const i18n = createAdminI18n();
|
|
1296
1496
|
const tone = state === "locked" ? "warning" : state === "readonly" ? "info" : "critical";
|
|
1297
1497
|
const title = state === "acquiring" ? i18n.t("acquiringLock") : state === "locked" ? i18n.t("locked") : state === "readonly" ? i18n.t("readonly") : i18n.t("lockLost");
|
|
1298
|
-
return /* @__PURE__ */
|
|
1498
|
+
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
1499
|
}
|
|
1300
1500
|
function InspectorSection({ title, children, defaultOpen = true }) {
|
|
1301
|
-
return /* @__PURE__ */
|
|
1302
|
-
/* @__PURE__ */
|
|
1303
|
-
/* @__PURE__ */
|
|
1304
|
-
/* @__PURE__ */
|
|
1501
|
+
return /* @__PURE__ */ jsxs7("details", { className: "pb-inspector-section", open: defaultOpen, children: [
|
|
1502
|
+
/* @__PURE__ */ jsxs7("summary", { children: [
|
|
1503
|
+
/* @__PURE__ */ jsx9("span", { children: title }),
|
|
1504
|
+
/* @__PURE__ */ jsx9("span", { "aria-hidden": "true", children: "\u2304" })
|
|
1305
1505
|
] }),
|
|
1306
|
-
/* @__PURE__ */
|
|
1506
|
+
/* @__PURE__ */ jsx9("div", { className: "pb-inspector-section__body", children })
|
|
1307
1507
|
] });
|
|
1308
1508
|
}
|
|
1309
1509
|
function InspectorTextControl({ label, value, control, maxLength, disabled, onChange }) {
|
|
1310
1510
|
const stringValue = typeof value === "string" ? value : "";
|
|
1311
|
-
if (control === "color") return /* @__PURE__ */
|
|
1511
|
+
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
1512
|
const length = Array.from(stringValue).length;
|
|
1313
|
-
const field = /* @__PURE__ */
|
|
1513
|
+
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
1514
|
if (maxLength === void 0) return field;
|
|
1315
|
-
return /* @__PURE__ */
|
|
1515
|
+
return /* @__PURE__ */ jsxs7("div", { className: "pb-inspector-field__limited", children: [
|
|
1316
1516
|
field,
|
|
1317
|
-
/* @__PURE__ */
|
|
1517
|
+
/* @__PURE__ */ jsxs7("span", { className: "pb-inspector-field__limit", "aria-label": `Limit ${maxLength}`, children: [
|
|
1318
1518
|
length,
|
|
1319
1519
|
"/",
|
|
1320
1520
|
maxLength
|
|
@@ -1322,20 +1522,20 @@ function InspectorTextControl({ label, value, control, maxLength, disabled, onCh
|
|
|
1322
1522
|
] });
|
|
1323
1523
|
}
|
|
1324
1524
|
function InspectorAssetControl({ value, disabled, picker, pageId, blockId, i18n, onChange }) {
|
|
1325
|
-
const [busy, setBusy] =
|
|
1326
|
-
const [error, setError] =
|
|
1327
|
-
const active =
|
|
1328
|
-
|
|
1525
|
+
const [busy, setBusy] = useState4(false);
|
|
1526
|
+
const [error, setError] = useState4(null);
|
|
1527
|
+
const active = useRef5(true);
|
|
1528
|
+
useEffect4(() => {
|
|
1329
1529
|
active.current = !disabled;
|
|
1330
1530
|
return () => {
|
|
1331
1531
|
active.current = false;
|
|
1332
1532
|
};
|
|
1333
1533
|
}, [disabled]);
|
|
1334
1534
|
const url = typeof value === "string" && validateFieldValue({ field: "", control: "asset" }, value).length === 0 ? value : "";
|
|
1335
|
-
return /* @__PURE__ */
|
|
1336
|
-
url ? /* @__PURE__ */
|
|
1337
|
-
url ? /* @__PURE__ */
|
|
1338
|
-
/* @__PURE__ */
|
|
1535
|
+
return /* @__PURE__ */ jsxs7("div", { className: "pb-asset-picker", "data-testid": "asset-picker", children: [
|
|
1536
|
+
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") }),
|
|
1537
|
+
url ? /* @__PURE__ */ jsx9(Button2, { fullWidth: true, variant: "tertiary", disabled: disabled || busy, onClick: () => onChange(""), children: i18n.t("removeAsset") }) : null,
|
|
1538
|
+
/* @__PURE__ */ jsx9(Button2, { fullWidth: true, disabled: disabled || busy || !picker, onClick: () => void (async () => {
|
|
1339
1539
|
if (!picker) return;
|
|
1340
1540
|
setBusy(true);
|
|
1341
1541
|
setError(null);
|
|
@@ -1351,20 +1551,20 @@ function InspectorAssetControl({ value, disabled, picker, pageId, blockId, i18n,
|
|
|
1351
1551
|
setBusy(false);
|
|
1352
1552
|
}
|
|
1353
1553
|
})(), children: busy ? i18n.t("selectingAsset") : i18n.t("selectAsset") }),
|
|
1354
|
-
error ? /* @__PURE__ */
|
|
1554
|
+
error ? /* @__PURE__ */ jsx9(Text3, { as: "p", variant: "bodySm", tone: "critical", children: error }) : null
|
|
1355
1555
|
] });
|
|
1356
1556
|
}
|
|
1357
1557
|
function InspectorProductsControl({ value, disabled, picker, pageId, blockId, i18n, onChange }) {
|
|
1358
1558
|
const products = parseProductReferences(value);
|
|
1359
|
-
const [busy, setBusy] =
|
|
1360
|
-
const [error, setError] =
|
|
1559
|
+
const [busy, setBusy] = useState4(false);
|
|
1560
|
+
const [error, setError] = useState4(null);
|
|
1361
1561
|
const preview = products.slice(0, 4);
|
|
1362
|
-
return /* @__PURE__ */
|
|
1363
|
-
/* @__PURE__ */
|
|
1364
|
-
preview.length ? /* @__PURE__ */
|
|
1365
|
-
/* @__PURE__ */
|
|
1562
|
+
return /* @__PURE__ */ jsxs7("div", { className: "pb-product-picker", "data-testid": "product-picker", children: [
|
|
1563
|
+
/* @__PURE__ */ jsxs7("div", { className: "pb-product-picker__summary", children: [
|
|
1564
|
+
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,
|
|
1565
|
+
/* @__PURE__ */ jsx9(Text3, { as: "p", variant: "bodySm", children: products.length ? `${products.length} ${i18n.t("productCountSuffix")}` : i18n.t("emptyProducts") })
|
|
1366
1566
|
] }),
|
|
1367
|
-
/* @__PURE__ */
|
|
1567
|
+
/* @__PURE__ */ jsx9(Button2, { fullWidth: true, icon: ProductIcon, variant: "secondary", disabled: disabled || busy || !picker, onClick: () => void (async () => {
|
|
1368
1568
|
if (!picker) return;
|
|
1369
1569
|
setBusy(true);
|
|
1370
1570
|
setError(null);
|
|
@@ -1377,50 +1577,50 @@ function InspectorProductsControl({ value, disabled, picker, pageId, blockId, i1
|
|
|
1377
1577
|
setBusy(false);
|
|
1378
1578
|
}
|
|
1379
1579
|
})(), children: busy ? i18n.t("selectingProducts") : i18n.t("selectProducts") }),
|
|
1380
|
-
error ? /* @__PURE__ */
|
|
1580
|
+
error ? /* @__PURE__ */ jsx9(Text3, { as: "p", variant: "bodySm", tone: "critical", children: error }) : null
|
|
1381
1581
|
] });
|
|
1382
1582
|
}
|
|
1383
1583
|
function InspectorField({ name, field, value, registry, disabled, assetPicker, productPicker, pageId, blockId, i18n, onChange }) {
|
|
1384
1584
|
const label = field.label ?? name;
|
|
1385
1585
|
const issues = validateFieldValue(field, value);
|
|
1386
1586
|
const Field = registry?.getField(field.field)?.component;
|
|
1387
|
-
return /* @__PURE__ */
|
|
1388
|
-
/* @__PURE__ */
|
|
1389
|
-
/* @__PURE__ */
|
|
1390
|
-
field.description ? /* @__PURE__ */
|
|
1587
|
+
return /* @__PURE__ */ jsxs7("div", { className: "pb-inspector-field", "data-control": field.control ?? "custom", children: [
|
|
1588
|
+
/* @__PURE__ */ jsxs7("div", { className: "pb-inspector-field__heading", children: [
|
|
1589
|
+
/* @__PURE__ */ jsx9(Text3, { as: "p", variant: "bodySm", fontWeight: "semibold", children: label }),
|
|
1590
|
+
field.description ? /* @__PURE__ */ jsx9(Text3, { as: "p", variant: "bodySm", tone: "subdued", children: field.description }) : null
|
|
1391
1591
|
] }),
|
|
1392
|
-
field.control === "products" ? /* @__PURE__ */
|
|
1393
|
-
issues.map((issue) => /* @__PURE__ */
|
|
1592
|
+
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,
|
|
1593
|
+
issues.map((issue) => /* @__PURE__ */ jsx9(Text3, { as: "p", variant: "bodySm", tone: "critical", children: issue.message }, issue.message))
|
|
1394
1594
|
] });
|
|
1395
1595
|
}
|
|
1396
1596
|
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__ */
|
|
1597
|
+
return /* @__PURE__ */ jsxs7("div", { className: "pb-inspector-actions", "aria-label": `Actions for ${block.id}`, children: [
|
|
1598
|
+
/* @__PURE__ */ jsxs7(ButtonGroup2, { children: [
|
|
1599
|
+
/* @__PURE__ */ jsx9(Button2, { disabled: !canMove || !canMoveUp, onClick: () => onMove(-1), children: i18n.t("moveUp") }),
|
|
1600
|
+
/* @__PURE__ */ jsx9(Button2, { disabled: !canMove || !canMoveDown, onClick: () => onMove(1), children: i18n.t("moveDown") }),
|
|
1601
|
+
/* @__PURE__ */ jsx9(Button2, { disabled: !canDuplicate, accessibilityLabel: canDuplicate ? i18n.t("duplicate") : i18n.t("duplicateUnavailable"), onClick: onDuplicate, children: i18n.t("duplicate") }),
|
|
1602
|
+
/* @__PURE__ */ jsx9(Button2, { disabled: !canDelete, tone: "critical", onClick: onDelete, children: i18n.t("remove") })
|
|
1403
1603
|
] }),
|
|
1404
|
-
!canDuplicate ? /* @__PURE__ */
|
|
1604
|
+
!canDuplicate ? /* @__PURE__ */ jsx9(Text3, { as: "p", variant: "bodySm", tone: "subdued", children: i18n.t("duplicateUnavailable") }) : null
|
|
1405
1605
|
] });
|
|
1406
1606
|
}
|
|
1407
1607
|
function DeleteConfirmation({ block, config, i18n, onCancel, onConfirm }) {
|
|
1408
|
-
return /* @__PURE__ */
|
|
1409
|
-
/* @__PURE__ */
|
|
1410
|
-
/* @__PURE__ */
|
|
1411
|
-
/* @__PURE__ */
|
|
1412
|
-
/* @__PURE__ */
|
|
1413
|
-
/* @__PURE__ */
|
|
1608
|
+
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: [
|
|
1609
|
+
/* @__PURE__ */ jsx9(Text3, { as: "h2", variant: "headingMd", id: "pb-delete-confirmation-title", children: config?.title ?? i18n.t("confirmDeleteTitle") }),
|
|
1610
|
+
/* @__PURE__ */ jsx9(Text3, { as: "p", variant: "bodyMd", children: config?.message?.(block) ?? i18n.t("confirmDeleteMessage") }),
|
|
1611
|
+
/* @__PURE__ */ jsxs7(ButtonGroup2, { children: [
|
|
1612
|
+
/* @__PURE__ */ jsx9(Button2, { onClick: onCancel, children: config?.cancelLabel ?? i18n.t("cancel") }),
|
|
1613
|
+
/* @__PURE__ */ jsx9(Button2, { tone: "critical", onClick: onConfirm, children: config?.confirmLabel ?? i18n.t("confirm") })
|
|
1414
1614
|
] })
|
|
1415
1615
|
] }) });
|
|
1416
1616
|
}
|
|
1417
1617
|
function LeaveConfirmation({ i18n, onCancel, onConfirm }) {
|
|
1418
|
-
return /* @__PURE__ */
|
|
1419
|
-
/* @__PURE__ */
|
|
1420
|
-
/* @__PURE__ */
|
|
1421
|
-
/* @__PURE__ */
|
|
1422
|
-
/* @__PURE__ */
|
|
1423
|
-
/* @__PURE__ */
|
|
1618
|
+
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: [
|
|
1619
|
+
/* @__PURE__ */ jsx9(Text3, { as: "h2", variant: "headingMd", id: "pb-leave-confirmation-title", children: i18n.t("confirmLeaveTitle") }),
|
|
1620
|
+
/* @__PURE__ */ jsx9(Text3, { as: "p", variant: "bodyMd", children: i18n.t("leaveWarning") }),
|
|
1621
|
+
/* @__PURE__ */ jsxs7(ButtonGroup2, { children: [
|
|
1622
|
+
/* @__PURE__ */ jsx9(Button2, { onClick: onCancel, children: i18n.t("cancel") }),
|
|
1623
|
+
/* @__PURE__ */ jsx9(Button2, { tone: "critical", onClick: onConfirm, children: i18n.t("leave") })
|
|
1424
1624
|
] })
|
|
1425
1625
|
] }) });
|
|
1426
1626
|
}
|
|
@@ -1432,8 +1632,8 @@ function inspectorFieldConfig(name, field) {
|
|
|
1432
1632
|
}
|
|
1433
1633
|
var appearanceTokens = [["color.primary", "\u4E3B\u8272"], ["color.surface", "\u8868\u9762\u8272"], ["radius", "\u5706\u89D2"], ["spacing", "\u95F4\u8DDD"]];
|
|
1434
1634
|
function DocumentInspector({ settings, pageId, assetPicker, productPicker, i18n, block, registry, disabled, appearanceControls, onChange, onPresentationChange }) {
|
|
1435
|
-
const [assetError, setAssetError] =
|
|
1436
|
-
const [selectingAsset, setSelectingAsset] =
|
|
1635
|
+
const [assetError, setAssetError] = useState4(null);
|
|
1636
|
+
const [selectingAsset, setSelectingAsset] = useState4(false);
|
|
1437
1637
|
const definition = registry?.getBlock(block.type);
|
|
1438
1638
|
const groupedFields = definition ? Object.entries(definition.fields).reduce((groups, entry) => {
|
|
1439
1639
|
const [name, field] = entry;
|
|
@@ -1442,20 +1642,20 @@ function DocumentInspector({ settings, pageId, assetPicker, productPicker, i18n,
|
|
|
1442
1642
|
(groups[group] ??= []).push([name, configuredField]);
|
|
1443
1643
|
return groups;
|
|
1444
1644
|
}, {}) : {};
|
|
1445
|
-
return /* @__PURE__ */
|
|
1446
|
-
/* @__PURE__ */
|
|
1447
|
-
/* @__PURE__ */
|
|
1448
|
-
/* @__PURE__ */
|
|
1449
|
-
/* @__PURE__ */
|
|
1450
|
-
/* @__PURE__ */
|
|
1645
|
+
return /* @__PURE__ */ jsxs7("div", { className: "pb-inspector", "data-testid": "document-inspector", children: [
|
|
1646
|
+
/* @__PURE__ */ jsxs7("header", { className: "pb-inspector__header", children: [
|
|
1647
|
+
/* @__PURE__ */ jsx9(Badge3, { children: block.type }),
|
|
1648
|
+
/* @__PURE__ */ jsxs7("div", { children: [
|
|
1649
|
+
/* @__PURE__ */ jsx9(Text3, { as: "p", variant: "headingSm", children: blockLabel(block, registry) }),
|
|
1650
|
+
/* @__PURE__ */ jsx9(Text3, { as: "p", variant: "bodySm", tone: "subdued", children: definition?.category ?? "Core block" })
|
|
1451
1651
|
] })
|
|
1452
1652
|
] }),
|
|
1453
|
-
block.type === "core.text" ? /* @__PURE__ */
|
|
1454
|
-
block.type === "core.image" ? /* @__PURE__ */
|
|
1455
|
-
/* @__PURE__ */
|
|
1456
|
-
/* @__PURE__ */
|
|
1457
|
-
assetPicker ? /* @__PURE__ */
|
|
1458
|
-
/* @__PURE__ */
|
|
1653
|
+
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,
|
|
1654
|
+
block.type === "core.image" ? /* @__PURE__ */ jsxs7(InspectorSection, { title: "Image", children: [
|
|
1655
|
+
/* @__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 }) }),
|
|
1656
|
+
/* @__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 }) }),
|
|
1657
|
+
assetPicker ? /* @__PURE__ */ jsxs7(Fragment2, { children: [
|
|
1658
|
+
/* @__PURE__ */ jsx9(Button2, { disabled: disabled || selectingAsset, onClick: () => void (async () => {
|
|
1459
1659
|
setSelectingAsset(true);
|
|
1460
1660
|
setAssetError(null);
|
|
1461
1661
|
try {
|
|
@@ -1467,13 +1667,13 @@ function DocumentInspector({ settings, pageId, assetPicker, productPicker, i18n,
|
|
|
1467
1667
|
setSelectingAsset(false);
|
|
1468
1668
|
}
|
|
1469
1669
|
})(), children: selectingAsset ? "\u6B63\u5728\u9009\u62E9\u7D20\u6750\u2026" : "\u9009\u62E9\u7D20\u6750" }),
|
|
1470
|
-
assetError ? /* @__PURE__ */
|
|
1670
|
+
assetError ? /* @__PURE__ */ jsx9(Text3, { as: "p", variant: "bodySm", tone: "critical", children: assetError }) : null
|
|
1471
1671
|
] }) : null
|
|
1472
1672
|
] }) : null,
|
|
1473
|
-
Object.entries(groupedFields).map(([group, fields]) => /* @__PURE__ */
|
|
1673
|
+
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
1674
|
Object.values(definition?.fields ?? {}).some((field) => field.persist === false) ? settings?.footer : null,
|
|
1475
|
-
appearanceControls && definition?.variants?.length ? /* @__PURE__ */
|
|
1476
|
-
appearanceControls && definition ? /* @__PURE__ */
|
|
1675
|
+
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,
|
|
1676
|
+
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
1677
|
const style = { ...block.style };
|
|
1478
1678
|
if (value.trim()) style[token] = value;
|
|
1479
1679
|
else delete style[token];
|
package/package.json
CHANGED
package/src/styles.css
CHANGED
|
@@ -90,16 +90,27 @@ button:focus-visible, [role="button"]:focus-visible { outline: 2px solid var(--b
|
|
|
90
90
|
.pb-canvas-area { display: flex; flex-direction: column; gap: var(--builder-space-3); min-width: 0; min-height: 0; padding: var(--builder-space-4); overflow: auto; background: var(--builder-canvas-bg); }
|
|
91
91
|
.pb-canvas-toolbar { padding: var(--builder-space-2); border: 1px solid var(--builder-border); border-radius: var(--builder-panel-radius); background: var(--builder-surface); }
|
|
92
92
|
.pb-canvas-stage { position: relative; display: block; padding: 0; height: auto; }
|
|
93
|
-
.pb-canvas-frame { width: 100%; height: auto; margin: 0 auto; overflow: visible; border: 1px solid var(--builder-border); border-radius: var(--builder-canvas-radius); background: var(--builder-surface); box-shadow: var(--builder-canvas-shadow); transition: width 160ms ease, transform 160ms ease; }
|
|
93
|
+
.pb-canvas-frame { --puck-color-line-placeholder: var(--builder-accent); --puck-line-placeholder-width: 3px; width: 100%; height: auto; margin: 0 auto; overflow: visible; border: 1px solid var(--builder-border); border-radius: var(--builder-canvas-radius); background: var(--builder-surface); box-shadow: var(--builder-canvas-shadow); transition: width 160ms ease, transform 160ms ease; }
|
|
94
94
|
.pb-canvas-frame iframe { display: block; width: 100%; height: auto !important; min-height: 0 !important; border: 0; }
|
|
95
95
|
.pb-canvas-frame [class*="PuckPreview"] { position: relative; height: auto !important; }
|
|
96
|
-
.pb-canvas-
|
|
96
|
+
.pb-canvas-frame [data-puck-component] { cursor: grab; }
|
|
97
|
+
.pb-canvas-frame [data-puck-component]:active, .pb-canvas-frame [data-dnd-dragging] { cursor: grabbing; }
|
|
98
|
+
.pb-canvas-frame [data-puck-disabled] { cursor: pointer; }
|
|
99
|
+
.pb-canvas-frame [data-puck-component] [contenteditable="true"], .pb-canvas-frame [data-puck-component] input, .pb-canvas-frame [data-puck-component] textarea { cursor: text; }
|
|
100
|
+
.pb-canvas-drop-target { position: absolute; inset: 0; z-index: 2; display: grid; place-items: start center; min-height: 12rem; border: 0; border-radius: var(--builder-canvas-radius); color: var(--builder-accent); background: transparent; font-weight: 600; pointer-events: auto; }
|
|
101
|
+
.pb-canvas-drop-target__hint { position: sticky; top: var(--builder-space-3); z-index: 1; margin-top: var(--builder-space-3); padding: 6px 10px; border: 1px solid color-mix(in srgb, var(--builder-accent) 28%, transparent); border-radius: 999px; color: var(--builder-accent); background: color-mix(in srgb, var(--builder-surface) 92%, var(--builder-accent-subtle)); box-shadow: 0 4px 12px rgb(15 23 42 / 10%); font-size: 12px; line-height: 1.2; pointer-events: none; }
|
|
102
|
+
.pb-canvas-drop-target:has(.pb-canvas-drop-marker) > .pb-canvas-drop-target__hint { opacity: 0; }
|
|
103
|
+
.pb-canvas-drop-marker { position: absolute; z-index: 2; height: 3px; min-height: 3px; border-radius: 999px; background: var(--builder-accent); box-shadow: 0 0 0 2px color-mix(in srgb, var(--builder-accent) 16%, transparent), 0 2px 8px color-mix(in srgb, var(--builder-accent) 38%, transparent); transform: translateY(-50%); pointer-events: none; }
|
|
104
|
+
.pb-canvas-drop-marker::before, .pb-canvas-drop-marker::after { position: absolute; top: 50%; width: 7px; height: 7px; border-radius: 50%; background: var(--builder-accent); box-shadow: 0 1px 4px color-mix(in srgb, var(--builder-accent) 38%, transparent); content: ""; transform: translateY(-50%); }
|
|
105
|
+
.pb-canvas-drop-marker::before { left: -2px; }
|
|
106
|
+
.pb-canvas-drop-marker::after { right: -2px; }
|
|
107
|
+
.pb-canvas-drop-marker__label { position: absolute; top: -8px; left: 50%; padding: 3px 8px; border-radius: 999px; color: var(--builder-accent); background: var(--builder-surface); box-shadow: 0 2px 8px rgb(15 23 42 / 12%); font-size: 11px; line-height: 1.2; white-space: nowrap; transform: translate(-50%, -100%); pointer-events: none; }
|
|
97
108
|
.pb-canvas-frame--tablet { width: min(100%, 768px); }
|
|
98
109
|
.pb-canvas-frame--mobile { width: min(100%, 390px); }
|
|
99
110
|
.pb-canvas-frame--full { width: 100%; }
|
|
100
|
-
.pb-canvas-frame--zoom-50 {
|
|
101
|
-
.pb-canvas-frame--zoom-70 {
|
|
102
|
-
.pb-canvas-frame--zoom-100 {
|
|
111
|
+
.pb-canvas-frame--zoom-50 { zoom: 0.5; }
|
|
112
|
+
.pb-canvas-frame--zoom-70 { zoom: 0.7; }
|
|
113
|
+
.pb-canvas-frame--zoom-100 { zoom: 1; }
|
|
103
114
|
.pb-canvas-overlay { position: absolute; top: var(--builder-space-2); left: 50%; display: flex; gap: var(--builder-space-2); padding: var(--builder-space-1) var(--builder-space-2); border: 2px solid var(--builder-accent); border-radius: var(--builder-control-radius); color: var(--builder-accent); background: var(--builder-surface); font-size: 12px; font-weight: 600; transform: translateX(-50%); box-shadow: var(--builder-canvas-shadow); pointer-events: none; }
|
|
104
115
|
.pb-canvas-overlay span:last-child { color: var(--builder-text-muted); font-weight: 500; }
|
|
105
116
|
.pb-collapsed-actions { display: flex; gap: var(--builder-space-2); }
|
|
@@ -115,6 +126,8 @@ button:focus-visible, [role="button"]:focus-visible { outline: 2px solid var(--b
|
|
|
115
126
|
.pb-document-block-row { display: flex; align-items: center; gap: var(--builder-space-2); padding: var(--builder-space-2); border: 1px solid transparent; border-radius: var(--builder-panel-radius); background: transparent; }
|
|
116
127
|
.pb-document-block-row--library { width: 100%; flex-direction: column; align-items: flex-start; text-align: left; color: var(--builder-text); font: inherit; cursor: grab; }
|
|
117
128
|
.pb-document-block-row--library:active { cursor: grabbing; }
|
|
129
|
+
.pb-document-block-row--library[aria-disabled="true"] { cursor: default; }
|
|
130
|
+
.pb-document-block-row--library[type="button"] { cursor: pointer; }
|
|
118
131
|
.pb-library-block-title { display: flex; align-items: center; justify-content: space-between; width: 100%; gap: var(--builder-space-2); }
|
|
119
132
|
.pb-library-block-drag-hint { display: inline-flex; color: var(--builder-text-muted); pointer-events: none; }
|
|
120
133
|
.pb-library-block-drag-hint svg { width: 16px; height: 16px; }
|
|
@@ -128,13 +141,14 @@ button:focus-visible, [role="button"]:focus-visible { outline: 2px solid var(--b
|
|
|
128
141
|
.pb-toast-host .Polaris-Frame { min-height: 0; width: 0; height: 0; overflow: visible; background: transparent; }
|
|
129
142
|
.pb-toast-host .Polaris-Frame__Skip,
|
|
130
143
|
.pb-toast-host .Polaris-Frame__Main { display: none; }
|
|
131
|
-
.pb-document-canvas__text, .pb-document-canvas__image { max-width: 760px; margin: 0 auto; padding: 48px; color: #1d2939; background: #fff; cursor:
|
|
144
|
+
.pb-document-canvas__text, .pb-document-canvas__image { max-width: 760px; margin: 0 auto; padding: 48px; color: #1d2939; background: #fff; cursor: grab; }
|
|
145
|
+
.pb-document-canvas__extension { cursor: grab; }
|
|
132
146
|
.pb-document-canvas__text { font-size: clamp(32px, 4vw, 52px); font-weight: 650; line-height: 1.1; letter-spacing: -.03em; }
|
|
133
147
|
.pb-document-canvas__text p { margin: 0; }
|
|
134
148
|
.pb-document-canvas__text p[contenteditable="true"] { /* outline: 1px dashed var(--builder-accent); outline-offset: 8px; */ cursor: text; }
|
|
135
149
|
.pb-document-canvas__image { padding-top: 0; }
|
|
136
150
|
.pb-document-canvas__image img { display: block; width: 100%; border-radius: 12px; }
|
|
137
|
-
.pb-document-canvas__image input { width: 100%; margin-top: var(--builder-space-3); padding: var(--builder-space-2); border: 1px solid var(--builder-accent); border-radius: var(--builder-control-radius); color: var(--builder-text); background: var(--builder-surface); font: inherit; }
|
|
151
|
+
.pb-document-canvas__image input { width: 100%; margin-top: var(--builder-space-3); padding: var(--builder-space-2); border: 1px solid var(--builder-accent); border-radius: var(--builder-control-radius); color: var(--builder-text); background: var(--builder-surface); font: inherit; cursor: text; }
|
|
138
152
|
.pb-document-export { max-height: 420px; padding: var(--builder-space-3); overflow: auto; border-radius: var(--builder-control-radius); color: var(--builder-text); background: var(--builder-surface-subtle); font: 12px/1.5 ui-monospace, SFMono-Regular, Menlo, monospace; white-space: pre-wrap; }
|
|
139
153
|
.pb-web-renderer { min-height: 100vh; padding: 72px clamp(24px, 10vw, 180px); color: #1d2939; background: #fff; font-family: Inter, -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif; }
|
|
140
154
|
.pb-web-renderer__text { max-width: 760px; margin: 0 auto 40px; font-size: clamp(32px, 5vw, 64px); font-weight: 650; line-height: 1.08; letter-spacing: -.04em; }
|