@standhigher/puck-page-builder 0.12.6 → 0.12.8

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 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`, `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.
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. A product snapshot may include catalog display money as `{ amount, currencyCode }` minor units; formatted price strings are dropped. 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
 
@@ -7,6 +7,13 @@ function isHttpUrl(value) {
7
7
  return false;
8
8
  }
9
9
  }
10
+ function isProductMoney(value) {
11
+ if (!value || typeof value !== "object" || Array.isArray(value)) return false;
12
+ const candidate = value;
13
+ const amount = candidate.amount;
14
+ const currencyCode = candidate.currencyCode;
15
+ return typeof amount === "number" && Number.isInteger(amount) && amount >= 0 && typeof currencyCode === "string" && Boolean(currencyCode.trim());
16
+ }
10
17
  function isProductReference(value) {
11
18
  if (!value || typeof value !== "object" || Array.isArray(value)) return false;
12
19
  const candidate = value;
@@ -14,6 +21,7 @@ function isProductReference(value) {
14
21
  if (candidate.title !== void 0 && typeof candidate.title !== "string") return false;
15
22
  if (candidate.handle !== void 0 && typeof candidate.handle !== "string") return false;
16
23
  if (candidate.imageUrl !== void 0 && (typeof candidate.imageUrl !== "string" || !isHttpUrl(candidate.imageUrl))) return false;
24
+ if (candidate.price !== void 0 && !isProductMoney(candidate.price)) return false;
17
25
  return true;
18
26
  }
19
27
  function parseProductReferences(value) {
@@ -27,7 +35,8 @@ function parseProductReferences(value) {
27
35
  id: candidate.id.trim(),
28
36
  ...typeof candidate.title === "string" && candidate.title.trim() ? { title: candidate.title.trim() } : {},
29
37
  ...typeof candidate.handle === "string" && candidate.handle.trim() ? { handle: candidate.handle.trim() } : {},
30
- ...typeof candidate.imageUrl === "string" && isHttpUrl(candidate.imageUrl) ? { imageUrl: candidate.imageUrl } : {}
38
+ ...typeof candidate.imageUrl === "string" && isHttpUrl(candidate.imageUrl) ? { imageUrl: candidate.imageUrl } : {},
39
+ ...isProductMoney(candidate.price) ? { price: { amount: candidate.price.amount, currencyCode: candidate.price.currencyCode } } : {}
31
40
  });
32
41
  }
33
42
  return products;
@@ -37,7 +46,8 @@ function toProductReferenceJson(product) {
37
46
  id: product.id,
38
47
  ...product.title ? { title: product.title } : {},
39
48
  ...product.handle ? { handle: product.handle } : {},
40
- ...product.imageUrl ? { imageUrl: product.imageUrl } : {}
49
+ ...product.imageUrl ? { imageUrl: product.imageUrl } : {},
50
+ ...isProductMoney(product.price) ? { price: { amount: product.price.amount, currencyCode: product.price.currencyCode } } : {}
41
51
  };
42
52
  }
43
53
 
