cms-renderer 0.6.10 → 0.6.12

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.
@@ -46,6 +46,15 @@ declare function walkReactNode(node: React__default.ReactNode, visitors: WalkVis
46
46
  key?: React__default.Key | null;
47
47
  inSvg?: boolean;
48
48
  }): React__default.ReactNode;
49
+ type ContentMatch = {
50
+ contentPath: string;
51
+ value: string;
52
+ };
53
+ /**
54
+ * Extracts all string values from a content object with their paths.
55
+ * Returns a Map where keys are string values and values are arrays of content paths.
56
+ */
57
+ declare function extractContentValues(content: Record<string, unknown>, basePath?: string[]): Map<string, ContentMatch[]>;
49
58
  /**
50
59
  * Renders the shared CMS edit-mode styles and click-routing script.
51
60
  * Place this once at the top of your page when edit_mode is active.
@@ -79,20 +88,30 @@ interface BlockRendererProps {
79
88
  */
80
89
  path?: string;
81
90
  }
91
+ /**
92
+ * Returns true if each segment of `path` matches the corresponding segment in
93
+ * `pattern`, where a pattern segment wrapped in `{…}` or `(…)` is a wildcard.
94
+ */
95
+ declare function pathMatchesPattern(path: string, pattern: string): boolean;
96
+ /**
97
+ * Resolves the component for `blockType` from the registry.
98
+ *
99
+ * When `path` is provided, keys of the form `"/{pattern} BlockType"` are
100
+ * checked first. The first key whose path pattern matches the current path
101
+ * and whose block-type suffix matches `blockType` wins. Falls back to a
102
+ * direct `registry[blockType]` lookup.
103
+ */
104
+ declare function resolveComponent(registry: Partial<BlockComponentRegistry>, blockType: string, path?: string): BlockComponentRegistry[string] | undefined;
82
105
  /**
83
106
  * Renders a single block by dispatching to the appropriate component.
84
107
  *
85
108
  * Uses the ComponentMap pattern: the block's `type` field determines which
86
109
  * component renders the block's `content`.
87
110
  *
88
- * In editable mode, wraps the block in a ClientEditableBlock that:
89
- * - Stamps data-cms-block attributes directly on the component's root element
90
- * - Injects data-cms-editable spans around matching text nodes
91
- * - Portals the BlockToolbar into the component's root element
92
- *
93
- * Render CmsEditableInit once at the page level to include the shared styles
94
- * and click-routing script.
111
+ * In editable mode, renders a hidden sentinel before the component. The shared
112
+ * CMS overlay script uses that sentinel to stamp attributes on the component's
113
+ * root element without adding a layout-affecting wrapper.
95
114
  */
96
115
  declare function BlockRenderer({ block, registry, disableEditable, routeParams, path, }: BlockRendererProps): React__default.JSX.Element | null;
97
116
 
98
- export { BlockRenderer, CmsEditableInit, walkReactNode };
117
+ export { BlockRenderer, CmsEditableInit, extractContentValues, pathMatchesPattern, resolveComponent, walkReactNode };
@@ -1,6 +1,426 @@
1
1
  // lib/block-renderer.tsx
2
2
  import React from "react";
