@symbo.ls/brender 3.8.1 → 3.8.2

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 (2) hide show
  1. package/package.json +1 -1
  2. package/render.js +48 -2
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@symbo.ls/brender",
3
- "version": "3.8.1",
3
+ "version": "3.8.2",
4
4
  "license": "CC-BY-NC-4.0",
5
5
  "type": "module",
6
6
  "module": "./dist/esm/index.js",
package/render.js CHANGED
@@ -543,6 +543,40 @@ const UIKIT_STUBS = {
543
543
  Text: { tag: 'span' }
544
544
  }
545
545
 
546
+ // ── BR path registry ─────────────────────────────────────────────────────────
547
+
548
+ /**
549
+ * Walks a DOMQL element tree (after mapKeysToElements has set __brKey on each
550
+ * element) and returns a plain object mapping "element path" → "data-br key".
551
+ *
552
+ * The path is a dot-separated chain of element keys from root to leaf:
553
+ * '' (root element itself) → '__root'
554
+ * 'Header' → 'Header'
555
+ * 'Header.Nav' → 'Header.Nav'
556
+ *
557
+ * The registry is serialized into the pre-rendered HTML so the browser can
558
+ * assign the correct brKey to each skeleton element during true hydration.
559
+ */
560
+ const buildPathRegistry = (element, path = '') => {
561
+ if (!element || !element.__ref) return {}
562
+ const registry = {}
563
+
564
+ const brKey = element.__ref.__brKey
565
+ if (brKey) registry[path === '' ? '__root' : path] = brKey
566
+
567
+ if (element.__ref.__children) {
568
+ for (const childKey of element.__ref.__children) {
569
+ const child = element[childKey]
570
+ if (child && child.__ref) {
571
+ const childPath = path === '' ? childKey : `${path}.${childKey}`
572
+ Object.assign(registry, buildPathRegistry(child, childPath))
573
+ }
574
+ }
575
+ }
576
+
577
+ return registry
578
+ }
579
+
546
580
  /**
547
581
  * Renders a Symbols/DOMQL project to HTML on the server.
548
582
  *
@@ -740,6 +774,10 @@ export const render = async (data, options = {}) => {
740
774
 
741
775
  const registry = mapKeysToElements(element)
742
776
 
777
+ // Build element path → brKey registry for client-side true hydration.
778
+ // Walks the element tree after mapKeysToElements has set __brKey on each element.
779
+ const brRegistry = buildPathRegistry(element)
780
+
743
781
  // Extract metadata for the rendered route
744
782
  // Pass the rendered element and its state so function-valued metadata
745
783
  // (e.g. detail page titles from fetched data) can be resolved
@@ -809,7 +847,7 @@ export const render = async (data, options = {}) => {
809
847
  if (_prevLoc !== undefined) globalThis.location = _prevLoc
810
848
  else delete globalThis.location
811
849
 
812
- return { html, metadata, registry, element, emotionCSS, document, window, ssrTranslations, prefetchedPages }
850
+ return { html, metadata, registry, brRegistry, element, emotionCSS, document, window, ssrTranslations, prefetchedPages }
813
851
  }
814
852
 
815
853
  /**
@@ -1171,6 +1209,7 @@ export const renderRoute = async (data, options = {}) => {
1171
1209
  fontLinks: generateFontLinks(ds),
1172
1210
  metadata: result.metadata || extractMetadata(data, route),
1173
1211
  brKeyCount: result.registry ? Object.keys(result.registry).length : 0,
1212
+ brRegistry: result.brRegistry || {},
1174
1213
  ssrTranslations: result.ssrTranslations,
1175
1214
  prefetchedState,
1176
1215
  activeLang
@@ -1265,7 +1304,14 @@ export const renderPage = async (data, route = '/', options = {}) => {
1265
1304
  translationSeed = `<script>try{${seedEntries.join(';')}}catch(e){}</script>\n`
1266
1305
  }
1267
1306
  }
1268
- isrBody = `${translationSeed}<script>window.__BRENDER__ = true</script>
1307
+ // Embed BR registry for true DOM-adoption hydration
1308
+ const brRegistryJson = result.brRegistry && Object.keys(result.brRegistry).length
1309
+ ? JSON.stringify(result.brRegistry)
1310
+ : null
1311
+ const brRegistryScript = brRegistryJson
1312
+ ? `<script>window.__BR_REGISTRY__=${brRegistryJson}</script>\n`
1313
+ : ''
1314
+ isrBody = `${translationSeed}${brRegistryScript}<script>window.__BRENDER__=true</script>
1269
1315
  <script type="module" src="${prefix}${isr.clientScript}"></script>`
1270
1316
  } else {
1271
1317
  // Legacy swap mode: SPA creates new DOM, MutationObserver removes brender nodes