@@ -14,13 +14,19 @@ declare function validatePageDocumentWithRegistry(document: PageDocument, regist
14
14
 
15
15
  /**
16
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.
17
+ * Hosts may add a stable id plus display fields. Catalog display money may be
18
+ * stored as minor units; never persist tokens, secrets, or formatted price strings.
18
19
  */
20
+ type ProductReferenceMoney = {
21
+ amount: number;
22
+ currencyCode: string;
23
+ };
19
24
  type ProductReference = {
20
25
  id: string;
21
26
  title?: string;
22
27
  imageUrl?: string;
23
28
  handle?: string;
29
+ price?: ProductReferenceMoney;
24
30
  };
25
31
  declare function isProductReference(value: unknown): value is ProductReference;
26
32
  declare function parseProductReferences(value: unknown): ProductReference[];
@@ -34,4 +40,4 @@ declare function mergeBlockPolicies(...policies: Array<BlockPolicy | undefined>)
34
40
  declare function minimumBlockInstances(policy: BlockPolicy | undefined): number;
35
41
  declare function maximumBlockInstances(policy: BlockPolicy | undefined): number;
36
42
 
37
- export { BlockPolicy, ExtensionRegistry, FieldConfig, type ProductReference, ValidationIssue, isProductReference, maximumBlockInstances, mergeBlockPolicies, minimumBlockInstances, parseProductReferences, toProductReferenceJson, validateBlockPolicy, validateFieldValue, validatePageDocumentWithRegistry };
43
+ export { BlockPolicy, ExtensionRegistry, FieldConfig, type ProductReference, type ProductReferenceMoney, ValidationIssue, isProductReference, maximumBlockInstances, mergeBlockPolicies, minimumBlockInstances, parseProductReferences, toProductReferenceJson, validateBlockPolicy, validateFieldValue, validatePageDocumentWithRegistry };
@@ -13,7 +13,7 @@ import {
13
13
  validateBlockPolicy,
14
14
  validateFieldValue,
15
15
  validatePageDocumentWithRegistry
16
- } from "./chunk-RLKWR5JM.js";
16
+ } from "./chunk-UWS3OP2P.js";
17
17
  export {
18
18
  ExtensionRegistry,
19
19
  ExtensionRegistryError,
package/dist/index.d.ts CHANGED
@@ -5,7 +5,7 @@ export { B as BlockDefinition, a as BlockEditorProps, b as BlockOperation, d as
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';
8
- export { isProductReference, maximumBlockInstances, mergeBlockPolicies, minimumBlockInstances, parseProductReferences, toProductReferenceJson, validateBlockPolicy, validateFieldValue, validatePageDocumentWithRegistry } from './extensions.js';
8
+ export { ProductReferenceMoney, isProductReference, maximumBlockInstances, mergeBlockPolicies, minimumBlockInstances, parseProductReferences, toProductReferenceJson, validateBlockPolicy, validateFieldValue, validatePageDocumentWithRegistry } from './extensions.js';
9
9
  export { ThemeTokenName, ThemeTokens, mergeThemeTokens, normalizeThemeTokens, systemThemeTokens, toThemeStyle } from './theme.js';
10
10
  import { Data } from '@puckeditor/core';
11
11
  export { WebRenderer, WebRendererProps } from './renderer.js';
@@ -195,7 +195,7 @@ type EditorContextValue = {
195
195
  confirmDeleteBlock(): void;
196
196
  deleteBlock(id: string): void;
197
197
  moveBlock(id: string, direction: -1 | 1): void;
198
- reorderBlock(id: string, beforeId: string): void;
198
+ reorderBlock(id: string, beforeId?: string): void;
199
199
  updateBlockProps(id: string, props: Record<string, JsonValue>): void;
200
200
  updateBlockPresentation(id: string, presentation: Pick<BlockNode, "variant" | "style">): void;
201
201
  undo(): void;
package/dist/index.js CHANGED
@@ -13,7 +13,7 @@ import {
13
13
  validateBlockPolicy,
14
14
  validateFieldValue,
15
15
  validatePageDocumentWithRegistry
16
- } from "./chunk-RLKWR5JM.js";
16
+ } from "./chunk-UWS3OP2P.js";
17
17
  import {
18
18
  WebRenderer
19
19
  } from "./chunk-KYXIXIWK.js";
@@ -759,11 +759,17 @@ function EditorProvider({ initialDocument, registry, policy, loadState = "ready"
759
759
  reorderBlock: (id, beforeId) => {
760
760
  if (!editable || id === beforeId) return;
761
761
  const source = history.document.blocks.find((block) => block.id === id);
762
+ if (!source || !canDragBlock(source, registry?.getBlock(source.type), policy)) return;
762
763
  const withoutSource = history.document.blocks.filter((block) => block.id !== id);
763
- const targetIndex = withoutSource.findIndex((block) => block.id === beforeId);
764
- if (!source || targetIndex < 0 || !canDragBlock(source, registry?.getBlock(source.type), policy)) return;
765
764
  const blocks = [...withoutSource];
766
- blocks.splice(targetIndex, 0, source);
765
+ if (beforeId) {
766
+ const targetIndex = withoutSource.findIndex((block) => block.id === beforeId);
767
+ if (targetIndex < 0) return;
768
+ blocks.splice(targetIndex, 0, source);
769
+ } else {
770
+ blocks.push(source);
771
+ }
772
+ if (blocks.every((block, index) => block.id === history.document.blocks[index]?.id)) return;
767
773
  replace({ ...history.document, blocks }, id);
768
774
  },
769
775
  updateBlockProps,
@@ -966,6 +972,29 @@ import { useEffect as useEffect3, useRef as useRef4, useState as useState3 } fro
966
972
  function nearestBlockIdAtY(blocks, y) {
967
973
  return blocks.find((block) => y < block.top + block.height / 2)?.id;
968
974
  }
975
+ function libraryTypesInDocumentOrder(blockTypes, blocks) {
976
+ const allowed = new Set(blockTypes);
977
+ const seen = /* @__PURE__ */ new Set();
978
+ const ordered = [];
979
+ for (const block of blocks) {
980
+ if (!allowed.has(block.type) || seen.has(block.type)) continue;
981
+ ordered.push(block.type);
982
+ seen.add(block.type);
983
+ }
984
+ for (const type of blockTypes) {
985
+ if (!seen.has(type)) ordered.push(type);
986
+ }
987
+ return ordered;
988
+ }
989
+ function dropPlacement(clientY, top, height) {
990
+ if (height <= 0) return "before";
991
+ return clientY < top + height / 2 ? "before" : "after";
992
+ }
993
+ function beforeIdAfterPlacement(blockIds, targetId, placement) {
994
+ if (placement === "before") return targetId;
995
+ const index = blockIds.indexOf(targetId);
996
+ return index < 0 ? targetId : blockIds[index + 1];
997
+ }
969
998
 
970
999
  // src/editor/shell/CanvasLibraryDropTarget.tsx
971
1000
  import { jsx as jsx8, jsxs as jsxs6 } from "react/jsx-runtime";
@@ -1221,6 +1250,9 @@ function PageDocumentEditor({ iframe = false, registry, adminLocale, onSave, onP
1221
1250
  const [leftRailOpen, setLeftRailOpen] = useState4(true);
1222
1251
  const [rightPanelOpen, setRightPanelOpen] = useState4(true);
1223
1252
  const [draggingLibraryType, setDraggingLibraryType] = useState4(null);
1253
+ const [draggingBlockId, setDraggingBlockId] = useState4(null);
1254
+ const draggingBlockIdRef = useRef5(null);
1255
+ const [dropTarget, setDropTarget] = useState4(null);
1224
1256
  const canvasFrameRef = useRef5(null);
1225
1257
  const [canvasMutationVersion, setCanvasMutationVersion] = useState4(0);
1226
1258
  const [canvasResetVersion, setCanvasResetVersion] = useState4(0);
@@ -1313,14 +1345,27 @@ function PageDocumentEditor({ iframe = false, registry, adminLocale, onSave, onP
1313
1345
  if (editor.sessionState !== "active") return /* @__PURE__ */ jsx9(EditorSessionStatus, { state: editor.sessionState, message: editor.sessionMessage });
1314
1346
  const allBlockTypes = ["core.text", "core.image", ...registry?.blocks.map((block) => block.type) ?? []];
1315
1347
  const blockTypes = availableBlockTypes ? allBlockTypes.filter((type) => availableBlockTypes.includes(type)) : allBlockTypes;
1348
+ const orderedBlockTypes = libraryTypesInDocumentOrder(blockTypes, editor.document.blocks);
1316
1349
  const addFromLibrary = (type, beforeId) => {
1317
1350
  const id = editor.addBlock(type, beforeId);
1318
1351
  if (id) editor.requestCanvasSelection(id);
1319
1352
  };
1353
+ const clearLibraryDrag = () => {
1354
+ draggingBlockIdRef.current = null;
1355
+ setDraggingLibraryType(null);
1356
+ setDraggingBlockId(null);
1357
+ setDropTarget(null);
1358
+ };
1320
1359
  const cancelLibraryDrop = (event) => {
1321
1360
  event.preventDefault();
1322
1361
  event.stopPropagation();
1323
- setDraggingLibraryType(null);
1362
+ clearLibraryDrag();
1363
+ };
1364
+ const applyListReorder = (sourceId, targetId, edge) => {
1365
+ const beforeId = beforeIdAfterPlacement(editorRef.current.document.blocks.map((block) => block.id), targetId, edge);
1366
+ editorRef.current.reorderBlock(sourceId, beforeId);
1367
+ editorRef.current.requestCanvasSelection(sourceId);
1368
+ scrollCanvasBlockIntoView(sourceId, canvasFrameRef.current);
1324
1369
  };
1325
1370
  const saveBadgeTone = resolvedSaveState === "failed" ? "critical" : resolvedSaveState === "offline" || resolvedSaveState === "dirty" ? "attention" : "success";
1326
1371
  const saveBadgeLabel = resolvedSaveState === "saving" ? i18n.t("saving") : resolvedSaveState === "failed" ? i18n.t("saveFailed") : resolvedSaveState === "offline" ? i18n.t("offline") : resolvedSaveState === "dirty" ? i18n.t("unsaved") : i18n.t("saved");
@@ -1381,26 +1426,57 @@ function PageDocumentEditor({ iframe = false, registry, adminLocale, onSave, onP
1381
1426
  /* @__PURE__ */ jsx9(Text3, { as: "h2", variant: "headingSm", children: blockView === "blocks" ? i18n.t("blocks") : i18n.t("outline") }),
1382
1427
  /* @__PURE__ */ jsx9(Button2, { accessibilityLabel: i18n.t("collapseLeft"), icon: XIcon2, variant: "tertiary", onClick: () => setLeftRailOpen(false) })
1383
1428
  ] }),
1384
- blockView === "blocks" ? /* @__PURE__ */ jsx9("div", { className: "pb-block-list", "data-testid": "blocks-view", "aria-label": "\u533A\u5757\u7C7B\u578B\u5E93", role: "list", onDrop: cancelLibraryDrop, children: blockTypes.map((type) => /* @__PURE__ */ jsxs7("div", { className: `pb-document-block-row pb-document-block-row--library ${editor.selectedBlock?.type === type ? "pb-document-block-row--selected" : ""}`, "data-block-type": type, "data-selected": editor.selectedBlock?.type === type, role: "listitem", draggable: editor.canAddBlock(type), "aria-disabled": !editor.canAddBlock(type), "aria-label": `${blockTypeLabel(type, registry)}\uFF0C\u62D6\u62FD\u81F3\u753B\u5E03\u4EE5\u6DFB\u52A0${editor.selectedBlock?.type === type ? "\uFF0C\u5F53\u524D\u9009\u4E2D\u7C7B\u578B" : ""}`, onClick: () => {
1385
- const block = editor.document.blocks.find((item) => item.type === type);
1386
- if (!block) return;
1387
- editor.requestCanvasSelection(block.id);
1388
- scrollCanvasBlockIntoView(block.id, canvasFrameRef.current);
1389
- }, onDragStart: (event) => {
1390
- if (!editor.canAddBlock(type)) {
1429
+ blockView === "blocks" ? /* @__PURE__ */ jsx9("div", { className: "pb-block-list", "data-testid": "blocks-view", "aria-label": "\u533A\u5757\u7C7B\u578B\u5E93", role: "list", onDrop: cancelLibraryDrop, children: orderedBlockTypes.map((type) => {
1430
+ const instance = editor.document.blocks.find((item) => item.type === type);
1431
+ const canAdd = editor.canAddBlock(type);
1432
+ const canReorder = Boolean(instance && editor.canDragBlock(instance.id));
1433
+ const draggable = canAdd || canReorder;
1434
+ const selected = editor.selectedBlock?.type === type;
1435
+ const dropEdge = draggingBlockId && instance && dropTarget?.id === instance.id ? dropTarget.edge : void 0;
1436
+ const actionHint = canReorder && canAdd ? "\uFF0C\u62D6\u62FD\u6392\u5E8F\uFF0C\u6216\u62D6\u62FD\u81F3\u753B\u5E03\u4EE5\u6DFB\u52A0" : canReorder ? "\uFF0C\u62D6\u62FD\u6392\u5E8F" : canAdd ? "\uFF0C\u62D6\u62FD\u81F3\u753B\u5E03\u4EE5\u6DFB\u52A0" : "";
1437
+ return /* @__PURE__ */ jsxs7("div", { className: `pb-document-block-row pb-document-block-row--library${selected ? " pb-document-block-row--selected" : ""}${draggingBlockId === instance?.id ? " pb-document-block-row--dragging" : ""}${dropEdge === "before" ? " pb-document-block-row--drop-before" : ""}${dropEdge === "after" ? " pb-document-block-row--drop-after" : ""}`, "data-block-type": type, "data-selected": selected, "data-drop-edge": dropEdge, role: "listitem", draggable, "aria-disabled": !draggable, "aria-label": `${blockTypeLabel(type, registry)}${actionHint}${selected ? "\uFF0C\u5F53\u524D\u9009\u4E2D\u7C7B\u578B" : ""}`, onClick: () => {
1438
+ if (!instance) return;
1439
+ editor.requestCanvasSelection(instance.id);
1440
+ scrollCanvasBlockIntoView(instance.id, canvasFrameRef.current);
1441
+ }, onDragStart: (event) => {
1442
+ if (!draggable) {
1443
+ event.preventDefault();
1444
+ return;
1445
+ }
1446
+ event.dataTransfer.setData("application/x-page-document-block", type);
1447
+ if (instance && canReorder) {
1448
+ event.dataTransfer.setData("application/x-page-document-block-id", instance.id);
1449
+ event.dataTransfer.effectAllowed = canAdd ? "copyMove" : "move";
1450
+ draggingBlockIdRef.current = instance.id;
1451
+ setDraggingBlockId(instance.id);
1452
+ } else event.dataTransfer.effectAllowed = "copy";
1453
+ if (canAdd) setDraggingLibraryType(type);
1454
+ }, onDragOver: (event) => {
1455
+ const sourceId = draggingBlockIdRef.current;
1456
+ if (!sourceId || !instance || sourceId === instance.id) return;
1457
+ event.preventDefault();
1458
+ event.stopPropagation();
1459
+ event.dataTransfer.dropEffect = "move";
1460
+ const rect = event.currentTarget.getBoundingClientRect();
1461
+ setDropTarget({ id: instance.id, edge: dropPlacement(event.clientY, rect.top, rect.height) });
1462
+ }, onDragLeave: (event) => {
1463
+ if (instance && !event.currentTarget.contains(event.relatedTarget)) setDropTarget((current) => current?.id === instance.id ? null : current);
1464
+ }, onDrop: (event) => {
1465
+ const sourceId = draggingBlockIdRef.current;
1466
+ if (!sourceId || !instance || sourceId === instance.id) return;
1391
1467
  event.preventDefault();
1392
- return;
1393
- }
1394
- event.dataTransfer.setData("application/x-page-document-block", type);
1395
- event.dataTransfer.effectAllowed = "copy";
1396
- setDraggingLibraryType(type);
1397
- }, onDragEnd: () => setDraggingLibraryType(null), children: [
1398
- /* @__PURE__ */ jsxs7("span", { className: "pb-library-block-title", children: [
1399
- /* @__PURE__ */ jsx9(Text3, { as: "span", variant: "bodySm", fontWeight: "semibold", children: blockTypeLabel(type, registry) }),
1400
- /* @__PURE__ */ jsx9("span", { className: "pb-library-block-drag-hint", "aria-hidden": "true", children: /* @__PURE__ */ jsx9(DragHandleIcon2, {}) })
1401
- ] }),
1402
- /* @__PURE__ */ jsx9(Text3, { as: "span", variant: "bodySm", tone: "subdued", children: type })
1403
- ] }, type)) }) : editor.document.blocks.length === 0 ? /* @__PURE__ */ jsx9(Text3, { as: "p", tone: "subdued", children: i18n.t("empty") }) : /* @__PURE__ */ jsx9("div", { className: "pb-block-list", "data-testid": "outline-view", children: editor.document.blocks.map((block) => /* @__PURE__ */ jsxs7("button", { type: "button", className: `pb-document-block-row pb-document-block-row--library ${block.id === editor.selectedBlockId ? "pb-document-block-row--selected" : ""}`, "aria-pressed": block.id === editor.selectedBlockId, onClick: () => {
1468
+ event.stopPropagation();
1469
+ const rect = event.currentTarget.getBoundingClientRect();
1470
+ applyListReorder(sourceId, instance.id, dropPlacement(event.clientY, rect.top, rect.height));
1471
+ clearLibraryDrag();
1472
+ }, onDragEnd: clearLibraryDrag, children: [
1473
+ /* @__PURE__ */ jsxs7("span", { className: "pb-library-block-title", children: [
1474
+ /* @__PURE__ */ jsx9(Text3, { as: "span", variant: "bodySm", fontWeight: "semibold", children: blockTypeLabel(type, registry) }),
1475
+ /* @__PURE__ */ jsx9("span", { className: "pb-library-block-drag-hint", "aria-hidden": "true", children: /* @__PURE__ */ jsx9(DragHandleIcon2, {}) })
1476
+ ] }),
1477
+ /* @__PURE__ */ jsx9(Text3, { as: "span", variant: "bodySm", tone: "subdued", children: type })
1478
+ ] }, type);
1479
+ }) }) : editor.document.blocks.length === 0 ? /* @__PURE__ */ jsx9(Text3, { as: "p", tone: "subdued", children: i18n.t("empty") }) : /* @__PURE__ */ jsx9("div", { className: "pb-block-list", "data-testid": "outline-view", children: editor.document.blocks.map((block) => /* @__PURE__ */ jsxs7("button", { type: "button", className: `pb-document-block-row pb-document-block-row--library ${block.id === editor.selectedBlockId ? "pb-document-block-row--selected" : ""}`, "aria-pressed": block.id === editor.selectedBlockId, onClick: () => {
1404
1480
  editor.requestCanvasSelection(block.id);
1405
1481
  scrollCanvasBlockIntoView(block.id, canvasFrameRef.current);
1406
1482
  }, children: [
package/dist/runtime.d.ts CHANGED
@@ -1,6 +1,6 @@
1
1
  export { WebRenderer, WebRendererProps } from './renderer.js';
2
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
- export { ProductReference, isProductReference, maximumBlockInstances, mergeBlockPolicies, minimumBlockInstances, parseProductReferences, toProductReferenceJson, validateBlockPolicy, validateFieldValue, validatePageDocumentWithRegistry } from './extensions.js';
3
+ export { ProductReference, ProductReferenceMoney, 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
@@ -13,7 +13,7 @@ import {
13
13
  validateBlockPolicy,
14
14
  validateFieldValue,
15
15
  validatePageDocumentWithRegistry
16
- } from "./chunk-RLKWR5JM.js";
16
+ } from "./chunk-UWS3OP2P.js";
17
17
  import {
18
18
  WebRenderer
19
19
  } from "./chunk-KYXIXIWK.js";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@standhigher/puck-page-builder",
3
- "version": "0.12.6",
3
+ "version": "0.12.8",
4
4
  "description": "React PageDocument editor, extension registry, and web renderer for BestTrack page experiences.",
5
5
  "type": "module",
6
6
  "repository": {
package/src/styles.css CHANGED
@@ -127,6 +127,9 @@ button:focus-visible, [role="button"]:focus-visible { outline: 2px solid var(--b
127
127
  .pb-document-block-row--library { width: 100%; flex-direction: column; align-items: flex-start; text-align: left; color: var(--builder-text); font: inherit; cursor: grab; }
128
128
  .pb-document-block-row--library:active { cursor: grabbing; }
129
129
  .pb-document-block-row--library[aria-disabled="true"] { cursor: default; }
130
+ .pb-document-block-row--dragging { opacity: 0.55; }
131
+ .pb-document-block-row--drop-before { box-shadow: inset 0 3px 0 0 var(--builder-accent); }
132
+ .pb-document-block-row--drop-after { box-shadow: inset 0 -3px 0 0 var(--builder-accent); }
130
133
  .pb-document-block-row--library[type="button"] { cursor: pointer; }
131
134
  .pb-library-block-title { display: flex; align-items: center; justify-content: space-between; width: 100%; gap: var(--builder-space-2); }
132
135
  .pb-library-block-drag-hint { display: inline-flex; color: var(--builder-text-muted); pointer-events: none; }