@obelism/content 0.19.1 → 0.20.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/bridge.mjs CHANGED
@@ -1,4 +1,4 @@
1
- import { P as PREVIEW_PARAMS, U as UID_ATTRIBUTE, E as ENTRY_ATTRIBUTE, a as PRODUCT_ATTRIBUTE, b as PRODUCT_HANDLE_ATTRIBUTE } from './preview-jcmxxj92.mjs';
1
+ import { P as PREVIEW_PARAMS, U as UID_ATTRIBUTE, E as ENTRY_ATTRIBUTE, C as COLLECTION_ATTRIBUTE, a as COLLECTION_HANDLE_ATTRIBUTE, b as PRODUCT_ATTRIBUTE, c as PRODUCT_HANDLE_ATTRIBUTE } from './preview-fu3qtgfx.mjs';
2
2
  import { SITE_EDITING_COOKIE, SITE_REQUEST_HEADER } from './site.mjs';
3
3
  import { n as normalizeUrl, D as DEFAULT_URL } from './config-c6qktlz6.mjs';
4
4
 
@@ -10,7 +10,7 @@ import { n as normalizeUrl, D as DEFAULT_URL } from './config-c6qktlz6.mjs';
10
10
  //
11
11
  // Sites tag a block's clickable element with `data-numbers-id={block._uid}`
12
12
  // and load Obelism numbers' script; the CMS reads the rates from numbers
13
- // (the CMS's content/docs/guides/visual-editor.mdx, "Click rates").
13
+ // (the CMS's content/docs/guides/canvas.mdx, "Click rates").
14
14
  const DEFAULT_STATS_LABELS = {
15
15
  clicked: '{rate}% clicked',
16
16
  title: '{clickers} of {viewers} visitors of its page clicked it in the last 30 days ({clicks} clicks)'
@@ -163,6 +163,91 @@ const mountStatsOverlay = (win, { selector, onSelect, labels: labelOverrides })=
163
163
  };
164
164
  };
165
165
 
166
+ // Content's canvas shows a whole page in a frame as tall as the page, so the
167
+ // frame is the page's height, not the screen's. Sizes in viewport-height
168
+ // units (`vh`, `svh`, `lvh`, `dvh`) would follow it: a `100vh` hero makes
169
+ // the page taller, the canvas makes the frame taller, and the hero grows
170
+ // again. The editor sends the height the frame stands for (`viewport`), and
171
+ // this rewrites those units in the page's stylesheets as pixels of that
172
+ // height. Stylesheets from another origin can't be read and keep theirs.
173
+ const UNIT = /(-?\d*\.?\d+)(?:s|l|d)?vh\b/g;
174
+ // A value with its viewport-height units as pixels of `height`, or null when
175
+ // it has none.
176
+ const freezeValue = (value, height)=>{
177
+ UNIT.lastIndex = 0;
178
+ if (!UNIT.test(value)) return null;
179
+ return value.replace(UNIT, (_, amount)=>`${Math.round(Number(amount) * height / 100 * 100) / 100}px`);
180
+ };
181
+ const freezeStyle = (style, height)=>{
182
+ for(let index = 0; index < style.length; index++){
183
+ const property = style.item(index);
184
+ const frozen = freezeValue(style.getPropertyValue(property), height);
185
+ if (frozen !== null) {
186
+ style.setProperty(property, frozen, style.getPropertyPriority(property));
187
+ }
188
+ }
189
+ };
190
+ // Style rules, and those inside @media, @supports and @layer blocks.
191
+ const freezeRules = (rules, height)=>{
192
+ for (const rule of Array.from(rules)){
193
+ const { style, cssRules } = rule;
194
+ if (style) freezeStyle(style, height);
195
+ if (cssRules) freezeRules(cssRules, height);
196
+ }
197
+ };
198
+ const createViewportUnits = (doc)=>{
199
+ const done = new WeakSet();
200
+ let height = null;
201
+ let observer = null;
202
+ let scheduled = false;
203
+ const freezeSheets = ()=>{
204
+ if (height === null) return;
205
+ for (const sheet of Array.from(doc.styleSheets)){
206
+ if (done.has(sheet)) continue;
207
+ let rules;
208
+ try {
209
+ rules = sheet.cssRules;
210
+ } catch {
211
+ continue;
212
+ }
213
+ done.add(sheet);
214
+ freezeRules(rules, height);
215
+ }
216
+ doc.querySelectorAll('[style*="vh"]').forEach((element)=>{
217
+ freezeStyle(element.style, height);
218
+ });
219
+ };
220
+ return {
221
+ freeze (next) {
222
+ // Once: the frame stands for one screen size until it reloads.
223
+ if (height !== null || !(next > 0)) return;
224
+ height = next;
225
+ freezeSheets();
226
+ const View = doc.defaultView?.MutationObserver;
227
+ if (!View) return;
228
+ // Once per frame, however much the page changes in it.
229
+ observer = new View(()=>{
230
+ if (scheduled) return;
231
+ scheduled = true;
232
+ const run = ()=>{
233
+ scheduled = false;
234
+ freezeSheets();
235
+ };
236
+ if (doc.defaultView?.requestAnimationFrame) {
237
+ doc.defaultView.requestAnimationFrame(run);
238
+ } else run();
239
+ });
240
+ observer.observe(doc.documentElement, {
241
+ childList: true,
242
+ subtree: true
243
+ });
244
+ },
245
+ destroy () {
246
+ observer?.disconnect();
247
+ }
248
+ };
249
+ };
250
+
166
251
  // The site's half of the visual editor (the CMS's public/bridge.js, as a
167
252
  // module). Inside the editor's iframe it outlines blocks, tells the editor
168
253
  // which one was clicked, hands the editor's live, unsaved entry to listeners
@@ -171,10 +256,10 @@ const mountStatsOverlay = (win, { selector, onSelect, labels: labelOverrides })=
171
256
  // Messages are only exchanged with the CMS origin, and only with the parent
172
257
  // window:
173
258
  // - site → editor: { source: 'obelism-content-bridge', type: 'ready' |
