@elytracms/studio 0.0.94 → 0.0.96

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.
Files changed (164) hide show
  1. package/convex/asset-alt-migration.test.ts +2 -2
  2. package/convex/asset-meta-patch.test.ts +218 -0
  3. package/convex/asset-replace-delete-race.test.ts +127 -0
  4. package/convex/assets.ts +27 -2
  5. package/convex/cms.ts +124 -8
  6. package/convex/delivery-redirects.test.ts +167 -0
  7. package/convex/delivery.ts +15 -5
  8. package/convex/rail-write-parity.test.ts +6 -6
  9. package/convex/redirects.ts +1 -1
  10. package/convex/schema.ts +6 -0
  11. package/convex/strict-reference-race.test.ts +139 -0
  12. package/dist/addon.d.ts +1 -1
  13. package/dist/addon.js.map +1 -1
  14. package/dist/components/ai/ai-chat-panel.js +15 -2
  15. package/dist/components/ai/ai-chat-panel.js.map +1 -1
  16. package/dist/components/ai/translate-document-action.d.ts +6 -0
  17. package/dist/components/ai/translate-document-action.js.map +1 -1
  18. package/dist/components/ai/translate-document-dialog.d.ts +1 -1
  19. package/dist/components/ai/translate-document-dialog.js +5 -5
  20. package/dist/components/ai/translate-document-dialog.js.map +1 -1
  21. package/dist/components/assets/asset-detail.js +29 -11
  22. package/dist/components/assets/asset-detail.js.map +1 -1
  23. package/dist/components/assets/asset-locale.d.ts +16 -0
  24. package/dist/components/assets/asset-locale.js +30 -0
  25. package/dist/components/assets/asset-locale.js.map +1 -0
  26. package/dist/components/assets/asset-meta-drift-notice.d.ts +13 -0
  27. package/dist/components/assets/asset-meta-drift-notice.js +22 -0
  28. package/dist/components/assets/asset-meta-drift-notice.js.map +1 -0
  29. package/dist/components/assets/asset-meta-label.d.ts +13 -0
  30. package/dist/components/assets/asset-meta-label.js +17 -0
  31. package/dist/components/assets/asset-meta-label.js.map +1 -0
  32. package/dist/components/assets/asset-metadata.d.ts +89 -15
  33. package/dist/components/assets/asset-metadata.js +123 -11
  34. package/dist/components/assets/asset-metadata.js.map +1 -1
  35. package/dist/components/assets/asset-search.d.ts +6 -2
  36. package/dist/components/assets/asset-search.js +19 -3
  37. package/dist/components/assets/asset-search.js.map +1 -1
  38. package/dist/components/assets/asset-thumb.js +6 -2
  39. package/dist/components/assets/asset-thumb.js.map +1 -1
  40. package/dist/components/assets/assets-collection-view-source.d.ts +25 -9
  41. package/dist/components/assets/assets-collection-view-source.js +80 -26
  42. package/dist/components/assets/assets-collection-view-source.js.map +1 -1
  43. package/dist/components/assets/assets-store.js +17 -4
  44. package/dist/components/assets/assets-store.js.map +1 -1
  45. package/dist/components/builder/builder-store.d.ts +21 -0
  46. package/dist/components/builder/builder-store.js +22 -0
  47. package/dist/components/builder/builder-store.js.map +1 -1
  48. package/dist/components/builder/canvas-commit-boundary.d.ts +22 -0
  49. package/dist/components/builder/canvas-commit-boundary.js +27 -0
  50. package/dist/components/builder/canvas-commit-boundary.js.map +1 -0
  51. package/dist/components/builder/canvas-rebase.d.ts +101 -0
  52. package/dist/components/builder/canvas-rebase.js +179 -0
  53. package/dist/components/builder/canvas-rebase.js.map +1 -0
  54. package/dist/components/builder/canvas-render-context.d.ts +6 -3
  55. package/dist/components/builder/canvas-render-context.js +17 -8
  56. package/dist/components/builder/canvas-render-context.js.map +1 -1
  57. package/dist/components/builder/composition-field-editor.d.ts +26 -2
  58. package/dist/components/builder/composition-field-editor.js +46 -27
  59. package/dist/components/builder/composition-field-editor.js.map +1 -1
  60. package/dist/components/builder/node-factory.js +15 -3
  61. package/dist/components/builder/node-factory.js.map +1 -1
  62. package/dist/components/builder/property-inspector.js +3 -1
  63. package/dist/components/builder/property-inspector.js.map +1 -1
  64. package/dist/components/builder/run-inspector.js +10 -6
  65. package/dist/components/builder/run-inspector.js.map +1 -1
  66. package/dist/components/cms/asset-field.d.ts +5 -2
  67. package/dist/components/cms/asset-field.js +34 -17
  68. package/dist/components/cms/asset-field.js.map +1 -1
  69. package/dist/components/cms/asset-picker-core.d.ts +2 -2
  70. package/dist/components/cms/asset-picker-core.js +2 -2
  71. package/dist/components/cms/asset-picker-core.js.map +1 -1
  72. package/dist/components/cms/asset-picker.js +6 -2
  73. package/dist/components/cms/asset-picker.js.map +1 -1
  74. package/dist/components/cms/canvas-commit.d.ts +62 -0
  75. package/dist/components/cms/canvas-commit.js +39 -0
  76. package/dist/components/cms/canvas-commit.js.map +1 -0
  77. package/dist/components/cms/cms-store.d.ts +21 -8
  78. package/dist/components/cms/cms-store.js +19 -10
  79. package/dist/components/cms/cms-store.js.map +1 -1
  80. package/dist/components/cms/collection-table.js +27 -18
  81. package/dist/components/cms/collection-table.js.map +1 -1
  82. package/dist/components/cms/commit-policy.d.ts +6 -2
  83. package/dist/components/cms/commit-policy.js +1 -1
  84. package/dist/components/cms/commit-policy.js.map +1 -1
  85. package/dist/components/cms/detail-editor.js +12 -2
  86. package/dist/components/cms/detail-editor.js.map +1 -1
  87. package/dist/components/cms/draft-commit.d.ts +16 -3
  88. package/dist/components/cms/draft-commit.js +3 -2
  89. package/dist/components/cms/draft-commit.js.map +1 -1
  90. package/dist/components/cms/use-document-draft.d.ts +121 -5
  91. package/dist/components/cms/use-document-draft.js +197 -54
  92. package/dist/components/cms/use-document-draft.js.map +1 -1
  93. package/dist/components/cms/use-live-url.d.ts +6 -1
  94. package/dist/components/cms/use-live-url.js +12 -9
  95. package/dist/components/cms/use-live-url.js.map +1 -1
  96. package/dist/components/collection-view/cms-collection-view-source.js +11 -5
  97. package/dist/components/collection-view/cms-collection-view-source.js.map +1 -1
  98. package/dist/components/components/transfer-dialog.js +6 -4
  99. package/dist/components/components/transfer-dialog.js.map +1 -1
  100. package/dist/components/deployment-setup-gate.js +10 -1
  101. package/dist/components/deployment-setup-gate.js.map +1 -1
  102. package/dist/components/records/record-lens.js +3 -8
  103. package/dist/components/records/record-lens.js.map +1 -1
  104. package/dist/lib/ai/chat-state.d.ts +7 -0
  105. package/dist/lib/ai/chat-state.js.map +1 -1
  106. package/dist/lib/ai/tools.d.ts +8 -0
  107. package/dist/lib/ai/tools.js +4 -0
  108. package/dist/lib/ai/tools.js.map +1 -1
  109. package/dist/lib/assets/upload.d.ts +25 -7
  110. package/dist/lib/assets/upload.js +30 -21
  111. package/dist/lib/assets/upload.js.map +1 -1
  112. package/dist/lib/cms/published-documents.d.ts +24 -6
  113. package/dist/lib/cms/published-documents.js +39 -6
  114. package/dist/lib/cms/published-documents.js.map +1 -1
  115. package/dist/lib/cms-views/view-model.d.ts +25 -105
  116. package/dist/lib/cms-views/view-model.js +36 -103
  117. package/dist/lib/cms-views/view-model.js.map +1 -1
  118. package/dist/lib/collection-view/__fixtures__/document-writes.js +1 -0
  119. package/dist/lib/collection-view/__fixtures__/document-writes.js.map +1 -1
  120. package/dist/lib/collection-view/collection-view-source.d.ts +21 -8
  121. package/dist/lib/collection-view/collection-view-source.js.map +1 -1
  122. package/dist/lib/data/collection-content.js +5 -0
  123. package/dist/lib/data/collection-content.js.map +1 -1
  124. package/dist/lib/engine-version.d.ts +1 -1
  125. package/dist/lib/engine-version.js +1 -1
  126. package/dist/lib/engine-version.js.map +1 -1
  127. package/dist/lib/i18n/messages.de.js +20 -4
  128. package/dist/lib/i18n/messages.de.js.map +1 -1
  129. package/dist/lib/i18n/messages.en.d.ts +16 -1
  130. package/dist/lib/i18n/messages.en.js +22 -5
  131. package/dist/lib/i18n/messages.en.js.map +1 -1
  132. package/dist/lib/operations/cms-persistence.d.ts +80 -35
  133. package/dist/lib/operations/cms-persistence.js +348 -85
  134. package/dist/lib/operations/cms-persistence.js.map +1 -1
  135. package/dist/lib/operations/config-manifest-lookup.d.ts +1 -1
  136. package/dist/lib/operations/config-manifest-lookup.js +3 -3
  137. package/dist/lib/operations/config-manifest-lookup.js.map +1 -1
  138. package/dist/lib/persistence/convex-adapter.js +54 -8
  139. package/dist/lib/persistence/convex-adapter.js.map +1 -1
  140. package/dist/lib/persistence/deployment-readiness.js +14 -11
  141. package/dist/lib/persistence/deployment-readiness.js.map +1 -1
  142. package/dist/lib/persona/labels.js +2 -0
  143. package/dist/lib/persona/labels.js.map +1 -1
  144. package/dist/lib/query/index.d.ts +2 -2
  145. package/dist/lib/query/index.js +1 -1
  146. package/dist/lib/query/index.js.map +1 -1
  147. package/dist/lib/query/operations-query.d.ts +26 -0
  148. package/dist/lib/query/operations-query.js +12 -0
  149. package/dist/lib/query/operations-query.js.map +1 -1
  150. package/dist/lib/registry/index.js +2 -2
  151. package/dist/lib/registry/index.js.map +1 -1
  152. package/dist/lib/registry/preview.d.ts +10 -0
  153. package/dist/lib/registry/preview.js +13 -4
  154. package/dist/lib/registry/preview.js.map +1 -1
  155. package/dist/lib/routes/route-issues.js +6 -3
  156. package/dist/lib/routes/route-issues.js.map +1 -1
  157. package/dist/lib/workspace/workspace-source.js +6 -7
  158. package/dist/lib/workspace/workspace-source.js.map +1 -1
  159. package/dist/previews/entry-node.d.ts +14 -0
  160. package/dist/previews/entry-node.js +22 -0
  161. package/dist/previews/entry-node.js.map +1 -0
  162. package/dist/previews/harness.js +2 -16
  163. package/dist/previews/harness.js.map +1 -1
  164. package/package.json +3 -3
@@ -1,9 +1,10 @@
1
1
  import { jsx as _jsx } from "react/jsx-runtime";
2
- import { useCallback, useContext, useMemo, useRef, useState } from 'react';
2
+ import { useCallback, useContext, useEffect, useMemo, useRef, useState } from 'react';
3
3
  import { deleteAsset, runVariantBackfill, runUpload, xhrUploadTransport } from '../../lib/assets/index.js';
4
+ import { configureStudioLocales } from '../../lib/locale/index.js';
4
5
  import { loadInboundAssetReferenceViews } from '../../lib/references/index.js';
5
6
  import { getStudioOperations, operationsAssetRepository } from '../../lib/operations/index.js';
6
- import { projectCollections } from '../../lib/operations/project-runtime-config.js';
7
+ import { projectCollections, projectLocaleConfig } from '../../lib/operations/project-runtime-config.js';
7
8
  import { listStoreState, useOperationCache, useOperationQuery } from '../../lib/query/index.js';
8
9
  import { createRequiredContext } from '../../lib/required-context.js';
9
10
  import { updateAssetMetadata } from './asset-metadata.js';
