@pwfabric/runtime 0.0.0-stage → 1.0.0-rc.1

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 (447) hide show
  1. package/LICENSE +90 -0
  2. package/README.md +43 -2
  3. package/dist/a11y/announcer.d.ts +65 -0
  4. package/dist/a11y/announcer.js +140 -0
  5. package/dist/a11y/announcer.js.map +1 -0
  6. package/dist/a11y/contrast.d.ts +54 -0
  7. package/dist/a11y/contrast.js +93 -0
  8. package/dist/a11y/contrast.js.map +1 -0
  9. package/dist/a11y/focus.d.ts +123 -0
  10. package/dist/a11y/focus.js +282 -0
  11. package/dist/a11y/focus.js.map +1 -0
  12. package/dist/a11y/index.d.ts +21 -0
  13. package/dist/a11y/index.js +18 -0
  14. package/dist/a11y/index.js.map +1 -0
  15. package/dist/a11y/keyboard.d.ts +144 -0
  16. package/dist/a11y/keyboard.js +317 -0
  17. package/dist/a11y/keyboard.js.map +1 -0
  18. package/dist/adapters/default-image.d.ts +25 -0
  19. package/dist/adapters/default-image.js +37 -0
  20. package/dist/adapters/default-image.js.map +1 -0
  21. package/dist/adapters/index.d.ts +27 -0
  22. package/dist/adapters/index.js +28 -0
  23. package/dist/adapters/index.js.map +1 -0
  24. package/dist/adapters/next-image.d.ts +38 -0
  25. package/dist/adapters/next-image.js +124 -0
  26. package/dist/adapters/next-image.js.map +1 -0
  27. package/dist/adapters/types.d.ts +61 -0
  28. package/dist/adapters/types.js +11 -0
  29. package/dist/adapters/types.js.map +1 -0
  30. package/dist/analytics/index.d.ts +14 -0
  31. package/dist/analytics/index.js +15 -0
  32. package/dist/analytics/index.js.map +1 -0
  33. package/dist/analytics/tracker.d.ts +65 -0
  34. package/dist/analytics/tracker.js +251 -0
  35. package/dist/analytics/tracker.js.map +1 -0
  36. package/dist/analytics/types.d.ts +130 -0
  37. package/dist/analytics/types.js +11 -0
  38. package/dist/analytics/types.js.map +1 -0
  39. package/dist/auth/index.d.ts +15 -0
  40. package/dist/auth/index.js +14 -0
  41. package/dist/auth/index.js.map +1 -0
  42. package/dist/auth/provider.d.ts +132 -0
  43. package/dist/auth/provider.js +473 -0
  44. package/dist/auth/provider.js.map +1 -0
  45. package/dist/auth/types.d.ts +117 -0
  46. package/dist/auth/types.js +9 -0
  47. package/dist/auth/types.js.map +1 -0
  48. package/dist/binding/collection.d.ts +190 -0
  49. package/dist/binding/collection.js +358 -0
  50. package/dist/binding/collection.js.map +1 -0
  51. package/dist/binding/datasource.d.ts +319 -0
  52. package/dist/binding/datasource.js +556 -0
  53. package/dist/binding/datasource.js.map +1 -0
  54. package/dist/binding/engine.d.ts +65 -0
  55. package/dist/binding/engine.js +268 -0
  56. package/dist/binding/engine.js.map +1 -0
  57. package/dist/binding/expression.d.ts +150 -0
  58. package/dist/binding/expression.js +787 -0
  59. package/dist/binding/expression.js.map +1 -0
  60. package/dist/binding/index.d.ts +19 -0
  61. package/dist/binding/index.js +14 -0
  62. package/dist/binding/index.js.map +1 -0
  63. package/dist/binding/two-way.d.ts +149 -0
  64. package/dist/binding/two-way.js +462 -0
  65. package/dist/binding/two-way.js.map +1 -0
  66. package/dist/binding/types.d.ts +119 -0
  67. package/dist/binding/types.js +9 -0
  68. package/dist/binding/types.js.map +1 -0
  69. package/dist/blocks/component-types.d.ts +81 -0
  70. package/dist/blocks/component-types.js +11 -0
  71. package/dist/blocks/component-types.js.map +1 -0
  72. package/dist/blocks/composition-rules.d.ts +168 -0
  73. package/dist/blocks/composition-rules.js +391 -0
  74. package/dist/blocks/composition-rules.js.map +1 -0
  75. package/dist/blocks/hooks.d.ts +31 -0
  76. package/dist/blocks/hooks.js +42 -0
  77. package/dist/blocks/hooks.js.map +1 -0
  78. package/dist/blocks/index.d.ts +14 -0
  79. package/dist/blocks/index.js +23 -0
  80. package/dist/blocks/index.js.map +1 -0
  81. package/dist/blocks/registry.d.ts +84 -0
  82. package/dist/blocks/registry.js +136 -0
  83. package/dist/blocks/registry.js.map +1 -0
  84. package/dist/blocks/rule-engine.d.ts +131 -0
  85. package/dist/blocks/rule-engine.js +321 -0
  86. package/dist/blocks/rule-engine.js.map +1 -0
  87. package/dist/blocks/surface-event-context.d.ts +13 -0
  88. package/dist/blocks/surface-event-context.js +14 -0
  89. package/dist/blocks/surface-event-context.js.map +1 -0
  90. package/dist/blocks/surface-id-context.d.ts +13 -0
  91. package/dist/blocks/surface-id-context.js +15 -0
  92. package/dist/blocks/surface-id-context.js.map +1 -0
  93. package/dist/bus.d.ts +41 -0
  94. package/dist/bus.js +158 -0
  95. package/dist/bus.js.map +1 -0
  96. package/dist/cache/index.d.ts +9 -0
  97. package/dist/cache/index.js +10 -0
  98. package/dist/cache/index.js.map +1 -0
  99. package/dist/cache/memory.d.ts +32 -0
  100. package/dist/cache/memory.js +138 -0
  101. package/dist/cache/memory.js.map +1 -0
  102. package/dist/cache/types.d.ts +62 -0
  103. package/dist/cache/types.js +9 -0
  104. package/dist/cache/types.js.map +1 -0
  105. package/dist/capability/index.d.ts +72 -0
  106. package/dist/capability/index.js +87 -0
  107. package/dist/capability/index.js.map +1 -0
  108. package/dist/capability/kernel-capabilities.d.ts +31 -0
  109. package/dist/capability/kernel-capabilities.js +36 -0
  110. package/dist/capability/kernel-capabilities.js.map +1 -0
  111. package/dist/capability/platform-capabilities.d.ts +71 -0
  112. package/dist/capability/platform-capabilities.js +267 -0
  113. package/dist/capability/platform-capabilities.js.map +1 -0
  114. package/dist/capability/type-mapping.d.ts +70 -0
  115. package/dist/capability/type-mapping.js +107 -0
  116. package/dist/capability/type-mapping.js.map +1 -0
  117. package/dist/capability/validation.d.ts +46 -0
  118. package/dist/capability/validation.js +54 -0
  119. package/dist/capability/validation.js.map +1 -0
  120. package/dist/connectors/declared-connector.d.ts +48 -0
  121. package/dist/connectors/declared-connector.js +333 -0
  122. package/dist/connectors/declared-connector.js.map +1 -0
  123. package/dist/connectors/engine-registry.d.ts +50 -0
  124. package/dist/connectors/engine-registry.js +135 -0
  125. package/dist/connectors/engine-registry.js.map +1 -0
  126. package/dist/connectors/index.d.ts +14 -0
  127. package/dist/connectors/index.js +14 -0
  128. package/dist/connectors/index.js.map +1 -0
  129. package/dist/connectors/module-loader.d.ts +70 -0
  130. package/dist/connectors/module-loader.js +143 -0
  131. package/dist/connectors/module-loader.js.map +1 -0
  132. package/dist/connectors/types.d.ts +174 -0
  133. package/dist/connectors/types.js +23 -0
  134. package/dist/connectors/types.js.map +1 -0
  135. package/dist/context.d.ts +27 -0
  136. package/dist/context.js +38 -0
  137. package/dist/context.js.map +1 -0
  138. package/dist/data/DataCapabilityProvider.d.ts +39 -0
  139. package/dist/data/DataCapabilityProvider.js +58 -0
  140. package/dist/data/DataCapabilityProvider.js.map +1 -0
  141. package/dist/data/index.d.ts +17 -0
  142. package/dist/data/index.js +18 -0
  143. package/dist/data/index.js.map +1 -0
  144. package/dist/data/manager.d.ts +40 -0
  145. package/dist/data/manager.js +442 -0
  146. package/dist/data/manager.js.map +1 -0
  147. package/dist/data/types.d.ts +218 -0
  148. package/dist/data/types.js +2 -0
  149. package/dist/data/types.js.map +1 -0
  150. package/dist/entity/aggregate.d.ts +8 -0
  151. package/dist/entity/aggregate.js +24 -0
  152. package/dist/entity/aggregate.js.map +1 -0
  153. package/dist/entity/apply-query.d.ts +58 -0
  154. package/dist/entity/apply-query.js +264 -0
  155. package/dist/entity/apply-query.js.map +1 -0
  156. package/dist/entity/behavior.d.ts +94 -0
  157. package/dist/entity/behavior.js +78 -0
  158. package/dist/entity/behavior.js.map +1 -0
  159. package/dist/entity/connector.d.ts +141 -0
  160. package/dist/entity/connector.js +89 -0
  161. package/dist/entity/connector.js.map +1 -0
  162. package/dist/entity/connectors/index.d.ts +12 -0
  163. package/dist/entity/connectors/index.js +11 -0
  164. package/dist/entity/connectors/index.js.map +1 -0
  165. package/dist/entity/connectors/static.d.ts +51 -0
  166. package/dist/entity/connectors/static.js +245 -0
  167. package/dist/entity/connectors/static.js.map +1 -0
  168. package/dist/entity/entity-datasource.d.ts +50 -0
  169. package/dist/entity/entity-datasource.js +33 -0
  170. package/dist/entity/entity-datasource.js.map +1 -0
  171. package/dist/entity/facade.d.ts +70 -0
  172. package/dist/entity/facade.js +70 -0
  173. package/dist/entity/facade.js.map +1 -0
  174. package/dist/entity/http-connector.d.ts +123 -0
  175. package/dist/entity/http-connector.js +295 -0
  176. package/dist/entity/http-connector.js.map +1 -0
  177. package/dist/entity/index.d.ts +38 -0
  178. package/dist/entity/index.js +31 -0
  179. package/dist/entity/index.js.map +1 -0
  180. package/dist/entity/postgres-connector.d.ts +64 -0
  181. package/dist/entity/postgres-connector.js +239 -0
  182. package/dist/entity/postgres-connector.js.map +1 -0
  183. package/dist/entity/registry.d.ts +59 -0
  184. package/dist/entity/registry.js +90 -0
  185. package/dist/entity/registry.js.map +1 -0
  186. package/dist/entity/store.d.ts +66 -0
  187. package/dist/entity/store.js +349 -0
  188. package/dist/entity/store.js.map +1 -0
  189. package/dist/entity/types.d.ts +180 -0
  190. package/dist/entity/types.js +10 -0
  191. package/dist/entity/types.js.map +1 -0
  192. package/dist/execution-context.d.ts +88 -0
  193. package/dist/execution-context.js +146 -0
  194. package/dist/execution-context.js.map +1 -0
  195. package/dist/executor.d.ts +27 -0
  196. package/dist/executor.js +33 -0
  197. package/dist/executor.js.map +1 -0
  198. package/dist/forms/form-entity-bridge.d.ts +94 -0
  199. package/dist/forms/form-entity-bridge.js +96 -0
  200. package/dist/forms/form-entity-bridge.js.map +1 -0
  201. package/dist/forms/form-write-target.d.ts +34 -0
  202. package/dist/forms/form-write-target.js +81 -0
  203. package/dist/forms/form-write-target.js.map +1 -0
  204. package/dist/forms/index.d.ts +22 -0
  205. package/dist/forms/index.js +25 -0
  206. package/dist/forms/index.js.map +1 -0
  207. package/dist/forms/named-control-values.d.ts +27 -0
  208. package/dist/forms/named-control-values.js +42 -0
  209. package/dist/forms/named-control-values.js.map +1 -0
  210. package/dist/forms/processor.d.ts +55 -0
  211. package/dist/forms/processor.js +154 -0
  212. package/dist/forms/processor.js.map +1 -0
  213. package/dist/forms/types.d.ts +174 -0
  214. package/dist/forms/types.js +33 -0
  215. package/dist/forms/types.js.map +1 -0
  216. package/dist/forms/validator.d.ts +61 -0
  217. package/dist/forms/validator.js +218 -0
  218. package/dist/forms/validator.js.map +1 -0
  219. package/dist/graph/index.d.ts +10 -0
  220. package/dist/graph/index.js +9 -0
  221. package/dist/graph/index.js.map +1 -0
  222. package/dist/graph/resolver.d.ts +66 -0
  223. package/dist/graph/resolver.js +243 -0
  224. package/dist/graph/resolver.js.map +1 -0
  225. package/dist/graph/types.d.ts +125 -0
  226. package/dist/graph/types.js +9 -0
  227. package/dist/graph/types.js.map +1 -0
  228. package/dist/hooks/useInstalledAtoms.d.ts +96 -0
  229. package/dist/hooks/useInstalledAtoms.js +92 -0
  230. package/dist/hooks/useInstalledAtoms.js.map +1 -0
  231. package/dist/i18n/index.d.ts +15 -0
  232. package/dist/i18n/index.js +14 -0
  233. package/dist/i18n/index.js.map +1 -0
  234. package/dist/i18n/translator.d.ts +76 -0
  235. package/dist/i18n/translator.js +357 -0
  236. package/dist/i18n/translator.js.map +1 -0
  237. package/dist/i18n/types.d.ts +93 -0
  238. package/dist/i18n/types.js +9 -0
  239. package/dist/i18n/types.js.map +1 -0
  240. package/dist/index.d.ts +64 -0
  241. package/dist/index.js +95 -0
  242. package/dist/index.js.map +1 -0
  243. package/dist/kernel.d.ts +47 -0
  244. package/dist/kernel.js +258 -0
  245. package/dist/kernel.js.map +1 -0
  246. package/dist/perf/budget.d.ts +92 -0
  247. package/dist/perf/budget.js +122 -0
  248. package/dist/perf/budget.js.map +1 -0
  249. package/dist/perf/index.d.ts +16 -0
  250. package/dist/perf/index.js +13 -0
  251. package/dist/perf/index.js.map +1 -0
  252. package/dist/perf/render-timer.d.ts +90 -0
  253. package/dist/perf/render-timer.js +136 -0
  254. package/dist/perf/render-timer.js.map +1 -0
  255. package/dist/perf/reporter.d.ts +126 -0
  256. package/dist/perf/reporter.js +241 -0
  257. package/dist/perf/reporter.js.map +1 -0
  258. package/dist/perf/web-vitals.d.ts +111 -0
  259. package/dist/perf/web-vitals.js +268 -0
  260. package/dist/perf/web-vitals.js.map +1 -0
  261. package/dist/registry.d.ts +63 -0
  262. package/dist/registry.js +126 -0
  263. package/dist/registry.js.map +1 -0
  264. package/dist/render/BehaviorSurfaceProvider.d.ts +65 -0
  265. package/dist/render/BehaviorSurfaceProvider.js +185 -0
  266. package/dist/render/BehaviorSurfaceProvider.js.map +1 -0
  267. package/dist/render/BlockErrorBoundary.d.ts +26 -0
  268. package/dist/render/BlockErrorBoundary.js +41 -0
  269. package/dist/render/BlockErrorBoundary.js.map +1 -0
  270. package/dist/render/DataBoundSurfaceRenderer.d.ts +78 -0
  271. package/dist/render/DataBoundSurfaceRenderer.js +998 -0
  272. package/dist/render/DataBoundSurfaceRenderer.js.map +1 -0
  273. package/dist/render/DynamicBlockWrapper.d.ts +23 -0
  274. package/dist/render/DynamicBlockWrapper.js +117 -0
  275. package/dist/render/DynamicBlockWrapper.js.map +1 -0
  276. package/dist/render/appearance-resolver.d.ts +50 -0
  277. package/dist/render/appearance-resolver.js +78 -0
  278. package/dist/render/appearance-resolver.js.map +1 -0
  279. package/dist/render/capability-gate.d.ts +69 -0
  280. package/dist/render/capability-gate.js +94 -0
  281. package/dist/render/capability-gate.js.map +1 -0
  282. package/dist/render/conditional-states-css.d.ts +41 -0
  283. package/dist/render/conditional-states-css.js +82 -0
  284. package/dist/render/conditional-states-css.js.map +1 -0
  285. package/dist/render/connections-context.d.ts +31 -0
  286. package/dist/render/connections-context.js +34 -0
  287. package/dist/render/connections-context.js.map +1 -0
  288. package/dist/render/dark-theme-css.d.ts +36 -0
  289. package/dist/render/dark-theme-css.js +67 -0
  290. package/dist/render/dark-theme-css.js.map +1 -0
  291. package/dist/render/data-binding-types.d.ts +191 -0
  292. package/dist/render/data-binding-types.js +11 -0
  293. package/dist/render/data-binding-types.js.map +1 -0
  294. package/dist/render/data-cache.d.ts +30 -0
  295. package/dist/render/data-cache.js +37 -0
  296. package/dist/render/data-cache.js.map +1 -0
  297. package/dist/render/derive-dark-theme.d.ts +17 -0
  298. package/dist/render/derive-dark-theme.js +18 -0
  299. package/dist/render/derive-dark-theme.js.map +1 -0
  300. package/dist/render/dynamic-artifact-context.d.ts +77 -0
  301. package/dist/render/dynamic-artifact-context.js +89 -0
  302. package/dist/render/dynamic-artifact-context.js.map +1 -0
  303. package/dist/render/dynamic-block-loader.d.ts +80 -0
  304. package/dist/render/dynamic-block-loader.js +197 -0
  305. package/dist/render/dynamic-block-loader.js.map +1 -0
  306. package/dist/render/endpoint.d.ts +18 -0
  307. package/dist/render/endpoint.js +109 -0
  308. package/dist/render/endpoint.js.map +1 -0
  309. package/dist/render/entity-facade-context.d.ts +34 -0
  310. package/dist/render/entity-facade-context.js +37 -0
  311. package/dist/render/entity-facade-context.js.map +1 -0
  312. package/dist/render/group-states-css.d.ts +41 -0
  313. package/dist/render/group-states-css.js +73 -0
  314. package/dist/render/group-states-css.js.map +1 -0
  315. package/dist/render/hooks/useSurfaceEvents.d.ts +8 -0
  316. package/dist/render/hooks/useSurfaceEvents.js +9 -0
  317. package/dist/render/hooks/useSurfaceEvents.js.map +1 -0
  318. package/dist/render/hooks/useSurfaceId.d.ts +8 -0
  319. package/dist/render/hooks/useSurfaceId.js +9 -0
  320. package/dist/render/hooks/useSurfaceId.js.map +1 -0
  321. package/dist/render/index.d.ts +48 -0
  322. package/dist/render/index.js +61 -0
  323. package/dist/render/index.js.map +1 -0
  324. package/dist/render/interaction-rule-engine.d.ts +12 -0
  325. package/dist/render/interaction-rule-engine.js +47 -0
  326. package/dist/render/interaction-rule-engine.js.map +1 -0
  327. package/dist/render/keyframes-css.d.ts +31 -0
  328. package/dist/render/keyframes-css.js +44 -0
  329. package/dist/render/keyframes-css.js.map +1 -0
  330. package/dist/render/query-state.d.ts +3 -0
  331. package/dist/render/query-state.js +70 -0
  332. package/dist/render/query-state.js.map +1 -0
  333. package/dist/render/renderer.d.ts +44 -0
  334. package/dist/render/renderer.js +937 -0
  335. package/dist/render/renderer.js.map +1 -0
  336. package/dist/render/resolve-expressions.d.ts +37 -0
  337. package/dist/render/resolve-expressions.js +309 -0
  338. package/dist/render/resolve-expressions.js.map +1 -0
  339. package/dist/render/responsive-style-css.d.ts +42 -0
  340. package/dist/render/responsive-style-css.js +123 -0
  341. package/dist/render/responsive-style-css.js.map +1 -0
  342. package/dist/render/responsive.d.ts +49 -0
  343. package/dist/render/responsive.js +99 -0
  344. package/dist/render/responsive.js.map +1 -0
  345. package/dist/render/scoped-css.d.ts +71 -0
  346. package/dist/render/scoped-css.js +102 -0
  347. package/dist/render/scoped-css.js.map +1 -0
  348. package/dist/render/shell-selection.d.ts +69 -0
  349. package/dist/render/shell-selection.js +117 -0
  350. package/dist/render/shell-selection.js.map +1 -0
  351. package/dist/render/states-css.d.ts +32 -0
  352. package/dist/render/states-css.js +63 -0
  353. package/dist/render/states-css.js.map +1 -0
  354. package/dist/render/surface-data-context.d.ts +18 -0
  355. package/dist/render/surface-data-context.js +21 -0
  356. package/dist/render/surface-data-context.js.map +1 -0
  357. package/dist/render/surface-event-bus.d.ts +19 -0
  358. package/dist/render/surface-event-bus.js +68 -0
  359. package/dist/render/surface-event-bus.js.map +1 -0
  360. package/dist/render/surface-event-context.d.ts +11 -0
  361. package/dist/render/surface-event-context.js +12 -0
  362. package/dist/render/surface-event-context.js.map +1 -0
  363. package/dist/render/surface-id-context.d.ts +8 -0
  364. package/dist/render/surface-id-context.js +9 -0
  365. package/dist/render/surface-id-context.js.map +1 -0
  366. package/dist/render/theme-utils.d.ts +14 -0
  367. package/dist/render/theme-utils.js +15 -0
  368. package/dist/render/theme-utils.js.map +1 -0
  369. package/dist/render/types.d.ts +282 -0
  370. package/dist/render/types.js +9 -0
  371. package/dist/render/types.js.map +1 -0
  372. package/dist/render/visibility-css.d.ts +42 -0
  373. package/dist/render/visibility-css.js +119 -0
  374. package/dist/render/visibility-css.js.map +1 -0
  375. package/dist/render/width-scope.d.ts +34 -0
  376. package/dist/render/width-scope.js +44 -0
  377. package/dist/render/width-scope.js.map +1 -0
  378. package/dist/render/write-only-sources.d.ts +33 -0
  379. package/dist/render/write-only-sources.js +99 -0
  380. package/dist/render/write-only-sources.js.map +1 -0
  381. package/dist/routing/index.d.ts +14 -0
  382. package/dist/routing/index.js +15 -0
  383. package/dist/routing/index.js.map +1 -0
  384. package/dist/routing/router.d.ts +42 -0
  385. package/dist/routing/router.js +218 -0
  386. package/dist/routing/router.js.map +1 -0
  387. package/dist/routing/types.d.ts +124 -0
  388. package/dist/routing/types.js +9 -0
  389. package/dist/routing/types.js.map +1 -0
  390. package/dist/seo/generator.d.ts +39 -0
  391. package/dist/seo/generator.js +236 -0
  392. package/dist/seo/generator.js.map +1 -0
  393. package/dist/seo/index.d.ts +14 -0
  394. package/dist/seo/index.js +15 -0
  395. package/dist/seo/index.js.map +1 -0
  396. package/dist/seo/types.d.ts +181 -0
  397. package/dist/seo/types.js +9 -0
  398. package/dist/seo/types.js.map +1 -0
  399. package/dist/state/index.d.ts +15 -0
  400. package/dist/state/index.js +16 -0
  401. package/dist/state/index.js.map +1 -0
  402. package/dist/state/manager.d.ts +33 -0
  403. package/dist/state/manager.js +81 -0
  404. package/dist/state/manager.js.map +1 -0
  405. package/dist/state/store.d.ts +40 -0
  406. package/dist/state/store.js +145 -0
  407. package/dist/state/store.js.map +1 -0
  408. package/dist/state/types.d.ts +107 -0
  409. package/dist/state/types.js +9 -0
  410. package/dist/state/types.js.map +1 -0
  411. package/dist/surface/expression.d.ts +65 -0
  412. package/dist/surface/expression.js +179 -0
  413. package/dist/surface/expression.js.map +1 -0
  414. package/dist/surface/index.d.ts +32 -0
  415. package/dist/surface/index.js +25 -0
  416. package/dist/surface/index.js.map +1 -0
  417. package/dist/surface/interpreter.d.ts +96 -0
  418. package/dist/surface/interpreter.js +231 -0
  419. package/dist/surface/interpreter.js.map +1 -0
  420. package/dist/surface/layout.d.ts +54 -0
  421. package/dist/surface/layout.js +288 -0
  422. package/dist/surface/layout.js.map +1 -0
  423. package/dist/surface/output.d.ts +90 -0
  424. package/dist/surface/output.js +104 -0
  425. package/dist/surface/output.js.map +1 -0
  426. package/dist/surface/primitives.d.ts +180 -0
  427. package/dist/surface/primitives.js +339 -0
  428. package/dist/surface/primitives.js.map +1 -0
  429. package/dist/surface/renderer.d.ts +96 -0
  430. package/dist/surface/renderer.js +190 -0
  431. package/dist/surface/renderer.js.map +1 -0
  432. package/dist/surface/schemas.d.ts +181 -0
  433. package/dist/surface/schemas.js +142 -0
  434. package/dist/surface/schemas.js.map +1 -0
  435. package/dist/surface/transforms.d.ts +144 -0
  436. package/dist/surface/transforms.js +120 -0
  437. package/dist/surface/transforms.js.map +1 -0
  438. package/dist/surface/types.d.ts +160 -0
  439. package/dist/surface/types.js +51 -0
  440. package/dist/surface/types.js.map +1 -0
  441. package/dist/surface/validation.d.ts +123 -0
  442. package/dist/surface/validation.js +147 -0
  443. package/dist/surface/validation.js.map +1 -0
  444. package/dist/validator.d.ts +55 -0
  445. package/dist/validator.js +100 -0
  446. package/dist/validator.js.map +1 -0
  447. package/package.json +106 -3