174
- // 'select' | 'prompt' | 'undo', uid?, id?, prompt? }
259
+ // 'size' | 'select' | 'prompt' | 'undo', uid?, id?, prompt?, height? }
175
260
  // - editor → site: { source: 'obelism-content-editor', type: 'connect' |
176
261
  // 'update' | 'select' | 'saved' | 'published' | 'features' |
177
- // 'promptResult' | 'promptState' | 'stats', … }
262
+ // 'promptResult' | 'promptState' | 'stats' | 'viewport', … }
178
263
  const BRIDGE_SOURCE = 'obelism-content-bridge';
179
264
  const EDITOR_SOURCE = 'obelism-content-editor';
180
265
  // How long a prompt may take before it counts as failed.
@@ -228,6 +313,7 @@ const INERT_METHODS = {
228
313
  prompt: inertPrompt,
229
314
  createPage: ()=>Promise.reject(new Error('New pages are made on the site itself')),
230
315
  createProductPage: ()=>Promise.reject(new Error('Product pages are made on the site itself')),
316
+ createCollectionPage: ()=>Promise.reject(new Error('Collection pages are made on the site itself')),
231
317
  view: onlyWhileEditingSite,
232
318
  applyJson: onlyWhileEditingSite,
233
319
  openForm: (_container, options = {})=>{
@@ -286,6 +372,7 @@ const createBridge = (win, cmsOrigin)=>{
286
372
  entryId: params.get(PREVIEW_PARAMS.entry),
287
373
  environment: params.get(PREVIEW_PARAMS.environment),
288
374
  product: null,
375
+ collection: null,
289
376
  on: emitter.on,
290
377
  getState: ()=>state,
291
378
  ...INERT_METHODS,
@@ -340,9 +427,32 @@ const createBridge = (win, cmsOrigin)=>{
340
427
  };
341
428
  doc.addEventListener('click', onClick, true);
342
429
  cleanup.push(()=>doc.removeEventListener('click', onClick, true));
343
- const ready = ()=>send('ready', {
344
- url: win.location.href
430
+ // The page's height, which an editor on another origin can't read: the
431
+ // canvas makes its frame as tall as the page. With `ready`, and as `size`
432
+ // whenever it changes.
433
+ const pageHeight = ()=>Math.ceil(Math.max(doc.documentElement.scrollHeight, doc.body?.scrollHeight ?? 0));
434
+ let sentHeight = 0;
435
+ const ready = ()=>{
436
+ sentHeight = pageHeight();
437
+ send('ready', {
438
+ url: win.location.href,
439
+ height: sentHeight
345
440
  });
441
+ };
442
+ const Observer = win.ResizeObserver;
443
+ if (typeof Observer === 'function') {
444
+ const observer = new Observer(()=>{
445
+ const height = pageHeight();
446
+ if (height === sentHeight) return;
447
+ sentHeight = height;
448
+ send('size', {
449
+ height
450
+ });
451
+ });
452
+ observer.observe(doc.documentElement);
453
+ if (doc.body) observer.observe(doc.body);
454
+ cleanup.push(()=>observer.disconnect());
455
+ }
346
456
  // Prompts waiting for the editor's answer, by id.
347
457
  const pending = new Map();
348
458
  let nextId = 0;
@@ -406,6 +516,8 @@ const createBridge = (win, cmsOrigin)=>{
406
516
  settle(id)?.reject(new Error('The bridge was destroyed'));
407
517
  }
408
518
  });
519
+ const viewportUnits = createViewportUnits(doc);
520
+ cleanup.push(()=>viewportUnits.destroy());
409
521
  const onMessage = (event)=>{
410
522
  if (event.origin !== cmsOrigin || event.source !== win.parent) return;
411
523
  const data = event.data;
@@ -438,6 +550,10 @@ const createBridge = (win, cmsOrigin)=>{
438
550
  statsVisible: data.visible !== false
439
551
  });
440
552
  showStats();
553
+ } else if (data.type === 'viewport' && typeof data.height === 'number') {
554
+ // The canvas: the frame is as tall as the page (`size`), so `vh`
555
+ // sizes are fixed at the screen height it stands for.
556
+ viewportUnits.freeze(data.height);
441
557
  } else if (data.type === 'promptState') {
442
558
  setState({
443
559
  canUndo: data.canUndo === true
@@ -479,6 +595,7 @@ const wrapScriptBridge = (script, params)=>{
479
595
  entryId: script.entryId,
480
596
  environment: params.get(PREVIEW_PARAMS.environment),
481
597
  product: null,
598
+ collection: null,
482
599
  on: (event, listener)=>{
483
600
  if (event === 'update' && !forwardingUpdates) {
484
601
  forwardingUpdates = true;
@@ -542,7 +659,11 @@ const DEFAULT_PROMPT_LABELS = {
542
659
  addProductPage: 'Add a product page',
543
660
  addingProductPage: 'Making the product page…',
544
661
  addedProductPage: 'Opening the product page…',
545
- productPageHint: 'This product has no page yet. Add one for what the store doesn’t say.'
662
+ productPageHint: 'This product has no page yet. Add one for what the store doesn’t say.',
663
+ addCollectionPage: 'Add a collection page',
664
+ addingCollectionPage: 'Making the collection page…',
665
+ addedCollectionPage: 'Opening the collection page…',
666
+ collectionPageHint: 'This collection has no page yet. Add one for what goes around its products.'
546
667
  };
547
668
  const SIDE_KEY = 'obelism-content-prompt-side';
548
669
  // How far the pointer moves before it drags the box, not clicks it.
@@ -687,7 +808,20 @@ textarea::placeholder { color: rgb(var(--theme-foreground-muted-rgb)); }
687
808
  display: block; width: 100%; height: min(560px, 60vh); border: none; border-radius: 12px;
688
809
  background: rgb(var(--theme-background-actions-rgb) / .45);
689
810
  }
690
- .form.loading iframe { visibility: hidden; }
811
+ /* Loading, it keeps the form's own height, the spinner in the middle,
812
+ whatever the form says meanwhile; the frame shows once the form does. */
813
+ .form.loading { position: relative; height: calc(min(560px, 60vh) + 12px); }
814
+ .form.loading iframe { position: absolute; visibility: hidden; }
815
+ .form-loader {
816
+ position: absolute; inset: 12px 12px 0; display: flex; align-items: center; justify-content: center;
817
+ gap: 10px; border-radius: 12px; color: rgb(var(--theme-foreground-muted-rgb));
818
+ background: rgb(var(--theme-background-actions-rgb) / .45);
819
+ }
820
+ .form-loader::before {
821
+ content: ''; width: 16px; height: 16px; flex: none; border-radius: 50%;
822
+ border: 2px solid rgb(var(--theme-border-rgb) / .3); border-top-color: rgb(var(--theme-accent-rgb));
823
+ animation: spin .7s linear infinite;
824
+ }
691
825
  /* New page: where it goes, above what it is for. */
692
826
  .path {
693
827
  display: flex; align-items: center; gap: 10px; padding: 16px 22px 0;
@@ -860,9 +994,14 @@ const mountPromptBox = (doc, bridge, options = {})=>{
860
994
  });
861
995
  input.setAttribute('aria-label', labels.open);
862
996
  // Form mode (on the site): the CMS's form, mounted while shown.
997
+ const formLoader = element(doc, 'div', {
998
+ className: 'form-loader',
999
+ textContent: labels.formLoading
1000
+ });
1001
+ formLoader.setAttribute('role', 'status');
863
1002
  const formBox = element(doc, 'div', {
864
1003
  className: 'form'
865
- });
1004
+ }, formLoader);
866
1005
  // What the prompt acts on: the whole page, or the selected block with a
867
1006
  // way back to the page.
868
1007
  const pageIcon = icon(doc, 'page');
@@ -903,8 +1042,9 @@ const mountPromptBox = (doc, bridge, options = {})=>{
903
1042
  className: 'action chip',
904
1043
  type: 'button'
905
1044
  }, icon(doc, 'newPage'), labels.newPage);
906
- // A product the site marks (editableProduct) without a page of its own:
907
- // one click makes its product page, which the page then shows.
1045
+ // A product (collection) the site marks (editableProduct,
1046
+ // editableCollection) without a page of its own: one click makes its
1047
+ // page, which the page then shows.
908
1048
  const addProduct = element(doc, 'button', {
909
1049
  className: 'action chip product',
910
1050
  type: 'button'
@@ -1158,8 +1298,20 @@ const mountPromptBox = (doc, bridge, options = {})=>{
1158
1298
  // A page of the site that isn't an entry (no `editable(entry)`, like a
1159
1299
  // hand-written /about) has nothing to edit: only New page.
1160
1300
  const pageless = site && bridge.entryId === null;
1161
- // …unless it shows a product: then Add a product page first.
1162
- const productHere = pageless && canCreate && bridge.product !== null;
1301
+ // …unless it shows a product (collection): then Add a product
1302
+ // (collection) page first.
1303
+ const shopHere = !pageless || !canCreate ? null : bridge.product ? 'product' : bridge.collection ? 'collection' : null;
1304
+ const productHere = shopHere !== null;
1305
+ const shopCopy = shopHere === 'collection' ? {
1306
+ add: labels.addCollectionPage,
1307
+ adding: labels.addingCollectionPage,
1308
+ hint: labels.collectionPageHint
1309
+ } : {
1310
+ add: labels.addProductPage,
1311
+ adding: labels.addingProductPage,
1312
+ hint: labels.productPageHint
1313
+ };
1314
+ addProduct.lastChild.textContent = shopCopy.add;
1163
1315
  const onlyNew = pageless && canCreate && !productHere;
1164
1316
  if (!canCreate) creating = false;
1165
1317
  if (onlyNew) creating = true;
@@ -1169,7 +1321,7 @@ const mountPromptBox = (doc, bridge, options = {})=>{
1169
1321
  if (showForm && !formHandle) mountForm();
1170
1322
  else if (!showForm && formHandle) unmountForm();
1171
1323
  const offerProduct = productHere && !creating;
1172
- pillText.textContent = offerProduct ? labels.addProductPage : onlyNew ? labels.newPage : labels.open;
1324
+ pillText.textContent = offerProduct ? shopCopy.add : onlyNew ? labels.newPage : labels.open;
1173
1325
  cancelNew.hidden = onlyNew;
1174
1326
  scope.hidden = creating || offerProduct;
1175
1327
  newScope.hidden = !creating;
@@ -1183,6 +1335,7 @@ const mountPromptBox = (doc, bridge, options = {})=>{
1183
1335
  input.hidden = form || picking || minimized || offerProduct;
1184
1336
  formBox.hidden = !form || picking || minimized;
1185
1337
  formBox.classList.toggle('loading', formLoading);
1338
+ formLoader.hidden = !formLoading;
1186
1339
  toolbar.hidden = picking;
1187
1340
  pagesSection.hidden = !picking;
1188
1341
  input.placeholder = creating ? labels.newPagePlaceholder : labels.placeholder;
@@ -1223,8 +1376,9 @@ const mountPromptBox = (doc, bridge, options = {})=>{
1223
1376
  pageChip.setAttribute('aria-expanded', String(picking));
1224
1377
  pageChipText.textContent = pages?.find(({ entryId })=>entryId === bridge.entryId)?.name ?? labels.pages;
1225
1378
  const loadingForm = form && formLoading && !picking;
1226
- const working = state.prompting || loadingForm;
1227
- const note = state.prompting ? creating ? labels.creating : offerProduct ? labels.addingProductPage : labels.working : loadingForm ? labels.formLoading : message?.text ?? (offerProduct ? labels.productPageHint : site && !creating && !picking && !state.selectedUid ? labels.selectHint : '');
1379
+ const working = state.prompting;
1380
+ // A form opening says so in its own place.
1381
+ const note = state.prompting ? creating ? labels.creating : offerProduct ? shopCopy.adding : labels.working : loadingForm ? '' : message?.text ?? (offerProduct ? shopCopy.hint : site && !creating && !picking && !state.selectedUid ? labels.selectHint : '');
1228
1382
  status.textContent = note;
1229
1383
  status.hidden = !note || minimized;
1230
1384
  status.className = `status${working ? ' working' : ''}${!busy && !loadingForm && message?.error ? ' error' : ''}`;
@@ -1447,11 +1601,19 @@ const mountPromptBox = (doc, bridge, options = {})=>{
1447
1601
  message = null;
1448
1602
  try {
1449
1603
  // The bridge reloads the page; this shows until it does.
1450
- await bridge.createProductPage();
1451
- message = {
1452
- text: labels.addedProductPage,
1453
- error: false
1454
- };
1604
+ if (bridge.product) {
1605
+ await bridge.createProductPage();
1606
+ message = {
1607
+ text: labels.addedProductPage,
1608
+ error: false
1609
+ };
1610
+ } else {
1611
+ await bridge.createCollectionPage();
1612
+ message = {
1613
+ text: labels.addedCollectionPage,
1614
+ error: false
1615
+ };
1616
+ }
1455
1617
  } catch (error) {
1456
1618
  message = failure(error);
1457
1619
  }
@@ -1648,7 +1810,7 @@ const FORM_BURST_MS = 1000;
1648
1810
  // How long the page waits for the form's edits to settle before it shows
1649
1811
  // them.
1650
1812
  const FORM_RENDER_MS = 300;
1651
- const createSiteBridge = (win, basePath, { pagePath = (path)=>`/${path}`, productPath: ownProductPath } = {})=>{
1813
+ const createSiteBridge = (win, basePath, { pagePath = (path)=>`/${path}`, productPath: ownProductPath, collectionPath: ownCollectionPath } = {})=>{
1652
1814
  const doc = win.document;
1653
1815
  const emitter = createEmitter();
1654
1816
  const cleanup = [];
@@ -1659,6 +1821,7 @@ const createSiteBridge = (win, basePath, { pagePath = (path)=>`/${path}`, produc
1659
1821
  const touched = new Set();
1660
1822
  let session = null;
1661
1823
  const productPath = (handle, locale)=>ownProductPath ? ownProductPath(handle, locale) : (session?.productPath ?? '/products/{handle}').replaceAll('{handle}', encodeURIComponent(handle));
1824
+ const collectionPath = (handle, locale)=>ownCollectionPath ? ownCollectionPath(handle, locale) : (session?.collectionPath ?? '/collections/{handle}').replaceAll('{handle}', encodeURIComponent(handle));
1662
1825
  // The open form's, if any; and when the form last changed content, for
1663
1826
  // undo steps (-Infinity: the next edit starts a new step).
1664
1827
  let closeForm = null;
@@ -1713,6 +1876,16 @@ const createSiteBridge = (win, basePath, { pagePath = (path)=>`/${path}`, produc
1713
1876
  handle
1714
1877
  } : null;
1715
1878
  };
1879
+ // The collection the page shows (editableCollection), if it marks one.
1880
+ const pageCollection = ()=>{
1881
+ const element = doc.querySelector(`[${COLLECTION_ATTRIBUTE}]`);
1882
+ const id = element?.getAttribute(COLLECTION_ATTRIBUTE);
1883
+ const handle = element?.getAttribute(COLLECTION_HANDLE_ATTRIBUTE);
1884
+ return id && handle ? {
1885
+ id,
1886
+ handle
1887
+ } : null;
1888
+ };
1716
1889
  const entryFor = (uid)=>{
1717
1890
  const block = uid ? doc.querySelector(blockSelector(uid)) : null;
1718
1891
  return block?.closest(`[${ENTRY_ATTRIBUTE}]`)?.getAttribute(ENTRY_ATTRIBUTE) ?? pageEntryId();
@@ -1823,6 +1996,9 @@ const createSiteBridge = (win, basePath, { pagePath = (path)=>`/${path}`, produc
1823
1996
  get product () {
1824
1997
  return pageProduct();
1825
1998
  },
1999
+ get collection () {
2000
+ return pageCollection();
2001
+ },
1826
2002
  environment: null,
1827
2003
  on: emitter.on,
1828
2004
  getState: ()=>state,
@@ -1920,6 +2096,34 @@ const createSiteBridge = (win, basePath, { pagePath = (path)=>`/${path}`, produc
1920
2096
  });
1921
2097
  }
1922
2098
  },
2099
+ async createCollectionPage (collection = pageCollection() ?? undefined) {
2100
+ if (!collection) {
2101
+ throw new Error('Nothing on this page is marked as a collection: add editableCollection(collection)');
2102
+ }
2103
+ if (!has('create')) throw new Error('You may not add pages here');
2104
+ if (state.unsaved) {
2105
+ throw new Error('Save or undo your changes before adding a page');
2106
+ }
2107
+ setState({
2108
+ prompting: true
2109
+ });
2110
+ try {
2111
+ const made = await api('collection-pages', {
2112
+ collection: {
2113
+ id: collection.id,
2114
+ handle: collection.handle
2115
+ }
2116
+ });
2117
+ // The site's collection route finds its page now (drafts, while
2118
+ // editing): show it.
2119
+ win.location.reload();
2120
+ return made;
2121
+ } finally{
2122
+ setState({
2123
+ prompting: false
2124
+ });
2125
+ }
2126
+ },
1923
2127
  async view (options = {}) {
1924
2128
  const { uid, entryId } = target(options.uid);
1925
2129
  const entry = await load(entryId);
@@ -2073,8 +2277,9 @@ const createSiteBridge = (win, basePath, { pagePath = (path)=>`/${path}`, produc
2073
2277
  contentType: page.contentType,
2074
2278
  status: page.status,
2075
2279
  path,
2076
- url: page.product ? productPath(page.product.handle, code) : pagePath(path, code),
2077
- product: page.product ?? null
2280
+ url: page.product ? productPath(page.product.handle, code) : page.collection ? collectionPath(page.collection.handle, code) : pagePath(path, code),
2281
+ product: page.product ?? null,
2282
+ collection: page.collection ?? null
2078
2283
  }
2079
2284
  ];
2080
2285
  });
@@ -2219,7 +2424,7 @@ const peekContentBridge = ()=>typeof window === 'undefined' ? null : window[KEY]
2219
2424
  // if (bridge.isEditing) bridge.on('update', ({ entry }) => render(entry))
2220
2425
  //
2221
2426
  // The first call's options win: there is one bridge per page.
2222
- const getContentBridge = ({ url, prompt = true, pagePath, productPath } = {})=>{
2427
+ const getContentBridge = ({ url, prompt = true, pagePath, productPath, collectionPath } = {})=>{
2223
2428
  if (typeof window === 'undefined') return SERVER_BRIDGE;
2224
2429
  const win = window;
2225
2430
  if (win[KEY]) return win[KEY];
@@ -2233,12 +2438,26 @@ const getContentBridge = ({ url, prompt = true, pagePath, productPath } = {})=>{
2233
2438
  const sitePath = bridge.isEditing || win.parent !== win ? null : readSiteEditing(win.document);
2234
2439
  if (sitePath) bridge = createSiteBridge(win, sitePath, {
2235
2440
  pagePath,
2236
- productPath
2441
+ productPath,
2442
+ collectionPath
2237
2443
  });
2238
2444
  if (bridge.isEditing && prompt) {
2239
- const unmount = mountPromptBox(win.document, bridge, prompt === true ? {} : prompt);
2445
+ const doc = win.document;
2446
+ let unmount = ()=>{};
2447
+ let destroyed = false;
2448
+ const mount = ()=>{
2449
+ if (destroyed) return;
2450
+ unmount = mountPromptBox(doc, bridge, prompt === true ? {} : prompt);
2451
+ };
2452
+ // A script tag in <head> runs before there is a body to mount into.
2453
+ if (doc.body) mount();
2454
+ else doc.addEventListener('DOMContentLoaded', mount, {
2455
+ once: true
2456
+ });
2240
2457
  const destroy = bridge.destroy;
2241
2458
  bridge.destroy = ()=>{
2459
+ destroyed = true;
2460
+ doc.removeEventListener('DOMContentLoaded', mount);
2242
2461
  unmount();
2243
2462
  destroy();
2244
2463
  };
package/dist/index.d.mts CHANGED
@@ -80,6 +80,14 @@ declare const editableProduct: (product: {
80
80
  id: string;
81
81
  handle: string;
82
82
  } | null | undefined) => EditableProduct;
83
+ type EditableCollection = {
84
+ 'data-cms-collection'?: string;
85
+ 'data-cms-collection-handle'?: string;
86
+ };
87
+ declare const editableCollection: (collection: {
88
+ id: string;
89
+ handle: string;
90
+ } | null | undefined) => EditableCollection;
83
91
 
84
92
  declare class ContentApiError extends Error {
85
93
  readonly status: number;
@@ -195,6 +203,6 @@ type SitemapOptions = LocalizedUrlOptions & {
195
203
  };
196
204
  declare const sitemapXml: (entries: Iterable<Page>, { exclude, ...options }: SitemapOptions) => string;
197
205
 
198
- export { Asset, Block, ContentApiError, ContentClient, DEFAULT_URL, ENTRY_ATTRIBUTE, Entry, EntryList, EntryStub, IMPROVE_BLOCK, ImproveBlock, Link, LinkTarget, ModelFile, PREVIEW_PARAMS, PRODUCT_ATTRIBUTE, PRODUCT_HANDLE_ATTRIBUTE, Redirect, RedirectList, RichTextFormat, RichTextNode, SAFE_HREF, SHOPIFY_STOREFRONT_API_VERSION, ShopifyItem, ShopifyStorefrontError, UID_ATTRIBUTE, alternateLinks, editable, editableProduct, escapeHtml, fetchShopifyCollection, fetchShopifyProducts, headingLevel, imageSrcSet, imageUrl, isImproveBlock, linkHref, pickImproveVariant, readPreviewParams, richTextToHtml, richTextToPlainText, sitemapXml };
206
+ export { Asset, Block, ContentApiError, ContentClient, DEFAULT_URL, ENTRY_ATTRIBUTE, Entry, EntryList, EntryStub, IMPROVE_BLOCK, ImproveBlock, Link, LinkTarget, ModelFile, PREVIEW_PARAMS, PRODUCT_ATTRIBUTE, PRODUCT_HANDLE_ATTRIBUTE, Redirect, RedirectList, RichTextFormat, RichTextNode, SAFE_HREF, SHOPIFY_STOREFRONT_API_VERSION, ShopifyItem, ShopifyStorefrontError, UID_ATTRIBUTE, alternateLinks, editable, editableCollection, editableProduct, escapeHtml, fetchShopifyCollection, fetchShopifyProducts, headingLevel, imageSrcSet, imageUrl, isImproveBlock, linkHref, pickImproveVariant, readPreviewParams, richTextToHtml, richTextToPlainText, sitemapXml };
199
207
  export type { AlternateLink, ContentClientOptions, EntriesQuery, ImageTransform, LinkHrefOptions, LocalizedUrlOptions, PageLookup, PreviewParams, RedirectsQuery, RequestOptions, RichTextHtmlOptions, ShopifyCollection, ShopifyImage, ShopifyMoney, ShopifyProduct, ShopifyStorefrontOptions, SitemapOptions };
200
208
  //# sourceMappingURL=index.d.mts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.mts","sources":["../src/client.ts","../src/config.ts","../src/editable.ts","../src/errors.ts","../src/images.ts","../src/improve.ts","../src/links.ts","../src/preview.ts","../src/shopify.ts","../src/richText.ts","../src/sitemap.ts"],"mappings":"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","names":[]}
1
+ {"version":3,"file":"index.d.mts","sources":["../src/client.ts","../src/config.ts","../src/editable.ts","../src/errors.ts","../src/images.ts","../src/improve.ts","../src/links.ts","../src/preview.ts","../src/shopify.ts","../src/richText.ts","../src/sitemap.ts"],"mappings":";;;AACA,KAAK,oBAAoB;AACzB;AACA;AACA;AACA;AACA,eAAe,cAAc;AAC7B;AACA,WAAW,WAAW;AACtB,mBAAmB,KAAK;AACxB;AACA,KAAK,cAAc;AACnB;AACA;AACA,eAAe,cAAc;AAC7B,WAAW,WAAW;AACtB;AACA,KAAK,gBAAgB;AACrB,KAAK,YAAY,GAAG,cAAc;AAClC;AACA;AACA,aAAa,MAAM,SAAS,gBAAgB,YAAY,gBAAgB;AACxE;AACA;AACA;AACA;AACA,KAAK,cAAc;AACnB;AACA;AACA;AACA,WAAW,WAAW;AACtB;AACA,KAAK,UAAU,gBAAgB,KAAK,GAAG,KAAK;AAC5C;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,cAAc,aAAa;AAC3B;AACA;AACA,2FAA2F,oBAAoB;AAC/G,6BAA6B,KAAK,GAAG,KAAK,0BAA0B,cAAc,KAAK,OAAO;AAC9F,8BAA8B,KAAK,GAAG,KAAK,0BAA0B,cAAc,KAAK,OAAO,CAAC,UAAU;AAC1G,oDAAoD,cAAc,KAAK,OAAO,CAAC,YAAY;AAC3F,4BAA4B,IAAI,CAAC,cAAc,YAAY,cAAc,CAAC,QAAQ;AAClF,8BAA8B,KAAK,GAAG,KAAK,wBAAwB,cAAc,KAAK,OAAO;AAC7F,gCAAgC,KAAK,GAAG,KAAK,wEAAwE,YAAY,KAAK,OAAO,CAAC,SAAS;AACvJ,mCAAmC,KAAK,GAAG,KAAK,UAAU,IAAI,CAAC,YAAY,wBAAwB,OAAO;AAC1G,iCAAiC,KAAK,GAAG,KAAK,UAAU,IAAI,CAAC,YAAY,YAAY,cAAc;AACnG,gCAAgC,IAAI,CAAC,cAAc,cAAc,OAAO,CAAC,SAAS;AAClF;;ACtDA,cAAc,WAAW;;ACAzB,cAAc,aAAa;AAC3B,cAAc,eAAe;AAC7B,cAAc,iBAAiB;AAC/B,cAAc,wBAAwB;AAGtC,KAAK,QAAQ;AACb;AACA;AACA;AACA,cAAc,QAAQ;AACtB;AACA;AACA;AACA;AACA,yBAAyB,QAAQ;AACjC,KAAK,eAAe;AACpB;AACA;AACA;AACA,cAAc,eAAe;AAC7B;AACA;AACA,yBAAyB,eAAe;AACxC,KAAK,kBAAkB;AACvB;AACA;AACA;AACA,cAAc,kBAAkB;AAChC;AACA;AACA,yBAAyB,kBAAkB;;AC/B3C,cAAc,eAAe,SAAS,KAAK;AAC3C;AACA;AACA;AACA;AACA;;ACJA,KAAK,cAAc;AACnB;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,cAAc,QAAQ,WAAW,IAAI,CAAC,KAAK,WAAW,OAAO,CAAC,IAAI,CAAC,KAAK,wCAAwC,cAAc;AAC9H,cAAc,WAAW,WAAW,IAAI,CAAC,KAAK,WAAW,OAAO,CAAC,IAAI,CAAC,KAAK,0DAA0D,IAAI,CAAC,cAAc;;ACZxJ,cAAc,aAAa;AAC3B,cAAc,cAAc,UAAU,KAAK,cAAc,YAAY;AACrE,cAAc,kBAAkB,kBAAkB,KAAK,SAAS,YAAY;;ACF5E,KAAK,eAAe;AACpB;AACA,yBAAyB,WAAW,QAAQ,UAAU;AACtD;AACA,cAAc,QAAQ,SAAS,IAAI,yCAAyC,eAAe;;ACL3F,cAAc,cAAc;AAC5B;AACA;AACA;AACA;AACA;AACA,KAAK,aAAa;AAClB;AACA;AACA;AACA;AACA,KAAK,iBAAiB,GAAG,GAAG,GAAG,eAAe,YAAY,MAAM;AAChE,cAAc,iBAAiB,UAAU,iBAAiB,KAAK,aAAa;;ACX5E,cAAc,8BAA8B;AAC5C,KAAK,wBAAwB;AAC7B;AACA;AACA;AACA;AACA,WAAW,WAAW;AACtB,mBAAmB,KAAK;AACxB;AACA,KAAK,YAAY;AACjB;AACA;AACA;AACA,KAAK,YAAY;AACjB;AACA;AACA;AACA;AACA;AACA,KAAK,cAAc;AACnB;AACA;AACA;AACA;AACA,mBAAmB,YAAY;AAC/B;AACA,yBAAyB,YAAY;AACrC;AACA;AACA,KAAK,iBAAiB;AACtB;AACA;AACA;AACA,cAAc,cAAc;AAC5B;AACA,cAAc,sBAAsB,SAAS,KAAK;AAClD;AACA;AACA;AACA,cAAc,sBAAsB,SAAS,WAAW,WAAW,wBAAwB;AAC3F;AACA,MAAM,OAAO,CAAC,iBAAiB;AAC/B,cAAc,oBAAoB,UAAU,WAAW,GAAG,WAAW,gCAAgC,wBAAwB,KAAK,OAAO,CAAC,cAAc;;AC1CxJ,cAAc,SAAS,EAAE,MAAM;AAC/B,cAAc,UAAU;AACxB,KAAK,mBAAmB;AACxB,0BAA0B,KAAK,GAAG,SAAS,QAAQ,YAAY;AAC/D,0BAA0B,KAAK,QAAQ,YAAY;AACnD;AACA,cAAc,cAAc,QAAQ,YAAY,oDAAoD,mBAAmB;AACvH,cAAc,YAAY,SAAS,YAAY;AAC/C,cAAc,mBAAmB,QAAQ,YAAY;;ACRrD,KAAK,mBAAmB;AACxB;AACA;AACA;AACA,KAAK,aAAa;AAClB;AACA;AACA;AACA,KAAK,IAAI,GAAG,IAAI,CAAC,KAAK,aAAa,OAAO,CAAC,IAAI,CAAC,KAAK;AACrD,cAAc,cAAc,UAAU,IAAI,CAAC,KAAK,oCAAoC,mBAAmB,KAAK,aAAa;AACzH,KAAK,cAAc,GAAG,mBAAmB;AACzC,uBAAuB,IAAI;AAC3B;AACA,cAAc,UAAU,YAAY,QAAQ,CAAC,IAAI,4BAA4B,cAAc;;","names":[]}
package/dist/index.d.ts CHANGED
@@ -80,6 +80,14 @@ declare const editableProduct: (product: {
80
80
  id: string;
81
81
  handle: string;
82
82
  } | null | undefined) => EditableProduct;
83
+ type EditableCollection = {
84
+ 'data-cms-collection'?: string;
85
+ 'data-cms-collection-handle'?: string;
86
+ };
87
+ declare const editableCollection: (collection: {
88
+ id: string;
89
+ handle: string;
90
+ } | null | undefined) => EditableCollection;
83
91
 
84
92
  declare class ContentApiError extends Error {
85
93
  readonly status: number;
@@ -195,6 +203,6 @@ type SitemapOptions = LocalizedUrlOptions & {
195
203
  };
196
204
  declare const sitemapXml: (entries: Iterable<Page>, { exclude, ...options }: SitemapOptions) => string;
197
205
 
198
- export { Asset, Block, ContentApiError, ContentClient, DEFAULT_URL, ENTRY_ATTRIBUTE, Entry, EntryList, EntryStub, IMPROVE_BLOCK, ImproveBlock, Link, LinkTarget, ModelFile, PREVIEW_PARAMS, PRODUCT_ATTRIBUTE, PRODUCT_HANDLE_ATTRIBUTE, Redirect, RedirectList, RichTextFormat, RichTextNode, SAFE_HREF, SHOPIFY_STOREFRONT_API_VERSION, ShopifyItem, ShopifyStorefrontError, UID_ATTRIBUTE, alternateLinks, editable, editableProduct, escapeHtml, fetchShopifyCollection, fetchShopifyProducts, headingLevel, imageSrcSet, imageUrl, isImproveBlock, linkHref, pickImproveVariant, readPreviewParams, richTextToHtml, richTextToPlainText, sitemapXml };
206
+ export { Asset, Block, ContentApiError, ContentClient, DEFAULT_URL, ENTRY_ATTRIBUTE, Entry, EntryList, EntryStub, IMPROVE_BLOCK, ImproveBlock, Link, LinkTarget, ModelFile, PREVIEW_PARAMS, PRODUCT_ATTRIBUTE, PRODUCT_HANDLE_ATTRIBUTE, Redirect, RedirectList, RichTextFormat, RichTextNode, SAFE_HREF, SHOPIFY_STOREFRONT_API_VERSION, ShopifyItem, ShopifyStorefrontError, UID_ATTRIBUTE, alternateLinks, editable, editableCollection, editableProduct, escapeHtml, fetchShopifyCollection, fetchShopifyProducts, headingLevel, imageSrcSet, imageUrl, isImproveBlock, linkHref, pickImproveVariant, readPreviewParams, richTextToHtml, richTextToPlainText, sitemapXml };
199
207
  export type { AlternateLink, ContentClientOptions, EntriesQuery, ImageTransform, LinkHrefOptions, LocalizedUrlOptions, PageLookup, PreviewParams, RedirectsQuery, RequestOptions, RichTextHtmlOptions, ShopifyCollection, ShopifyImage, ShopifyMoney, ShopifyProduct, ShopifyStorefrontOptions, SitemapOptions };
200
208
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sources":["../src/client.ts","../src/config.ts","../src/editable.ts","../src/errors.ts","../src/images.ts","../src/improve.ts","../src/links.ts","../src/preview.ts","../src/shopify.ts","../src/richText.ts","../src/sitemap.ts"],"mappings":"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","names":[]}
1
+ {"version":3,"file":"index.d.ts","sources":["../src/client.ts","../src/config.ts","../src/editable.ts","../src/errors.ts","../src/images.ts","../src/improve.ts","../src/links.ts","../src/preview.ts","../src/shopify.ts","../src/richText.ts","../src/sitemap.ts"],"mappings":"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","names":[]}
package/dist/index.js CHANGED
@@ -1,7 +1,7 @@
1
1
  Object.defineProperty(exports, '__esModule', { value: true });
2
2
 
3
3
  var config = require('./config-ci2hxmas.js');
4
- var preview = require('./preview-ijk3ixwb.js');
4
+ var preview = require('./preview-ooq8w3jv.js');
5
5
 
6
6
  // A response from the API that wasn't a success. `message` is the API's own
7
7
  // `error` text when it sent one.
@@ -513,6 +513,7 @@ exports.PRODUCT_ATTRIBUTE = preview.PRODUCT_ATTRIBUTE;
513
513
  exports.PRODUCT_HANDLE_ATTRIBUTE = preview.PRODUCT_HANDLE_ATTRIBUTE;
514
514
  exports.UID_ATTRIBUTE = preview.UID_ATTRIBUTE;
515
515
  exports.editable = preview.editable;
516
+ exports.editableCollection = preview.editableCollection;
516
517
  exports.editableProduct = preview.editableProduct;
517
518
  exports.readPreviewParams = preview.readPreviewParams;
518
519
  exports.ContentApiError = ContentApiError;
package/dist/index.mjs CHANGED
@@ -1,5 +1,5 @@
1
1
  import { n as normalizeUrl, a as DEFAULT_TIMEOUT, b as DELIVERY_PATH, D as DEFAULT_URL } from './config-c6qktlz6.mjs';
2
- export { E as ENTRY_ATTRIBUTE, P as PREVIEW_PARAMS, a as PRODUCT_ATTRIBUTE, b as PRODUCT_HANDLE_ATTRIBUTE, U as UID_ATTRIBUTE, e as editable, c as editableProduct, r as readPreviewParams } from './preview-jcmxxj92.mjs';
2
+ export { E as ENTRY_ATTRIBUTE, P as PREVIEW_PARAMS, b as PRODUCT_ATTRIBUTE, c as PRODUCT_HANDLE_ATTRIBUTE, U as UID_ATTRIBUTE, e as editable, d as editableCollection, f as editableProduct, r as readPreviewParams } from './preview-fu3qtgfx.mjs';
3
3
 
4
4
  // A response from the API that wasn't a success. `message` is the API's own
5
5
  // `error` text when it sent one.
@@ -2,6 +2,8 @@ const UID_ATTRIBUTE = 'data-cms-uid';
2
2
  const ENTRY_ATTRIBUTE = 'data-cms-entry';
3
3
  const PRODUCT_ATTRIBUTE = 'data-cms-product';
4
4
  const PRODUCT_HANDLE_ATTRIBUTE = 'data-cms-product-handle';
5
+ const COLLECTION_ATTRIBUTE = 'data-cms-collection';
6
+ const COLLECTION_HANDLE_ATTRIBUTE = 'data-cms-collection-handle';
5
7
  // The attribute that lets editors select a block on the page, in the visual
6
8
  // editor and on the site. Spread it on the block's outermost element:
7
9
  //
@@ -36,6 +38,18 @@ const editableProduct = (product)=>product?.id ? {
36
38
  'data-cms-product': product.id,
37
39
  'data-cms-product-handle': product.handle
38
40
  } : {};
41
+ // The Shopify collection a page shows, on a collection route: editing on the
42
+ // site then offers "Add a collection page" when the page has no collection
43
+ // page yet (no `editable(entry)`), and makes one for this collection.
44
+ //
45
+ // <main {...editableCollection(collection)} {...editable(page)}>…</main>
46
+ //
47
+ // `collection` is the store's (its GID and handle), from the Storefront API
48
+ // or a Shopify field.
49
+ const editableCollection = (collection)=>collection?.id ? {
50
+ 'data-cms-collection': collection.id,
51
+ 'data-cms-collection-handle': collection.handle
52
+ } : {};
39
53
 
40
54
  // The visual editor loads the site in an iframe at the environment's preview
41
55
  // URL plus the entry's path, with these parameters added. `cms_token` is a
@@ -84,4 +98,4 @@ const readPreviewParams = (input)=>{
84
98
  };
85
99
  };
86
100
 
87
- export { ENTRY_ATTRIBUTE as E, PREVIEW_PARAMS as P, UID_ATTRIBUTE as U, PRODUCT_ATTRIBUTE as a, PRODUCT_HANDLE_ATTRIBUTE as b, editableProduct as c, editable as e, readPreviewParams as r };
101
+ export { COLLECTION_ATTRIBUTE as C, ENTRY_ATTRIBUTE as E, PREVIEW_PARAMS as P, UID_ATTRIBUTE as U, COLLECTION_HANDLE_ATTRIBUTE as a, PRODUCT_ATTRIBUTE as b, PRODUCT_HANDLE_ATTRIBUTE as c, editableCollection as d, editable as e, editableProduct as f, readPreviewParams as r };
@@ -2,6 +2,8 @@ const UID_ATTRIBUTE = 'data-cms-uid';
2
2
  const ENTRY_ATTRIBUTE = 'data-cms-entry';
3
3
  const PRODUCT_ATTRIBUTE = 'data-cms-product';
4
4
  const PRODUCT_HANDLE_ATTRIBUTE = 'data-cms-product-handle';
5
+ const COLLECTION_ATTRIBUTE = 'data-cms-collection';
6
+ const COLLECTION_HANDLE_ATTRIBUTE = 'data-cms-collection-handle';
5
7
  // The attribute that lets editors select a block on the page, in the visual
6
8
  // editor and on the site. Spread it on the block's outermost element:
7
9
  //
@@ -36,6 +38,18 @@ const editableProduct = (product)=>product?.id ? {
36
38
  'data-cms-product': product.id,
37
39
  'data-cms-product-handle': product.handle
38
40
  } : {};
41
+ // The Shopify collection a page shows, on a collection route: editing on the
42
+ // site then offers "Add a collection page" when the page has no collection
43
+ // page yet (no `editable(entry)`), and makes one for this collection.
44
+ //
45
+ // <main {...editableCollection(collection)} {...editable(page)}>…</main>
46
+ //
47
+ // `collection` is the store's (its GID and handle), from the Storefront API
48
+ // or a Shopify field.
49
+ const editableCollection = (collection)=>collection?.id ? {
50
+ 'data-cms-collection': collection.id,
51
+ 'data-cms-collection-handle': collection.handle
52
+ } : {};
39
53
 
40
54
  // The visual editor loads the site in an iframe at the environment's preview
41
55
  // URL plus the entry's path, with these parameters added. `cms_token` is a
@@ -84,11 +98,14 @@ const readPreviewParams = (input)=>{
84
98
  };
85
99
  };
86
100
 
101
+ exports.COLLECTION_ATTRIBUTE = COLLECTION_ATTRIBUTE;
102
+ exports.COLLECTION_HANDLE_ATTRIBUTE = COLLECTION_HANDLE_ATTRIBUTE;
87
103
  exports.ENTRY_ATTRIBUTE = ENTRY_ATTRIBUTE;
88
104
  exports.PREVIEW_PARAMS = PREVIEW_PARAMS;
89
105
  exports.PRODUCT_ATTRIBUTE = PRODUCT_ATTRIBUTE;
90
106
  exports.PRODUCT_HANDLE_ATTRIBUTE = PRODUCT_HANDLE_ATTRIBUTE;
91
107
  exports.UID_ATTRIBUTE = UID_ATTRIBUTE;
92
108
  exports.editable = editable;
109
+ exports.editableCollection = editableCollection;
93
110
  exports.editableProduct = editableProduct;
94
111
  exports.readPreviewParams = readPreviewParams;