@weaverse/next 0.1.0-alpha.8 → 0.1.0-alpha.9

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/index.d.mts CHANGED
@@ -1,8 +1,8 @@
1
- import { Weaverse } from '@weaverse/react';
1
+ import { WeaverseItemStore, Weaverse, ElementData } from '@weaverse/react';
2
2
  export { isBrowser, isIframe, useChildInstances, useItemInstance, useParentInstance, useWeaverse } from '@weaverse/react';
3
3
  export { InspectorGroup, PageType, SchemaType, createSchema } from '@weaverse/schema';
4
- import { h as WeaverseNextClientConfig, g as WeaverseNextClient, i as WeaverseNextCommerceContext, x as WeaverseNextRequestContext, t as WeaverseNextLoaderData, a as TranslationStore, y as WeaverseNextRequestInfo, k as WeaverseNextComponentData, I as WeaverseNextThemeSettingsStore, A as WeaverseNextRuntimeInternal, M as WeaverseNextTranslationMap, z as WeaverseNextRuntimeConfig, J as WeaverseNextTranslationChanges, v as WeaverseNextPageData } from './seo-CpN6tC36.mjs';
5
- export { T as ThemeTextStore, W as WeaverseArticle, b as WeaverseBlog, c as WeaverseCollection, d as WeaverseMetaObject, j as WeaverseNextComponent, l as WeaverseNextComponentLoaderArgs, m as WeaverseNextComponentProps, o as WeaverseNextCustomPageEntry, p as WeaverseNextFetchCustomPagesOptions, r as WeaverseNextI18n, s as WeaverseNextLoadPageInput, u as WeaverseNextPageAssignment, B as WeaverseNextSeoMetadata, F as WeaverseNextStorefront, K as WeaverseNextTranslationEntry, L as WeaverseNextTranslationItemEntry, N as WeaverseNextTranslationMapEntry, O as WeaverseProduct, P as formatWeaverseNextSeoMetadata, Q as getWeaverseNextSeoMetadata } from './seo-CpN6tC36.mjs';
4
+ import { h as WeaverseNextClientConfig, g as WeaverseNextClient, i as WeaverseNextCommerceContext, x as WeaverseNextRequestContext, t as WeaverseNextLoaderData, a as TranslationStore, y as WeaverseNextRequestInfo, k as WeaverseNextComponentData, I as WeaverseNextThemeSettingsStore, A as WeaverseNextRuntimeInternal, M as WeaverseNextTranslationMap, v as WeaverseNextPageData, z as WeaverseNextRuntimeConfig, J as WeaverseNextTranslationChanges } from './seo-Dos9t22_.mjs';
5
+ export { T as ThemeTextStore, W as WeaverseArticle, b as WeaverseBlog, c as WeaverseCollection, d as WeaverseMetaObject, j as WeaverseNextComponent, l as WeaverseNextComponentLoaderArgs, m as WeaverseNextComponentProps, o as WeaverseNextCustomPageEntry, p as WeaverseNextFetchCustomPagesOptions, r as WeaverseNextI18n, s as WeaverseNextLoadPageInput, u as WeaverseNextPageAssignment, B as WeaverseNextSeoMetadata, F as WeaverseNextStorefront, K as WeaverseNextTranslationEntry, L as WeaverseNextTranslationItemEntry, N as WeaverseNextTranslationMapEntry, O as WeaverseProduct, P as formatWeaverseNextSeoMetadata, Q as getWeaverseNextSeoMetadata } from './seo-Dos9t22_.mjs';
6
6
  import * as react_jsx_runtime from 'react/jsx-runtime';
7
7
  import * as react from 'react';
8
8
  import { ReactNode } from 'react';
