@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.
- package/LICENSE +90 -0
- package/README.md +43 -2
- package/dist/a11y/announcer.d.ts +65 -0
- package/dist/a11y/announcer.js +140 -0
- package/dist/a11y/announcer.js.map +1 -0
- package/dist/a11y/contrast.d.ts +54 -0
- package/dist/a11y/contrast.js +93 -0
- package/dist/a11y/contrast.js.map +1 -0
- package/dist/a11y/focus.d.ts +123 -0
- package/dist/a11y/focus.js +282 -0
- package/dist/a11y/focus.js.map +1 -0
- package/dist/a11y/index.d.ts +21 -0
- package/dist/a11y/index.js +18 -0
- package/dist/a11y/index.js.map +1 -0
- package/dist/a11y/keyboard.d.ts +144 -0
- package/dist/a11y/keyboard.js +317 -0
- package/dist/a11y/keyboard.js.map +1 -0
- package/dist/adapters/default-image.d.ts +25 -0
- package/dist/adapters/default-image.js +37 -0
- package/dist/adapters/default-image.js.map +1 -0
- package/dist/adapters/index.d.ts +27 -0
- package/dist/adapters/index.js +28 -0
- package/dist/adapters/index.js.map +1 -0
- package/dist/adapters/next-image.d.ts +38 -0
- package/dist/adapters/next-image.js +124 -0
- package/dist/adapters/next-image.js.map +1 -0
- package/dist/adapters/types.d.ts +61 -0
- package/dist/adapters/types.js +11 -0
- package/dist/adapters/types.js.map +1 -0
- package/dist/analytics/index.d.ts +14 -0
- package/dist/analytics/index.js +15 -0
- package/dist/analytics/index.js.map +1 -0
- package/dist/analytics/tracker.d.ts +65 -0
- package/dist/analytics/tracker.js +251 -0
- package/dist/analytics/tracker.js.map +1 -0
- package/dist/analytics/types.d.ts +130 -0
- package/dist/analytics/types.js +11 -0
- package/dist/analytics/types.js.map +1 -0
- package/dist/auth/index.d.ts +15 -0
- package/dist/auth/index.js +14 -0
- package/dist/auth/index.js.map +1 -0
- package/dist/auth/provider.d.ts +132 -0
- package/dist/auth/provider.js +473 -0
- package/dist/auth/provider.js.map +1 -0
- package/dist/auth/types.d.ts +117 -0
- package/dist/auth/types.js +9 -0
- package/dist/auth/types.js.map +1 -0
- package/dist/binding/collection.d.ts +190 -0
- package/dist/binding/collection.js +358 -0
- package/dist/binding/collection.js.map +1 -0
- package/dist/binding/datasource.d.ts +319 -0
- package/dist/binding/datasource.js +556 -0
- package/dist/binding/datasource.js.map +1 -0
- package/dist/binding/engine.d.ts +65 -0
- package/dist/binding/engine.js +268 -0
- package/dist/binding/engine.js.map +1 -0
- package/dist/binding/expression.d.ts +150 -0
- package/dist/binding/expression.js +787 -0
- package/dist/binding/expression.js.map +1 -0
- package/dist/binding/index.d.ts +19 -0
- package/dist/binding/index.js +14 -0
- package/dist/binding/index.js.map +1 -0
- package/dist/binding/two-way.d.ts +149 -0
- package/dist/binding/two-way.js +462 -0
- package/dist/binding/two-way.js.map +1 -0
- package/dist/binding/types.d.ts +119 -0
- package/dist/binding/types.js +9 -0
- package/dist/binding/types.js.map +1 -0
- package/dist/blocks/component-types.d.ts +81 -0
- package/dist/blocks/component-types.js +11 -0
- package/dist/blocks/component-types.js.map +1 -0
- package/dist/blocks/composition-rules.d.ts +168 -0
- package/dist/blocks/composition-rules.js +391 -0
- package/dist/blocks/composition-rules.js.map +1 -0
- package/dist/blocks/hooks.d.ts +31 -0
- package/dist/blocks/hooks.js +42 -0
- package/dist/blocks/hooks.js.map +1 -0
- package/dist/blocks/index.d.ts +14 -0
- package/dist/blocks/index.js +23 -0
- package/dist/blocks/index.js.map +1 -0
- package/dist/blocks/registry.d.ts +84 -0
- package/dist/blocks/registry.js +136 -0
- package/dist/blocks/registry.js.map +1 -0
- package/dist/blocks/rule-engine.d.ts +131 -0
- package/dist/blocks/rule-engine.js +321 -0
- package/dist/blocks/rule-engine.js.map +1 -0
- package/dist/blocks/surface-event-context.d.ts +13 -0
- package/dist/blocks/surface-event-context.js +14 -0
- package/dist/blocks/surface-event-context.js.map +1 -0
- package/dist/blocks/surface-id-context.d.ts +13 -0
- package/dist/blocks/surface-id-context.js +15 -0
- package/dist/blocks/surface-id-context.js.map +1 -0
- package/dist/bus.d.ts +41 -0
- package/dist/bus.js +158 -0
- package/dist/bus.js.map +1 -0
- package/dist/cache/index.d.ts +9 -0
- package/dist/cache/index.js +10 -0
- package/dist/cache/index.js.map +1 -0
- package/dist/cache/memory.d.ts +32 -0
- package/dist/cache/memory.js +138 -0
- package/dist/cache/memory.js.map +1 -0
- package/dist/cache/types.d.ts +62 -0
- package/dist/cache/types.js +9 -0
- package/dist/cache/types.js.map +1 -0
- package/dist/capability/index.d.ts +72 -0
- package/dist/capability/index.js +87 -0
- package/dist/capability/index.js.map +1 -0
- package/dist/capability/kernel-capabilities.d.ts +31 -0
- package/dist/capability/kernel-capabilities.js +36 -0
- package/dist/capability/kernel-capabilities.js.map +1 -0
- package/dist/capability/platform-capabilities.d.ts +71 -0
- package/dist/capability/platform-capabilities.js +267 -0
- package/dist/capability/platform-capabilities.js.map +1 -0
- package/dist/capability/type-mapping.d.ts +70 -0
- package/dist/capability/type-mapping.js +107 -0
- package/dist/capability/type-mapping.js.map +1 -0
- package/dist/capability/validation.d.ts +46 -0
- package/dist/capability/validation.js +54 -0
- package/dist/capability/validation.js.map +1 -0
- package/dist/connectors/declared-connector.d.ts +48 -0
- package/dist/connectors/declared-connector.js +333 -0
- package/dist/connectors/declared-connector.js.map +1 -0
- package/dist/connectors/engine-registry.d.ts +50 -0
- package/dist/connectors/engine-registry.js +135 -0
- package/dist/connectors/engine-registry.js.map +1 -0
- package/dist/connectors/index.d.ts +14 -0
- package/dist/connectors/index.js +14 -0
- package/dist/connectors/index.js.map +1 -0
- package/dist/connectors/module-loader.d.ts +70 -0
- package/dist/connectors/module-loader.js +143 -0
- package/dist/connectors/module-loader.js.map +1 -0
- package/dist/connectors/types.d.ts +174 -0
- package/dist/connectors/types.js +23 -0
- package/dist/connectors/types.js.map +1 -0
- package/dist/context.d.ts +27 -0
- package/dist/context.js +38 -0
- package/dist/context.js.map +1 -0
- package/dist/data/DataCapabilityProvider.d.ts +39 -0
- package/dist/data/DataCapabilityProvider.js +58 -0
- package/dist/data/DataCapabilityProvider.js.map +1 -0
- package/dist/data/index.d.ts +17 -0
- package/dist/data/index.js +18 -0
- package/dist/data/index.js.map +1 -0
- package/dist/data/manager.d.ts +40 -0
- package/dist/data/manager.js +442 -0
- package/dist/data/manager.js.map +1 -0
- package/dist/data/types.d.ts +218 -0
- package/dist/data/types.js +2 -0
- package/dist/data/types.js.map +1 -0
- package/dist/entity/aggregate.d.ts +8 -0
- package/dist/entity/aggregate.js +24 -0
- package/dist/entity/aggregate.js.map +1 -0
- package/dist/entity/apply-query.d.ts +58 -0
- package/dist/entity/apply-query.js +264 -0
- package/dist/entity/apply-query.js.map +1 -0
- package/dist/entity/behavior.d.ts +94 -0
- package/dist/entity/behavior.js +78 -0
- package/dist/entity/behavior.js.map +1 -0
- package/dist/entity/connector.d.ts +141 -0
- package/dist/entity/connector.js +89 -0
- package/dist/entity/connector.js.map +1 -0
- package/dist/entity/connectors/index.d.ts +12 -0
- package/dist/entity/connectors/index.js +11 -0
- package/dist/entity/connectors/index.js.map +1 -0
- package/dist/entity/connectors/static.d.ts +51 -0
- package/dist/entity/connectors/static.js +245 -0
- package/dist/entity/connectors/static.js.map +1 -0
- package/dist/entity/entity-datasource.d.ts +50 -0
- package/dist/entity/entity-datasource.js +33 -0
- package/dist/entity/entity-datasource.js.map +1 -0
- package/dist/entity/facade.d.ts +70 -0
- package/dist/entity/facade.js +70 -0
- package/dist/entity/facade.js.map +1 -0
- package/dist/entity/http-connector.d.ts +123 -0
- package/dist/entity/http-connector.js +295 -0
- package/dist/entity/http-connector.js.map +1 -0
- package/dist/entity/index.d.ts +38 -0
- package/dist/entity/index.js +31 -0
- package/dist/entity/index.js.map +1 -0
- package/dist/entity/postgres-connector.d.ts +64 -0
- package/dist/entity/postgres-connector.js +239 -0
- package/dist/entity/postgres-connector.js.map +1 -0
- package/dist/entity/registry.d.ts +59 -0
- package/dist/entity/registry.js +90 -0
- package/dist/entity/registry.js.map +1 -0
- package/dist/entity/store.d.ts +66 -0
- package/dist/entity/store.js +349 -0
- package/dist/entity/store.js.map +1 -0
- package/dist/entity/types.d.ts +180 -0
- package/dist/entity/types.js +10 -0
- package/dist/entity/types.js.map +1 -0
- package/dist/execution-context.d.ts +88 -0
- package/dist/execution-context.js +146 -0
- package/dist/execution-context.js.map +1 -0
- package/dist/executor.d.ts +27 -0
- package/dist/executor.js +33 -0
- package/dist/executor.js.map +1 -0
- package/dist/forms/form-entity-bridge.d.ts +94 -0
- package/dist/forms/form-entity-bridge.js +96 -0
- package/dist/forms/form-entity-bridge.js.map +1 -0
- package/dist/forms/form-write-target.d.ts +34 -0
- package/dist/forms/form-write-target.js +81 -0
- package/dist/forms/form-write-target.js.map +1 -0
- package/dist/forms/index.d.ts +22 -0
- package/dist/forms/index.js +25 -0
- package/dist/forms/index.js.map +1 -0
- package/dist/forms/named-control-values.d.ts +27 -0
- package/dist/forms/named-control-values.js +42 -0
- package/dist/forms/named-control-values.js.map +1 -0
- package/dist/forms/processor.d.ts +55 -0
- package/dist/forms/processor.js +154 -0
- package/dist/forms/processor.js.map +1 -0
- package/dist/forms/types.d.ts +174 -0
- package/dist/forms/types.js +33 -0
- package/dist/forms/types.js.map +1 -0
- package/dist/forms/validator.d.ts +61 -0
- package/dist/forms/validator.js +218 -0
- package/dist/forms/validator.js.map +1 -0
- package/dist/graph/index.d.ts +10 -0
- package/dist/graph/index.js +9 -0
- package/dist/graph/index.js.map +1 -0
- package/dist/graph/resolver.d.ts +66 -0
- package/dist/graph/resolver.js +243 -0
- package/dist/graph/resolver.js.map +1 -0
- package/dist/graph/types.d.ts +125 -0
- package/dist/graph/types.js +9 -0
- package/dist/graph/types.js.map +1 -0
- package/dist/hooks/useInstalledAtoms.d.ts +96 -0
- package/dist/hooks/useInstalledAtoms.js +92 -0
- package/dist/hooks/useInstalledAtoms.js.map +1 -0
- package/dist/i18n/index.d.ts +15 -0
- package/dist/i18n/index.js +14 -0
- package/dist/i18n/index.js.map +1 -0
- package/dist/i18n/translator.d.ts +76 -0
- package/dist/i18n/translator.js +357 -0
- package/dist/i18n/translator.js.map +1 -0
- package/dist/i18n/types.d.ts +93 -0
- package/dist/i18n/types.js +9 -0
- package/dist/i18n/types.js.map +1 -0
- package/dist/index.d.ts +64 -0
- package/dist/index.js +95 -0
- package/dist/index.js.map +1 -0
- package/dist/kernel.d.ts +47 -0
- package/dist/kernel.js +258 -0
- package/dist/kernel.js.map +1 -0
- package/dist/perf/budget.d.ts +92 -0
- package/dist/perf/budget.js +122 -0
- package/dist/perf/budget.js.map +1 -0
- package/dist/perf/index.d.ts +16 -0
- package/dist/perf/index.js +13 -0
- package/dist/perf/index.js.map +1 -0
- package/dist/perf/render-timer.d.ts +90 -0
- package/dist/perf/render-timer.js +136 -0
- package/dist/perf/render-timer.js.map +1 -0
- package/dist/perf/reporter.d.ts +126 -0
- package/dist/perf/reporter.js +241 -0
- package/dist/perf/reporter.js.map +1 -0
- package/dist/perf/web-vitals.d.ts +111 -0
- package/dist/perf/web-vitals.js +268 -0
- package/dist/perf/web-vitals.js.map +1 -0
- package/dist/registry.d.ts +63 -0
- package/dist/registry.js +126 -0
- package/dist/registry.js.map +1 -0
- package/dist/render/BehaviorSurfaceProvider.d.ts +65 -0
- package/dist/render/BehaviorSurfaceProvider.js +185 -0
- package/dist/render/BehaviorSurfaceProvider.js.map +1 -0
- package/dist/render/BlockErrorBoundary.d.ts +26 -0
- package/dist/render/BlockErrorBoundary.js +41 -0
- package/dist/render/BlockErrorBoundary.js.map +1 -0
- package/dist/render/DataBoundSurfaceRenderer.d.ts +78 -0
- package/dist/render/DataBoundSurfaceRenderer.js +998 -0
- package/dist/render/DataBoundSurfaceRenderer.js.map +1 -0
- package/dist/render/DynamicBlockWrapper.d.ts +23 -0
- package/dist/render/DynamicBlockWrapper.js +117 -0
- package/dist/render/DynamicBlockWrapper.js.map +1 -0
- package/dist/render/appearance-resolver.d.ts +50 -0
- package/dist/render/appearance-resolver.js +78 -0
- package/dist/render/appearance-resolver.js.map +1 -0
- package/dist/render/capability-gate.d.ts +69 -0
- package/dist/render/capability-gate.js +94 -0
- package/dist/render/capability-gate.js.map +1 -0
- package/dist/render/conditional-states-css.d.ts +41 -0
- package/dist/render/conditional-states-css.js +82 -0
- package/dist/render/conditional-states-css.js.map +1 -0
- package/dist/render/connections-context.d.ts +31 -0
- package/dist/render/connections-context.js +34 -0
- package/dist/render/connections-context.js.map +1 -0
- package/dist/render/dark-theme-css.d.ts +36 -0
- package/dist/render/dark-theme-css.js +67 -0
- package/dist/render/dark-theme-css.js.map +1 -0
- package/dist/render/data-binding-types.d.ts +191 -0
- package/dist/render/data-binding-types.js +11 -0
- package/dist/render/data-binding-types.js.map +1 -0
- package/dist/render/data-cache.d.ts +30 -0
- package/dist/render/data-cache.js +37 -0
- package/dist/render/data-cache.js.map +1 -0
- package/dist/render/derive-dark-theme.d.ts +17 -0
- package/dist/render/derive-dark-theme.js +18 -0
- package/dist/render/derive-dark-theme.js.map +1 -0
- package/dist/render/dynamic-artifact-context.d.ts +77 -0
- package/dist/render/dynamic-artifact-context.js +89 -0
- package/dist/render/dynamic-artifact-context.js.map +1 -0
- package/dist/render/dynamic-block-loader.d.ts +80 -0
- package/dist/render/dynamic-block-loader.js +197 -0
- package/dist/render/dynamic-block-loader.js.map +1 -0
- package/dist/render/endpoint.d.ts +18 -0
- package/dist/render/endpoint.js +109 -0
- package/dist/render/endpoint.js.map +1 -0
- package/dist/render/entity-facade-context.d.ts +34 -0
- package/dist/render/entity-facade-context.js +37 -0
- package/dist/render/entity-facade-context.js.map +1 -0
- package/dist/render/group-states-css.d.ts +41 -0
- package/dist/render/group-states-css.js +73 -0
- package/dist/render/group-states-css.js.map +1 -0
- package/dist/render/hooks/useSurfaceEvents.d.ts +8 -0
- package/dist/render/hooks/useSurfaceEvents.js +9 -0
- package/dist/render/hooks/useSurfaceEvents.js.map +1 -0
- package/dist/render/hooks/useSurfaceId.d.ts +8 -0
- package/dist/render/hooks/useSurfaceId.js +9 -0
- package/dist/render/hooks/useSurfaceId.js.map +1 -0
- package/dist/render/index.d.ts +48 -0
- package/dist/render/index.js +61 -0
- package/dist/render/index.js.map +1 -0
- package/dist/render/interaction-rule-engine.d.ts +12 -0
- package/dist/render/interaction-rule-engine.js +47 -0
- package/dist/render/interaction-rule-engine.js.map +1 -0
- package/dist/render/keyframes-css.d.ts +31 -0
- package/dist/render/keyframes-css.js +44 -0
- package/dist/render/keyframes-css.js.map +1 -0
- package/dist/render/query-state.d.ts +3 -0
- package/dist/render/query-state.js +70 -0
- package/dist/render/query-state.js.map +1 -0
- package/dist/render/renderer.d.ts +44 -0
- package/dist/render/renderer.js +937 -0
- package/dist/render/renderer.js.map +1 -0
- package/dist/render/resolve-expressions.d.ts +37 -0
- package/dist/render/resolve-expressions.js +309 -0
- package/dist/render/resolve-expressions.js.map +1 -0
- package/dist/render/responsive-style-css.d.ts +42 -0
- package/dist/render/responsive-style-css.js +123 -0
- package/dist/render/responsive-style-css.js.map +1 -0
- package/dist/render/responsive.d.ts +49 -0
- package/dist/render/responsive.js +99 -0
- package/dist/render/responsive.js.map +1 -0
- package/dist/render/scoped-css.d.ts +71 -0
- package/dist/render/scoped-css.js +102 -0
- package/dist/render/scoped-css.js.map +1 -0
- package/dist/render/shell-selection.d.ts +69 -0
- package/dist/render/shell-selection.js +117 -0
- package/dist/render/shell-selection.js.map +1 -0
- package/dist/render/states-css.d.ts +32 -0
- package/dist/render/states-css.js +63 -0
- package/dist/render/states-css.js.map +1 -0
- package/dist/render/surface-data-context.d.ts +18 -0
- package/dist/render/surface-data-context.js +21 -0
- package/dist/render/surface-data-context.js.map +1 -0
- package/dist/render/surface-event-bus.d.ts +19 -0
- package/dist/render/surface-event-bus.js +68 -0
- package/dist/render/surface-event-bus.js.map +1 -0
- package/dist/render/surface-event-context.d.ts +11 -0
- package/dist/render/surface-event-context.js +12 -0
- package/dist/render/surface-event-context.js.map +1 -0
- package/dist/render/surface-id-context.d.ts +8 -0
- package/dist/render/surface-id-context.js +9 -0
- package/dist/render/surface-id-context.js.map +1 -0
- package/dist/render/theme-utils.d.ts +14 -0
- package/dist/render/theme-utils.js +15 -0
- package/dist/render/theme-utils.js.map +1 -0
- package/dist/render/types.d.ts +282 -0
- package/dist/render/types.js +9 -0
- package/dist/render/types.js.map +1 -0
- package/dist/render/visibility-css.d.ts +42 -0
- package/dist/render/visibility-css.js +119 -0
- package/dist/render/visibility-css.js.map +1 -0
- package/dist/render/width-scope.d.ts +34 -0
- package/dist/render/width-scope.js +44 -0
- package/dist/render/width-scope.js.map +1 -0
- package/dist/render/write-only-sources.d.ts +33 -0
- package/dist/render/write-only-sources.js +99 -0
- package/dist/render/write-only-sources.js.map +1 -0
- package/dist/routing/index.d.ts +14 -0
- package/dist/routing/index.js +15 -0
- package/dist/routing/index.js.map +1 -0
- package/dist/routing/router.d.ts +42 -0
- package/dist/routing/router.js +218 -0
- package/dist/routing/router.js.map +1 -0
- package/dist/routing/types.d.ts +124 -0
- package/dist/routing/types.js +9 -0
- package/dist/routing/types.js.map +1 -0
- package/dist/seo/generator.d.ts +39 -0
- package/dist/seo/generator.js +236 -0
- package/dist/seo/generator.js.map +1 -0
- package/dist/seo/index.d.ts +14 -0
- package/dist/seo/index.js +15 -0
- package/dist/seo/index.js.map +1 -0
- package/dist/seo/types.d.ts +181 -0
- package/dist/seo/types.js +9 -0
- package/dist/seo/types.js.map +1 -0
- package/dist/state/index.d.ts +15 -0
- package/dist/state/index.js +16 -0
- package/dist/state/index.js.map +1 -0
- package/dist/state/manager.d.ts +33 -0
- package/dist/state/manager.js +81 -0
- package/dist/state/manager.js.map +1 -0
- package/dist/state/store.d.ts +40 -0
- package/dist/state/store.js +145 -0
- package/dist/state/store.js.map +1 -0
- package/dist/state/types.d.ts +107 -0
- package/dist/state/types.js +9 -0
- package/dist/state/types.js.map +1 -0
- package/dist/surface/expression.d.ts +65 -0
- package/dist/surface/expression.js +179 -0
- package/dist/surface/expression.js.map +1 -0
- package/dist/surface/index.d.ts +32 -0
- package/dist/surface/index.js +25 -0
- package/dist/surface/index.js.map +1 -0
- package/dist/surface/interpreter.d.ts +96 -0
- package/dist/surface/interpreter.js +231 -0
- package/dist/surface/interpreter.js.map +1 -0
- package/dist/surface/layout.d.ts +54 -0
- package/dist/surface/layout.js +288 -0
- package/dist/surface/layout.js.map +1 -0
- package/dist/surface/output.d.ts +90 -0
- package/dist/surface/output.js +104 -0
- package/dist/surface/output.js.map +1 -0
- package/dist/surface/primitives.d.ts +180 -0
- package/dist/surface/primitives.js +339 -0
- package/dist/surface/primitives.js.map +1 -0
- package/dist/surface/renderer.d.ts +96 -0
- package/dist/surface/renderer.js +190 -0
- package/dist/surface/renderer.js.map +1 -0
- package/dist/surface/schemas.d.ts +181 -0
- package/dist/surface/schemas.js +142 -0
- package/dist/surface/schemas.js.map +1 -0
- package/dist/surface/transforms.d.ts +144 -0
- package/dist/surface/transforms.js +120 -0
- package/dist/surface/transforms.js.map +1 -0
- package/dist/surface/types.d.ts +160 -0
- package/dist/surface/types.js +51 -0
- package/dist/surface/types.js.map +1 -0
- package/dist/surface/validation.d.ts +123 -0
- package/dist/surface/validation.js +147 -0
- package/dist/surface/validation.js.map +1 -0
- package/dist/validator.d.ts +55 -0
- package/dist/validator.js +100 -0
- package/dist/validator.js.map +1 -0
- package/package.json +106 -3
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
/** The form a single state value takes inside a mixed endpoint. */
|
|
2
|
+
export declare function encodeEndpointValue(value: unknown): string;
|
|
3
|
+
export declare function resolveEndpoint(endpoint: string, state: Readonly<Record<string, unknown>>): string;
|
|
4
|
+
/**
|
|
5
|
+
* Would this endpoint be requested with a required value MISSING?
|
|
6
|
+
*
|
|
7
|
+
* A detail source is authored as `/carts/{{state.numara}}`. Until the visitor
|
|
8
|
+
* types a number, `numara` is empty and the request would go to `/carts/` —
|
|
9
|
+
* the whole collection (DummyJSON redirects there), which then fails `returns`
|
|
10
|
+
* and opens the page on an error. A placeholder in the PATH is
|
|
11
|
+
* required: when it resolves to nothing (`''`, `null`, `undefined`) or cannot
|
|
12
|
+
* be evaluated, the source is not fetched at all and stays idle.
|
|
13
|
+
*
|
|
14
|
+
* A placeholder in the QUERY STRING (`?q={{state.q}}`) is not required — an
|
|
15
|
+
* empty search box legitimately means "no constraint". An endpoint that is
|
|
16
|
+
* ONE expression (`{{state.url}}`) is required as a whole.
|
|
17
|
+
*/
|
|
18
|
+
export declare function endpointMissingPathValue(endpoint: string, state: Readonly<Record<string, unknown>>): boolean;
|
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* resolveEndpoint — place surface state into a REST source's `endpoint`.
|
|
3
|
+
*
|
|
4
|
+
* EVERY VALUE IS URL-ENCODED WHEN THE ENDPOINT MIXES TEXT AND EXPRESSIONS.
|
|
5
|
+
*
|
|
6
|
+
* A raw interpolation would be harmless if state could only come from the
|
|
7
|
+
* page's own controls, but a published app can seed state from its address
|
|
8
|
+
* (`/product?id=12`): `?id=12/../../admin` or `?id=1%26role=owner` would
|
|
9
|
+
* rewrite the path or the query of a request the visitor's credential rides on. A space or a `ü`
|
|
10
|
+
* was always encoded by `fetch`; what this adds is `& # + % ? /`.
|
|
11
|
+
*
|
|
12
|
+
* Three rules:
|
|
13
|
+
*
|
|
14
|
+
* - mixed endpoint (`/products/{{state.id}}`, `?q={{state.q}}`): each value
|
|
15
|
+
* goes through `encodeURIComponent` — ALL values, not only the ones that
|
|
16
|
+
* came from the address, because the renderer cannot tell them apart;
|
|
17
|
+
* - a value that is exactly `.` or `..` becomes `''` — `encodeURIComponent`
|
|
18
|
+
* leaves both alone, and a lone `..` segment still climbs a directory;
|
|
19
|
+
* - an endpoint that is ONE expression (`"{{state.url}}"`) is left as it
|
|
20
|
+
* resolves, unencoded — today's behaviour. The published-app runner never
|
|
21
|
+
* seeds a key read there (nor one read in the scheme/host part), so the
|
|
22
|
+
* address cannot reach it.
|
|
23
|
+
*
|
|
24
|
+
* A failed expression leaves the endpoint as authored, as it always did.
|
|
25
|
+
*
|
|
26
|
+
* @module @pwfabric/runtime/render/endpoint
|
|
27
|
+
*/
|
|
28
|
+
import { createExpressionContext, evaluate, interpolate } from '../surface/expression.js';
|
|
29
|
+
/** `"{{ expr }}"` and nothing else (surrounding whitespace allowed). */
|
|
30
|
+
const WHOLE = /^\s*\{\{\s*([^{}]+?)\s*\}\}\s*$/;
|
|
31
|
+
/** One `{{ … }}` placeholder — the same shape `interpolate` walks. */
|
|
32
|
+
const PLACEHOLDER = /\{\{(.+?)\}\}/g;
|
|
33
|
+
/** The form a single state value takes inside a mixed endpoint. */
|
|
34
|
+
export function encodeEndpointValue(value) {
|
|
35
|
+
const s = String(value ?? '');
|
|
36
|
+
if (s === '.' || s === '..')
|
|
37
|
+
return '';
|
|
38
|
+
return encodeURIComponent(s);
|
|
39
|
+
}
|
|
40
|
+
export function resolveEndpoint(endpoint, state) {
|
|
41
|
+
if (!endpoint.includes('{{'))
|
|
42
|
+
return endpoint;
|
|
43
|
+
const ctx = createExpressionContext({ state: state });
|
|
44
|
+
// One expression: resolved as before, no encoding (see module note).
|
|
45
|
+
if (WHOLE.test(endpoint)) {
|
|
46
|
+
const r = interpolate(endpoint, ctx);
|
|
47
|
+
return r.success ? r.value : endpoint;
|
|
48
|
+
}
|
|
49
|
+
let failed = false;
|
|
50
|
+
const out = endpoint.replace(PLACEHOLDER, (_match, expression) => {
|
|
51
|
+
if (failed)
|
|
52
|
+
return '';
|
|
53
|
+
const r = evaluate(expression.trim(), ctx);
|
|
54
|
+
if (!r.success) {
|
|
55
|
+
failed = true;
|
|
56
|
+
return '';
|
|
57
|
+
}
|
|
58
|
+
return encodeEndpointValue(r.value);
|
|
59
|
+
});
|
|
60
|
+
return failed ? endpoint : out;
|
|
61
|
+
}
|
|
62
|
+
/**
|
|
63
|
+
* Would this endpoint be requested with a required value MISSING?
|
|
64
|
+
*
|
|
65
|
+
* A detail source is authored as `/carts/{{state.numara}}`. Until the visitor
|
|
66
|
+
* types a number, `numara` is empty and the request would go to `/carts/` —
|
|
67
|
+
* the whole collection (DummyJSON redirects there), which then fails `returns`
|
|
68
|
+
* and opens the page on an error. A placeholder in the PATH is
|
|
69
|
+
* required: when it resolves to nothing (`''`, `null`, `undefined`) or cannot
|
|
70
|
+
* be evaluated, the source is not fetched at all and stays idle.
|
|
71
|
+
*
|
|
72
|
+
* A placeholder in the QUERY STRING (`?q={{state.q}}`) is not required — an
|
|
73
|
+
* empty search box legitimately means "no constraint". An endpoint that is
|
|
74
|
+
* ONE expression (`{{state.url}}`) is required as a whole.
|
|
75
|
+
*/
|
|
76
|
+
export function endpointMissingPathValue(endpoint, state) {
|
|
77
|
+
if (!endpoint.includes('{{'))
|
|
78
|
+
return false;
|
|
79
|
+
const ctx = createExpressionContext({ state: state });
|
|
80
|
+
const empty = (expression) => {
|
|
81
|
+
const r = evaluate(expression.trim(), ctx);
|
|
82
|
+
return !r.success || r.value === undefined || r.value === null || String(r.value).trim() === '';
|
|
83
|
+
};
|
|
84
|
+
const whole = WHOLE.exec(endpoint);
|
|
85
|
+
if (whole)
|
|
86
|
+
return empty(whole[1] ?? '');
|
|
87
|
+
// The path part ends at the first `?` or `#` that is not inside a placeholder.
|
|
88
|
+
let pathEnd = endpoint.length;
|
|
89
|
+
for (let i = 0, depth = 0; i < endpoint.length; i++) {
|
|
90
|
+
if (endpoint.startsWith('{{', i)) {
|
|
91
|
+
depth++;
|
|
92
|
+
i++;
|
|
93
|
+
}
|
|
94
|
+
else if (endpoint.startsWith('}}', i) && depth > 0) {
|
|
95
|
+
depth--;
|
|
96
|
+
i++;
|
|
97
|
+
}
|
|
98
|
+
else if (depth === 0 && (endpoint[i] === '?' || endpoint[i] === '#')) {
|
|
99
|
+
pathEnd = i;
|
|
100
|
+
break;
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
for (const m of endpoint.slice(0, pathEnd).matchAll(PLACEHOLDER)) {
|
|
104
|
+
if (empty(m[1] ?? ''))
|
|
105
|
+
return true;
|
|
106
|
+
}
|
|
107
|
+
return false;
|
|
108
|
+
}
|
|
109
|
+
//# sourceMappingURL=endpoint.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"endpoint.js","sourceRoot":"","sources":["../../src/render/endpoint.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * resolveEndpoint — place surface state into a REST source's `endpoint`.\n *\n * EVERY VALUE IS URL-ENCODED WHEN THE ENDPOINT MIXES TEXT AND EXPRESSIONS.\n *\n * A raw interpolation would be harmless if state could only come from the\n * page's own controls, but a published app can seed state from its address\n * (`/product?id=12`): `?id=12/../../admin` or `?id=1%26role=owner` would\n * rewrite the path or the query of a request the visitor's credential rides on. A space or a `ü`\n * was always encoded by `fetch`; what this adds is `& # + % ? /`.\n *\n * Three rules:\n *\n * - mixed endpoint (`/products/{{state.id}}`, `?q={{state.q}}`): each value\n * goes through `encodeURIComponent` — ALL values, not only the ones that\n * came from the address, because the renderer cannot tell them apart;\n * - a value that is exactly `.` or `..` becomes `''` — `encodeURIComponent`\n * leaves both alone, and a lone `..` segment still climbs a directory;\n * - an endpoint that is ONE expression (`\"{{state.url}}\"`) is left as it\n * resolves, unencoded — today's behaviour. The published-app runner never\n * seeds a key read there (nor one read in the scheme/host part), so the\n * address cannot reach it.\n *\n * A failed expression leaves the endpoint as authored, as it always did.\n *\n * @module @pwfabric/runtime/render/endpoint\n */\nimport { createExpressionContext, evaluate, interpolate } from '../surface/expression.js'\n\n/** `\"{{ expr }}\"` and nothing else (surrounding whitespace allowed). */\nconst WHOLE = /^\\s*\\{\\{\\s*([^{}]+?)\\s*\\}\\}\\s*$/\n\n/** One `{{ … }}` placeholder — the same shape `interpolate` walks. */\nconst PLACEHOLDER = /\\{\\{(.+?)\\}\\}/g\n\n/** The form a single state value takes inside a mixed endpoint. */\nexport function encodeEndpointValue(value: unknown): string {\n const s = String(value ?? '')\n if (s === '.' || s === '..') return ''\n return encodeURIComponent(s)\n}\n\nexport function resolveEndpoint(endpoint: string, state: Readonly<Record<string, unknown>>): string {\n if (!endpoint.includes('{{')) return endpoint\n const ctx = createExpressionContext({ state: state as Record<string, unknown> })\n\n // One expression: resolved as before, no encoding (see module note).\n if (WHOLE.test(endpoint)) {\n const r = interpolate(endpoint, ctx)\n return r.success ? r.value : endpoint\n }\n\n let failed = false\n const out = endpoint.replace(PLACEHOLDER, (_match, expression: string) => {\n if (failed) return ''\n const r = evaluate(expression.trim(), ctx)\n if (!r.success) {\n failed = true\n return ''\n }\n return encodeEndpointValue(r.value)\n })\n return failed ? endpoint : out\n}\n\n/**\n * Would this endpoint be requested with a required value MISSING?\n *\n * A detail source is authored as `/carts/{{state.numara}}`. Until the visitor\n * types a number, `numara` is empty and the request would go to `/carts/` —\n * the whole collection (DummyJSON redirects there), which then fails `returns`\n * and opens the page on an error. A placeholder in the PATH is\n * required: when it resolves to nothing (`''`, `null`, `undefined`) or cannot\n * be evaluated, the source is not fetched at all and stays idle.\n *\n * A placeholder in the QUERY STRING (`?q={{state.q}}`) is not required — an\n * empty search box legitimately means \"no constraint\". An endpoint that is\n * ONE expression (`{{state.url}}`) is required as a whole.\n */\nexport function endpointMissingPathValue(\n endpoint: string,\n state: Readonly<Record<string, unknown>>\n): boolean {\n if (!endpoint.includes('{{')) return false\n const ctx = createExpressionContext({ state: state as Record<string, unknown> })\n const empty = (expression: string): boolean => {\n const r = evaluate(expression.trim(), ctx)\n return !r.success || r.value === undefined || r.value === null || String(r.value).trim() === ''\n }\n const whole = WHOLE.exec(endpoint)\n if (whole) return empty(whole[1] ?? '')\n\n // The path part ends at the first `?` or `#` that is not inside a placeholder.\n let pathEnd = endpoint.length\n for (let i = 0, depth = 0; i < endpoint.length; i++) {\n if (endpoint.startsWith('{{', i)) {\n depth++\n i++\n } else if (endpoint.startsWith('}}', i) && depth > 0) {\n depth--\n i++\n } else if (depth === 0 && (endpoint[i] === '?' || endpoint[i] === '#')) {\n pathEnd = i\n break\n }\n }\n for (const m of endpoint.slice(0, pathEnd).matchAll(PLACEHOLDER)) {\n if (empty(m[1] ?? '')) return true\n }\n return false\n}\n"]}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Entity Facade React Context
|
|
3
|
+
*
|
|
4
|
+
* Provides EntityFacade to the surface render tree via React
|
|
5
|
+
* context. Pattern mirrors SurfaceRoutingContext / useSurfaceRouting().
|
|
6
|
+
*
|
|
7
|
+
* Injection point: EntityFacadeContext.Provider wraps BehaviorSurfaceProvider
|
|
8
|
+
* inside SurfaceRenderer when entityFacade prop is supplied.
|
|
9
|
+
*
|
|
10
|
+
* @module @pwfabric/runtime/render/entity-facade-context
|
|
11
|
+
*/
|
|
12
|
+
import type { EntityFacade } from '../entity/facade.js';
|
|
13
|
+
/**
|
|
14
|
+
* React context that carries an EntityFacade instance through the render tree.
|
|
15
|
+
* Defaults to null — blocks that require entity access check for null and
|
|
16
|
+
* gracefully handle the absent-facade case.
|
|
17
|
+
*/
|
|
18
|
+
export declare const EntityFacadeContext: import("react").Context<EntityFacade | null>;
|
|
19
|
+
/**
|
|
20
|
+
* Returns the EntityFacade from the nearest EntityFacadeContext.Provider.
|
|
21
|
+
* Returns null when no provider is present (entity support not configured).
|
|
22
|
+
*
|
|
23
|
+
* @example
|
|
24
|
+
* ```tsx
|
|
25
|
+
* import { useEntityFacade } from '@pwfabric/runtime/render'
|
|
26
|
+
*
|
|
27
|
+
* function MyBlock() {
|
|
28
|
+
* const facade = useEntityFacade()
|
|
29
|
+
* if (!facade) return null // No entity support configured
|
|
30
|
+
* const result = await facade.store.query('Employee', {})
|
|
31
|
+
* }
|
|
32
|
+
* ```
|
|
33
|
+
*/
|
|
34
|
+
export declare function useEntityFacade(): EntityFacade | null;
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Entity Facade React Context
|
|
3
|
+
*
|
|
4
|
+
* Provides EntityFacade to the surface render tree via React
|
|
5
|
+
* context. Pattern mirrors SurfaceRoutingContext / useSurfaceRouting().
|
|
6
|
+
*
|
|
7
|
+
* Injection point: EntityFacadeContext.Provider wraps BehaviorSurfaceProvider
|
|
8
|
+
* inside SurfaceRenderer when entityFacade prop is supplied.
|
|
9
|
+
*
|
|
10
|
+
* @module @pwfabric/runtime/render/entity-facade-context
|
|
11
|
+
*/
|
|
12
|
+
import { createContext, useContext } from 'react';
|
|
13
|
+
/**
|
|
14
|
+
* React context that carries an EntityFacade instance through the render tree.
|
|
15
|
+
* Defaults to null — blocks that require entity access check for null and
|
|
16
|
+
* gracefully handle the absent-facade case.
|
|
17
|
+
*/
|
|
18
|
+
export const EntityFacadeContext = createContext(null);
|
|
19
|
+
/**
|
|
20
|
+
* Returns the EntityFacade from the nearest EntityFacadeContext.Provider.
|
|
21
|
+
* Returns null when no provider is present (entity support not configured).
|
|
22
|
+
*
|
|
23
|
+
* @example
|
|
24
|
+
* ```tsx
|
|
25
|
+
* import { useEntityFacade } from '@pwfabric/runtime/render'
|
|
26
|
+
*
|
|
27
|
+
* function MyBlock() {
|
|
28
|
+
* const facade = useEntityFacade()
|
|
29
|
+
* if (!facade) return null // No entity support configured
|
|
30
|
+
* const result = await facade.store.query('Employee', {})
|
|
31
|
+
* }
|
|
32
|
+
* ```
|
|
33
|
+
*/
|
|
34
|
+
export function useEntityFacade() {
|
|
35
|
+
return useContext(EntityFacadeContext);
|
|
36
|
+
}
|
|
37
|
+
//# sourceMappingURL=entity-facade-context.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"entity-facade-context.js","sourceRoot":"","sources":["../../src/render/entity-facade-context.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAEH,OAAO,EAAE,aAAa,EAAE,UAAU,EAAE,MAAM,OAAO,CAAA;AAGjD;;;;GAIG;AACH,MAAM,CAAC,MAAM,mBAAmB,GAAG,aAAa,CAAsB,IAAI,CAAC,CAAA;AAE3E;;;;;;;;;;;;;;GAcG;AACH,MAAM,UAAU,eAAe;IAC7B,OAAO,UAAU,CAAC,mBAAmB,CAAC,CAAA;AACxC,CAAC","sourcesContent":["/**\n * Entity Facade React Context\n *\n * Provides EntityFacade to the surface render tree via React\n * context. Pattern mirrors SurfaceRoutingContext / useSurfaceRouting().\n *\n * Injection point: EntityFacadeContext.Provider wraps BehaviorSurfaceProvider\n * inside SurfaceRenderer when entityFacade prop is supplied.\n *\n * @module @pwfabric/runtime/render/entity-facade-context\n */\n\nimport { createContext, useContext } from 'react'\nimport type { EntityFacade } from '../entity/facade.js'\n\n/**\n * React context that carries an EntityFacade instance through the render tree.\n * Defaults to null — blocks that require entity access check for null and\n * gracefully handle the absent-facade case.\n */\nexport const EntityFacadeContext = createContext<EntityFacade | null>(null)\n\n/**\n * Returns the EntityFacade from the nearest EntityFacadeContext.Provider.\n * Returns null when no provider is present (entity support not configured).\n *\n * @example\n * ```tsx\n * import { useEntityFacade } from '@pwfabric/runtime/render'\n *\n * function MyBlock() {\n * const facade = useEntityFacade()\n * if (!facade) return null // No entity support configured\n * const result = await facade.store.query('Employee', {})\n * }\n * ```\n */\nexport function useEntityFacade(): EntityFacade | null {\n return useContext(EntityFacadeContext)\n}\n"]}
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Group-hover scoped CSS generation (Tailwind `group` + `group-hover:`).
|
|
3
|
+
*
|
|
4
|
+
* A parent container marked `groupRoot: true` is a hover SOURCE: hovering it
|
|
5
|
+
* restyles descendants that declare `groupStates.hover`. `block.style` is inline
|
|
6
|
+
* and can express neither the ancestor `:hover` nor the descendant relationship,
|
|
7
|
+
* so the runtime emits a scoped descendant rule keyed by BOTH block ids:
|
|
8
|
+
*
|
|
9
|
+
* `[data-pw-surface] [data-block-id="<rootId>"]:hover [data-block-id="<thisId>"]{ … }`
|
|
10
|
+
*
|
|
11
|
+
* The host element already rendered for every block (`data-block-id`) is
|
|
12
|
+
* sufficient on both ends — no extra attribute is needed. Keys are CSS camelCase
|
|
13
|
+
* property names (converted to kebab-case); declarations are emitted with
|
|
14
|
+
* `!important` because a block COMPONENT often applies the same property inline
|
|
15
|
+
* with its own default and inline beats any plain stylesheet rule. Scoped to the
|
|
16
|
+
* one descendant under the one root.
|
|
17
|
+
*
|
|
18
|
+
* Only the NEAREST ancestor with `groupRoot:true` drives a block's
|
|
19
|
+
* `groupStates`; a block with `groupStates.hover` but no `groupRoot` ancestor
|
|
20
|
+
* emits zero bytes. Surfaces using no `groupStates` emit zero bytes so existing
|
|
21
|
+
* surfaces are byte-identical.
|
|
22
|
+
*
|
|
23
|
+
* @module @pwfabric/runtime/render/group-states-css
|
|
24
|
+
*/
|
|
25
|
+
import type { Block } from '@pwfabric/core';
|
|
26
|
+
/**
|
|
27
|
+
* Emit the scoped group-hover rule for a single descendant block, given the id
|
|
28
|
+
* of the nearest `groupRoot` ancestor. Targets
|
|
29
|
+
* `[data-block-id="<rootId>"]:hover [data-block-id="<thisId>"]` scoped under the
|
|
30
|
+
* surface root. Returns '' when the descendant declares no non-empty
|
|
31
|
+
* `groupStates.hover` record.
|
|
32
|
+
*/
|
|
33
|
+
export declare function blockGroupStatesCss(rootId: string, thisId: string, groupStates: NonNullable<Block['groupStates']>, surfaceId?: string): string;
|
|
34
|
+
/**
|
|
35
|
+
* Walk a surface block tree tracking the nearest ancestor marked
|
|
36
|
+
* `groupRoot: true`; for each block declaring `groupStates.hover` UNDER such an
|
|
37
|
+
* ancestor, concatenate its scoped group-hover CSS. Blocks with `groupStates`
|
|
38
|
+
* but no `groupRoot` ancestor — and surfaces with no `groupStates` at all —
|
|
39
|
+
* emit zero bytes (existing surfaces byte-identical).
|
|
40
|
+
*/
|
|
41
|
+
export declare function collectGroupStatesCss(blocks: readonly Block[], surfaceId?: string): string;
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Group-hover scoped CSS generation (Tailwind `group` + `group-hover:`).
|
|
3
|
+
*
|
|
4
|
+
* A parent container marked `groupRoot: true` is a hover SOURCE: hovering it
|
|
5
|
+
* restyles descendants that declare `groupStates.hover`. `block.style` is inline
|
|
6
|
+
* and can express neither the ancestor `:hover` nor the descendant relationship,
|
|
7
|
+
* so the runtime emits a scoped descendant rule keyed by BOTH block ids:
|
|
8
|
+
*
|
|
9
|
+
* `[data-pw-surface] [data-block-id="<rootId>"]:hover [data-block-id="<thisId>"]{ … }`
|
|
10
|
+
*
|
|
11
|
+
* The host element already rendered for every block (`data-block-id`) is
|
|
12
|
+
* sufficient on both ends — no extra attribute is needed. Keys are CSS camelCase
|
|
13
|
+
* property names (converted to kebab-case); declarations are emitted with
|
|
14
|
+
* `!important` because a block COMPONENT often applies the same property inline
|
|
15
|
+
* with its own default and inline beats any plain stylesheet rule. Scoped to the
|
|
16
|
+
* one descendant under the one root.
|
|
17
|
+
*
|
|
18
|
+
* Only the NEAREST ancestor with `groupRoot:true` drives a block's
|
|
19
|
+
* `groupStates`; a block with `groupStates.hover` but no `groupRoot` ancestor
|
|
20
|
+
* emits zero bytes. Surfaces using no `groupStates` emit zero bytes so existing
|
|
21
|
+
* surfaces are byte-identical.
|
|
22
|
+
*
|
|
23
|
+
* @module @pwfabric/runtime/render/group-states-css
|
|
24
|
+
*/
|
|
25
|
+
import { blockIdAttr, blockSelector, camelToKebab } from './scoped-css.js';
|
|
26
|
+
/** Serialize a camelCase decl record to `prop:value !important;…` (values pass through). */
|
|
27
|
+
function declsToCss(decls) {
|
|
28
|
+
return Object.entries(decls)
|
|
29
|
+
.map(([prop, value]) => `${camelToKebab(prop)}:${value} !important`)
|
|
30
|
+
.join(';');
|
|
31
|
+
}
|
|
32
|
+
/**
|
|
33
|
+
* Emit the scoped group-hover rule for a single descendant block, given the id
|
|
34
|
+
* of the nearest `groupRoot` ancestor. Targets
|
|
35
|
+
* `[data-block-id="<rootId>"]:hover [data-block-id="<thisId>"]` scoped under the
|
|
36
|
+
* surface root. Returns '' when the descendant declares no non-empty
|
|
37
|
+
* `groupStates.hover` record.
|
|
38
|
+
*/
|
|
39
|
+
export function blockGroupStatesCss(rootId, thisId, groupStates, surfaceId) {
|
|
40
|
+
const decls = groupStates.hover;
|
|
41
|
+
if (!decls || Object.keys(decls).length === 0)
|
|
42
|
+
return '';
|
|
43
|
+
// `blockSelector(rootId)` already includes the `[data-pw-surface]` prefix; the
|
|
44
|
+
// descendant half is just the bare `[data-block-id]` attribute selector (the
|
|
45
|
+
// shared surface scope is carried by the root half).
|
|
46
|
+
return `${blockSelector(rootId, surfaceId)}:hover ${blockIdAttr(thisId)}{${declsToCss(decls)}}`;
|
|
47
|
+
}
|
|
48
|
+
/**
|
|
49
|
+
* Walk a surface block tree tracking the nearest ancestor marked
|
|
50
|
+
* `groupRoot: true`; for each block declaring `groupStates.hover` UNDER such an
|
|
51
|
+
* ancestor, concatenate its scoped group-hover CSS. Blocks with `groupStates`
|
|
52
|
+
* but no `groupRoot` ancestor — and surfaces with no `groupStates` at all —
|
|
53
|
+
* emit zero bytes (existing surfaces byte-identical).
|
|
54
|
+
*/
|
|
55
|
+
export function collectGroupStatesCss(blocks, surfaceId) {
|
|
56
|
+
let css = '';
|
|
57
|
+
const walk = (block, nearestRootId) => {
|
|
58
|
+
if (block.groupStates && nearestRootId !== undefined) {
|
|
59
|
+
css += blockGroupStatesCss(nearestRootId, block.id, block.groupStates, surfaceId);
|
|
60
|
+
}
|
|
61
|
+
// This block becomes the nearest root for its own descendants when it is a
|
|
62
|
+
// group root (innermost groupRoot wins).
|
|
63
|
+
const rootForChildren = block.groupRoot ? block.id : nearestRootId;
|
|
64
|
+
if (block.children) {
|
|
65
|
+
for (const child of block.children)
|
|
66
|
+
walk(child, rootForChildren);
|
|
67
|
+
}
|
|
68
|
+
};
|
|
69
|
+
for (const block of blocks)
|
|
70
|
+
walk(block, undefined);
|
|
71
|
+
return css;
|
|
72
|
+
}
|
|
73
|
+
//# sourceMappingURL=group-states-css.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"group-states-css.js","sourceRoot":"","sources":["../../src/render/group-states-css.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AAGH,OAAO,EAAE,WAAW,EAAE,aAAa,EAAE,YAAY,EAAE,MAAM,iBAAiB,CAAA;AAE1E,4FAA4F;AAC5F,SAAS,UAAU,CAAC,KAAuC;IACzD,OAAO,MAAM,CAAC,OAAO,CAAC,KAAK,CAAC;SACzB,GAAG,CAAC,CAAC,CAAC,IAAI,EAAE,KAAK,CAAC,EAAE,EAAE,CAAC,GAAG,YAAY,CAAC,IAAI,CAAC,IAAI,KAAK,aAAa,CAAC;SACnE,IAAI,CAAC,GAAG,CAAC,CAAA;AACd,CAAC;AAED;;;;;;GAMG;AACH,MAAM,UAAU,mBAAmB,CACjC,MAAc,EACd,MAAc,EACd,WAA8C,EAC9C,SAAkB;IAElB,MAAM,KAAK,GAAG,WAAW,CAAC,KAAK,CAAA;IAC/B,IAAI,CAAC,KAAK,IAAI,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO,EAAE,CAAA;IACxD,+EAA+E;IAC/E,6EAA6E;IAC7E,qDAAqD;IACrD,OAAO,GAAG,aAAa,CAAC,MAAM,EAAE,SAAS,CAAC,UAAU,WAAW,CAAC,MAAM,CAAC,IAAI,UAAU,CAAC,KAAK,CAAC,GAAG,CAAA;AACjG,CAAC;AAED;;;;;;GAMG;AACH,MAAM,UAAU,qBAAqB,CAAC,MAAwB,EAAE,SAAkB;IAChF,IAAI,GAAG,GAAG,EAAE,CAAA;IACZ,MAAM,IAAI,GAAG,CAAC,KAAY,EAAE,aAAiC,EAAQ,EAAE;QACrE,IAAI,KAAK,CAAC,WAAW,IAAI,aAAa,KAAK,SAAS,EAAE,CAAC;YACrD,GAAG,IAAI,mBAAmB,CAAC,aAAa,EAAE,KAAK,CAAC,EAAE,EAAE,KAAK,CAAC,WAAW,EAAE,SAAS,CAAC,CAAA;QACnF,CAAC;QACD,2EAA2E;QAC3E,yCAAyC;QACzC,MAAM,eAAe,GAAG,KAAK,CAAC,SAAS,CAAC,CAAC,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC,CAAC,aAAa,CAAA;QAClE,IAAI,KAAK,CAAC,QAAQ,EAAE,CAAC;YACnB,KAAK,MAAM,KAAK,IAAI,KAAK,CAAC,QAAQ;gBAAE,IAAI,CAAC,KAAK,EAAE,eAAe,CAAC,CAAA;QAClE,CAAC;IACH,CAAC,CAAA;IACD,KAAK,MAAM,KAAK,IAAI,MAAM;QAAE,IAAI,CAAC,KAAK,EAAE,SAAS,CAAC,CAAA;IAClD,OAAO,GAAG,CAAA;AACZ,CAAC","sourcesContent":["/**\n * Group-hover scoped CSS generation (Tailwind `group` + `group-hover:`).\n *\n * A parent container marked `groupRoot: true` is a hover SOURCE: hovering it\n * restyles descendants that declare `groupStates.hover`. `block.style` is inline\n * and can express neither the ancestor `:hover` nor the descendant relationship,\n * so the runtime emits a scoped descendant rule keyed by BOTH block ids:\n *\n * `[data-pw-surface] [data-block-id=\"<rootId>\"]:hover [data-block-id=\"<thisId>\"]{ … }`\n *\n * The host element already rendered for every block (`data-block-id`) is\n * sufficient on both ends — no extra attribute is needed. Keys are CSS camelCase\n * property names (converted to kebab-case); declarations are emitted with\n * `!important` because a block COMPONENT often applies the same property inline\n * with its own default and inline beats any plain stylesheet rule. Scoped to the\n * one descendant under the one root.\n *\n * Only the NEAREST ancestor with `groupRoot:true` drives a block's\n * `groupStates`; a block with `groupStates.hover` but no `groupRoot` ancestor\n * emits zero bytes. Surfaces using no `groupStates` emit zero bytes so existing\n * surfaces are byte-identical.\n *\n * @module @pwfabric/runtime/render/group-states-css\n */\n\nimport type { Block } from '@pwfabric/core'\nimport { blockIdAttr, blockSelector, camelToKebab } from './scoped-css.js'\n\n/** Serialize a camelCase decl record to `prop:value !important;…` (values pass through). */\nfunction declsToCss(decls: Readonly<Record<string, string>>): string {\n return Object.entries(decls)\n .map(([prop, value]) => `${camelToKebab(prop)}:${value} !important`)\n .join(';')\n}\n\n/**\n * Emit the scoped group-hover rule for a single descendant block, given the id\n * of the nearest `groupRoot` ancestor. Targets\n * `[data-block-id=\"<rootId>\"]:hover [data-block-id=\"<thisId>\"]` scoped under the\n * surface root. Returns '' when the descendant declares no non-empty\n * `groupStates.hover` record.\n */\nexport function blockGroupStatesCss(\n rootId: string,\n thisId: string,\n groupStates: NonNullable<Block['groupStates']>,\n surfaceId?: string\n): string {\n const decls = groupStates.hover\n if (!decls || Object.keys(decls).length === 0) return ''\n // `blockSelector(rootId)` already includes the `[data-pw-surface]` prefix; the\n // descendant half is just the bare `[data-block-id]` attribute selector (the\n // shared surface scope is carried by the root half).\n return `${blockSelector(rootId, surfaceId)}:hover ${blockIdAttr(thisId)}{${declsToCss(decls)}}`\n}\n\n/**\n * Walk a surface block tree tracking the nearest ancestor marked\n * `groupRoot: true`; for each block declaring `groupStates.hover` UNDER such an\n * ancestor, concatenate its scoped group-hover CSS. Blocks with `groupStates`\n * but no `groupRoot` ancestor — and surfaces with no `groupStates` at all —\n * emit zero bytes (existing surfaces byte-identical).\n */\nexport function collectGroupStatesCss(blocks: readonly Block[], surfaceId?: string): string {\n let css = ''\n const walk = (block: Block, nearestRootId: string | undefined): void => {\n if (block.groupStates && nearestRootId !== undefined) {\n css += blockGroupStatesCss(nearestRootId, block.id, block.groupStates, surfaceId)\n }\n // This block becomes the nearest root for its own descendants when it is a\n // group root (innermost groupRoot wins).\n const rootForChildren = block.groupRoot ? block.id : nearestRootId\n if (block.children) {\n for (const child of block.children) walk(child, rootForChildren)\n }\n }\n for (const block of blocks) walk(block, undefined)\n return css\n}\n"]}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* useSurfaceEvents hook
|
|
3
|
+
*
|
|
4
|
+
* Re-exports from `@pwfabric/runtime/blocks` (its canonical home).
|
|
5
|
+
*
|
|
6
|
+
* @module @pwfabric/runtime/render/hooks/useSurfaceEvents
|
|
7
|
+
*/
|
|
8
|
+
export { useSurfaceEvents } from '../../blocks/index.js';
|
|
9
|
+
//# sourceMappingURL=useSurfaceEvents.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"useSurfaceEvents.js","sourceRoot":"","sources":["../../../src/render/hooks/useSurfaceEvents.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,EAAE,gBAAgB,EAAE,MAAM,uBAAuB,CAAA","sourcesContent":["/**\n * useSurfaceEvents hook\n *\n * Re-exports from `@pwfabric/runtime/blocks` (its canonical home).\n *\n * @module @pwfabric/runtime/render/hooks/useSurfaceEvents\n */\n\nexport { useSurfaceEvents } from '../../blocks/index.js'\n"]}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"useSurfaceId.js","sourceRoot":"","sources":["../../../src/render/hooks/useSurfaceId.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,EAAE,YAAY,EAAE,MAAM,uBAAuB,CAAA","sourcesContent":["/**\n * useSurfaceId hook\n *\n * Re-exports from `@pwfabric/runtime/blocks` (its canonical home).\n *\n * @module @pwfabric/runtime/render/hooks/useSurfaceId\n */\n\nexport { useSurfaceId } from '../../blocks/index.js'\n"]}
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Surface Renderer Module
|
|
3
|
+
*
|
|
4
|
+
* Phase 2A.1: Surface-to-React rendering infrastructure
|
|
5
|
+
*
|
|
6
|
+
* @module @pwfabric/runtime/render
|
|
7
|
+
*/
|
|
8
|
+
export type { BlockComponentProps, BlockComponent, BlockComponentRegistry, CapabilityProvider, BlockContext, SurfaceEventType, SurfaceEvent, SurfaceRendererProps, BlockRendererProps, RenderResult, RenderableSurface, CapabilityType, ImageAdapter, ImageAdapterProps, BlockWrapperProps, BlockWrapperRenderArgs, BlockInteractionMode, } from './types.js';
|
|
9
|
+
export { SurfaceRenderer, BlockRenderer, getBlockIds, findBlockById, updateBlockById, } from './renderer.js';
|
|
10
|
+
export { surfaceThemeToCSS } from './theme-utils.js';
|
|
11
|
+
export { deriveDarkTheme } from './derive-dark-theme.js';
|
|
12
|
+
export { resolveResponsiveValue, resolveSpanAtBreakpoint, getColumnsAtBreakpoint, getBreakpointForWidth, resolveBlockLayout, resolveMeasureStyle, resolveSurfaceRootStyle, useViewport, } from './responsive.js';
|
|
13
|
+
export { collectVisibilityCss, blockVisibilityCss, resolveHiddenBreakpoints, } from './visibility-css.js';
|
|
14
|
+
export { collectStatesCss, blockStatesCss } from './states-css.js';
|
|
15
|
+
export { collectConditionalStatesCss, blockConditionalStatesCss, } from './conditional-states-css.js';
|
|
16
|
+
export { buildKeyframesCss } from './keyframes-css.js';
|
|
17
|
+
export { collectResponsiveStyleCss, blockResponsiveStyleCss, } from './responsive-style-css.js';
|
|
18
|
+
export { collectGroupStatesCss, blockGroupStatesCss } from './group-states-css.js';
|
|
19
|
+
export { cssEscapeId, camelToKebab, blockIdAttr, blockSelector, collectScopedCss, } from './scoped-css.js';
|
|
20
|
+
export { buildDarkThemeCss } from './dark-theme-css.js';
|
|
21
|
+
export { resolveAppearanceDarkVars, resolveAppearanceKeyframes } from './appearance-resolver.js';
|
|
22
|
+
export type { SurfaceDataSourceKind, SurfaceDataSourceDefinition, SurfaceActionType, SurfaceAction, BlockActionProp, DataBoundSurface, DataBoundSurfaceRendererProps, } from './data-binding-types.js';
|
|
23
|
+
export { DataBoundSurfaceRenderer, surfaceNeedsDataBinding, blockActionsOf } from './DataBoundSurfaceRenderer.js';
|
|
24
|
+
export { resolveEndpoint, encodeEndpointValue } from './endpoint.js';
|
|
25
|
+
export { dataSourceCacheKey } from './data-cache.js';
|
|
26
|
+
export type { SurfaceDataCache } from './data-cache.js';
|
|
27
|
+
export { resolveBlockExpressions, resolveString } from './resolve-expressions.js';
|
|
28
|
+
export { BlockErrorBoundary } from './BlockErrorBoundary.js';
|
|
29
|
+
export type { EntitlementContextValue, EntitlementProviderProps, GatedBlockPlaceholderProps, } from './capability-gate.js';
|
|
30
|
+
export { EntitlementProvider, useEntitlements, GatedBlockPlaceholder } from './capability-gate.js';
|
|
31
|
+
export { BlockModuleLoader } from './dynamic-block-loader.js';
|
|
32
|
+
export type { DynamicBlockWrapperProps } from './DynamicBlockWrapper.js';
|
|
33
|
+
export { DynamicBlockWrapper } from './DynamicBlockWrapper.js';
|
|
34
|
+
export type { DynamicArtifactContextValue, DynamicArtifactProviderProps, } from './dynamic-artifact-context.js';
|
|
35
|
+
export { DynamicArtifactProvider, preloadDynamicBlocks, useDynamicBlocks, useDynamicStarters, } from './dynamic-artifact-context.js';
|
|
36
|
+
export { createSurfaceEventBus } from './surface-event-bus.js';
|
|
37
|
+
export { SurfaceEventContext } from './surface-event-context.js';
|
|
38
|
+
export { useSurfaceEvents } from './hooks/useSurfaceEvents.js';
|
|
39
|
+
export type { BehaviorSurfaceProviderProps } from './BehaviorSurfaceProvider.js';
|
|
40
|
+
export { BehaviorSurfaceProvider } from './BehaviorSurfaceProvider.js';
|
|
41
|
+
export { SurfaceIdContext } from './surface-id-context.js';
|
|
42
|
+
export { useSurfaceId } from './hooks/useSurfaceId.js';
|
|
43
|
+
export { EntityFacadeContext, useEntityFacade } from './entity-facade-context.js';
|
|
44
|
+
export { SurfaceDataContext, useSurfaceData } from './surface-data-context.js';
|
|
45
|
+
export type { SurfaceData } from './surface-data-context.js';
|
|
46
|
+
export { SurfaceConnectionsContext, useSurfaceConnections } from './connections-context.js';
|
|
47
|
+
export type { ShellSelectionStore, ShellSelectionOptions, ShellSelectionProviderProps } from './shell-selection.js';
|
|
48
|
+
export { ShellSelectionContext, ShellSelectionProvider, createShellSelectionStore, useShellSelection, } from './shell-selection.js';
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Surface Renderer Module
|
|
3
|
+
*
|
|
4
|
+
* Phase 2A.1: Surface-to-React rendering infrastructure
|
|
5
|
+
*
|
|
6
|
+
* @module @pwfabric/runtime/render
|
|
7
|
+
*/
|
|
8
|
+
// Components
|
|
9
|
+
export { SurfaceRenderer, BlockRenderer, getBlockIds, findBlockById, updateBlockById, } from './renderer.js';
|
|
10
|
+
// legacy first-party `*Block` component re-exports +
|
|
11
|
+
// `defaultBlockComponents` retired. Components flow through the install
|
|
12
|
+
// pipeline (pwpack publish → CDN bundle → BlockModuleLoader); the static
|
|
13
|
+
// re-exports that lived here are gone.
|
|
14
|
+
// Theme utilities
|
|
15
|
+
export { surfaceThemeToCSS } from './theme-utils.js';
|
|
16
|
+
export { deriveDarkTheme } from './derive-dark-theme.js';
|
|
17
|
+
// Responsive utilities
|
|
18
|
+
export { resolveResponsiveValue, resolveSpanAtBreakpoint, getColumnsAtBreakpoint, getBreakpointForWidth, resolveBlockLayout, resolveMeasureStyle, resolveSurfaceRootStyle, useViewport, } from './responsive.js';
|
|
19
|
+
// Per-breakpoint visibility (hideOn/showOn) CSS generation
|
|
20
|
+
export { collectVisibilityCss, blockVisibilityCss, resolveHiddenBreakpoints, } from './visibility-css.js';
|
|
21
|
+
// Interaction-state (hover/active/focus) CSS generation
|
|
22
|
+
export { collectStatesCss, blockStatesCss } from './states-css.js';
|
|
23
|
+
// Conditional-state (aria/data/disabled/checked/:has) CSS generation
|
|
24
|
+
export { collectConditionalStatesCss, blockConditionalStatesCss, } from './conditional-states-css.js';
|
|
25
|
+
// Surface keyframe registry (appearance.config.keyframes) CSS generation
|
|
26
|
+
export { buildKeyframesCss } from './keyframes-css.js';
|
|
27
|
+
// Per-prop responsive style (block.style breakpoint maps) CSS generation
|
|
28
|
+
export { collectResponsiveStyleCss, blockResponsiveStyleCss, } from './responsive-style-css.js';
|
|
29
|
+
// Group-hover (block.groupRoot + descendant block.groupStates) CSS generation
|
|
30
|
+
export { collectGroupStatesCss, blockGroupStatesCss } from './group-states-css.js';
|
|
31
|
+
// Shared scoped-CSS helpers (used by the per-block collectors above)
|
|
32
|
+
export { cssEscapeId, camelToKebab, blockIdAttr, blockSelector, collectScopedCss, } from './scoped-css.js';
|
|
33
|
+
// Dark theme variant CSS generation + resolver
|
|
34
|
+
export { buildDarkThemeCss } from './dark-theme-css.js';
|
|
35
|
+
export { resolveAppearanceDarkVars, resolveAppearanceKeyframes } from './appearance-resolver.js';
|
|
36
|
+
export { DataBoundSurfaceRenderer, surfaceNeedsDataBinding, blockActionsOf } from './DataBoundSurfaceRenderer.js';
|
|
37
|
+
export { resolveEndpoint, encodeEndpointValue } from './endpoint.js';
|
|
38
|
+
export { dataSourceCacheKey } from './data-cache.js';
|
|
39
|
+
export { resolveBlockExpressions, resolveString } from './resolve-expressions.js';
|
|
40
|
+
// Block Error Boundary (crash isolation)
|
|
41
|
+
export { BlockErrorBoundary } from './BlockErrorBoundary.js';
|
|
42
|
+
export { EntitlementProvider, useEntitlements, GatedBlockPlaceholder } from './capability-gate.js';
|
|
43
|
+
// Dynamic Artifact Loading
|
|
44
|
+
export { BlockModuleLoader } from './dynamic-block-loader.js';
|
|
45
|
+
export { DynamicBlockWrapper } from './DynamicBlockWrapper.js';
|
|
46
|
+
export { DynamicArtifactProvider, preloadDynamicBlocks, useDynamicBlocks, useDynamicStarters, } from './dynamic-artifact-context.js';
|
|
47
|
+
// Surface event protocol
|
|
48
|
+
export { createSurfaceEventBus } from './surface-event-bus.js';
|
|
49
|
+
export { SurfaceEventContext } from './surface-event-context.js';
|
|
50
|
+
export { useSurfaceEvents } from './hooks/useSurfaceEvents.js';
|
|
51
|
+
export { BehaviorSurfaceProvider } from './BehaviorSurfaceProvider.js';
|
|
52
|
+
export { SurfaceIdContext } from './surface-id-context.js';
|
|
53
|
+
export { useSurfaceId } from './hooks/useSurfaceId.js';
|
|
54
|
+
// EntityFacade → Surface Renderer integration
|
|
55
|
+
export { EntityFacadeContext, useEntityFacade } from './entity-facade-context.js';
|
|
56
|
+
// What the data-bound path has currently bound, by source id (form writer reads it)
|
|
57
|
+
export { SurfaceDataContext, useSurfaceData } from './surface-data-context.js';
|
|
58
|
+
// Connections context (world connections + engine registry)
|
|
59
|
+
export { SurfaceConnectionsContext, useSurfaceConnections } from './connections-context.js';
|
|
60
|
+
export { ShellSelectionContext, ShellSelectionProvider, createShellSelectionStore, useShellSelection, } from './shell-selection.js';
|
|
61
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/render/index.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Surface Renderer Module\n *\n * Phase 2A.1: Surface-to-React rendering infrastructure\n *\n * @module @pwfabric/runtime/render\n */\n\n// Types\nexport type {\n BlockComponentProps,\n BlockComponent,\n BlockComponentRegistry,\n CapabilityProvider,\n BlockContext,\n SurfaceEventType,\n SurfaceEvent,\n SurfaceRendererProps,\n BlockRendererProps,\n RenderResult,\n RenderableSurface,\n CapabilityType,\n ImageAdapter,\n ImageAdapterProps,\n BlockWrapperProps,\n BlockWrapperRenderArgs,\n BlockInteractionMode,\n} from './types.js'\n\n// Components\nexport {\n SurfaceRenderer,\n BlockRenderer,\n getBlockIds,\n findBlockById,\n updateBlockById,\n} from './renderer.js'\n\n// legacy first-party `*Block` component re-exports +\n// `defaultBlockComponents` retired. Components flow through the install\n// pipeline (pwpack publish → CDN bundle → BlockModuleLoader); the static\n// re-exports that lived here are gone.\n\n// Theme utilities\nexport { surfaceThemeToCSS } from './theme-utils.js'\nexport { deriveDarkTheme } from './derive-dark-theme.js'\n\n// Responsive utilities\nexport {\n resolveResponsiveValue,\n resolveSpanAtBreakpoint,\n getColumnsAtBreakpoint,\n getBreakpointForWidth,\n resolveBlockLayout,\n resolveMeasureStyle,\n resolveSurfaceRootStyle,\n useViewport,\n} from './responsive.js'\n\n// Per-breakpoint visibility (hideOn/showOn) CSS generation\nexport {\n collectVisibilityCss,\n blockVisibilityCss,\n resolveHiddenBreakpoints,\n} from './visibility-css.js'\n\n// Interaction-state (hover/active/focus) CSS generation\nexport { collectStatesCss, blockStatesCss } from './states-css.js'\n\n// Conditional-state (aria/data/disabled/checked/:has) CSS generation\nexport {\n collectConditionalStatesCss,\n blockConditionalStatesCss,\n} from './conditional-states-css.js'\n\n// Surface keyframe registry (appearance.config.keyframes) CSS generation\nexport { buildKeyframesCss } from './keyframes-css.js'\n\n// Per-prop responsive style (block.style breakpoint maps) CSS generation\nexport {\n collectResponsiveStyleCss,\n blockResponsiveStyleCss,\n} from './responsive-style-css.js'\n\n// Group-hover (block.groupRoot + descendant block.groupStates) CSS generation\nexport { collectGroupStatesCss, blockGroupStatesCss } from './group-states-css.js'\n\n// Shared scoped-CSS helpers (used by the per-block collectors above)\nexport {\n cssEscapeId,\n camelToKebab,\n blockIdAttr,\n blockSelector,\n collectScopedCss,\n} from './scoped-css.js'\n\n// Dark theme variant CSS generation + resolver\nexport { buildDarkThemeCss } from './dark-theme-css.js'\nexport { resolveAppearanceDarkVars, resolveAppearanceKeyframes } from './appearance-resolver.js'\n\n// Data-bound rendering\nexport type {\n SurfaceDataSourceKind,\n SurfaceDataSourceDefinition,\n SurfaceActionType,\n SurfaceAction,\n BlockActionProp,\n DataBoundSurface,\n DataBoundSurfaceRendererProps,\n} from './data-binding-types.js'\n\nexport { DataBoundSurfaceRenderer, surfaceNeedsDataBinding, blockActionsOf } from './DataBoundSurfaceRenderer.js'\nexport { resolveEndpoint, encodeEndpointValue } from './endpoint.js'\nexport { dataSourceCacheKey } from './data-cache.js'\nexport type { SurfaceDataCache } from './data-cache.js'\nexport { resolveBlockExpressions, resolveString } from './resolve-expressions.js'\n\n// Block Error Boundary (crash isolation)\nexport { BlockErrorBoundary } from './BlockErrorBoundary.js'\n\n// Capability Gate (Entitlement enforcement)\nexport type {\n EntitlementContextValue,\n EntitlementProviderProps,\n GatedBlockPlaceholderProps,\n} from './capability-gate.js'\nexport { EntitlementProvider, useEntitlements, GatedBlockPlaceholder } from './capability-gate.js'\n\n// Dynamic Artifact Loading\nexport { BlockModuleLoader } from './dynamic-block-loader.js'\nexport type { DynamicBlockWrapperProps } from './DynamicBlockWrapper.js'\nexport { DynamicBlockWrapper } from './DynamicBlockWrapper.js'\nexport type {\n DynamicArtifactContextValue,\n DynamicArtifactProviderProps,\n} from './dynamic-artifact-context.js'\nexport {\n DynamicArtifactProvider,\n preloadDynamicBlocks,\n useDynamicBlocks,\n useDynamicStarters,\n} from './dynamic-artifact-context.js'\n\n// Surface event protocol\nexport { createSurfaceEventBus } from './surface-event-bus.js'\nexport { SurfaceEventContext } from './surface-event-context.js'\nexport { useSurfaceEvents } from './hooks/useSurfaceEvents.js'\n\n// BehaviorSurfaceProvider — runtime surface wiring\nexport type { BehaviorSurfaceProviderProps } from './BehaviorSurfaceProvider.js'\nexport { BehaviorSurfaceProvider } from './BehaviorSurfaceProvider.js'\nexport { SurfaceIdContext } from './surface-id-context.js'\nexport { useSurfaceId } from './hooks/useSurfaceId.js'\n\n// EntityFacade → Surface Renderer integration\nexport { EntityFacadeContext, useEntityFacade } from './entity-facade-context.js'\n\n// What the data-bound path has currently bound, by source id (form writer reads it)\nexport { SurfaceDataContext, useSurfaceData } from './surface-data-context.js'\nexport type { SurfaceData } from './surface-data-context.js'\n\n// Connections context (world connections + engine registry)\nexport { SurfaceConnectionsContext, useSurfaceConnections } from './connections-context.js'\n\n// Shell × body: SPLIT shell selection, projected onto the URL so a selected\n// record can be linked to and the Back button undoes the selection.\nexport type { ShellSelectionStore, ShellSelectionOptions, ShellSelectionProviderProps } from './shell-selection.js'\nexport {\n ShellSelectionContext,\n ShellSelectionProvider,\n createShellSelectionStore,\n useShellSelection,\n} from './shell-selection.js'\n"]}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import type { InteractionRule, InteractionRuleEngine, SurfaceEventTrigger, SurfaceEventDescriptor } from '@pwfabric/contracts';
|
|
2
|
+
export type { InteractionRule, InteractionRuleEngine, SurfaceEventTrigger };
|
|
3
|
+
export declare class DefaultInteractionRuleEngine implements InteractionRuleEngine {
|
|
4
|
+
private readonly rules;
|
|
5
|
+
register(rule: InteractionRule): void;
|
|
6
|
+
unregister(ruleId: string): boolean;
|
|
7
|
+
attach(bus: {
|
|
8
|
+
on(pattern: string, handler: (e: SurfaceEventDescriptor) => void): () => void;
|
|
9
|
+
}): () => void;
|
|
10
|
+
clear(): void;
|
|
11
|
+
}
|
|
12
|
+
export declare function createInteractionRuleEngine(): InteractionRuleEngine;
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
// packages/runtime/src/render/interaction-rule-engine.ts
|
|
2
|
+
// DefaultInteractionRuleEngine (formerly DefaultSurfaceBehaviorEngine)
|
|
3
|
+
export class DefaultInteractionRuleEngine {
|
|
4
|
+
rules = new Map();
|
|
5
|
+
register(rule) {
|
|
6
|
+
this.rules.set(rule.id, rule);
|
|
7
|
+
}
|
|
8
|
+
unregister(ruleId) {
|
|
9
|
+
return this.rules.delete(ruleId);
|
|
10
|
+
}
|
|
11
|
+
attach(bus) {
|
|
12
|
+
const unsubscribers = [];
|
|
13
|
+
// Group rules by trigger, subscribe once per trigger
|
|
14
|
+
const byTrigger = new Map();
|
|
15
|
+
for (const rule of this.rules.values()) {
|
|
16
|
+
const existing = byTrigger.get(rule.trigger) ?? [];
|
|
17
|
+
existing.push(rule);
|
|
18
|
+
byTrigger.set(rule.trigger, existing);
|
|
19
|
+
}
|
|
20
|
+
for (const [trigger, triggerRules] of byTrigger) {
|
|
21
|
+
const unsub = bus.on(trigger, async (event) => {
|
|
22
|
+
// Sort by priority (higher = first)
|
|
23
|
+
const sorted = [...triggerRules].sort((a, b) => (b.priority ?? 0) - (a.priority ?? 0));
|
|
24
|
+
for (const rule of sorted) {
|
|
25
|
+
try {
|
|
26
|
+
if (rule.guard && !rule.guard(event))
|
|
27
|
+
continue;
|
|
28
|
+
await rule.action(event);
|
|
29
|
+
}
|
|
30
|
+
catch (err) {
|
|
31
|
+
// Fail-safe: log but don't break other rules
|
|
32
|
+
console.warn(`[InteractionRuleEngine] Rule '${rule.id}' failed:`, err);
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
});
|
|
36
|
+
unsubscribers.push(unsub);
|
|
37
|
+
}
|
|
38
|
+
return () => unsubscribers.forEach((u) => u());
|
|
39
|
+
}
|
|
40
|
+
clear() {
|
|
41
|
+
this.rules.clear();
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
export function createInteractionRuleEngine() {
|
|
45
|
+
return new DefaultInteractionRuleEngine();
|
|
46
|
+
}
|
|
47
|
+
//# sourceMappingURL=interaction-rule-engine.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"interaction-rule-engine.js","sourceRoot":"","sources":["../../src/render/interaction-rule-engine.ts"],"names":[],"mappings":"AAAA,yDAAyD;AACzD,uEAAuE;AAWvE,MAAM,OAAO,4BAA4B;IACtB,KAAK,GAAG,IAAI,GAAG,EAA2B,CAAA;IAE3D,QAAQ,CAAC,IAAqB;QAC5B,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,EAAE,IAAI,CAAC,CAAA;IAC/B,CAAC;IAED,UAAU,CAAC,MAAc;QACvB,OAAO,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,MAAM,CAAC,CAAA;IAClC,CAAC;IAED,MAAM,CAAC,GAEN;QACC,MAAM,aAAa,GAAmB,EAAE,CAAA;QAExC,qDAAqD;QACrD,MAAM,SAAS,GAAG,IAAI,GAAG,EAA6B,CAAA;QACtD,KAAK,MAAM,IAAI,IAAI,IAAI,CAAC,KAAK,CAAC,MAAM,EAAE,EAAE,CAAC;YACvC,MAAM,QAAQ,GAAG,SAAS,CAAC,GAAG,CAAC,IAAI,CAAC,OAAO,CAAC,IAAI,EAAE,CAAA;YAClD,QAAQ,CAAC,IAAI,CAAC,IAAI,CAAC,CAAA;YACnB,SAAS,CAAC,GAAG,CAAC,IAAI,CAAC,OAAO,EAAE,QAAQ,CAAC,CAAA;QACvC,CAAC;QAED,KAAK,MAAM,CAAC,OAAO,EAAE,YAAY,CAAC,IAAI,SAAS,EAAE,CAAC;YAChD,MAAM,KAAK,GAAG,GAAG,CAAC,EAAE,CAAC,OAAO,EAAE,KAAK,EAAE,KAA6B,EAAE,EAAE;gBACpE,oCAAoC;gBACpC,MAAM,MAAM,GAAG,CAAC,GAAG,YAAY,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,QAAQ,IAAI,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,QAAQ,IAAI,CAAC,CAAC,CAAC,CAAA;gBACtF,KAAK,MAAM,IAAI,IAAI,MAAM,EAAE,CAAC;oBAC1B,IAAI,CAAC;wBACH,IAAI,IAAI,CAAC,KAAK,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC;4BAAE,SAAQ;wBAC9C,MAAM,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,CAAA;oBAC1B,CAAC;oBAAC,OAAO,GAAG,EAAE,CAAC;wBACb,6CAA6C;wBAC7C,OAAO,CAAC,IAAI,CAAC,iCAAiC,IAAI,CAAC,EAAE,WAAW,EAAE,GAAG,CAAC,CAAA;oBACxE,CAAC;gBACH,CAAC;YACH,CAAC,CAAC,CAAA;YACF,aAAa,CAAC,IAAI,CAAC,KAAK,CAAC,CAAA;QAC3B,CAAC;QAED,OAAO,GAAG,EAAE,CAAC,aAAa,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,EAAE,CAAC,CAAA;IAChD,CAAC;IAED,KAAK;QACH,IAAI,CAAC,KAAK,CAAC,KAAK,EAAE,CAAA;IACpB,CAAC;CACF;AAED,MAAM,UAAU,2BAA2B;IACzC,OAAO,IAAI,4BAA4B,EAAE,CAAA;AAC3C,CAAC","sourcesContent":["// packages/runtime/src/render/interaction-rule-engine.ts\n// DefaultInteractionRuleEngine (formerly DefaultSurfaceBehaviorEngine)\n\nimport type {\n InteractionRule,\n InteractionRuleEngine,\n SurfaceEventTrigger,\n SurfaceEventDescriptor,\n} from '@pwfabric/contracts'\n\nexport type { InteractionRule, InteractionRuleEngine, SurfaceEventTrigger }\n\nexport class DefaultInteractionRuleEngine implements InteractionRuleEngine {\n private readonly rules = new Map<string, InteractionRule>()\n\n register(rule: InteractionRule): void {\n this.rules.set(rule.id, rule)\n }\n\n unregister(ruleId: string): boolean {\n return this.rules.delete(ruleId)\n }\n\n attach(bus: {\n on(pattern: string, handler: (e: SurfaceEventDescriptor) => void): () => void\n }): () => void {\n const unsubscribers: (() => void)[] = []\n\n // Group rules by trigger, subscribe once per trigger\n const byTrigger = new Map<string, InteractionRule[]>()\n for (const rule of this.rules.values()) {\n const existing = byTrigger.get(rule.trigger) ?? []\n existing.push(rule)\n byTrigger.set(rule.trigger, existing)\n }\n\n for (const [trigger, triggerRules] of byTrigger) {\n const unsub = bus.on(trigger, async (event: SurfaceEventDescriptor) => {\n // Sort by priority (higher = first)\n const sorted = [...triggerRules].sort((a, b) => (b.priority ?? 0) - (a.priority ?? 0))\n for (const rule of sorted) {\n try {\n if (rule.guard && !rule.guard(event)) continue\n await rule.action(event)\n } catch (err) {\n // Fail-safe: log but don't break other rules\n console.warn(`[InteractionRuleEngine] Rule '${rule.id}' failed:`, err)\n }\n }\n })\n unsubscribers.push(unsub)\n }\n\n return () => unsubscribers.forEach((u) => u())\n }\n\n clear(): void {\n this.rules.clear()\n }\n}\n\nexport function createInteractionRuleEngine(): InteractionRuleEngine {\n return new DefaultInteractionRuleEngine()\n}\n"]}
|