@standhigher/puck-page-builder 0.12.4 → 0.12.5
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 +5 -1
- package/dist/index.js +72 -20
- package/package.json +1 -1
- package/src/styles.css +4 -1
package/dist/index.d.ts
CHANGED
|
@@ -179,6 +179,8 @@ type EditorContextValue = {
|
|
|
179
179
|
actionState: EditorActionState;
|
|
180
180
|
canAddBlock(type: string): boolean;
|
|
181
181
|
canDragBlock(id: string): boolean;
|
|
182
|
+
canDeleteBlock(id: string): boolean;
|
|
183
|
+
canDuplicateBlock(id: string): boolean;
|
|
182
184
|
/** Request a canvas selection. The inspector changes only after Puck confirms it. */
|
|
183
185
|
requestCanvasSelection(id: string): void;
|
|
184
186
|
/** Called from the canvas/Puck selection event. */
|
|
@@ -299,6 +301,7 @@ declare const messages: {
|
|
|
299
301
|
readonly undo: "撤销";
|
|
300
302
|
readonly redo: "恢复";
|
|
301
303
|
readonly duplicate: "复制";
|
|
304
|
+
readonly duplicateUnavailable: "此区块已达到允许数量上限,或复制操作已被禁用。";
|
|
302
305
|
readonly remove: "删除";
|
|
303
306
|
readonly confirmDeleteTitle: "确认删除区块?";
|
|
304
307
|
readonly confirmDeleteMessage: "删除后可使用撤销恢复。";
|
|
@@ -363,6 +366,7 @@ declare const messages: {
|
|
|
363
366
|
readonly undo: "Undo";
|
|
364
367
|
readonly redo: "Redo";
|
|
365
368
|
readonly duplicate: "Duplicate";
|
|
369
|
+
readonly duplicateUnavailable: "This block has reached its limit or duplication is disabled.";
|
|
366
370
|
readonly remove: "Delete";
|
|
367
371
|
readonly confirmDeleteTitle: "Delete this block?";
|
|
368
372
|
readonly confirmDeleteMessage: "You can restore it with Undo after deleting.";
|
|
@@ -424,7 +428,7 @@ type AdminMessageKey = keyof typeof messages["zh-CN"];
|
|
|
424
428
|
/** Minimal, dependency-free Admin copy catalog. Product locale remains PageDocument.settings.locale. */
|
|
425
429
|
declare function createAdminI18n(locale?: string): {
|
|
426
430
|
locale: AdminLocale;
|
|
427
|
-
t: (key: AdminMessageKey) => "Desktop" | "Tablet" | "Mobile" | "未保存变更" | "Outline" | "Preview" | "缩放" | "区块" | "结构" | "撤销" | "恢复" | "收起左侧面板" | "收起属性面板" | "Delete" | "Duplicate" | "products" | "编辑锁已失效" | "属性" | "添加区块" | "复制" | "删除" | "确认删除区块?" | "删除后可使用撤销恢复。" | "取消" | "确认删除" | "上移" | "下移" | "正在加载编辑器…" | "页面还没有区块" | "编辑器无法加载" | "编辑器当前不可编辑" | "操作已完成" | "所有更改已保留在当前会话中" | "保存草稿" | "历史记录" | "正在保存…" | "发布" | "正在发布…" | "保存草稿失败" | "重试保存" | "当前离线,恢复网络后将自动保存" | "发布失败" | "已发布" | "发布成功" | "返回" | "离开编辑器?" | "离开" | "自动缩放" | "正式预览" | "添加到店铺" | "正在获取编辑锁…" | "该页面正在被编辑" | "页面为只读状态" | "你有未保存的更改。确定要离开吗?" | "选择一个区块以编辑。" | "桌面" | "平板" | "手机" | "打开区块面板" | "打开属性面板" | "从 Shopify 选择商品" | "正在选择商品…" | "无法选择商品,请重试。" | "未选择商品" | "件商品" | "选择图片" | "正在上传图片…" | "无法上传图片,请重试。" | "未设置图片" | "移除图片" | "Blocks" | "Properties" | "Add block" | "Undo" | "Redo" | "Delete this block?" | "You can restore it with Undo after deleting." | "Cancel" | "Delete block" | "Move up" | "Move down" | "Loading editor…" | "This page has no blocks" | "The editor could not load" | "The editor is currently read-only" | "Action completed" | "Unsaved changes" | "Changes are kept in this session" | "Save draft" | "History" | "Saving…" | "Publish" | "Publishing…" | "Could not save draft" | "Retry save" | "Offline — changes will save when connection returns" | "Could not publish" | "Published" | "Back" | "Leave the editor?" | "Leave" | "Zoom" | "Auto zoom" | "Add to store" | "Acquiring edit lock…" | "This page is being edited" | "The edit lock has expired" | "This page is read-only" | "You have unsaved changes. Are you sure you want to leave?" | "Select a block to edit it." | "Collapse blocks panel" | "Collapse properties panel" | "Open blocks panel" | "Open properties panel" | "Select from Shopify" | "Selecting products…" | "Could not select products. Try again." | "No products selected" | "Select image" | "Uploading image…" | "Could not upload the image. Try again." | "No image selected" | "Remove image";
|
|
431
|
+
t: (key: AdminMessageKey) => "Desktop" | "Tablet" | "Mobile" | "未保存变更" | "Outline" | "Preview" | "缩放" | "区块" | "结构" | "撤销" | "恢复" | "收起左侧面板" | "收起属性面板" | "Delete" | "Duplicate" | "products" | "编辑锁已失效" | "属性" | "添加区块" | "复制" | "此区块已达到允许数量上限,或复制操作已被禁用。" | "删除" | "确认删除区块?" | "删除后可使用撤销恢复。" | "取消" | "确认删除" | "上移" | "下移" | "正在加载编辑器…" | "页面还没有区块" | "编辑器无法加载" | "编辑器当前不可编辑" | "操作已完成" | "所有更改已保留在当前会话中" | "保存草稿" | "历史记录" | "正在保存…" | "发布" | "正在发布…" | "保存草稿失败" | "重试保存" | "当前离线,恢复网络后将自动保存" | "发布失败" | "已发布" | "发布成功" | "返回" | "离开编辑器?" | "离开" | "自动缩放" | "正式预览" | "添加到店铺" | "正在获取编辑锁…" | "该页面正在被编辑" | "页面为只读状态" | "你有未保存的更改。确定要离开吗?" | "选择一个区块以编辑。" | "桌面" | "平板" | "手机" | "打开区块面板" | "打开属性面板" | "从 Shopify 选择商品" | "正在选择商品…" | "无法选择商品,请重试。" | "未选择商品" | "件商品" | "选择图片" | "正在上传图片…" | "无法上传图片,请重试。" | "未设置图片" | "移除图片" | "Blocks" | "Properties" | "Add block" | "Undo" | "Redo" | "This block has reached its limit or duplication is disabled." | "Delete this block?" | "You can restore it with Undo after deleting." | "Cancel" | "Delete block" | "Move up" | "Move down" | "Loading editor…" | "This page has no blocks" | "The editor could not load" | "The editor is currently read-only" | "Action completed" | "Unsaved changes" | "Changes are kept in this session" | "Save draft" | "History" | "Saving…" | "Publish" | "Publishing…" | "Could not save draft" | "Retry save" | "Offline — changes will save when connection returns" | "Could not publish" | "Published" | "Back" | "Leave the editor?" | "Leave" | "Zoom" | "Auto zoom" | "Add to store" | "Acquiring edit lock…" | "This page is being edited" | "The edit lock has expired" | "This page is read-only" | "You have unsaved changes. Are you sure you want to leave?" | "Select a block to edit it." | "Collapse blocks panel" | "Collapse properties panel" | "Open blocks panel" | "Open properties panel" | "Select from Shopify" | "Selecting products…" | "Could not select products. Try again." | "No products selected" | "Select image" | "Uploading image…" | "Could not upload the image. Try again." | "No image selected" | "Remove image";
|
|
428
432
|
};
|
|
429
433
|
|
|
430
434
|
declare function toEngineData(document: PageDocument, registry?: ExtensionRegistry): Data;
|
package/dist/index.js
CHANGED
|
@@ -353,7 +353,7 @@ function PropertyPanel({
|
|
|
353
353
|
import { Puck as Puck2, usePuck } from "@puckeditor/core";
|
|
354
354
|
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
355
|
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 useEffect3, useMemo as useMemo2, useRef as useRef4, useState as useState3 } from "react";
|
|
356
|
+
import { useCallback as useCallback2, useEffect as useEffect3, useLayoutEffect, useMemo as useMemo2, useRef as useRef4, useState as useState3 } from "react";
|
|
357
357
|
|
|
358
358
|
// src/adapters/puck/canvas-extension-block.tsx
|
|
359
359
|
import { registerOverlayPortal } from "@puckeditor/core";
|
|
@@ -369,6 +369,20 @@ function CanvasExtensionBlock({ active, children, label, onSelect }) {
|
|
|
369
369
|
|
|
370
370
|
// src/adapters/puck/page-document-config.tsx
|
|
371
371
|
import { Fragment, jsx as jsx4, jsxs as jsxs3 } from "react/jsx-runtime";
|
|
372
|
+
function withBlockPermissions(component, type, resolvePermissions) {
|
|
373
|
+
if (!resolvePermissions) return component;
|
|
374
|
+
return {
|
|
375
|
+
...component,
|
|
376
|
+
// Keep actions hidden until the policy resolver has produced the current
|
|
377
|
+
// per-block result. This prevents a one-frame clickable action that may be
|
|
378
|
+
// rejected by the PageDocument policy after Puck emits onChange.
|
|
379
|
+
permissions: { drag: false, duplicate: false, delete: false, edit: false, insert: false },
|
|
380
|
+
resolvePermissions: (item) => {
|
|
381
|
+
const id = typeof item?.props?.id === "string" ? item.props.id : "";
|
|
382
|
+
return resolvePermissions({ id, type });
|
|
383
|
+
}
|
|
384
|
+
};
|
|
385
|
+
}
|
|
372
386
|
function canvasFieldFallback({ block, props, registry, onPropsChange }) {
|
|
373
387
|
const fields = Object.entries(block.fields);
|
|
374
388
|
if (!fields.length) return null;
|
|
@@ -380,11 +394,11 @@ function canvasFieldFallback({ block, props, registry, onPropsChange }) {
|
|
|
380
394
|
] }, name) : null;
|
|
381
395
|
}) });
|
|
382
396
|
}
|
|
383
|
-
function createPageDocumentPuckConfig(onSelect, onPropsChange, selectedBlockId, registry) {
|
|
397
|
+
function createPageDocumentPuckConfig(onSelect, onPropsChange, selectedBlockId, registry, resolveBlockPermissions) {
|
|
384
398
|
const extensionComponents = Object.fromEntries((registry?.blocks ?? []).flatMap((block) => {
|
|
385
399
|
const BlockRenderer = block.render.web;
|
|
386
400
|
if (!BlockRenderer) return [];
|
|
387
|
-
return [[block.type, {
|
|
401
|
+
return [[block.type, withBlockPermissions({
|
|
388
402
|
render: (props) => {
|
|
389
403
|
const id = typeof props.id === "string" ? props.id : `unknown-${block.type}`;
|
|
390
404
|
const EditorRenderer = block.render.editor;
|
|
@@ -394,11 +408,11 @@ function createPageDocumentPuckConfig(onSelect, onPropsChange, selectedBlockId,
|
|
|
394
408
|
active ? canvasFieldFallback({ block, props, registry, onPropsChange: (next) => onPropsChange(id, next) }) : null
|
|
395
409
|
] }) });
|
|
396
410
|
}
|
|
397
|
-
}]];
|
|
411
|
+
}, block.type, resolveBlockPermissions)]];
|
|
398
412
|
}));
|
|
399
413
|
return {
|
|
400
414
|
components: {
|
|
401
|
-
Text: {
|
|
415
|
+
Text: withBlockPermissions({
|
|
402
416
|
render: (props) => {
|
|
403
417
|
const id = typeof props.id === "string" ? props.id : "unknown-text";
|
|
404
418
|
const content = typeof props.content === "string" ? props.content : "";
|
|
@@ -409,8 +423,8 @@ function createPageDocumentPuckConfig(onSelect, onPropsChange, selectedBlockId,
|
|
|
409
423
|
if (editable) onPropsChange(id, { content: event.currentTarget.textContent ?? "" }, true);
|
|
410
424
|
}, children: content }) });
|
|
411
425
|
}
|
|
412
|
-
},
|
|
413
|
-
Image: {
|
|
426
|
+
}, "core.text", resolveBlockPermissions),
|
|
427
|
+
Image: withBlockPermissions({
|
|
414
428
|
render: (props) => {
|
|
415
429
|
const id = typeof props.id === "string" ? props.id : "unknown-image";
|
|
416
430
|
const src = typeof props.src === "string" ? props.src : "";
|
|
@@ -423,7 +437,7 @@ function createPageDocumentPuckConfig(onSelect, onPropsChange, selectedBlockId,
|
|
|
423
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
|
|
424
438
|
] });
|
|
425
439
|
}
|
|
426
|
-
},
|
|
440
|
+
}, "core.image", resolveBlockPermissions),
|
|
427
441
|
...extensionComponents
|
|
428
442
|
}
|
|
429
443
|
};
|
|
@@ -658,6 +672,14 @@ function EditorProvider({ initialDocument, registry, policy, loadState = "ready"
|
|
|
658
672
|
const block = history.document.blocks.find((item) => item.id === id);
|
|
659
673
|
return editable && canDragBlock(block, registry?.getBlock(block?.type ?? ""), policy);
|
|
660
674
|
},
|
|
675
|
+
canDeleteBlock: (id) => {
|
|
676
|
+
const block = history.document.blocks.find((item) => item.id === id);
|
|
677
|
+
return editable && canDeleteBlock(block, history.document.blocks, registry?.getBlock(block?.type ?? ""), policy);
|
|
678
|
+
},
|
|
679
|
+
canDuplicateBlock: (id) => {
|
|
680
|
+
const block = history.document.blocks.find((item) => item.id === id);
|
|
681
|
+
return editable && canDuplicateBlock(block, history.document.blocks, registry?.getBlock(block?.type ?? ""), policy);
|
|
682
|
+
},
|
|
661
683
|
requestCanvasSelection,
|
|
662
684
|
confirmCanvasSelection,
|
|
663
685
|
updateFromCanvas,
|
|
@@ -774,6 +796,7 @@ var messages = {
|
|
|
774
796
|
undo: "\u64A4\u9500",
|
|
775
797
|
redo: "\u6062\u590D",
|
|
776
798
|
duplicate: "\u590D\u5236",
|
|
799
|
+
duplicateUnavailable: "\u6B64\u533A\u5757\u5DF2\u8FBE\u5230\u5141\u8BB8\u6570\u91CF\u4E0A\u9650\uFF0C\u6216\u590D\u5236\u64CD\u4F5C\u5DF2\u88AB\u7981\u7528\u3002",
|
|
777
800
|
remove: "\u5220\u9664",
|
|
778
801
|
confirmDeleteTitle: "\u786E\u8BA4\u5220\u9664\u533A\u5757\uFF1F",
|
|
779
802
|
confirmDeleteMessage: "\u5220\u9664\u540E\u53EF\u4F7F\u7528\u64A4\u9500\u6062\u590D\u3002",
|
|
@@ -838,6 +861,7 @@ var messages = {
|
|
|
838
861
|
undo: "Undo",
|
|
839
862
|
redo: "Redo",
|
|
840
863
|
duplicate: "Duplicate",
|
|
864
|
+
duplicateUnavailable: "This block has reached its limit or duplication is disabled.",
|
|
841
865
|
remove: "Delete",
|
|
842
866
|
confirmDeleteTitle: "Delete this block?",
|
|
843
867
|
confirmDeleteMessage: "You can restore it with Undo after deleting.",
|
|
@@ -974,6 +998,10 @@ function PageDocumentEditorShell(props) {
|
|
|
974
998
|
}
|
|
975
999
|
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 }) {
|
|
976
1000
|
const editor = useEditorContext();
|
|
1001
|
+
const editorRef = useRef4(editor);
|
|
1002
|
+
useLayoutEffect(() => {
|
|
1003
|
+
editorRef.current = editor;
|
|
1004
|
+
}, [editor]);
|
|
977
1005
|
const [blockView, setBlockView] = useState3("blocks");
|
|
978
1006
|
const [leftRailOpen, setLeftRailOpen] = useState3(true);
|
|
979
1007
|
const [rightPanelOpen, setRightPanelOpen] = useState3(true);
|
|
@@ -1000,7 +1028,14 @@ function PageDocumentEditor({ iframe = false, registry, adminLocale, onSave, onP
|
|
|
1000
1028
|
if (preserveCanvasValue) setCanvasMutationVersion((version) => version + 1);
|
|
1001
1029
|
updateBlockProps(id, props);
|
|
1002
1030
|
}, [updateBlockProps]);
|
|
1003
|
-
const
|
|
1031
|
+
const resolveBlockPermissions = useCallback2(({ id, type }) => ({
|
|
1032
|
+
duplicate: editorRef.current.canDuplicateBlock(id),
|
|
1033
|
+
delete: editorRef.current.canDeleteBlock(id),
|
|
1034
|
+
drag: editorRef.current.canDragBlock(id),
|
|
1035
|
+
edit: editorRef.current.isEditable,
|
|
1036
|
+
insert: editorRef.current.canAddBlock(type)
|
|
1037
|
+
}), []);
|
|
1038
|
+
const config = useMemo2(() => createPageDocumentPuckConfig(confirmCanvasSelection, updateFromCanvasInput, selectedBlockId, registry, resolveBlockPermissions), [confirmCanvasSelection, registry, resolveBlockPermissions, selectedBlockId, updateFromCanvasInput]);
|
|
1004
1039
|
useEffect3(() => {
|
|
1005
1040
|
const online = () => setIsOnline(true);
|
|
1006
1041
|
const offline = () => setIsOnline(false);
|
|
@@ -1110,7 +1145,7 @@ function PageDocumentEditor({ iframe = false, registry, adminLocale, onSave, onP
|
|
|
1110
1145
|
/* @__PURE__ */ jsx7(Puck2, { config, data: engineData, iframe: { enabled: iframe }, onChange: (data) => {
|
|
1111
1146
|
if (!editor.updateFromCanvas(fromEngineData(data, editor.document, registry))) setCanvasResetVersion((version) => version + 1);
|
|
1112
1147
|
}, children: /* @__PURE__ */ jsxs5(Puck2.Layout, { children: [
|
|
1113
|
-
/* @__PURE__ */ jsx7(CanvasSelectionBridge, { data: engineData, requestedBlockId: editor.canvasSelectionRequest, onCanvasSelected: confirmCanvasSelection, canvasMutationVersion, canvasResetVersion }),
|
|
1148
|
+
/* @__PURE__ */ jsx7(CanvasSelectionBridge, { data: engineData, requestedBlockId: editor.canvasSelectionRequest, onCanvasSelected: confirmCanvasSelection, canvasMutationVersion, canvasResetVersion, permissionsVersion: `${editor.isEditable}:${editor.document.blocks.map((block) => `${block.id}:${block.type}`).join("|")}` }),
|
|
1114
1149
|
/* @__PURE__ */ jsxs5("div", { className: "pb-shell pb-shell--v04", "data-testid": "page-document-editor", "data-page-id": editor.document.pageId, "data-dirty": editor.isDirty, "data-editor-state": editor.loadState, "data-editor-session-state": editor.sessionState, "data-save-state": resolvedSaveState, "data-left-panel": leftRailOpen ? "open" : "closed", "data-right-panel": rightPanelOpen ? "open" : "closed", children: [
|
|
1115
1150
|
/* @__PURE__ */ jsx7("header", { className: "pb-header", children: /* @__PURE__ */ jsxs5("div", { className: "pb-header-content", children: [
|
|
1116
1151
|
/* @__PURE__ */ jsxs5("div", { className: "pb-header-title-group", children: [
|
|
@@ -1214,13 +1249,14 @@ function PageDocumentEditor({ iframe = false, registry, adminLocale, onSave, onP
|
|
|
1214
1249
|
/* @__PURE__ */ jsx7("div", { className: "pb-toast-host", ...notice === "published" ? { "data-testid": "editor-notice", "data-notice": "published" } : {}, children: /* @__PURE__ */ jsx7(Frame, { children: notice === "published" ? /* @__PURE__ */ jsx7(Toast, { content: i18n.t("publishSuccessTitle"), onDismiss: dismissPublishedNotice }) : null }) })
|
|
1215
1250
|
] });
|
|
1216
1251
|
}
|
|
1217
|
-
function CanvasSelectionBridge({ data, requestedBlockId, onCanvasSelected, canvasMutationVersion, canvasResetVersion }) {
|
|
1252
|
+
function CanvasSelectionBridge({ data, requestedBlockId, onCanvasSelected, canvasMutationVersion, canvasResetVersion, permissionsVersion }) {
|
|
1218
1253
|
const puck = usePuck();
|
|
1219
1254
|
const lastSelectedId = useRef4(null);
|
|
1220
1255
|
const lastSyncedData = useRef4(null);
|
|
1221
1256
|
const lastCanvasMutationVersion = useRef4(0);
|
|
1222
1257
|
const lastCanvasResetVersion = useRef4(0);
|
|
1223
1258
|
const serializedData = JSON.stringify(data);
|
|
1259
|
+
const refreshPermissions = puck.refreshPermissions;
|
|
1224
1260
|
useEffect3(() => {
|
|
1225
1261
|
const forceReset = canvasResetVersion > lastCanvasResetVersion.current;
|
|
1226
1262
|
if (lastSyncedData.current === serializedData && !forceReset) return;
|
|
@@ -1232,6 +1268,9 @@ function CanvasSelectionBridge({ data, requestedBlockId, onCanvasSelected, canva
|
|
|
1232
1268
|
}
|
|
1233
1269
|
puck.dispatch({ type: "setData", data });
|
|
1234
1270
|
}, [canvasMutationVersion, canvasResetVersion, data, puck, serializedData]);
|
|
1271
|
+
useEffect3(() => {
|
|
1272
|
+
refreshPermissions?.({}, true);
|
|
1273
|
+
}, [permissionsVersion, refreshPermissions]);
|
|
1235
1274
|
useEffect3(() => {
|
|
1236
1275
|
if (!requestedBlockId) return;
|
|
1237
1276
|
const selector = puck.getSelectorForId(requestedBlockId);
|
|
@@ -1267,10 +1306,20 @@ function InspectorSection({ title, children, defaultOpen = true }) {
|
|
|
1267
1306
|
/* @__PURE__ */ jsx7("div", { className: "pb-inspector-section__body", children })
|
|
1268
1307
|
] });
|
|
1269
1308
|
}
|
|
1270
|
-
function InspectorTextControl({ label, value, control, disabled, onChange }) {
|
|
1309
|
+
function InspectorTextControl({ label, value, control, maxLength, disabled, onChange }) {
|
|
1271
1310
|
const stringValue = typeof value === "string" ? value : "";
|
|
1272
1311
|
if (control === "color") return /* @__PURE__ */ jsx7("input", { "aria-label": label, type: "color", value: /^#[\da-f]{6}$/i.test(stringValue) ? stringValue : "#000000", disabled, onChange: (event) => onChange(event.currentTarget.value) });
|
|
1273
|
-
|
|
1312
|
+
const length = Array.from(stringValue).length;
|
|
1313
|
+
const field = /* @__PURE__ */ jsx7(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
|
+
if (maxLength === void 0) return field;
|
|
1315
|
+
return /* @__PURE__ */ jsxs5("div", { className: "pb-inspector-field__limited", children: [
|
|
1316
|
+
field,
|
|
1317
|
+
/* @__PURE__ */ jsxs5("span", { className: "pb-inspector-field__limit", "aria-label": `Limit ${maxLength}`, children: [
|
|
1318
|
+
length,
|
|
1319
|
+
"/",
|
|
1320
|
+
maxLength
|
|
1321
|
+
] })
|
|
1322
|
+
] });
|
|
1274
1323
|
}
|
|
1275
1324
|
function InspectorAssetControl({ value, disabled, picker, pageId, blockId, i18n, onChange }) {
|
|
1276
1325
|
const [busy, setBusy] = useState3(false);
|
|
@@ -1340,17 +1389,20 @@ function InspectorField({ name, field, value, registry, disabled, assetPicker, p
|
|
|
1340
1389
|
/* @__PURE__ */ jsx7(Text3, { as: "p", variant: "bodySm", fontWeight: "semibold", children: label }),
|
|
1341
1390
|
field.description ? /* @__PURE__ */ jsx7(Text3, { as: "p", variant: "bodySm", tone: "subdued", children: field.description }) : null
|
|
1342
1391
|
] }),
|
|
1343
|
-
field.control === "products" ? /* @__PURE__ */ jsx7(InspectorProductsControl, { value, disabled, picker: productPicker, pageId, blockId, i18n, onChange }) : field.control === "asset" ? /* @__PURE__ */ jsx7(InspectorAssetControl, { value, disabled, picker: assetPicker, pageId, blockId, i18n, onChange }) : field.control ? /* @__PURE__ */ jsx7(InspectorTextControl, { label, value, control: field.control, disabled, onChange: (next) => onChange(next) }) : Field ? /* @__PURE__ */ jsx7(Field, { value, onChange }) : null,
|
|
1392
|
+
field.control === "products" ? /* @__PURE__ */ jsx7(InspectorProductsControl, { value, disabled, picker: productPicker, pageId, blockId, i18n, onChange }) : field.control === "asset" ? /* @__PURE__ */ jsx7(InspectorAssetControl, { value, disabled, picker: assetPicker, pageId, blockId, i18n, onChange }) : field.control ? /* @__PURE__ */ jsx7(InspectorTextControl, { label, value, control: field.control, maxLength: field.validation?.maxLength, disabled, onChange: (next) => onChange(next) }) : Field ? /* @__PURE__ */ jsx7(Field, { value, onChange }) : null,
|
|
1344
1393
|
issues.map((issue) => /* @__PURE__ */ jsx7(Text3, { as: "p", variant: "bodySm", tone: "critical", children: issue.message }, issue.message))
|
|
1345
1394
|
] });
|
|
1346
1395
|
}
|
|
1347
1396
|
function InspectorActions({ block, canDuplicate, canDelete, canMove, canMoveUp, canMoveDown, i18n, onDuplicate, onDelete, onMove }) {
|
|
1348
|
-
return /* @__PURE__ */
|
|
1349
|
-
/* @__PURE__ */
|
|
1350
|
-
|
|
1351
|
-
|
|
1352
|
-
|
|
1353
|
-
|
|
1397
|
+
return /* @__PURE__ */ jsxs5("div", { className: "pb-inspector-actions", "aria-label": `Actions for ${block.id}`, children: [
|
|
1398
|
+
/* @__PURE__ */ jsxs5(ButtonGroup2, { children: [
|
|
1399
|
+
/* @__PURE__ */ jsx7(Button2, { disabled: !canMove || !canMoveUp, onClick: () => onMove(-1), children: i18n.t("moveUp") }),
|
|
1400
|
+
/* @__PURE__ */ jsx7(Button2, { disabled: !canMove || !canMoveDown, onClick: () => onMove(1), children: i18n.t("moveDown") }),
|
|
1401
|
+
/* @__PURE__ */ jsx7(Button2, { disabled: !canDuplicate, accessibilityLabel: canDuplicate ? i18n.t("duplicate") : i18n.t("duplicateUnavailable"), onClick: onDuplicate, children: i18n.t("duplicate") }),
|
|
1402
|
+
/* @__PURE__ */ jsx7(Button2, { disabled: !canDelete, tone: "critical", onClick: onDelete, children: i18n.t("remove") })
|
|
1403
|
+
] }),
|
|
1404
|
+
!canDuplicate ? /* @__PURE__ */ jsx7(Text3, { as: "p", variant: "bodySm", tone: "subdued", children: i18n.t("duplicateUnavailable") }) : null
|
|
1405
|
+
] });
|
|
1354
1406
|
}
|
|
1355
1407
|
function DeleteConfirmation({ block, config, i18n, onCancel, onConfirm }) {
|
|
1356
1408
|
return /* @__PURE__ */ jsx7("div", { className: "pb-delete-confirmation-backdrop", role: "presentation", children: /* @__PURE__ */ jsxs5("section", { className: "pb-delete-confirmation", role: "dialog", "aria-modal": "true", "aria-labelledby": "pb-delete-confirmation-title", children: [
|
package/package.json
CHANGED
package/src/styles.css
CHANGED
|
@@ -48,6 +48,9 @@ button:focus-visible, [role="button"]:focus-visible { outline: 2px solid var(--b
|
|
|
48
48
|
.pb-inspector-section:not([open]) > summary > span:last-child { transform: rotate(-90deg); }
|
|
49
49
|
.pb-inspector-section__body { display: grid; gap: var(--builder-space-3); padding: 0 var(--builder-space-3) var(--builder-space-3); border-top: 1px solid #f1f5f9; }
|
|
50
50
|
.pb-inspector-field { display: grid; gap: 6px; }
|
|
51
|
+
.pb-inspector-field__limited { display: flex; align-items: center; gap: 8px; }
|
|
52
|
+
.pb-inspector-field__limited > :first-child { flex: 1; min-width: 0; }
|
|
53
|
+
.pb-inspector-field__limit { flex: 0 0 auto; color: #6d7175; font-size: 12px; font-variant-numeric: tabular-nums; }
|
|
51
54
|
.pb-inspector-field__heading { display: grid; gap: 2px; }
|
|
52
55
|
.pb-inspector-field__heading p { margin: 0; }
|
|
53
56
|
.pb-inspector-field__heading p:first-child { color: #334155; font-size: 13px; }
|
|
@@ -68,7 +71,7 @@ button:focus-visible, [role="button"]:focus-visible { outline: 2px solid var(--b
|
|
|
68
71
|
.pb-product-picker__thumb img, .pb-product-picker__thumb-fallback { display: block; width: 100%; height: 100%; object-fit: cover; }
|
|
69
72
|
.pb-product-picker__thumb-fallback { background: #cbd5e1; }
|
|
70
73
|
.pb-asset-picker { display: grid; gap: 8px; }
|
|
71
|
-
.pb-asset-picker__preview { display: block; width: 100%;
|
|
74
|
+
.pb-asset-picker__preview { display: block; width: 100%; aspect-ratio: 20 / 9; object-fit: fill; object-position: center; border: 1px solid #e2e8f0; border-radius: 8px; background: #f8fafc; }
|
|
72
75
|
.pb-inspector__hint { margin: 0; padding: 0 var(--builder-space-2); color: #64748b; font-size: 12px; line-height: 1.5; }
|
|
73
76
|
.pb-inspector-actions { padding-top: var(--builder-space-2); border-top: 1px solid #e2e8f0; }
|
|
74
77
|
.pb-delete-confirmation-backdrop { position: fixed; z-index: 1000; inset: 0; display: grid; place-items: center; padding: var(--builder-space-4); background: rgb(15 23 42 / 42%); }
|