@standhigher/puck-page-builder 0.12.0 → 0.12.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/{chunk-YXBTNYPR.js → chunk-RLKWR5JM.js} +3 -2
- package/dist/extensions.d.ts +2 -2
- package/dist/extensions.js +1 -1
- package/dist/index.d.ts +20 -3
- package/dist/index.js +69 -23
- package/dist/{registry-CXJdOya3.d.ts → registry-BkqtMP-A.d.ts} +3 -1
- package/dist/renderer.d.ts +1 -1
- package/dist/runtime.d.ts +1 -1
- package/dist/runtime.js +1 -1
- package/package.json +1 -1
- package/src/styles.css +7 -5
|
@@ -72,7 +72,7 @@ function validateFieldValue(config, value) {
|
|
|
72
72
|
if (control === "text" && /[\r\n]/.test(value)) issues.push({ path: "", message: "\u5FC5\u987B\u4E3A\u5355\u884C\u6587\u672C\u3002" });
|
|
73
73
|
if (config.validation?.minLength !== void 0 && stringLength(value) < config.validation.minLength) issues.push({ path: "", message: `\u81F3\u5C11\u9700\u8981 ${config.validation.minLength} \u4E2A\u5B57\u7B26\u3002` });
|
|
74
74
|
if (config.validation?.maxLength !== void 0 && stringLength(value) > config.validation.maxLength) issues.push({ path: "", message: `\u6700\u591A\u5141\u8BB8 ${config.validation.maxLength} \u4E2A\u5B57\u7B26\u3002` });
|
|
75
|
-
if (value && control === "url" && !isSafeUrl(value, config)) issues.push({ path: "", message: "\u5FC5\u987B\u662F\u7AD9\u5185\u76F8\u5BF9\u8DEF\u5F84\u6216\u5141\u8BB8\u7684 HTTP(S) URL\u3002" });
|
|
75
|
+
if (value && (control === "url" || control === "asset") && !isSafeUrl(value, config)) issues.push({ path: "", message: "\u5FC5\u987B\u662F\u7AD9\u5185\u76F8\u5BF9\u8DEF\u5F84\u6216\u5141\u8BB8\u7684 HTTP(S) URL\u3002" });
|
|
76
76
|
if (value && control === "color" && !hexColor.test(value)) issues.push({ path: "", message: "\u5FC5\u987B\u662F\u5341\u516D\u8FDB\u5236\u989C\u8272\uFF0C\u4F8B\u5982 #005BD3\u3002" });
|
|
77
77
|
return issues;
|
|
78
78
|
}
|
|
@@ -327,11 +327,12 @@ function validateBlock(document, index, registry) {
|
|
|
327
327
|
if (block.version !== definition.version) issues.push({ path: `${path}.version`, message: `\u533A\u5757\u7248\u672C\u5FC5\u987B\u4E3A ${definition.version}\u3002` });
|
|
328
328
|
if (!supportsTarget(definition, document.target)) issues.push({ path, message: `\u533A\u5757\u4E0D\u652F\u6301 ${document.target} target\u3002` });
|
|
329
329
|
if (definition.variants?.length && !definition.variants.some((variant) => variant.id === block.variant)) issues.push({ path: `${path}.variant`, message: `\u4E0D\u652F\u6301\u7684 variant\uFF1A${block.variant}\u3002` });
|
|
330
|
-
const allowedProps = /* @__PURE__ */ new Set([...Object.keys(definition.defaultProps), ...Object.
|
|
330
|
+
const allowedProps = /* @__PURE__ */ new Set([...Object.keys(definition.defaultProps), ...Object.entries(definition.fields).filter(([, field]) => field.persist !== false).map(([name]) => name)]);
|
|
331
331
|
for (const key of Object.keys(block.props)) {
|
|
332
332
|
if (!allowedProps.has(key)) issues.push({ path: `${path}.props.${key}`, message: "\u4E0D\u5141\u8BB8\u4FDD\u5B58\u672A\u77E5\u5B57\u6BB5\u3002" });
|
|
333
333
|
}
|
|
334
334
|
for (const [name, field] of Object.entries(definition.fields)) {
|
|
335
|
+
if (field.persist === false) continue;
|
|
335
336
|
for (const issue of validateFieldValue(field, block.props[name])) {
|
|
336
337
|
issues.push({ ...issue, path: issue.path ? `${path}.props.${name}.${issue.path}` : `${path}.props.${name}` });
|
|
337
338
|
}
|
package/dist/extensions.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { h as ExtensionRegistry, V as ValidationIssue, c as BlockPolicy, F as FieldConfig } from './registry-
|
|
2
|
-
export { B as BlockDefinition, a as BlockEditorProps, b as BlockOperation, d as BlockVariantDefinition, D as DataSourceDefinition, E as EditorAction, e as EditorActionPosition, f as EditorOperationPolicy, g as ExtensionActionContext, i as ExtensionRegistryError, j as ExtensionRegistryErrorCode, k as ExtensionRegistryOptions, l as ExtensionTarget, m as FieldDefinition, n as FieldProps, o as FieldValidation, L as LifecycleHooks, P as PageBuilderExtension, R as RendererDefinition, T as TemplateDefinition, p as TemplateRegistry, q as TemplateSource, U as UISlotContribution, r as UISlotName, s as createExtensionRegistry, t as createTemplateRegistry } from './registry-
|
|
1
|
+
import { h as ExtensionRegistry, V as ValidationIssue, c as BlockPolicy, F as FieldConfig } from './registry-BkqtMP-A.js';
|
|
2
|
+
export { B as BlockDefinition, a as BlockEditorProps, b as BlockOperation, d as BlockVariantDefinition, D as DataSourceDefinition, E as EditorAction, e as EditorActionPosition, f as EditorOperationPolicy, g as ExtensionActionContext, i as ExtensionRegistryError, j as ExtensionRegistryErrorCode, k as ExtensionRegistryOptions, l as ExtensionTarget, m as FieldDefinition, n as FieldProps, o as FieldValidation, L as LifecycleHooks, P as PageBuilderExtension, R as RendererDefinition, T as TemplateDefinition, p as TemplateRegistry, q as TemplateSource, U as UISlotContribution, r as UISlotName, s as createExtensionRegistry, t as createTemplateRegistry } from './registry-BkqtMP-A.js';
|
|
3
3
|
import { PageDocument, JsonValue } from './schema.js';
|
|
4
4
|
import 'react';
|
|
5
5
|
import './theme.js';
|
package/dist/extensions.js
CHANGED
package/dist/index.d.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import * as react from 'react';
|
|
2
2
|
import { ReactNode } from 'react';
|
|
3
|
-
import { f as EditorOperationPolicy, c as BlockPolicy, V as ValidationIssue, h as ExtensionRegistry } from './registry-
|
|
4
|
-
export { B as BlockDefinition, a as BlockEditorProps, b as BlockOperation, d as BlockVariantDefinition, D as DataSourceDefinition, E as EditorAction, e as EditorActionPosition, g as ExtensionActionContext, i as ExtensionRegistryError, j as ExtensionRegistryErrorCode, k as ExtensionRegistryOptions, l as ExtensionTarget, F as FieldConfig, m as FieldDefinition, n as FieldProps, o as FieldValidation, L as LifecycleHooks, P as PageBuilderExtension, R as RendererDefinition, T as TemplateDefinition, p as TemplateRegistry, q as TemplateSource, U as UISlotContribution, r as UISlotName, s as createExtensionRegistry, t as createTemplateRegistry } from './registry-
|
|
3
|
+
import { f as EditorOperationPolicy, c as BlockPolicy, V as ValidationIssue, h as ExtensionRegistry } from './registry-BkqtMP-A.js';
|
|
4
|
+
export { B as BlockDefinition, a as BlockEditorProps, b as BlockOperation, d as BlockVariantDefinition, D as DataSourceDefinition, E as EditorAction, e as EditorActionPosition, g as ExtensionActionContext, i as ExtensionRegistryError, j as ExtensionRegistryErrorCode, k as ExtensionRegistryOptions, l as ExtensionTarget, F as FieldConfig, m as FieldDefinition, n as FieldProps, o as FieldValidation, L as LifecycleHooks, P as PageBuilderExtension, R as RendererDefinition, T as TemplateDefinition, p as TemplateRegistry, q as TemplateSource, U as UISlotContribution, r as UISlotName, s as createExtensionRegistry, t as createTemplateRegistry } from './registry-BkqtMP-A.js';
|
|
5
5
|
import { PageDocument, BlockNode, JsonValue } from './schema.js';
|
|
6
6
|
export { BlockStyleOverrides, DataBinding, PageDocumentIssue, PageDocumentMigration, PageDocumentSchemaVersion, PageSettings, RenderTarget, createPageDocument, migratePageDocument, validatePageDocument } from './schema.js';
|
|
7
7
|
import { ProductReference } from './extensions.js';
|
|
@@ -247,6 +247,13 @@ type PageDocumentEditorShellProps = {
|
|
|
247
247
|
publishAction?: PublishAction;
|
|
248
248
|
/** Host-owned picker/uploader for shop-scoped assets. */
|
|
249
249
|
assetPicker?: AssetPickerAdapter;
|
|
250
|
+
/** External settings, keyed by block id (or block type for shared settings), outside document history and persistence. */
|
|
251
|
+
inspectorSettings?: Record<string, {
|
|
252
|
+
values: Record<string, JsonValue>;
|
|
253
|
+
disabled?: boolean;
|
|
254
|
+
onChange: (fieldName: string, value: JsonValue) => void;
|
|
255
|
+
footer?: ReactNode;
|
|
256
|
+
}>;
|
|
250
257
|
/** Host-owned product picker. The shell only shows the selected snapshot and a button. */
|
|
251
258
|
productPicker?: ProductPickerAdapter;
|
|
252
259
|
/** Optional reusable page lifecycle summary. */
|
|
@@ -341,6 +348,11 @@ declare const messages: {
|
|
|
341
348
|
readonly selectProductsFailed: "无法选择商品,请重试。";
|
|
342
349
|
readonly emptyProducts: "未选择商品";
|
|
343
350
|
readonly productCountSuffix: "件商品";
|
|
351
|
+
readonly selectAsset: "选择图片";
|
|
352
|
+
readonly selectingAsset: "正在上传图片…";
|
|
353
|
+
readonly selectAssetFailed: "无法上传图片,请重试。";
|
|
354
|
+
readonly emptyAsset: "未设置图片";
|
|
355
|
+
readonly removeAsset: "移除图片";
|
|
344
356
|
};
|
|
345
357
|
readonly en: {
|
|
346
358
|
readonly blocks: "Blocks";
|
|
@@ -399,13 +411,18 @@ declare const messages: {
|
|
|
399
411
|
readonly selectProductsFailed: "Could not select products. Try again.";
|
|
400
412
|
readonly emptyProducts: "No products selected";
|
|
401
413
|
readonly productCountSuffix: "products";
|
|
414
|
+
readonly selectAsset: "Select image";
|
|
415
|
+
readonly selectingAsset: "Uploading image…";
|
|
416
|
+
readonly selectAssetFailed: "Could not upload the image. Try again.";
|
|
417
|
+
readonly emptyAsset: "No image selected";
|
|
418
|
+
readonly removeAsset: "Remove image";
|
|
402
419
|
};
|
|
403
420
|
};
|
|
404
421
|
type AdminMessageKey = keyof typeof messages["zh-CN"];
|
|
405
422
|
/** Minimal, dependency-free Admin copy catalog. Product locale remains PageDocument.settings.locale. */
|
|
406
423
|
declare function createAdminI18n(locale?: string): {
|
|
407
424
|
locale: AdminLocale;
|
|
408
|
-
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";
|
|
425
|
+
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";
|
|
409
426
|
};
|
|
410
427
|
|
|
411
428
|
declare function toEngineData(document: PageDocument, registry?: ExtensionRegistry): Data;
|
package/dist/index.js
CHANGED
|
@@ -13,7 +13,7 @@ import {
|
|
|
13
13
|
validateBlockPolicy,
|
|
14
14
|
validateFieldValue,
|
|
15
15
|
validatePageDocumentWithRegistry
|
|
16
|
-
} from "./chunk-
|
|
16
|
+
} from "./chunk-RLKWR5JM.js";
|
|
17
17
|
import {
|
|
18
18
|
WebRenderer
|
|
19
19
|
} from "./chunk-KYXIXIWK.js";
|
|
@@ -822,7 +822,12 @@ var messages = {
|
|
|
822
822
|
selectingProducts: "\u6B63\u5728\u9009\u62E9\u5546\u54C1\u2026",
|
|
823
823
|
selectProductsFailed: "\u65E0\u6CD5\u9009\u62E9\u5546\u54C1\uFF0C\u8BF7\u91CD\u8BD5\u3002",
|
|
824
824
|
emptyProducts: "\u672A\u9009\u62E9\u5546\u54C1",
|
|
825
|
-
productCountSuffix: "\u4EF6\u5546\u54C1"
|
|
825
|
+
productCountSuffix: "\u4EF6\u5546\u54C1",
|
|
826
|
+
selectAsset: "\u9009\u62E9\u56FE\u7247",
|
|
827
|
+
selectingAsset: "\u6B63\u5728\u4E0A\u4F20\u56FE\u7247\u2026",
|
|
828
|
+
selectAssetFailed: "\u65E0\u6CD5\u4E0A\u4F20\u56FE\u7247\uFF0C\u8BF7\u91CD\u8BD5\u3002",
|
|
829
|
+
emptyAsset: "\u672A\u8BBE\u7F6E\u56FE\u7247",
|
|
830
|
+
removeAsset: "\u79FB\u9664\u56FE\u7247"
|
|
826
831
|
},
|
|
827
832
|
en: {
|
|
828
833
|
blocks: "Blocks",
|
|
@@ -880,7 +885,12 @@ var messages = {
|
|
|
880
885
|
selectingProducts: "Selecting products\u2026",
|
|
881
886
|
selectProductsFailed: "Could not select products. Try again.",
|
|
882
887
|
emptyProducts: "No products selected",
|
|
883
|
-
productCountSuffix: "products"
|
|
888
|
+
productCountSuffix: "products",
|
|
889
|
+
selectAsset: "Select image",
|
|
890
|
+
selectingAsset: "Uploading image\u2026",
|
|
891
|
+
selectAssetFailed: "Could not upload the image. Try again.",
|
|
892
|
+
emptyAsset: "No image selected",
|
|
893
|
+
removeAsset: "Remove image"
|
|
884
894
|
}
|
|
885
895
|
};
|
|
886
896
|
function createAdminI18n(locale) {
|
|
@@ -960,7 +970,7 @@ function PageDocumentEditorShell(props) {
|
|
|
960
970
|
}, [managedSession.state, onSessionStateChange]);
|
|
961
971
|
return /* @__PURE__ */ jsx7(EditorProvider, { initialDocument: props.initialDocument, registry: props.registry, policy: props.policy, loadState: props.loadState, sessionState: managedSession.state, session: managedSession.session, sessionMessage: managedSession.message, leaveWarning: createAdminI18n(props.adminLocale).t("leaveWarning"), onDocumentChange: props.onDocumentChange, children: /* @__PURE__ */ jsx7(PageDocumentEditor, { ...props }) });
|
|
962
972
|
}
|
|
963
|
-
function PageDocumentEditor({ iframe = false, registry, adminLocale, onSave, onPublish, draftPersistence, draftRevision: initialDraftRevision, autoSave = true, autoSaveDelayMs = 800, publishAction, assetPicker, productPicker, pageStatus, onBack, onHistory, onPreview, onAddToStore, deleteConfirmation, availableBlockTypes, appearanceControls = false }) {
|
|
973
|
+
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 }) {
|
|
964
974
|
const editor = useEditorContext();
|
|
965
975
|
const [blockView, setBlockView] = useState3("blocks");
|
|
966
976
|
const [leftRailOpen, setLeftRailOpen] = useState3(true);
|
|
@@ -1109,20 +1119,22 @@ function PageDocumentEditor({ iframe = false, registry, adminLocale, onSave, onP
|
|
|
1109
1119
|
pageStatus ? /* @__PURE__ */ jsx7(PageStatusCard, { status: pageStatus, sessionState: editor.sessionState }) : null
|
|
1110
1120
|
] })
|
|
1111
1121
|
] }),
|
|
1112
|
-
/* @__PURE__ */
|
|
1113
|
-
/* @__PURE__ */
|
|
1114
|
-
|
|
1115
|
-
|
|
1116
|
-
|
|
1117
|
-
/* @__PURE__ */ jsx7(
|
|
1118
|
-
|
|
1119
|
-
|
|
1120
|
-
|
|
1121
|
-
|
|
1122
|
-
|
|
1123
|
-
|
|
1124
|
-
|
|
1125
|
-
|
|
1122
|
+
/* @__PURE__ */ jsxs5("div", { className: "pb-header-controls", children: [
|
|
1123
|
+
/* @__PURE__ */ jsxs5("div", { className: "pb-header-device-toolbar", children: [
|
|
1124
|
+
/* @__PURE__ */ jsx7(ButtonGroup2, { variant: "segmented", children: Object.keys(deviceLabels2).map((device) => /* @__PURE__ */ jsx7(Button2, { pressed: editor.device === device, onClick: () => editor.setDevice(device), children: i18n.t(deviceLabels2[device]) }, device)) }),
|
|
1125
|
+
/* @__PURE__ */ jsx7("div", { className: "pb-zoom-control", children: /* @__PURE__ */ jsx7(Select2, { label: i18n.t("zoom"), labelHidden: true, options: [{ label: i18n.t("zoomAuto"), value: "auto" }, { label: "50%", value: "50" }, { label: "70%", value: "70" }, { label: "100%", value: "100" }], value: zoom, onChange: (value) => setZoom(value) }) })
|
|
1126
|
+
] }),
|
|
1127
|
+
/* @__PURE__ */ jsx7("div", { className: "pb-header-actions", children: /* @__PURE__ */ jsxs5(InlineStack3, { gap: "150", blockAlign: "center", wrap: true, children: [
|
|
1128
|
+
/* @__PURE__ */ jsx7(Badge3, { tone: saveBadgeTone, children: saveBadgeLabel }),
|
|
1129
|
+
onHistory ? /* @__PURE__ */ jsx7("span", { "data-editor-history": "", children: /* @__PURE__ */ jsx7(Button2, { disabled: request !== "idle", onClick: () => onHistory({ document: editor.document, draftRevision, session: editor.session }), children: i18n.t("history") }) }) : null,
|
|
1130
|
+
/* @__PURE__ */ jsx7(Button2, { disabled: !canPersistDraft || !editor.isDirty || request !== "idle" || validationIssues.length > 0 || !isOnline, onClick: () => void save(), children: saveButtonLabel }),
|
|
1131
|
+
onPreview ? /* @__PURE__ */ jsx7(Button2, { disabled: request !== "idle" || !isOnline, onClick: () => void onPreview({ document: editor.document, draftRevision, session: editor.session }), children: i18n.t("preview") }) : null,
|
|
1132
|
+
onAddToStore ? /* @__PURE__ */ jsx7(Button2, { disabled: request !== "idle" || pageStatus?.publicationStatus === "unpublished", onClick: () => void onAddToStore({ document: editor.document, session: editor.session }), children: i18n.t("addToStore") }) : null,
|
|
1133
|
+
/* @__PURE__ */ jsx7(Button2, { variant: "primary", disabled: !publishAction && !onPublish || request !== "idle" || validationIssues.length > 0 || !isOnline, onClick: () => void publish(), children: request === "publishing" ? i18n.t("publishing") : i18n.t("publish") }),
|
|
1134
|
+
/* @__PURE__ */ jsx7(Button2, { accessibilityLabel: i18n.t("undo"), icon: UndoIcon2, variant: "tertiary", disabled: !editor.actionState.canUndo, onClick: editor.undo }),
|
|
1135
|
+
/* @__PURE__ */ jsx7(Button2, { accessibilityLabel: i18n.t("redo"), icon: RedoIcon2, variant: "tertiary", disabled: !editor.actionState.canRedo, onClick: editor.redo })
|
|
1136
|
+
] }) })
|
|
1137
|
+
] })
|
|
1126
1138
|
] }) }),
|
|
1127
1139
|
editor.loadState === "success" ? /* @__PURE__ */ jsx7(Banner, { tone: "success", children: i18n.t("success") }) : null,
|
|
1128
1140
|
notice ? /* @__PURE__ */ jsx7(Banner, { tone: notice === "published" ? "success" : "critical", children: i18n.t(notice) }) : null,
|
|
@@ -1189,7 +1201,7 @@ function PageDocumentEditor({ iframe = false, registry, adminLocale, onSave, onP
|
|
|
1189
1201
|
/* @__PURE__ */ jsx7(Button2, { accessibilityLabel: i18n.t("collapseRight"), icon: XIcon2, variant: "tertiary", onClick: () => setRightPanelOpen(false) })
|
|
1190
1202
|
] }),
|
|
1191
1203
|
editor.selectedBlock ? /* @__PURE__ */ jsxs5(Fragment2, { children: [
|
|
1192
|
-
/* @__PURE__ */ jsx7(DocumentInspector, { 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) }),
|
|
1204
|
+
/* @__PURE__ */ jsx7(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),
|
|
1193
1205
|
/* @__PURE__ */ jsx7(InspectorActions, { block: editor.selectedBlock, canDuplicate: editor.actionState.canDuplicate, canDelete: editor.actionState.canDelete, canMove: editor.actionState.canReorder, canMoveUp: editor.document.blocks[0]?.id !== editor.selectedBlock.id, canMoveDown: editor.document.blocks.at(-1)?.id !== editor.selectedBlock.id, i18n, onDuplicate: () => editor.duplicateBlock(editor.selectedBlock.id), onDelete: () => editor.requestDeleteBlock(editor.selectedBlock.id), onMove: (direction) => editor.moveBlock(editor.selectedBlock.id, direction) })
|
|
1194
1206
|
] }) : /* @__PURE__ */ jsx7(Text3, { as: "p", tone: "subdued", children: i18n.t("selectBlock") })
|
|
1195
1207
|
] })
|
|
@@ -1260,6 +1272,39 @@ function InspectorTextControl({ label, value, control, disabled, onChange }) {
|
|
|
1260
1272
|
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) });
|
|
1261
1273
|
return /* @__PURE__ */ jsx7(TextField, { label, labelHidden: true, value: stringValue, onChange, autoComplete: "off", disabled, multiline: control === "textarea" ? 4 : false, type: control === "url" ? "url" : "text" });
|
|
1262
1274
|
}
|
|
1275
|
+
function InspectorAssetControl({ value, disabled, picker, pageId, blockId, i18n, onChange }) {
|
|
1276
|
+
const [busy, setBusy] = useState3(false);
|
|
1277
|
+
const [error, setError] = useState3(null);
|
|
1278
|
+
const active = useRef4(true);
|
|
1279
|
+
useEffect3(() => {
|
|
1280
|
+
active.current = !disabled;
|
|
1281
|
+
return () => {
|
|
1282
|
+
active.current = false;
|
|
1283
|
+
};
|
|
1284
|
+
}, [disabled]);
|
|
1285
|
+
const url = typeof value === "string" && validateFieldValue({ field: "", control: "asset" }, value).length === 0 ? value : "";
|
|
1286
|
+
return /* @__PURE__ */ jsxs5("div", { className: "pb-asset-picker", "data-testid": "asset-picker", children: [
|
|
1287
|
+
url ? /* @__PURE__ */ jsx7("img", { src: url, alt: "", className: "pb-asset-picker__preview" }) : /* @__PURE__ */ jsx7(Text3, { as: "p", variant: "bodySm", tone: "subdued", children: i18n.t("emptyAsset") }),
|
|
1288
|
+
url ? /* @__PURE__ */ jsx7(Button2, { fullWidth: true, variant: "tertiary", disabled: disabled || busy, onClick: () => onChange(""), children: i18n.t("removeAsset") }) : null,
|
|
1289
|
+
/* @__PURE__ */ jsx7(Button2, { fullWidth: true, disabled: disabled || busy || !picker, onClick: () => void (async () => {
|
|
1290
|
+
if (!picker) return;
|
|
1291
|
+
setBusy(true);
|
|
1292
|
+
setError(null);
|
|
1293
|
+
try {
|
|
1294
|
+
const asset = await picker.selectAsset({ pageId, blockId, current: { url } });
|
|
1295
|
+
if (asset && active.current) {
|
|
1296
|
+
if (validateFieldValue({ field: "", control: "asset", required: true }, asset.url).length) throw new Error("Invalid image URL");
|
|
1297
|
+
onChange(asset.url);
|
|
1298
|
+
}
|
|
1299
|
+
} catch {
|
|
1300
|
+
setError(i18n.t("selectAssetFailed"));
|
|
1301
|
+
} finally {
|
|
1302
|
+
setBusy(false);
|
|
1303
|
+
}
|
|
1304
|
+
})(), children: busy ? i18n.t("selectingAsset") : i18n.t("selectAsset") }),
|
|
1305
|
+
error ? /* @__PURE__ */ jsx7(Text3, { as: "p", variant: "bodySm", tone: "critical", children: error }) : null
|
|
1306
|
+
] });
|
|
1307
|
+
}
|
|
1263
1308
|
function InspectorProductsControl({ value, disabled, picker, pageId, blockId, i18n, onChange }) {
|
|
1264
1309
|
const products = parseProductReferences(value);
|
|
1265
1310
|
const [busy, setBusy] = useState3(false);
|
|
@@ -1286,7 +1331,7 @@ function InspectorProductsControl({ value, disabled, picker, pageId, blockId, i1
|
|
|
1286
1331
|
error ? /* @__PURE__ */ jsx7(Text3, { as: "p", variant: "bodySm", tone: "critical", children: error }) : null
|
|
1287
1332
|
] });
|
|
1288
1333
|
}
|
|
1289
|
-
function InspectorField({ name, field, value, registry, disabled, productPicker, pageId, blockId, i18n, onChange }) {
|
|
1334
|
+
function InspectorField({ name, field, value, registry, disabled, assetPicker, productPicker, pageId, blockId, i18n, onChange }) {
|
|
1290
1335
|
const label = field.label ?? name;
|
|
1291
1336
|
const issues = validateFieldValue(field, value);
|
|
1292
1337
|
const Field = registry?.getField(field.field)?.component;
|
|
@@ -1295,7 +1340,7 @@ function InspectorField({ name, field, value, registry, disabled, productPicker,
|
|
|
1295
1340
|
/* @__PURE__ */ jsx7(Text3, { as: "p", variant: "bodySm", fontWeight: "semibold", children: label }),
|
|
1296
1341
|
field.description ? /* @__PURE__ */ jsx7(Text3, { as: "p", variant: "bodySm", tone: "subdued", children: field.description }) : null
|
|
1297
1342
|
] }),
|
|
1298
|
-
field.control === "products" ? /* @__PURE__ */ jsx7(InspectorProductsControl, { value, disabled, picker: productPicker, 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,
|
|
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,
|
|
1299
1344
|
issues.map((issue) => /* @__PURE__ */ jsx7(Text3, { as: "p", variant: "bodySm", tone: "critical", children: issue.message }, issue.message))
|
|
1300
1345
|
] });
|
|
1301
1346
|
}
|
|
@@ -1334,7 +1379,7 @@ function inspectorFieldConfig(name, field) {
|
|
|
1334
1379
|
return { ...field, group: field.group ?? group, description };
|
|
1335
1380
|
}
|
|
1336
1381
|
var appearanceTokens = [["color.primary", "\u4E3B\u8272"], ["color.surface", "\u8868\u9762\u8272"], ["radius", "\u5706\u89D2"], ["spacing", "\u95F4\u8DDD"]];
|
|
1337
|
-
function DocumentInspector({ pageId, assetPicker, productPicker, i18n, block, registry, disabled, appearanceControls, onChange, onPresentationChange }) {
|
|
1382
|
+
function DocumentInspector({ settings, pageId, assetPicker, productPicker, i18n, block, registry, disabled, appearanceControls, onChange, onPresentationChange }) {
|
|
1338
1383
|
const [assetError, setAssetError] = useState3(null);
|
|
1339
1384
|
const [selectingAsset, setSelectingAsset] = useState3(false);
|
|
1340
1385
|
const definition = registry?.getBlock(block.type);
|
|
@@ -1373,7 +1418,8 @@ function DocumentInspector({ pageId, assetPicker, productPicker, i18n, block, re
|
|
|
1373
1418
|
assetError ? /* @__PURE__ */ jsx7(Text3, { as: "p", variant: "bodySm", tone: "critical", children: assetError }) : null
|
|
1374
1419
|
] }) : null
|
|
1375
1420
|
] }) : null,
|
|
1376
|
-
Object.entries(groupedFields).map(([group, fields]) => /* @__PURE__ */ jsx7(InspectorSection, { title: group, defaultOpen: group !== "Advanced", children: fields.map(([name, field]) => /* @__PURE__ */ jsx7(InspectorField, { name, field, value: block.props[name], registry, disabled, productPicker, pageId, blockId: block.id, i18n, onChange: (value) => onChange({
|
|
1421
|
+
Object.entries(groupedFields).map(([group, fields]) => /* @__PURE__ */ jsx7(InspectorSection, { title: group, defaultOpen: group !== "Advanced", children: fields.map(([name, field]) => /* @__PURE__ */ jsx7(InspectorField, { name, field, value: 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)),
|
|
1422
|
+
Object.values(definition?.fields ?? {}).some((field) => field.persist === false) ? settings?.footer : null,
|
|
1377
1423
|
appearanceControls && definition?.variants?.length ? /* @__PURE__ */ jsx7(InspectorSection, { title: "\u5916\u89C2", children: /* @__PURE__ */ jsx7(Select2, { label: "\u6837\u5F0F\u53D8\u4F53", options: definition.variants.map((variant) => ({ label: variant.label, value: variant.id })), value: block.variant, disabled, onChange: (variant) => onPresentationChange({ variant, style: block.style }) }) }) : null,
|
|
1378
1424
|
appearanceControls && definition ? /* @__PURE__ */ jsx7(InspectorSection, { title: "\u6837\u5F0F\u8986\u76D6", defaultOpen: false, children: appearanceTokens.map(([token, label]) => /* @__PURE__ */ jsx7(TextField, { label, value: block.style[token] ?? "", placeholder: "\u7EE7\u627F\u9875\u9762\u6216\u6A21\u677F\u8BBE\u7F6E", autoComplete: "off", disabled, onChange: (value) => {
|
|
1379
1425
|
const style = { ...block.style };
|
|
@@ -42,9 +42,11 @@ type FieldConfig = {
|
|
|
42
42
|
field: string;
|
|
43
43
|
label?: string;
|
|
44
44
|
/** Product-facing editor metadata. Custom field components remain supported. */
|
|
45
|
-
control?: "text" | "textarea" | "url" | "color" | "products";
|
|
45
|
+
control?: "text" | "textarea" | "url" | "color" | "products" | "asset";
|
|
46
46
|
description?: string;
|
|
47
47
|
group?: string;
|
|
48
|
+
/** Host-owned setting; never written to PageDocument props. */
|
|
49
|
+
persist?: boolean;
|
|
48
50
|
/** Kept for compatibility; it participates in the built-in validation. */
|
|
49
51
|
required?: boolean;
|
|
50
52
|
validation?: FieldValidation;
|
package/dist/renderer.d.ts
CHANGED
package/dist/runtime.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
export { WebRenderer, WebRendererProps } from './renderer.js';
|
|
2
|
-
export { B as BlockDefinition, a as BlockEditorProps, b as BlockOperation, c as BlockPolicy, d as BlockVariantDefinition, D as DataSourceDefinition, E as EditorAction, e as EditorActionPosition, f as EditorOperationPolicy, g as ExtensionActionContext, h as ExtensionRegistry, i as ExtensionRegistryError, j as ExtensionRegistryErrorCode, k as ExtensionRegistryOptions, l as ExtensionTarget, F as FieldConfig, m as FieldDefinition, n as FieldProps, o as FieldValidation, L as LifecycleHooks, P as PageBuilderExtension, R as RendererDefinition, T as TemplateDefinition, p as TemplateRegistry, q as TemplateSource, U as UISlotContribution, r as UISlotName, V as ValidationIssue, s as createExtensionRegistry, t as createTemplateRegistry } from './registry-
|
|
2
|
+
export { B as BlockDefinition, a as BlockEditorProps, b as BlockOperation, c as BlockPolicy, d as BlockVariantDefinition, D as DataSourceDefinition, E as EditorAction, e as EditorActionPosition, f as EditorOperationPolicy, g as ExtensionActionContext, h as ExtensionRegistry, i as ExtensionRegistryError, j as ExtensionRegistryErrorCode, k as ExtensionRegistryOptions, l as ExtensionTarget, F as FieldConfig, m as FieldDefinition, n as FieldProps, o as FieldValidation, L as LifecycleHooks, P as PageBuilderExtension, R as RendererDefinition, T as TemplateDefinition, p as TemplateRegistry, q as TemplateSource, U as UISlotContribution, r as UISlotName, V as ValidationIssue, s as createExtensionRegistry, t as createTemplateRegistry } from './registry-BkqtMP-A.js';
|
|
3
3
|
export { ProductReference, isProductReference, maximumBlockInstances, mergeBlockPolicies, minimumBlockInstances, parseProductReferences, toProductReferenceJson, validateBlockPolicy, validateFieldValue, validatePageDocumentWithRegistry } from './extensions.js';
|
|
4
4
|
export { BlockNode, BlockStyleOverrides, DataBinding, JsonPrimitive, JsonValue, PageDocument, PageDocumentIssue, PageDocumentMigration, PageDocumentSchemaVersion, PageDocumentValidation, PageSettings, RenderTarget, createPageDocument, migratePageDocument, validatePageDocument } from './schema.js';
|
|
5
5
|
export { ThemeTokenName, ThemeTokenValidation, ThemeTokens, mergeThemeTokens, normalizeThemeTokens, systemThemeTokens, toThemeStyle } from './theme.js';
|
package/dist/runtime.js
CHANGED
package/package.json
CHANGED
package/src/styles.css
CHANGED
|
@@ -8,14 +8,14 @@ button:focus-visible, [role="button"]:focus-visible { outline: 2px solid var(--b
|
|
|
8
8
|
.pb-shell [class*="PuckLayout-inner"] { height: auto !important; min-height: 100%; }
|
|
9
9
|
.pb-header { position: sticky; top: 0; z-index: 20; min-height: 56px; padding: var(--builder-space-2) var(--builder-space-4); border-bottom: 1px solid var(--builder-border); background: var(--builder-surface); }
|
|
10
10
|
.pb-header-content { display: flex; flex-wrap: wrap; align-items: center; gap: var(--builder-space-2) var(--builder-space-3); }
|
|
11
|
-
.pb-header-title-group { display: flex; flex: 1 1
|
|
11
|
+
.pb-header-title-group { display: flex; flex: 1 1 12rem; align-items: center; gap: var(--builder-space-2); min-width: 0; }
|
|
12
12
|
.pb-header-sidebar-toggles, [class*="PuckHeader-toggle"] { display: none !important; }
|
|
13
13
|
.pb-page-title { display: grid; gap: 0; min-width: 0; }
|
|
14
14
|
.pb-page-title h1, .pb-page-title p { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
|
|
15
15
|
.pb-page-title p { margin: 0; }
|
|
16
|
-
.pb-header-controls { display: flex; flex:
|
|
17
|
-
.pb-header-device-toolbar { display: flex; align-items: center; gap: var(--builder-space-2); }
|
|
18
|
-
.pb-header-actions { display: flex; flex: 1 1
|
|
16
|
+
.pb-header-controls { display: flex; flex: 2 1 28rem; flex-wrap: wrap; align-items: center; justify-content: flex-end; gap: var(--builder-space-2) var(--builder-space-3); min-width: 0; }
|
|
17
|
+
.pb-header-device-toolbar { display: flex; flex: 0 1 auto; align-items: center; gap: var(--builder-space-2); min-width: 0; }
|
|
18
|
+
.pb-header-actions { display: flex; flex: 1 1 16rem; justify-content: flex-end; min-width: 0; }
|
|
19
19
|
.pb-header-actions .Polaris-InlineStack { flex-wrap: wrap; justify-content: flex-end; }
|
|
20
20
|
.pb-header-actions .Polaris-Badge { max-width: 14rem; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
|
|
21
21
|
.pb-zoom-control { width: 112px; flex: 0 0 auto; }
|
|
@@ -60,6 +60,8 @@ button:focus-visible, [role="button"]:focus-visible { outline: 2px solid var(--b
|
|
|
60
60
|
.pb-product-picker__thumb:first-child { margin-left: 0; }
|
|
61
61
|
.pb-product-picker__thumb img, .pb-product-picker__thumb-fallback { display: block; width: 100%; height: 100%; object-fit: cover; }
|
|
62
62
|
.pb-product-picker__thumb-fallback { background: #cbd5e1; }
|
|
63
|
+
.pb-asset-picker { display: grid; gap: 8px; }
|
|
64
|
+
.pb-asset-picker__preview { display: block; width: 100%; max-height: 180px; object-fit: cover; border: 1px solid #e2e8f0; border-radius: 10px; background: #f8fafc; }
|
|
63
65
|
.pb-inspector__hint { margin: 0; padding: 0 var(--builder-space-2); color: #64748b; font-size: 12px; line-height: 1.5; }
|
|
64
66
|
.pb-inspector-actions { padding-top: var(--builder-space-2); border-top: 1px solid #e2e8f0; }
|
|
65
67
|
.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%); }
|
|
@@ -143,4 +145,4 @@ button:focus-visible, [role="button"]:focus-visible { outline: 2px solid var(--b
|
|
|
143
145
|
.bt-storefront__form button { padding: 13px 18px; border: 0; border-radius: 8px; color: white; background: #203e54; font: inherit; font-weight: 600; }
|
|
144
146
|
@media (max-width: 1180px) { .pb-workspace { grid-template-columns: 64px minmax(260px, 300px) minmax(0, 1fr); } .pb-workspace--left-closed { grid-template-columns: 64px minmax(0, 1fr); } .pb-right-panel { grid-column: 2 / -1; border-top: 1px solid var(--builder-border); border-left: 0; } }
|
|
145
147
|
@media (max-width: 1023px) { .pb-header { position: static; } .pb-workspace { grid-template-columns: 64px minmax(0, 1fr); } .pb-left-panel, .pb-right-panel { grid-column: 2; border-left: 0; border-right: 0; border-bottom: 1px solid var(--builder-border); } .pb-canvas-area { grid-column: 2; } }
|
|
146
|
-
@media (max-width: 640px) { .pb-header, .pb-canvas-area { padding: var(--builder-space-2); } .pb-header-title-group, .pb-header-controls, .pb-header-actions { flex:
|
|
148
|
+
@media (max-width: 640px) { .pb-header, .pb-canvas-area { padding: var(--builder-space-2); } .pb-header-title-group, .pb-header-controls, .pb-header-actions { flex-basis: 100%; } .pb-header-controls, .pb-header-actions { justify-content: flex-start; } .pb-header-actions .Polaris-InlineStack { justify-content: flex-start; } .pb-canvas-stage { padding: 0; } .pb-canvas-frame--tablet, .pb-canvas-frame--mobile { width: 100%; } .bt-storefront { padding: 28px 20px; } .bt-storefront__form { flex-direction: column; } }
|