3
- import { ClientEditableBlock } from "./client-editable-block.js";
3
+
4
+ // lib/cms-overlay-script.ts
5
+ function generateCmsOverlayScript(cmsParentOrigin) {
6
+ return `
7
+ (function() {
8
+ if (window.__cmsOverlayInitialized) return;
9
+ window.__cmsOverlayInitialized = true;
10
+
11
+ var CMS_PARENT_ORIGIN = ${JSON.stringify(cmsParentOrigin)};
12
+
13
+ var style = document.createElement('style');
14
+ style.setAttribute('data-cms-overlay', '');
15
+ style.textContent = \`
16
+ [data-cms-block],
17
+ [data-cms-editable] {
18
+ cursor: pointer;
19
+ }
20
+ [data-cms-editable] {
21
+ border-radius: 2px;
22
+ }
23
+ [data-cms-editable]:not([data-cms-block]):hover {
24
+ outline: 2px solid #3b82f6;
25
+ outline-offset: 2px;
26
+ }
27
+ #cms-overlay-root {
28
+ position: fixed;
29
+ top: 0;
30
+ left: 0;
31
+ width: 0;
32
+ height: 0;
33
+ pointer-events: none;
34
+ z-index: 99998;
35
+ }
36
+ #cms-overlay-root > * {
37
+ pointer-events: none;
38
+ }
39
+ .cms-block-outline {
40
+ position: fixed;
41
+ border: 2px solid #3b82f6;
42
+ border-radius: 4px;
43
+ pointer-events: none;
44
+ z-index: 99997;
45
+ transition: all 0.15s ease;
46
+ }
47
+ .cms-block-outline.cms-outline-selected {
48
+ border-color: #2563eb;
49
+ border-width: 3px;
50
+ }
51
+ .cms-block-cursor {
52
+ position: fixed;
53
+ width: 22px;
54
+ height: 22px;
55
+ background: radial-gradient(circle, #fff 5px, #000 5px);
56
+ border-radius: 50%;
57
+ pointer-events: none;
58
+ z-index: 99999;
59
+ transform: translate(-50%, -50%);
60
+ opacity: 0;
61
+ transition: opacity 0.1s ease;
62
+ }
63
+ .cms-block-cursor.cms-cursor-visible {
64
+ opacity: 1;
65
+ }
66
+ .cms-block-toolbar {
67
+ position: fixed;
68
+ display: flex;
69
+ gap: 4px;
70
+ background: #1f2937;
71
+ border-radius: 6px;
72
+ padding: 4px;
73
+ box-shadow: 0 4px 12px rgba(0,0,0,0.25);
74
+ z-index: 99999;
75
+ pointer-events: none;
76
+ opacity: 0;
77
+ transform: scale(0.9) translateY(4px);
78
+ transition: opacity 0.15s ease, transform 0.15s ease;
79
+ }
80
+ .cms-block-toolbar.cms-toolbar-visible {
81
+ opacity: 1;
82
+ transform: scale(1) translateY(0);
83
+ pointer-events: auto;
84
+ }
85
+ .cms-block-toolbar button {
86
+ display: flex;
87
+ align-items: center;
88
+ justify-content: center;
89
+ width: 28px;
90
+ height: 28px;
91
+ border: none;
92
+ background: transparent;
93
+ color: #9ca3af;
94
+ border-radius: 4px;
95
+ cursor: pointer;
96
+ transition: background 0.15s ease, color 0.15s ease;
97
+ }
98
+ .cms-block-toolbar button:hover {
99
+ background: #374151;
100
+ color: #fff;
101
+ }
102
+ .cms-block-toolbar button.delete:hover {
103
+ background: #dc2626;
104
+ color: #fff;
105
+ }
106
+ .cms-block-toolbar button:disabled {
107
+ opacity: 0.4;
108
+ cursor: not-allowed;
109
+ }
110
+ .cms-block-toolbar button:disabled:hover {
111
+ background: transparent;
112
+ color: #9ca3af;
113
+ }
114
+ .cms-block-toolbar svg {
115
+ width: 16px;
116
+ height: 16px;
117
+ }
118
+ \`;
119
+ document.head.appendChild(style);
120
+
121
+ function stampBlockElements() {
122
+ var sentinels = document.querySelectorAll('[data-cms-sentinel]');
123
+ sentinels.forEach(function(sentinel) {
124
+ var blockEl = sentinel.nextElementSibling;
125
+ if (!blockEl) return;
126
+
127
+ var blockId = sentinel.getAttribute('data-block-id');
128
+ var blockType = sentinel.getAttribute('data-block-type');
129
+
130
+ blockEl.setAttribute('data-cms-block', '');
131
+ blockEl.setAttribute('data-block-id', blockId);
132
+ blockEl.setAttribute('data-block-type', blockType);
133
+ });
134
+ }
135
+
136
+ stampBlockElements();
137
+
138
+ var stampObserver = new MutationObserver(function(mutations) {
139
+ var needsStamp = mutations.some(function(m) {
140
+ return m.addedNodes.length > 0;
141
+ });
142
+ if (needsStamp) stampBlockElements();
143
+ });
144
+ stampObserver.observe(document.body, { childList: true, subtree: true });
145
+
146
+ var overlayRoot = document.createElement('div');
147
+ overlayRoot.id = 'cms-overlay-root';
148
+ document.body.appendChild(overlayRoot);
149
+
150
+ var cursor = document.createElement('div');
151
+ cursor.className = 'cms-block-cursor';
152
+ overlayRoot.appendChild(cursor);
153
+
154
+ var outline = document.createElement('div');
155
+ outline.className = 'cms-block-outline';
156
+ outline.style.display = 'none';
157
+ overlayRoot.appendChild(outline);
158
+
159
+ var selectedOutline = document.createElement('div');
160
+ selectedOutline.className = 'cms-block-outline cms-outline-selected';
161
+ selectedOutline.style.display = 'none';
162
+ overlayRoot.appendChild(selectedOutline);
163
+
164
+ var toolbar = document.createElement('div');
165
+ toolbar.className = 'cms-block-toolbar';
166
+ toolbar.setAttribute('data-cms-toolbar', '');
167
+ toolbar.innerHTML = \`
168
+ <button class="move-up" title="Move up">
169
+ <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
170
+ <path d="M18 15l-6-6-6 6"/>
171
+ </svg>
172
+ </button>
173
+ <button class="move-down" title="Move down">
174
+ <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
175
+ <path d="M6 9l6 6 6-6"/>
176
+ </svg>
177
+ </button>
178
+ <button class="delete" title="Delete">
179
+ <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
180
+ <path d="M19 7l-.867 12.142A2 2 0 0116.138 21H7.862a2 2 0 01-1.995-1.858L5 7m5 4v6m4-6v6m1-10V4a1 1 0 00-1-1h-4a1 1 0 00-1 1v3M4 7h16"/>
181
+ </svg>
182
+ </button>
183
+ \`;
184
+ overlayRoot.appendChild(toolbar);
185
+
186
+ var currentBlockId = null;
187
+ var toolbarVisible = false;
188
+ var selectedBlockId = null;
189
+
190
+ function decoratePreviewUrl(rawHref) {
191
+ if (!rawHref) return rawHref;
192
+ try {
193
+ var url = new URL(rawHref, window.location.href);
194
+ if (url.origin !== window.location.origin) return rawHref;
195
+ url.searchParams.set('edit_mode', 'true');
196
+ if (CMS_PARENT_ORIGIN) {
197
+ url.searchParams.set('cms_parent_origin', CMS_PARENT_ORIGIN);
198
+ }
199
+ return url.toString();
200
+ } catch (_) {
201
+ return rawHref;
202
+ }
203
+ }
204
+
205
+ function preserveEditParamsOnNavigation(e) {
206
+ if (e.defaultPrevented || e.button !== 0 || e.metaKey || e.ctrlKey || e.shiftKey || e.altKey) {
207
+ return;
208
+ }
209
+
210
+ var anchor = e.target.closest('a[href]');
211
+ if (!anchor || (anchor.target && anchor.target !== '_self') || anchor.hasAttribute('download')) {
212
+ return;
213
+ }
214
+
215
+ var href = anchor.getAttribute('href');
216
+ var decorated = decoratePreviewUrl(href);
217
+ if (decorated && decorated !== href) {
218
+ anchor.setAttribute('href', decorated);
219
+ }
220
+ }
221
+
222
+ function postToParent(message) {
223
+ if (!CMS_PARENT_ORIGIN || !window.parent || window.parent === window) {
224
+ return;
225
+ }
226
+ window.parent.postMessage(message, CMS_PARENT_ORIGIN);
227
+ }
228
+
229
+ function sendReadySignal() {
230
+ postToParent({ type: 'cms-preview-ready' });
231
+ }
232
+ sendReadySignal();
233
+ // The preview iframe can execute before the admin listener is attached.
234
+ setTimeout(sendReadySignal, 500);
235
+ setTimeout(sendReadySignal, 1500);
236
+
237
+ function getBlockElement(blockId) {
238
+ return document.querySelector('[data-block-id="' + blockId + '"]');
239
+ }
240
+
241
+ function getAllBlocks() {
242
+ return Array.from(document.querySelectorAll('[data-cms-block]'));
243
+ }
244
+
245
+ function getBlockIndex(blockId) {
246
+ var blocks = getAllBlocks();
247
+ for (var i = 0; i < blocks.length; i++) {
248
+ if (blocks[i].getAttribute('data-block-id') === blockId) return i;
249
+ }
250
+ return -1;
251
+ }
252
+
253
+ function updateOutline(el, outlineEl) {
254
+ if (!el) {
255
+ outlineEl.style.display = 'none';
256
+ return;
257
+ }
258
+ var rect = el.getBoundingClientRect();
259
+ outlineEl.style.display = 'block';
260
+ outlineEl.style.top = rect.top + 'px';
261
+ outlineEl.style.left = rect.left + 'px';
262
+ outlineEl.style.width = rect.width + 'px';
263
+ outlineEl.style.height = rect.height + 'px';
264
+ }
265
+
266
+ function positionToolbar(x, y) {
267
+ var rect = toolbar.getBoundingClientRect();
268
+ var top = Math.max(4, y - rect.height - 12);
269
+ var left = Math.max(4, Math.min(x - rect.width / 2, window.innerWidth - rect.width - 4));
270
+ toolbar.style.top = top + 'px';
271
+ toolbar.style.left = left + 'px';
272
+ }
273
+
274
+ function showToolbar(x, y, blockId) {
275
+ currentBlockId = blockId;
276
+ toolbarVisible = true;
277
+ positionToolbar(x, y);
278
+ toolbar.classList.add('cms-toolbar-visible');
279
+
280
+ var index = getBlockIndex(blockId);
281
+ var total = getAllBlocks().length;
282
+ toolbar.querySelector('.move-up').disabled = index <= 0;
283
+ toolbar.querySelector('.move-down').disabled = index >= total - 1;
284
+ }
285
+
286
+ function hideToolbar() {
287
+ toolbarVisible = false;
288
+ toolbar.classList.remove('cms-toolbar-visible');
289
+ }
290
+
291
+ function showCursor(x, y) {
292
+ cursor.style.top = y + 'px';
293
+ cursor.style.left = x + 'px';
294
+ cursor.classList.add('cms-cursor-visible');
295
+ }
296
+
297
+ function hideCursor() {
298
+ cursor.classList.remove('cms-cursor-visible');
299
+ }
300
+
301
+ document.addEventListener('mouseover', function(e) {
302
+ if (toolbarVisible) return;
303
+ var block = e.target.closest('[data-cms-block]');
304
+ if (block) {
305
+ updateOutline(block, outline);
306
+ }
307
+ });
308
+
309
+ document.addEventListener('mouseout', function(e) {
310
+ var block = e.target.closest('[data-cms-block]');
311
+ var related = e.relatedTarget ? e.relatedTarget.closest('[data-cms-block]') : null;
312
+ if (block && block !== related) {
313
+ outline.style.display = 'none';
314
+ hideCursor();
315
+ }
316
+ });
317
+
318
+ document.addEventListener('mousemove', function(e) {
319
+ if (toolbarVisible) return;
320
+ var block = e.target.closest('[data-cms-block]');
321
+ if (block) {
322
+ showCursor(e.clientX, e.clientY);
323
+ }
324
+ });
325
+
326
+ document.addEventListener('contextmenu', function(e) {
327
+ if (e.target.closest('[data-cms-toolbar]')) return;
328
+ var block = e.target.closest('[data-cms-block]');
329
+ if (block) {
330
+ if (toolbarVisible) return;
331
+ e.preventDefault();
332
+ hideCursor();
333
+ outline.style.display = 'none';
334
+ var blockId = block.getAttribute('data-block-id');
335
+ showToolbar(e.clientX, e.clientY, blockId);
336
+ }
337
+ });
338
+
339
+ document.addEventListener('click', function(e) {
340
+ preserveEditParamsOnNavigation(e);
341
+
342
+ if (toolbarVisible && !e.target.closest('[data-cms-toolbar]')) {
343
+ var block = e.target.closest('[data-cms-block]');
344
+ if (!block || block.getAttribute('data-block-id') !== currentBlockId) {
345
+ hideToolbar();
346
+ }
347
+ }
348
+
349
+ if (e.target.closest('[data-cms-toolbar]')) return;
350
+
351
+ var editable = e.target.closest('[data-cms-editable]');
352
+ if (editable) {
353
+ postToParent({
354
+ type: 'cms-editable-click',
355
+ blockId: editable.getAttribute('data-block-id'),
356
+ blockType: editable.getAttribute('data-block-type'),
357
+ contentPath: editable.getAttribute('data-content-path')
358
+ });
359
+ return;
360
+ }
361
+
362
+ var block = e.target.closest('[data-cms-block]');
363
+ if (block) {
364
+ postToParent({
365
+ type: 'cms-editable-click',
366
+ blockId: block.getAttribute('data-block-id'),
367
+ blockType: block.getAttribute('data-block-type'),
368
+ contentPath: null
369
+ });
370
+ }
371
+ }, true);
372
+
373
+ toolbar.querySelector('.move-up').addEventListener('click', function() {
374
+ if (!currentBlockId) return;
375
+ postToParent({ type: 'cms-block-action', action: 'move-up', blockId: currentBlockId });
376
+ hideToolbar();
377
+ });
378
+
379
+ toolbar.querySelector('.move-down').addEventListener('click', function() {
380
+ if (!currentBlockId) return;
381
+ postToParent({ type: 'cms-block-action', action: 'move-down', blockId: currentBlockId });
382
+ hideToolbar();
383
+ });
384
+
385
+ toolbar.querySelector('.delete').addEventListener('click', function() {
386
+ if (!currentBlockId) return;
387
+ postToParent({ type: 'cms-block-action', action: 'delete', blockId: currentBlockId });
388
+ hideToolbar();
389
+ });
390
+
391
+ window.addEventListener('scroll', function() {
392
+ hideCursor();
393
+ hideToolbar();
394
+ if (selectedBlockId) {
395
+ var el = getBlockElement(selectedBlockId);
396
+ updateOutline(el, selectedOutline);
397
+ }
398
+ }, { passive: true, capture: true });
399
+
400
+ window.addEventListener('resize', function() {
401
+ if (selectedBlockId) {
402
+ var el = getBlockElement(selectedBlockId);
403
+ updateOutline(el, selectedOutline);
404
+ }
405
+ }, { passive: true });
406
+
407
+ window.addEventListener('message', function(e) {
408
+ if (CMS_PARENT_ORIGIN && e.origin !== CMS_PARENT_ORIGIN) return;
409
+ if (e.source !== window.parent) return;
410
+
411
+ if (e.data && e.data.type === 'cms-select-block') {
412
+ selectedBlockId = e.data.blockId || null;
413
+ if (selectedBlockId) {
414
+ var el = getBlockElement(selectedBlockId);
415
+ updateOutline(el, selectedOutline);
416
+ } else {
417
+ selectedOutline.style.display = 'none';
418
+ }
419
+ }
420
+ });
421
+ })();
422
+ `;
423
+ }
4
424
 