@@ -0,0 +1,42 @@
1
+ /**
2
+ * Per-prop responsive style CSS generation (block.style values vary by breakpoint).
3
+ *
4
+ * `block.style` sits inline and can express a single value per property; it
5
+ * cannot express media queries. A style prop whose value is a
6
+ * `ResponsiveValue<string>` map (`{ xs?, sm?, md?, lg?, xl?, '2xl'? }`) instead
7
+ * of a flat string declares a value that varies per breakpoint. The renderer
8
+ * flattens the base (`xs` / smallest defined) value inline so SSR / no-JS get a
9
+ * sane default; this collector emits the LARGER-breakpoint values as scoped,
10
+ * mobile-first `min-width` media-query rules — keyed by the block's
11
+ * `data-block-id` — that override upward. Same mechanism `layout.hideOn`/
12
+ * `showOn` (visibility-css) and `block.states` (states-css) use.
13
+ *
14
+ * For a block with `style.padding = { xs:'8px', md:'24px', lg:'48px' }`:
15
+ *
16
+ * `@media (min-width:768px){[data-pw-surface] [data-block-id="<id>"]{padding:24px}}`
17
+ * `@media (min-width:1024px){[data-pw-surface] [data-block-id="<id>"]{padding:48px}}`
18
+ *
19
+ * The `xs` (base) value is NOT emitted here — it is rendered inline by the
20
+ * renderer. Flat string values emit zero bytes (the inline path owns them).
21
+ * Blocks without any responsive style value emit zero bytes so existing
22
+ * surfaces are byte-identical.
23
+ *
24
+ * @module @pwfabric/runtime/render/responsive-style-css
25
+ */
26
+ import type { Block } from '@pwfabric/core';
27
+ /**
28
+ * Emit the scoped per-breakpoint media-query CSS for a single block's
29
+ * responsive style props. Targets `[data-block-id="<id>"]` scoped under the
30
+ * surface root so it cannot leak to the host page. Only breakpoints LARGER than
31
+ * `xs` are emitted (the `xs`/base value is inline); each emitted breakpoint key
32
+ * becomes a `@media (min-width:<px>)` rule. Returns '' when the block declares
33
+ * no responsive style value.
34
+ */
35
+ export declare function blockResponsiveStyleCss(blockId: string, style: NonNullable<Block['style']>, surfaceId?: string): string;
36
+ /**
37
+ * Walk a surface block tree and concatenate the per-block responsive style CSS
38
+ * for every block declaring a `ResponsiveValue` style prop. Blocks with only
39
+ * flat string style values (or no style) are skipped (zero bytes emitted) so
40
+ * existing surfaces are byte-identical.
41
+ */
42
+ export declare function collectResponsiveStyleCss(blocks: readonly Block[], surfaceId?: string): string;
@@ -0,0 +1,123 @@
1
+ /**
2
+ * Per-prop responsive style CSS generation (block.style values vary by breakpoint).
3
+ *
4
+ * `block.style` sits inline and can express a single value per property; it
5
+ * cannot express media queries. A style prop whose value is a
6
+ * `ResponsiveValue<string>` map (`{ xs?, sm?, md?, lg?, xl?, '2xl'? }`) instead
7
+ * of a flat string declares a value that varies per breakpoint. The renderer
8
+ * flattens the base (`xs` / smallest defined) value inline so SSR / no-JS get a
9
+ * sane default; this collector emits the LARGER-breakpoint values as scoped,
10
+ * mobile-first `min-width` media-query rules — keyed by the block's
11
+ * `data-block-id` — that override upward. Same mechanism `layout.hideOn`/
12
+ * `showOn` (visibility-css) and `block.states` (states-css) use.
13
+ *
14
+ * For a block with `style.padding = { xs:'8px', md:'24px', lg:'48px' }`:
15
+ *
16
+ * `@media (min-width:768px){[data-pw-surface] [data-block-id="<id>"]{padding:24px}}`
17
+ * `@media (min-width:1024px){[data-pw-surface] [data-block-id="<id>"]{padding:48px}}`
18
+ *
19
+ * The `xs` (base) value is NOT emitted here — it is rendered inline by the
20
+ * renderer. Flat string values emit zero bytes (the inline path owns them).
21
+ * Blocks without any responsive style value emit zero bytes so existing
22
+ * surfaces are byte-identical.
23
+ *
24
+ * @module @pwfabric/runtime/render/responsive-style-css
25
+ */
26
+ import { BREAKPOINTS, BREAKPOINT_ORDER } from '@pwfabric/core';
27
+ import { blockSelector, camelToKebab, collectScopedCss, LAYOUT_HOIST_KEYS, WRAPPER_ATTR } from './scoped-css.js';
28
+ /** Breakpoint name → `minWidth` px (same thresholds the span/visibility systems use). */
29
+ function minWidthFor(bp) {
30
+ return BREAKPOINTS.find((b) => b.name === bp)?.minWidth ?? 0;
31
+ }
32
+ /** A style prop value is responsive when it is a non-null object (not a flat string). */
33
+ function isResponsiveValue(value) {
34
+ return typeof value === 'object' && value !== null;
35
+ }
36
+ /**
37
+ * Emit the scoped per-breakpoint media-query CSS for a single block's
38
+ * responsive style props. Targets `[data-block-id="<id>"]` scoped under the
39
+ * surface root so it cannot leak to the host page. Only breakpoints LARGER than
40
+ * `xs` are emitted (the `xs`/base value is inline); each emitted breakpoint key
41
+ * becomes a `@media (min-width:<px>)` rule. Returns '' when the block declares
42
+ * no responsive style value.
43
+ */
44
+ export function blockResponsiveStyleCss(blockId, style, surfaceId) {
45
+ const selector = blockSelector(blockId, surfaceId);
46
+ // Group declarations by breakpoint so one prop's md value and another prop's
47
+ // md value share a single `@media` rule (mirrors how a mobile-first stylesheet
48
+ // would be authored). The base (smallest defined breakpoint per prop) is a
49
+ // NON-media rule so ALL breakpoints live in the stylesheet — never inline.
50
+ // (Inline always beats stylesheet rules incl. @media, so a flattened-inline
51
+ // base would pin the value and the larger @media overrides would never apply.)
52
+ // THE HOISTING RULE APPLIES ON THE SELECTOR SIDE TOO.
53
+ //
54
+ // `[data-block-id]` matches BOTH the wrapper AND the component root. For flat
55
+ // values the renderer hoists margin/maxWidth/flex to the wrapper and removes
56
+ // them from the root; for responsive values the value leaves the inline style
57
+ // and lands here, so without the same split here the rule would apply TWICE
58
+ // (`marginTop:'-40%'` → both -335px and -256px).
59
+ //
60
+ // Hence two sets: hoisted keys go ONLY to the wrapper, the rest ONLY to the
61
+ // component root.
62
+ const HOIST = new Set(LAYOUT_HOIST_KEYS);
63
+ const baseDecls = [];
64
+ const byBreakpoint = new Map();
65
+ const baseHoist = [];
66
+ const byBreakpointHoist = new Map();
67
+ for (const [prop, value] of Object.entries(style)) {
68
+ if (!isResponsiveValue(value))
69
+ continue; // flat string → inline path owns it
70
+ let baseTaken = false;
71
+ // BREAKPOINT_ORDER is mobile-first ascending → first defined key is the base.
72
+ for (const bp of BREAKPOINT_ORDER) {
73
+ const v = value[bp];
74
+ if (v === undefined)
75
+ continue;
76
+ // `!important`: a block COMPONENT often applies the same CSS property
77
+ // inline with its own default (e.g. the text block sets
78
+ // `font-size: var(--pw-font-size-base)`). Inline beats any stylesheet rule,
79
+ // so without `!important` the author's responsive value would be pinned to
80
+ // the component default. Scoped to `[data-block-id]`, this only overrides
81
+ // the one block's own responsive props. Base + larger are both `!important`
82
+ // at equal specificity → source order (larger emitted later) wins on match.
83
+ const hoisted = HOIST.has(prop);
84
+ const bag = hoisted ? baseHoist : baseDecls;
85
+ const map = hoisted ? byBreakpointHoist : byBreakpoint;
86
+ if (!baseTaken) {
87
+ bag.push(`${camelToKebab(prop)}:${v} !important`);
88
+ baseTaken = true;
89
+ }
90
+ else {
91
+ const decls = map.get(bp) ?? [];
92
+ decls.push(`${camelToKebab(prop)}:${v} !important`);
93
+ map.set(bp, decls);
94
+ }
95
+ }
96
+ }
97
+ let css = '';
98
+ // Base (non-media) first, then ascending breakpoint order so larger
99
+ // breakpoints (later in source) win the cascade at equal specificity.
100
+ const emit = (sel, base, map) => {
101
+ if (base.length > 0)
102
+ css += `${sel}{${base.join(';')}}`;
103
+ for (const bp of BREAKPOINT_ORDER) {
104
+ const decls = map.get(bp);
105
+ if (!decls || decls.length === 0)
106
+ continue;
107
+ css += `@media (min-width:${minWidthFor(bp)}px){${sel}{${decls.join(';')}}}`;
108
+ }
109
+ };
110
+ emit(`${selector}:not(${WRAPPER_ATTR})`, baseDecls, byBreakpoint);
111
+ emit(`${selector}${WRAPPER_ATTR}`, baseHoist, byBreakpointHoist);
112
+ return css;
113
+ }
114
+ /**
115
+ * Walk a surface block tree and concatenate the per-block responsive style CSS
116
+ * for every block declaring a `ResponsiveValue` style prop. Blocks with only
117
+ * flat string style values (or no style) are skipped (zero bytes emitted) so
118
+ * existing surfaces are byte-identical.
119
+ */
120
+ export function collectResponsiveStyleCss(blocks, surfaceId) {
121
+ return collectScopedCss(blocks, (block) => block.style ? blockResponsiveStyleCss(block.id, block.style, surfaceId) : '');
122
+ }
123
+ //# sourceMappingURL=responsive-style-css.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"responsive-style-css.js","sourceRoot":"","sources":["../../src/render/responsive-style-css.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Per-prop responsive style CSS generation (block.style values vary by breakpoint).\n *\n * `block.style` sits inline and can express a single value per property; it\n * cannot express media queries. A style prop whose value is a\n * `ResponsiveValue<string>` map (`{ xs?, sm?, md?, lg?, xl?, '2xl'? }`) instead\n * of a flat string declares a value that varies per breakpoint. The renderer\n * flattens the base (`xs` / smallest defined) value inline so SSR / no-JS get a\n * sane default; this collector emits the LARGER-breakpoint values as scoped,\n * mobile-first `min-width` media-query rules — keyed by the block's\n * `data-block-id` — that override upward. Same mechanism `layout.hideOn`/\n * `showOn` (visibility-css) and `block.states` (states-css) use.\n *\n * For a block with `style.padding = { xs:'8px', md:'24px', lg:'48px' }`:\n *\n * `@media (min-width:768px){[data-pw-surface] [data-block-id=\"<id>\"]{padding:24px}}`\n * `@media (min-width:1024px){[data-pw-surface] [data-block-id=\"<id>\"]{padding:48px}}`\n *\n * The `xs` (base) value is NOT emitted here — it is rendered inline by the\n * renderer. Flat string values emit zero bytes (the inline path owns them).\n * Blocks without any responsive style value emit zero bytes so existing\n * surfaces are byte-identical.\n *\n * @module @pwfabric/runtime/render/responsive-style-css\n */\n\nimport type { Block } from '@pwfabric/core'\nimport { BREAKPOINTS, BREAKPOINT_ORDER } from '@pwfabric/core'\nimport type { BreakpointName } from '@pwfabric/core'\nimport { blockSelector, camelToKebab, collectScopedCss, LAYOUT_HOIST_KEYS, WRAPPER_ATTR } from './scoped-css.js'\n\n/** Breakpoint name → `minWidth` px (same thresholds the span/visibility systems use). */\nfunction minWidthFor(bp: BreakpointName): number {\n return BREAKPOINTS.find((b) => b.name === bp)?.minWidth ?? 0\n}\n\n/** A per-breakpoint value map (the responsive form of a style prop value). */\ntype ResponsiveStyleValue = Partial<Record<BreakpointName, string>>\n\n/** A style prop value is responsive when it is a non-null object (not a flat string). */\nfunction isResponsiveValue(value: unknown): value is ResponsiveStyleValue {\n return typeof value === 'object' && value !== null\n}\n\n/**\n * Emit the scoped per-breakpoint media-query CSS for a single block's\n * responsive style props. Targets `[data-block-id=\"<id>\"]` scoped under the\n * surface root so it cannot leak to the host page. Only breakpoints LARGER than\n * `xs` are emitted (the `xs`/base value is inline); each emitted breakpoint key\n * becomes a `@media (min-width:<px>)` rule. Returns '' when the block declares\n * no responsive style value.\n */\nexport function blockResponsiveStyleCss(\n blockId: string,\n style: NonNullable<Block['style']>,\n surfaceId?: string\n): string {\n const selector = blockSelector(blockId, surfaceId)\n // Group declarations by breakpoint so one prop's md value and another prop's\n // md value share a single `@media` rule (mirrors how a mobile-first stylesheet\n // would be authored). The base (smallest defined breakpoint per prop) is a\n // NON-media rule so ALL breakpoints live in the stylesheet — never inline.\n // (Inline always beats stylesheet rules incl. @media, so a flattened-inline\n // base would pin the value and the larger @media overrides would never apply.)\n // THE HOISTING RULE APPLIES ON THE SELECTOR SIDE TOO.\n //\n // `[data-block-id]` matches BOTH the wrapper AND the component root. For flat\n // values the renderer hoists margin/maxWidth/flex to the wrapper and removes\n // them from the root; for responsive values the value leaves the inline style\n // and lands here, so without the same split here the rule would apply TWICE\n // (`marginTop:'-40%'` → both -335px and -256px).\n //\n // Hence two sets: hoisted keys go ONLY to the wrapper, the rest ONLY to the\n // component root.\n const HOIST = new Set<string>(LAYOUT_HOIST_KEYS)\n const baseDecls: string[] = []\n const byBreakpoint = new Map<BreakpointName, string[]>()\n const baseHoist: string[] = []\n const byBreakpointHoist = new Map<BreakpointName, string[]>()\n\n for (const [prop, value] of Object.entries(style)) {\n if (!isResponsiveValue(value)) continue // flat string → inline path owns it\n let baseTaken = false\n // BREAKPOINT_ORDER is mobile-first ascending → first defined key is the base.\n for (const bp of BREAKPOINT_ORDER) {\n const v = value[bp]\n if (v === undefined) continue\n // `!important`: a block COMPONENT often applies the same CSS property\n // inline with its own default (e.g. the text block sets\n // `font-size: var(--pw-font-size-base)`). Inline beats any stylesheet rule,\n // so without `!important` the author's responsive value would be pinned to\n // the component default. Scoped to `[data-block-id]`, this only overrides\n // the one block's own responsive props. Base + larger are both `!important`\n // at equal specificity → source order (larger emitted later) wins on match.\n const hoisted = HOIST.has(prop)\n const bag = hoisted ? baseHoist : baseDecls\n const map = hoisted ? byBreakpointHoist : byBreakpoint\n if (!baseTaken) {\n bag.push(`${camelToKebab(prop)}:${v} !important`)\n baseTaken = true\n } else {\n const decls = map.get(bp) ?? []\n decls.push(`${camelToKebab(prop)}:${v} !important`)\n map.set(bp, decls)\n }\n }\n }\n\n let css = ''\n // Base (non-media) first, then ascending breakpoint order so larger\n // breakpoints (later in source) win the cascade at equal specificity.\n const emit = (sel: string, base: string[], map: Map<BreakpointName, string[]>): void => {\n if (base.length > 0) css += `${sel}{${base.join(';')}}`\n for (const bp of BREAKPOINT_ORDER) {\n const decls = map.get(bp)\n if (!decls || decls.length === 0) continue\n css += `@media (min-width:${minWidthFor(bp)}px){${sel}{${decls.join(';')}}}`\n }\n }\n emit(`${selector}:not(${WRAPPER_ATTR})`, baseDecls, byBreakpoint)\n emit(`${selector}${WRAPPER_ATTR}`, baseHoist, byBreakpointHoist)\n return css\n}\n\n/**\n * Walk a surface block tree and concatenate the per-block responsive style CSS\n * for every block declaring a `ResponsiveValue` style prop. Blocks with only\n * flat string style values (or no style) are skipped (zero bytes emitted) so\n * existing surfaces are byte-identical.\n */\nexport function collectResponsiveStyleCss(blocks: readonly Block[], surfaceId?: string): string {\n return collectScopedCss(blocks, (block) =>\n block.style ? blockResponsiveStyleCss(block.id, block.style, surfaceId) : ''\n )\n}\n"]}
@@ -0,0 +1,49 @@
1
+ /**
2
+ * Responsive Rendering Utilities
3
+ *
4
+ * Viewport-aware layout resolution for runtime rendering.
5
+ * Re-exports pure functions from @pwfabric/core and provides
6
+ * React-specific viewport hook.
7
+ *
8
+ * @module @pwfabric/runtime/render/responsive
9
+ */
10
+ import * as React from 'react';
11
+ import type { BlockLayout, BreakpointName } from '@pwfabric/core';
12
+ export { resolveResponsiveValue, resolveSpanAtBreakpoint, getColumnsAtBreakpoint, getBreakpointForWidth, } from '@pwfabric/core';
13
+ /**
14
+ * Resolve the complete block layout at a given viewport breakpoint.
15
+ * Returns span, offset, order, and hidden values.
16
+ */
17
+ export declare function resolveBlockLayout(layout: BlockLayout, viewport: BreakpointName): {
18
+ span: number;
19
+ offset: number | undefined;
20
+ order: number | undefined;
21
+ hidden: boolean | undefined;
22
+ };
23
+ /**
24
+ * Surface root — carries NO MEASURE.
25
+ *
26
+ * If the root carried both the 12-column grid and
27
+ * `maxWidth: var(--pw-layout-container-max-width)` + `margin: 0 auto`,
28
+ * persistent chrome would sit inside the centred box too (a persistent rail
29
+ * would start well in from the screen edge, as part of the narrower container).
30
+ *
31
+ * The measure goes to the inner container through `resolveMeasureStyle`;
32
+ * the root is flow only.
33
+ */
34
+ export declare function resolveSurfaceRootStyle(gap?: string | number, padding?: string | number): React.CSSProperties;
35
+ /**
36
+ * Measured container — the wrapper of `container`-scoped blocks.
37
+ *
38
+ * The 12-column grid and `containerMaxWidth` live HERE. Blocks that declare
39
+ * `widthScope:'viewport'` are drawn as SIBLINGS of this container, not its
40
+ * children — the escape is placement, not a CSS trick (see render/width-scope.ts).
41
+ */
42
+ export declare function resolveMeasureStyle(viewport: BreakpointName, gap?: string | number, padding?: string | number, containerMaxWidth?: string): React.CSSProperties;
43
+ /**
44
+ * React hook that returns the current viewport breakpoint.
45
+ * Uses matchMedia for efficient viewport detection.
46
+ *
47
+ * Returns 'lg' on server (SSR fallback).
48
+ */
49
+ export declare function useViewport(): BreakpointName;
@@ -0,0 +1,99 @@
1
+ /**
2
+ * Responsive Rendering Utilities
3
+ *
4
+ * Viewport-aware layout resolution for runtime rendering.
5
+ * Re-exports pure functions from @pwfabric/core and provides
6
+ * React-specific viewport hook.
7
+ *
8
+ * @module @pwfabric/runtime/render/responsive
9
+ */
10
+ import * as React from 'react';
11
+ import { BREAKPOINTS, resolveSpanAtBreakpoint, resolveResponsiveValue, getColumnsAtBreakpoint, getBreakpointForWidth, } from '@pwfabric/core';
12
+ // Re-export pure functions for convenience
13
+ export { resolveResponsiveValue, resolveSpanAtBreakpoint, getColumnsAtBreakpoint, getBreakpointForWidth, } from '@pwfabric/core';
14
+ // ============================================================
15
+ // BLOCK STYLE RESOLUTION
16
+ // ============================================================
17
+ /**
18
+ * Resolve the complete block layout at a given viewport breakpoint.
19
+ * Returns span, offset, order, and hidden values.
20
+ */
21
+ export function resolveBlockLayout(layout, viewport) {
22
+ return {
23
+ span: resolveSpanAtBreakpoint(layout, viewport),
24
+ offset: resolveResponsiveValue(layout.offset, viewport),
25
+ order: resolveResponsiveValue(layout.order, viewport),
26
+ hidden: resolveResponsiveValue(layout.hidden, viewport),
27
+ };
28
+ }
29
+ /**
30
+ * Surface root — carries NO MEASURE.
31
+ *
32
+ * If the root carried both the 12-column grid and
33
+ * `maxWidth: var(--pw-layout-container-max-width)` + `margin: 0 auto`,
34
+ * persistent chrome would sit inside the centred box too (a persistent rail
35
+ * would start well in from the screen edge, as part of the narrower container).
36
+ *
37
+ * The measure goes to the inner container through `resolveMeasureStyle`;
38
+ * the root is flow only.
39
+ */
40
+ export function resolveSurfaceRootStyle(gap = 16, padding = 0) {
41
+ return {
42
+ display: 'flex',
43
+ flexDirection: 'column',
44
+ gap: typeof gap === 'number' ? `${gap}px` : gap,
45
+ padding: typeof padding === 'number' ? `${padding}px` : padding,
46
+ };
47
+ }
48
+ /**
49
+ * Measured container — the wrapper of `container`-scoped blocks.
50
+ *
51
+ * The 12-column grid and `containerMaxWidth` live HERE. Blocks that declare
52
+ * `widthScope:'viewport'` are drawn as SIBLINGS of this container, not its
53
+ * children — the escape is placement, not a CSS trick (see render/width-scope.ts).
54
+ */
55
+ export function resolveMeasureStyle(viewport, gap = 16, padding = 24, containerMaxWidth = 'var(--pw-layout-container-max-width)') {
56
+ const columns = getColumnsAtBreakpoint(viewport);
57
+ return {
58
+ display: 'grid',
59
+ gridTemplateColumns: `repeat(${columns}, 1fr)`,
60
+ gap: typeof gap === 'number' ? `${gap}px` : gap,
61
+ padding: typeof padding === 'number' ? `${padding}px` : padding,
62
+ maxWidth: containerMaxWidth,
63
+ margin: '0 auto',
64
+ width: '100%',
65
+ };
66
+ }
67
+ // ============================================================
68
+ // VIEWPORT HOOK
69
+ // ============================================================
70
+ /**
71
+ * React hook that returns the current viewport breakpoint.
72
+ * Uses matchMedia for efficient viewport detection.
73
+ *
74
+ * Returns 'lg' on server (SSR fallback).
75
+ */
76
+ export function useViewport() {
77
+ const [breakpoint, setBreakpoint] = React.useState('lg');
78
+ React.useEffect(() => {
79
+ // Set initial value from current window width
80
+ setBreakpoint(getBreakpointForWidth(window.innerWidth));
81
+ // Create media query listeners for each breakpoint transition
82
+ const listeners = [];
83
+ for (const bp of BREAKPOINTS) {
84
+ const mql = window.matchMedia(`(min-width: ${bp.minWidth}px)`);
85
+ const handler = () => {
86
+ setBreakpoint(getBreakpointForWidth(window.innerWidth));
87
+ };
88
+ mql.addEventListener('change', handler);
89
+ listeners.push({ mql, handler });
90
+ }
91
+ return () => {
92
+ for (const { mql, handler } of listeners) {
93
+ mql.removeEventListener('change', handler);
94
+ }
95
+ };
96
+ }, []);
97
+ return breakpoint;
98
+ }
99
+ //# sourceMappingURL=responsive.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"responsive.js","sourceRoot":"","sources":["../../src/render/responsive.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Responsive Rendering Utilities\n *\n * Viewport-aware layout resolution for runtime rendering.\n * Re-exports pure functions from @pwfabric/core and provides\n * React-specific viewport hook.\n *\n * @module @pwfabric/runtime/render/responsive\n */\n\nimport * as React from 'react'\nimport type { BlockLayout, BreakpointName } from '@pwfabric/core'\nimport {\n BREAKPOINTS,\n resolveSpanAtBreakpoint,\n resolveResponsiveValue,\n getColumnsAtBreakpoint,\n getBreakpointForWidth,\n} from '@pwfabric/core'\n\n// Re-export pure functions for convenience\nexport {\n resolveResponsiveValue,\n resolveSpanAtBreakpoint,\n getColumnsAtBreakpoint,\n getBreakpointForWidth,\n} from '@pwfabric/core'\n\n// ============================================================\n// BLOCK STYLE RESOLUTION\n// ============================================================\n\n/**\n * Resolve the complete block layout at a given viewport breakpoint.\n * Returns span, offset, order, and hidden values.\n */\nexport function resolveBlockLayout(\n layout: BlockLayout,\n viewport: BreakpointName\n): {\n span: number\n offset: number | undefined\n order: number | undefined\n hidden: boolean | undefined\n} {\n return {\n span: resolveSpanAtBreakpoint(layout, viewport),\n offset: resolveResponsiveValue(layout.offset, viewport),\n order: resolveResponsiveValue(layout.order, viewport),\n hidden: resolveResponsiveValue(layout.hidden, viewport),\n }\n}\n\n/**\n * Surface root — carries NO MEASURE.\n *\n * If the root carried both the 12-column grid and\n * `maxWidth: var(--pw-layout-container-max-width)` + `margin: 0 auto`,\n * persistent chrome would sit inside the centred box too (a persistent rail\n * would start well in from the screen edge, as part of the narrower container).\n *\n * The measure goes to the inner container through `resolveMeasureStyle`;\n * the root is flow only.\n */\nexport function resolveSurfaceRootStyle(\n gap: string | number = 16,\n padding: string | number = 0\n): React.CSSProperties {\n return {\n display: 'flex',\n flexDirection: 'column',\n gap: typeof gap === 'number' ? `${gap}px` : gap,\n padding: typeof padding === 'number' ? `${padding}px` : padding,\n }\n}\n\n/**\n * Measured container — the wrapper of `container`-scoped blocks.\n *\n * The 12-column grid and `containerMaxWidth` live HERE. Blocks that declare\n * `widthScope:'viewport'` are drawn as SIBLINGS of this container, not its\n * children — the escape is placement, not a CSS trick (see render/width-scope.ts).\n */\nexport function resolveMeasureStyle(\n viewport: BreakpointName,\n gap: string | number = 16,\n padding: string | number = 24,\n containerMaxWidth = 'var(--pw-layout-container-max-width)'\n): React.CSSProperties {\n const columns = getColumnsAtBreakpoint(viewport)\n return {\n display: 'grid',\n gridTemplateColumns: `repeat(${columns}, 1fr)`,\n gap: typeof gap === 'number' ? `${gap}px` : gap,\n padding: typeof padding === 'number' ? `${padding}px` : padding,\n maxWidth: containerMaxWidth,\n margin: '0 auto',\n width: '100%',\n }\n}\n\n// ============================================================\n// VIEWPORT HOOK\n// ============================================================\n\n/**\n * React hook that returns the current viewport breakpoint.\n * Uses matchMedia for efficient viewport detection.\n *\n * Returns 'lg' on server (SSR fallback).\n */\nexport function useViewport(): BreakpointName {\n const [breakpoint, setBreakpoint] = React.useState<BreakpointName>('lg')\n\n React.useEffect(() => {\n // Set initial value from current window width\n setBreakpoint(getBreakpointForWidth(window.innerWidth))\n\n // Create media query listeners for each breakpoint transition\n const listeners: { mql: MediaQueryList; handler: () => void }[] = []\n\n for (const bp of BREAKPOINTS) {\n const mql = window.matchMedia(`(min-width: ${bp.minWidth}px)`)\n const handler = (): void => {\n setBreakpoint(getBreakpointForWidth(window.innerWidth))\n }\n mql.addEventListener('change', handler)\n listeners.push({ mql, handler })\n }\n\n return () => {\n for (const { mql, handler } of listeners) {\n mql.removeEventListener('change', handler)\n }\n }\n }, [])\n\n return breakpoint\n}\n"]}
@@ -0,0 +1,71 @@
1
+ /**
2
+ * Shared helpers for the scoped per-block CSS collectors.
3
+ *
4
+ * The runtime emits several kinds of scoped `<style>` rules keyed by a block's
5
+ * stable `data-block-id` (visibility / interaction-states / responsive-style /
6
+ * conditional-states / group-states). They all share the SAME primitives:
7
+ *
8
+ * - `cssEscapeId(id)` — conservative attribute-value escaper for block ids.
9
+ * - `camelToKebab(prop)` — CSS camelCase property name → kebab-case.
10
+ * - `blockSelector(id)` — `[data-pw-surface] [data-block-id="<escaped>"]`,
11
+ * the scoped base selector every rule attaches to.
12
+ * - `collectScopedCss(blocks, perBlockFn)` — walk the block tree (including
13
+ * children) and concatenate each block's CSS as
14
+ * produced by `perBlockFn(block)`.
15
+ *
16
+ * Centralising these keeps the per-collector files focused on their own
17
+ * selector/declaration semantics and guarantees byte-identical output across
18
+ * the family (the same escaper, the same selector string, the same walk order).
19
+ *
20
+ * @module @pwfabric/runtime/render/scoped-css
21
+ */
22
+ import type { Block } from '@pwfabric/core';
23
+ /** Conservative CSS attribute-selector value escaper (block ids are slugs, but be safe). */
24
+ export declare function cssEscapeId(id: string): string;
25
+ /** camelCase CSS property → kebab-case (e.g. `backgroundColor` → `background-color`). */
26
+ export declare function camelToKebab(prop: string): string;
27
+ /** The bare `[data-block-id="<escaped-id>"]` attribute selector (no surface scope). */
28
+ export declare function blockIdAttr(id: string): string;
29
+ /**
30
+ * The surface-root selector a scoped rule hangs off.
31
+ *
32
+ * With a `surfaceId` this is `[data-pw-surface="<id>"]` — scope carried by the
33
+ * attribute's VALUE, not merely its presence. That matters because the embed
34
+ * autoloader hydrates EVERY `[data-pw-surface]` element in a document, so a host
35
+ * page can hold several surfaces at once; a value-less selector makes each
36
+ * surface's rules apply to all of them, and the last one in document order wins.
37
+ *
38
+ * Without a `surfaceId` it degrades to the historical `[data-pw-surface]`, which
39
+ * is correct for rules whose content is identical for every surface (the base
40
+ * CSS) and for unit tests that render a single surface.
41
+ */
42
+ export declare function surfaceScope(surfaceId?: string): string;
43
+ /**
44
+ * The scoped base selector a per-block rule attaches to:
45
+ * `[data-pw-surface="<sid>"] [data-block-id="<escaped-id>"]`. Scoped under the
46
+ * surface root so a rule can never leak to the host page — and, when the surface
47
+ * id is supplied, never to a SIBLING surface that happens to reuse a block id.
48
+ */
49
+ export declare function blockSelector(id: string, surfaceId?: string): string;
50
+ /**
51
+ * Walk a surface block tree (depth-first, children after their parent — the
52
+ * order all collectors used) and concatenate the per-block CSS produced by
53
+ * `perBlockFn(block)`. Blocks for which `perBlockFn` returns '' contribute zero
54
+ * bytes, so existing surfaces stay byte-identical.
55
+ */
56
+ export declare function collectScopedCss(blocks: readonly Block[], perBlockFn: (block: Block) => string): string;
57
+ /**
58
+ * Style keys HOISTED to the wrapper — kept here so the renderer and the
59
+ * responsive CSS generator see the SAME list.
60
+ *
61
+ * This list is a RULE: these keys apply to the outer wrapper, not the
62
+ * component root. For flat values the renderer hoists them; for responsive
63
+ * values the value leaves the inline style entirely and lands in CSS, so the
64
+ * same rule has to be expressed on the selector side — otherwise the rule
65
+ * matches both the wrapper and the root and the value is applied TWICE
66
+ * (`marginTop:'-40%'` would move content by both -335px and -256px).
67
+ */
68
+ export declare const FLEX_HOIST_KEYS: readonly ["flex", "flexGrow", "flexShrink", "flexBasis"];
69
+ export declare const LAYOUT_HOIST_KEYS: readonly ["margin", "marginTop", "marginRight", "marginBottom", "marginLeft", "maxWidth", "minWidth", "flex", "flexGrow", "flexShrink", "flexBasis"];
70
+ /** The attribute that tells the wrapper from the component root (the same marker states-css uses). */
71
+ export declare const WRAPPER_ATTR = "[data-block-wrapper]";
@@ -0,0 +1,102 @@
1
+ /**
2
+ * Shared helpers for the scoped per-block CSS collectors.
3
+ *
4
+ * The runtime emits several kinds of scoped `<style>` rules keyed by a block's
5
+ * stable `data-block-id` (visibility / interaction-states / responsive-style /
6
+ * conditional-states / group-states). They all share the SAME primitives:
7
+ *
8
+ * - `cssEscapeId(id)` — conservative attribute-value escaper for block ids.
9
+ * - `camelToKebab(prop)` — CSS camelCase property name → kebab-case.
10
+ * - `blockSelector(id)` — `[data-pw-surface] [data-block-id="<escaped>"]`,
11
+ * the scoped base selector every rule attaches to.
12
+ * - `collectScopedCss(blocks, perBlockFn)` — walk the block tree (including
13
+ * children) and concatenate each block's CSS as
14
+ * produced by `perBlockFn(block)`.
15
+ *
16
+ * Centralising these keeps the per-collector files focused on their own
17
+ * selector/declaration semantics and guarantees byte-identical output across
18
+ * the family (the same escaper, the same selector string, the same walk order).
19
+ *
20
+ * @module @pwfabric/runtime/render/scoped-css
21
+ */
22
+ /** Conservative CSS attribute-selector value escaper (block ids are slugs, but be safe). */
23
+ export function cssEscapeId(id) {
24
+ return id.replace(/["\\]/g, '\\$&');
25
+ }
26
+ /** camelCase CSS property → kebab-case (e.g. `backgroundColor` → `background-color`). */
27
+ export function camelToKebab(prop) {
28
+ return prop.replace(/[A-Z]/g, (m) => `-${m.toLowerCase()}`);
29
+ }
30
+ /** The bare `[data-block-id="<escaped-id>"]` attribute selector (no surface scope). */
31
+ export function blockIdAttr(id) {
32
+ return `[data-block-id="${cssEscapeId(id)}"]`;
33
+ }
34
+ /**
35
+ * The surface-root selector a scoped rule hangs off.
36
+ *
37
+ * With a `surfaceId` this is `[data-pw-surface="<id>"]` — scope carried by the
38
+ * attribute's VALUE, not merely its presence. That matters because the embed
39
+ * autoloader hydrates EVERY `[data-pw-surface]` element in a document, so a host
40
+ * page can hold several surfaces at once; a value-less selector makes each
41
+ * surface's rules apply to all of them, and the last one in document order wins.
42
+ *
43
+ * Without a `surfaceId` it degrades to the historical `[data-pw-surface]`, which
44
+ * is correct for rules whose content is identical for every surface (the base
45
+ * CSS) and for unit tests that render a single surface.
46
+ */
47
+ export function surfaceScope(surfaceId) {
48
+ return surfaceId ? `[data-pw-surface="${cssEscapeId(surfaceId)}"]` : '[data-pw-surface]';
49
+ }
50
+ /**
51
+ * The scoped base selector a per-block rule attaches to:
52
+ * `[data-pw-surface="<sid>"] [data-block-id="<escaped-id>"]`. Scoped under the
53
+ * surface root so a rule can never leak to the host page — and, when the surface
54
+ * id is supplied, never to a SIBLING surface that happens to reuse a block id.
55
+ */
56
+ export function blockSelector(id, surfaceId) {
57
+ return `${surfaceScope(surfaceId)} ${blockIdAttr(id)}`;
58
+ }
59
+ /**
60
+ * Walk a surface block tree (depth-first, children after their parent — the
61
+ * order all collectors used) and concatenate the per-block CSS produced by
62
+ * `perBlockFn(block)`. Blocks for which `perBlockFn` returns '' contribute zero
63
+ * bytes, so existing surfaces stay byte-identical.
64
+ */
65
+ export function collectScopedCss(blocks, perBlockFn) {
66
+ let css = '';
67
+ const walk = (block) => {
68
+ css += perBlockFn(block);
69
+ if (block.children) {
70
+ for (const child of block.children)
71
+ walk(child);
72
+ }
73
+ };
74
+ for (const block of blocks)
75
+ walk(block);
76
+ return css;
77
+ }
78
+ /**
79
+ * Style keys HOISTED to the wrapper — kept here so the renderer and the
80
+ * responsive CSS generator see the SAME list.
81
+ *
82
+ * This list is a RULE: these keys apply to the outer wrapper, not the
83
+ * component root. For flat values the renderer hoists them; for responsive
84
+ * values the value leaves the inline style entirely and lands in CSS, so the
85
+ * same rule has to be expressed on the selector side — otherwise the rule
86
+ * matches both the wrapper and the root and the value is applied TWICE
87
+ * (`marginTop:'-40%'` would move content by both -335px and -256px).
88
+ */
89
+ export const FLEX_HOIST_KEYS = ['flex', 'flexGrow', 'flexShrink', 'flexBasis'];
90
+ export const LAYOUT_HOIST_KEYS = [
91
+ 'margin',
92
+ 'marginTop',
93
+ 'marginRight',
94
+ 'marginBottom',
95
+ 'marginLeft',
96
+ 'maxWidth',
97
+ 'minWidth',
98
+ ...FLEX_HOIST_KEYS,
99
+ ];
100
+ /** The attribute that tells the wrapper from the component root (the same marker states-css uses). */
101
+ export const WRAPPER_ATTR = '[data-block-wrapper]';
102
+ //# sourceMappingURL=scoped-css.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"scoped-css.js","sourceRoot":"","sources":["../../src/render/scoped-css.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;GAoBG;AAIH,4FAA4F;AAC5F,MAAM,UAAU,WAAW,CAAC,EAAU;IACpC,OAAO,EAAE,CAAC,OAAO,CAAC,QAAQ,EAAE,MAAM,CAAC,CAAA;AACrC,CAAC;AAED,yFAAyF;AACzF,MAAM,UAAU,YAAY,CAAC,IAAY;IACvC,OAAO,IAAI,CAAC,OAAO,CAAC,QAAQ,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,IAAI,CAAC,CAAC,WAAW,EAAE,EAAE,CAAC,CAAA;AAC7D,CAAC;AAED,uFAAuF;AACvF,MAAM,UAAU,WAAW,CAAC,EAAU;IACpC,OAAO,mBAAmB,WAAW,CAAC,EAAE,CAAC,IAAI,CAAA;AAC/C,CAAC;AAED;;;;;;;;;;;;GAYG;AACH,MAAM,UAAU,YAAY,CAAC,SAAkB;IAC7C,OAAO,SAAS,CAAC,CAAC,CAAC,qBAAqB,WAAW,CAAC,SAAS,CAAC,IAAI,CAAC,CAAC,CAAC,mBAAmB,CAAA;AAC1F,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,aAAa,CAAC,EAAU,EAAE,SAAkB;IAC1D,OAAO,GAAG,YAAY,CAAC,SAAS,CAAC,IAAI,WAAW,CAAC,EAAE,CAAC,EAAE,CAAA;AACxD,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,gBAAgB,CAC9B,MAAwB,EACxB,UAAoC;IAEpC,IAAI,GAAG,GAAG,EAAE,CAAA;IACZ,MAAM,IAAI,GAAG,CAAC,KAAY,EAAQ,EAAE;QAClC,GAAG,IAAI,UAAU,CAAC,KAAK,CAAC,CAAA;QACxB,IAAI,KAAK,CAAC,QAAQ,EAAE,CAAC;YACnB,KAAK,MAAM,KAAK,IAAI,KAAK,CAAC,QAAQ;gBAAE,IAAI,CAAC,KAAK,CAAC,CAAA;QACjD,CAAC;IACH,CAAC,CAAA;IACD,KAAK,MAAM,KAAK,IAAI,MAAM;QAAE,IAAI,CAAC,KAAK,CAAC,CAAA;IACvC,OAAO,GAAG,CAAA;AACZ,CAAC;AAED;;;;;;;;;;GAUG;AACH,MAAM,CAAC,MAAM,eAAe,GAAG,CAAC,MAAM,EAAE,UAAU,EAAE,YAAY,EAAE,WAAW,CAAU,CAAA;AAEvF,MAAM,CAAC,MAAM,iBAAiB,GAAG;IAC/B,QAAQ;IACR,WAAW;IACX,aAAa;IACb,cAAc;IACd,YAAY;IACZ,UAAU;IACV,UAAU;IACV,GAAG,eAAe;CACV,CAAA;AAEV,sGAAsG;AACtG,MAAM,CAAC,MAAM,YAAY,GAAG,sBAAsB,CAAA","sourcesContent":["/**\n * Shared helpers for the scoped per-block CSS collectors.\n *\n * The runtime emits several kinds of scoped `<style>` rules keyed by a block's\n * stable `data-block-id` (visibility / interaction-states / responsive-style /\n * conditional-states / group-states). They all share the SAME primitives:\n *\n * - `cssEscapeId(id)` — conservative attribute-value escaper for block ids.\n * - `camelToKebab(prop)` — CSS camelCase property name → kebab-case.\n * - `blockSelector(id)` — `[data-pw-surface] [data-block-id=\"<escaped>\"]`,\n * the scoped base selector every rule attaches to.\n * - `collectScopedCss(blocks, perBlockFn)` — walk the block tree (including\n * children) and concatenate each block's CSS as\n * produced by `perBlockFn(block)`.\n *\n * Centralising these keeps the per-collector files focused on their own\n * selector/declaration semantics and guarantees byte-identical output across\n * the family (the same escaper, the same selector string, the same walk order).\n *\n * @module @pwfabric/runtime/render/scoped-css\n */\n\nimport type { Block } from '@pwfabric/core'\n\n/** Conservative CSS attribute-selector value escaper (block ids are slugs, but be safe). */\nexport function cssEscapeId(id: string): string {\n return id.replace(/[\"\\\\]/g, '\\\\$&')\n}\n\n/** camelCase CSS property → kebab-case (e.g. `backgroundColor` → `background-color`). */\nexport function camelToKebab(prop: string): string {\n return prop.replace(/[A-Z]/g, (m) => `-${m.toLowerCase()}`)\n}\n\n/** The bare `[data-block-id=\"<escaped-id>\"]` attribute selector (no surface scope). */\nexport function blockIdAttr(id: string): string {\n return `[data-block-id=\"${cssEscapeId(id)}\"]`\n}\n\n/**\n * The surface-root selector a scoped rule hangs off.\n *\n * With a `surfaceId` this is `[data-pw-surface=\"<id>\"]` — scope carried by the\n * attribute's VALUE, not merely its presence. That matters because the embed\n * autoloader hydrates EVERY `[data-pw-surface]` element in a document, so a host\n * page can hold several surfaces at once; a value-less selector makes each\n * surface's rules apply to all of them, and the last one in document order wins.\n *\n * Without a `surfaceId` it degrades to the historical `[data-pw-surface]`, which\n * is correct for rules whose content is identical for every surface (the base\n * CSS) and for unit tests that render a single surface.\n */\nexport function surfaceScope(surfaceId?: string): string {\n return surfaceId ? `[data-pw-surface=\"${cssEscapeId(surfaceId)}\"]` : '[data-pw-surface]'\n}\n\n/**\n * The scoped base selector a per-block rule attaches to:\n * `[data-pw-surface=\"<sid>\"] [data-block-id=\"<escaped-id>\"]`. Scoped under the\n * surface root so a rule can never leak to the host page — and, when the surface\n * id is supplied, never to a SIBLING surface that happens to reuse a block id.\n */\nexport function blockSelector(id: string, surfaceId?: string): string {\n return `${surfaceScope(surfaceId)} ${blockIdAttr(id)}`\n}\n\n/**\n * Walk a surface block tree (depth-first, children after their parent — the\n * order all collectors used) and concatenate the per-block CSS produced by\n * `perBlockFn(block)`. Blocks for which `perBlockFn` returns '' contribute zero\n * bytes, so existing surfaces stay byte-identical.\n */\nexport function collectScopedCss(\n blocks: readonly Block[],\n perBlockFn: (block: Block) => string\n): string {\n let css = ''\n const walk = (block: Block): void => {\n css += perBlockFn(block)\n if (block.children) {\n for (const child of block.children) walk(child)\n }\n }\n for (const block of blocks) walk(block)\n return css\n}\n\n/**\n * Style keys HOISTED to the wrapper — kept here so the renderer and the\n * responsive CSS generator see the SAME list.\n *\n * This list is a RULE: these keys apply to the outer wrapper, not the\n * component root. For flat values the renderer hoists them; for responsive\n * values the value leaves the inline style entirely and lands in CSS, so the\n * same rule has to be expressed on the selector side — otherwise the rule\n * matches both the wrapper and the root and the value is applied TWICE\n * (`marginTop:'-40%'` would move content by both -335px and -256px).\n */\nexport const FLEX_HOIST_KEYS = ['flex', 'flexGrow', 'flexShrink', 'flexBasis'] as const\n\nexport const LAYOUT_HOIST_KEYS = [\n 'margin',\n 'marginTop',\n 'marginRight',\n 'marginBottom',\n 'marginLeft',\n 'maxWidth',\n 'minWidth',\n ...FLEX_HOIST_KEYS,\n] as const\n\n/** The attribute that tells the wrapper from the component root (the same marker states-css uses). */\nexport const WRAPPER_ATTR = '[data-block-wrapper]'\n"]}
@@ -0,0 +1,69 @@
1
+ /**
2
+ * Shell selection — the state a SPLIT shell runs on.
3
+ *
4
+ * WHY THIS IS IN THE RUNTIME AND NOT IN THE BLOCK. A split surface (list on the
5
+ * left, detail on the right) has exactly one piece of state: which item is
6
+ * selected. Kept inside the block it is invisible to everything else — the URL
7
+ * does not move, so the page cannot be linked to, the browser Back button does
8
+ * nothing, and a second block on the same surface (a header showing the
9
+ * selected record's title, a toolbar acting on it) has no way to read it.
10
+ *
11
+ * So selection is a SURFACE-level fact with a URL projection:
12
+ *
13
+ * ?<key>=<itemId>
14
+ *
15
+ * and this module is the single place that reads and writes it.
16
+ *
17
+ * THE URL IS THE SOURCE OF TRUTH when syncing is on. React state mirrors it
18
+ * rather than the other way round, which is what makes a pasted link, a Back
19
+ * press and a click on the list all land in the same place — three paths, one
20
+ * rule.
21
+ *
22
+ * INERT HOSTS DO NOT NAVIGATE. An editor or preview canvas renders the same
23
+ * block with `interactionMode: 'inert'`; there the selection stays in memory and
24
+ * the host's own URL is never touched. That mirrors the existing rule for blocks
25
+ * that navigate or write data.
26
+ */
27
+ import * as React from 'react';
28
+ type Listener = () => void;
29
+ export interface ShellSelectionStore {
30
+ /** Current selection for a key, or undefined when nothing is selected. */
31
+ get(key: string): string | undefined;
32
+ /** Select an item. Writes the URL when this store syncs. */
33
+ set(key: string, id: string | undefined): void;
34
+ subscribe(listener: Listener): () => void;
35
+ readonly syncUrl: boolean;
36
+ }
37
+ /**
38
+ * Create a selection store.
39
+ *
40
+ * `syncUrl: false` gives an in-memory store with identical semantics — the same
41
+ * hook, the same cross-block sharing, no address-bar side effects.
42
+ */
43
+ export declare function createShellSelectionStore(syncUrl: boolean): ShellSelectionStore;
44
+ export declare const ShellSelectionContext: React.Context<ShellSelectionStore | null>;
45
+ export interface ShellSelectionProviderProps {
46
+ /** Off for editor/preview canvases — selection works, the address bar does not move. */
47
+ readonly syncUrl?: boolean;
48
+ readonly children: React.ReactNode;
49
+ }
50
+ export declare function ShellSelectionProvider({ syncUrl, children, }: ShellSelectionProviderProps): React.ReactElement;
51
+ export interface ShellSelectionOptions {
52
+ /** Selected when the URL carries nothing — normally the first list item. */
53
+ readonly fallback?: string | undefined;
54
+ /**
55
+ * Override the provider. A block rendered inert must not move the host's URL
56
+ * even when the surrounding surface is live.
57
+ */
58
+ readonly syncUrl?: boolean;
59
+ }
60
+ /**
61
+ * Read and write the shell selection for `key`.
62
+ *
63
+ * Works with OR without a provider: with no `ShellSelectionProvider` above it,
64
+ * the hook makes its own store, so a block dropped into a bare React tree keeps
65
+ * behaving instead of throwing. The provider only widens the scope — one store
66
+ * per surface means two blocks reading the same key see the same value.
67
+ */
68
+ export declare function useShellSelection(key: string, options?: ShellSelectionOptions): readonly [string | undefined, (id: string | undefined) => void];
69
+ export {};