@standhigher/puck-page-builder 0.10.0 → 0.12.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1 -1
- package/dist/{chunk-PFCWXLWN.js → chunk-YXBTNYPR.js} +50 -0
- package/dist/extensions.d.ts +18 -4
- package/dist/extensions.js +7 -1
- package/dist/index.d.ts +46 -5
- package/dist/index.js +108 -36
- package/dist/{registry-eNtkEC6o.d.ts → registry-CXJdOya3.d.ts} +1 -1
- package/dist/renderer.d.ts +1 -1
- package/dist/runtime.d.ts +2 -2
- package/dist/runtime.js +7 -1
- package/package.json +1 -1
- package/src/styles.css +39 -18
package/README.md
CHANGED
|
@@ -65,7 +65,7 @@ const notice = {
|
|
|
65
65
|
/>
|
|
66
66
|
```
|
|
67
67
|
|
|
68
|
-
Built-in field controls are `text` (single line), `textarea` (multi-line), `url`, and `
|
|
68
|
+
Built-in field controls are `text` (single line), `textarea` (multi-line), `url`, `color`, and `products`. `products` only renders the selected snapshot and a host picker button; Shopify search stays in the host `productPicker` adapter. Their validation runs in the editor before save or publish; custom fields may continue using a block's `validate` function. `validateFieldValue` is exported from `/extensions` when a host needs the same validation outside the editor.
|
|
69
69
|
|
|
70
70
|
Theme values remain deliberately token-based: template theme → page theme → variant theme → block style. A block resets an inherited token by setting its local token explicitly (for example `{ radius: "0" }`), so no incompatible persisted style-reset shape is needed.
|
|
71
71
|
|
|
@@ -1,3 +1,46 @@
|
|
|
1
|
+
// src/core/extensions/product-reference.ts
|
|
2
|
+
function isHttpUrl(value) {
|
|
3
|
+
try {
|
|
4
|
+
const url = new URL(value);
|
|
5
|
+
return (url.protocol === "https:" || url.protocol === "http:") && !url.username && !url.password;
|
|
6
|
+
} catch {
|
|
7
|
+
return false;
|
|
8
|
+
}
|
|
9
|
+
}
|
|
10
|
+
function isProductReference(value) {
|
|
11
|
+
if (!value || typeof value !== "object" || Array.isArray(value)) return false;
|
|
12
|
+
const candidate = value;
|
|
13
|
+
if (typeof candidate.id !== "string" || !candidate.id.trim()) return false;
|
|
14
|
+
if (candidate.title !== void 0 && typeof candidate.title !== "string") return false;
|
|
15
|
+
if (candidate.handle !== void 0 && typeof candidate.handle !== "string") return false;
|
|
16
|
+
if (candidate.imageUrl !== void 0 && (typeof candidate.imageUrl !== "string" || !isHttpUrl(candidate.imageUrl))) return false;
|
|
17
|
+
return true;
|
|
18
|
+
}
|
|
19
|
+
function parseProductReferences(value) {
|
|
20
|
+
if (!Array.isArray(value)) return [];
|
|
21
|
+
const products = [];
|
|
22
|
+
for (const item of value) {
|
|
23
|
+
if (!item || typeof item !== "object" || Array.isArray(item)) continue;
|
|
24
|
+
const candidate = item;
|
|
25
|
+
if (typeof candidate.id !== "string" || !candidate.id.trim()) continue;
|
|
26
|
+
products.push({
|
|
27
|
+
id: candidate.id.trim(),
|
|
28
|
+
...typeof candidate.title === "string" && candidate.title.trim() ? { title: candidate.title.trim() } : {},
|
|
29
|
+
...typeof candidate.handle === "string" && candidate.handle.trim() ? { handle: candidate.handle.trim() } : {},
|
|
30
|
+
...typeof candidate.imageUrl === "string" && isHttpUrl(candidate.imageUrl) ? { imageUrl: candidate.imageUrl } : {}
|
|
31
|
+
});
|
|
32
|
+
}
|
|
33
|
+
return products;
|
|
34
|
+
}
|
|
35
|
+
function toProductReferenceJson(product) {
|
|
36
|
+
return {
|
|
37
|
+
id: product.id,
|
|
38
|
+
...product.title ? { title: product.title } : {},
|
|
39
|
+
...product.handle ? { handle: product.handle } : {},
|
|
40
|
+
...product.imageUrl ? { imageUrl: product.imageUrl } : {}
|
|
41
|
+
};
|
|
42
|
+
}
|
|
43
|
+
|
|
1
44
|
// src/core/extensions/validation.ts
|
|
2
45
|
var hexColor = /^#(?:[\da-f]{3}|[\da-f]{4}|[\da-f]{6}|[\da-f]{8})$/i;
|
|
3
46
|
function stringLength(value) {
|
|
@@ -19,6 +62,10 @@ function validateFieldValue(config, value) {
|
|
|
19
62
|
const control = config.control;
|
|
20
63
|
if (!control && !config.required && !config.validation) return [];
|
|
21
64
|
if (value === void 0 && !config.required) return [];
|
|
65
|
+
if (control === "products") {
|
|
66
|
+
if (!Array.isArray(value)) return [{ path: "", message: "\u5FC5\u987B\u662F\u5546\u54C1\u5217\u8868\u3002" }];
|
|
67
|
+
return value.flatMap((item, index) => isProductReference(item) ? [] : [{ path: String(index), message: "\u5FC5\u987B\u5305\u542B\u7A33\u5B9A\u7684\u5546\u54C1 ID\u3002" }]);
|
|
68
|
+
}
|
|
22
69
|
if (typeof value !== "string") return [{ path: "", message: "\u5FC5\u987B\u662F\u5B57\u7B26\u4E32\u3002" }];
|
|
23
70
|
const issues = [];
|
|
24
71
|
if (config.required && value.trim().length === 0) issues.push({ path: "", message: "\u6B64\u5B57\u6BB5\u4E3A\u5FC5\u586B\u9879\u3002" });
|
|
@@ -314,6 +361,9 @@ function validatePageDocumentWithRegistry(document, registry) {
|
|
|
314
361
|
}
|
|
315
362
|
|
|
316
363
|
export {
|
|
364
|
+
isProductReference,
|
|
365
|
+
parseProductReferences,
|
|
366
|
+
toProductReferenceJson,
|
|
317
367
|
validateFieldValue,
|
|
318
368
|
validateBlockPolicy,
|
|
319
369
|
mergeBlockPolicies,
|
package/dist/extensions.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
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-
|
|
3
|
-
import { PageDocument } from './schema.js';
|
|
1
|
+
import { h as ExtensionRegistry, V as ValidationIssue, c as BlockPolicy, F as FieldConfig } from './registry-CXJdOya3.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-CXJdOya3.js';
|
|
3
|
+
import { PageDocument, JsonValue } from './schema.js';
|
|
4
4
|
import 'react';
|
|
5
5
|
import './theme.js';
|
|
6
6
|
|
|
@@ -12,6 +12,20 @@ import './theme.js';
|
|
|
12
12
|
*/
|
|
13
13
|
declare function validatePageDocumentWithRegistry(document: PageDocument, registry: ExtensionRegistry): ValidationIssue[];
|
|
14
14
|
|
|
15
|
+
/**
|
|
16
|
+
* JSON-only product snapshot persisted in PageDocument props.
|
|
17
|
+
* Hosts may add a stable id plus display fields; never store tokens or prices as secrets.
|
|
18
|
+
*/
|
|
19
|
+
type ProductReference = {
|
|
20
|
+
id: string;
|
|
21
|
+
title?: string;
|
|
22
|
+
imageUrl?: string;
|
|
23
|
+
handle?: string;
|
|
24
|
+
};
|
|
25
|
+
declare function isProductReference(value: unknown): value is ProductReference;
|
|
26
|
+
declare function parseProductReferences(value: unknown): ProductReference[];
|
|
27
|
+
declare function toProductReferenceJson(product: ProductReference): JsonValue;
|
|
28
|
+
|
|
15
29
|
/** Validates the portable built-in controls without relying on browser-only APIs. */
|
|
16
30
|
declare function validateFieldValue(config: FieldConfig, value: unknown): ValidationIssue[];
|
|
17
31
|
/** Returns a diagnostic for an invalid declaration, or `null` when it is usable. */
|
|
@@ -20,4 +34,4 @@ declare function mergeBlockPolicies(...policies: Array<BlockPolicy | undefined>)
|
|
|
20
34
|
declare function minimumBlockInstances(policy: BlockPolicy | undefined): number;
|
|
21
35
|
declare function maximumBlockInstances(policy: BlockPolicy | undefined): number;
|
|
22
36
|
|
|
23
|
-
export { BlockPolicy, ExtensionRegistry, FieldConfig, ValidationIssue, maximumBlockInstances, mergeBlockPolicies, minimumBlockInstances, validateBlockPolicy, validateFieldValue, validatePageDocumentWithRegistry };
|
|
37
|
+
export { BlockPolicy, ExtensionRegistry, FieldConfig, type ProductReference, ValidationIssue, isProductReference, maximumBlockInstances, mergeBlockPolicies, minimumBlockInstances, parseProductReferences, toProductReferenceJson, validateBlockPolicy, validateFieldValue, validatePageDocumentWithRegistry };
|
package/dist/extensions.js
CHANGED
|
@@ -4,22 +4,28 @@ import {
|
|
|
4
4
|
TemplateRegistry,
|
|
5
5
|
createExtensionRegistry,
|
|
6
6
|
createTemplateRegistry,
|
|
7
|
+
isProductReference,
|
|
7
8
|
maximumBlockInstances,
|
|
8
9
|
mergeBlockPolicies,
|
|
9
10
|
minimumBlockInstances,
|
|
11
|
+
parseProductReferences,
|
|
12
|
+
toProductReferenceJson,
|
|
10
13
|
validateBlockPolicy,
|
|
11
14
|
validateFieldValue,
|
|
12
15
|
validatePageDocumentWithRegistry
|
|
13
|
-
} from "./chunk-
|
|
16
|
+
} from "./chunk-YXBTNYPR.js";
|
|
14
17
|
export {
|
|
15
18
|
ExtensionRegistry,
|
|
16
19
|
ExtensionRegistryError,
|
|
17
20
|
TemplateRegistry,
|
|
18
21
|
createExtensionRegistry,
|
|
19
22
|
createTemplateRegistry,
|
|
23
|
+
isProductReference,
|
|
20
24
|
maximumBlockInstances,
|
|
21
25
|
mergeBlockPolicies,
|
|
22
26
|
minimumBlockInstances,
|
|
27
|
+
parseProductReferences,
|
|
28
|
+
toProductReferenceJson,
|
|
23
29
|
validateBlockPolicy,
|
|
24
30
|
validateFieldValue,
|
|
25
31
|
validatePageDocumentWithRegistry
|
package/dist/index.d.ts
CHANGED
|
@@ -1,13 +1,14 @@
|
|
|
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-CXJdOya3.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-CXJdOya3.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
|
+
import { ProductReference } from './extensions.js';
|
|
8
|
+
export { isProductReference, maximumBlockInstances, mergeBlockPolicies, minimumBlockInstances, parseProductReferences, toProductReferenceJson, validateBlockPolicy, validateFieldValue, validatePageDocumentWithRegistry } from './extensions.js';
|
|
7
9
|
export { ThemeTokenName, ThemeTokens, mergeThemeTokens, normalizeThemeTokens, systemThemeTokens, toThemeStyle } from './theme.js';
|
|
8
10
|
import { Data } from '@puckeditor/core';
|
|
9
11
|
export { WebRenderer, WebRendererProps } from './renderer.js';
|
|
10
|
-
export { maximumBlockInstances, mergeBlockPolicies, minimumBlockInstances, validateBlockPolicy, validateFieldValue, validatePageDocumentWithRegistry } from './extensions.js';
|
|
11
12
|
|
|
12
13
|
type BlockView = "blocks" | "outline";
|
|
13
14
|
type Device = "desktop" | "tablet" | "mobile" | "full";
|
|
@@ -129,6 +130,19 @@ type AssetPickerAdapter = {
|
|
|
129
130
|
current?: Partial<AssetReference>;
|
|
130
131
|
}): Promise<AssetReference | null>;
|
|
131
132
|
};
|
|
133
|
+
/**
|
|
134
|
+
* Opens a host-owned product picker. Search, Shopify App Bridge, and
|
|
135
|
+
* authorization stay in the host; this package only displays the snapshot
|
|
136
|
+
* and forwards the button click.
|
|
137
|
+
*/
|
|
138
|
+
type ProductPickerAdapter = {
|
|
139
|
+
selectProducts(input: {
|
|
140
|
+
pageId: string;
|
|
141
|
+
blockId: string;
|
|
142
|
+
current: readonly ProductReference[];
|
|
143
|
+
multiple?: boolean;
|
|
144
|
+
}): Promise<readonly ProductReference[] | null>;
|
|
145
|
+
};
|
|
132
146
|
type PagePublicationStatus = "unpublished" | "published";
|
|
133
147
|
/** Presentational data for the reusable page state card. */
|
|
134
148
|
type PageStatus = {
|
|
@@ -233,9 +247,16 @@ type PageDocumentEditorShellProps = {
|
|
|
233
247
|
publishAction?: PublishAction;
|
|
234
248
|
/** Host-owned picker/uploader for shop-scoped assets. */
|
|
235
249
|
assetPicker?: AssetPickerAdapter;
|
|
250
|
+
/** Host-owned product picker. The shell only shows the selected snapshot and a button. */
|
|
251
|
+
productPicker?: ProductPickerAdapter;
|
|
236
252
|
/** Optional reusable page lifecycle summary. */
|
|
237
253
|
pageStatus?: PageStatus;
|
|
238
254
|
onBack?: () => void;
|
|
255
|
+
onHistory?: (input: {
|
|
256
|
+
document: PageDocument;
|
|
257
|
+
draftRevision?: number;
|
|
258
|
+
session?: EditorSession;
|
|
259
|
+
}) => void;
|
|
239
260
|
onPreview?: (input: {
|
|
240
261
|
document: PageDocument;
|
|
241
262
|
draftRevision?: number;
|
|
@@ -286,6 +307,7 @@ declare const messages: {
|
|
|
286
307
|
readonly unsaved: "未保存变更";
|
|
287
308
|
readonly saved: "所有更改已保留在当前会话中";
|
|
288
309
|
readonly save: "保存草稿";
|
|
310
|
+
readonly history: "历史记录";
|
|
289
311
|
readonly saving: "正在保存…";
|
|
290
312
|
readonly publish: "发布";
|
|
291
313
|
readonly publishing: "正在发布…";
|
|
@@ -310,6 +332,15 @@ declare const messages: {
|
|
|
310
332
|
readonly desktop: "桌面";
|
|
311
333
|
readonly tablet: "平板";
|
|
312
334
|
readonly mobile: "手机";
|
|
335
|
+
readonly collapseLeft: "收起左侧面板";
|
|
336
|
+
readonly collapseRight: "收起属性面板";
|
|
337
|
+
readonly expandLeft: "打开区块面板";
|
|
338
|
+
readonly expandRight: "打开属性面板";
|
|
339
|
+
readonly selectProducts: "从 Shopify 选择商品";
|
|
340
|
+
readonly selectingProducts: "正在选择商品…";
|
|
341
|
+
readonly selectProductsFailed: "无法选择商品,请重试。";
|
|
342
|
+
readonly emptyProducts: "未选择商品";
|
|
343
|
+
readonly productCountSuffix: "件商品";
|
|
313
344
|
};
|
|
314
345
|
readonly en: {
|
|
315
346
|
readonly blocks: "Blocks";
|
|
@@ -334,6 +365,7 @@ declare const messages: {
|
|
|
334
365
|
readonly unsaved: "Unsaved changes";
|
|
335
366
|
readonly saved: "Changes are kept in this session";
|
|
336
367
|
readonly save: "Save draft";
|
|
368
|
+
readonly history: "History";
|
|
337
369
|
readonly saving: "Saving…";
|
|
338
370
|
readonly publish: "Publish";
|
|
339
371
|
readonly publishing: "Publishing…";
|
|
@@ -358,16 +390,25 @@ declare const messages: {
|
|
|
358
390
|
readonly desktop: "Desktop";
|
|
359
391
|
readonly tablet: "Tablet";
|
|
360
392
|
readonly mobile: "Mobile";
|
|
393
|
+
readonly collapseLeft: "Collapse blocks panel";
|
|
394
|
+
readonly collapseRight: "Collapse properties panel";
|
|
395
|
+
readonly expandLeft: "Open blocks panel";
|
|
396
|
+
readonly expandRight: "Open properties panel";
|
|
397
|
+
readonly selectProducts: "Select from Shopify";
|
|
398
|
+
readonly selectingProducts: "Selecting products…";
|
|
399
|
+
readonly selectProductsFailed: "Could not select products. Try again.";
|
|
400
|
+
readonly emptyProducts: "No products selected";
|
|
401
|
+
readonly productCountSuffix: "products";
|
|
361
402
|
};
|
|
362
403
|
};
|
|
363
404
|
type AdminMessageKey = keyof typeof messages["zh-CN"];
|
|
364
405
|
/** Minimal, dependency-free Admin copy catalog. Product locale remains PageDocument.settings.locale. */
|
|
365
406
|
declare function createAdminI18n(locale?: string): {
|
|
366
407
|
locale: AdminLocale;
|
|
367
|
-
t: (key: AdminMessageKey) => "Desktop" | "Tablet" | "Mobile" | "未保存变更" | "Outline" | "Preview" | "缩放" | "区块" | "结构" | "撤销" | "恢复" | "Delete" | "Duplicate" | "编辑锁已失效" | "属性" | "添加区块" | "复制" | "删除" | "确认删除区块?" | "删除后可使用撤销恢复。" | "取消" | "确认删除" | "上移" | "下移" | "正在加载编辑器…" | "页面还没有区块" | "编辑器无法加载" | "编辑器当前不可编辑" | "操作已完成" | "所有更改已保留在当前会话中" | "保存草稿" | "正在保存…" | "发布" | "正在发布…" | "保存草稿失败" | "重试保存" | "当前离线,恢复网络后将自动保存" | "发布失败" | "已发布" | "返回" | "离开编辑器?" | "离开" | "自动缩放" | "正式预览" | "添加到店铺" | "正在获取编辑锁…" | "该页面正在被编辑" | "页面为只读状态" | "你有未保存的更改。确定要离开吗?" | "选择一个区块以编辑。" | "桌面" | "平板" | "手机" | "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" | "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.";
|
|
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";
|
|
368
409
|
};
|
|
369
410
|
|
|
370
411
|
declare function toEngineData(document: PageDocument, registry?: ExtensionRegistry): Data;
|
|
371
412
|
declare function fromEngineData(data: Data, base: PageDocument, registry?: ExtensionRegistry): PageDocument;
|
|
372
413
|
|
|
373
|
-
export { type AdminLocale, type AdminMessageKey, type AssetPickerAdapter, type AssetReference, type AssetStatus, BlockNode, BlockPolicy, type DeleteConfirmationConfig, type DemoBlock, type Device, type DraftPersistenceAdapter, type DraftSaveInput, type DraftSaveResult, type EditorActionState, type EditorLoadState, EditorOperationPolicy, EditorProvider, type EditorSession, type EditorSessionAcquireResult, type EditorSessionAdapter, type EditorSessionState, EditorShell, type EditorShellProps, type EditorState, ExtensionRegistry, JsonValue, PageDocument, type PageDocumentEditorPolicy, PageDocumentEditorShell, type PageDocumentEditorShellProps, type PagePublicationStatus, type PageStatus, PageStatusCard, type PageStatusCardProps, type PreviewMode, type PublishAction, type PublishActionInput, type PublishActionResult, type PublishState, type SaveState, ValidationIssue, type Zoom, createAdminI18n, fromEngineData, toEngineData, useEditorContext };
|
|
414
|
+
export { type AdminLocale, type AdminMessageKey, type AssetPickerAdapter, type AssetReference, type AssetStatus, BlockNode, BlockPolicy, type DeleteConfirmationConfig, type DemoBlock, type Device, type DraftPersistenceAdapter, type DraftSaveInput, type DraftSaveResult, type EditorActionState, type EditorLoadState, EditorOperationPolicy, EditorProvider, type EditorSession, type EditorSessionAcquireResult, type EditorSessionAdapter, type EditorSessionState, EditorShell, type EditorShellProps, type EditorState, ExtensionRegistry, JsonValue, PageDocument, type PageDocumentEditorPolicy, PageDocumentEditorShell, type PageDocumentEditorShellProps, type PagePublicationStatus, type PageStatus, PageStatusCard, type PageStatusCardProps, type PreviewMode, type ProductPickerAdapter, ProductReference, type PublishAction, type PublishActionInput, type PublishActionResult, type PublishState, type SaveState, ValidationIssue, type Zoom, createAdminI18n, fromEngineData, toEngineData, useEditorContext };
|
package/dist/index.js
CHANGED
|
@@ -4,13 +4,16 @@ import {
|
|
|
4
4
|
TemplateRegistry,
|
|
5
5
|
createExtensionRegistry,
|
|
6
6
|
createTemplateRegistry,
|
|
7
|
+
isProductReference,
|
|
7
8
|
maximumBlockInstances,
|
|
8
9
|
mergeBlockPolicies,
|
|
9
10
|
minimumBlockInstances,
|
|
11
|
+
parseProductReferences,
|
|
12
|
+
toProductReferenceJson,
|
|
10
13
|
validateBlockPolicy,
|
|
11
14
|
validateFieldValue,
|
|
12
15
|
validatePageDocumentWithRegistry
|
|
13
|
-
} from "./chunk-
|
|
16
|
+
} from "./chunk-YXBTNYPR.js";
|
|
14
17
|
import {
|
|
15
18
|
WebRenderer
|
|
16
19
|
} from "./chunk-KYXIXIWK.js";
|
|
@@ -349,7 +352,7 @@ function PropertyPanel({
|
|
|
349
352
|
// src/editor/shell/PageDocumentEditorShell.tsx
|
|
350
353
|
import { Puck as Puck2, usePuck } from "@puckeditor/core";
|
|
351
354
|
import { Badge as Badge3, Banner, Button as Button2, ButtonGroup as ButtonGroup2, InlineStack as InlineStack3, Select as Select2, Text as Text3, TextField } from "@shopify/polaris";
|
|
352
|
-
import { DragHandleIcon as DragHandleIcon2, LayoutSectionIcon as LayoutSectionIcon2, MenuIcon as MenuIcon2, RedoIcon as RedoIcon2, UndoIcon as UndoIcon2 } from "@shopify/polaris-icons";
|
|
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";
|
|
353
356
|
import { useCallback as useCallback2, useEffect as useEffect3, useMemo as useMemo2, useRef as useRef4, useState as useState3 } from "react";
|
|
354
357
|
|
|
355
358
|
// src/adapters/puck/canvas-extension-block.tsx
|
|
@@ -786,6 +789,7 @@ var messages = {
|
|
|
786
789
|
unsaved: "\u672A\u4FDD\u5B58\u53D8\u66F4",
|
|
787
790
|
saved: "\u6240\u6709\u66F4\u6539\u5DF2\u4FDD\u7559\u5728\u5F53\u524D\u4F1A\u8BDD\u4E2D",
|
|
788
791
|
save: "\u4FDD\u5B58\u8349\u7A3F",
|
|
792
|
+
history: "\u5386\u53F2\u8BB0\u5F55",
|
|
789
793
|
saving: "\u6B63\u5728\u4FDD\u5B58\u2026",
|
|
790
794
|
publish: "\u53D1\u5E03",
|
|
791
795
|
publishing: "\u6B63\u5728\u53D1\u5E03\u2026",
|
|
@@ -809,7 +813,16 @@ var messages = {
|
|
|
809
813
|
selectBlock: "\u9009\u62E9\u4E00\u4E2A\u533A\u5757\u4EE5\u7F16\u8F91\u3002",
|
|
810
814
|
desktop: "\u684C\u9762",
|
|
811
815
|
tablet: "\u5E73\u677F",
|
|
812
|
-
mobile: "\u624B\u673A"
|
|
816
|
+
mobile: "\u624B\u673A",
|
|
817
|
+
collapseLeft: "\u6536\u8D77\u5DE6\u4FA7\u9762\u677F",
|
|
818
|
+
collapseRight: "\u6536\u8D77\u5C5E\u6027\u9762\u677F",
|
|
819
|
+
expandLeft: "\u6253\u5F00\u533A\u5757\u9762\u677F",
|
|
820
|
+
expandRight: "\u6253\u5F00\u5C5E\u6027\u9762\u677F",
|
|
821
|
+
selectProducts: "\u4ECE Shopify \u9009\u62E9\u5546\u54C1",
|
|
822
|
+
selectingProducts: "\u6B63\u5728\u9009\u62E9\u5546\u54C1\u2026",
|
|
823
|
+
selectProductsFailed: "\u65E0\u6CD5\u9009\u62E9\u5546\u54C1\uFF0C\u8BF7\u91CD\u8BD5\u3002",
|
|
824
|
+
emptyProducts: "\u672A\u9009\u62E9\u5546\u54C1",
|
|
825
|
+
productCountSuffix: "\u4EF6\u5546\u54C1"
|
|
813
826
|
},
|
|
814
827
|
en: {
|
|
815
828
|
blocks: "Blocks",
|
|
@@ -834,6 +847,7 @@ var messages = {
|
|
|
834
847
|
unsaved: "Unsaved changes",
|
|
835
848
|
saved: "Changes are kept in this session",
|
|
836
849
|
save: "Save draft",
|
|
850
|
+
history: "History",
|
|
837
851
|
saving: "Saving\u2026",
|
|
838
852
|
publish: "Publish",
|
|
839
853
|
publishing: "Publishing\u2026",
|
|
@@ -857,7 +871,16 @@ var messages = {
|
|
|
857
871
|
selectBlock: "Select a block to edit it.",
|
|
858
872
|
desktop: "Desktop",
|
|
859
873
|
tablet: "Tablet",
|
|
860
|
-
mobile: "Mobile"
|
|
874
|
+
mobile: "Mobile",
|
|
875
|
+
collapseLeft: "Collapse blocks panel",
|
|
876
|
+
collapseRight: "Collapse properties panel",
|
|
877
|
+
expandLeft: "Open blocks panel",
|
|
878
|
+
expandRight: "Open properties panel",
|
|
879
|
+
selectProducts: "Select from Shopify",
|
|
880
|
+
selectingProducts: "Selecting products\u2026",
|
|
881
|
+
selectProductsFailed: "Could not select products. Try again.",
|
|
882
|
+
emptyProducts: "No products selected",
|
|
883
|
+
productCountSuffix: "products"
|
|
861
884
|
}
|
|
862
885
|
};
|
|
863
886
|
function createAdminI18n(locale) {
|
|
@@ -937,9 +960,11 @@ function PageDocumentEditorShell(props) {
|
|
|
937
960
|
}, [managedSession.state, onSessionStateChange]);
|
|
938
961
|
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 }) });
|
|
939
962
|
}
|
|
940
|
-
function PageDocumentEditor({ iframe =
|
|
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 }) {
|
|
941
964
|
const editor = useEditorContext();
|
|
942
965
|
const [blockView, setBlockView] = useState3("blocks");
|
|
966
|
+
const [leftRailOpen, setLeftRailOpen] = useState3(true);
|
|
967
|
+
const [rightPanelOpen, setRightPanelOpen] = useState3(true);
|
|
943
968
|
const [draggingLibraryType, setDraggingLibraryType] = useState3(null);
|
|
944
969
|
const canvasFrameRef = useRef4(null);
|
|
945
970
|
const [canvasMutationVersion, setCanvasMutationVersion] = useState3(0);
|
|
@@ -1069,7 +1094,7 @@ function PageDocumentEditor({ iframe = true, registry, adminLocale, onSave, onPu
|
|
|
1069
1094
|
if (!editor.updateFromCanvas(fromEngineData(data, editor.document, registry))) setCanvasResetVersion((version) => version + 1);
|
|
1070
1095
|
}, children: /* @__PURE__ */ jsxs5(Puck2.Layout, { children: [
|
|
1071
1096
|
/* @__PURE__ */ jsx7(CanvasSelectionBridge, { data: engineData, requestedBlockId: editor.canvasSelectionRequest, onCanvasSelected: confirmCanvasSelection, canvasMutationVersion, canvasResetVersion }),
|
|
1072
|
-
/* @__PURE__ */ jsxs5("div", { className: "pb-shell pb-shell--v04", "data-testid": "page-document-editor", "data-page-id": editor.document.pageId, "data-dirty": editor.isDirty, "data-editor-state": editor.loadState, "data-editor-session-state": editor.sessionState, "data-save-state": resolvedSaveState, children: [
|
|
1097
|
+
/* @__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: [
|
|
1073
1098
|
/* @__PURE__ */ jsx7("header", { className: "pb-header", children: /* @__PURE__ */ jsxs5("div", { className: "pb-header-content", children: [
|
|
1074
1099
|
/* @__PURE__ */ jsxs5("div", { className: "pb-header-title-group", children: [
|
|
1075
1100
|
onBack ? /* @__PURE__ */ jsx7(Button2, { variant: "tertiary", onClick: requestBack, children: i18n.t("back") }) : null,
|
|
@@ -1084,12 +1109,13 @@ function PageDocumentEditor({ iframe = true, registry, adminLocale, onSave, onPu
|
|
|
1084
1109
|
pageStatus ? /* @__PURE__ */ jsx7(PageStatusCard, { status: pageStatus, sessionState: editor.sessionState }) : null
|
|
1085
1110
|
] })
|
|
1086
1111
|
] }),
|
|
1087
|
-
/* @__PURE__ */ jsxs5("div", { className: "pb-header-device-toolbar", children: [
|
|
1112
|
+
/* @__PURE__ */ jsx7("div", { className: "pb-header-controls", children: /* @__PURE__ */ jsxs5("div", { className: "pb-header-device-toolbar", children: [
|
|
1088
1113
|
/* @__PURE__ */ jsx7(ButtonGroup2, { variant: "segmented", children: Object.keys(deviceLabels2).map((device) => /* @__PURE__ */ jsx7(Button2, { pressed: editor.device === device, onClick: () => editor.setDevice(device), children: i18n.t(deviceLabels2[device]) }, device)) }),
|
|
1089
1114
|
/* @__PURE__ */ jsx7("div", { className: "pb-zoom-control", children: /* @__PURE__ */ jsx7(Select2, { label: i18n.t("zoom"), labelHidden: true, options: [{ label: i18n.t("zoomAuto"), value: "auto" }, { label: "50%", value: "50" }, { label: "70%", value: "70" }, { label: "100%", value: "100" }], value: zoom, onChange: (value) => setZoom(value) }) })
|
|
1090
|
-
] }),
|
|
1091
|
-
/* @__PURE__ */ jsx7("div", { className: "pb-header-actions", children: /* @__PURE__ */ jsxs5(InlineStack3, { gap: "150", blockAlign: "center", wrap:
|
|
1115
|
+
] }) }),
|
|
1116
|
+
/* @__PURE__ */ jsx7("div", { className: "pb-header-actions", children: /* @__PURE__ */ jsxs5(InlineStack3, { gap: "150", blockAlign: "center", wrap: true, children: [
|
|
1092
1117
|
/* @__PURE__ */ jsx7(Badge3, { tone: saveBadgeTone, children: saveBadgeLabel }),
|
|
1118
|
+
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,
|
|
1093
1119
|
/* @__PURE__ */ jsx7(Button2, { disabled: !canPersistDraft || !editor.isDirty || request !== "idle" || validationIssues.length > 0 || !isOnline, onClick: () => void save(), children: saveButtonLabel }),
|
|
1094
1120
|
onPreview ? /* @__PURE__ */ jsx7(Button2, { disabled: request !== "idle" || !isOnline, onClick: () => void onPreview({ document: editor.document, draftRevision, session: editor.session }), children: i18n.t("preview") }) : null,
|
|
1095
1121
|
onAddToStore ? /* @__PURE__ */ jsx7(Button2, { disabled: request !== "idle" || pageStatus?.publicationStatus === "unpublished", onClick: () => void onAddToStore({ document: editor.document, session: editor.session }), children: i18n.t("addToStore") }) : null,
|
|
@@ -1105,13 +1131,22 @@ function PageDocumentEditor({ iframe = true, registry, adminLocale, onSave, onPu
|
|
|
1105
1131
|
": ",
|
|
1106
1132
|
issue.message
|
|
1107
1133
|
] }, `${issue.path}-${issue.message}`)) }) }) : null,
|
|
1108
|
-
/* @__PURE__ */ jsxs5("div", { className:
|
|
1134
|
+
/* @__PURE__ */ jsxs5("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: [
|
|
1109
1135
|
/* @__PURE__ */ jsxs5("nav", { className: "pb-tool-rail", "aria-label": "\u7F16\u8F91\u5668\u5DE5\u5177", children: [
|
|
1110
|
-
/* @__PURE__ */ jsx7(Button2, { accessibilityLabel: i18n.t("blocks"), icon: LayoutSectionIcon2, pressed: blockView === "blocks", variant: "tertiary", onClick: () =>
|
|
1111
|
-
|
|
1136
|
+
/* @__PURE__ */ jsx7(Button2, { accessibilityLabel: i18n.t("blocks"), icon: LayoutSectionIcon2, pressed: blockView === "blocks" && leftRailOpen, variant: "tertiary", onClick: () => {
|
|
1137
|
+
setBlockView("blocks");
|
|
1138
|
+
setLeftRailOpen(true);
|
|
1139
|
+
} }),
|
|
1140
|
+
/* @__PURE__ */ jsx7(Button2, { accessibilityLabel: i18n.t("outline"), icon: MenuIcon2, pressed: blockView === "outline" && leftRailOpen, variant: "tertiary", onClick: () => {
|
|
1141
|
+
setBlockView("outline");
|
|
1142
|
+
setLeftRailOpen(true);
|
|
1143
|
+
} })
|
|
1112
1144
|
] }),
|
|
1113
|
-
/* @__PURE__ */ jsxs5("aside", { className:
|
|
1114
|
-
/* @__PURE__ */
|
|
1145
|
+
/* @__PURE__ */ jsxs5("aside", { className: `pb-left-panel${leftRailOpen ? "" : " pb-panel--closed"}`, "aria-label": "PageDocument \u533A\u5757", children: [
|
|
1146
|
+
/* @__PURE__ */ jsxs5(InlineStack3, { align: "space-between", blockAlign: "center", children: [
|
|
1147
|
+
/* @__PURE__ */ jsx7(Text3, { as: "h2", variant: "headingSm", children: blockView === "blocks" ? i18n.t("blocks") : i18n.t("outline") }),
|
|
1148
|
+
/* @__PURE__ */ jsx7(Button2, { accessibilityLabel: i18n.t("collapseLeft"), icon: XIcon2, variant: "tertiary", onClick: () => setLeftRailOpen(false) })
|
|
1149
|
+
] }),
|
|
1115
1150
|
blockView === "blocks" ? /* @__PURE__ */ jsx7("div", { className: "pb-block-list", "data-testid": "blocks-view", "aria-label": "\u533A\u5757\u7C7B\u578B\u5E93", role: "list", onDrop: cancelLibraryDrop, children: blockTypes.map((type) => /* @__PURE__ */ jsxs5("div", { className: `pb-document-block-row pb-document-block-row--library ${editor.selectedBlock?.type === type ? "pb-document-block-row--selected" : ""}`, "data-block-type": type, "data-selected": editor.selectedBlock?.type === type, role: "listitem", draggable: editor.canAddBlock(type), "aria-disabled": !editor.canAddBlock(type), "aria-label": `${blockTypeLabel(type, registry)}\uFF0C\u62D6\u62FD\u81F3\u753B\u5E03\u4EE5\u6DFB\u52A0${editor.selectedBlock?.type === type ? "\uFF0C\u5F53\u524D\u9009\u4E2D\u7C7B\u578B" : ""}`, onDragStart: (event) => {
|
|
1116
1151
|
if (!editor.canAddBlock(type)) {
|
|
1117
1152
|
event.preventDefault();
|
|
@@ -1131,21 +1166,30 @@ function PageDocumentEditor({ iframe = true, registry, adminLocale, onSave, onPu
|
|
|
1131
1166
|
/* @__PURE__ */ jsx7(Text3, { as: "span", variant: "bodySm", tone: "subdued", children: block.id })
|
|
1132
1167
|
] }, block.id)) })
|
|
1133
1168
|
] }),
|
|
1134
|
-
/* @__PURE__ */
|
|
1135
|
-
/* @__PURE__ */
|
|
1136
|
-
|
|
1137
|
-
"\
|
|
1138
|
-
|
|
1139
|
-
|
|
1140
|
-
|
|
1141
|
-
/* @__PURE__ */
|
|
1142
|
-
|
|
1169
|
+
/* @__PURE__ */ jsxs5("main", { className: "pb-canvas-area", children: [
|
|
1170
|
+
/* @__PURE__ */ jsxs5("div", { className: "pb-canvas-stage", children: [
|
|
1171
|
+
/* @__PURE__ */ jsx7("div", { ref: canvasFrameRef, className: `pb-canvas-frame pb-canvas-frame--${editor.device}${zoom === "auto" ? "" : ` pb-canvas-frame--zoom-${zoom}`}`, "data-device": editor.device, "data-zoom": zoom, children: /* @__PURE__ */ jsx7(Puck2.Preview, {}) }),
|
|
1172
|
+
draggingLibraryType ? /* @__PURE__ */ jsxs5("div", { className: "pb-canvas-drop-target", "data-testid": "canvas-drop-target", role: "region", "aria-label": "\u533A\u5757\u6295\u653E\u533A", onDragOver: (event) => event.preventDefault(), onDrop: dropFromLibrary, children: [
|
|
1173
|
+
"\u677E\u5F00\u4EE5\u6DFB\u52A0 ",
|
|
1174
|
+
blockTypeLabel(draggingLibraryType, registry)
|
|
1175
|
+
] }) : null,
|
|
1176
|
+
editor.selectedBlock ? /* @__PURE__ */ jsxs5("div", { className: "pb-canvas-overlay", "aria-label": `\u5DF2\u9009\u62E9 ${blockLabel(editor.selectedBlock, registry)}`, children: [
|
|
1177
|
+
/* @__PURE__ */ jsx7("span", { children: blockLabel(editor.selectedBlock, registry) }),
|
|
1178
|
+
/* @__PURE__ */ jsx7("span", { children: "Selected" })
|
|
1179
|
+
] }) : null
|
|
1180
|
+
] }),
|
|
1181
|
+
!leftRailOpen || !rightPanelOpen ? /* @__PURE__ */ jsxs5("div", { className: "pb-collapsed-actions", children: [
|
|
1182
|
+
!leftRailOpen ? /* @__PURE__ */ jsx7(Button2, { onClick: () => setLeftRailOpen(true), children: i18n.t("expandLeft") }) : null,
|
|
1183
|
+
!rightPanelOpen ? /* @__PURE__ */ jsx7(Button2, { onClick: () => setRightPanelOpen(true), children: i18n.t("expandRight") }) : null
|
|
1143
1184
|
] }) : null
|
|
1144
|
-
] })
|
|
1145
|
-
/* @__PURE__ */ jsxs5("aside", { className:
|
|
1146
|
-
/* @__PURE__ */
|
|
1185
|
+
] }),
|
|
1186
|
+
/* @__PURE__ */ jsxs5("aside", { className: `pb-right-panel${rightPanelOpen ? "" : " pb-panel--closed"}`, "aria-label": "PageDocument \u5C5E\u6027", children: [
|
|
1187
|
+
/* @__PURE__ */ jsxs5(InlineStack3, { align: "space-between", blockAlign: "center", children: [
|
|
1188
|
+
/* @__PURE__ */ jsx7(Text3, { as: "h2", variant: "headingSm", children: i18n.t("properties") }),
|
|
1189
|
+
/* @__PURE__ */ jsx7(Button2, { accessibilityLabel: i18n.t("collapseRight"), icon: XIcon2, variant: "tertiary", onClick: () => setRightPanelOpen(false) })
|
|
1190
|
+
] }),
|
|
1147
1191
|
editor.selectedBlock ? /* @__PURE__ */ jsxs5(Fragment2, { children: [
|
|
1148
|
-
/* @__PURE__ */ jsx7(DocumentInspector, { pageId: editor.document.pageId, assetPicker, block: editor.selectedBlock, registry, disabled: !editor.actionState.canEdit, appearanceControls, onChange: (props) => editor.updateBlockProps(editor.selectedBlock.id, props), onPresentationChange: (presentation) => updateBlockPresentation(editor.selectedBlock.id, presentation) }),
|
|
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) }),
|
|
1149
1193
|
/* @__PURE__ */ jsx7(InspectorActions, { block: editor.selectedBlock, canDuplicate: editor.actionState.canDuplicate, canDelete: editor.actionState.canDelete, canMove: editor.actionState.canReorder, canMoveUp: editor.document.blocks[0]?.id !== editor.selectedBlock.id, canMoveDown: editor.document.blocks.at(-1)?.id !== editor.selectedBlock.id, i18n, onDuplicate: () => editor.duplicateBlock(editor.selectedBlock.id), onDelete: () => editor.requestDeleteBlock(editor.selectedBlock.id), onMove: (direction) => editor.moveBlock(editor.selectedBlock.id, direction) })
|
|
1150
1194
|
] }) : /* @__PURE__ */ jsx7(Text3, { as: "p", tone: "subdued", children: i18n.t("selectBlock") })
|
|
1151
1195
|
] })
|
|
@@ -1216,7 +1260,33 @@ function InspectorTextControl({ label, value, control, disabled, onChange }) {
|
|
|
1216
1260
|
if (control === "color") return /* @__PURE__ */ jsx7("input", { "aria-label": label, type: "color", value: /^#[\da-f]{6}$/i.test(stringValue) ? stringValue : "#000000", disabled, onChange: (event) => onChange(event.currentTarget.value) });
|
|
1217
1261
|
return /* @__PURE__ */ jsx7(TextField, { label, labelHidden: true, value: stringValue, onChange, autoComplete: "off", disabled, multiline: control === "textarea" ? 4 : false, type: control === "url" ? "url" : "text" });
|
|
1218
1262
|
}
|
|
1219
|
-
function
|
|
1263
|
+
function InspectorProductsControl({ value, disabled, picker, pageId, blockId, i18n, onChange }) {
|
|
1264
|
+
const products = parseProductReferences(value);
|
|
1265
|
+
const [busy, setBusy] = useState3(false);
|
|
1266
|
+
const [error, setError] = useState3(null);
|
|
1267
|
+
const preview = products.slice(0, 4);
|
|
1268
|
+
return /* @__PURE__ */ jsxs5("div", { className: "pb-product-picker", "data-testid": "product-picker", children: [
|
|
1269
|
+
/* @__PURE__ */ jsxs5("div", { className: "pb-product-picker__summary", children: [
|
|
1270
|
+
preview.length ? /* @__PURE__ */ jsx7("span", { className: "pb-product-picker__thumbs", "aria-hidden": "true", children: preview.map((product, index) => /* @__PURE__ */ jsx7("span", { className: "pb-product-picker__thumb", style: { zIndex: preview.length - index }, children: product.imageUrl ? /* @__PURE__ */ jsx7("img", { src: product.imageUrl, alt: "" }) : /* @__PURE__ */ jsx7("span", { className: "pb-product-picker__thumb-fallback" }) }, product.id)) }) : null,
|
|
1271
|
+
/* @__PURE__ */ jsx7(Text3, { as: "p", variant: "bodySm", children: products.length ? `${products.length} ${i18n.t("productCountSuffix")}` : i18n.t("emptyProducts") })
|
|
1272
|
+
] }),
|
|
1273
|
+
/* @__PURE__ */ jsx7(Button2, { fullWidth: true, icon: ProductIcon, variant: "secondary", disabled: disabled || busy || !picker, onClick: () => void (async () => {
|
|
1274
|
+
if (!picker) return;
|
|
1275
|
+
setBusy(true);
|
|
1276
|
+
setError(null);
|
|
1277
|
+
try {
|
|
1278
|
+
const next = await picker.selectProducts({ pageId, blockId, current: products, multiple: true });
|
|
1279
|
+
if (next) onChange(parseProductReferences(next).map(toProductReferenceJson));
|
|
1280
|
+
} catch {
|
|
1281
|
+
setError(i18n.t("selectProductsFailed"));
|
|
1282
|
+
} finally {
|
|
1283
|
+
setBusy(false);
|
|
1284
|
+
}
|
|
1285
|
+
})(), children: busy ? i18n.t("selectingProducts") : i18n.t("selectProducts") }),
|
|
1286
|
+
error ? /* @__PURE__ */ jsx7(Text3, { as: "p", variant: "bodySm", tone: "critical", children: error }) : null
|
|
1287
|
+
] });
|
|
1288
|
+
}
|
|
1289
|
+
function InspectorField({ name, field, value, registry, disabled, productPicker, pageId, blockId, i18n, onChange }) {
|
|
1220
1290
|
const label = field.label ?? name;
|
|
1221
1291
|
const issues = validateFieldValue(field, value);
|
|
1222
1292
|
const Field = registry?.getField(field.field)?.component;
|
|
@@ -1225,7 +1295,7 @@ function InspectorField({ name, field, value, registry, disabled, onChange }) {
|
|
|
1225
1295
|
/* @__PURE__ */ jsx7(Text3, { as: "p", variant: "bodySm", fontWeight: "semibold", children: label }),
|
|
1226
1296
|
field.description ? /* @__PURE__ */ jsx7(Text3, { as: "p", variant: "bodySm", tone: "subdued", children: field.description }) : null
|
|
1227
1297
|
] }),
|
|
1228
|
-
field.control ? /* @__PURE__ */ jsx7(InspectorTextControl, { label, value, control: field.control, disabled, onChange: (next) => onChange(next) }) : Field ? /* @__PURE__ */ jsx7(Field, { value, onChange }) : null,
|
|
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,
|
|
1229
1299
|
issues.map((issue) => /* @__PURE__ */ jsx7(Text3, { as: "p", variant: "bodySm", tone: "critical", children: issue.message }, issue.message))
|
|
1230
1300
|
] });
|
|
1231
1301
|
}
|
|
@@ -1264,7 +1334,7 @@ function inspectorFieldConfig(name, field) {
|
|
|
1264
1334
|
return { ...field, group: field.group ?? group, description };
|
|
1265
1335
|
}
|
|
1266
1336
|
var appearanceTokens = [["color.primary", "\u4E3B\u8272"], ["color.surface", "\u8868\u9762\u8272"], ["radius", "\u5706\u89D2"], ["spacing", "\u95F4\u8DDD"]];
|
|
1267
|
-
function DocumentInspector({ pageId, assetPicker, block, registry, disabled, appearanceControls, onChange, onPresentationChange }) {
|
|
1337
|
+
function DocumentInspector({ pageId, assetPicker, productPicker, i18n, block, registry, disabled, appearanceControls, onChange, onPresentationChange }) {
|
|
1268
1338
|
const [assetError, setAssetError] = useState3(null);
|
|
1269
1339
|
const [selectingAsset, setSelectingAsset] = useState3(false);
|
|
1270
1340
|
const definition = registry?.getBlock(block.type);
|
|
@@ -1283,10 +1353,10 @@ function DocumentInspector({ pageId, assetPicker, block, registry, disabled, app
|
|
|
1283
1353
|
/* @__PURE__ */ jsx7(Text3, { as: "p", variant: "bodySm", tone: "subdued", children: definition?.category ?? "Core block" })
|
|
1284
1354
|
] })
|
|
1285
1355
|
] }),
|
|
1286
|
-
block.type === "core.text" ? /* @__PURE__ */ jsx7(InspectorSection, { title: "Content", children: /* @__PURE__ */ jsx7(InspectorField, { name: "content", field: { field: "", label: "\u6587\u672C\u5185\u5BB9", control: "textarea", description: "\u652F\u6301\u8F83\u957F\u7684\u6B63\u6587\u5185\u5BB9\u3002" }, value: block.props.content, registry, disabled, onChange: (content) => onChange({ content }) }) }) : null,
|
|
1356
|
+
block.type === "core.text" ? /* @__PURE__ */ jsx7(InspectorSection, { title: "Content", children: /* @__PURE__ */ jsx7(InspectorField, { name: "content", field: { field: "", label: "\u6587\u672C\u5185\u5BB9", control: "textarea", description: "\u652F\u6301\u8F83\u957F\u7684\u6B63\u6587\u5185\u5BB9\u3002" }, value: block.props.content, registry, disabled, productPicker, pageId, blockId: block.id, i18n, onChange: (content) => onChange({ content }) }) }) : null,
|
|
1287
1357
|
block.type === "core.image" ? /* @__PURE__ */ jsxs5(InspectorSection, { title: "Image", children: [
|
|
1288
|
-
/* @__PURE__ */ jsx7(InspectorField, { name: "src", field: { field: "", label: "\u56FE\u7247 URL", control: "url", description: "\u4F7F\u7528 HTTPS \u56FE\u7247\u5730\u5740\u3002" }, value: block.props.src, registry, disabled, onChange: (src) => onChange({ src }) }),
|
|
1289
|
-
/* @__PURE__ */ jsx7(InspectorField, { name: "alt", field: { field: "", label: "\u66FF\u4EE3\u6587\u672C", control: "text", description: "\u7528\u4E8E\u65E0\u969C\u788D\u9605\u8BFB\u548C\u56FE\u7247\u52A0\u8F7D\u5931\u8D25\u573A\u666F\u3002" }, value: block.props.alt, registry, disabled, onChange: (alt) => onChange({ alt }) }),
|
|
1358
|
+
/* @__PURE__ */ jsx7(InspectorField, { name: "src", field: { field: "", label: "\u56FE\u7247 URL", control: "url", description: "\u4F7F\u7528 HTTPS \u56FE\u7247\u5730\u5740\u3002" }, value: block.props.src, registry, disabled, productPicker, pageId, blockId: block.id, i18n, onChange: (src) => onChange({ src }) }),
|
|
1359
|
+
/* @__PURE__ */ jsx7(InspectorField, { name: "alt", field: { field: "", label: "\u66FF\u4EE3\u6587\u672C", control: "text", description: "\u7528\u4E8E\u65E0\u969C\u788D\u9605\u8BFB\u548C\u56FE\u7247\u52A0\u8F7D\u5931\u8D25\u573A\u666F\u3002" }, value: block.props.alt, registry, disabled, productPicker, pageId, blockId: block.id, i18n, onChange: (alt) => onChange({ alt }) }),
|
|
1290
1360
|
assetPicker ? /* @__PURE__ */ jsxs5(Fragment2, { children: [
|
|
1291
1361
|
/* @__PURE__ */ jsx7(Button2, { disabled: disabled || selectingAsset, onClick: () => void (async () => {
|
|
1292
1362
|
setSelectingAsset(true);
|
|
@@ -1303,15 +1373,14 @@ function DocumentInspector({ pageId, assetPicker, block, registry, disabled, app
|
|
|
1303
1373
|
assetError ? /* @__PURE__ */ jsx7(Text3, { as: "p", variant: "bodySm", tone: "critical", children: assetError }) : null
|
|
1304
1374
|
] }) : null
|
|
1305
1375
|
] }) : null,
|
|
1306
|
-
Object.entries(groupedFields).map(([group, fields]) => /* @__PURE__ */ jsx7(InspectorSection, { title: group, defaultOpen: group !== "Advanced", children: fields.map(([name, field]) => /* @__PURE__ */ jsx7(InspectorField, { name, field, value: block.props[name], registry, disabled, onChange: (value) => onChange({ ...block.props, [name]: value }) }, name)) }, group)),
|
|
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({ ...block.props, [name]: value }) }, name)) }, group)),
|
|
1307
1377
|
appearanceControls && definition?.variants?.length ? /* @__PURE__ */ jsx7(InspectorSection, { title: "\u5916\u89C2", children: /* @__PURE__ */ jsx7(Select2, { label: "\u6837\u5F0F\u53D8\u4F53", options: definition.variants.map((variant) => ({ label: variant.label, value: variant.id })), value: block.variant, disabled, onChange: (variant) => onPresentationChange({ variant, style: block.style }) }) }) : null,
|
|
1308
1378
|
appearanceControls && definition ? /* @__PURE__ */ jsx7(InspectorSection, { title: "\u6837\u5F0F\u8986\u76D6", defaultOpen: false, children: appearanceTokens.map(([token, label]) => /* @__PURE__ */ jsx7(TextField, { label, value: block.style[token] ?? "", placeholder: "\u7EE7\u627F\u9875\u9762\u6216\u6A21\u677F\u8BBE\u7F6E", autoComplete: "off", disabled, onChange: (value) => {
|
|
1309
1379
|
const style = { ...block.style };
|
|
1310
1380
|
if (value.trim()) style[token] = value;
|
|
1311
1381
|
else delete style[token];
|
|
1312
1382
|
onPresentationChange({ variant: block.variant, style });
|
|
1313
|
-
} }, token)) }) : null
|
|
1314
|
-
definition ? /* @__PURE__ */ jsx7("p", { className: "pb-inspector__hint", children: "\u753B\u5E03\u4E2D\u5E26\u865A\u7EBF\u8FB9\u6846\u7684\u5185\u5BB9\u53EF\u76F4\u63A5\u7F16\u8F91\u3002" }) : null
|
|
1383
|
+
} }, token)) }) : null
|
|
1315
1384
|
] });
|
|
1316
1385
|
}
|
|
1317
1386
|
export {
|
|
@@ -1328,14 +1397,17 @@ export {
|
|
|
1328
1397
|
createPageDocument,
|
|
1329
1398
|
createTemplateRegistry,
|
|
1330
1399
|
fromEngineData,
|
|
1400
|
+
isProductReference,
|
|
1331
1401
|
maximumBlockInstances,
|
|
1332
1402
|
mergeBlockPolicies,
|
|
1333
1403
|
mergeThemeTokens,
|
|
1334
1404
|
migratePageDocument,
|
|
1335
1405
|
minimumBlockInstances,
|
|
1336
1406
|
normalizeThemeTokens,
|
|
1407
|
+
parseProductReferences,
|
|
1337
1408
|
systemThemeTokens,
|
|
1338
1409
|
toEngineData,
|
|
1410
|
+
toProductReferenceJson,
|
|
1339
1411
|
toThemeStyle,
|
|
1340
1412
|
useEditorContext,
|
|
1341
1413
|
validateBlockPolicy,
|
|
@@ -42,7 +42,7 @@ 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";
|
|
45
|
+
control?: "text" | "textarea" | "url" | "color" | "products";
|
|
46
46
|
description?: string;
|
|
47
47
|
group?: string;
|
|
48
48
|
/** Kept for compatibility; it participates in the built-in validation. */
|
package/dist/renderer.d.ts
CHANGED
package/dist/runtime.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
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-
|
|
3
|
-
export { maximumBlockInstances, mergeBlockPolicies, minimumBlockInstances, validateBlockPolicy, validateFieldValue, validatePageDocumentWithRegistry } from './extensions.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-CXJdOya3.js';
|
|
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';
|
|
6
6
|
import 'react';
|
package/dist/runtime.js
CHANGED
|
@@ -4,13 +4,16 @@ import {
|
|
|
4
4
|
TemplateRegistry,
|
|
5
5
|
createExtensionRegistry,
|
|
6
6
|
createTemplateRegistry,
|
|
7
|
+
isProductReference,
|
|
7
8
|
maximumBlockInstances,
|
|
8
9
|
mergeBlockPolicies,
|
|
9
10
|
minimumBlockInstances,
|
|
11
|
+
parseProductReferences,
|
|
12
|
+
toProductReferenceJson,
|
|
10
13
|
validateBlockPolicy,
|
|
11
14
|
validateFieldValue,
|
|
12
15
|
validatePageDocumentWithRegistry
|
|
13
|
-
} from "./chunk-
|
|
16
|
+
} from "./chunk-YXBTNYPR.js";
|
|
14
17
|
import {
|
|
15
18
|
WebRenderer
|
|
16
19
|
} from "./chunk-KYXIXIWK.js";
|
|
@@ -33,13 +36,16 @@ export {
|
|
|
33
36
|
createExtensionRegistry,
|
|
34
37
|
createPageDocument,
|
|
35
38
|
createTemplateRegistry,
|
|
39
|
+
isProductReference,
|
|
36
40
|
maximumBlockInstances,
|
|
37
41
|
mergeBlockPolicies,
|
|
38
42
|
mergeThemeTokens,
|
|
39
43
|
migratePageDocument,
|
|
40
44
|
minimumBlockInstances,
|
|
41
45
|
normalizeThemeTokens,
|
|
46
|
+
parseProductReferences,
|
|
42
47
|
systemThemeTokens,
|
|
48
|
+
toProductReferenceJson,
|
|
43
49
|
toThemeStyle,
|
|
44
50
|
validateBlockPolicy,
|
|
45
51
|
validateFieldValue,
|
package/package.json
CHANGED
package/src/styles.css
CHANGED
|
@@ -5,17 +5,26 @@
|
|
|
5
5
|
body { margin: 0; min-width: 320px; }
|
|
6
6
|
button:focus-visible, [role="button"]:focus-visible { outline: 2px solid var(--builder-accent); outline-offset: 2px; }
|
|
7
7
|
.pb-shell { min-height: 100vh; color: var(--builder-text); background: var(--builder-canvas-bg); }
|
|
8
|
+
.pb-shell [class*="PuckLayout-inner"] { height: auto !important; min-height: 100%; }
|
|
8
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); }
|
|
9
|
-
.pb-header-content { display:
|
|
10
|
-
.pb-header-title-group { display: flex; align-items:
|
|
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 0; align-items: center; gap: var(--builder-space-2); min-width: 0; }
|
|
12
|
+
.pb-header-sidebar-toggles, [class*="PuckHeader-toggle"] { display: none !important; }
|
|
11
13
|
.pb-page-title { display: grid; gap: 0; min-width: 0; }
|
|
14
|
+
.pb-page-title h1, .pb-page-title p { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
|
|
12
15
|
.pb-page-title p { margin: 0; }
|
|
13
|
-
.pb-header-
|
|
14
|
-
.pb-header-
|
|
15
|
-
.pb-
|
|
16
|
+
.pb-header-controls { display: flex; flex: 0 0 auto; align-items: center; justify-content: center; }
|
|
17
|
+
.pb-header-device-toolbar { display: flex; align-items: center; gap: var(--builder-space-2); }
|
|
18
|
+
.pb-header-actions { display: flex; flex: 1 1 0; justify-content: flex-end; min-width: 0; }
|
|
19
|
+
.pb-header-actions .Polaris-InlineStack { flex-wrap: wrap; justify-content: flex-end; }
|
|
20
|
+
.pb-header-actions .Polaris-Badge { max-width: 14rem; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
|
|
21
|
+
.pb-zoom-control { width: 112px; flex: 0 0 auto; }
|
|
16
22
|
.pb-page-status-card { display: grid; gap: 2px; margin-top: var(--builder-space-1); }
|
|
17
23
|
.pb-page-status-card p { margin: 0; }
|
|
18
|
-
.pb-workspace { display: grid; grid-template-columns: 64px minmax(260px, 300px) minmax(
|
|
24
|
+
.pb-workspace { display: grid; grid-template-columns: 64px minmax(260px, 300px) minmax(0, 1fr) minmax(300px, 320px); min-height: calc(100vh - 56px); }
|
|
25
|
+
.pb-workspace--left-closed:not(.pb-workspace--right-closed) { grid-template-columns: 64px minmax(0, 1fr) minmax(300px, 320px); }
|
|
26
|
+
.pb-workspace--right-closed:not(.pb-workspace--left-closed) { grid-template-columns: 64px minmax(260px, 300px) minmax(0, 1fr); }
|
|
27
|
+
.pb-workspace--left-closed.pb-workspace--right-closed { grid-template-columns: 64px minmax(0, 1fr); }
|
|
19
28
|
.pb-tool-rail { display: flex; flex-direction: column; align-items: center; gap: var(--builder-space-2); padding: var(--builder-space-2); border-right: 1px solid var(--builder-border); background: var(--builder-surface-subtle); }
|
|
20
29
|
.pb-tool-rail .Polaris-Button { min-width: 44px; min-height: 44px; }
|
|
21
30
|
.pb-left-panel, .pb-right-panel { display: flex; flex-direction: column; gap: var(--builder-space-4); min-width: 0; padding: var(--builder-space-4); overflow: auto; background: var(--builder-surface); }
|
|
@@ -43,6 +52,14 @@ button:focus-visible, [role="button"]:focus-visible { outline: 2px solid var(--b
|
|
|
43
52
|
.pb-inspector-field input:hover, .pb-inspector-field textarea:hover { border-color: #94a3b8; }
|
|
44
53
|
.pb-inspector-field input:focus, .pb-inspector-field textarea:focus { border-color: #2563eb; box-shadow: 0 0 0 3px rgb(37 99 235 / 12%); }
|
|
45
54
|
.pb-inspector-field input:disabled, .pb-inspector-field textarea:disabled { color: #94a3b8; background: #f8fafc; cursor: not-allowed; }
|
|
55
|
+
.pb-product-picker { display: grid; gap: 8px; }
|
|
56
|
+
.pb-product-picker__summary { display: flex; align-items: center; gap: 10px; min-height: 44px; padding: 10px 12px; border: 1px solid #e2e8f0; border-radius: 10px; background: #fff; }
|
|
57
|
+
.pb-product-picker__summary p { margin: 0; color: #334155; }
|
|
58
|
+
.pb-product-picker__thumbs { display: flex; align-items: center; }
|
|
59
|
+
.pb-product-picker__thumb { display: inline-flex; width: 32px; height: 32px; margin-left: -8px; overflow: hidden; border: 2px solid #fff; border-radius: 8px; background: #e2e8f0; box-shadow: 0 0 0 1px #e2e8f0; }
|
|
60
|
+
.pb-product-picker__thumb:first-child { margin-left: 0; }
|
|
61
|
+
.pb-product-picker__thumb img, .pb-product-picker__thumb-fallback { display: block; width: 100%; height: 100%; object-fit: cover; }
|
|
62
|
+
.pb-product-picker__thumb-fallback { background: #cbd5e1; }
|
|
46
63
|
.pb-inspector__hint { margin: 0; padding: 0 var(--builder-space-2); color: #64748b; font-size: 12px; line-height: 1.5; }
|
|
47
64
|
.pb-inspector-actions { padding-top: var(--builder-space-2); border-top: 1px solid #e2e8f0; }
|
|
48
65
|
.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%); }
|
|
@@ -58,18 +75,20 @@ button:focus-visible, [role="button"]:focus-visible { outline: 2px solid var(--b
|
|
|
58
75
|
.pb-block-select { display: flex; flex: 1; flex-direction: column; gap: var(--builder-space-1); min-width: 0; padding: var(--builder-space-1); border: 0; border-radius: var(--builder-control-radius); text-align: left; color: inherit; background: transparent; cursor: pointer; }
|
|
59
76
|
.pb-block-actions { display: none; align-items: center; gap: var(--builder-space-1); }
|
|
60
77
|
.pb-block-row:hover .pb-block-actions, .pb-block-row--selected .pb-block-actions, .pb-block-row:focus-within .pb-block-actions { display: flex; }
|
|
61
|
-
.pb-canvas-area { display: flex; flex-direction: column; gap: var(--builder-space-3); min-width: 0; padding: var(--builder-space-4); overflow: auto; background: var(--builder-canvas-bg); }
|
|
78
|
+
.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); }
|
|
62
79
|
.pb-canvas-toolbar { padding: var(--builder-space-2); border: 1px solid var(--builder-border); border-radius: var(--builder-panel-radius); background: var(--builder-surface); }
|
|
63
|
-
.pb-canvas-stage { position: relative; display:
|
|
64
|
-
.pb-canvas-frame { width: 100%;
|
|
65
|
-
.pb-canvas-
|
|
80
|
+
.pb-canvas-stage { position: relative; display: block; padding: 0; height: auto; }
|
|
81
|
+
.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; }
|
|
82
|
+
.pb-canvas-frame iframe { display: block; width: 100%; height: auto !important; min-height: 0 !important; border: 0; }
|
|
83
|
+
.pb-canvas-frame [class*="PuckPreview"] { position: relative; height: auto !important; }
|
|
84
|
+
.pb-canvas-drop-target { position: absolute; inset: 0; z-index: 2; display: grid; place-items: center; min-height: 12rem; border: 2px dashed var(--builder-accent); border-radius: var(--builder-canvas-radius); color: var(--builder-accent); background: color-mix(in srgb, var(--builder-accent-subtle) 88%, transparent); font-weight: 600; pointer-events: auto; }
|
|
66
85
|
.pb-canvas-frame--tablet { width: min(100%, 768px); }
|
|
67
86
|
.pb-canvas-frame--mobile { width: min(100%, 390px); }
|
|
68
87
|
.pb-canvas-frame--full { width: 100%; }
|
|
69
|
-
.pb-canvas-frame--zoom-50 { transform: scale(.5); transform-origin: top center;
|
|
70
|
-
.pb-canvas-frame--zoom-70 { transform: scale(.7); transform-origin: top center;
|
|
88
|
+
.pb-canvas-frame--zoom-50 { transform: scale(.5); transform-origin: top center; }
|
|
89
|
+
.pb-canvas-frame--zoom-70 { transform: scale(.7); transform-origin: top center; }
|
|
71
90
|
.pb-canvas-frame--zoom-100 { transform: scale(1); }
|
|
72
|
-
.pb-canvas-overlay { position: absolute; top:
|
|
91
|
+
.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; }
|
|
73
92
|
.pb-canvas-overlay span:last-child { color: var(--builder-text-muted); font-weight: 500; }
|
|
74
93
|
.pb-collapsed-actions { display: flex; gap: var(--builder-space-2); }
|
|
75
94
|
.pb-inspector-tabs { display: grid; grid-template-columns: repeat(3, 1fr); padding: var(--builder-space-1); border: 1px solid var(--builder-border); border-radius: var(--builder-control-radius); background: var(--builder-surface-subtle); }
|
|
@@ -89,12 +108,13 @@ button:focus-visible, [role="button"]:focus-visible { outline: 2px solid var(--b
|
|
|
89
108
|
.pb-library-block-drag-hint svg { width: 16px; height: 16px; }
|
|
90
109
|
.pb-document-block-row:hover { background: var(--builder-surface-subtle); }
|
|
91
110
|
.pb-document-block-row--selected { border-color: var(--builder-accent); background: var(--builder-accent-subtle); }
|
|
92
|
-
.pb-editor-status { display: grid; place-items: center; min-height:
|
|
111
|
+
.pb-editor-status { display: grid; place-items: center; box-sizing: border-box; width: 100%; min-height: 100dvh; padding: var(--builder-space-6); }
|
|
112
|
+
.pb-editor-status > * { width: min(100%, 28rem); justify-self: center; }
|
|
93
113
|
.pb-shell--v04 > .Polaris-Banner { margin: var(--builder-space-3) var(--builder-space-4) 0; }
|
|
94
114
|
.pb-document-canvas__text, .pb-document-canvas__image { max-width: 760px; margin: 0 auto; padding: 48px; color: #1d2939; background: #fff; cursor: pointer; }
|
|
95
115
|
.pb-document-canvas__text { font-size: clamp(32px, 4vw, 52px); font-weight: 650; line-height: 1.1; letter-spacing: -.03em; }
|
|
96
116
|
.pb-document-canvas__text p { margin: 0; }
|
|
97
|
-
.pb-document-canvas__text p[contenteditable="true"] { outline: 1px dashed var(--builder-accent); outline-offset: 8px; cursor: text; }
|
|
117
|
+
.pb-document-canvas__text p[contenteditable="true"] { /* outline: 1px dashed var(--builder-accent); outline-offset: 8px; */ cursor: text; }
|
|
98
118
|
.pb-document-canvas__image { padding-top: 0; }
|
|
99
119
|
.pb-document-canvas__image img { display: block; width: 100%; border-radius: 12px; }
|
|
100
120
|
.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; }
|
|
@@ -106,6 +126,7 @@ button:focus-visible, [role="button"]:focus-visible { outline: 2px solid var(--b
|
|
|
106
126
|
.pb-web-renderer__image img { display: block; width: 100%; border-radius: 18px; }
|
|
107
127
|
|
|
108
128
|
/* Storefront-only presentation rendered inside the Puck iframe. */
|
|
129
|
+
#frame-root { height: auto !important; min-height: 0 !important; }
|
|
109
130
|
.bt-storefront { min-height: 100%; padding: 48px clamp(24px, 7vw, 96px); color: #18212b; background: #fffdf9; font-family: Inter, -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif; }
|
|
110
131
|
.bt-storefront__header { display: flex; justify-content: space-between; align-items: center; padding-bottom: 32px; border-bottom: 1px solid #e6e1da; font-size: 14px; }
|
|
111
132
|
.bt-storefront__brand { font-weight: 700; letter-spacing: .04em; }
|
|
@@ -120,6 +141,6 @@ button:focus-visible, [role="button"]:focus-visible { outline: 2px solid var(--b
|
|
|
120
141
|
.bt-storefront__form { display: flex; gap: 12px; margin-top: 24px; }
|
|
121
142
|
.bt-storefront__form input { flex: 1; min-width: 0; padding: 13px 14px; border: 1px solid #b8c3cc; border-radius: 8px; font: inherit; }
|
|
122
143
|
.bt-storefront__form button { padding: 13px 18px; border: 0; border-radius: 8px; color: white; background: #203e54; font: inherit; font-weight: 600; }
|
|
123
|
-
@media (max-width: 1180px) { .pb-workspace { grid-template-columns: 64px minmax(260px, 300px) minmax(0, 1fr); } .pb-right-panel { grid-column: 2 / -1; border-top: 1px solid var(--builder-border); border-left: 0; } }
|
|
124
|
-
@media (max-width: 1023px) { .pb-header { position: static;
|
|
125
|
-
@media (max-width: 640px) { .pb-header, .pb-canvas-area { padding: var(--builder-space-2); } .pb-header-content {
|
|
144
|
+
@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
|
+
@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: 1 1 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; } }
|