@@ -331,6 +331,43 @@ interface WeaverseNextRootProviderProps {
331
331
  */
332
332
  declare function WeaverseNextRootProvider(props: WeaverseNextRootProviderProps): react_jsx_runtime.JSX.Element;
333
333
 
334
+ /**
335
+ * Item store that flattens the serialized item's nested `data` field onto the
336
+ * store and seeds schema defaults — same shape Hydrogen produces, so the
337
+ * shared `@weaverse/react` renderer can spread props at the top level.
338
+ */
339
+ declare class WeaverseNextItem extends WeaverseItemStore {
340
+ weaverse: WeaverseNextRuntime;
341
+ /**
342
+ * Cached merged snapshot (base `_store` + translations). Reset whenever the
343
+ * `_store` ref or the item's translation entry ref changes, so
344
+ * `useSyncExternalStore` sees a stable object between unrelated re-renders.
345
+ */
346
+ private _cachedSnapshot;
347
+ private _snapshotStoreRef;
348
+ private _snapshotTranslationRef;
349
+ constructor(initialData: WeaverseNextComponentData, weaverse: Weaverse);
350
+ /**
351
+ * Flatten nested `data` on updates exactly like the constructor does. Core's
352
+ * `initProject()` calls `setData(item)` when a new runtime serves a page
353
+ * whose item instances already exist (e.g. locale/client navigation), and
354
+ * the inherited shallow merge would leave stale top-level props behind.
355
+ * Assigning through the inherited `data` setter swaps the `_store` ref,
356
+ * which invalidates the memoized snapshot below. The subscriber emit is
357
+ * queued instead of fired when a render-phase deferral is active (see
358
+ * `collectDeferredItemUpdates`).
359
+ */
360
+ setData: (update: Omit<ElementData, "id" | "type">) => ElementData;
361
+ /**
362
+ * Overlay item-level translations onto the base store when the runtime is in
363
+ * translation mode. Mirrors Hydrogen's `WeaverseHydrogenItem.getSnapShot()`:
364
+ * memoized by `_store` ref + translation entry ref so the returned object is
365
+ * referentially stable, and a fast path that returns the base store untouched
366
+ * when the item has no translations.
367
+ */
368
+ getSnapShot: () => ElementData;
369
+ }
370
+
334
371
  declare global {
335
372
  interface Window {
336
373
  __weaverse?: WeaverseNextRuntime;
@@ -352,6 +389,24 @@ declare class WeaverseNextRuntime extends Weaverse {
352
389
  translationMap: WeaverseNextTranslationMap;
353
390
  translationLocale: string;
354
391
  translationLanguageId: string;
392
+ /**
393
+ * Fresh page data captured while React was rendering. Runtime reuse happens
394
+ * inside the renderer's render phase (`useMemo`), where applying it through
395
+ * `setProjectData()` would emit item updates to `useSyncExternalStore`
396
+ * subscribers mid-render. The renderer applies it post-commit via
397
+ * `flushRenderPhaseUpdates()`. Never set on design-mode runtimes — the live
398
+ * Studio tree owns the page data there.
399
+ */
400
+ pendingProjectData?: WeaverseNextPageData & {
401
+ rootId: string;
402
+ };
403
+ /**
404
+ * Reused item instances whose data was refreshed while this runtime was
405
+ * constructed during render (core `initProject()` calls `setData()` on
406
+ * them). Their data is already fresh; only the subscriber notification was
407
+ * deferred to `flushRenderPhaseUpdates()`.
408
+ */
409
+ pendingItemUpdates: WeaverseNextItem[];
355
410
  constructor(config: WeaverseNextRuntimeConfig);
356
411
  /**
357
412
  * Pull `translationMap` / `translationLocale` / `translationLanguageId` off
@@ -388,6 +443,14 @@ declare class WeaverseNextRuntime extends Weaverse {
388
443
  setProjectData: (data: WeaverseNextPageData & {
389
444
  rootId: string;
390
445
  }) => void;
446
+ /**
447
+ * Apply updates deferred off the render phase: swap in any pending page data
448
+ * captured on runtime reuse, then notify items whose data was refreshed
449
+ * during construction. The renderer calls this from a layout effect right
450
+ * after commit, so subscribers re-render before paint (no content flash) and
451
+ * without React's setState-in-render warning.
452
+ */
453
+ flushRenderPhaseUpdates: () => void;
391
454
  }
392
455
  declare function createWeaverseNextRuntime(config: WeaverseNextRuntimeConfig): WeaverseNextRuntime;
393
456
  declare function bindWeaverseNextStudioRuntime(runtime: WeaverseNextRuntime): boolean;
package/dist/index.d.ts CHANGED
@@ -1,8 +1,8 @@
1
- import { Weaverse } from '@weaverse/react';
1
+ import { WeaverseItemStore, Weaverse, ElementData } from '@weaverse/react';
2
2
  export { isBrowser, isIframe, useChildInstances, useItemInstance, useParentInstance, useWeaverse } from '@weaverse/react';
3
3
  export { InspectorGroup, PageType, SchemaType, createSchema } from '@weaverse/schema';
4
- import { h as WeaverseNextClientConfig, g as WeaverseNextClient, i as WeaverseNextCommerceContext, x as WeaverseNextRequestContext, t as WeaverseNextLoaderData, a as TranslationStore, y as WeaverseNextRequestInfo, k as WeaverseNextComponentData, I as WeaverseNextThemeSettingsStore, A as WeaverseNextRuntimeInternal, M as WeaverseNextTranslationMap, z as WeaverseNextRuntimeConfig, J as WeaverseNextTranslationChanges, v as WeaverseNextPageData } from './seo-CpN6tC36.js';
5
- export { T as ThemeTextStore, W as WeaverseArticle, b as WeaverseBlog, c as WeaverseCollection, d as WeaverseMetaObject, j as WeaverseNextComponent, l as WeaverseNextComponentLoaderArgs, m as WeaverseNextComponentProps, o as WeaverseNextCustomPageEntry, p as WeaverseNextFetchCustomPagesOptions, r as WeaverseNextI18n, s as WeaverseNextLoadPageInput, u as WeaverseNextPageAssignment, B as WeaverseNextSeoMetadata, F as WeaverseNextStorefront, K as WeaverseNextTranslationEntry, L as WeaverseNextTranslationItemEntry, N as WeaverseNextTranslationMapEntry, O as WeaverseProduct, P as formatWeaverseNextSeoMetadata, Q as getWeaverseNextSeoMetadata } from './seo-CpN6tC36.js';
4
+ import { h as WeaverseNextClientConfig, g as WeaverseNextClient, i as WeaverseNextCommerceContext, x as WeaverseNextRequestContext, t as WeaverseNextLoaderData, a as TranslationStore, y as WeaverseNextRequestInfo, k as WeaverseNextComponentData, I as WeaverseNextThemeSettingsStore, A as WeaverseNextRuntimeInternal, M as WeaverseNextTranslationMap, v as WeaverseNextPageData, z as WeaverseNextRuntimeConfig, J as WeaverseNextTranslationChanges } from './seo-Dos9t22_.js';
5
+ export { T as ThemeTextStore, W as WeaverseArticle, b as WeaverseBlog, c as WeaverseCollection, d as WeaverseMetaObject, j as WeaverseNextComponent, l as WeaverseNextComponentLoaderArgs, m as WeaverseNextComponentProps, o as WeaverseNextCustomPageEntry, p as WeaverseNextFetchCustomPagesOptions, r as WeaverseNextI18n, s as WeaverseNextLoadPageInput, u as WeaverseNextPageAssignment, B as WeaverseNextSeoMetadata, F as WeaverseNextStorefront, K as WeaverseNextTranslationEntry, L as WeaverseNextTranslationItemEntry, N as WeaverseNextTranslationMapEntry, O as WeaverseProduct, P as formatWeaverseNextSeoMetadata, Q as getWeaverseNextSeoMetadata } from './seo-Dos9t22_.js';
6
6
  import * as react_jsx_runtime from 'react/jsx-runtime';
7
7
  import * as react from 'react';
8
8
  import { ReactNode } from 'react';
@@ -331,6 +331,43 @@ interface WeaverseNextRootProviderProps {
331
331
  */
332
332
  declare function WeaverseNextRootProvider(props: WeaverseNextRootProviderProps): react_jsx_runtime.JSX.Element;
333
333
 
334
+ /**
335
+ * Item store that flattens the serialized item's nested `data` field onto the
336
+ * store and seeds schema defaults — same shape Hydrogen produces, so the
337
+ * shared `@weaverse/react` renderer can spread props at the top level.
338
+ */
339
+ declare class WeaverseNextItem extends WeaverseItemStore {
340
+ weaverse: WeaverseNextRuntime;
341
+ /**
342
+ * Cached merged snapshot (base `_store` + translations). Reset whenever the
343
+ * `_store` ref or the item's translation entry ref changes, so
344
+ * `useSyncExternalStore` sees a stable object between unrelated re-renders.
345
+ */
346
+ private _cachedSnapshot;
347
+ private _snapshotStoreRef;
348
+ private _snapshotTranslationRef;
349
+ constructor(initialData: WeaverseNextComponentData, weaverse: Weaverse);
350
+ /**
351
+ * Flatten nested `data` on updates exactly like the constructor does. Core's
352
+ * `initProject()` calls `setData(item)` when a new runtime serves a page
353
+ * whose item instances already exist (e.g. locale/client navigation), and
354
+ * the inherited shallow merge would leave stale top-level props behind.
355
+ * Assigning through the inherited `data` setter swaps the `_store` ref,
356
+ * which invalidates the memoized snapshot below. The subscriber emit is
357
+ * queued instead of fired when a render-phase deferral is active (see
358
+ * `collectDeferredItemUpdates`).
359
+ */
360
+ setData: (update: Omit<ElementData, "id" | "type">) => ElementData;
361
+ /**
362
+ * Overlay item-level translations onto the base store when the runtime is in
363
+ * translation mode. Mirrors Hydrogen's `WeaverseHydrogenItem.getSnapShot()`:
364
+ * memoized by `_store` ref + translation entry ref so the returned object is
365
+ * referentially stable, and a fast path that returns the base store untouched
366
+ * when the item has no translations.
367
+ */
368
+ getSnapShot: () => ElementData;
369
+ }
370
+
334
371
  declare global {
335
372
  interface Window {
336
373
  __weaverse?: WeaverseNextRuntime;
@@ -352,6 +389,24 @@ declare class WeaverseNextRuntime extends Weaverse {
352
389
  translationMap: WeaverseNextTranslationMap;
353
390
  translationLocale: string;
354
391
  translationLanguageId: string;
392
+ /**
393
+ * Fresh page data captured while React was rendering. Runtime reuse happens
394
+ * inside the renderer's render phase (`useMemo`), where applying it through
395
+ * `setProjectData()` would emit item updates to `useSyncExternalStore`
396
+ * subscribers mid-render. The renderer applies it post-commit via
397
+ * `flushRenderPhaseUpdates()`. Never set on design-mode runtimes — the live
398
+ * Studio tree owns the page data there.
399
+ */
400
+ pendingProjectData?: WeaverseNextPageData & {
401
+ rootId: string;
402
+ };
403
+ /**
404
+ * Reused item instances whose data was refreshed while this runtime was
405
+ * constructed during render (core `initProject()` calls `setData()` on
406
+ * them). Their data is already fresh; only the subscriber notification was
407
+ * deferred to `flushRenderPhaseUpdates()`.
408
+ */
409
+ pendingItemUpdates: WeaverseNextItem[];
355
410
  constructor(config: WeaverseNextRuntimeConfig);
356
411
  /**
357
412
  * Pull `translationMap` / `translationLocale` / `translationLanguageId` off
@@ -388,6 +443,14 @@ declare class WeaverseNextRuntime extends Weaverse {
388
443
  setProjectData: (data: WeaverseNextPageData & {
389
444
  rootId: string;
390
445
  }) => void;
446
+ /**
447
+ * Apply updates deferred off the render phase: swap in any pending page data
448
+ * captured on runtime reuse, then notify items whose data was refreshed
449
+ * during construction. The renderer calls this from a layout effect right
450
+ * after commit, so subscribers re-render before paint (no content flash) and
451
+ * without React's setState-in-render warning.
452
+ */
453
+ flushRenderPhaseUpdates: () => void;
391
454
  }
392
455
  declare function createWeaverseNextRuntime(config: WeaverseNextRuntimeConfig): WeaverseNextRuntime;
393
456
  declare function bindWeaverseNextStudioRuntime(runtime: WeaverseNextRuntime): boolean;
package/dist/index.js CHANGED
@@ -27,6 +27,24 @@ function generateDataFromSchema(schema) {
27
27
  }
28
28
 
29
29
  // src/item.ts
30
+ function flattenItemData(update) {
31
+ let { data, ...rest } = update;
32
+ if (!(data && typeof data === "object" && !Array.isArray(data))) {
33
+ return rest;
34
+ }
35
+ return { ...data, ...rest };
36
+ }
37
+ var deferredItemUpdates = null;
38
+ function collectDeferredItemUpdates(create) {
39
+ let previousQueue = deferredItemUpdates;
40
+ let queue = /* @__PURE__ */ new Set();
41
+ deferredItemUpdates = queue;
42
+ try {
43
+ return [create(), [...queue]];
44
+ } finally {
45
+ deferredItemUpdates = previousQueue;
46
+ }
47
+ }
30
48
  var WeaverseNextItem = class extends react.WeaverseItemStore {
31
49
  /**
32
50
  * Cached merged snapshot (base `_store` + translations). Reset whenever the
@@ -38,10 +56,28 @@ var WeaverseNextItem = class extends react.WeaverseItemStore {
38
56
  _snapshotTranslationRef = null;
39
57
  constructor(initialData, weaverse) {
40
58
  super(initialData, weaverse);
41
- let { data, ...rest } = initialData;
42
59
  let schemaData = generateDataFromSchema(this.Element?.schema);
43
- Object.assign(this._store, schemaData, data, rest);
60
+ Object.assign(this._store, schemaData, flattenItemData(initialData));
44
61
  }
62
+ /**
63
+ * Flatten nested `data` on updates exactly like the constructor does. Core's
64
+ * `initProject()` calls `setData(item)` when a new runtime serves a page
65
+ * whose item instances already exist (e.g. locale/client navigation), and
66
+ * the inherited shallow merge would leave stale top-level props behind.
67
+ * Assigning through the inherited `data` setter swaps the `_store` ref,
68
+ * which invalidates the memoized snapshot below. The subscriber emit is
69
+ * queued instead of fired when a render-phase deferral is active (see
70
+ * `collectDeferredItemUpdates`).
71
+ */
72
+ setData = (update) => {
73
+ this.data = flattenItemData(update);
74
+ if (deferredItemUpdates) {
75
+ deferredItemUpdates.add(this);
76
+ } else {
77
+ this.triggerUpdate();
78
+ }
79
+ return this.data;
80
+ };
45
81
  /**
46
82
  * Overlay item-level translations onto the base store when the runtime is in
47
83
  * translation mode. Mirrors Hydrogen's `WeaverseHydrogenItem.getSnapShot()`:
@@ -681,6 +717,22 @@ var WeaverseNextRuntime = class extends react.Weaverse {
681
717
  translationMap = {};
682
718
  translationLocale = String();
683
719
  translationLanguageId = String();
720
+ /**
721
+ * Fresh page data captured while React was rendering. Runtime reuse happens
722
+ * inside the renderer's render phase (`useMemo`), where applying it through
723
+ * `setProjectData()` would emit item updates to `useSyncExternalStore`
724
+ * subscribers mid-render. The renderer applies it post-commit via
725
+ * `flushRenderPhaseUpdates()`. Never set on design-mode runtimes — the live
726
+ * Studio tree owns the page data there.
727
+ */
728
+ pendingProjectData;
729
+ /**
730
+ * Reused item instances whose data was refreshed while this runtime was
731
+ * constructed during render (core `initProject()` calls `setData()` on
732
+ * them). Their data is already fresh; only the subscriber notification was
733
+ * deferred to `flushRenderPhaseUpdates()`.
734
+ */
735
+ pendingItemUpdates = [];
684
736
  constructor(config) {
685
737
  let { client, data } = config;
686
738
  let page = getRenderablePage(data);
@@ -804,6 +856,27 @@ var WeaverseNextRuntime = class extends react.Weaverse {
804
856
  this.extractTranslationSidecar();
805
857
  this.initProject();
806
858
  };
859
+ /**
860
+ * Apply updates deferred off the render phase: swap in any pending page data
861
+ * captured on runtime reuse, then notify items whose data was refreshed
862
+ * during construction. The renderer calls this from a layout effect right
863
+ * after commit, so subscribers re-render before paint (no content flash) and
864
+ * without React's setState-in-render warning.
865
+ */
866
+ flushRenderPhaseUpdates = () => {
867
+ let pendingData = this.pendingProjectData;
868
+ if (pendingData) {
869
+ this.pendingProjectData = void 0;
870
+ this.setProjectData(pendingData);
871
+ }
872
+ let pendingItems = this.pendingItemUpdates;
873
+ if (pendingItems.length > 0) {
874
+ this.pendingItemUpdates = [];
875
+ for (let item of pendingItems) {
876
+ item.triggerUpdate();
877
+ }
878
+ }
879
+ };
807
880
  };
808
881
  function createWeaverseNextRuntime(config) {
809
882
  let requestInfo = buildWeaverseNextRequestInfo(config.client?.requestContext);
@@ -813,8 +886,10 @@ function createWeaverseNextRuntime(config) {
813
886
  let requestKey = getRuntimeKey(page.id, requestInfo);
814
887
  if (existing?.__weaverseNextRequestKey === requestKey) {
815
888
  let nextIsDesignMode = config.client?.requestContext?.isDesignMode ?? false;
816
- if (!(existing.isDesignMode || nextIsDesignMode)) {
817
- existing.setProjectData(page);
889
+ if (existing.isDesignMode || nextIsDesignMode) {
890
+ existing.pendingProjectData = void 0;
891
+ } else {
892
+ existing.pendingProjectData = page;
818
893
  }
819
894
  existing.__weaverseNextLatestData = page;
820
895
  existing.dataContext = resolveDataContext(config);
@@ -845,7 +920,10 @@ function createWeaverseNextRuntime(config) {
845
920
  registerRuntime(existing);
846
921
  return existing;
847
922
  }
848
- let runtime = new WeaverseNextRuntime(config);
923
+ let [runtime, refreshedItems] = collectDeferredItemUpdates(
924
+ () => new WeaverseNextRuntime(config)
925
+ );
926
+ runtime.pendingItemUpdates = refreshedItems;
849
927
  runtime.__weaverseNextRequestKey = requestKey;
850
928
  runtime.__weaverseNextLatestData = page;
851
929
  registerRuntime(runtime);
@@ -998,6 +1076,7 @@ function WeaverseNextStudio(props) {
998
1076
  );
999
1077
  }
1000
1078
  var EMPTY_DATA_CONTEXT = {};
1079
+ var useIsomorphicLayoutEffect = typeof window === "undefined" ? react$1.useEffect : react$1.useLayoutEffect;
1001
1080
  function getRenderablePage2(data) {
1002
1081
  let page = data?.page;
1003
1082
  if (!page) {
@@ -1033,6 +1112,9 @@ var WeaverseNextRenderer = react$1.memo(function WeaverseNextRendererComponent(p
1033
1112
  context?.themeSettingsStore,
1034
1113
  context?.translationStore
1035
1114
  ]);
1115
+ useIsomorphicLayoutEffect(() => {
1116
+ weaverse?.flushRenderPhaseUpdates();
1117
+ }, [weaverse]);
1036
1118
  if (!weaverse) {
1037
1119
  return null;
1038
1120
  }