@cratis/scene.react 4.7.0 → 4.9.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (72) hide show
  1. package/SceneElementView.tsx +10 -3
  2. package/dist/cjs/SceneElementView.js +4 -2
  3. package/dist/cjs/SceneElementView.js.map +1 -1
  4. package/dist/cjs/index.js +11 -0
  5. package/dist/cjs/index.js.map +1 -1
  6. package/dist/cjs/packages/ComponentsUiLibraryContract.js +72 -0
  7. package/dist/cjs/packages/ComponentsUiLibraryContract.js.map +1 -0
  8. package/dist/cjs/packages/DesignTimeBundle.js +17 -0
  9. package/dist/cjs/packages/DesignTimeBundle.js.map +1 -0
  10. package/dist/cjs/packages/PackageHostConfiguration.js +43 -0
  11. package/dist/cjs/packages/PackageHostConfiguration.js.map +1 -0
  12. package/dist/cjs/packages/ScenePackageBundle.js +9 -0
  13. package/dist/cjs/packages/ScenePackageBundle.js.map +1 -1
  14. package/dist/cjs/renderer/BindingOutputContext.js +74 -0
  15. package/dist/cjs/renderer/BindingOutputContext.js.map +1 -0
  16. package/dist/cjs/renderer/InteractiveComponent.js +7 -1
  17. package/dist/cjs/renderer/InteractiveComponent.js.map +1 -1
  18. package/dist/esm/SceneElementView.d.ts +2 -1
  19. package/dist/esm/SceneElementView.d.ts.map +1 -1
  20. package/dist/esm/SceneElementView.js +5 -3
  21. package/dist/esm/SceneElementView.js.map +1 -1
  22. package/dist/esm/index.js +4 -0
  23. package/dist/esm/index.js.map +1 -1
  24. package/dist/esm/packages/ComponentsUiLibraryContract.d.ts +19 -0
  25. package/dist/esm/packages/ComponentsUiLibraryContract.d.ts.map +1 -0
  26. package/dist/esm/packages/ComponentsUiLibraryContract.js +69 -0
  27. package/dist/esm/packages/ComponentsUiLibraryContract.js.map +1 -0
  28. package/dist/esm/packages/DesignTimeAction.d.ts +23 -0
  29. package/dist/esm/packages/DesignTimeAction.d.ts.map +1 -0
  30. package/dist/esm/packages/DesignTimeAction.js +2 -0
  31. package/dist/esm/packages/DesignTimeAction.js.map +1 -0
  32. package/dist/esm/packages/DesignTimeBundle.d.ts +17 -0
  33. package/dist/esm/packages/DesignTimeBundle.d.ts.map +1 -0
  34. package/dist/esm/packages/DesignTimeBundle.js +15 -0
  35. package/dist/esm/packages/DesignTimeBundle.js.map +1 -0
  36. package/dist/esm/packages/PackageHostConfiguration.d.ts +18 -0
  37. package/dist/esm/packages/PackageHostConfiguration.d.ts.map +1 -0
  38. package/dist/esm/packages/PackageHostConfiguration.js +41 -0
  39. package/dist/esm/packages/PackageHostConfiguration.js.map +1 -0
  40. package/dist/esm/packages/ScenePackageBundle.d.ts +4 -0
  41. package/dist/esm/packages/ScenePackageBundle.d.ts.map +1 -1
  42. package/dist/esm/packages/ScenePackageBundle.js +9 -0
  43. package/dist/esm/packages/ScenePackageBundle.js.map +1 -1
  44. package/dist/esm/packages/index.d.ts +4 -0
  45. package/dist/esm/packages/index.d.ts.map +1 -1
  46. package/dist/esm/packages/index.js +4 -0
  47. package/dist/esm/packages/index.js.map +1 -1
  48. package/dist/esm/renderer/BindingOutputContext.d.ts +18 -0
  49. package/dist/esm/renderer/BindingOutputContext.d.ts.map +1 -0
  50. package/dist/esm/renderer/BindingOutputContext.js +70 -0
  51. package/dist/esm/renderer/BindingOutputContext.js.map +1 -0
  52. package/dist/esm/renderer/ComponentRegistry.d.ts +2 -0
  53. package/dist/esm/renderer/ComponentRegistry.d.ts.map +1 -1
  54. package/dist/esm/renderer/InteractiveComponent.d.ts.map +1 -1
  55. package/dist/esm/renderer/InteractiveComponent.js +8 -2
  56. package/dist/esm/renderer/InteractiveComponent.js.map +1 -1
  57. package/dist/esm/renderer/index.d.ts +1 -0
  58. package/dist/esm/renderer/index.d.ts.map +1 -1
  59. package/dist/esm/renderer/index.js +1 -0
  60. package/dist/esm/renderer/index.js.map +1 -1
  61. package/dist/esm/tsconfig.tsbuildinfo +1 -1
  62. package/package.json +5 -5
  63. package/packages/ComponentsUiLibraryContract.ts +89 -0
  64. package/packages/DesignTimeAction.ts +25 -0
  65. package/packages/DesignTimeBundle.ts +27 -0
  66. package/packages/PackageHostConfiguration.ts +56 -0
  67. package/packages/ScenePackageBundle.ts +19 -0
  68. package/packages/index.ts +4 -0
  69. package/renderer/BindingOutputContext.tsx +69 -0
  70. package/renderer/ComponentRegistry.ts +4 -0
  71. package/renderer/InteractiveComponent.tsx +5 -2
  72. package/renderer/index.ts +1 -0
@@ -4,7 +4,7 @@
4
4
  import { useMemo } from 'react';
5
5
  import { applyEffectiveConfiguration, renderElement, BindingResolver } from '@cratis/scene.engine';
6
6
  import { EffectiveConfiguration, SceneElement } from '@cratis/scene.model';
7
- import { ComponentRegistry, createReactRenderer } from './renderer';
7
+ import { BindingOutputProvider, ComponentRegistry, createReactRenderer } from './renderer';
8
8
 