5
425
  // lib/cms-post-message.ts
6
426
  var CMS_PARENT_ORIGIN_PARAM = "cms_parent_origin";
@@ -128,112 +548,15 @@ function CmsEditableInit({
128
548
  cmsUrl,
129
549
  cmsParentOrigin
130
550
  }) {
131
- const cmsParentOriginJson = JSON.stringify(
132
- getCmsParentTargetOrigin(cmsUrl, cmsParentOrigin) ?? ""
133
- );
134
- return /* @__PURE__ */ jsxs(Fragment, { children: [
135
- /* @__PURE__ */ jsx("style", { children: `
136
- [data-cms-editable] {
137
- cursor: pointer;
138
- border-radius: 2px;
139
- }
140
- [data-cms-editable]:hover {
141
- outline: 2px solid #3b82f6;
142
- outline-offset: 2px;
143
- }
144
- .cms-block-toolbar {
145
- position: fixed;
146
- display: flex;
147
- gap: 4px;
148
- background: #1f2937;
149
- border-radius: 6px;
150
- padding: 4px;
151
- box-shadow: 0 2px 8px rgba(0, 0, 0, 0.15);
152
- transition: opacity 0.15s ease;
153
- z-index: 99999;
154
- pointer-events: auto;
155
- }
156
- .cms-block-toolbar button {
157
- display: flex;
158
- align-items: center;
159
- justify-content: center;
160
- width: 28px;
161
- height: 28px;
162
- border: none;
163
- background: transparent;
164
- color: #9ca3af;
165
- border-radius: 4px;
166
- cursor: pointer;
167
- transition: background 0.15s ease, color 0.15s ease;
168
- }
169
- .cms-block-toolbar button:hover {
170
- background: #374151;
171
- color: #fff;
172
- }
173
- .cms-block-toolbar button.delete:hover {
174
- background: #dc2626;
175
- color: #fff;
176
- }
177
- .cms-block-toolbar button:disabled {
178
- opacity: 0.4;
179
- cursor: not-allowed;
180
- }
181
- .cms-block-toolbar button:disabled:hover {
182
- background: transparent;
183
- color: #9ca3af;
184
- }
185
- .cms-block-toolbar svg {
186
- width: 16px;
187
- height: 16px;
188
- }
189
- ` }),
190
- /* @__PURE__ */ jsx(
191
- "script",
192
- {
193
- dangerouslySetInnerHTML: {
194
- __html: `
195
- (function() {
196
- var cmsParentOrigin = ${cmsParentOriginJson};
197
- if (!window.__cmsEditableInitialized) {
198
- window.__cmsEditableInitialized = true;
199
-
200
- document.addEventListener('click', function(e) {
201
- if (e.target.closest('.cms-block-toolbar')) return;
202
-
203
- var editableTarget = e.target.closest('[data-cms-editable]');
204
- if (editableTarget) {
205
- var message = {
206
- type: 'cms-editable-click',
207
- blockId: editableTarget.getAttribute('data-block-id'),
208
- blockType: editableTarget.getAttribute('data-block-type'),
209
- contentPath: editableTarget.getAttribute('data-content-path')
210
- };
211
- if (cmsParentOrigin && window.parent && window.parent !== window) {
212
- window.parent.postMessage(message, cmsParentOrigin);
213
- }
214
- return;
215
- }
216
-
217
- var blockTarget = e.target.closest('[data-cms-block]');
218
- if (blockTarget) {
219
- var message = {
220
- type: 'cms-editable-click',
221
- blockId: blockTarget.getAttribute('data-block-id'),
222
- blockType: blockTarget.getAttribute('data-block-type'),
223
- contentPath: null
224
- };
225
- if (cmsParentOrigin && window.parent && window.parent !== window) {
226
- window.parent.postMessage(message, cmsParentOrigin);
227
- }
228
- }
229
- });
230
- }
231
- })();
232
- `
233
- }
551
+ const targetOrigin = getCmsParentTargetOrigin(cmsUrl, cmsParentOrigin) ?? "";
552
+ return /* @__PURE__ */ jsx(
553
+ "script",
554
+ {
555
+ dangerouslySetInnerHTML: {
556
+ __html: generateCmsOverlayScript(targetOrigin)
234
557
  }
235
- )
236
- ] });
558
+ }
559
+ );
237
560
  }
238
561
  function pathMatchesPattern(path, pattern) {
239
562
  const pathSegs = path.split("/").filter(Boolean);
@@ -284,13 +607,26 @@ function BlockRenderer({
284
607
  if (disableEditable) {
285
608
  return component;
286
609
  }
287
- const contentValueMap = extractContentValues(block.content);
288
- const contentEntries = Array.from(contentValueMap.entries()).map(([value, matches]) => ({ v: value, p: matches[0]?.contentPath })).filter((e) => !!e.p);
289
- return /* @__PURE__ */ jsx(ClientEditableBlock, { blockId: block.id, blockType: block.type, contentEntries, children: component });
610
+ return /* @__PURE__ */ jsxs(Fragment, { children: [
611
+ /* @__PURE__ */ jsx(
612
+ "span",
613
+ {
614
+ "data-cms-sentinel": "",
615
+ "data-block-id": block.id,
616
+ "data-block-type": block.type,
617
+ style: { display: "none" },
618
+ "aria-hidden": "true"
619
+ }
620
+ ),
621
+ component
622
+ ] });
290
623
  }
291
624
  export {
292
625
  BlockRenderer,
293
626
  CmsEditableInit,
627
+ extractContentValues,
628
+ pathMatchesPattern,
629
+ resolveComponent,
294
630
  walkReactNode
295
631
  };
296
632
  //# sourceMappingURL=block-renderer.js.map