@@ -31,6 +32,16 @@ export function AssetsProvider({ projectId, children, }) {
31
32
  // EC-568: the asset collection's fields — their `source` declarations map a file's
32
33
  // embedded IPTC facts onto `meta` on every upload and replace. Config, read once.
33
34
  const assetFields = useMemo(() => projectCollections(projectId).find((collection) => collection.kind === 'asset')?.fields, [projectId]);
35
+ // EC-632: the project's locales — a localized asset field's embedded values (XMP
36
+ // `xml:lang` alternatives) land in their locale buckets. Config, read once.
37
+ const locales = useMemo(() => projectLocaleConfig(projectId), [projectId]);
38
+ // EC-632: the asset surfaces read and edit a localized field in the studio's ambient
39
+ // locale — install the project's locales (idempotent, as the CMS store does), so the asset
40
+ // library opened before any CMS surface has them too.
41
+ useEffect(() => {
42
+ if (locales)
43
+ configureStudioLocales(locales);
44
+ }, [locales]);
34
45
  /** The shared studio operations bundle + the metadata-write facade over it. */
35
46
  const studio = useCallback(async () => {
36
47
  const bundle = await getStudioOperations();
@@ -63,6 +74,7 @@ export function AssetsProvider({ projectId, children, }) {
63
74
  blobs: adapter.blobs,
64
75
  assets: assetRepo,
65
76
  ...(assetFields ? { assetFields } : {}),
77
+ ...(locales ? { locales } : {}),
66
78
  ...(typeof XMLHttpRequest !== 'undefined' ? { transport: xhrUploadTransport } : {}),
67
79
  }, {
68
80
  projectId,
@@ -76,7 +88,7 @@ export function AssetsProvider({ projectId, children, }) {
76
88
  setUploads((prev) => prev.filter((u) => u.id !== uploadId));
77
89
  await refresh();
78
90
  }
79
- }, [studio, projectId, refresh, setUploadState, assetFields]);
91
+ }, [studio, projectId, refresh, setUploadState, assetFields, locales]);
80
92
  const upload = useCallback((files) => {
81
93
  const ids = [];
82
94
  for (const file of files) {
@@ -144,6 +156,7 @@ export function AssetsProvider({ projectId, children, }) {
144
156
  blobs: adapter.blobs,
145
157
  assets: assetRepo,
146
158
  ...(assetFields ? { assetFields } : {}),
159
+ ...(locales ? { locales } : {}),
147
160
  ...(typeof XMLHttpRequest !== 'undefined' ? { transport: xhrUploadTransport } : {}),
148
161
  }, { projectId, file, replace: { assetId } });
149
162
  if (!result.ok)
@@ -151,7 +164,7 @@ export function AssetsProvider({ projectId, children, }) {
151
164
  const updated = result.asset;
152
165
  cache.patch(assetsQueryKey(projectId), (prev) => (prev ?? []).map((a) => (a.id === assetId ? updated : a)));
153
166
  return { ok: true, asset: updated };
154
- }, [studio, projectId, cache, assetFields]);
167
+ }, [studio, projectId, cache, assetFields, locales]);
155
168
  const generatePreviews = useCallback(async (handlers) => {
156
169
  const { adapter, assetRepo } = await studio();
157
170
  // Reads (list) + the variant patch (upsert) go through the operations facade;
@@ -1 +1 @@
1
- {"version":3,"file":"assets-store.js","sourceRoot":"","sources":["../../../src/components/assets/assets-store.tsx"],"names":[],"mappings":"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","sourcesContent":["import { useCallback, useContext, useMemo, useRef, useState } from 'react'\nimport type { ReactNode } from 'react'\nimport type { AssetRecord, AssetRepository } from '@elytracms/core/persistence'\nimport { deleteAsset, runVariantBackfill, runUpload, xhrUploadTransport } from '../../lib/assets'\nimport type {\n BackfillProgress,\n BackfillSignal,\n DeleteAssetResult,\n UploadState,\n UploadableFile,\n} from '../../lib/assets'\nimport { loadInboundAssetReferenceViews } from '../../lib/references'\nimport type { ReferenceEntryView } from '../../lib/references'\nimport { getStudioOperations, operationsAssetRepository } from '../../lib/operations'\nimport { projectCollections } from '../../lib/operations/project-runtime-config'\nimport type { OperationsClient, StudioOperations } from '../../lib/operations'\nimport { listStoreState, useOperationCache, useOperationQuery } from '../../lib/query'\nimport { createRequiredContext } from '../../lib/required-context'\nimport { updateAssetMetadata } from './asset-metadata'\nimport type { AssetMetadataPatch, UpdateAssetMetadataResult } from './asset-metadata'\n\n/**\n * Asset library store (EC-151, EC-141). Asset *metadata* mutations go through\n * the shared operations client (`assets.*` commands — validate → authorize →\n * mutate → event); blob *bytes* ride on `adapter.blobs`, which is transport,\n * not domain. The UI works identically against the in-memory seed and a live\n * Convex deployment.\n */\n\nexport interface UploadEntry {\n id: string\n filename: string\n state: UploadState\n}\n\nexport interface AssetsStore {\n /** The active project (e.g. for reference deep links, EC-202). */\n projectId: string\n status: 'loading' | 'ready' | 'error'\n errorMessage?: string\n assets: readonly AssetRecord[]\n uploads: readonly UploadEntry[]\n /**\n * Queue files for upload. Returns the upload-queue id of each file, in order, so a\n * caller can follow exactly ITS uploads (EC-588 A7) — see {@link landedAssetId}.\n */\n upload(files: Iterable<UploadableFile>): readonly string[]\n /**\n * The asset id an upload landed as, once its record is confirmed (EC-588 A7);\n * `undefined` while it runs, after it failed, or for an id this store never issued.\n * A completed upload leaves the queue, so this is where its outcome stays readable.\n */\n landedAssetId(uploadId: string): string | undefined\n retryUpload(uploadId: string): void\n dismissUpload(uploadId: string): void\n /**\n * Index-accurate inbound references of an asset (EC-202): the \"used by\"\n * pre-flight of the block-or-confirm delete dialog, read from the EC-155\n * reference index (not the retired string scan).\n */\n usagesOf(assetId: string): Promise<ReferenceEntryView[]>\n remove(assetId: string, options?: { confirmInUse?: boolean }): Promise<DeleteAssetResult>\n /** Edit alt/title (EC-152); persists through the operations asset facade. */\n updateMetadata(assetId: string, patch: AssetMetadataPatch): Promise<UpdateAssetMetadataResult>\n /**\n * EC-568 — replace the file inside an asset: the same id, the new bytes, everything\n * derived regenerated through THE upload path, the file's embedded metadata over\n * `meta` per key (else kept), the focal point kept.\n */\n replaceFile(assetId: string, file: UploadableFile): Promise<ReplaceFileResult>\n /**\n * Backfill downscaled previews onto existing images (EC-400 AD-1). Sequential,\n * idempotent, cancellable; each patch flows through the operations facade and\n * the shared query cache (AD-5/AD-17). Reports progress via `handlers.onProgress`\n * and stops when `handlers.signal.cancelled` flips.\n */\n generatePreviews(handlers?: {\n onProgress?: (progress: BackfillProgress) => void\n signal?: BackfillSignal\n }): Promise<BackfillProgress>\n refresh(): Promise<void>\n}\n\n/** The outcome of {@link AssetsStore.replaceFile}. */\nexport type ReplaceFileResult = { ok: true; asset: AssetRecord } | { ok: false; message: string }\n\nconst { Context: AssetsContext, useRequired: useAssets } = createRequiredContext<AssetsStore>(\n 'Assets',\n { article: 'an' },\n)\n\nconst EMPTY_ASSETS: readonly AssetRecord[] = []\n\n/** Cache key for a project's asset library (shared by the query and its patches). */\nfunction assetsQueryKey(projectId: string): readonly [string, string] {\n return ['assets', projectId]\n}\n\n/** Load a project's asset library (pure over the operations client). A list\n * failure throws so the query surfaces it as an error status. */\nasync function loadAssets(operations: OperationsClient, projectId: string): Promise<AssetRecord[]> {\n const result = await operations.assets.list({ projectId })\n if (!result.ok) throw new Error(result.error.message)\n return [...result.value]\n}\n\nexport function AssetsProvider({\n projectId,\n children,\n}: {\n projectId: string\n children: ReactNode\n}) {\n const uploadFilesRef = useRef(new Map<string, UploadableFile>())\n // EC-588 A7: upload id → the asset id it landed as. Written BEFORE the entry leaves\n // the queue, so a reader never sees an upload that is neither running nor landed.\n const landedRef = useRef(new Map<string, string>())\n const uploadSeq = useRef(0)\n const [uploads, setUploads] = useState<readonly UploadEntry[]>([])\n\n // EC-568: the asset collection's fields — their `source` declarations map a file's\n // embedded IPTC facts onto `meta` on every upload and replace. Config, read once.\n const assetFields = useMemo(\n () => projectCollections(projectId).find((collection) => collection.kind === 'asset')?.fields,\n [projectId],\n )\n\n /** The shared studio operations bundle + the metadata-write facade over it. */\n const studio = useCallback(async (): Promise<\n StudioOperations & { assetRepo: AssetRepository }\n > => {\n const bundle = await getStudioOperations()\n return { ...bundle, assetRepo: operationsAssetRepository(bundle.operations) }\n }, [])\n\n // The library list, read through the one operations-backed query cache\n // (EC-308/AD-17). No `invalidateOn`: this provider is the sole writer of its\n // project's assets, so its own mutations patch the cache in place (the EC-301\n // rule — a metadata or focal-point edit must never trigger a full re-list).\n const query = useOperationQuery<AssetRecord[]>({\n queryKey: assetsQueryKey(projectId),\n loader: (operations) => loadAssets(operations, projectId),\n })\n const cache = useOperationCache()\n const refetch = query.refetch\n const assets = query.data ?? EMPTY_ASSETS\n const { status, errorMessage } = listStoreState(query)\n\n /** Re-list from the backend (the public escape hatch + post-upload reconcile). */\n const refresh = useCallback(async () => {\n await refetch()\n }, [refetch])\n\n const setUploadState = useCallback((uploadId: string, state: UploadState) => {\n setUploads((prev) => prev.map((u) => (u.id === uploadId ? { ...u, state } : u)))\n }, [])\n\n const runEntry = useCallback(\n async (uploadId: string, file: UploadableFile, previous?: UploadState) => {\n const { adapter, assetRepo } = await studio()\n const result = await runUpload(\n {\n // Bytes ride on blob storage (transport); the metadata record is\n // confirmed through the `assets.upsert` operation command.\n blobs: adapter.blobs,\n assets: assetRepo,\n ...(assetFields ? { assetFields } : {}),\n ...(typeof XMLHttpRequest !== 'undefined' ? { transport: xhrUploadTransport } : {}),\n },\n {\n projectId,\n file,\n onState: (state) => setUploadState(uploadId, state),\n },\n previous,\n )\n if (result.ok) {\n // Completed uploads leave the queue; the asset appears in the library.\n landedRef.current.set(uploadId, result.asset.id)\n uploadFilesRef.current.delete(uploadId)\n setUploads((prev) => prev.filter((u) => u.id !== uploadId))\n await refresh()\n }\n },\n [studio, projectId, refresh, setUploadState, assetFields],\n )\n\n const upload = useCallback(\n (files: Iterable<UploadableFile>): readonly string[] => {\n const ids: string[] = []\n for (const file of files) {\n uploadSeq.current += 1\n const uploadId = `upload-${uploadSeq.current}`\n ids.push(uploadId)\n uploadFilesRef.current.set(uploadId, file)\n setUploads((prev) => [\n ...prev,\n { id: uploadId, filename: file.name, state: { phase: 'idle', progress: 0, attempt: 0 } },\n ])\n void runEntry(uploadId, file)\n }\n return ids\n },\n [runEntry],\n )\n\n const landedAssetId = useCallback((uploadId: string) => landedRef.current.get(uploadId), [])\n\n const retryUpload = useCallback(\n (uploadId: string) => {\n const file = uploadFilesRef.current.get(uploadId)\n const entry = uploads.find((u) => u.id === uploadId)\n if (!file || !entry || entry.state.phase !== 'failed') return\n void runEntry(uploadId, file, entry.state)\n },\n [runEntry, uploads],\n )\n\n const dismissUpload = useCallback((uploadId: string) => {\n uploadFilesRef.current.delete(uploadId)\n setUploads((prev) => prev.filter((u) => u.id !== uploadId))\n }, [])\n\n const usagesOf = useCallback(\n // Index-accurate (EC-202): inbound references from the EC-155 index via the\n // operations queries — the same machinery the References panel uses.\n async (assetId: string) => loadInboundAssetReferenceViews(projectId, assetId),\n [projectId],\n )\n\n const remove = useCallback(\n async (assetId: string, options?: { confirmInUse?: boolean }) => {\n const { adapter, assetRepo } = await studio()\n // Metadata removal goes through the `assets.remove` command (via the\n // facade); blob byte deletion stays on the adapter; the usage gate reads\n // the EC-155 reference index (`adapter.references`, EC-202).\n const result = await deleteAsset(\n { assets: assetRepo, blobs: adapter.blobs, references: adapter.references },\n projectId,\n assetId,\n options,\n )\n // Drop the one removed record from the cache rather than re-listing the whole\n // library (EC-301 perf, mirrors updateMetadata) — a delete must not trigger a full\n // `assets.list` round-trip on top of the deletion itself.\n if (result.outcome === 'deleted' || result.outcome === 'not-found') {\n cache.patch<AssetRecord[]>(assetsQueryKey(projectId), (prev) =>\n (prev ?? []).filter((a) => a.id !== assetId),\n )\n }\n return result\n },\n [studio, projectId, cache],\n )\n\n const updateMetadata = useCallback(\n async (assetId: string, patch: AssetMetadataPatch) => {\n // Metadata writes go through the `assets.upsert` command via the\n // operations facade (EC-141) — never straight at a repository.\n const { assetRepo } = await studio()\n const result = await updateAssetMetadata({ assets: assetRepo }, projectId, assetId, patch)\n if (result.ok) {\n // Patch the one updated record into the cache rather than re-listing the\n // whole library (EC-301). A focal-point or alt edit must not trigger a full\n // `assets.list` round-trip — that re-list (plus the marker only moving once\n // it returned) was the focal-point picker's lag and query storm.\n const updated = result.asset\n cache.patch<AssetRecord[]>(assetsQueryKey(projectId), (prev) =>\n (prev ?? []).map((a) => (a.id === assetId ? updated : a)),\n )\n }\n return result\n },\n [studio, projectId, cache],\n )\n\n const replaceFile = useCallback(\n async (assetId: string, file: UploadableFile): Promise<ReplaceFileResult> => {\n const { adapter, assetRepo } = await studio()\n // EC-568: THE upload path, in replace mode — not a second uploader.\n const result = await runUpload(\n {\n blobs: adapter.blobs,\n assets: assetRepo,\n ...(assetFields ? { assetFields } : {}),\n ...(typeof XMLHttpRequest !== 'undefined' ? { transport: xhrUploadTransport } : {}),\n },\n { projectId, file, replace: { assetId } },\n )\n if (!result.ok) return { ok: false, message: result.failure.message }\n const updated = result.asset\n cache.patch<AssetRecord[]>(assetsQueryKey(projectId), (prev) =>\n (prev ?? []).map((a) => (a.id === assetId ? updated : a)),\n )\n return { ok: true, asset: updated }\n },\n [studio, projectId, cache, assetFields],\n )\n\n const generatePreviews = useCallback(\n async (handlers?: {\n onProgress?: (progress: BackfillProgress) => void\n signal?: BackfillSignal\n }) => {\n const { adapter, assetRepo } = await studio()\n // Reads (list) + the variant patch (upsert) go through the operations facade;\n // bytes ride on `adapter.blobs`. The backfill is per-variant (EC-420 AD-4):\n // one fetch of each original fills whichever of thumb/lqip is missing. Each\n // generated record is patched into the shared cache in place (EC-301 perf,\n // AD-17) so the grid updates live without a full re-list.\n return runVariantBackfill(\n {\n assets: assetRepo,\n blobs: adapter.blobs,\n onGenerated: (updated) =>\n cache.patch<AssetRecord[]>(assetsQueryKey(projectId), (prev) =>\n (prev ?? []).map((a) => (a.id === updated.id ? updated : a)),\n ),\n ...(handlers?.onProgress ? { onProgress: handlers.onProgress } : {}),\n ...(handlers?.signal ? { signal: handlers.signal } : {}),\n },\n projectId,\n )\n },\n [studio, projectId, cache],\n )\n\n const store = useMemo<AssetsStore>(\n () => ({\n projectId,\n status,\n ...(errorMessage !== undefined ? { errorMessage } : {}),\n assets,\n uploads,\n upload,\n landedAssetId,\n retryUpload,\n dismissUpload,\n usagesOf,\n remove,\n updateMetadata,\n replaceFile,\n generatePreviews,\n refresh,\n }),\n [\n projectId,\n status,\n errorMessage,\n assets,\n uploads,\n upload,\n landedAssetId,\n retryUpload,\n dismissUpload,\n usagesOf,\n remove,\n updateMetadata,\n replaceFile,\n generatePreviews,\n refresh,\n ],\n )\n\n return <AssetsContext.Provider value={store}>{children}</AssetsContext.Provider>\n}\n\nexport { useAssets }\n\n/**\n * The assets store when an `<AssetsProvider>` is mounted above, else `null`.\n * Lets surfaces outside the Assets section (the CMS asset picker, EC-152)\n * reuse an ambient provider or mount their own.\n */\nexport function useOptionalAssets(): AssetsStore | null {\n return useContext(AssetsContext)\n}\n"]}
1
+ {"version":3,"file":"assets-store.js","sourceRoot":"","sources":["../../../src/components/assets/assets-store.tsx"],"names":[],"mappings":";AAAA,OAAO,EAAE,WAAW,EAAE,UAAU,EAAE,SAAS,EAAE,OAAO,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,OAAO,CAAA;AAGrF,OAAO,EAAE,WAAW,EAAE,kBAAkB,EAAE,SAAS,EAAE,kBAAkB,EAAE,MAAM,kBAAkB,CAAA;AAQjG,OAAO,EAAE,sBAAsB,EAAE,MAAM,kBAAkB,CAAA;AACzD,OAAO,EAAE,8BAA8B,EAAE,MAAM,sBAAsB,CAAA;AAErE,OAAO,EAAE,mBAAmB,EAAE,yBAAyB,EAAE,MAAM,sBAAsB,CAAA;AACrF,OAAO,EAAE,kBAAkB,EAAE,mBAAmB,EAAE,MAAM,6CAA6C,CAAA;AAErG,OAAO,EAAE,cAAc,EAAE,iBAAiB,EAAE,iBAAiB,EAAE,MAAM,iBAAiB,CAAA;AACtF,OAAO,EAAE,qBAAqB,EAAE,MAAM,4BAA4B,CAAA;AAClE,OAAO,EAAE,mBAAmB,EAAE,MAAM,kBAAkB,CAAA;AAoEtD,MAAM,EAAE,OAAO,EAAE,aAAa,EAAE,WAAW,EAAE,SAAS,EAAE,GAAG,qBAAqB,CAC9E,QAAQ,EACR,EAAE,OAAO,EAAE,IAAI,EAAE,CAClB,CAAA;AAED,MAAM,YAAY,GAA2B,EAAE,CAAA;AAE/C,qFAAqF;AACrF,SAAS,cAAc,CAAC,SAAiB;IACvC,OAAO,CAAC,QAAQ,EAAE,SAAS,CAAC,CAAA;AAC9B,CAAC;AAED;kEACkE;AAClE,KAAK,UAAU,UAAU,CAAC,UAA4B,EAAE,SAAiB;IACvE,MAAM,MAAM,GAAG,MAAM,UAAU,CAAC,MAAM,CAAC,IAAI,CAAC,EAAE,SAAS,EAAE,CAAC,CAAA;IAC1D,IAAI,CAAC,MAAM,CAAC,EAAE;QAAE,MAAM,IAAI,KAAK,CAAC,MAAM,CAAC,KAAK,CAAC,OAAO,CAAC,CAAA;IACrD,OAAO,CAAC,GAAG,MAAM,CAAC,KAAK,CAAC,CAAA;AAC1B,CAAC;AAED,MAAM,UAAU,cAAc,CAAC,EAC7B,SAAS,EACT,QAAQ,GAIT;IACC,MAAM,cAAc,GAAG,MAAM,CAAC,IAAI,GAAG,EAA0B,CAAC,CAAA;IAChE,oFAAoF;IACpF,kFAAkF;IAClF,MAAM,SAAS,GAAG,MAAM,CAAC,IAAI,GAAG,EAAkB,CAAC,CAAA;IACnD,MAAM,SAAS,GAAG,MAAM,CAAC,CAAC,CAAC,CAAA;IAC3B,MAAM,CAAC,OAAO,EAAE,UAAU,CAAC,GAAG,QAAQ,CAAyB,EAAE,CAAC,CAAA;IAElE,mFAAmF;IACnF,kFAAkF;IAClF,MAAM,WAAW,GAAG,OAAO,CACzB,GAAG,EAAE,CAAC,kBAAkB,CAAC,SAAS,CAAC,CAAC,IAAI,CAAC,CAAC,UAAU,EAAE,EAAE,CAAC,UAAU,CAAC,IAAI,KAAK,OAAO,CAAC,EAAE,MAAM,EAC7F,CAAC,SAAS,CAAC,CACZ,CAAA;IACD,iFAAiF;IACjF,4EAA4E;IAC5E,MAAM,OAAO,GAAG,OAAO,CAAC,GAAG,EAAE,CAAC,mBAAmB,CAAC,SAAS,CAAC,EAAE,CAAC,SAAS,CAAC,CAAC,CAAA;IAC1E,qFAAqF;IACrF,2FAA2F;IAC3F,sDAAsD;IACtD,SAAS,CAAC,GAAG,EAAE;QACb,IAAI,OAAO;YAAE,sBAAsB,CAAC,OAAO,CAAC,CAAA;IAC9C,CAAC,EAAE,CAAC,OAAO,CAAC,CAAC,CAAA;IAEb,+EAA+E;IAC/E,MAAM,MAAM,GAAG,WAAW,CAAC,KAAK,IAE9B,EAAE;QACF,MAAM,MAAM,GAAG,MAAM,mBAAmB,EAAE,CAAA;QAC1C,OAAO,EAAE,GAAG,MAAM,EAAE,SAAS,EAAE,yBAAyB,CAAC,MAAM,CAAC,UAAU,CAAC,EAAE,CAAA;IAC/E,CAAC,EAAE,EAAE,CAAC,CAAA;IAEN,uEAAuE;IACvE,6EAA6E;IAC7E,8EAA8E;IAC9E,4EAA4E;IAC5E,MAAM,KAAK,GAAG,iBAAiB,CAAgB;QAC7C,QAAQ,EAAE,cAAc,CAAC,SAAS,CAAC;QACnC,MAAM,EAAE,CAAC,UAAU,EAAE,EAAE,CAAC,UAAU,CAAC,UAAU,EAAE,SAAS,CAAC;KAC1D,CAAC,CAAA;IACF,MAAM,KAAK,GAAG,iBAAiB,EAAE,CAAA;IACjC,MAAM,OAAO,GAAG,KAAK,CAAC,OAAO,CAAA;IAC7B,MAAM,MAAM,GAAG,KAAK,CAAC,IAAI,IAAI,YAAY,CAAA;IACzC,MAAM,EAAE,MAAM,EAAE,YAAY,EAAE,GAAG,cAAc,CAAC,KAAK,CAAC,CAAA;IAEtD,kFAAkF;IAClF,MAAM,OAAO,GAAG,WAAW,CAAC,KAAK,IAAI,EAAE;QACrC,MAAM,OAAO,EAAE,CAAA;IACjB,CAAC,EAAE,CAAC,OAAO,CAAC,CAAC,CAAA;IAEb,MAAM,cAAc,GAAG,WAAW,CAAC,CAAC,QAAgB,EAAE,KAAkB,EAAE,EAAE;QAC1E,UAAU,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,EAAE,KAAK,QAAQ,CAAC,CAAC,CAAC,EAAE,GAAG,CAAC,EAAE,KAAK,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAA;IAClF,CAAC,EAAE,EAAE,CAAC,CAAA;IAEN,MAAM,QAAQ,GAAG,WAAW,CAC1B,KAAK,EAAE,QAAgB,EAAE,IAAoB,EAAE,QAAsB,EAAE,EAAE;QACvE,MAAM,EAAE,OAAO,EAAE,SAAS,EAAE,GAAG,MAAM,MAAM,EAAE,CAAA;QAC7C,MAAM,MAAM,GAAG,MAAM,SAAS,CAC5B;YACE,iEAAiE;YACjE,2DAA2D;YAC3D,KAAK,EAAE,OAAO,CAAC,KAAK;YACpB,MAAM,EAAE,SAAS;YACjB,GAAG,CAAC,WAAW,CAAC,CAAC,CAAC,EAAE,WAAW,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;YACvC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,OAAO,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;YAC/B,GAAG,CAAC,OAAO,cAAc,KAAK,WAAW,CAAC,CAAC,CAAC,EAAE,SAAS,EAAE,kBAAkB,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;SACpF,EACD;YACE,SAAS;YACT,IAAI;YACJ,OAAO,EAAE,CAAC,KAAK,EAAE,EAAE,CAAC,cAAc,CAAC,QAAQ,EAAE,KAAK,CAAC;SACpD,EACD,QAAQ,CACT,CAAA;QACD,IAAI,MAAM,CAAC,EAAE,EAAE,CAAC;YACd,uEAAuE;YACvE,SAAS,CAAC,OAAO,CAAC,GAAG,CAAC,QAAQ,EAAE,MAAM,CAAC,KAAK,CAAC,EAAE,CAAC,CAAA;YAChD,cAAc,CAAC,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAA;YACvC,UAAU,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,EAAE,KAAK,QAAQ,CAAC,CAAC,CAAA;YAC3D,MAAM,OAAO,EAAE,CAAA;QACjB,CAAC;IACH,CAAC,EACD,CAAC,MAAM,EAAE,SAAS,EAAE,OAAO,EAAE,cAAc,EAAE,WAAW,EAAE,OAAO,CAAC,CACnE,CAAA;IAED,MAAM,MAAM,GAAG,WAAW,CACxB,CAAC,KAA+B,EAAqB,EAAE;QACrD,MAAM,GAAG,GAAa,EAAE,CAAA;QACxB,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;YACzB,SAAS,CAAC,OAAO,IAAI,CAAC,CAAA;YACtB,MAAM,QAAQ,GAAG,UAAU,SAAS,CAAC,OAAO,EAAE,CAAA;YAC9C,GAAG,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAA;YAClB,cAAc,CAAC,OAAO,CAAC,GAAG,CAAC,QAAQ,EAAE,IAAI,CAAC,CAAA;YAC1C,UAAU,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC;gBACnB,GAAG,IAAI;gBACP,EAAE,EAAE,EAAE,QAAQ,EAAE,QAAQ,EAAE,IAAI,CAAC,IAAI,EAAE,KAAK,EAAE,EAAE,KAAK,EAAE,MAAM,EAAE,QAAQ,EAAE,CAAC,EAAE,OAAO,EAAE,CAAC,EAAE,EAAE;aACzF,CAAC,CAAA;YACF,KAAK,QAAQ,CAAC,QAAQ,EAAE,IAAI,CAAC,CAAA;QAC/B,CAAC;QACD,OAAO,GAAG,CAAA;IACZ,CAAC,EACD,CAAC,QAAQ,CAAC,CACX,CAAA;IAED,MAAM,aAAa,GAAG,WAAW,CAAC,CAAC,QAAgB,EAAE,EAAE,CAAC,SAAS,CAAC,OAAO,CAAC,GAAG,CAAC,QAAQ,CAAC,EAAE,EAAE,CAAC,CAAA;IAE5F,MAAM,WAAW,GAAG,WAAW,CAC7B,CAAC,QAAgB,EAAE,EAAE;QACnB,MAAM,IAAI,GAAG,cAAc,CAAC,OAAO,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAA;QACjD,MAAM,KAAK,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,EAAE,KAAK,QAAQ,CAAC,CAAA;QACpD,IAAI,CAAC,IAAI,IAAI,CAAC,KAAK,IAAI,KAAK,CAAC,KAAK,CAAC,KAAK,KAAK,QAAQ;YAAE,OAAM;QAC7D,KAAK,QAAQ,CAAC,QAAQ,EAAE,IAAI,EAAE,KAAK,CAAC,KAAK,CAAC,CAAA;IAC5C,CAAC,EACD,CAAC,QAAQ,EAAE,OAAO,CAAC,CACpB,CAAA;IAED,MAAM,aAAa,GAAG,WAAW,CAAC,CAAC,QAAgB,EAAE,EAAE;QACrD,cAAc,CAAC,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAA;QACvC,UAAU,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,EAAE,KAAK,QAAQ,CAAC,CAAC,CAAA;IAC7D,CAAC,EAAE,EAAE,CAAC,CAAA;IAEN,MAAM,QAAQ,GAAG,WAAW;IAC1B,4EAA4E;IAC5E,qEAAqE;IACrE,KAAK,EAAE,OAAe,EAAE,EAAE,CAAC,8BAA8B,CAAC,SAAS,EAAE,OAAO,CAAC,EAC7E,CAAC,SAAS,CAAC,CACZ,CAAA;IAED,MAAM,MAAM,GAAG,WAAW,CACxB,KAAK,EAAE,OAAe,EAAE,OAAoC,EAAE,EAAE;QAC9D,MAAM,EAAE,OAAO,EAAE,SAAS,EAAE,GAAG,MAAM,MAAM,EAAE,CAAA;QAC7C,qEAAqE;QACrE,yEAAyE;QACzE,6DAA6D;QAC7D,MAAM,MAAM,GAAG,MAAM,WAAW,CAC9B,EAAE,MAAM,EAAE,SAAS,EAAE,KAAK,EAAE,OAAO,CAAC,KAAK,EAAE,UAAU,EAAE,OAAO,CAAC,UAAU,EAAE,EAC3E,SAAS,EACT,OAAO,EACP,OAAO,CACR,CAAA;QACD,8EAA8E;QAC9E,mFAAmF;QACnF,0DAA0D;QAC1D,IAAI,MAAM,CAAC,OAAO,KAAK,SAAS,IAAI,MAAM,CAAC,OAAO,KAAK,WAAW,EAAE,CAAC;YACnE,KAAK,CAAC,KAAK,CAAgB,cAAc,CAAC,SAAS,CAAC,EAAE,CAAC,IAAI,EAAE,EAAE,CAC7D,CAAC,IAAI,IAAI,EAAE,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,EAAE,KAAK,OAAO,CAAC,CAC7C,CAAA;QACH,CAAC;QACD,OAAO,MAAM,CAAA;IACf,CAAC,EACD,CAAC,MAAM,EAAE,SAAS,EAAE,KAAK,CAAC,CAC3B,CAAA;IAED,MAAM,cAAc,GAAG,WAAW,CAChC,KAAK,EAAE,OAAe,EAAE,KAAyB,EAAE,EAAE;QACnD,iEAAiE;QACjE,+DAA+D;QAC/D,MAAM,EAAE,SAAS,EAAE,GAAG,MAAM,MAAM,EAAE,CAAA;QACpC,MAAM,MAAM,GAAG,MAAM,mBAAmB,CAAC,EAAE,MAAM,EAAE,SAAS,EAAE,EAAE,SAAS,EAAE,OAAO,EAAE,KAAK,CAAC,CAAA;QAC1F,IAAI,MAAM,CAAC,EAAE,EAAE,CAAC;YACd,yEAAyE;YACzE,4EAA4E;YAC5E,4EAA4E;YAC5E,iEAAiE;YACjE,MAAM,OAAO,GAAG,MAAM,CAAC,KAAK,CAAA;YAC5B,KAAK,CAAC,KAAK,CAAgB,cAAc,CAAC,SAAS,CAAC,EAAE,CAAC,IAAI,EAAE,EAAE,CAC7D,CAAC,IAAI,IAAI,EAAE,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,EAAE,KAAK,OAAO,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAC1D,CAAA;QACH,CAAC;QACD,OAAO,MAAM,CAAA;IACf,CAAC,EACD,CAAC,MAAM,EAAE,SAAS,EAAE,KAAK,CAAC,CAC3B,CAAA;IAED,MAAM,WAAW,GAAG,WAAW,CAC7B,KAAK,EAAE,OAAe,EAAE,IAAoB,EAA8B,EAAE;QAC1E,MAAM,EAAE,OAAO,EAAE,SAAS,EAAE,GAAG,MAAM,MAAM,EAAE,CAAA;QAC7C,oEAAoE;QACpE,MAAM,MAAM,GAAG,MAAM,SAAS,CAC5B;YACE,KAAK,EAAE,OAAO,CAAC,KAAK;YACpB,MAAM,EAAE,SAAS;YACjB,GAAG,CAAC,WAAW,CAAC,CAAC,CAAC,EAAE,WAAW,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;YACvC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,OAAO,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;YAC/B,GAAG,CAAC,OAAO,cAAc,KAAK,WAAW,CAAC,CAAC,CAAC,EAAE,SAAS,EAAE,kBAAkB,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;SACpF,EACD,EAAE,SAAS,EAAE,IAAI,EAAE,OAAO,EAAE,EAAE,OAAO,EAAE,EAAE,CAC1C,CAAA;QACD,IAAI,CAAC,MAAM,CAAC,EAAE;YAAE,OAAO,EAAE,EAAE,EAAE,KAAK,EAAE,OAAO,EAAE,MAAM,CAAC,OAAO,CAAC,OAAO,EAAE,CAAA;QACrE,MAAM,OAAO,GAAG,MAAM,CAAC,KAAK,CAAA;QAC5B,KAAK,CAAC,KAAK,CAAgB,cAAc,CAAC,SAAS,CAAC,EAAE,CAAC,IAAI,EAAE,EAAE,CAC7D,CAAC,IAAI,IAAI,EAAE,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,EAAE,KAAK,OAAO,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAC1D,CAAA;QACD,OAAO,EAAE,EAAE,EAAE,IAAI,EAAE,KAAK,EAAE,OAAO,EAAE,CAAA;IACrC,CAAC,EACD,CAAC,MAAM,EAAE,SAAS,EAAE,KAAK,EAAE,WAAW,EAAE,OAAO,CAAC,CACjD,CAAA;IAED,MAAM,gBAAgB,GAAG,WAAW,CAClC,KAAK,EAAE,QAGN,EAAE,EAAE;QACH,MAAM,EAAE,OAAO,EAAE,SAAS,EAAE,GAAG,MAAM,MAAM,EAAE,CAAA;QAC7C,8EAA8E;QAC9E,4EAA4E;QAC5E,4EAA4E;QAC5E,2EAA2E;QAC3E,0DAA0D;QAC1D,OAAO,kBAAkB,CACvB;YACE,MAAM,EAAE,SAAS;YACjB,KAAK,EAAE,OAAO,CAAC,KAAK;YACpB,WAAW,EAAE,CAAC,OAAO,EAAE,EAAE,CACvB,KAAK,CAAC,KAAK,CAAgB,cAAc,CAAC,SAAS,CAAC,EAAE,CAAC,IAAI,EAAE,EAAE,CAC7D,CAAC,IAAI,IAAI,EAAE,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,EAAE,KAAK,OAAO,CAAC,EAAE,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAC7D;YACH,GAAG,CAAC,QAAQ,EAAE,UAAU,CAAC,CAAC,CAAC,EAAE,UAAU,EAAE,QAAQ,CAAC,UAAU,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;YACpE,GAAG,CAAC,QAAQ,EAAE,MAAM,CAAC,CAAC,CAAC,EAAE,MAAM,EAAE,QAAQ,CAAC,MAAM,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;SACzD,EACD,SAAS,CACV,CAAA;IACH,CAAC,EACD,CAAC,MAAM,EAAE,SAAS,EAAE,KAAK,CAAC,CAC3B,CAAA;IAED,MAAM,KAAK,GAAG,OAAO,CACnB,GAAG,EAAE,CAAC,CAAC;QACL,SAAS;QACT,MAAM;QACN,GAAG,CAAC,YAAY,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,YAAY,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;QACvD,MAAM;QACN,OAAO;QACP,MAAM;QACN,aAAa;QACb,WAAW;QACX,aAAa;QACb,QAAQ;QACR,MAAM;QACN,cAAc;QACd,WAAW;QACX,gBAAgB;QAChB,OAAO;KACR,CAAC,EACF;QACE,SAAS;QACT,MAAM;QACN,YAAY;QACZ,MAAM;QACN,OAAO;QACP,MAAM;QACN,aAAa;QACb,WAAW;QACX,aAAa;QACb,QAAQ;QACR,MAAM;QACN,cAAc;QACd,WAAW;QACX,gBAAgB;QAChB,OAAO;KACR,CACF,CAAA;IAED,OAAO,KAAC,aAAa,CAAC,QAAQ,IAAC,KAAK,EAAE,KAAK,YAAG,QAAQ,GAA0B,CAAA;AAClF,CAAC;AAED,OAAO,EAAE,SAAS,EAAE,CAAA;AAEpB;;;;GAIG;AACH,MAAM,UAAU,iBAAiB;IAC/B,OAAO,UAAU,CAAC,aAAa,CAAC,CAAA;AAClC,CAAC","sourcesContent":["import { useCallback, useContext, useEffect, useMemo, useRef, useState } from 'react'\nimport type { ReactNode } from 'react'\nimport type { AssetRecord, AssetRepository } from '@elytracms/core/persistence'\nimport { deleteAsset, runVariantBackfill, runUpload, xhrUploadTransport } from '../../lib/assets'\nimport type {\n BackfillProgress,\n BackfillSignal,\n DeleteAssetResult,\n UploadState,\n UploadableFile,\n} from '../../lib/assets'\nimport { configureStudioLocales } from '../../lib/locale'\nimport { loadInboundAssetReferenceViews } from '../../lib/references'\nimport type { ReferenceEntryView } from '../../lib/references'\nimport { getStudioOperations, operationsAssetRepository } from '../../lib/operations'\nimport { projectCollections, projectLocaleConfig } from '../../lib/operations/project-runtime-config'\nimport type { OperationsClient, StudioOperations } from '../../lib/operations'\nimport { listStoreState, useOperationCache, useOperationQuery } from '../../lib/query'\nimport { createRequiredContext } from '../../lib/required-context'\nimport { updateAssetMetadata } from './asset-metadata'\nimport type { AssetMetadataPatch, UpdateAssetMetadataResult } from './asset-metadata'\n\n/**\n * Asset library store (EC-151, EC-141). Asset *metadata* mutations go through\n * the shared operations client (`assets.*` commands — validate → authorize →\n * mutate → event); blob *bytes* ride on `adapter.blobs`, which is transport,\n * not domain. The UI works identically against the in-memory seed and a live\n * Convex deployment.\n */\n\nexport interface UploadEntry {\n id: string\n filename: string\n state: UploadState\n}\n\nexport interface AssetsStore {\n /** The active project (e.g. for reference deep links, EC-202). */\n projectId: string\n status: 'loading' | 'ready' | 'error'\n errorMessage?: string\n assets: readonly AssetRecord[]\n uploads: readonly UploadEntry[]\n /**\n * Queue files for upload. Returns the upload-queue id of each file, in order, so a\n * caller can follow exactly ITS uploads (EC-588 A7) — see {@link landedAssetId}.\n */\n upload(files: Iterable<UploadableFile>): readonly string[]\n /**\n * The asset id an upload landed as, once its record is confirmed (EC-588 A7);\n * `undefined` while it runs, after it failed, or for an id this store never issued.\n * A completed upload leaves the queue, so this is where its outcome stays readable.\n */\n landedAssetId(uploadId: string): string | undefined\n retryUpload(uploadId: string): void\n dismissUpload(uploadId: string): void\n /**\n * Index-accurate inbound references of an asset (EC-202): the \"used by\"\n * pre-flight of the block-or-confirm delete dialog, read from the EC-155\n * reference index (not the retired string scan).\n */\n usagesOf(assetId: string): Promise<ReferenceEntryView[]>\n remove(assetId: string, options?: { confirmInUse?: boolean }): Promise<DeleteAssetResult>\n /** Edit alt/title (EC-152); persists through the operations asset facade. */\n updateMetadata(assetId: string, patch: AssetMetadataPatch): Promise<UpdateAssetMetadataResult>\n /**\n * EC-568 — replace the file inside an asset: the same id, the new bytes, everything\n * derived regenerated through THE upload path, the file's embedded metadata over\n * `meta` per key (else kept), the focal point kept.\n */\n replaceFile(assetId: string, file: UploadableFile): Promise<ReplaceFileResult>\n /**\n * Backfill downscaled previews onto existing images (EC-400 AD-1). Sequential,\n * idempotent, cancellable; each patch flows through the operations facade and\n * the shared query cache (AD-5/AD-17). Reports progress via `handlers.onProgress`\n * and stops when `handlers.signal.cancelled` flips.\n */\n generatePreviews(handlers?: {\n onProgress?: (progress: BackfillProgress) => void\n signal?: BackfillSignal\n }): Promise<BackfillProgress>\n refresh(): Promise<void>\n}\n\n/** The outcome of {@link AssetsStore.replaceFile}. */\nexport type ReplaceFileResult = { ok: true; asset: AssetRecord } | { ok: false; message: string }\n\nconst { Context: AssetsContext, useRequired: useAssets } = createRequiredContext<AssetsStore>(\n 'Assets',\n { article: 'an' },\n)\n\nconst EMPTY_ASSETS: readonly AssetRecord[] = []\n\n/** Cache key for a project's asset library (shared by the query and its patches). */\nfunction assetsQueryKey(projectId: string): readonly [string, string] {\n return ['assets', projectId]\n}\n\n/** Load a project's asset library (pure over the operations client). A list\n * failure throws so the query surfaces it as an error status. */\nasync function loadAssets(operations: OperationsClient, projectId: string): Promise<AssetRecord[]> {\n const result = await operations.assets.list({ projectId })\n if (!result.ok) throw new Error(result.error.message)\n return [...result.value]\n}\n\nexport function AssetsProvider({\n projectId,\n children,\n}: {\n projectId: string\n children: ReactNode\n}) {\n const uploadFilesRef = useRef(new Map<string, UploadableFile>())\n // EC-588 A7: upload id → the asset id it landed as. Written BEFORE the entry leaves\n // the queue, so a reader never sees an upload that is neither running nor landed.\n const landedRef = useRef(new Map<string, string>())\n const uploadSeq = useRef(0)\n const [uploads, setUploads] = useState<readonly UploadEntry[]>([])\n\n // EC-568: the asset collection's fields — their `source` declarations map a file's\n // embedded IPTC facts onto `meta` on every upload and replace. Config, read once.\n const assetFields = useMemo(\n () => projectCollections(projectId).find((collection) => collection.kind === 'asset')?.fields,\n [projectId],\n )\n // EC-632: the project's locales — a localized asset field's embedded values (XMP\n // `xml:lang` alternatives) land in their locale buckets. Config, read once.\n const locales = useMemo(() => projectLocaleConfig(projectId), [projectId])\n // EC-632: the asset surfaces read and edit a localized field in the studio's ambient\n // locale — install the project's locales (idempotent, as the CMS store does), so the asset\n // library opened before any CMS surface has them too.\n useEffect(() => {\n if (locales) configureStudioLocales(locales)\n }, [locales])\n\n /** The shared studio operations bundle + the metadata-write facade over it. */\n const studio = useCallback(async (): Promise<\n StudioOperations & { assetRepo: AssetRepository }\n > => {\n const bundle = await getStudioOperations()\n return { ...bundle, assetRepo: operationsAssetRepository(bundle.operations) }\n }, [])\n\n // The library list, read through the one operations-backed query cache\n // (EC-308/AD-17). No `invalidateOn`: this provider is the sole writer of its\n // project's assets, so its own mutations patch the cache in place (the EC-301\n // rule — a metadata or focal-point edit must never trigger a full re-list).\n const query = useOperationQuery<AssetRecord[]>({\n queryKey: assetsQueryKey(projectId),\n loader: (operations) => loadAssets(operations, projectId),\n })\n const cache = useOperationCache()\n const refetch = query.refetch\n const assets = query.data ?? EMPTY_ASSETS\n const { status, errorMessage } = listStoreState(query)\n\n /** Re-list from the backend (the public escape hatch + post-upload reconcile). */\n const refresh = useCallback(async () => {\n await refetch()\n }, [refetch])\n\n const setUploadState = useCallback((uploadId: string, state: UploadState) => {\n setUploads((prev) => prev.map((u) => (u.id === uploadId ? { ...u, state } : u)))\n }, [])\n\n const runEntry = useCallback(\n async (uploadId: string, file: UploadableFile, previous?: UploadState) => {\n const { adapter, assetRepo } = await studio()\n const result = await runUpload(\n {\n // Bytes ride on blob storage (transport); the metadata record is\n // confirmed through the `assets.upsert` operation command.\n blobs: adapter.blobs,\n assets: assetRepo,\n ...(assetFields ? { assetFields } : {}),\n ...(locales ? { locales } : {}),\n ...(typeof XMLHttpRequest !== 'undefined' ? { transport: xhrUploadTransport } : {}),\n },\n {\n projectId,\n file,\n onState: (state) => setUploadState(uploadId, state),\n },\n previous,\n )\n if (result.ok) {\n // Completed uploads leave the queue; the asset appears in the library.\n landedRef.current.set(uploadId, result.asset.id)\n uploadFilesRef.current.delete(uploadId)\n setUploads((prev) => prev.filter((u) => u.id !== uploadId))\n await refresh()\n }\n },\n [studio, projectId, refresh, setUploadState, assetFields, locales],\n )\n\n const upload = useCallback(\n (files: Iterable<UploadableFile>): readonly string[] => {\n const ids: string[] = []\n for (const file of files) {\n uploadSeq.current += 1\n const uploadId = `upload-${uploadSeq.current}`\n ids.push(uploadId)\n uploadFilesRef.current.set(uploadId, file)\n setUploads((prev) => [\n ...prev,\n { id: uploadId, filename: file.name, state: { phase: 'idle', progress: 0, attempt: 0 } },\n ])\n void runEntry(uploadId, file)\n }\n return ids\n },\n [runEntry],\n )\n\n const landedAssetId = useCallback((uploadId: string) => landedRef.current.get(uploadId), [])\n\n const retryUpload = useCallback(\n (uploadId: string) => {\n const file = uploadFilesRef.current.get(uploadId)\n const entry = uploads.find((u) => u.id === uploadId)\n if (!file || !entry || entry.state.phase !== 'failed') return\n void runEntry(uploadId, file, entry.state)\n },\n [runEntry, uploads],\n )\n\n const dismissUpload = useCallback((uploadId: string) => {\n uploadFilesRef.current.delete(uploadId)\n setUploads((prev) => prev.filter((u) => u.id !== uploadId))\n }, [])\n\n const usagesOf = useCallback(\n // Index-accurate (EC-202): inbound references from the EC-155 index via the\n // operations queries — the same machinery the References panel uses.\n async (assetId: string) => loadInboundAssetReferenceViews(projectId, assetId),\n [projectId],\n )\n\n const remove = useCallback(\n async (assetId: string, options?: { confirmInUse?: boolean }) => {\n const { adapter, assetRepo } = await studio()\n // Metadata removal goes through the `assets.remove` command (via the\n // facade); blob byte deletion stays on the adapter; the usage gate reads\n // the EC-155 reference index (`adapter.references`, EC-202).\n const result = await deleteAsset(\n { assets: assetRepo, blobs: adapter.blobs, references: adapter.references },\n projectId,\n assetId,\n options,\n )\n // Drop the one removed record from the cache rather than re-listing the whole\n // library (EC-301 perf, mirrors updateMetadata) — a delete must not trigger a full\n // `assets.list` round-trip on top of the deletion itself.\n if (result.outcome === 'deleted' || result.outcome === 'not-found') {\n cache.patch<AssetRecord[]>(assetsQueryKey(projectId), (prev) =>\n (prev ?? []).filter((a) => a.id !== assetId),\n )\n }\n return result\n },\n [studio, projectId, cache],\n )\n\n const updateMetadata = useCallback(\n async (assetId: string, patch: AssetMetadataPatch) => {\n // Metadata writes go through the `assets.upsert` command via the\n // operations facade (EC-141) — never straight at a repository.\n const { assetRepo } = await studio()\n const result = await updateAssetMetadata({ assets: assetRepo }, projectId, assetId, patch)\n if (result.ok) {\n // Patch the one updated record into the cache rather than re-listing the\n // whole library (EC-301). A focal-point or alt edit must not trigger a full\n // `assets.list` round-trip — that re-list (plus the marker only moving once\n // it returned) was the focal-point picker's lag and query storm.\n const updated = result.asset\n cache.patch<AssetRecord[]>(assetsQueryKey(projectId), (prev) =>\n (prev ?? []).map((a) => (a.id === assetId ? updated : a)),\n )\n }\n return result\n },\n [studio, projectId, cache],\n )\n\n const replaceFile = useCallback(\n async (assetId: string, file: UploadableFile): Promise<ReplaceFileResult> => {\n const { adapter, assetRepo } = await studio()\n // EC-568: THE upload path, in replace mode — not a second uploader.\n const result = await runUpload(\n {\n blobs: adapter.blobs,\n assets: assetRepo,\n ...(assetFields ? { assetFields } : {}),\n ...(locales ? { locales } : {}),\n ...(typeof XMLHttpRequest !== 'undefined' ? { transport: xhrUploadTransport } : {}),\n },\n { projectId, file, replace: { assetId } },\n )\n if (!result.ok) return { ok: false, message: result.failure.message }\n const updated = result.asset\n cache.patch<AssetRecord[]>(assetsQueryKey(projectId), (prev) =>\n (prev ?? []).map((a) => (a.id === assetId ? updated : a)),\n )\n return { ok: true, asset: updated }\n },\n [studio, projectId, cache, assetFields, locales],\n )\n\n const generatePreviews = useCallback(\n async (handlers?: {\n onProgress?: (progress: BackfillProgress) => void\n signal?: BackfillSignal\n }) => {\n const { adapter, assetRepo } = await studio()\n // Reads (list) + the variant patch (upsert) go through the operations facade;\n // bytes ride on `adapter.blobs`. The backfill is per-variant (EC-420 AD-4):\n // one fetch of each original fills whichever of thumb/lqip is missing. Each\n // generated record is patched into the shared cache in place (EC-301 perf,\n // AD-17) so the grid updates live without a full re-list.\n return runVariantBackfill(\n {\n assets: assetRepo,\n blobs: adapter.blobs,\n onGenerated: (updated) =>\n cache.patch<AssetRecord[]>(assetsQueryKey(projectId), (prev) =>\n (prev ?? []).map((a) => (a.id === updated.id ? updated : a)),\n ),\n ...(handlers?.onProgress ? { onProgress: handlers.onProgress } : {}),\n ...(handlers?.signal ? { signal: handlers.signal } : {}),\n },\n projectId,\n )\n },\n [studio, projectId, cache],\n )\n\n const store = useMemo<AssetsStore>(\n () => ({\n projectId,\n status,\n ...(errorMessage !== undefined ? { errorMessage } : {}),\n assets,\n uploads,\n upload,\n landedAssetId,\n retryUpload,\n dismissUpload,\n usagesOf,\n remove,\n updateMetadata,\n replaceFile,\n generatePreviews,\n refresh,\n }),\n [\n projectId,\n status,\n errorMessage,\n assets,\n uploads,\n upload,\n landedAssetId,\n retryUpload,\n dismissUpload,\n usagesOf,\n remove,\n updateMetadata,\n replaceFile,\n generatePreviews,\n refresh,\n ],\n )\n\n return <AssetsContext.Provider value={store}>{children}</AssetsContext.Provider>\n}\n\nexport { useAssets }\n\n/**\n * The assets store when an `<AssetsProvider>` is mounted above, else `null`.\n * Lets surfaces outside the Assets section (the CMS asset picker, EC-152)\n * reuse an ambient provider or mount their own.\n */\nexport function useOptionalAssets(): AssetsStore | null {\n return useContext(AssetsContext)\n}\n"]}
@@ -122,6 +122,18 @@ export type BuilderAction = {
122
122
  run: number;
123
123
  content: readonly unknown[];
124
124
  coalesceKey?: string;
125
+ }
126
+ /**
127
+ * EC-630 — the field's value changed UNDERNEATH the canvas (a colleague's patch by
128
+ * subscription, a write's canonical row, a resolved conflict), from `from` to `to` (the
129
+ * draft's values before and after): the present absorbs the change and the history and
130
+ * selection rebase onto it (`canvas-rebase.ts`) — never a remount. Not an edit: it adds
131
+ * no history entry, and the canvas writes nothing for it.
132
+ */
133
+ | {
134
+ type: 'rebase';
135
+ from: unknown;
136
+ to: unknown;
125
137
  };
126
138
  /** The structural actions the placement judge rules on (EC-584): every node that enters or moves. */
127
139
  export type PlacingAction = Extract<BuilderAction, {
@@ -186,6 +198,12 @@ export interface BuilderState {
186
198
  * action changes no tree, so it adds no history entry and emits no canvas patch.
187
199
  */
188
200
  refusal: PlacementRefusal | null;
201
+ /**
202
+ * EC-630 — how many `rebase` actions the store has applied (external changes of its
203
+ * field). The canvas sync reads it to tell a store value from before a rebase it
204
+ * dispatched from one after it (`createCanvasSync`).
205
+ */
206
+ rebased: number;
189
207
  }
190
208
  type Action = BuilderAction;
191
209
  /**
@@ -251,6 +269,9 @@ preserved?: readonly PreservedItem[]): BuilderState;
251
269
  * persistence layer: it is a pure in-memory editor. The block-field editor lifts
252
270
  * its committed composition into the open CMS document via `onChange`
253
271
  * (`composition-field-editor`); the document's own Save persists it as content.
272
+ * EC-630: a change of the field made underneath the store (a colleague's patch) is
273
+ * absorbed by the present AND every snapshot (`rebase`, `canvas-rebase.ts`), so an undo
274
+ * never reverts it.
254
275
  */
255
276
  export declare function BuilderProvider({ composition, preserved, field, components, layout, idFactory, children, }: {
256
277
  /** The composition root to edit (the composition-field editor's synthetic root). */
@@ -4,6 +4,7 @@ import { DEFAULT_SLOT, cloneWithNewIds, duplicateNode, getNode, getParentInfo, g
4
4
  import { createUuidIdFactory } from '@elytracms/core/persistence';
5
5
  import { WRAP_GRID_OPTIONS, applyWrap } from '../../lib/dnd/drop-rules.js';
6
6
  import { replaceRun, runByKey } from './canvas-runs.js';
7
+ import { rebaseCanvas } from './canvas-rebase.js';
7
8
  import { createRequiredContext } from '../../lib/required-context.js';
8
9
  const HISTORY_LIMIT = 100;
9
10
  /**
@@ -137,6 +138,23 @@ function transition(state, action, placement) {
137
138
  return state;
138
139
  return restore(state, next, [...state.past, snapshotOf(state)], state.future.slice(1));
139
140
  }
141
+ case 'rebase': {
142
+ // EC-630: undo never reverts the external change — every snapshot absorbs it. The
143
+ // next edit starts a new undo step (the step it would coalesce into may have been
144
+ // dropped by the rebase, and an edit must never land in a step it cannot undo).
145
+ const rebased = rebaseCanvas(state, action.from, action.to);
146
+ // Counted even when it changes nothing: the canvas sync waits for every rebase it dispatched.
147
+ if (!rebased)
148
+ return { ...state, rebased: state.rebased + 1 };
149
+ return {
150
+ ...state,
151
+ ...rebased,
152
+ past: [...rebased.past],
153
+ future: [...rebased.future],
154
+ lastCoalesceKey: null,
155
+ rebased: state.rebased + 1,
156
+ };
157
+ }
140
158
  case 'insert': {
141
159
  const node = action.minted ? action.node : cloneWithNewIds(action.node, state.newId);
142
160
  const verdict = subtreePlacementRefusal(root, node, landingOf(action.target), placement);
@@ -279,6 +297,7 @@ preserved = []) {
279
297
  lastCoalesceKey: null,
280
298
  layout,
281
299
  refusal: null,
300
+ rebased: 0,
282
301
  };
283
302
  }
284
303
  /**
@@ -288,6 +307,9 @@ preserved = []) {
288
307
  * persistence layer: it is a pure in-memory editor. The block-field editor lifts
289
308
  * its committed composition into the open CMS document via `onChange`
290
309
  * (`composition-field-editor`); the document's own Save persists it as content.
310
+ * EC-630: a change of the field made underneath the store (a colleague's patch) is
311
+ * absorbed by the present AND every snapshot (`rebase`, `canvas-rebase.ts`), so an undo
312
+ * never reverts it.
291
313
  */
292
314
  export function BuilderProvider({ composition, preserved, field, components, layout, idFactory, children, }) {
293
315
  const [newId] = useState(() => idFactory ?? createUuidIdFactory());
@@ -1 +1 @@
1
- {"version":3,"file":"builder-store.js","sourceRoot":"","sources":["../../../src/components/builder/builder-store.tsx"],"names":[],"mappings":"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","sourcesContent":["import { useMemo, useReducer, useState } from 'react'\nimport type { ReactNode } from 'react'\nimport {\n DEFAULT_SLOT,\n cloneWithNewIds,\n duplicateNode,\n getNode,\n getParentInfo,\n gridContainerNode,\n insertNode,\n moveNode,\n normalizeContainers,\n removeNode,\n removeNodeProp,\n reorderNode,\n replaceNode,\n replacePlacementRefusal,\n setNodeProp,\n subtreePlacementRefusal,\n} from '@elytracms/core/project-graph'\nimport type {\n AllowList,\n ComponentLookup,\n ComponentNode,\n InsertTarget,\n LayoutContainerIds,\n PlacementScope,\n PlacementVerdict,\n PropValue,\n} from '@elytracms/core/project-graph'\nimport { createUuidIdFactory } from '@elytracms/core/persistence'\nimport type { IdFactory } from '@elytracms/core/persistence'\nimport { WRAP_GRID_OPTIONS, applyWrap } from '../../lib/dnd/drop-rules'\nimport { replaceRun, runByKey } from './canvas-runs'\nimport type { PreservedItem } from './canvas-runs'\nimport { createRequiredContext } from '../../lib/required-context'\n\nconst HISTORY_LIMIT = 100\n\n/**\n * A canvas preview-width key (EC-250): `'full'` (unconstrained) or a configured\n * breakpoint name (`'sm'`, `'md'`, …). Dynamic because the set is sourced from\n * the consuming site's breakpoints, so it is a string, not a fixed union — the\n * switcher resolves the available options via {@link resolveCanvasViewports}.\n */\nexport type Viewport = string\n\n/**\n * The builder store's action union. EC-287 retired the DB-resident project graph\n * and its persistence mirror, so these actions are pure in-memory editor state —\n * no action maps to a persisted `graph.*` command anymore. The block-field editor\n * lifts committed edits into the CMS document via `onChange`\n * (`composition-field-editor`); nothing persists a graph.\n */\nexport type BuilderAction =\n | { type: 'select'; id: string | null }\n | { type: 'hover'; id: string | null }\n | { type: 'viewport'; viewport: Viewport }\n | { type: 'undo' }\n | { type: 'redo' }\n /**\n * Insert a node (its subtree re-id'd from the store's id factory). `minted` — the\n * node ALREADY carries fresh ids from the same factory (the paste path mints first\n * so its issue deep links name exactly the ids that land); the reducer then inserts\n * it as given.\n */\n | { type: 'insert'; target: InsertTarget; node: ComponentNode; select?: boolean; minted?: true }\n | { type: 'remove'; id: string }\n | { type: 'duplicate'; id: string }\n | { type: 'reorder'; id: string; delta: -1 | 1 }\n | { type: 'move'; id: string; target: InsertTarget }\n /**\n * EC-282 reuse gesture: replace a node with zero or more nodes at its\n * position (clone-with-fresh-ids, like `insert`). Promote → 1 embed node;\n * detach → the referenced element's inline blocks. One atomic structural\n * edit, one undo step.\n */\n | { type: 'replace'; id: string; nodes: ComponentNode[]; select?: boolean }\n /**\n * EC-162 layout gesture: wrap the reference node and the dragged subject in\n * a two-column Grid container as ONE atomic structural edit (one undo step).\n */\n | {\n type: 'wrap'\n referenceId: string\n side: 'left' | 'right'\n subject: { kind: 'node'; nodeId: string } | { kind: 'component'; node: ComponentNode }\n }\n | { type: 'setProp'; id: string; name: string; value: PropValue; coalesceKey?: string }\n | { type: 'removeProp'; id: string; name: string }\n /** EC-584: the editor dismissed the visible refusal ({@link BuilderState.refusal}). */\n | { type: 'clearRefusal' }\n /**\n * EC-549 — select a typography RUN by its key (`canvas-runs.ts`: the index of its\n * first preserved item); `null` clears it. A run and a node are never both selected.\n */\n | { type: 'selectRun'; run: number | null }\n /** EC-549 — delete a typography run: a real, undoable edit of the preserved list. */\n | { type: 'removeRun'; run: number }\n /**\n * EC-549 — replace a run's typography with `content` (the inspector's rich-text\n * editor on that run; consecutive same-key edits coalesce into one undo step). Empty\n * `content` deletes the run.\n */\n | { type: 'setRun'; run: number; content: readonly unknown[]; coalesceKey?: string }\n\n/** The structural actions the placement judge rules on (EC-584): every node that enters or moves. */\nexport type PlacingAction = Extract<BuilderAction, { type: 'insert' | 'replace' | 'move' | 'wrap' | 'duplicate' }>\n\n/** A refused placement (EC-584): the judge's verdict and the action it refused. */\nexport interface PlacementRefusal {\n action: PlacingAction['type']\n verdict: PlacementVerdict\n}\n\n/**\n * One history entry (EC-549): the component tree AND the preserved typography — so a\n * run's deletion or edit is undone exactly like a block's.\n */\nexport interface CanvasSnapshot {\n root: ComponentNode\n preserved: readonly PreservedItem[]\n}\n\nexport interface BuilderState {\n /**\n * The edited composition: one root-bearing component tree (EC-287). The canvas\n * wraps a page document's `body` blocks into a synthetic root and edits it\n * directly — no page/layout wrapper. Undo/redo snapshot it with the preserved\n * typography ({@link CanvasSnapshot}).\n */\n past: CanvasSnapshot[]\n present: ComponentNode\n future: CanvasSnapshot[]\n /**\n * EC-549 — the field value's typography items (no ids, EC-500 D1), each anchored by\n * how many component roots preceded it (`componentPrefix`); the field value is\n * `mergeBlockRoots(present's roots, preserved)`. In the store, so selecting,\n * deleting and editing a run is a real action with truthful undo.\n */\n preserved: readonly PreservedItem[]\n selectedId: string | null\n /** EC-549 — the selected typography run's key, or `null` (exclusive with {@link selectedId}). */\n selectedRun: number | null\n hoveredId: string | null\n viewport: Viewport\n /**\n * EC-578 / EC-595 A2 — THE node-id factory (injected; UUIDs in the studio, a\n * sequential factory in fixtures). It replaced the per-session `node-<n>` counter,\n * which two sessions editing one page advanced identically — both minted the same\n * next id, a `duplicate-node-id` on the second save. Stored ids are untouched.\n */\n newId: IdFactory\n /** Coalescing key of the last edit (consecutive same-key edits don't stack history). */\n lastCoalesceKey: string | null\n /**\n * The components filling the layout roles (EC-591, `ComponentRegistry.layout`),\n * fixed for the store's lifetime: which nodes container normalization treats as\n * Stack/Grid, and the Grid the wrap gesture builds. No hardcoded engine id.\n */\n layout: LayoutContainerIds\n /**\n * EC-584 — the last REFUSED placement, with its reason: the reducer judged an\n * `insert`/`replace`/`move`/`wrap`/`duplicate` against the field and slot\n * vocabularies and canvas eligibility (the core placement judge) and left the\n * composition unchanged. Transient — the next edit, selection, undo or redo clears\n * it — and never silent: the canvas shows it (`PlacementRefusalNotice`). A refused\n * action changes no tree, so it adds no history entry and emits no canvas patch.\n */\n refusal: PlacementRefusal | null\n}\n\ntype Action = BuilderAction\n\n/**\n * Push a new graph onto history, coalescing consecutive edits with the same key.\n *\n * Every commit normalizes layout containers (EC-162 ledger fix): the\n * operations layer normalizes every persisted `graph.*` write (EC-161), so\n * the optimistic working graph must apply the same `normalizeContainers` pass\n * or the UI state diverges from the persisted revision after\n * container-emptying moves/removes. The mirrored command stays un-normalized\n * (`graphInvocationFor` sees the raw action); both sides normalize\n * identically, so they land on the same graph.\n */\nfunction commit(\n state: BuilderState,\n root: ComponentNode,\n opts: {\n coalesceKey?: string\n selectedId?: string | null\n preserved?: readonly PreservedItem[]\n selectedRun?: number | null\n } = {},\n): BuilderState {\n const normalized = normalizeContainers(root, state.layout)\n const present = normalized\n const preserved = opts.preserved ?? state.preserved\n const coalesce = opts.coalesceKey != null && opts.coalesceKey === state.lastCoalesceKey\n // Normalization can dissolve the node a caller wanted selected (e.g. the\n // parent container of a removed child) — selection never points at a ghost.\n const desired = opts.selectedId !== undefined ? opts.selectedId : state.selectedId\n const selectedId = desired !== null && getNode(normalized, desired) ? desired : null\n const desiredRun = opts.selectedRun !== undefined ? opts.selectedRun : state.selectedRun\n return {\n ...state,\n past: coalesce ? state.past : [...state.past, snapshotOf(state)].slice(-HISTORY_LIMIT),\n present,\n preserved,\n future: [],\n lastCoalesceKey: opts.coalesceKey ?? null,\n selectedId,\n selectedRun: liveRun(present, preserved, desiredRun),\n refusal: null,\n }\n}\n\nfunction snapshotOf(state: BuilderState): CanvasSnapshot {\n return { root: state.present, preserved: state.preserved }\n}\n\n/** The run key if that run still exists in this state, else `null` (never a ghost selection). */\nfunction liveRun(root: ComponentNode, preserved: readonly PreservedItem[], run: number | null): number | null {\n if (run === null) return null\n return runByKey(rootCount(root), preserved, run) ? run : null\n}\n\n/** How many component roots the composition has (the synthetic root's children). */\nfunction rootCount(root: ComponentNode): number {\n return root.slots?.[DEFAULT_SLOT]?.length ?? 0\n}\n\n/** Restore a history entry (undo/redo), keeping a selection only where it still exists. */\nfunction restore(state: BuilderState, to: CanvasSnapshot, past: CanvasSnapshot[], future: CanvasSnapshot[]): BuilderState {\n return {\n ...state,\n past,\n present: to.root,\n preserved: to.preserved,\n future,\n lastCoalesceKey: null,\n selectedId: getNode(to.root, state.selectedId ?? '') ? state.selectedId : null,\n selectedRun: liveRun(to.root, to.preserved, state.selectedRun),\n refusal: null,\n }\n}\n\n/** Leave the composition untouched and say why (EC-584 — never a silent no-op). */\nfunction refuse(state: BuilderState, action: PlacingAction, verdict: PlacementVerdict): BuilderState {\n return { ...state, refusal: { action: action.type, verdict } }\n}\n\n/**\n * The builder's pure state transition, CONSTRUCTED with the placement scope it judges\n * by (EC-584, owner-ratified 4a): the field's effective top-level vocabulary and the\n * manifest lookup. The scope is static per store and deliberately not reducer STATE\n * (it is the declaration the tree is judged against, not part of the tree) — the\n * reducer RECEIVES it, so there is no `(state, action)` to call without it.\n *\n * Every structural action that places a node — `insert`, `replace`, `move`, `wrap`,\n * `duplicate` — runs the ONE core judge (`subtreePlacementRefusal`) over every node\n * that enters or moves, BEFORE committing. A refusal returns the composition\n * unchanged, with the verdict in {@link BuilderState.refusal}: so no gesture — a\n * forgotten pre-check, promote, detach, a fixture's `slotChildren`, a server-only\n * paste — can place what the field, a slot or canvas eligibility forbids, and the\n * publish gate (which calls the same judge) cannot disagree with the canvas.\n *\n * Exported (with `initialBuilderState`) for unit tests — gesture determinism and\n * normalization lockstep are reducer-level properties, not render behavior.\n */\nexport function createBuilderReducer(\n placement: PlacementScope,\n): (state: BuilderState, action: Action) => BuilderState {\n return (state, action) => transition(state, action, placement)\n}\n\nfunction transition(state: BuilderState, action: Action, placement: PlacementScope): BuilderState {\n const root = state.present\n switch (action.type) {\n case 'select':\n return { ...state, selectedId: action.id, selectedRun: action.id === null ? state.selectedRun : null, refusal: null }\n case 'selectRun':\n return {\n ...state,\n selectedRun: liveRun(root, state.preserved, action.run),\n selectedId: action.run === null ? state.selectedId : null,\n refusal: null,\n }\n case 'removeRun': {\n const run = runByKey(rootCount(root), state.preserved, action.run)\n if (!run) return state\n return commit(state, root, { preserved: replaceRun(state.preserved, run, []), selectedRun: null })\n }\n case 'setRun': {\n const run = runByKey(rootCount(root), state.preserved, action.run)\n if (!run) return state\n return commit(state, root, {\n preserved: replaceRun(state.preserved, run, action.content),\n coalesceKey: action.coalesceKey,\n selectedRun: action.content.length > 0 ? action.run : null,\n })\n }\n case 'hover':\n return state.hoveredId === action.id ? state : { ...state, hoveredId: action.id }\n case 'viewport':\n return { ...state, viewport: action.viewport }\n case 'clearRefusal':\n return state.refusal === null ? state : { ...state, refusal: null }\n\n case 'undo': {\n const prev = state.past.at(-1)\n if (!prev) return state\n return restore(state, prev, state.past.slice(0, -1), [snapshotOf(state), ...state.future])\n }\n case 'redo': {\n const next = state.future[0]\n if (!next) return state\n return restore(state, next, [...state.past, snapshotOf(state)], state.future.slice(1))\n }\n\n case 'insert': {\n const node = action.minted ? action.node : cloneWithNewIds(action.node, state.newId)\n const verdict = subtreePlacementRefusal(root, node, landingOf(action.target), placement)\n if (verdict) return refuse(state, action, verdict)\n const next = insertNode(root, action.target, node)\n return commit(state, next, {\n selectedId: action.select === false ? state.selectedId : node.id,\n })\n }\n case 'remove': {\n const parent = getParentInfo(root, action.id)\n const next = removeNode(root, action.id)\n const selectedId =\n state.selectedId === action.id ? (parent?.parent.id ?? null) : state.selectedId\n return commit(state, next, { selectedId })\n }\n case 'duplicate': {\n // The copy (and every node of its subtree) ENTERS beside the original.\n const info = getParentInfo(root, action.id)\n const source = getNode(root, action.id)\n if (info && source) {\n const verdict = subtreePlacementRefusal(root, source, { parentId: info.parent.id, slot: info.slot }, placement)\n if (verdict) return refuse(state, action, verdict)\n }\n const { root: next, newId } = duplicateNode(root, action.id, state.newId)\n return commit(state, next, { selectedId: newId ?? state.selectedId })\n }\n case 'reorder':\n // Same parent, same slot: the placement does not change — nothing to judge.\n return commit(state, reorderNode(root, action.id, action.delta))\n case 'move': {\n // A node that changes parent or slot lands somewhere new (its descendants keep\n // their own slots, so only it is judged); a move within its own slot is a\n // reorder and leaves the placement as it was.\n const info = getParentInfo(root, action.id)\n const node = getNode(root, action.id)\n const relocates = !info || info.parent.id !== action.target.parentId || info.slot !== action.target.slot\n if (node && relocates) {\n const verdict = subtreePlacementRefusal(root, withoutSlots(node), landingOf(action.target), placement)\n if (verdict) return refuse(state, action, verdict)\n }\n return commit(state, moveNode(root, action.id, action.target))\n }\n case 'replace': {\n // Mint fresh ids for the incoming nodes (page-local namespace) so a detached\n // copy never collides with the page, and a promoted block's source subtree\n // (kept for the new reusable document) stays untouched.\n const cloned = action.nodes.map((n) => cloneWithNewIds(n, state.newId))\n // EC-560: promote (one embed) and detach (the reusable's content) land where the\n // replaced node was — judged there like any insert (the reuse preflight asks the\n // same `replacePlacementRefusal` before any side effect).\n const verdict = replacePlacementRefusal(root, action.id, cloned, placement)\n if (verdict) return refuse(state, action, verdict)\n const next = replaceNode(root, action.id, cloned)\n if (next === root) return state // root or absent id — no-op\n return commit(state, next, {\n selectedId: action.select === false ? state.selectedId : (cloned[0]?.id ?? state.selectedId),\n })\n }\n case 'wrap': {\n // Layout gesture (EC-162): the reference and the dragged subject become\n // the two columns of a new Grid container — ONE structural edit, one\n // history entry, one mirrored command, so a single undo dissolves the\n // whole gesture.\n const partner =\n action.subject.kind === 'node'\n ? { kind: 'node' as const, nodeId: action.subject.nodeId }\n : { kind: 'subtree' as const, node: cloneWithNewIds(action.subject.node, state.newId) }\n // EC-591: the gesture builds the `layout.grid` component; with none, it is off\n // (the drop rules refuse it before dispatch — this guard keeps the reducer total).\n const gridComponentId = state.layout.grid\n if (gridComponentId === undefined) return state\n // EC-584: the Grid lands where the reference is; the reference and the partner\n // land in the Grid's column slot. A moved partner keeps its own subtree (only it\n // relocates); a new one (a blocks-panel tile) enters whole.\n const reference = getNode(root, action.referenceId)\n const referenceInfo = getParentInfo(root, action.referenceId)\n const partnerNode = partner.kind === 'node' ? getNode(root, partner.nodeId) : partner.node\n if (reference && referenceInfo && partnerNode) {\n const columns = [withoutSlots(reference), partner.kind === 'node' ? withoutSlots(partnerNode) : partnerNode]\n const probe = gridContainerNode(gridComponentId, 'wrap', WRAP_GRID_OPTIONS, columns)\n const verdict = subtreePlacementRefusal(\n root,\n probe,\n { parentId: referenceInfo.parent.id, slot: referenceInfo.slot },\n placement,\n )\n if (verdict) return refuse(state, action, verdict)\n }\n const containerId = state.newId()\n const wrapped = applyWrap({\n root,\n gridComponentId,\n referenceId: action.referenceId,\n side: action.side,\n partner,\n containerId,\n })\n if (!wrapped) return state\n return commit(state, wrapped.root, { selectedId: containerId })\n }\n case 'setProp':\n return commit(state, setNodeProp(root, action.id, action.name, action.value), {\n coalesceKey: action.coalesceKey,\n })\n case 'removeProp':\n return commit(state, removeNodeProp(root, action.id, action.name))\n default:\n return state\n }\n}\n\nfunction landingOf(target: InsertTarget): { parentId: string; slot?: string } {\n return { parentId: target.parentId, slot: target.slot }\n}\n\n/** The node alone — a move relocates it; its descendants keep their own slots. */\nfunction withoutSlots(node: ComponentNode): ComponentNode {\n const { slots: _slots, ...rest } = node\n return rest\n}\n\n/**\n * The composition FIELD whose value the store edits (EC-554). Static for the\n * store's lifetime and deliberately NOT reducer state: it is the declaration the\n * edited tree is judged against, not part of the tree. It travels WITH the store\n * so every placement surface under the provider — the canvas and page-tree\n * drag-and-drop, paste (canvas, tree, keyboard), and the insert offer — reads the\n * same value from the one context it already requires; none can be mounted\n * without it, and `BuilderProvider` cannot be mounted without declaring it.\n */\nexport interface CompositionFieldScope {\n /** The field's display label — what a refusal notice names (e.g. \"Canvas\"). */\n label: string\n /**\n * The field's EFFECTIVE top-level vocabulary (EC-188; EC-584 — `fieldAllowList(field)`:\n * its `allow`, else the `blocks` type's default). The judge applies it only to\n * direct children of the composition root (`allowAt`, core `placement.ts`).\n */\n allow: AllowList\n}\n\nexport interface BuilderStore extends BuilderState {\n canUndo: boolean\n canRedo: boolean\n selectedNode: ComponentNode | null\n /** The composition field being edited (EC-554) — see {@link CompositionFieldScope}. */\n field: CompositionFieldScope\n /**\n * EC-584 — what the reducer judges every placement by: the manifest lookup and the\n * field's vocabulary. The gestures' own pre-checks (drag-and-drop, paste, the insert\n * offer, the reuse preflight) read the SAME scope, so an indicator and the sink agree.\n */\n placement: PlacementScope\n dispatch: (action: Action) => void\n}\n\nconst { Context: BuilderContext, useRequired: useBuilder } =\n createRequiredContext<BuilderStore>('Builder')\n\nexport function initialBuilderState(\n composition: ComponentNode,\n layout: LayoutContainerIds,\n newId: IdFactory,\n /** EC-549 — the field value's typography items with their anchors (`splitBlockRoots`). */\n preserved: readonly PreservedItem[] = [],\n): BuilderState {\n // Start container-normal (idempotent on healthy trees) so the session and the\n // lifted baseline agree from the first edit.\n const present = normalizeContainers(composition, layout)\n return {\n past: [],\n present,\n future: [],\n preserved,\n selectedId: present.id,\n selectedRun: null,\n hoveredId: null,\n viewport: 'full',\n // EC-578: fresh ids come from the injected factory — never a counter seeded past\n // the tree's `node-<n>` ids (EC-203), which two sessions advanced identically.\n newId,\n lastCoalesceKey: null,\n layout,\n refusal: null,\n }\n}\n\n/**\n * Undo/redo design (EC-141): the history stack is *UI state* — an in-memory\n * stack of composition-root snapshots. EC-287 retired the DB-resident project\n * graph and its append-only revision log, so the store no longer mirrors edits onto a\n * persistence layer: it is a pure in-memory editor. The block-field editor lifts\n * its committed composition into the open CMS document via `onChange`\n * (`composition-field-editor`); the document's own Save persists it as content.\n */\nexport function BuilderProvider({\n composition,\n preserved,\n field,\n components,\n layout,\n idFactory,\n children,\n}: {\n /** The composition root to edit (the composition-field editor's synthetic root). */\n composition: ComponentNode\n /** EC-549 — the field value's typography items (`splitBlockRoots(value).preserved`). */\n preserved?: readonly PreservedItem[]\n /** The field the composition is the value of (EC-554) — required, never defaulted. */\n field: CompositionFieldScope\n /** The manifest lookup the placement judge reads (EC-584, `registry.lookup`) — required. */\n components: ComponentLookup\n /** The layout-role component ids (EC-591, `ComponentRegistry.layout`) — required. */\n layout: LayoutContainerIds\n /**\n * EC-578 — the node-id factory. Defaults to UUIDs (`createUuidIdFactory`, one per\n * store); fixtures inject a deterministic factory.\n */\n idFactory?: IdFactory\n children: ReactNode\n}) {\n const [newId] = useState<IdFactory>(() => idFactory ?? createUuidIdFactory())\n // EC-584: the reducer is constructed ONCE with the scope it judges by — the field\n // and the lookup are static for the store's lifetime (a remount re-reads them).\n const [placement] = useState<PlacementScope>(() => ({ components, fieldAllow: field.allow }))\n const [reducer] = useState(() => createBuilderReducer(placement))\n // EC-287: nothing persists a graph — committed edits are lifted into the CMS\n // document by the composition-field editor's `onChange`. `useReducer` drives the\n // pure reducer (consecutive dispatches in one gesture apply in sequence); the\n // store below decorates the state with the derived undo/redo + selection flags.\n const [state, dispatch] = useReducer(reducer, { composition, layout, newId, preserved }, (init) =>\n initialBuilderState(init.composition, init.layout, init.newId, init.preserved),\n )\n\n const store = useMemo<BuilderStore>(() => {\n const selectedNode = state.selectedId\n ? (getNode(state.present, state.selectedId) ?? null)\n : null\n return {\n ...state,\n canUndo: state.past.length > 0,\n canRedo: state.future.length > 0,\n selectedNode,\n field,\n placement,\n dispatch,\n }\n }, [state, field, placement, dispatch])\n\n return <BuilderContext.Provider value={store}>{children}</BuilderContext.Provider>\n}\n\nexport { useBuilder }\n"]}
1
+ {"version":3,"file":"builder-store.js","sourceRoot":"","sources":["../../../src/components/builder/builder-store.tsx"],"names":[],"mappings":"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","sourcesContent":["import { useMemo, useReducer, useState } from 'react'\nimport type { ReactNode } from 'react'\nimport {\n DEFAULT_SLOT,\n cloneWithNewIds,\n duplicateNode,\n getNode,\n getParentInfo,\n gridContainerNode,\n insertNode,\n moveNode,\n normalizeContainers,\n removeNode,\n removeNodeProp,\n reorderNode,\n replaceNode,\n replacePlacementRefusal,\n setNodeProp,\n subtreePlacementRefusal,\n} from '@elytracms/core/project-graph'\nimport type {\n AllowList,\n ComponentLookup,\n ComponentNode,\n InsertTarget,\n LayoutContainerIds,\n PlacementScope,\n PlacementVerdict,\n PropValue,\n} from '@elytracms/core/project-graph'\nimport { createUuidIdFactory } from '@elytracms/core/persistence'\nimport type { IdFactory } from '@elytracms/core/persistence'\nimport { WRAP_GRID_OPTIONS, applyWrap } from '../../lib/dnd/drop-rules'\nimport { replaceRun, runByKey } from './canvas-runs'\nimport type { PreservedItem } from './canvas-runs'\nimport { rebaseCanvas } from './canvas-rebase'\nimport { createRequiredContext } from '../../lib/required-context'\n\nconst HISTORY_LIMIT = 100\n\n/**\n * A canvas preview-width key (EC-250): `'full'` (unconstrained) or a configured\n * breakpoint name (`'sm'`, `'md'`, …). Dynamic because the set is sourced from\n * the consuming site's breakpoints, so it is a string, not a fixed union — the\n * switcher resolves the available options via {@link resolveCanvasViewports}.\n */\nexport type Viewport = string\n\n/**\n * The builder store's action union. EC-287 retired the DB-resident project graph\n * and its persistence mirror, so these actions are pure in-memory editor state —\n * no action maps to a persisted `graph.*` command anymore. The block-field editor\n * lifts committed edits into the CMS document via `onChange`\n * (`composition-field-editor`); nothing persists a graph.\n */\nexport type BuilderAction =\n | { type: 'select'; id: string | null }\n | { type: 'hover'; id: string | null }\n | { type: 'viewport'; viewport: Viewport }\n | { type: 'undo' }\n | { type: 'redo' }\n /**\n * Insert a node (its subtree re-id'd from the store's id factory). `minted` — the\n * node ALREADY carries fresh ids from the same factory (the paste path mints first\n * so its issue deep links name exactly the ids that land); the reducer then inserts\n * it as given.\n */\n | { type: 'insert'; target: InsertTarget; node: ComponentNode; select?: boolean; minted?: true }\n | { type: 'remove'; id: string }\n | { type: 'duplicate'; id: string }\n | { type: 'reorder'; id: string; delta: -1 | 1 }\n | { type: 'move'; id: string; target: InsertTarget }\n /**\n * EC-282 reuse gesture: replace a node with zero or more nodes at its\n * position (clone-with-fresh-ids, like `insert`). Promote → 1 embed node;\n * detach → the referenced element's inline blocks. One atomic structural\n * edit, one undo step.\n */\n | { type: 'replace'; id: string; nodes: ComponentNode[]; select?: boolean }\n /**\n * EC-162 layout gesture: wrap the reference node and the dragged subject in\n * a two-column Grid container as ONE atomic structural edit (one undo step).\n */\n | {\n type: 'wrap'\n referenceId: string\n side: 'left' | 'right'\n subject: { kind: 'node'; nodeId: string } | { kind: 'component'; node: ComponentNode }\n }\n | { type: 'setProp'; id: string; name: string; value: PropValue; coalesceKey?: string }\n | { type: 'removeProp'; id: string; name: string }\n /** EC-584: the editor dismissed the visible refusal ({@link BuilderState.refusal}). */\n | { type: 'clearRefusal' }\n /**\n * EC-549 — select a typography RUN by its key (`canvas-runs.ts`: the index of its\n * first preserved item); `null` clears it. A run and a node are never both selected.\n */\n | { type: 'selectRun'; run: number | null }\n /** EC-549 — delete a typography run: a real, undoable edit of the preserved list. */\n | { type: 'removeRun'; run: number }\n /**\n * EC-549 — replace a run's typography with `content` (the inspector's rich-text\n * editor on that run; consecutive same-key edits coalesce into one undo step). Empty\n * `content` deletes the run.\n */\n | { type: 'setRun'; run: number; content: readonly unknown[]; coalesceKey?: string }\n /**\n * EC-630 — the field's value changed UNDERNEATH the canvas (a colleague's patch by\n * subscription, a write's canonical row, a resolved conflict), from `from` to `to` (the\n * draft's values before and after): the present absorbs the change and the history and\n * selection rebase onto it (`canvas-rebase.ts`) — never a remount. Not an edit: it adds\n * no history entry, and the canvas writes nothing for it.\n */\n | { type: 'rebase'; from: unknown; to: unknown }\n\n/** The structural actions the placement judge rules on (EC-584): every node that enters or moves. */\nexport type PlacingAction = Extract<BuilderAction, { type: 'insert' | 'replace' | 'move' | 'wrap' | 'duplicate' }>\n\n/** A refused placement (EC-584): the judge's verdict and the action it refused. */\nexport interface PlacementRefusal {\n action: PlacingAction['type']\n verdict: PlacementVerdict\n}\n\n/**\n * One history entry (EC-549): the component tree AND the preserved typography — so a\n * run's deletion or edit is undone exactly like a block's.\n */\nexport interface CanvasSnapshot {\n root: ComponentNode\n preserved: readonly PreservedItem[]\n}\n\nexport interface BuilderState {\n /**\n * The edited composition: one root-bearing component tree (EC-287). The canvas\n * wraps a page document's `body` blocks into a synthetic root and edits it\n * directly — no page/layout wrapper. Undo/redo snapshot it with the preserved\n * typography ({@link CanvasSnapshot}).\n */\n past: CanvasSnapshot[]\n present: ComponentNode\n future: CanvasSnapshot[]\n /**\n * EC-549 — the field value's typography items (no ids, EC-500 D1), each anchored by\n * how many component roots preceded it (`componentPrefix`); the field value is\n * `mergeBlockRoots(present's roots, preserved)`. In the store, so selecting,\n * deleting and editing a run is a real action with truthful undo.\n */\n preserved: readonly PreservedItem[]\n selectedId: string | null\n /** EC-549 — the selected typography run's key, or `null` (exclusive with {@link selectedId}). */\n selectedRun: number | null\n hoveredId: string | null\n viewport: Viewport\n /**\n * EC-578 / EC-595 A2 — THE node-id factory (injected; UUIDs in the studio, a\n * sequential factory in fixtures). It replaced the per-session `node-<n>` counter,\n * which two sessions editing one page advanced identically — both minted the same\n * next id, a `duplicate-node-id` on the second save. Stored ids are untouched.\n */\n newId: IdFactory\n /** Coalescing key of the last edit (consecutive same-key edits don't stack history). */\n lastCoalesceKey: string | null\n /**\n * The components filling the layout roles (EC-591, `ComponentRegistry.layout`),\n * fixed for the store's lifetime: which nodes container normalization treats as\n * Stack/Grid, and the Grid the wrap gesture builds. No hardcoded engine id.\n */\n layout: LayoutContainerIds\n /**\n * EC-584 — the last REFUSED placement, with its reason: the reducer judged an\n * `insert`/`replace`/`move`/`wrap`/`duplicate` against the field and slot\n * vocabularies and canvas eligibility (the core placement judge) and left the\n * composition unchanged. Transient — the next edit, selection, undo or redo clears\n * it — and never silent: the canvas shows it (`PlacementRefusalNotice`). A refused\n * action changes no tree, so it adds no history entry and emits no canvas patch.\n */\n refusal: PlacementRefusal | null\n /**\n * EC-630 — how many `rebase` actions the store has applied (external changes of its\n * field). The canvas sync reads it to tell a store value from before a rebase it\n * dispatched from one after it (`createCanvasSync`).\n */\n rebased: number\n}\n\ntype Action = BuilderAction\n\n/**\n * Push a new graph onto history, coalescing consecutive edits with the same key.\n *\n * Every commit normalizes layout containers (EC-162 ledger fix): the\n * operations layer normalizes every persisted `graph.*` write (EC-161), so\n * the optimistic working graph must apply the same `normalizeContainers` pass\n * or the UI state diverges from the persisted revision after\n * container-emptying moves/removes. The mirrored command stays un-normalized\n * (`graphInvocationFor` sees the raw action); both sides normalize\n * identically, so they land on the same graph.\n */\nfunction commit(\n state: BuilderState,\n root: ComponentNode,\n opts: {\n coalesceKey?: string\n selectedId?: string | null\n preserved?: readonly PreservedItem[]\n selectedRun?: number | null\n } = {},\n): BuilderState {\n const normalized = normalizeContainers(root, state.layout)\n const present = normalized\n const preserved = opts.preserved ?? state.preserved\n const coalesce = opts.coalesceKey != null && opts.coalesceKey === state.lastCoalesceKey\n // Normalization can dissolve the node a caller wanted selected (e.g. the\n // parent container of a removed child) — selection never points at a ghost.\n const desired = opts.selectedId !== undefined ? opts.selectedId : state.selectedId\n const selectedId = desired !== null && getNode(normalized, desired) ? desired : null\n const desiredRun = opts.selectedRun !== undefined ? opts.selectedRun : state.selectedRun\n return {\n ...state,\n past: coalesce ? state.past : [...state.past, snapshotOf(state)].slice(-HISTORY_LIMIT),\n present,\n preserved,\n future: [],\n lastCoalesceKey: opts.coalesceKey ?? null,\n selectedId,\n selectedRun: liveRun(present, preserved, desiredRun),\n refusal: null,\n }\n}\n\nfunction snapshotOf(state: BuilderState): CanvasSnapshot {\n return { root: state.present, preserved: state.preserved }\n}\n\n/** The run key if that run still exists in this state, else `null` (never a ghost selection). */\nfunction liveRun(root: ComponentNode, preserved: readonly PreservedItem[], run: number | null): number | null {\n if (run === null) return null\n return runByKey(rootCount(root), preserved, run) ? run : null\n}\n\n/** How many component roots the composition has (the synthetic root's children). */\nfunction rootCount(root: ComponentNode): number {\n return root.slots?.[DEFAULT_SLOT]?.length ?? 0\n}\n\n/** Restore a history entry (undo/redo), keeping a selection only where it still exists. */\nfunction restore(state: BuilderState, to: CanvasSnapshot, past: CanvasSnapshot[], future: CanvasSnapshot[]): BuilderState {\n return {\n ...state,\n past,\n present: to.root,\n preserved: to.preserved,\n future,\n lastCoalesceKey: null,\n selectedId: getNode(to.root, state.selectedId ?? '') ? state.selectedId : null,\n selectedRun: liveRun(to.root, to.preserved, state.selectedRun),\n refusal: null,\n }\n}\n\n/** Leave the composition untouched and say why (EC-584 — never a silent no-op). */\nfunction refuse(state: BuilderState, action: PlacingAction, verdict: PlacementVerdict): BuilderState {\n return { ...state, refusal: { action: action.type, verdict } }\n}\n\n/**\n * The builder's pure state transition, CONSTRUCTED with the placement scope it judges\n * by (EC-584, owner-ratified 4a): the field's effective top-level vocabulary and the\n * manifest lookup. The scope is static per store and deliberately not reducer STATE\n * (it is the declaration the tree is judged against, not part of the tree) — the\n * reducer RECEIVES it, so there is no `(state, action)` to call without it.\n *\n * Every structural action that places a node — `insert`, `replace`, `move`, `wrap`,\n * `duplicate` — runs the ONE core judge (`subtreePlacementRefusal`) over every node\n * that enters or moves, BEFORE committing. A refusal returns the composition\n * unchanged, with the verdict in {@link BuilderState.refusal}: so no gesture — a\n * forgotten pre-check, promote, detach, a fixture's `slotChildren`, a server-only\n * paste — can place what the field, a slot or canvas eligibility forbids, and the\n * publish gate (which calls the same judge) cannot disagree with the canvas.\n *\n * Exported (with `initialBuilderState`) for unit tests — gesture determinism and\n * normalization lockstep are reducer-level properties, not render behavior.\n */\nexport function createBuilderReducer(\n placement: PlacementScope,\n): (state: BuilderState, action: Action) => BuilderState {\n return (state, action) => transition(state, action, placement)\n}\n\nfunction transition(state: BuilderState, action: Action, placement: PlacementScope): BuilderState {\n const root = state.present\n switch (action.type) {\n case 'select':\n return { ...state, selectedId: action.id, selectedRun: action.id === null ? state.selectedRun : null, refusal: null }\n case 'selectRun':\n return {\n ...state,\n selectedRun: liveRun(root, state.preserved, action.run),\n selectedId: action.run === null ? state.selectedId : null,\n refusal: null,\n }\n case 'removeRun': {\n const run = runByKey(rootCount(root), state.preserved, action.run)\n if (!run) return state\n return commit(state, root, { preserved: replaceRun(state.preserved, run, []), selectedRun: null })\n }\n case 'setRun': {\n const run = runByKey(rootCount(root), state.preserved, action.run)\n if (!run) return state\n return commit(state, root, {\n preserved: replaceRun(state.preserved, run, action.content),\n coalesceKey: action.coalesceKey,\n selectedRun: action.content.length > 0 ? action.run : null,\n })\n }\n case 'hover':\n return state.hoveredId === action.id ? state : { ...state, hoveredId: action.id }\n case 'viewport':\n return { ...state, viewport: action.viewport }\n case 'clearRefusal':\n return state.refusal === null ? state : { ...state, refusal: null }\n\n case 'undo': {\n const prev = state.past.at(-1)\n if (!prev) return state\n return restore(state, prev, state.past.slice(0, -1), [snapshotOf(state), ...state.future])\n }\n case 'redo': {\n const next = state.future[0]\n if (!next) return state\n return restore(state, next, [...state.past, snapshotOf(state)], state.future.slice(1))\n }\n case 'rebase': {\n // EC-630: undo never reverts the external change — every snapshot absorbs it. The\n // next edit starts a new undo step (the step it would coalesce into may have been\n // dropped by the rebase, and an edit must never land in a step it cannot undo).\n const rebased = rebaseCanvas(state, action.from, action.to)\n // Counted even when it changes nothing: the canvas sync waits for every rebase it dispatched.\n if (!rebased) return { ...state, rebased: state.rebased + 1 }\n return {\n ...state,\n ...rebased,\n past: [...rebased.past],\n future: [...rebased.future],\n lastCoalesceKey: null,\n rebased: state.rebased + 1,\n }\n }\n\n case 'insert': {\n const node = action.minted ? action.node : cloneWithNewIds(action.node, state.newId)\n const verdict = subtreePlacementRefusal(root, node, landingOf(action.target), placement)\n if (verdict) return refuse(state, action, verdict)\n const next = insertNode(root, action.target, node)\n return commit(state, next, {\n selectedId: action.select === false ? state.selectedId : node.id,\n })\n }\n case 'remove': {\n const parent = getParentInfo(root, action.id)\n const next = removeNode(root, action.id)\n const selectedId =\n state.selectedId === action.id ? (parent?.parent.id ?? null) : state.selectedId\n return commit(state, next, { selectedId })\n }\n case 'duplicate': {\n // The copy (and every node of its subtree) ENTERS beside the original.\n const info = getParentInfo(root, action.id)\n const source = getNode(root, action.id)\n if (info && source) {\n const verdict = subtreePlacementRefusal(root, source, { parentId: info.parent.id, slot: info.slot }, placement)\n if (verdict) return refuse(state, action, verdict)\n }\n const { root: next, newId } = duplicateNode(root, action.id, state.newId)\n return commit(state, next, { selectedId: newId ?? state.selectedId })\n }\n case 'reorder':\n // Same parent, same slot: the placement does not change — nothing to judge.\n return commit(state, reorderNode(root, action.id, action.delta))\n case 'move': {\n // A node that changes parent or slot lands somewhere new (its descendants keep\n // their own slots, so only it is judged); a move within its own slot is a\n // reorder and leaves the placement as it was.\n const info = getParentInfo(root, action.id)\n const node = getNode(root, action.id)\n const relocates = !info || info.parent.id !== action.target.parentId || info.slot !== action.target.slot\n if (node && relocates) {\n const verdict = subtreePlacementRefusal(root, withoutSlots(node), landingOf(action.target), placement)\n if (verdict) return refuse(state, action, verdict)\n }\n return commit(state, moveNode(root, action.id, action.target))\n }\n case 'replace': {\n // Mint fresh ids for the incoming nodes (page-local namespace) so a detached\n // copy never collides with the page, and a promoted block's source subtree\n // (kept for the new reusable document) stays untouched.\n const cloned = action.nodes.map((n) => cloneWithNewIds(n, state.newId))\n // EC-560: promote (one embed) and detach (the reusable's content) land where the\n // replaced node was — judged there like any insert (the reuse preflight asks the\n // same `replacePlacementRefusal` before any side effect).\n const verdict = replacePlacementRefusal(root, action.id, cloned, placement)\n if (verdict) return refuse(state, action, verdict)\n const next = replaceNode(root, action.id, cloned)\n if (next === root) return state // root or absent id — no-op\n return commit(state, next, {\n selectedId: action.select === false ? state.selectedId : (cloned[0]?.id ?? state.selectedId),\n })\n }\n case 'wrap': {\n // Layout gesture (EC-162): the reference and the dragged subject become\n // the two columns of a new Grid container — ONE structural edit, one\n // history entry, one mirrored command, so a single undo dissolves the\n // whole gesture.\n const partner =\n action.subject.kind === 'node'\n ? { kind: 'node' as const, nodeId: action.subject.nodeId }\n : { kind: 'subtree' as const, node: cloneWithNewIds(action.subject.node, state.newId) }\n // EC-591: the gesture builds the `layout.grid` component; with none, it is off\n // (the drop rules refuse it before dispatch — this guard keeps the reducer total).\n const gridComponentId = state.layout.grid\n if (gridComponentId === undefined) return state\n // EC-584: the Grid lands where the reference is; the reference and the partner\n // land in the Grid's column slot. A moved partner keeps its own subtree (only it\n // relocates); a new one (a blocks-panel tile) enters whole.\n const reference = getNode(root, action.referenceId)\n const referenceInfo = getParentInfo(root, action.referenceId)\n const partnerNode = partner.kind === 'node' ? getNode(root, partner.nodeId) : partner.node\n if (reference && referenceInfo && partnerNode) {\n const columns = [withoutSlots(reference), partner.kind === 'node' ? withoutSlots(partnerNode) : partnerNode]\n const probe = gridContainerNode(gridComponentId, 'wrap', WRAP_GRID_OPTIONS, columns)\n const verdict = subtreePlacementRefusal(\n root,\n probe,\n { parentId: referenceInfo.parent.id, slot: referenceInfo.slot },\n placement,\n )\n if (verdict) return refuse(state, action, verdict)\n }\n const containerId = state.newId()\n const wrapped = applyWrap({\n root,\n gridComponentId,\n referenceId: action.referenceId,\n side: action.side,\n partner,\n containerId,\n })\n if (!wrapped) return state\n return commit(state, wrapped.root, { selectedId: containerId })\n }\n case 'setProp':\n return commit(state, setNodeProp(root, action.id, action.name, action.value), {\n coalesceKey: action.coalesceKey,\n })\n case 'removeProp':\n return commit(state, removeNodeProp(root, action.id, action.name))\n default:\n return state\n }\n}\n\nfunction landingOf(target: InsertTarget): { parentId: string; slot?: string } {\n return { parentId: target.parentId, slot: target.slot }\n}\n\n/** The node alone — a move relocates it; its descendants keep their own slots. */\nfunction withoutSlots(node: ComponentNode): ComponentNode {\n const { slots: _slots, ...rest } = node\n return rest\n}\n\n/**\n * The composition FIELD whose value the store edits (EC-554). Static for the\n * store's lifetime and deliberately NOT reducer state: it is the declaration the\n * edited tree is judged against, not part of the tree. It travels WITH the store\n * so every placement surface under the provider — the canvas and page-tree\n * drag-and-drop, paste (canvas, tree, keyboard), and the insert offer — reads the\n * same value from the one context it already requires; none can be mounted\n * without it, and `BuilderProvider` cannot be mounted without declaring it.\n */\nexport interface CompositionFieldScope {\n /** The field's display label — what a refusal notice names (e.g. \"Canvas\"). */\n label: string\n /**\n * The field's EFFECTIVE top-level vocabulary (EC-188; EC-584 — `fieldAllowList(field)`:\n * its `allow`, else the `blocks` type's default). The judge applies it only to\n * direct children of the composition root (`allowAt`, core `placement.ts`).\n */\n allow: AllowList\n}\n\nexport interface BuilderStore extends BuilderState {\n canUndo: boolean\n canRedo: boolean\n selectedNode: ComponentNode | null\n /** The composition field being edited (EC-554) — see {@link CompositionFieldScope}. */\n field: CompositionFieldScope\n /**\n * EC-584 — what the reducer judges every placement by: the manifest lookup and the\n * field's vocabulary. The gestures' own pre-checks (drag-and-drop, paste, the insert\n * offer, the reuse preflight) read the SAME scope, so an indicator and the sink agree.\n */\n placement: PlacementScope\n dispatch: (action: Action) => void\n}\n\nconst { Context: BuilderContext, useRequired: useBuilder } =\n createRequiredContext<BuilderStore>('Builder')\n\nexport function initialBuilderState(\n composition: ComponentNode,\n layout: LayoutContainerIds,\n newId: IdFactory,\n /** EC-549 — the field value's typography items with their anchors (`splitBlockRoots`). */\n preserved: readonly PreservedItem[] = [],\n): BuilderState {\n // Start container-normal (idempotent on healthy trees) so the session and the\n // lifted baseline agree from the first edit.\n const present = normalizeContainers(composition, layout)\n return {\n past: [],\n present,\n future: [],\n preserved,\n selectedId: present.id,\n selectedRun: null,\n hoveredId: null,\n viewport: 'full',\n // EC-578: fresh ids come from the injected factory — never a counter seeded past\n // the tree's `node-<n>` ids (EC-203), which two sessions advanced identically.\n newId,\n lastCoalesceKey: null,\n layout,\n refusal: null,\n rebased: 0,\n }\n}\n\n/**\n * Undo/redo design (EC-141): the history stack is *UI state* — an in-memory\n * stack of composition-root snapshots. EC-287 retired the DB-resident project\n * graph and its append-only revision log, so the store no longer mirrors edits onto a\n * persistence layer: it is a pure in-memory editor. The block-field editor lifts\n * its committed composition into the open CMS document via `onChange`\n * (`composition-field-editor`); the document's own Save persists it as content.\n * EC-630: a change of the field made underneath the store (a colleague's patch) is\n * absorbed by the present AND every snapshot (`rebase`, `canvas-rebase.ts`), so an undo\n * never reverts it.\n */\nexport function BuilderProvider({\n composition,\n preserved,\n field,\n components,\n layout,\n idFactory,\n children,\n}: {\n /** The composition root to edit (the composition-field editor's synthetic root). */\n composition: ComponentNode\n /** EC-549 — the field value's typography items (`splitBlockRoots(value).preserved`). */\n preserved?: readonly PreservedItem[]\n /** The field the composition is the value of (EC-554) — required, never defaulted. */\n field: CompositionFieldScope\n /** The manifest lookup the placement judge reads (EC-584, `registry.lookup`) — required. */\n components: ComponentLookup\n /** The layout-role component ids (EC-591, `ComponentRegistry.layout`) — required. */\n layout: LayoutContainerIds\n /**\n * EC-578 — the node-id factory. Defaults to UUIDs (`createUuidIdFactory`, one per\n * store); fixtures inject a deterministic factory.\n */\n idFactory?: IdFactory\n children: ReactNode\n}) {\n const [newId] = useState<IdFactory>(() => idFactory ?? createUuidIdFactory())\n // EC-584: the reducer is constructed ONCE with the scope it judges by — the field\n // and the lookup are static for the store's lifetime (a remount re-reads them).\n const [placement] = useState<PlacementScope>(() => ({ components, fieldAllow: field.allow }))\n const [reducer] = useState(() => createBuilderReducer(placement))\n // EC-287: nothing persists a graph — committed edits are lifted into the CMS\n // document by the composition-field editor's `onChange`. `useReducer` drives the\n // pure reducer (consecutive dispatches in one gesture apply in sequence); the\n // store below decorates the state with the derived undo/redo + selection flags.\n const [state, dispatch] = useReducer(reducer, { composition, layout, newId, preserved }, (init) =>\n initialBuilderState(init.composition, init.layout, init.newId, init.preserved),\n )\n\n const store = useMemo<BuilderStore>(() => {\n const selectedNode = state.selectedId\n ? (getNode(state.present, state.selectedId) ?? null)\n : null\n return {\n ...state,\n canUndo: state.past.length > 0,\n canRedo: state.future.length > 0,\n selectedNode,\n field,\n placement,\n dispatch,\n }\n }, [state, field, placement, dispatch])\n\n return <BuilderContext.Provider value={store}>{children}</BuilderContext.Provider>\n}\n\nexport { useBuilder }\n"]}
@@ -0,0 +1,22 @@
1
+ import type { ReactNode } from 'react';
2
+ import type { CommitPolicy } from '../cms/commit-policy.js';
3
+ import type { CanvasControlPosition } from '../cms/canvas-commit.js';
4
+ /**
5
+ * EC-630 — the canvas inspector's commit boundary. The document editor hands the canvas a
6
+ * channel to its committer ({@link CanvasCommitChannel}); every inspector control that
7
+ * types (a prop's control, a typography run's editor) stands inside a boundary naming the
8
+ * position it writes and its kind's policy (`commitPolicyOf`), so a burst of typing is
9
+ * committed on blur / Enter / the idle pause like a form field's — never per keystroke.
10
+ * Without a channel (a surface with no document — the component preview) it is inert.
11
+ */
12
+ export interface CanvasCommitChannel {
13
+ focused(position: CanvasControlPosition, policy: CommitPolicy): void;
14
+ blurred(position: CanvasControlPosition): void;
15
+ entered(position: CanvasControlPosition): void;
16
+ }
17
+ export declare const CanvasCommitProvider: import("react").Provider<CanvasCommitChannel | null>;
18
+ export declare function CanvasCommitBoundary({ position, policy, children, }: {
19
+ position: CanvasControlPosition;
20
+ policy: CommitPolicy;
21
+ children: ReactNode;
22
+ }): import("react").JSX.Element;
@@ -0,0 +1,27 @@
1
+ import { Fragment as _Fragment, jsx as _jsx } from "react/jsx-runtime";
2
+ import { createContext, useContext, useEffect, useRef } from 'react';
3
+ import { FieldCommitBoundary } from '../cms/field-collaboration.js';
4
+ const CanvasCommitContext = createContext(null);
5
+ export const CanvasCommitProvider = CanvasCommitContext.Provider;
6
+ export function CanvasCommitBoundary({ position, policy, children, }) {
7
+ const channel = useContext(CanvasCommitContext);
8
+ const focusedRef = useRef(false);
9
+ const latest = useRef({ channel, position });
10
+ latest.current = { channel, position };
11
+ // A control that unmounts while focused (its node removed underneath, the selection
12
+ // moved) never sees a blur: leave it here, so its burst commits and focus is released.
13
+ useEffect(() => () => {
14
+ if (focusedRef.current)
15
+ latest.current.channel?.blurred(latest.current.position);
16
+ }, []);
17
+ if (!channel)
18
+ return _jsx(_Fragment, { children: children });
19
+ return (_jsx(FieldCommitBoundary, { onFocusField: () => {
20
+ focusedRef.current = true;
21
+ channel.focused(position, policy);
22
+ }, onBlurField: () => {
23
+ focusedRef.current = false;
24
+ channel.blurred(position);
25
+ }, onEnter: () => channel.entered(position), children: children }));
26
+ }
27
+ //# sourceMappingURL=canvas-commit-boundary.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"canvas-commit-boundary.js","sourceRoot":"","sources":["../../../src/components/builder/canvas-commit-boundary.tsx"],"names":[],"mappings":";AAAA,OAAO,EAAE,aAAa,EAAE,UAAU,EAAE,SAAS,EAAE,MAAM,EAAE,MAAM,OAAO,CAAA;AAEpE,OAAO,EAAE,mBAAmB,EAAE,MAAM,4BAA4B,CAAA;AAkBhE,MAAM,mBAAmB,GAAG,aAAa,CAA6B,IAAI,CAAC,CAAA;AAE3E,MAAM,CAAC,MAAM,oBAAoB,GAAG,mBAAmB,CAAC,QAAQ,CAAA;AAEhE,MAAM,UAAU,oBAAoB,CAAC,EACnC,QAAQ,EACR,MAAM,EACN,QAAQ,GAKT;IACC,MAAM,OAAO,GAAG,UAAU,CAAC,mBAAmB,CAAC,CAAA;IAC/C,MAAM,UAAU,GAAG,MAAM,CAAC,KAAK,CAAC,CAAA;IAChC,MAAM,MAAM,GAAG,MAAM,CAAC,EAAE,OAAO,EAAE,QAAQ,EAAE,CAAC,CAAA;IAC5C,MAAM,CAAC,OAAO,GAAG,EAAE,OAAO,EAAE,QAAQ,EAAE,CAAA;IACtC,oFAAoF;IACpF,uFAAuF;IACvF,SAAS,CACP,GAAG,EAAE,CAAC,GAAG,EAAE;QACT,IAAI,UAAU,CAAC,OAAO;YAAE,MAAM,CAAC,OAAO,CAAC,OAAO,EAAE,OAAO,CAAC,MAAM,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAA;IAClF,CAAC,EACD,EAAE,CACH,CAAA;IACD,IAAI,CAAC,OAAO;QAAE,OAAO,4BAAG,QAAQ,GAAI,CAAA;IACpC,OAAO,CACL,KAAC,mBAAmB,IAClB,YAAY,EAAE,GAAG,EAAE;YACjB,UAAU,CAAC,OAAO,GAAG,IAAI,CAAA;YACzB,OAAO,CAAC,OAAO,CAAC,QAAQ,EAAE,MAAM,CAAC,CAAA;QACnC,CAAC,EACD,WAAW,EAAE,GAAG,EAAE;YAChB,UAAU,CAAC,OAAO,GAAG,KAAK,CAAA;YAC1B,OAAO,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAA;QAC3B,CAAC,EACD,OAAO,EAAE,GAAG,EAAE,CAAC,OAAO,CAAC,OAAO,CAAC,QAAQ,CAAC,YAEvC,QAAQ,GACW,CACvB,CAAA;AACH,CAAC","sourcesContent":["import { createContext, useContext, useEffect, useRef } from 'react'\nimport type { ReactNode } from 'react'\nimport { FieldCommitBoundary } from '../cms/field-collaboration'\nimport type { CommitPolicy } from '../cms/commit-policy'\nimport type { CanvasControlPosition } from '../cms/canvas-commit'\n\n/**\n * EC-630 — the canvas inspector's commit boundary. The document editor hands the canvas a\n * channel to its committer ({@link CanvasCommitChannel}); every inspector control that\n * types (a prop's control, a typography run's editor) stands inside a boundary naming the\n * position it writes and its kind's policy (`commitPolicyOf`), so a burst of typing is\n * committed on blur / Enter / the idle pause like a form field's — never per keystroke.\n * Without a channel (a surface with no document — the component preview) it is inert.\n */\nexport interface CanvasCommitChannel {\n focused(position: CanvasControlPosition, policy: CommitPolicy): void\n blurred(position: CanvasControlPosition): void\n entered(position: CanvasControlPosition): void\n}\n\nconst CanvasCommitContext = createContext<CanvasCommitChannel | null>(null)\n\nexport const CanvasCommitProvider = CanvasCommitContext.Provider\n\nexport function CanvasCommitBoundary({\n position,\n policy,\n children,\n}: {\n position: CanvasControlPosition\n policy: CommitPolicy\n children: ReactNode\n}) {\n const channel = useContext(CanvasCommitContext)\n const focusedRef = useRef(false)\n const latest = useRef({ channel, position })\n latest.current = { channel, position }\n // A control that unmounts while focused (its node removed underneath, the selection\n // moved) never sees a blur: leave it here, so its burst commits and focus is released.\n useEffect(\n () => () => {\n if (focusedRef.current) latest.current.channel?.blurred(latest.current.position)\n },\n [],\n )\n if (!channel) return <>{children}</>\n return (\n <FieldCommitBoundary\n onFocusField={() => {\n focusedRef.current = true\n channel.focused(position, policy)\n }}\n onBlurField={() => {\n focusedRef.current = false\n channel.blurred(position)\n }}\n onEnter={() => channel.entered(position)}\n >\n {children}\n </FieldCommitBoundary>\n )\n}\n"]}