9
9
  export interface SceneElementViewProps {
10
10
  element: SceneElement;
@@ -18,14 +18,21 @@ export interface SceneElementViewProps {
18
18
  * being edited or played: there is no design-time mode.
19
19
  */
20
20
  configuration?: EffectiveConfiguration;
21
+
22
+ /** Called when rendered components publish or clear output properties for typed bindings. */
23
+ onComponentOutputsChanged?: (outputs: Record<string, Record<string, unknown>>) => void;
21
24
  }
22
25
 
23
26
  /**
24
27
  * Renders a Scene element tree with the real `Scene.React` renderer - the WYSIWYG building block Studio's
25
28
  * preview surface and Stage's shipped web bundle both consume unmodified.
26
29
  */
27
- export function SceneElementView({ element, registry, resolveBinding, configuration }: SceneElementViewProps) {
30
+ export function SceneElementView({ element, registry, resolveBinding, configuration, onComponentOutputsChanged }: SceneElementViewProps) {
28
31
  const renderer = useMemo(() => createReactRenderer(registry), [registry]);
29
32
  const configured = useMemo(() => configuration ? applyEffectiveConfiguration(element, configuration) : element, [element, configuration]);
30
- return <>{renderElement(configured, renderer, resolveBinding)}</>;
33
+ return (
34
+ <BindingOutputProvider onOutputsChanged={onComponentOutputsChanged}>
35
+ {renderElement(configured, renderer, resolveBinding)}
36
+ </BindingOutputProvider>
37
+ );
31
38
  }
@@ -3,6 +3,7 @@
3
3
  var jsxRuntime = require('react/jsx-runtime');
4
4
  var react = require('react');
5
5
  var scene_engine = require('@cratis/scene.engine');
6
+ var BindingOutputContext = require('./renderer/BindingOutputContext.js');
6
7
  var createReactRenderer = require('./renderer/createReactRenderer.js');
7
8
  require('./interactions/useInteractions.js');
8
9
  require('./interactions/NotificationHost.js');
@@ -10,7 +11,7 @@ require('./interactions/NotificationHost.js');
10
11
  /**
11
12
  * Renders a Scene element tree with the real `Scene.React` renderer - the WYSIWYG building block Studio's
12
13
  * preview surface and Stage's shipped web bundle both consume unmodified.
13
- */ function SceneElementView({ element, registry, resolveBinding, configuration }) {
14
+ */ function SceneElementView({ element, registry, resolveBinding, configuration, onComponentOutputsChanged }) {
14
15
  const renderer = react.useMemo(()=>createReactRenderer.createReactRenderer(registry), [
15
16
  registry
16
17
  ]);
@@ -18,7 +19,8 @@ require('./interactions/NotificationHost.js');
18
19
  element,
19
20
  configuration
20
21
  ]);
21
- return /*#__PURE__*/ jsxRuntime.jsx(jsxRuntime.Fragment, {
22
+ return /*#__PURE__*/ jsxRuntime.jsx(BindingOutputContext.BindingOutputProvider, {
23
+ onOutputsChanged: onComponentOutputsChanged,
22
24
  children: scene_engine.renderElement(configured, renderer, resolveBinding)
23
25
  });
24
26
  }
@@ -1 +1 @@
1
- {"version":3,"file":"SceneElementView.js","sources":["../../SceneElementView.tsx"],"sourcesContent":["// Copyright (c) Cratis. All rights reserved.\n// Licensed under the MIT license. See LICENSE file in the project root for full license information.\n\nimport { useMemo } from 'react';\nimport { applyEffectiveConfiguration, renderElement, BindingResolver } from '@cratis/scene.engine';\nimport { EffectiveConfiguration, SceneElement } from '@cratis/scene.model';\nimport { ComponentRegistry, createReactRenderer } from './renderer';\n\nexport interface SceneElementViewProps {\n element: SceneElement;\n registry: ComponentRegistry;\n resolveBinding: BindingResolver;\n\n /**\n * The resolved configuration of the template chain the element sits in, from `resolveEffectiveConfiguration`.\n * When given, each configurable component renders with its resolved properties - what a screen's own values add\n * to an inherited template. It is the same data the editor shows, and the same code path whether the screen is\n * being edited or played: there is no design-time mode.\n */\n configuration?: EffectiveConfiguration;\n}\n\n/**\n * Renders a Scene element tree with the real `Scene.React` renderer - the WYSIWYG building block Studio's\n * preview surface and Stage's shipped web bundle both consume unmodified.\n */\nexport function SceneElementView({ element, registry, resolveBinding, configuration }: SceneElementViewProps) {\n const renderer = useMemo(() => createReactRenderer(registry), [registry]);\n const configured = useMemo(() => configuration ? applyEffectiveConfiguration(element, configuration) : element, [element, configuration]);\n return <>{renderElement(configured, renderer, resolveBinding)}</>;\n}\n"],"names":["SceneElementView","element","registry","resolveBinding","configuration","renderer","useMemo","createReactRenderer","configured","applyEffectiveConfiguration","_jsx","_Fragment","renderElement"],"mappings":";;;;;;;;;AAsBA;;;IAIO,SAASA,gBAAAA,CAAiB,EAAEC,OAAO,EAAEC,QAAQ,EAAEC,cAAc,EAAEC,aAAa,EAAyB,EAAA;AACxG,IAAA,MAAMC,QAAAA,GAAWC,aAAAA,CAAQ,IAAMC,uCAAAA,CAAoBL,QAAAA,CAAAA,EAAW;AAACA,QAAAA;AAAS,KAAA,CAAA;AACxE,IAAA,MAAMM,aAAaF,aAAAA,CAAQ,IAAMF,gBAAgBK,wCAAAA,CAA4BR,OAAAA,EAASG,iBAAiBH,OAAAA,EAAS;AAACA,QAAAA,OAAAA;AAASG,QAAAA;AAAc,KAAA,CAAA;IACxI,qBAAOM,cAAA,CAAAC,mBAAA,EAAA;AAAGC,QAAAA,QAAAA,EAAAA,0BAAAA,CAAcJ,YAAYH,QAAAA,EAAUF,cAAAA;;AAClD;;"}
1
+ {"version":3,"file":"SceneElementView.js","sources":["../../SceneElementView.tsx"],"sourcesContent":["// Copyright (c) Cratis. All rights reserved.\n// Licensed under the MIT license. See LICENSE file in the project root for full license information.\n\nimport { useMemo } from 'react';\nimport { applyEffectiveConfiguration, renderElement, BindingResolver } from '@cratis/scene.engine';\nimport { EffectiveConfiguration, SceneElement } from '@cratis/scene.model';\nimport { BindingOutputProvider, ComponentRegistry, createReactRenderer } from './renderer';\n\nexport interface SceneElementViewProps {\n element: SceneElement;\n registry: ComponentRegistry;\n resolveBinding: BindingResolver;\n\n /**\n * The resolved configuration of the template chain the element sits in, from `resolveEffectiveConfiguration`.\n * When given, each configurable component renders with its resolved properties - what a screen's own values add\n * to an inherited template. It is the same data the editor shows, and the same code path whether the screen is\n * being edited or played: there is no design-time mode.\n */\n configuration?: EffectiveConfiguration;\n\n /** Called when rendered components publish or clear output properties for typed bindings. */\n onComponentOutputsChanged?: (outputs: Record<string, Record<string, unknown>>) => void;\n}\n\n/**\n * Renders a Scene element tree with the real `Scene.React` renderer - the WYSIWYG building block Studio's\n * preview surface and Stage's shipped web bundle both consume unmodified.\n */\nexport function SceneElementView({ element, registry, resolveBinding, configuration, onComponentOutputsChanged }: SceneElementViewProps) {\n const renderer = useMemo(() => createReactRenderer(registry), [registry]);\n const configured = useMemo(() => configuration ? applyEffectiveConfiguration(element, configuration) : element, [element, configuration]);\n return (\n <BindingOutputProvider onOutputsChanged={onComponentOutputsChanged}>\n {renderElement(configured, renderer, resolveBinding)}\n </BindingOutputProvider>\n );\n}\n"],"names":["SceneElementView","element","registry","resolveBinding","configuration","onComponentOutputsChanged","renderer","useMemo","createReactRenderer","configured","applyEffectiveConfiguration","_jsx","BindingOutputProvider","onOutputsChanged","renderElement"],"mappings":";;;;;;;;;;AAyBA;;;AAGC,IACM,SAASA,gBAAAA,CAAiB,EAAEC,OAAO,EAAEC,QAAQ,EAAEC,cAAc,EAAEC,aAAa,EAAEC,yBAAyB,EAAyB,EAAA;AACnI,IAAA,MAAMC,QAAAA,GAAWC,aAAAA,CAAQ,IAAMC,uCAAAA,CAAoBN,QAAAA,CAAAA,EAAW;AAACA,QAAAA;AAAS,KAAA,CAAA;AACxE,IAAA,MAAMO,aAAaF,aAAAA,CAAQ,IAAMH,gBAAgBM,wCAAAA,CAA4BT,OAAAA,EAASG,iBAAiBH,OAAAA,EAAS;AAACA,QAAAA,OAAAA;AAASG,QAAAA;AAAc,KAAA,CAAA;AACxI,IAAA,qBACIO,cAAA,CAACC,0CAAAA,EAAAA;QAAsBC,gBAAAA,EAAkBR,yBAAAA;AACpCS,QAAAA,QAAAA,EAAAA,0BAAAA,CAAcL,YAAYH,QAAAA,EAAUH,cAAAA;;AAGjD;;"}
package/dist/cjs/index.js CHANGED
@@ -1,6 +1,7 @@
1
1
  'use strict';
2
2
 
3
3
  var SceneElementView = require('./SceneElementView.js');
4
+ var BindingOutputContext = require('./renderer/BindingOutputContext.js');
4
5
  var UnresolvedComponent = require('./renderer/UnresolvedComponent.js');
5
6
  var createReactRenderer = require('./renderer/createReactRenderer.js');
6
7
  var InteractiveComponent = require('./renderer/InteractiveComponent.js');
@@ -18,7 +19,10 @@ var IconAdapterRegistry = require('./icons/IconAdapterRegistry.js');
18
19
  var IconAdapterContext = require('./icons/IconAdapterContext.js');
19
20
  var useIconGlyph = require('./icons/useIconGlyph.js');
20
21
  var SceneIcon = require('./icons/SceneIcon.js');
22
+ var DesignTimeBundle = require('./packages/DesignTimeBundle.js');
23
+ var PackageHostConfiguration = require('./packages/PackageHostConfiguration.js');
21
24
  var ScenePackageBundle = require('./packages/ScenePackageBundle.js');
25
+ var ComponentsUiLibraryContract = require('./packages/ComponentsUiLibraryContract.js');
22
26
  var themeTokens = require('./theme/themeTokens.js');
23
27
  var SceneThemeProvider = require('./theme/SceneThemeProvider.js');
24
28
  var InteractionScope = require('./interactions/InteractionScope.js');
@@ -32,6 +36,9 @@ var useInteractionHosts = require('./interactions/useInteractionHosts.js');
32
36
 
33
37
 
34
38
  exports.SceneElementView = SceneElementView.SceneElementView;
39
+ exports.BindingOutputProvider = BindingOutputContext.BindingOutputProvider;
40
+ exports.useBindingOutputScope = BindingOutputContext.useBindingOutputScope;
41
+ exports.useBindingOutputs = BindingOutputContext.useBindingOutputs;
35
42
  exports.UnresolvedComponent = UnresolvedComponent.UnresolvedComponent;
36
43
  exports.createReactRenderer = createReactRenderer.createReactRenderer;
37
44
  exports.InteractiveComponent = InteractiveComponent.InteractiveComponent;
@@ -62,10 +69,14 @@ exports.IconAdapterProvider = IconAdapterContext.IconAdapterProvider;
62
69
  exports.useIconAdapters = IconAdapterContext.useIconAdapters;
63
70
  exports.useIconGlyph = useIconGlyph.useIconGlyph;
64
71
  exports.SceneIcon = SceneIcon.SceneIcon;
72
+ exports.validateDesignTimeBundle = DesignTimeBundle.validateDesignTimeBundle;
73
+ exports.resolvePackageHost = PackageHostConfiguration.resolvePackageHost;
65
74
  exports.componentRegistryKey = ScenePackageBundle.componentRegistryKey;
66
75
  exports.mergeIconAdapters = ScenePackageBundle.mergeIconAdapters;
67
76
  exports.mergePackageRegistries = ScenePackageBundle.mergePackageRegistries;
68
77
  exports.validatePackageBundle = ScenePackageBundle.validatePackageBundle;
78
+ exports.validateComponentsUiLibraryContract = ComponentsUiLibraryContract.validateComponentsUiLibraryContract;
79
+ exports.validateComponentsUiLibraryMapping = ComponentsUiLibraryContract.validateComponentsUiLibraryMapping;
69
80
  exports.applyThemeTokens = themeTokens.applyThemeTokens;
70
81
  exports.themeTokenPrefix = themeTokens.themeTokenPrefix;
71
82
  exports.themeTokenProperty = themeTokens.themeTokenProperty;
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;"}
1
+ {"version":3,"file":"index.js","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;"}
@@ -0,0 +1,72 @@
1
+ 'use strict';
2
+
3
+ // Copyright (c) Cratis. All rights reserved.
4
+ // Licensed under the MIT license. See LICENSE file in the project root for full license information.
5
+ /**
6
+ * The web-only mapping between an independently authored Scene catalog and a Components renderer.
7
+ * Primitive slot identities are not Scene component names: composites such as DataTable remain
8
+ * library-independent. This contract belongs to the React bundle, never the platform-neutral model.
9
+ */ /** Checks a mapping before loading executable frontend code. */ function validateComponentsUiLibraryContract(contract) {
10
+ const problems = [];
11
+ for (const field of [
12
+ 'module',
13
+ 'exportName',
14
+ 'id',
15
+ 'profile'
16
+ ]){
17
+ if (contract[field].trim().length === 0) problems.push(`Components UI library mapping has an empty '${field}'`);
18
+ }
19
+ if (!Number.isInteger(contract.abi) || contract.abi < 1) {
20
+ problems.push('Components UI library mapping requires a positive integer ABI major');
21
+ }
22
+ for (const [field, values] of [
23
+ [
24
+ 'requiredSlots',
25
+ contract.requiredSlots
26
+ ],
27
+ [
28
+ 'requiredCapabilities',
29
+ contract.requiredCapabilities ?? []
30
+ ]
31
+ ]){
32
+ const seen = new Set();
33
+ for (const value of values){
34
+ if (value.trim().length === 0) problems.push(`Components UI library mapping has an empty '${field}' entry`);
35
+ if (seen.has(value)) problems.push(`Components UI library mapping repeats '${value}' in '${field}'`);
36
+ seen.add(value);
37
+ }
38
+ }
39
+ return problems;
40
+ }
41
+ /**
42
+ * Proves that an allowlisted module export satisfies its Scene mapping. Hosts must reject problems,
43
+ * rather than silently falling back to a different library. Additional slots are permitted: a
44
+ * renderer can support more than the bounded profile this integration consumes.
45
+ */ function validateComponentsUiLibraryMapping(contract, library) {
46
+ const problems = validateComponentsUiLibraryContract(contract);
47
+ for (const field of [
48
+ 'id',
49
+ 'abi',
50
+ 'profile'
51
+ ]){
52
+ if (library[field] !== contract[field]) {
53
+ problems.push(`Components UI library '${contract.id}' requires ${field} '${contract[field]}' but the loaded library supplies '${library[field]}'`);
54
+ }
55
+ }
56
+ const slots = new Map(Object.entries(library.slots));
57
+ for (const slot of contract.requiredSlots){
58
+ if (!slots.has(slot) || slots.get(slot) === undefined || slots.get(slot) === null) {
59
+ problems.push(`Components UI library '${contract.id}' provides no implementation for required slot '${slot}'`);
60
+ }
61
+ }
62
+ for (const capability of contract.requiredCapabilities ?? []){
63
+ if (!library.capabilities.includes(capability)) {
64
+ problems.push(`Components UI library '${contract.id}' does not support required capability '${capability}'`);
65
+ }
66
+ }
67
+ return problems;
68
+ }
69
+
70
+ exports.validateComponentsUiLibraryContract = validateComponentsUiLibraryContract;
71
+ exports.validateComponentsUiLibraryMapping = validateComponentsUiLibraryMapping;
72
+ //# sourceMappingURL=ComponentsUiLibraryContract.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ComponentsUiLibraryContract.js","sources":["../../../packages/ComponentsUiLibraryContract.ts"],"sourcesContent":["// Copyright (c) Cratis. All rights reserved.\n// Licensed under the MIT license. See LICENSE file in the project root for full license information.\n\n/**\n * The web-only mapping between an independently authored Scene catalog and a Components renderer.\n * Primitive slot identities are not Scene component names: composites such as DataTable remain\n * library-independent. This contract belongs to the React bundle, never the platform-neutral model.\n */\nexport interface ComponentsUiLibraryContract {\n /** The npm module the host loads through its explicit package allowlist. */\n module: string;\n /** The named export supplying the Components UiLibrary. */\n exportName: string;\n /** The expected runtime library identity. */\n id: string;\n /** The Components renderer ABI major required by this mapping. */\n abi: number;\n /** The renderer profile promised by the library. */\n profile: string;\n /** Primitive or presentation slots the Scene integration requires. */\n requiredSlots: readonly string[];\n /** Capabilities required by the integration, not inferred from library identity. */\n requiredCapabilities?: readonly string[];\n}\n\n/**\n * The structural part of Components' UiLibrary needed to check a mapping. The actual library may\n * also contain providers and executable slot declarations; Scene does not load or reinterpret them.\n * Keeping this structural avoids a Components ABI dependency in Scene.Model or Scene.Engine.\n */\nexport interface ComponentsUiLibraryManifest {\n readonly id: string;\n readonly abi: number;\n readonly profile: string;\n readonly slots: object;\n readonly capabilities: readonly string[];\n}\n\n/** Checks a mapping before loading executable frontend code. */\nexport function validateComponentsUiLibraryContract(contract: ComponentsUiLibraryContract): string[] {\n const problems: string[] = [];\n for (const field of ['module', 'exportName', 'id', 'profile'] as const) {\n if (contract[field].trim().length === 0) problems.push(`Components UI library mapping has an empty '${field}'`);\n }\n if (!Number.isInteger(contract.abi) || contract.abi < 1) {\n problems.push('Components UI library mapping requires a positive integer ABI major');\n }\n for (const [field, values] of [\n ['requiredSlots', contract.requiredSlots],\n ['requiredCapabilities', contract.requiredCapabilities ?? []],\n ] as const) {\n const seen = new Set<string>();\n for (const value of values) {\n if (value.trim().length === 0) problems.push(`Components UI library mapping has an empty '${field}' entry`);\n if (seen.has(value)) problems.push(`Components UI library mapping repeats '${value}' in '${field}'`);\n seen.add(value);\n }\n }\n return problems;\n}\n\n/**\n * Proves that an allowlisted module export satisfies its Scene mapping. Hosts must reject problems,\n * rather than silently falling back to a different library. Additional slots are permitted: a\n * renderer can support more than the bounded profile this integration consumes.\n */\nexport function validateComponentsUiLibraryMapping(\n contract: ComponentsUiLibraryContract,\n library: ComponentsUiLibraryManifest,\n): string[] {\n const problems = validateComponentsUiLibraryContract(contract);\n for (const field of ['id', 'abi', 'profile'] as const) {\n if (library[field] !== contract[field]) {\n problems.push(`Components UI library '${contract.id}' requires ${field} '${contract[field]}' but the loaded library supplies '${library[field]}'`);\n }\n }\n const slots = new Map(Object.entries(library.slots));\n for (const slot of contract.requiredSlots) {\n if (!slots.has(slot) || slots.get(slot) === undefined || slots.get(slot) === null) {\n problems.push(`Components UI library '${contract.id}' provides no implementation for required slot '${slot}'`);\n }\n }\n for (const capability of contract.requiredCapabilities ?? []) {\n if (!library.capabilities.includes(capability)) {\n problems.push(`Components UI library '${contract.id}' does not support required capability '${capability}'`);\n }\n }\n return problems;\n}\n"],"names":["validateComponentsUiLibraryContract","contract","problems","field","trim","length","push","Number","isInteger","abi","values","requiredSlots","requiredCapabilities","seen","Set","value","has","add","validateComponentsUiLibraryMapping","library","id","slots","Map","Object","entries","slot","get","undefined","capability","capabilities","includes"],"mappings":"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"}
@@ -0,0 +1,17 @@
1
+ 'use strict';
2
+
3
+ // Copyright (c) Cratis. All rights reserved.
4
+ // Licensed under the MIT license. See LICENSE file in the project root for full license information.
5
+ function validateDesignTimeBundle(bundle) {
6
+ if (!bundle) return [];
7
+ const problems = [];
8
+ for (const [name, action] of Object.entries(bundle.actions ?? {})){
9
+ if (action.descriptor.id !== name) {
10
+ problems.push(`registers design-time action '${name}' with descriptor id '${action.descriptor.id}'`);
11
+ }
12
+ }
13
+ return problems;
14
+ }
15
+
16
+ exports.validateDesignTimeBundle = validateDesignTimeBundle;
17
+ //# sourceMappingURL=DesignTimeBundle.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"DesignTimeBundle.js","sources":["../../../packages/DesignTimeBundle.ts"],"sourcesContent":["// Copyright (c) Cratis. All rights reserved.\n// Licensed under the MIT license. See LICENSE file in the project root for full license information.\n\nimport { ComponentType, ReactNode } from 'react';\nimport { DesignTimeAction } from './DesignTimeAction';\n\n/**\n * Optional React-only design-time surface a package may publish beside its runtime bundle.\n */\nexport interface DesignTimeBundle {\n previews?: Record<string, ComponentType<{ children?: ReactNode }>>;\n designers?: Record<string, ComponentType<{ children?: ReactNode }>>;\n propertyEditors?: Record<string, ComponentType<Record<string, unknown>>>;\n propertyDisplays?: Record<string, ComponentType<{ value: unknown }>>;\n actions?: Record<string, DesignTimeAction>;\n}\n\nexport function validateDesignTimeBundle(bundle: DesignTimeBundle | undefined): string[] {\n if (!bundle) return [];\n const problems: string[] = [];\n for (const [name, action] of Object.entries(bundle.actions ?? {})) {\n if (action.descriptor.id !== name) {\n problems.push(`registers design-time action '${name}' with descriptor id '${action.descriptor.id}'`);\n }\n }\n return problems;\n}\n"],"names":["validateDesignTimeBundle","bundle","problems","name","action","Object","entries","actions","descriptor","id","push"],"mappings":";;AAAA;AACA;AAgBO,SAASA,yBAAyBC,MAAoC,EAAA;IACzE,IAAI,CAACA,MAAAA,EAAQ,OAAO,EAAE;AACtB,IAAA,MAAMC,WAAqB,EAAE;AAC7B,IAAA,KAAK,MAAM,CAACC,IAAAA,EAAMC,MAAAA,CAAO,IAAIC,MAAAA,CAAOC,OAAO,CAACL,MAAAA,CAAOM,OAAO,IAAI,EAAC,CAAA,CAAI;AAC/D,QAAA,IAAIH,MAAAA,CAAOI,UAAU,CAACC,EAAE,KAAKN,IAAAA,EAAM;AAC/BD,YAAAA,QAAAA,CAASQ,IAAI,CAAC,CAAC,8BAA8B,EAAEP,IAAAA,CAAK,sBAAsB,EAAEC,MAAAA,CAAOI,UAAU,CAACC,EAAE,CAAC,CAAC,CAAC,CAAA;AACvG,QAAA;AACJ,IAAA;IACA,OAAOP,QAAAA;AACX;;"}
@@ -0,0 +1,43 @@
1
+ 'use strict';
2
+
3
+ var ScenePackageBundle = require('./ScenePackageBundle.js');
4
+
5
+ // Copyright (c) Cratis. All rights reserved.
6
+ // Licensed under the MIT license. See LICENSE file in the project root for full license information.
7
+ /**
8
+ * Resolves the approved package set a standalone or embedded React host uses.
9
+ */ function resolvePackageHost(configuration) {
10
+ const diagnostics = [];
11
+ const byName = new Map(configuration.bundles.map((bundle)=>[
12
+ bundle.manifest.name,
13
+ bundle
14
+ ]));
15
+ const bundles = [];
16
+ const runtimeSingletons = new Map();
17
+ for (const packageName of configuration.profile.packages){
18
+ const bundle = byName.get(packageName);
19
+ if (!bundle) {
20
+ diagnostics.push(`UI profile asks for '${packageName}' but the host did not approve a bundle for it`);
21
+ continue;
22
+ }
23
+ if (!configuration.policy.allowNetworkAssets && (bundle.manifest.assets ?? []).some((asset)=>/^https?:\/\//.test(asset))) {
24
+ diagnostics.push(`Package '${packageName}' declares network assets, but host policy forbids them`);
25
+ }
26
+ for (const dependency of bundle.manifest.runtimeSingletons ?? []){
27
+ const owner = runtimeSingletons.get(dependency);
28
+ if (owner && owner !== packageName) {
29
+ diagnostics.push(`Runtime singleton '${dependency}' is provided by both '${owner}' and '${packageName}'`);
30
+ }
31
+ runtimeSingletons.set(dependency, packageName);
32
+ }
33
+ bundles.push(bundle);
34
+ }
35
+ return {
36
+ bundles,
37
+ components: ScenePackageBundle.mergePackageRegistries(bundles),
38
+ diagnostics
39
+ };
40
+ }
41
+
42
+ exports.resolvePackageHost = resolvePackageHost;
43
+ //# sourceMappingURL=PackageHostConfiguration.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"PackageHostConfiguration.js","sources":["../../../packages/PackageHostConfiguration.ts"],"sourcesContent":["// Copyright (c) Cratis. All rights reserved.\n// Licensed under the MIT license. See LICENSE file in the project root for full license information.\n\nimport { UiProfile } from '@cratis/scene.model';\nimport { ScenePackageBundle, mergePackageRegistries } from './ScenePackageBundle';\n\nexport interface PackageHostPolicy {\n allowExecutableImports: boolean;\n allowNetworkAssets: boolean;\n}\n\nexport interface PackageHostConfiguration {\n bundles: ScenePackageBundle[];\n profile: UiProfile;\n policy: PackageHostPolicy;\n}\n\nexport interface ResolvedPackageHost {\n bundles: ScenePackageBundle[];\n components: ReturnType<typeof mergePackageRegistries>;\n diagnostics: string[];\n}\n\n/**\n * Resolves the approved package set a standalone or embedded React host uses.\n */\nexport function resolvePackageHost(configuration: PackageHostConfiguration): ResolvedPackageHost {\n const diagnostics: string[] = [];\n const byName = new Map(configuration.bundles.map(bundle => [bundle.manifest.name, bundle]));\n const bundles: ScenePackageBundle[] = [];\n const runtimeSingletons = new Map<string, string>();\n\n for (const packageName of configuration.profile.packages) {\n const bundle = byName.get(packageName);\n if (!bundle) {\n diagnostics.push(`UI profile asks for '${packageName}' but the host did not approve a bundle for it`);\n continue;\n }\n\n if (!configuration.policy.allowNetworkAssets && (bundle.manifest.assets ?? []).some(asset => /^https?:\\/\\//.test(asset))) {\n diagnostics.push(`Package '${packageName}' declares network assets, but host policy forbids them`);\n }\n\n for (const dependency of bundle.manifest.runtimeSingletons ?? []) {\n const owner = runtimeSingletons.get(dependency);\n if (owner && owner !== packageName) {\n diagnostics.push(`Runtime singleton '${dependency}' is provided by both '${owner}' and '${packageName}'`);\n }\n runtimeSingletons.set(dependency, packageName);\n }\n\n bundles.push(bundle);\n }\n\n return { bundles, components: mergePackageRegistries(bundles), diagnostics };\n}\n"],"names":["resolvePackageHost","configuration","diagnostics","byName","Map","bundles","map","bundle","manifest","name","runtimeSingletons","packageName","profile","packages","get","push","policy","allowNetworkAssets","assets","some","asset","test","dependency","owner","set","components","mergePackageRegistries"],"mappings":";;;;AAAA;AACA;AAsBA;;IAGO,SAASA,kBAAAA,CAAmBC,aAAuC,EAAA;AACtE,IAAA,MAAMC,cAAwB,EAAE;IAChC,MAAMC,MAAAA,GAAS,IAAIC,GAAAA,CAAIH,aAAAA,CAAcI,OAAO,CAACC,GAAG,CAACC,CAAAA,MAAAA,GAAU;YAACA,MAAAA,CAAOC,QAAQ,CAACC,IAAI;AAAEF,YAAAA;AAAO,SAAA,CAAA,CAAA;AACzF,IAAA,MAAMF,UAAgC,EAAE;AACxC,IAAA,MAAMK,oBAAoB,IAAIN,GAAAA,EAAAA;AAE9B,IAAA,KAAK,MAAMO,WAAAA,IAAeV,aAAAA,CAAcW,OAAO,CAACC,QAAQ,CAAE;QACtD,MAAMN,MAAAA,GAASJ,MAAAA,CAAOW,GAAG,CAACH,WAAAA,CAAAA;AAC1B,QAAA,IAAI,CAACJ,MAAAA,EAAQ;AACTL,YAAAA,WAAAA,CAAYa,IAAI,CAAC,CAAC,qBAAqB,EAAEJ,WAAAA,CAAY,8CAA8C,CAAC,CAAA;AACpG,YAAA;AACJ,QAAA;QAEA,IAAI,CAACV,cAAce,MAAM,CAACC,kBAAkB,IAAKV,CAAAA,MAAAA,CAAOC,QAAQ,CAACU,MAAM,IAAI,EAAE,EAAEC,IAAI,CAACC,CAAAA,KAAAA,GAAS,cAAA,CAAeC,IAAI,CAACD,KAAAA,CAAAA,CAAAA,EAAS;AACtHlB,YAAAA,WAAAA,CAAYa,IAAI,CAAC,CAAC,SAAS,EAAEJ,WAAAA,CAAY,uDAAuD,CAAC,CAAA;AACrG,QAAA;QAEA,KAAK,MAAMW,cAAcf,MAAAA,CAAOC,QAAQ,CAACE,iBAAiB,IAAI,EAAE,CAAE;YAC9D,MAAMa,KAAAA,GAAQb,iBAAAA,CAAkBI,GAAG,CAACQ,UAAAA,CAAAA;YACpC,IAAIC,KAAAA,IAASA,UAAUZ,WAAAA,EAAa;AAChCT,gBAAAA,WAAAA,CAAYa,IAAI,CAAC,CAAC,mBAAmB,EAAEO,UAAAA,CAAW,uBAAuB,EAAEC,KAAAA,CAAM,OAAO,EAAEZ,WAAAA,CAAY,CAAC,CAAC,CAAA;AAC5G,YAAA;YACAD,iBAAAA,CAAkBc,GAAG,CAACF,UAAAA,EAAYX,WAAAA,CAAAA;AACtC,QAAA;AAEAN,QAAAA,OAAAA,CAAQU,IAAI,CAACR,MAAAA,CAAAA;AACjB,IAAA;IAEA,OAAO;AAAEF,QAAAA,OAAAA;AAASoB,QAAAA,UAAAA,EAAYC,yCAAAA,CAAuBrB,OAAAA,CAAAA;AAAUH,QAAAA;AAAY,KAAA;AAC/E;;"}
@@ -2,6 +2,8 @@
2
2
 
3
3
  var scene_model = require('@cratis/scene.model');
4
4
  var IconAdapterRegistry = require('../icons/IconAdapterRegistry.js');
5
+ var ComponentsUiLibraryContract = require('./ComponentsUiLibraryContract.js');
6
+ var DesignTimeBundle = require('./DesignTimeBundle.js');
5
7
 
6
8
  // Copyright (c) Cratis. All rights reserved.
7
9
  // Licensed under the MIT license. See LICENSE file in the project root for full license information.
@@ -63,8 +65,15 @@ var IconAdapterRegistry = require('../icons/IconAdapterRegistry.js');
63
65
  problems.push(`declares the theme '${name}' but provides no definition for it`);
64
66
  }
65
67
  }
68
+ if (bundle.componentsUiLibrary) {
69
+ if (manifest.kind !== scene_model.PackageKind.ComponentLibrary) {
70
+ problems.push('declares a Components UI library mapping but is not of kind ComponentLibrary');
71
+ }
72
+ problems.push(...ComponentsUiLibraryContract.validateComponentsUiLibraryContract(bundle.componentsUiLibrary));
73
+ }
66
74
  problems.push(...validateIconLibrary(bundle));
67
75
  problems.push(...validateDescriptors(bundle));
76
+ problems.push(...DesignTimeBundle.validateDesignTimeBundle(bundle.designTime));
68
77
  return problems;
69
78
  }
70
79
  function validateIconLibrary(bundle) {
@@ -1 +1 @@
1
- {"version":3,"file":"ScenePackageBundle.js","sources":["../../../packages/ScenePackageBundle.ts"],"sourcesContent":["// Copyright (c) Cratis. All rights reserved.\n// Licensed under the MIT license. See LICENSE file in the project root for full license information.\n\nimport { ComponentDescriptor, DialogTemplate, Layout, PackageKind, PropertyValueType, ScenePackage, Screen, ScreenTemplate, Theme } from '@cratis/scene.model';\nimport { IconAdapterRegistry, createIconAdapterRegistry } from '../icons/IconAdapterRegistry';\nimport { IconLibraryBundle } from '../icons/IconLibraryBundle';\nimport { ComponentRegistry } from '../renderer';\n\n/**\n * What a package actually ships to a React renderer, as opposed to what it *declares*.\n *\n * `ScenePackage` is the declaration — a name, a kind, dependencies, and the names of what it\n * contributes. It is deliberately platform-agnostic and lives in `Scene.Model`, because Stage's build and\n * Studio's design-time queries both read it without ever loading a component. A bundle is the other half:\n * the real React components, layouts, screens and themes behind those names, which only a renderer needs.\n *\n * A package publishes exactly one bundle, as a named export following its own name —\n * `primeReactPackage`, `cratisComponentsPackage`, `corePackage`. A host loads it from the module the\n * declaration's `ScenePackage.module` names.\n */\nexport interface ScenePackageBundle {\n /**\n * The package's own declaration. Its `components`, `layouts` and `themes` name lists must agree with\n * what this bundle actually provides — {@link validatePackageBundle} is what proves they do.\n */\n manifest: ScenePackage;\n\n /**\n * The components this package provides, keyed by {@link componentRegistryKey}.\n */\n components: ComponentRegistry;\n\n /**\n * The application shells this package provides, if any. Only a blueprint has these.\n */\n layouts?: Layout[];\n\n /**\n * The screen templates this package provides — the shapes that go inside a layout, each declaring\n * which of its parent's slots it fills.\n */\n screenTemplates?: ScreenTemplate[];\n\n /**\n * The dialog templates this package provides.\n */\n dialogTemplates?: DialogTemplate[];\n\n /**\n * Sample screens this package ships — a layout package's gallery, so a preview has real content to\n * put through the real engine rather than a mockup.\n */\n screens?: Screen[];\n\n /**\n * What can be edited on this package's components - one {@link ComponentDescriptor} per component that is\n * editable at design time. They are data, so Studio reads them without rendering anything, and they travel with\n * the components they describe rather than in a registry of their own. {@link validatePackageBundle} checks\n * that every descriptor names a component the manifest declares.\n */\n descriptors?: ComponentDescriptor[];\n\n /**\n * The themes this package ships, if any.\n */\n themes?: Theme[];\n\n /**\n * The icon catalog and renderer adapter of an icon-library package. Present exactly when the\n * manifest declares an icon library.\n */\n iconLibrary?: IconLibraryBundle;\n}\n\n/**\n * The key a component is registered and looked up under: the package that provides it, then the bare name\n * a screen refers to it by.\n *\n * A screen writes a bare name (`button`) or a package-qualified one (`PrimeReact.button`);\n * `resolveComponentName` turns either into a `{ name, package }` pair, and this turns that pair into the\n * registry key. Nothing should build this string by hand — the separator is an implementation detail of\n * the registry, deliberately not the `.` used for qualification in a screen, so a package name containing\n * dots stays unambiguous.\n */\nexport function componentRegistryKey(packageName: string, componentName: string): string {\n return `${packageName}:${componentName}`;\n}\n\n/**\n * Checks that a bundle provides everything its manifest declares, and declares everything it provides, and that\n * every descriptor it ships is for a component it declares and is well formed.\n *\n * A manifest that promises a component the bundle does not register renders as `UnresolvedComponent` at\n * runtime — a blank box, far from where the mistake was made. A component registered but not declared is\n * invisible to `resolveComponentName`, so a screen can never name it. Both are silent failures, which is\n * why every package's specs run this.\n */\nexport function validatePackageBundle(bundle: ScenePackageBundle): string[] {\n const problems: string[] = [];\n const { manifest } = bundle;\n\n for (const name of manifest.components) {\n if (!(componentRegistryKey(manifest.name, name) in bundle.components)) {\n problems.push(`declares the component '${name}' but registers no implementation for it`);\n }\n }\n\n const declared = new Set(manifest.components.map((name) => componentRegistryKey(manifest.name, name)));\n for (const key of Object.keys(bundle.components)) {\n if (!declared.has(key)) {\n problems.push(`registers '${key}', which the manifest does not declare`);\n }\n }\n\n const providedLayouts = new Set((bundle.layouts ?? []).map((layout) => layout.name));\n for (const name of manifest.layouts) {\n if (!providedLayouts.has(name)) {\n problems.push(`declares the layout '${name}' but provides no definition for it`);\n }\n }\n\n const providedScreenTemplates = new Set((bundle.screenTemplates ?? []).map((template) => template.name));\n for (const name of manifest.screenTemplates) {\n if (!providedScreenTemplates.has(name)) {\n problems.push(`declares the screen template '${name}' but provides no definition for it`);\n }\n }\n\n const providedDialogTemplates = new Set((bundle.dialogTemplates ?? []).map((template) => template.name));\n for (const name of manifest.dialogTemplates) {\n if (!providedDialogTemplates.has(name)) {\n problems.push(`declares the dialog template '${name}' but provides no definition for it`);\n }\n }\n\n const providedThemes = new Set((bundle.themes ?? []).map((theme) => theme.name));\n for (const name of manifest.themes) {\n if (!providedThemes.has(name)) {\n problems.push(`declares the theme '${name}' but provides no definition for it`);\n }\n }\n\n problems.push(...validateIconLibrary(bundle));\n problems.push(...validateDescriptors(bundle));\n\n return problems;\n}\n\nfunction validateIconLibrary(bundle: ScenePackageBundle): string[] {\n const problems: string[] = [];\n const { manifest, iconLibrary } = bundle;\n const declaresIconLibrary = manifest.kind === PackageKind.IconLibrary || manifest.iconLibrary !== undefined;\n\n if (manifest.kind === PackageKind.IconLibrary && !manifest.iconLibrary) {\n problems.push('is an icon library but declares no iconLibrary metadata');\n }\n\n if (manifest.kind !== PackageKind.IconLibrary && manifest.iconLibrary) {\n problems.push('declares iconLibrary metadata but is not of kind IconLibrary');\n }\n\n if (declaresIconLibrary && !iconLibrary) {\n problems.push('declares an icon library but the bundle provides no catalog or adapter for it');\n }\n\n if (!declaresIconLibrary && iconLibrary) {\n problems.push('provides an icon catalog and adapter, which the manifest does not declare');\n }\n\n if (iconLibrary) {\n if (iconLibrary.catalog.library !== manifest.name) {\n problems.push(`provides an icon catalog for '${iconLibrary.catalog.library}' instead of '${manifest.name}'`);\n }\n\n if (iconLibrary.adapter.library !== manifest.name) {\n problems.push(`provides an icon adapter for '${iconLibrary.adapter.library}' instead of '${manifest.name}'`);\n }\n\n if (manifest.iconLibrary && !manifest.iconLibrary.renderers.includes('react')) {\n problems.push(\"provides a React icon adapter but does not list 'react' among its icon renderers\");\n }\n }\n\n return problems;\n}\n\nfunction validateDescriptors(bundle: ScenePackageBundle): string[] {\n const problems: string[] = [];\n const declared = new Set(bundle.manifest.components.map((name) => componentRegistryKey(bundle.manifest.name, name)));\n const described = new Set<string>();\n\n for (const descriptor of bundle.descriptors ?? []) {\n if (!declared.has(descriptor.component)) {\n problems.push(`describes '${descriptor.component}', which the manifest does not declare as a component`);\n }\n\n if (described.has(descriptor.component)) {\n problems.push(`describes '${descriptor.component}' more than once`);\n }\n\n described.add(descriptor.component);\n\n const paths = new Set<string>();\n for (const property of descriptor.properties) {\n if (paths.has(property.path)) {\n problems.push(`'${descriptor.component}' describes the property '${property.path}' more than once`);\n }\n\n paths.add(property.path);\n\n if (property.valueType === PropertyValueType.Collection && property.item === undefined) {\n problems.push(`'${descriptor.component}' describes the collection '${property.path}' without describing its items`);\n }\n\n if (property.valueType === PropertyValueType.Enum && (property.choices ?? []).length === 0) {\n problems.push(`'${descriptor.component}' describes the enum '${property.path}' without choices`);\n }\n }\n }\n\n return problems;\n}\n\n/**\n * Merges the component registries of several bundles into the single registry a renderer consumes.\n *\n * Keys carry their package name, so nothing collides and merge order does not matter — which package wins\n * a *bare* name is decided earlier, by `resolveComponentName` walking the profile's priority order.\n */\nexport function mergePackageRegistries(bundles: ScenePackageBundle[]): ComponentRegistry {\n return Object.assign({}, ...bundles.map((bundle) => bundle.components)) as ComponentRegistry;\n}\n\n/**\n * Collects the icon adapters of several bundles into the registry `SceneIcon` renders through.\n *\n * @throws Error when two bundles provide an adapter for the same library.\n */\nexport function mergeIconAdapters(bundles: ScenePackageBundle[]): IconAdapterRegistry {\n return createIconAdapterRegistry(bundles.flatMap((bundle) => (bundle.iconLibrary ? [bundle.iconLibrary.adapter] : [])));\n}\n"],"names":["componentRegistryKey","packageName","componentName","validatePackageBundle","bundle","problems","manifest","name","components","push","declared","Set","map","key","Object","keys","has","providedLayouts","layouts","layout","providedScreenTemplates","screenTemplates","template","providedDialogTemplates","dialogTemplates","providedThemes","themes","theme","validateIconLibrary","validateDescriptors","iconLibrary","declaresIconLibrary","kind","PackageKind","IconLibrary","undefined","catalog","library","adapter","renderers","includes","described","descriptor","descriptors","component","add","paths","property","properties","path","valueType","PropertyValueType","Collection","item","Enum","choices","length","mergePackageRegistries","bundles","assign","mergeIconAdapters","createIconAdapterRegistry","flatMap"],"mappings":"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"}
1
+ {"version":3,"file":"ScenePackageBundle.js","sources":["../../../packages/ScenePackageBundle.ts"],"sourcesContent":["// Copyright (c) Cratis. All rights reserved.\n// Licensed under the MIT license. See LICENSE file in the project root for full license information.\n\nimport { ComponentDescriptor, DialogTemplate, Layout, PackageKind, PropertyValueType, ScenePackage, Screen, ScreenTemplate, Theme } from '@cratis/scene.model';\nimport { IconAdapterRegistry, createIconAdapterRegistry } from '../icons/IconAdapterRegistry';\nimport { IconLibraryBundle } from '../icons/IconLibraryBundle';\nimport { ComponentRegistry } from '../renderer';\nimport { ComponentsUiLibraryContract, validateComponentsUiLibraryContract } from './ComponentsUiLibraryContract';\nimport { DesignTimeBundle, validateDesignTimeBundle } from './DesignTimeBundle';\n\n/**\n * What a package actually ships to a React renderer, as opposed to what it *declares*.\n *\n * `ScenePackage` is the declaration — a name, a kind, dependencies, and the names of what it\n * contributes. It is deliberately platform-agnostic and lives in `Scene.Model`, because Stage's build and\n * Studio's design-time queries both read it without ever loading a component. A bundle is the other half:\n * the real React components, layouts, screens and themes behind those names, which only a renderer needs.\n *\n * A package publishes exactly one bundle, as a named export following its own name —\n * `primeReactPackage`, `cratisComponentsPackage`, `corePackage`. A host loads it from the module the\n * declaration's `ScenePackage.module` names.\n */\nexport interface ScenePackageBundle {\n /**\n * The package's own declaration. Its `components`, `layouts` and `themes` name lists must agree with\n * what this bundle actually provides — {@link validatePackageBundle} is what proves they do.\n */\n manifest: ScenePackage;\n\n /**\n * The components this package provides, keyed by {@link componentRegistryKey}.\n */\n components: ComponentRegistry;\n\n /**\n * The application shells this package provides, if any. Only a blueprint has these.\n */\n layouts?: Layout[];\n\n /**\n * The screen templates this package provides — the shapes that go inside a layout, each declaring\n * which of its parent's slots it fills.\n */\n screenTemplates?: ScreenTemplate[];\n\n /**\n * The dialog templates this package provides.\n */\n dialogTemplates?: DialogTemplate[];\n\n /**\n * Sample screens this package ships — a layout package's gallery, so a preview has real content to\n * put through the real engine rather than a mockup.\n */\n screens?: Screen[];\n\n /**\n * What can be edited on this package's components - one {@link ComponentDescriptor} per component that is\n * editable at design time. They are data, so Studio reads them without rendering anything, and they travel with\n * the components they describe rather than in a registry of their own. {@link validatePackageBundle} checks\n * that every descriptor names a component the manifest declares.\n */\n descriptors?: ComponentDescriptor[];\n\n /**\n * The themes this package ships, if any.\n */\n themes?: Theme[];\n\n /**\n * The icon catalog and renderer adapter of an icon-library package. Present exactly when the\n * manifest declares an icon library.\n */\n iconLibrary?: IconLibraryBundle;\n\n /**\n * Optional web-renderer mapping to a Components UiLibrary. Scene's catalog remains independently\n * authored; hosts check the loaded export with validateComponentsUiLibraryMapping before rendering.\n */\n componentsUiLibrary?: ComponentsUiLibraryContract;\n\n /** Optional React-only design-time tooling. Runtime hosts can omit it entirely. */\n designTime?: DesignTimeBundle;\n}\n\n/**\n * The key a component is registered and looked up under: the package that provides it, then the bare name\n * a screen refers to it by.\n *\n * A screen writes a bare name (`button`) or a package-qualified one (`PrimeReact.button`);\n * `resolveComponentName` turns either into a `{ name, package }` pair, and this turns that pair into the\n * registry key. Nothing should build this string by hand — the separator is an implementation detail of\n * the registry, deliberately not the `.` used for qualification in a screen, so a package name containing\n * dots stays unambiguous.\n */\nexport function componentRegistryKey(packageName: string, componentName: string): string {\n return `${packageName}:${componentName}`;\n}\n\n/**\n * Checks that a bundle provides everything its manifest declares, and declares everything it provides, and that\n * every descriptor it ships is for a component it declares and is well formed.\n *\n * A manifest that promises a component the bundle does not register renders as `UnresolvedComponent` at\n * runtime — a blank box, far from where the mistake was made. A component registered but not declared is\n * invisible to `resolveComponentName`, so a screen can never name it. Both are silent failures, which is\n * why every package's specs run this.\n */\nexport function validatePackageBundle(bundle: ScenePackageBundle): string[] {\n const problems: string[] = [];\n const { manifest } = bundle;\n\n for (const name of manifest.components) {\n if (!(componentRegistryKey(manifest.name, name) in bundle.components)) {\n problems.push(`declares the component '${name}' but registers no implementation for it`);\n }\n }\n\n const declared = new Set(manifest.components.map((name) => componentRegistryKey(manifest.name, name)));\n for (const key of Object.keys(bundle.components)) {\n if (!declared.has(key)) {\n problems.push(`registers '${key}', which the manifest does not declare`);\n }\n }\n\n const providedLayouts = new Set((bundle.layouts ?? []).map((layout) => layout.name));\n for (const name of manifest.layouts) {\n if (!providedLayouts.has(name)) {\n problems.push(`declares the layout '${name}' but provides no definition for it`);\n }\n }\n\n const providedScreenTemplates = new Set((bundle.screenTemplates ?? []).map((template) => template.name));\n for (const name of manifest.screenTemplates) {\n if (!providedScreenTemplates.has(name)) {\n problems.push(`declares the screen template '${name}' but provides no definition for it`);\n }\n }\n\n const providedDialogTemplates = new Set((bundle.dialogTemplates ?? []).map((template) => template.name));\n for (const name of manifest.dialogTemplates) {\n if (!providedDialogTemplates.has(name)) {\n problems.push(`declares the dialog template '${name}' but provides no definition for it`);\n }\n }\n\n const providedThemes = new Set((bundle.themes ?? []).map((theme) => theme.name));\n for (const name of manifest.themes) {\n if (!providedThemes.has(name)) {\n problems.push(`declares the theme '${name}' but provides no definition for it`);\n }\n }\n\n if (bundle.componentsUiLibrary) {\n if (manifest.kind !== PackageKind.ComponentLibrary) {\n problems.push('declares a Components UI library mapping but is not of kind ComponentLibrary');\n }\n problems.push(...validateComponentsUiLibraryContract(bundle.componentsUiLibrary));\n }\n\n problems.push(...validateIconLibrary(bundle));\n problems.push(...validateDescriptors(bundle));\n problems.push(...validateDesignTimeBundle(bundle.designTime));\n\n return problems;\n}\n\nfunction validateIconLibrary(bundle: ScenePackageBundle): string[] {\n const problems: string[] = [];\n const { manifest, iconLibrary } = bundle;\n const declaresIconLibrary = manifest.kind === PackageKind.IconLibrary || manifest.iconLibrary !== undefined;\n\n if (manifest.kind === PackageKind.IconLibrary && !manifest.iconLibrary) {\n problems.push('is an icon library but declares no iconLibrary metadata');\n }\n\n if (manifest.kind !== PackageKind.IconLibrary && manifest.iconLibrary) {\n problems.push('declares iconLibrary metadata but is not of kind IconLibrary');\n }\n\n if (declaresIconLibrary && !iconLibrary) {\n problems.push('declares an icon library but the bundle provides no catalog or adapter for it');\n }\n\n if (!declaresIconLibrary && iconLibrary) {\n problems.push('provides an icon catalog and adapter, which the manifest does not declare');\n }\n\n if (iconLibrary) {\n if (iconLibrary.catalog.library !== manifest.name) {\n problems.push(`provides an icon catalog for '${iconLibrary.catalog.library}' instead of '${manifest.name}'`);\n }\n\n if (iconLibrary.adapter.library !== manifest.name) {\n problems.push(`provides an icon adapter for '${iconLibrary.adapter.library}' instead of '${manifest.name}'`);\n }\n\n if (manifest.iconLibrary && !manifest.iconLibrary.renderers.includes('react')) {\n problems.push(\"provides a React icon adapter but does not list 'react' among its icon renderers\");\n }\n }\n\n return problems;\n}\n\nfunction validateDescriptors(bundle: ScenePackageBundle): string[] {\n const problems: string[] = [];\n const declared = new Set(bundle.manifest.components.map((name) => componentRegistryKey(bundle.manifest.name, name)));\n const described = new Set<string>();\n\n for (const descriptor of bundle.descriptors ?? []) {\n if (!declared.has(descriptor.component)) {\n problems.push(`describes '${descriptor.component}', which the manifest does not declare as a component`);\n }\n\n if (described.has(descriptor.component)) {\n problems.push(`describes '${descriptor.component}' more than once`);\n }\n\n described.add(descriptor.component);\n\n const paths = new Set<string>();\n for (const property of descriptor.properties) {\n if (paths.has(property.path)) {\n problems.push(`'${descriptor.component}' describes the property '${property.path}' more than once`);\n }\n\n paths.add(property.path);\n\n if (property.valueType === PropertyValueType.Collection && property.item === undefined) {\n problems.push(`'${descriptor.component}' describes the collection '${property.path}' without describing its items`);\n }\n\n if (property.valueType === PropertyValueType.Enum && (property.choices ?? []).length === 0) {\n problems.push(`'${descriptor.component}' describes the enum '${property.path}' without choices`);\n }\n }\n }\n\n return problems;\n}\n\n/**\n * Merges the component registries of several bundles into the single registry a renderer consumes.\n *\n * Keys carry their package name, so nothing collides and merge order does not matter — which package wins\n * a *bare* name is decided earlier, by `resolveComponentName` walking the profile's priority order.\n */\nexport function mergePackageRegistries(bundles: ScenePackageBundle[]): ComponentRegistry {\n return Object.assign({}, ...bundles.map((bundle) => bundle.components)) as ComponentRegistry;\n}\n\n/**\n * Collects the icon adapters of several bundles into the registry `SceneIcon` renders through.\n *\n * @throws Error when two bundles provide an adapter for the same library.\n */\nexport function mergeIconAdapters(bundles: ScenePackageBundle[]): IconAdapterRegistry {\n return createIconAdapterRegistry(bundles.flatMap((bundle) => (bundle.iconLibrary ? [bundle.iconLibrary.adapter] : [])));\n}\n"],"names":["componentRegistryKey","packageName","componentName","validatePackageBundle","bundle","problems","manifest","name","components","push","declared","Set","map","key","Object","keys","has","providedLayouts","layouts","layout","providedScreenTemplates","screenTemplates","template","providedDialogTemplates","dialogTemplates","providedThemes","themes","theme","componentsUiLibrary","kind","PackageKind","ComponentLibrary","validateComponentsUiLibraryContract","validateIconLibrary","validateDescriptors","validateDesignTimeBundle","designTime","iconLibrary","declaresIconLibrary","IconLibrary","undefined","catalog","library","adapter","renderers","includes","described","descriptor","descriptors","component","add","paths","property","properties","path","valueType","PropertyValueType","Collection","item","Enum","choices","length","mergePackageRegistries","bundles","assign","mergeIconAdapters","createIconAdapterRegistry","flatMap"],"mappings":"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"}
@@ -0,0 +1,74 @@
1
+ 'use strict';
2
+
3
+ var jsxRuntime = require('react/jsx-runtime');
4
+ var react = require('react');
5
+
6
+ const emptyOutputs = {
7
+ setOutput: ()=>undefined,
8
+ clearOutput: ()=>undefined,
9
+ clearAll: ()=>undefined
10
+ };
11
+ const Context = /*#__PURE__*/ react.createContext(undefined);
12
+ /**
13
+ * Tracks component output properties for typed component-property bindings and clears them with component lifecycle.
14
+ */ function BindingOutputProvider({ children, onOutputsChanged }) {
15
+ const [outputs, setOutputs] = react.useState({});
16
+ react.useEffect(()=>{
17
+ onOutputsChanged?.(outputs);
18
+ }, [
19
+ onOutputsChanged,
20
+ outputs
21
+ ]);
22
+ const outputFor = react.useCallback((elementId)=>({
23
+ setOutput: (property, propertyValue)=>setOutputs((current)=>({
24
+ ...current,
25
+ [elementId]: {
26
+ ...current[elementId] ?? {},
27
+ [property]: propertyValue
28
+ }
29
+ })),
30
+ clearOutput: (property)=>setOutputs((current)=>{
31
+ const elementOutputs = {
32
+ ...current[elementId] ?? {}
33
+ };
34
+ delete elementOutputs[property];
35
+ return {
36
+ ...current,
37
+ [elementId]: elementOutputs
38
+ };
39
+ }),
40
+ clearAll: ()=>setOutputs((current)=>{
41
+ const next = {
42
+ ...current
43
+ };
44
+ delete next[elementId];
45
+ return next;
46
+ })
47
+ }), []);
48
+ const value = react.useMemo(()=>({
49
+ outputs,
50
+ outputFor
51
+ }), [
52
+ outputs,
53
+ outputFor
54
+ ]);
55
+ return /*#__PURE__*/ jsxRuntime.jsx(Context.Provider, {
56
+ value: value,
57
+ children: children
58
+ });
59
+ }
60
+ function useBindingOutputs(elementId) {
61
+ const outputFor = react.useContext(Context)?.outputFor;
62
+ return react.useMemo(()=>outputFor?.(elementId) ?? emptyOutputs, [
63
+ outputFor,
64
+ elementId
65
+ ]);
66
+ }
67
+ function useBindingOutputScope() {
68
+ return react.useContext(Context)?.outputs ?? {};
69
+ }
70
+
71
+ exports.BindingOutputProvider = BindingOutputProvider;
72
+ exports.useBindingOutputScope = useBindingOutputScope;
73
+ exports.useBindingOutputs = useBindingOutputs;
74
+ //# sourceMappingURL=BindingOutputContext.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"BindingOutputContext.js","sources":["../../../renderer/BindingOutputContext.tsx"],"sourcesContent":["// Copyright (c) Cratis. All rights reserved.\n// Licensed under the MIT license. See LICENSE file in the project root for full license information.\n\nimport { ReactNode, createContext, useCallback, useContext, useEffect, useMemo, useState } from 'react';\n\nexport interface ComponentBindingOutputs {\n setOutput(property: string, value: unknown): void;\n clearOutput(property: string): void;\n clearAll(): void;\n}\n\nexport interface BindingOutputProviderValue {\n outputs: Record<string, Record<string, unknown>>;\n outputFor(elementId: string): ComponentBindingOutputs;\n}\n\nconst emptyOutputs: ComponentBindingOutputs = {\n setOutput: () => undefined,\n clearOutput: () => undefined,\n clearAll: () => undefined,\n};\n\nconst Context = createContext<BindingOutputProviderValue | undefined>(undefined);\n\nexport interface BindingOutputProviderProps {\n children: ReactNode;\n onOutputsChanged?: (outputs: Record<string, Record<string, unknown>>) => void;\n}\n\n/**\n * Tracks component output properties for typed component-property bindings and clears them with component lifecycle.\n */\nexport function BindingOutputProvider({ children, onOutputsChanged }: BindingOutputProviderProps) {\n const [outputs, setOutputs] = useState<Record<string, Record<string, unknown>>>({});\n\n useEffect(() => {\n onOutputsChanged?.(outputs);\n }, [onOutputsChanged, outputs]);\n\n const outputFor = useCallback((elementId: string): ComponentBindingOutputs => ({\n setOutput: (property: string, propertyValue: unknown) => setOutputs(current => ({\n ...current,\n [elementId]: { ...(current[elementId] ?? {}), [property]: propertyValue },\n })),\n clearOutput: (property: string) => setOutputs(current => {\n const elementOutputs = { ...(current[elementId] ?? {}) };\n delete elementOutputs[property];\n return { ...current, [elementId]: elementOutputs };\n }),\n clearAll: () => setOutputs(current => {\n const next = { ...current };\n delete next[elementId];\n return next;\n }),\n }), []);\n\n const value = useMemo<BindingOutputProviderValue>(() => ({ outputs, outputFor }), [outputs, outputFor]);\n\n return <Context.Provider value={value}>{children}</Context.Provider>;\n}\n\nexport function useBindingOutputs(elementId: string): ComponentBindingOutputs {\n const outputFor = useContext(Context)?.outputFor;\n return useMemo(() => outputFor?.(elementId) ?? emptyOutputs, [outputFor, elementId]);\n}\n\nexport function useBindingOutputScope(): Record<string, Record<string, unknown>> {\n return useContext(Context)?.outputs ?? {};\n}\n"],"names":["emptyOutputs","setOutput","undefined","clearOutput","clearAll","Context","createContext","BindingOutputProvider","children","onOutputsChanged","outputs","setOutputs","useState","useEffect","outputFor","useCallback","elementId","property","propertyValue","current","elementOutputs","next","value","useMemo","_jsx","Provider","useBindingOutputs","useContext","useBindingOutputScope"],"mappings":";;;;;AAgBA,MAAMA,YAAAA,GAAwC;AAC1CC,IAAAA,SAAAA,EAAW,IAAMC,SAAAA;AACjBC,IAAAA,WAAAA,EAAa,IAAMD,SAAAA;AACnBE,IAAAA,QAAAA,EAAU,IAAMF;AACpB,CAAA;AAEA,MAAMG,wBAAUC,mBAAAA,CAAsDJ,SAAAA,CAAAA;AAOtE;;AAEC,IACM,SAASK,qBAAAA,CAAsB,EAAEC,QAAQ,EAAEC,gBAAgB,EAA8B,EAAA;AAC5F,IAAA,MAAM,CAACC,OAAAA,EAASC,UAAAA,CAAW,GAAGC,eAAkD,EAAC,CAAA;IAEjFC,eAAAA,CAAU,IAAA;QACNJ,gBAAAA,GAAmBC,OAAAA,CAAAA;IACvB,CAAA,EAAG;AAACD,QAAAA,gBAAAA;AAAkBC,QAAAA;AAAQ,KAAA,CAAA;AAE9B,IAAA,MAAMI,SAAAA,GAAYC,iBAAAA,CAAY,CAACC,SAAAA,IAAgD;AAC3Ef,YAAAA,SAAAA,EAAW,CAACgB,QAAAA,EAAkBC,aAAAA,GAA2BP,UAAAA,CAAWQ,CAAAA,WAAY;AAC5E,wBAAA,GAAGA,OAAO;AACV,wBAAA,CAACH,YAAY;AAAE,4BAAA,GAAIG,OAAO,CAACH,SAAAA,CAAU,IAAI,EAAE;AAAG,4BAAA,CAACC,WAAWC;AAAc;qBAC5E,CAAA,CAAA;YACAf,WAAAA,EAAa,CAACc,QAAAA,GAAqBN,UAAAA,CAAWQ,CAAAA,OAAAA,GAAAA;AAC1C,oBAAA,MAAMC,cAAAA,GAAiB;AAAE,wBAAA,GAAID,OAAO,CAACH,SAAAA,CAAU,IAAI;AAAI,qBAAA;oBACvD,OAAOI,cAAc,CAACH,QAAAA,CAAS;oBAC/B,OAAO;AAAE,wBAAA,GAAGE,OAAO;AAAE,wBAAA,CAACH,YAAYI;AAAe,qBAAA;AACrD,gBAAA,CAAA,CAAA;YACAhB,QAAAA,EAAU,IAAMO,WAAWQ,CAAAA,OAAAA,GAAAA;AACvB,oBAAA,MAAME,IAAAA,GAAO;AAAE,wBAAA,GAAGF;AAAQ,qBAAA;oBAC1B,OAAOE,IAAI,CAACL,SAAAA,CAAU;oBACtB,OAAOK,IAAAA;AACX,gBAAA,CAAA;AACJ,SAAA,GAAI,EAAE,CAAA;IAEN,MAAMC,KAAAA,GAAQC,aAAAA,CAAoC,KAAO;AAAEb,YAAAA,OAAAA;AAASI,YAAAA;AAAU,SAAA,CAAA,EAAI;AAACJ,QAAAA,OAAAA;AAASI,QAAAA;AAAU,KAAA,CAAA;IAEtG,qBAAOU,cAAA,CAACnB,QAAQoB,QAAQ,EAAA;QAACH,KAAAA,EAAOA,KAAAA;AAAQd,QAAAA,QAAAA,EAAAA;;AAC5C;AAEO,SAASkB,kBAAkBV,SAAiB,EAAA;IAC/C,MAAMF,SAAAA,GAAYa,iBAAWtB,OAAAA,CAAAA,EAAUS,SAAAA;AACvC,IAAA,OAAOS,aAAAA,CAAQ,IAAMT,SAAAA,GAAYE,SAAAA,CAAAA,IAAchB,YAAAA,EAAc;AAACc,QAAAA,SAAAA;AAAWE,QAAAA;AAAU,KAAA,CAAA;AACvF;AAEO,SAASY,qBAAAA,GAAAA;IACZ,OAAOD,gBAAAA,CAAWtB,OAAAA,CAAAA,EAAUK,OAAAA,IAAW,EAAC;AAC5C;;;;"}
@@ -4,6 +4,7 @@ var react = require('react');
4
4
  require('react/jsx-runtime');
5
5
  var useInteractions = require('../interactions/useInteractions.js');
6
6
  require('../interactions/NotificationHost.js');
7
+ var BindingOutputContext = require('./BindingOutputContext.js');
7
8
 
8
9
  // Copyright (c) Cratis. All rights reserved.
9
10
  // Licensed under the MIT license. See LICENSE file in the project root for full license information.
@@ -15,10 +16,15 @@ require('../interactions/NotificationHost.js');
15
16
  * same element tree be rendered by something that is not React at all.
16
17
  */ function InteractiveComponent({ component, element, slots }) {
17
18
  const interactions = useInteractions.useInteractions(element.id, element.behaviors);
19
+ const bindingOutputs = BindingOutputContext.useBindingOutputs(element.id);
20
+ react.useEffect(()=>()=>bindingOutputs.clearAll(), [
21
+ element.id
22
+ ]);
18
23
  return /*#__PURE__*/ react.createElement(component, {
19
24
  element,
20
25
  slots,
21
- interactions
26
+ interactions,
27
+ bindingOutputs
22
28
  });
23
29
  }
24
30
 
@@ -1 +1 @@
1
- {"version":3,"file":"InteractiveComponent.js","sources":["../../../renderer/InteractiveComponent.tsx"],"sourcesContent":["// Copyright (c) Cratis. All rights reserved.\n// Licensed under the MIT license. See LICENSE file in the project root for full license information.\n\nimport { ComponentType, ReactNode, createElement } from 'react';\nimport { ExternalComponent } from '@cratis/scene.model';\nimport { useInteractions } from '../interactions';\nimport { RegisteredComponentProps } from './ComponentRegistry';\n\nexport interface InteractiveComponentProps {\n component: ComponentType<RegisteredComponentProps>;\n element: ExternalComponent;\n slots: Record<string, ReactNode[]>;\n}\n\n/**\n * Resolves an element's interactions and hands them to the component that renders it.\n *\n * This exists as a component rather than as a call inside the renderer because resolving them is a hook, and a\n * hook cannot run inside the plain function a {@link Renderer} is. Keeping the renderer plain is what lets the\n * same element tree be rendered by something that is not React at all.\n */\nexport function InteractiveComponent({ component, element, slots }: InteractiveComponentProps) {\n const interactions = useInteractions(element.id, element.behaviors);\n return createElement(component, { element, slots, interactions });\n}\n"],"names":["InteractiveComponent","component","element","slots","interactions","useInteractions","id","behaviors","createElement"],"mappings":";;;;;;;AAAA;AACA;AAaA;;;;;;IAOO,SAASA,oBAAAA,CAAqB,EAAEC,SAAS,EAAEC,OAAO,EAAEC,KAAK,EAA6B,EAAA;AACzF,IAAA,MAAMC,eAAeC,+BAAAA,CAAgBH,OAAAA,CAAQI,EAAE,EAAEJ,QAAQK,SAAS,CAAA;AAClE,IAAA,qBAAOC,oBAAcP,SAAAA,EAAW;AAAEC,QAAAA,OAAAA;AAASC,QAAAA,KAAAA;AAAOC,QAAAA;AAAa,KAAA,CAAA;AACnE;;"}
1
+ {"version":3,"file":"InteractiveComponent.js","sources":["../../../renderer/InteractiveComponent.tsx"],"sourcesContent":["// Copyright (c) Cratis. All rights reserved.\n// Licensed under the MIT license. See LICENSE file in the project root for full license information.\n\nimport { ComponentType, ReactNode, createElement, useEffect } from 'react';\nimport { ExternalComponent } from '@cratis/scene.model';\nimport { useInteractions } from '../interactions';\nimport { useBindingOutputs } from './BindingOutputContext';\nimport { RegisteredComponentProps } from './ComponentRegistry';\n\nexport interface InteractiveComponentProps {\n component: ComponentType<RegisteredComponentProps>;\n element: ExternalComponent;\n slots: Record<string, ReactNode[]>;\n}\n\n/**\n * Resolves an element's interactions and hands them to the component that renders it.\n *\n * This exists as a component rather than as a call inside the renderer because resolving them is a hook, and a\n * hook cannot run inside the plain function a {@link Renderer} is. Keeping the renderer plain is what lets the\n * same element tree be rendered by something that is not React at all.\n */\nexport function InteractiveComponent({ component, element, slots }: InteractiveComponentProps) {\n const interactions = useInteractions(element.id, element.behaviors);\n const bindingOutputs = useBindingOutputs(element.id);\n useEffect(() => () => bindingOutputs.clearAll(), [element.id]);\n return createElement(component, { element, slots, interactions, bindingOutputs });\n}\n"],"names":["InteractiveComponent","component","element","slots","interactions","useInteractions","id","behaviors","bindingOutputs","useBindingOutputs","useEffect","clearAll","createElement"],"mappings":";;;;;;;;AAAA;AACA;AAcA;;;;;;IAOO,SAASA,oBAAAA,CAAqB,EAAEC,SAAS,EAAEC,OAAO,EAAEC,KAAK,EAA6B,EAAA;AACzF,IAAA,MAAMC,eAAeC,+BAAAA,CAAgBH,OAAAA,CAAQI,EAAE,EAAEJ,QAAQK,SAAS,CAAA;IAClE,MAAMC,cAAAA,GAAiBC,sCAAAA,CAAkBP,OAAAA,CAAQI,EAAE,CAAA;AACnDI,IAAAA,eAAAA,CAAU,IAAM,IAAMF,cAAAA,CAAeG,QAAQ,EAAA,EAAI;AAACT,QAAAA,OAAAA,CAAQI;AAAG,KAAA,CAAA;AAC7D,IAAA,qBAAOM,oBAAcX,SAAAA,EAAW;AAAEC,QAAAA,OAAAA;AAASC,QAAAA,KAAAA;AAAOC,QAAAA,YAAAA;AAAcI,QAAAA;AAAe,KAAA,CAAA;AACnF;;"}
@@ -6,6 +6,7 @@ export interface SceneElementViewProps {
6
6
  registry: ComponentRegistry;
7
7
  resolveBinding: BindingResolver;
8
8
  configuration?: EffectiveConfiguration;
9
+ onComponentOutputsChanged?: (outputs: Record<string, Record<string, unknown>>) => void;
9
10
  }
10
- export declare function SceneElementView({ element, registry, resolveBinding, configuration }: SceneElementViewProps): import("react").JSX.Element;
11
+ export declare function SceneElementView({ element, registry, resolveBinding, configuration, onComponentOutputsChanged }: SceneElementViewProps): import("react").JSX.Element;
11
12
  //# sourceMappingURL=SceneElementView.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"SceneElementView.d.ts","sourceRoot":"","sources":["../../SceneElementView.tsx"],"names":[],"mappings":"AAIA,OAAO,EAA8C,eAAe,EAAE,MAAM,sBAAsB,CAAC;AACnG,OAAO,EAAE,sBAAsB,EAAE,YAAY,EAAE,MAAM,qBAAqB,CAAC;AAC3E,OAAO,EAAE,iBAAiB,EAAuB,MAAM,YAAY,CAAC;AAEpE,MAAM,WAAW,qBAAqB;IAClC,OAAO,EAAE,YAAY,CAAC;IACtB,QAAQ,EAAE,iBAAiB,CAAC;IAC5B,cAAc,EAAE,eAAe,CAAC;IAQhC,aAAa,CAAC,EAAE,sBAAsB,CAAC;CAC1C;AAMD,wBAAgB,gBAAgB,CAAC,EAAE,OAAO,EAAE,QAAQ,EAAE,cAAc,EAAE,aAAa,EAAE,EAAE,qBAAqB,+BAI3G"}
1
+ {"version":3,"file":"SceneElementView.d.ts","sourceRoot":"","sources":["../../SceneElementView.tsx"],"names":[],"mappings":"AAIA,OAAO,EAA8C,eAAe,EAAE,MAAM,sBAAsB,CAAC;AACnG,OAAO,EAAE,sBAAsB,EAAE,YAAY,EAAE,MAAM,qBAAqB,CAAC;AAC3E,OAAO,EAAyB,iBAAiB,EAAuB,MAAM,YAAY,CAAC;AAE3F,MAAM,WAAW,qBAAqB;IAClC,OAAO,EAAE,YAAY,CAAC;IACtB,QAAQ,EAAE,iBAAiB,CAAC;IAC5B,cAAc,EAAE,eAAe,CAAC;IAQhC,aAAa,CAAC,EAAE,sBAAsB,CAAC;IAGvC,yBAAyB,CAAC,EAAE,CAAC,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,KAAK,IAAI,CAAC;CAC1F;AAMD,wBAAgB,gBAAgB,CAAC,EAAE,OAAO,EAAE,QAAQ,EAAE,cAAc,EAAE,aAAa,EAAE,yBAAyB,EAAE,EAAE,qBAAqB,+BAQtI"}
@@ -1,6 +1,7 @@
1
- import { jsx, Fragment } from 'react/jsx-runtime';
1
+ import { jsx } from 'react/jsx-runtime';
2
2
  import { useMemo } from 'react';
3
3
  import { applyEffectiveConfiguration, renderElement } from '@cratis/scene.engine';
4
+ import { BindingOutputProvider } from './renderer/BindingOutputContext.js';
4
5
  import { createReactRenderer } from './renderer/createReactRenderer.js';
5
6
  import './interactions/useInteractions.js';
6
7
  import './interactions/NotificationHost.js';
@@ -8,7 +9,7 @@ import './interactions/NotificationHost.js';
8
9
  /**
9
10
  * Renders a Scene element tree with the real `Scene.React` renderer - the WYSIWYG building block Studio's
10
11
  * preview surface and Stage's shipped web bundle both consume unmodified.
11
- */ function SceneElementView({ element, registry, resolveBinding, configuration }) {
12
+ */ function SceneElementView({ element, registry, resolveBinding, configuration, onComponentOutputsChanged }) {
12
13
  const renderer = useMemo(()=>createReactRenderer(registry), [
13
14
  registry
14
15
  ]);
@@ -16,7 +17,8 @@ import './interactions/NotificationHost.js';
16
17
  element,
17
18
  configuration
18
19
  ]);
19
- return /*#__PURE__*/ jsx(Fragment, {
20
+ return /*#__PURE__*/ jsx(BindingOutputProvider, {
21
+ onOutputsChanged: onComponentOutputsChanged,
20
22
  children: renderElement(configured, renderer, resolveBinding)
21
23
  });
22
24
  }
@@ -1 +1 @@
1
- {"version":3,"file":"SceneElementView.js","sources":["../../SceneElementView.tsx"],"sourcesContent":["// Copyright (c) Cratis. All rights reserved.\n// Licensed under the MIT license. See LICENSE file in the project root for full license information.\n\nimport { useMemo } from 'react';\nimport { applyEffectiveConfiguration, renderElement, BindingResolver } from '@cratis/scene.engine';\nimport { EffectiveConfiguration, SceneElement } from '@cratis/scene.model';\nimport { ComponentRegistry, createReactRenderer } from './renderer';\n\nexport interface SceneElementViewProps {\n element: SceneElement;\n registry: ComponentRegistry;\n resolveBinding: BindingResolver;\n\n /**\n * The resolved configuration of the template chain the element sits in, from `resolveEffectiveConfiguration`.\n * When given, each configurable component renders with its resolved properties - what a screen's own values add\n * to an inherited template. It is the same data the editor shows, and the same code path whether the screen is\n * being edited or played: there is no design-time mode.\n */\n configuration?: EffectiveConfiguration;\n}\n\n/**\n * Renders a Scene element tree with the real `Scene.React` renderer - the WYSIWYG building block Studio's\n * preview surface and Stage's shipped web bundle both consume unmodified.\n */\nexport function SceneElementView({ element, registry, resolveBinding, configuration }: SceneElementViewProps) {\n const renderer = useMemo(() => createReactRenderer(registry), [registry]);\n const configured = useMemo(() => configuration ? applyEffectiveConfiguration(element, configuration) : element, [element, configuration]);\n return <>{renderElement(configured, renderer, resolveBinding)}</>;\n}\n"],"names":["SceneElementView","element","registry","resolveBinding","configuration","renderer","useMemo","createReactRenderer","configured","applyEffectiveConfiguration","_jsx","_Fragment","renderElement"],"mappings":";;;;;;;AAsBA;;;IAIO,SAASA,gBAAAA,CAAiB,EAAEC,OAAO,EAAEC,QAAQ,EAAEC,cAAc,EAAEC,aAAa,EAAyB,EAAA;AACxG,IAAA,MAAMC,QAAAA,GAAWC,OAAAA,CAAQ,IAAMC,mBAAAA,CAAoBL,QAAAA,CAAAA,EAAW;AAACA,QAAAA;AAAS,KAAA,CAAA;AACxE,IAAA,MAAMM,aAAaF,OAAAA,CAAQ,IAAMF,gBAAgBK,2BAAAA,CAA4BR,OAAAA,EAASG,iBAAiBH,OAAAA,EAAS;AAACA,QAAAA,OAAAA;AAASG,QAAAA;AAAc,KAAA,CAAA;IACxI,qBAAOM,GAAA,CAAAC,QAAA,EAAA;AAAGC,QAAAA,QAAAA,EAAAA,aAAAA,CAAcJ,YAAYH,QAAAA,EAAUF,cAAAA;;AAClD;;"}
1
+ {"version":3,"file":"SceneElementView.js","sources":["../../SceneElementView.tsx"],"sourcesContent":["// Copyright (c) Cratis. All rights reserved.\n// Licensed under the MIT license. See LICENSE file in the project root for full license information.\n\nimport { useMemo } from 'react';\nimport { applyEffectiveConfiguration, renderElement, BindingResolver } from '@cratis/scene.engine';\nimport { EffectiveConfiguration, SceneElement } from '@cratis/scene.model';\nimport { BindingOutputProvider, ComponentRegistry, createReactRenderer } from './renderer';\n\nexport interface SceneElementViewProps {\n element: SceneElement;\n registry: ComponentRegistry;\n resolveBinding: BindingResolver;\n\n /**\n * The resolved configuration of the template chain the element sits in, from `resolveEffectiveConfiguration`.\n * When given, each configurable component renders with its resolved properties - what a screen's own values add\n * to an inherited template. It is the same data the editor shows, and the same code path whether the screen is\n * being edited or played: there is no design-time mode.\n */\n configuration?: EffectiveConfiguration;\n\n /** Called when rendered components publish or clear output properties for typed bindings. */\n onComponentOutputsChanged?: (outputs: Record<string, Record<string, unknown>>) => void;\n}\n\n/**\n * Renders a Scene element tree with the real `Scene.React` renderer - the WYSIWYG building block Studio's\n * preview surface and Stage's shipped web bundle both consume unmodified.\n */\nexport function SceneElementView({ element, registry, resolveBinding, configuration, onComponentOutputsChanged }: SceneElementViewProps) {\n const renderer = useMemo(() => createReactRenderer(registry), [registry]);\n const configured = useMemo(() => configuration ? applyEffectiveConfiguration(element, configuration) : element, [element, configuration]);\n return (\n <BindingOutputProvider onOutputsChanged={onComponentOutputsChanged}>\n {renderElement(configured, renderer, resolveBinding)}\n </BindingOutputProvider>\n );\n}\n"],"names":["SceneElementView","element","registry","resolveBinding","configuration","onComponentOutputsChanged","renderer","useMemo","createReactRenderer","configured","applyEffectiveConfiguration","_jsx","BindingOutputProvider","onOutputsChanged","renderElement"],"mappings":";;;;;;;;AAyBA;;;AAGC,IACM,SAASA,gBAAAA,CAAiB,EAAEC,OAAO,EAAEC,QAAQ,EAAEC,cAAc,EAAEC,aAAa,EAAEC,yBAAyB,EAAyB,EAAA;AACnI,IAAA,MAAMC,QAAAA,GAAWC,OAAAA,CAAQ,IAAMC,mBAAAA,CAAoBN,QAAAA,CAAAA,EAAW;AAACA,QAAAA;AAAS,KAAA,CAAA;AACxE,IAAA,MAAMO,aAAaF,OAAAA,CAAQ,IAAMH,gBAAgBM,2BAAAA,CAA4BT,OAAAA,EAASG,iBAAiBH,OAAAA,EAAS;AAACA,QAAAA,OAAAA;AAASG,QAAAA;AAAc,KAAA,CAAA;AACxI,IAAA,qBACIO,GAAA,CAACC,qBAAAA,EAAAA;QAAsBC,gBAAAA,EAAkBR,yBAAAA;AACpCS,QAAAA,QAAAA,EAAAA,aAAAA,CAAcL,YAAYH,QAAAA,EAAUH,cAAAA;;AAGjD;;"}