@vertesia/fusion-ux 1.0.0-dev.20260128.144200

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 (91) hide show
  1. package/LICENSE +13 -0
  2. package/README.md +160 -0
  3. package/lib/esm/fusion-fragment/ChartRenderer.js +70 -0
  4. package/lib/esm/fusion-fragment/ChartRenderer.js.map +1 -0
  5. package/lib/esm/fusion-fragment/FieldRenderer.js +153 -0
  6. package/lib/esm/fusion-fragment/FieldRenderer.js.map +1 -0
  7. package/lib/esm/fusion-fragment/FusionFragmentContext.js +53 -0
  8. package/lib/esm/fusion-fragment/FusionFragmentContext.js.map +1 -0
  9. package/lib/esm/fusion-fragment/FusionFragmentHandler.js +233 -0
  10. package/lib/esm/fusion-fragment/FusionFragmentHandler.js.map +1 -0
  11. package/lib/esm/fusion-fragment/FusionFragmentRenderer.js +108 -0
  12. package/lib/esm/fusion-fragment/FusionFragmentRenderer.js.map +1 -0
  13. package/lib/esm/fusion-fragment/SectionRenderer.js +134 -0
  14. package/lib/esm/fusion-fragment/SectionRenderer.js.map +1 -0
  15. package/lib/esm/fusion-fragment/TableRenderer.js +137 -0
  16. package/lib/esm/fusion-fragment/TableRenderer.js.map +1 -0
  17. package/lib/esm/fusion-fragment/index.js +11 -0
  18. package/lib/esm/fusion-fragment/index.js.map +1 -0
  19. package/lib/esm/index.js +44 -0
  20. package/lib/esm/index.js.map +1 -0
  21. package/lib/esm/render/index.js +12 -0
  22. package/lib/esm/render/index.js.map +1 -0
  23. package/lib/esm/render/textPreview.js +194 -0
  24. package/lib/esm/render/textPreview.js.map +1 -0
  25. package/lib/esm/types.js +8 -0
  26. package/lib/esm/types.js.map +1 -0
  27. package/lib/esm/validation/formatErrors.js +105 -0
  28. package/lib/esm/validation/formatErrors.js.map +1 -0
  29. package/lib/esm/validation/fuzzyMatch.js +87 -0
  30. package/lib/esm/validation/fuzzyMatch.js.map +1 -0
  31. package/lib/esm/validation/index.js +8 -0
  32. package/lib/esm/validation/index.js.map +1 -0
  33. package/lib/esm/validation/schemas.js +166 -0
  34. package/lib/esm/validation/schemas.js.map +1 -0
  35. package/lib/esm/validation/validateTemplate.js +247 -0
  36. package/lib/esm/validation/validateTemplate.js.map +1 -0
  37. package/lib/tsconfig.tsbuildinfo +1 -0
  38. package/lib/types/fusion-fragment/ChartRenderer.d.ts +23 -0
  39. package/lib/types/fusion-fragment/ChartRenderer.d.ts.map +1 -0
  40. package/lib/types/fusion-fragment/FieldRenderer.d.ts +12 -0
  41. package/lib/types/fusion-fragment/FieldRenderer.d.ts.map +1 -0
  42. package/lib/types/fusion-fragment/FusionFragmentContext.d.ts +48 -0
  43. package/lib/types/fusion-fragment/FusionFragmentContext.d.ts.map +1 -0
  44. package/lib/types/fusion-fragment/FusionFragmentHandler.d.ts +38 -0
  45. package/lib/types/fusion-fragment/FusionFragmentHandler.d.ts.map +1 -0
  46. package/lib/types/fusion-fragment/FusionFragmentRenderer.d.ts +32 -0
  47. package/lib/types/fusion-fragment/FusionFragmentRenderer.d.ts.map +1 -0
  48. package/lib/types/fusion-fragment/SectionRenderer.d.ts +12 -0
  49. package/lib/types/fusion-fragment/SectionRenderer.d.ts.map +1 -0
  50. package/lib/types/fusion-fragment/TableRenderer.d.ts +15 -0
  51. package/lib/types/fusion-fragment/TableRenderer.d.ts.map +1 -0
  52. package/lib/types/fusion-fragment/index.d.ts +11 -0
  53. package/lib/types/fusion-fragment/index.d.ts.map +1 -0
  54. package/lib/types/index.d.ts +42 -0
  55. package/lib/types/index.d.ts.map +1 -0
  56. package/lib/types/render/index.d.ts +12 -0
  57. package/lib/types/render/index.d.ts.map +1 -0
  58. package/lib/types/render/textPreview.d.ts +20 -0
  59. package/lib/types/render/textPreview.d.ts.map +1 -0
  60. package/lib/types/types.d.ts +262 -0
  61. package/lib/types/types.d.ts.map +1 -0
  62. package/lib/types/validation/formatErrors.d.ts +35 -0
  63. package/lib/types/validation/formatErrors.d.ts.map +1 -0
  64. package/lib/types/validation/fuzzyMatch.d.ts +25 -0
  65. package/lib/types/validation/fuzzyMatch.d.ts.map +1 -0
  66. package/lib/types/validation/index.d.ts +8 -0
  67. package/lib/types/validation/index.d.ts.map +1 -0
  68. package/lib/types/validation/schemas.d.ts +67 -0
  69. package/lib/types/validation/schemas.d.ts.map +1 -0
  70. package/lib/types/validation/validateTemplate.d.ts +22 -0
  71. package/lib/types/validation/validateTemplate.d.ts.map +1 -0
  72. package/lib/vertesia-fusion-ux.js +2 -0
  73. package/lib/vertesia-fusion-ux.js.map +1 -0
  74. package/package.json +68 -0
  75. package/src/fusion-fragment/ChartRenderer.tsx +136 -0
  76. package/src/fusion-fragment/FieldRenderer.tsx +199 -0
  77. package/src/fusion-fragment/FusionFragmentContext.tsx +92 -0
  78. package/src/fusion-fragment/FusionFragmentHandler.tsx +313 -0
  79. package/src/fusion-fragment/FusionFragmentRenderer.tsx +156 -0
  80. package/src/fusion-fragment/SectionRenderer.tsx +196 -0
  81. package/src/fusion-fragment/TableRenderer.tsx +204 -0
  82. package/src/fusion-fragment/index.ts +20 -0
  83. package/src/index.ts +89 -0
  84. package/src/render/index.ts +16 -0
  85. package/src/render/textPreview.ts +231 -0
  86. package/src/types.ts +278 -0
  87. package/src/validation/formatErrors.ts +128 -0
  88. package/src/validation/fuzzyMatch.ts +109 -0
  89. package/src/validation/index.ts +8 -0
  90. package/src/validation/schemas.ts +175 -0
  91. package/src/validation/validateTemplate.ts +282 -0
package/LICENSE ADDED
@@ -0,0 +1,13 @@
1
+ Copyright 2024 Composable
2
+
3
+ Licensed under the Apache License, Version 2.0 (the "License");
4
+ you may not use this file except in compliance with the License.
5
+ You may obtain a copy of the License at
6
+
7
+ http://www.apache.org/licenses/LICENSE-2.0
8
+
9
+ Unless required by applicable law or agreed to in writing, software
10
+ distributed under the License is distributed on an "AS IS" BASIS,
11
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ See the License for the specific language governing permissions and
13
+ limitations under the License.
package/README.md ADDED
@@ -0,0 +1,160 @@
1
+ # @vertesia/fusion-ux
2
+
3
+ Dynamic model-generated UI components for Vertesia. Models generate templates (structure), the system provides values (data).
4
+
5
+ ## Installation
6
+
7
+ ```bash
8
+ pnpm add @vertesia/fusion-ux
9
+ ```
10
+
11
+ ## Quick Start
12
+
13
+ ### Client-side (React)
14
+
15
+ ```tsx
16
+ import {
17
+ FusionFragmentRenderer,
18
+ FusionFragmentProvider,
19
+ FusionFragmentHandler,
20
+ } from '@vertesia/fusion-ux';
21
+
22
+ // Option 1: Direct rendering with template and data
23
+ <FusionFragmentRenderer
24
+ template={{
25
+ title: "Fund Parameters",
26
+ sections: [{
27
+ title: "Identity",
28
+ layout: "grid-3",
29
+ fields: [
30
+ { label: "Firm Name", key: "firmName" },
31
+ { label: "Vintage", key: "vintageYear", format: "number" }
32
+ ]
33
+ }]
34
+ }}
35
+ data={{ firmName: "Acme Capital", vintageYear: 2024 }}
36
+ onUpdate={async (key, value) => {
37
+ // Handle field updates
38
+ }}
39
+ />
40
+
41
+ // Option 2: Context-based rendering (for markdown code blocks)
42
+ <FusionFragmentProvider data={fund.parameters} onUpdate={handleUpdate}>
43
+ <MarkdownRenderer content={agentResponse} />
44
+ </FusionFragmentProvider>
45
+
46
+ // Option 3: Code block handler for markdown renderers
47
+ const codeBlockRenderers = {
48
+ 'fusion-fragment': ({ code }) => <FusionFragmentHandler code={code} />
49
+ };
50
+ ```
51
+
52
+ ### Server-side (Tools)
53
+
54
+ ```typescript
55
+ import { fusionUxTools } from '@vertesia/fusion-ux/server';
56
+
57
+ // Register tools with your server
58
+ server.registerCollection(fusionUxTools);
59
+ ```
60
+
61
+ ## Template Structure
62
+
63
+ ```typescript
64
+ interface FragmentTemplate {
65
+ title?: string;
66
+ entityType?: 'fund' | 'scenario' | 'portfolio' | 'transaction' | 'custom';
67
+ sections: SectionTemplate[];
68
+ footer?: string;
69
+ }
70
+
71
+ interface SectionTemplate {
72
+ title: string;
73
+ layout?: 'grid-2' | 'grid-3' | 'grid-4' | 'list';
74
+ collapsed?: boolean;
75
+ fields: FieldTemplate[];
76
+ }
77
+
78
+ interface FieldTemplate {
79
+ label: string; // Display label
80
+ key: string; // Data key (required)
81
+ format?: 'text' | 'number' | 'currency' | 'percent' | 'date' | 'boolean';
82
+ unit?: string; // e.g., "years", "USD"
83
+ editable?: boolean;
84
+ highlight?: 'success' | 'warning' | 'error' | 'info';
85
+ tooltip?: string;
86
+ decimals?: number; // For number/currency/percent
87
+ currency?: string; // For currency format
88
+ }
89
+ ```
90
+
91
+ ## Validation Tool
92
+
93
+ The `validate_fusion_fragment` tool allows models to validate templates:
94
+
95
+ ```json
96
+ {
97
+ "template": {
98
+ "sections": [{
99
+ "title": "Identity",
100
+ "fields": [{ "label": "Firm", "key": "firmName" }]
101
+ }]
102
+ },
103
+ "dataKeys": ["firmName", "fundName", "vintageYear"],
104
+ "preview": "text"
105
+ }
106
+ ```
107
+
108
+ Returns errors with suggestions or a text preview of the template.
109
+
110
+ ## API
111
+
112
+ ### Components
113
+
114
+ - `FusionFragmentRenderer` - Main renderer component
115
+ - `FusionFragmentProvider` - Context provider for data
116
+ - `FusionFragmentHandler` - Code block handler
117
+ - `SectionRenderer` - Section renderer
118
+ - `FieldRenderer` - Field renderer
119
+
120
+ ### Validation
121
+
122
+ - `validateTemplate(template, dataKeys)` - Validate a template
123
+ - `parseAndValidateTemplate(jsonString, dataKeys)` - Parse and validate
124
+ - `findClosestKey(input, validKeys)` - Fuzzy key matching
125
+ - `formatValidationErrors(errors)` - Format errors for models
126
+
127
+ ### Server
128
+
129
+ - `fusionUxTools` - Tool collection for registration
130
+ - `ValidateFusionFragmentTool` - The validation tool
131
+
132
+ ### Serverless Rendering
133
+
134
+ Render templates to PNG without a browser using `@napi-rs/canvas`:
135
+
136
+ ```typescript
137
+ import { renderToBuffer, renderToBase64, renderToDataUrl } from '@vertesia/fusion-ux/server';
138
+
139
+ // Render to PNG buffer
140
+ const buffer = renderToBuffer(template, data);
141
+ fs.writeFileSync('preview.png', buffer);
142
+
143
+ // Render to base64 string
144
+ const base64 = renderToBase64(template, data);
145
+
146
+ // Render to data URL
147
+ const dataUrl = renderToDataUrl(template, data);
148
+ // Returns: "data:image/png;base64,..."
149
+
150
+ // With custom options
151
+ const buffer = renderToBuffer(template, data, {
152
+ width: 800, // Canvas width (default: 600)
153
+ padding: 24, // Padding around content (default: 20)
154
+ fieldHeight: 60, // Height per field row (default: 50)
155
+ });
156
+ ```
157
+
158
+ ## License
159
+
160
+ Apache-2.0
@@ -0,0 +1,70 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { useFusionFragmentContextSafe } from './FusionFragmentContext.js';
3
+ /**
4
+ * Renders a Vega-Lite chart from a chart template.
5
+ * If dataKey is provided, it merges data from context into the spec.
6
+ * Uses the ChartComponent from FusionFragmentContext if available.
7
+ */
8
+ export function ChartRenderer({ chart, data, className }) {
9
+ const context = useFusionFragmentContextSafe();
10
+ const ChartComponent = context?.ChartComponent;
11
+ const artifactRunId = context?.artifactRunId;
12
+ // Debug logging
13
+ console.log('[ChartRenderer] Context:', {
14
+ hasContext: !!context,
15
+ hasChartComponent: !!ChartComponent,
16
+ artifactRunId,
17
+ chartTitle: chart.title,
18
+ dataKey: chart.dataKey,
19
+ });
20
+ // Resolve data from context if dataKey is provided
21
+ const resolvedSpec = { ...chart.spec };
22
+ if (chart.dataKey && data[chart.dataKey]) {
23
+ const chartData = data[chart.dataKey];
24
+ if (Array.isArray(chartData)) {
25
+ // Inject data into spec
26
+ resolvedSpec.data = { values: chartData };
27
+ }
28
+ }
29
+ // Build the VegaLiteChartSpec format expected by @vertesia/ui
30
+ const vegaSpec = {
31
+ library: 'vega-lite',
32
+ title: chart.title,
33
+ description: chart.description,
34
+ spec: resolvedSpec,
35
+ options: {
36
+ height: chart.height,
37
+ }
38
+ };
39
+ // If a ChartComponent is provided via context, use it to render the actual chart
40
+ if (ChartComponent) {
41
+ return (_jsx("div", { className: className, children: _jsx(ChartComponent, { spec: vegaSpec, artifactRunId: artifactRunId }) }));
42
+ }
43
+ // Fallback: render a placeholder with spec info when no ChartComponent is injected
44
+ return (_jsxs("div", { className: className, style: {
45
+ padding: '16px',
46
+ backgroundColor: 'var(--gray-2, #f9fafb)',
47
+ border: '1px solid var(--gray-5, #e5e7eb)',
48
+ borderRadius: '8px',
49
+ minHeight: chart.height || 280
50
+ }, children: [chart.title && (_jsx("div", { style: {
51
+ fontSize: '14px',
52
+ fontWeight: 600,
53
+ marginBottom: '8px',
54
+ color: 'var(--gray-12, #111827)'
55
+ }, children: chart.title })), chart.description && (_jsx("div", { style: {
56
+ fontSize: '12px',
57
+ color: 'var(--gray-11, #6b7280)',
58
+ marginBottom: '12px'
59
+ }, children: chart.description })), _jsx("div", { style: {
60
+ display: 'flex',
61
+ alignItems: 'center',
62
+ justifyContent: 'center',
63
+ height: (chart.height || 280) - 60,
64
+ backgroundColor: 'var(--gray-3, #f3f4f6)',
65
+ borderRadius: '4px',
66
+ color: 'var(--gray-11, #6b7280)',
67
+ fontSize: '12px'
68
+ }, "data-vega-spec": JSON.stringify(vegaSpec), children: _jsxs("div", { style: { textAlign: 'center' }, children: [_jsxs("div", { style: { marginBottom: '4px' }, children: ["Chart: ", resolvedSpec.mark ? String(typeof resolvedSpec.mark === 'string' ? resolvedSpec.mark : resolvedSpec.mark.type) : 'composite'] }), resolvedSpec.data?.values && (_jsxs("div", { style: { fontSize: '11px', opacity: 0.8 }, children: [resolvedSpec.data.values.length, " data points"] }))] }) })] }));
69
+ }
70
+ //# sourceMappingURL=ChartRenderer.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ChartRenderer.js","sourceRoot":"","sources":["../../../src/fusion-fragment/ChartRenderer.tsx"],"names":[],"mappings":"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"}
@@ -0,0 +1,153 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ /**
3
+ * FieldRenderer component
4
+ * Renders a single field with formatting and optional edit capability
5
+ */
6
+ import { useMemo, useState, useCallback } from 'react';
7
+ // Styles as constants
8
+ const styles = {
9
+ container: {
10
+ display: 'flex',
11
+ flexDirection: 'column',
12
+ gap: '2px',
13
+ minWidth: 0, // Allow text truncation
14
+ },
15
+ label: {
16
+ fontSize: '11px',
17
+ fontWeight: 500,
18
+ color: 'var(--gray-11, #6b7280)',
19
+ textTransform: 'uppercase',
20
+ letterSpacing: '0.5px',
21
+ },
22
+ value: {
23
+ fontSize: '14px',
24
+ fontWeight: 500,
25
+ color: 'var(--gray-12, #1f2937)',
26
+ fontFamily: 'var(--font-mono, ui-monospace, monospace)',
27
+ fontVariantNumeric: 'tabular-nums',
28
+ letterSpacing: '-0.02em',
29
+ },
30
+ unit: {
31
+ fontSize: '12px',
32
+ color: 'var(--gray-10, #9ca3af)',
33
+ marginLeft: '4px',
34
+ },
35
+ highlight: {
36
+ success: { color: 'var(--green-11, #15803d)' },
37
+ warning: { color: 'var(--yellow-11, #ca8a04)' },
38
+ error: { color: 'var(--red-11, #dc2626)' },
39
+ info: { color: 'var(--blue-11, #2563eb)' },
40
+ },
41
+ editable: {
42
+ cursor: 'pointer',
43
+ padding: '2px 4px',
44
+ borderRadius: '4px',
45
+ transition: 'background-color 0.15s',
46
+ },
47
+ tooltip: {
48
+ position: 'relative',
49
+ },
50
+ nullValue: {
51
+ color: 'var(--gray-9, #9ca3af)',
52
+ fontStyle: 'italic',
53
+ },
54
+ };
55
+ /**
56
+ * Format a value according to the field's format specification
57
+ */
58
+ function formatValue(value, field) {
59
+ if (value === null || value === undefined) {
60
+ return '\u2014'; // em-dash for null/undefined
61
+ }
62
+ switch (field.format) {
63
+ case 'number': {
64
+ const num = typeof value === 'number' ? value : parseFloat(String(value));
65
+ if (isNaN(num))
66
+ return String(value);
67
+ const options = {
68
+ minimumFractionDigits: field.decimals ?? 0,
69
+ maximumFractionDigits: field.decimals ?? 2,
70
+ };
71
+ return new Intl.NumberFormat('en-US', options).format(num);
72
+ }
73
+ case 'currency': {
74
+ const num = typeof value === 'number' ? value : parseFloat(String(value));
75
+ if (isNaN(num))
76
+ return String(value);
77
+ const options = {
78
+ style: 'currency',
79
+ currency: field.currency || 'USD',
80
+ minimumFractionDigits: field.decimals ?? 0,
81
+ maximumFractionDigits: field.decimals ?? 0,
82
+ };
83
+ return new Intl.NumberFormat('en-US', options).format(num);
84
+ }
85
+ case 'percent': {
86
+ const num = typeof value === 'number' ? value : parseFloat(String(value));
87
+ if (isNaN(num))
88
+ return String(value);
89
+ // Assume value is already a percentage (e.g., 25 for 25%)
90
+ // If it's a decimal (e.g., 0.25), multiply by 100
91
+ const pct = num < 1 && num > -1 && num !== 0 ? num * 100 : num;
92
+ const decimals = field.decimals ?? 1;
93
+ return `${pct.toFixed(decimals)}%`;
94
+ }
95
+ case 'date': {
96
+ if (!value)
97
+ return '\u2014';
98
+ const date = value instanceof Date ? value : new Date(String(value));
99
+ if (isNaN(date.getTime()))
100
+ return String(value);
101
+ return new Intl.DateTimeFormat('en-US', {
102
+ year: 'numeric',
103
+ month: 'short',
104
+ day: 'numeric',
105
+ }).format(date);
106
+ }
107
+ case 'boolean': {
108
+ const bool = typeof value === 'boolean' ? value : value === 'true' || value === '1';
109
+ return bool ? 'Yes' : 'No';
110
+ }
111
+ case 'text':
112
+ default:
113
+ return String(value);
114
+ }
115
+ }
116
+ /**
117
+ * FieldRenderer component
118
+ * Displays a field with label, formatted value, and optional highlighting
119
+ */
120
+ export function FieldRenderer({ field, value, onUpdate, agentMode, }) {
121
+ const [isHovered, setIsHovered] = useState(false);
122
+ const formattedValue = useMemo(() => formatValue(value, field), [value, field]);
123
+ const isNull = value === null || value === undefined;
124
+ const isEditable = field.editable && (onUpdate || agentMode);
125
+ const handleClick = useCallback(() => {
126
+ if (!isEditable)
127
+ return;
128
+ if (agentMode?.enabled && agentMode.sendMessage) {
129
+ // Send message to agent for editing
130
+ agentMode.sendMessage(`Please help me update the "${field.label}" field (key: ${field.key}). Current value: ${formattedValue}`);
131
+ }
132
+ // Direct edit mode would go here (Phase 2)
133
+ }, [isEditable, agentMode, field, formattedValue]);
134
+ const valueStyle = useMemo(() => {
135
+ const base = { ...styles.value };
136
+ if (isNull) {
137
+ return { ...base, ...styles.nullValue };
138
+ }
139
+ if (field.highlight) {
140
+ return { ...base, ...styles.highlight[field.highlight] };
141
+ }
142
+ if (isEditable) {
143
+ return {
144
+ ...base,
145
+ ...styles.editable,
146
+ backgroundColor: isHovered ? 'var(--gray-3, #f3f4f6)' : 'transparent',
147
+ };
148
+ }
149
+ return base;
150
+ }, [isNull, field.highlight, isEditable, isHovered]);
151
+ return (_jsxs("div", { style: styles.container, title: field.tooltip, onMouseEnter: () => setIsHovered(true), onMouseLeave: () => setIsHovered(false), onClick: handleClick, role: isEditable ? 'button' : undefined, tabIndex: isEditable ? 0 : undefined, children: [_jsx("span", { style: styles.label, children: field.label }), _jsxs("span", { style: valueStyle, children: [formattedValue, field.unit && !isNull && (_jsx("span", { style: styles.unit, children: field.unit }))] })] }));
152
+ }
153
+ //# sourceMappingURL=FieldRenderer.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"FieldRenderer.js","sourceRoot":"","sources":["../../../src/fusion-fragment/FieldRenderer.tsx"],"names":[],"mappings":";AAAA;;;GAGG;AAEH,OAAO,EAAE,OAAO,EAAE,QAAQ,EAAE,WAAW,EAAqB,MAAM,OAAO,CAAC;AAG1E,sBAAsB;AACtB,MAAM,MAAM,GAAG;IACb,SAAS,EAAE;QACT,OAAO,EAAE,MAAM;QACf,aAAa,EAAE,QAAiB;QAChC,GAAG,EAAE,KAAK;QACV,QAAQ,EAAE,CAAC,EAAE,wBAAwB;KACtC;IACD,KAAK,EAAE;QACL,QAAQ,EAAE,MAAM;QAChB,UAAU,EAAE,GAAG;QACf,KAAK,EAAE,yBAAyB;QAChC,aAAa,EAAE,WAAoB;QACnC,aAAa,EAAE,OAAO;KACvB;IACD,KAAK,EAAE;QACL,QAAQ,EAAE,MAAM;QAChB,UAAU,EAAE,GAAG;QACf,KAAK,EAAE,yBAAyB;QAChC,UAAU,EAAE,2CAA2C;QACvD,kBAAkB,EAAE,cAAuB;QAC3C,aAAa,EAAE,SAAS;KACzB;IACD,IAAI,EAAE;QACJ,QAAQ,EAAE,MAAM;QAChB,KAAK,EAAE,yBAAyB;QAChC,UAAU,EAAE,KAAK;KAClB;IACD,SAAS,EAAE;QACT,OAAO,EAAE,EAAE,KAAK,EAAE,0BAA0B,EAAE;QAC9C,OAAO,EAAE,EAAE,KAAK,EAAE,2BAA2B,EAAE;QAC/C,KAAK,EAAE,EAAE,KAAK,EAAE,wBAAwB,EAAE;QAC1C,IAAI,EAAE,EAAE,KAAK,EAAE,yBAAyB,EAAE;KAC3C;IACD,QAAQ,EAAE;QACR,MAAM,EAAE,SAAS;QACjB,OAAO,EAAE,SAAS;QAClB,YAAY,EAAE,KAAK;QACnB,UAAU,EAAE,wBAAwB;KACrC;IACD,OAAO,EAAE;QACP,QAAQ,EAAE,UAAmB;KAC9B;IACD,SAAS,EAAE;QACT,KAAK,EAAE,wBAAwB;QAC/B,SAAS,EAAE,QAAiB;KAC7B;CACF,CAAC;AAEF;;GAEG;AACH,SAAS,WAAW,CAAC,KAAc,EAAE,KAAoB;IACvD,IAAI,KAAK,KAAK,IAAI,IAAI,KAAK,KAAK,SAAS,EAAE,CAAC;QAC1C,OAAO,QAAQ,CAAC,CAAC,6BAA6B;IAChD,CAAC;IAED,QAAQ,KAAK,CAAC,MAAM,EAAE,CAAC;QACrB,KAAK,QAAQ,CAAC,CAAC,CAAC;YACd,MAAM,GAAG,GAAG,OAAO,KAAK,KAAK,QAAQ,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,UAAU,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC;YAC1E,IAAI,KAAK,CAAC,GAAG,CAAC;gBAAE,OAAO,MAAM,CAAC,KAAK,CAAC,CAAC;YAErC,MAAM,OAAO,GAA6B;gBACxC,qBAAqB,EAAE,KAAK,CAAC,QAAQ,IAAI,CAAC;gBAC1C,qBAAqB,EAAE,KAAK,CAAC,QAAQ,IAAI,CAAC;aAC3C,CAAC;YACF,OAAO,IAAI,IAAI,CAAC,YAAY,CAAC,OAAO,EAAE,OAAO,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;QAC7D,CAAC;QAED,KAAK,UAAU,CAAC,CAAC,CAAC;YAChB,MAAM,GAAG,GAAG,OAAO,KAAK,KAAK,QAAQ,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,UAAU,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC;YAC1E,IAAI,KAAK,CAAC,GAAG,CAAC;gBAAE,OAAO,MAAM,CAAC,KAAK,CAAC,CAAC;YAErC,MAAM,OAAO,GAA6B;gBACxC,KAAK,EAAE,UAAU;gBACjB,QAAQ,EAAE,KAAK,CAAC,QAAQ,IAAI,KAAK;gBACjC,qBAAqB,EAAE,KAAK,CAAC,QAAQ,IAAI,CAAC;gBAC1C,qBAAqB,EAAE,KAAK,CAAC,QAAQ,IAAI,CAAC;aAC3C,CAAC;YACF,OAAO,IAAI,IAAI,CAAC,YAAY,CAAC,OAAO,EAAE,OAAO,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;QAC7D,CAAC;QAED,KAAK,SAAS,CAAC,CAAC,CAAC;YACf,MAAM,GAAG,GAAG,OAAO,KAAK,KAAK,QAAQ,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,UAAU,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC;YAC1E,IAAI,KAAK,CAAC,GAAG,CAAC;gBAAE,OAAO,MAAM,CAAC,KAAK,CAAC,CAAC;YAErC,0DAA0D;YAC1D,kDAAkD;YAClD,MAAM,GAAG,GAAG,GAAG,GAAG,CAAC,IAAI,GAAG,GAAG,CAAC,CAAC,IAAI,GAAG,KAAK,CAAC,CAAC,CAAC,CAAC,GAAG,GAAG,GAAG,CAAC,CAAC,CAAC,GAAG,CAAC;YAC/D,MAAM,QAAQ,GAAG,KAAK,CAAC,QAAQ,IAAI,CAAC,CAAC;YACrC,OAAO,GAAG,GAAG,CAAC,OAAO,CAAC,QAAQ,CAAC,GAAG,CAAC;QACrC,CAAC;QAED,KAAK,MAAM,CAAC,CAAC,CAAC;YACZ,IAAI,CAAC,KAAK;gBAAE,OAAO,QAAQ,CAAC;YAE5B,MAAM,IAAI,GAAG,KAAK,YAAY,IAAI,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,IAAI,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC;YACrE,IAAI,KAAK,CAAC,IAAI,CAAC,OAAO,EAAE,CAAC;gBAAE,OAAO,MAAM,CAAC,KAAK,CAAC,CAAC;YAEhD,OAAO,IAAI,IAAI,CAAC,cAAc,CAAC,OAAO,EAAE;gBACtC,IAAI,EAAE,SAAS;gBACf,KAAK,EAAE,OAAO;gBACd,GAAG,EAAE,SAAS;aACf,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC;QAClB,CAAC;QAED,KAAK,SAAS,CAAC,CAAC,CAAC;YACf,MAAM,IAAI,GAAG,OAAO,KAAK,KAAK,SAAS,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,KAAK,KAAK,MAAM,IAAI,KAAK,KAAK,GAAG,CAAC;YACpF,OAAO,IAAI,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,IAAI,CAAC;QAC7B,CAAC;QAED,KAAK,MAAM,CAAC;QACZ;YACE,OAAO,MAAM,CAAC,KAAK,CAAC,CAAC;IACzB,CAAC;AACH,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,aAAa,CAAC,EAC5B,KAAK,EACL,KAAK,EACL,QAAQ,EACR,SAAS,GACU;IACnB,MAAM,CAAC,SAAS,EAAE,YAAY,CAAC,GAAG,QAAQ,CAAC,KAAK,CAAC,CAAC;IAElD,MAAM,cAAc,GAAG,OAAO,CAC5B,GAAG,EAAE,CAAC,WAAW,CAAC,KAAK,EAAE,KAAK,CAAC,EAC/B,CAAC,KAAK,EAAE,KAAK,CAAC,CACf,CAAC;IAEF,MAAM,MAAM,GAAG,KAAK,KAAK,IAAI,IAAI,KAAK,KAAK,SAAS,CAAC;IACrD,MAAM,UAAU,GAAG,KAAK,CAAC,QAAQ,IAAI,CAAC,QAAQ,IAAI,SAAS,CAAC,CAAC;IAE7D,MAAM,WAAW,GAAG,WAAW,CAAC,GAAG,EAAE;QACnC,IAAI,CAAC,UAAU;YAAE,OAAO;QAExB,IAAI,SAAS,EAAE,OAAO,IAAI,SAAS,CAAC,WAAW,EAAE,CAAC;YAChD,oCAAoC;YACpC,SAAS,CAAC,WAAW,CACnB,8BAA8B,KAAK,CAAC,KAAK,iBAAiB,KAAK,CAAC,GAAG,qBAAqB,cAAc,EAAE,CACzG,CAAC;QACJ,CAAC;QACD,2CAA2C;IAC7C,CAAC,EAAE,CAAC,UAAU,EAAE,SAAS,EAAE,KAAK,EAAE,cAAc,CAAC,CAAC,CAAC;IAEnD,MAAM,UAAU,GAAG,OAAO,CAAC,GAAG,EAAE;QAC9B,MAAM,IAAI,GAAG,EAAE,GAAG,MAAM,CAAC,KAAK,EAAE,CAAC;QAEjC,IAAI,MAAM,EAAE,CAAC;YACX,OAAO,EAAE,GAAG,IAAI,EAAE,GAAG,MAAM,CAAC,SAAS,EAAE,CAAC;QAC1C,CAAC;QAED,IAAI,KAAK,CAAC,SAAS,EAAE,CAAC;YACpB,OAAO,EAAE,GAAG,IAAI,EAAE,GAAG,MAAM,CAAC,SAAS,CAAC,KAAK,CAAC,SAAS,CAAC,EAAE,CAAC;QAC3D,CAAC;QAED,IAAI,UAAU,EAAE,CAAC;YACf,OAAO;gBACL,GAAG,IAAI;gBACP,GAAG,MAAM,CAAC,QAAQ;gBAClB,eAAe,EAAE,SAAS,CAAC,CAAC,CAAC,wBAAwB,CAAC,CAAC,CAAC,aAAa;aACtE,CAAC;QACJ,CAAC;QAED,OAAO,IAAI,CAAC;IACd,CAAC,EAAE,CAAC,MAAM,EAAE,KAAK,CAAC,SAAS,EAAE,UAAU,EAAE,SAAS,CAAC,CAAC,CAAC;IAErD,OAAO,CACL,eACE,KAAK,EAAE,MAAM,CAAC,SAAS,EACvB,KAAK,EAAE,KAAK,CAAC,OAAO,EACpB,YAAY,EAAE,GAAG,EAAE,CAAC,YAAY,CAAC,IAAI,CAAC,EACtC,YAAY,EAAE,GAAG,EAAE,CAAC,YAAY,CAAC,KAAK,CAAC,EACvC,OAAO,EAAE,WAAW,EACpB,IAAI,EAAE,UAAU,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,SAAS,EACvC,QAAQ,EAAE,UAAU,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,SAAS,aAEpC,eAAM,KAAK,EAAE,MAAM,CAAC,KAAK,YAAG,KAAK,CAAC,KAAK,GAAQ,EAC/C,gBAAM,KAAK,EAAE,UAAU,aACpB,cAAc,EACd,KAAK,CAAC,IAAI,IAAI,CAAC,MAAM,IAAI,CACxB,eAAM,KAAK,EAAE,MAAM,CAAC,IAAI,YAAG,KAAK,CAAC,IAAI,GAAQ,CAC9C,IACI,IACH,CACP,CAAC;AACJ,CAAC"}
@@ -0,0 +1,53 @@
1
+ import { jsx as _jsx } from "react/jsx-runtime";
2
+ /**
3
+ * Context provider for FusionFragment components
4
+ * Provides data and update handlers to nested components
5
+ */
6
+ import { createContext, useContext, useMemo } from 'react';
7
+ const FusionFragmentContext = createContext(null);
8
+ /**
9
+ * Provider component that supplies data and update handlers
10
+ * to FusionFragment components via context
11
+ *
12
+ * @example
13
+ * ```tsx
14
+ * <FusionFragmentProvider
15
+ * data={fund.parameters}
16
+ * onUpdate={async (key, value) => {
17
+ * await api.funds.updateParameters(fundId, { [key]: value });
18
+ * }}
19
+ * >
20
+ * <MarkdownRenderer content={agentResponse} />
21
+ * </FusionFragmentProvider>
22
+ * ```
23
+ */
24
+ export function FusionFragmentProvider({ data, onUpdate, sendMessage, ChartComponent, artifactRunId, children }) {
25
+ const value = useMemo(() => ({ data, onUpdate, sendMessage, ChartComponent, artifactRunId }), [data, onUpdate, sendMessage, ChartComponent, artifactRunId]);
26
+ // Debug logging
27
+ console.log('[FusionFragmentProvider] Created with:', {
28
+ hasData: !!data,
29
+ dataKeys: data ? Object.keys(data) : [],
30
+ hasChartComponent: !!ChartComponent,
31
+ artifactRunId,
32
+ });
33
+ return (_jsx(FusionFragmentContext.Provider, { value: value, children: children }));
34
+ }
35
+ /**
36
+ * Hook to access FusionFragment context
37
+ * @throws Error if used outside of FusionFragmentProvider
38
+ */
39
+ export function useFusionFragmentContext() {
40
+ const context = useContext(FusionFragmentContext);
41
+ if (!context) {
42
+ throw new Error('useFusionFragmentContext must be used within a FusionFragmentProvider');
43
+ }
44
+ return context;
45
+ }
46
+ /**
47
+ * Hook to safely access FusionFragment context
48
+ * Returns null if not within a provider (useful for optional context)
49
+ */
50
+ export function useFusionFragmentContextSafe() {
51
+ return useContext(FusionFragmentContext);
52
+ }
53
+ //# sourceMappingURL=FusionFragmentContext.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"FusionFragmentContext.js","sourceRoot":"","sources":["../../../src/fusion-fragment/FusionFragmentContext.tsx"],"names":[],"mappings":";AAAA;;;GAGG;AAEH,OAAO,EAAE,aAAa,EAAE,UAAU,EAAE,OAAO,EAAqC,MAAM,OAAO,CAAC;AAG9F,MAAM,qBAAqB,GAAG,aAAa,CAAoC,IAAI,CAAC,CAAC;AAiBrF;;;;;;;;;;;;;;;GAeG;AACH,MAAM,UAAU,sBAAsB,CAAC,EACrC,IAAI,EACJ,QAAQ,EACR,WAAW,EACX,cAAc,EACd,aAAa,EACb,QAAQ,EACoB;IAC5B,MAAM,KAAK,GAAG,OAAO,CACnB,GAAG,EAAE,CAAC,CAAC,EAAE,IAAI,EAAE,QAAQ,EAAE,WAAW,EAAE,cAAc,EAAE,aAAa,EAAE,CAAC,EACtE,CAAC,IAAI,EAAE,QAAQ,EAAE,WAAW,EAAE,cAAc,EAAE,aAAa,CAAC,CAC7D,CAAC;IAEF,gBAAgB;IAChB,OAAO,CAAC,GAAG,CAAC,wCAAwC,EAAE;QACpD,OAAO,EAAE,CAAC,CAAC,IAAI;QACf,QAAQ,EAAE,IAAI,CAAC,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,EAAE;QACvC,iBAAiB,EAAE,CAAC,CAAC,cAAc;QACnC,aAAa;KACd,CAAC,CAAC;IAEH,OAAO,CACL,KAAC,qBAAqB,CAAC,QAAQ,IAAC,KAAK,EAAE,KAAK,YACzC,QAAQ,GACsB,CAClC,CAAC;AACJ,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,wBAAwB;IACtC,MAAM,OAAO,GAAG,UAAU,CAAC,qBAAqB,CAAC,CAAC;IAElD,IAAI,CAAC,OAAO,EAAE,CAAC;QACb,MAAM,IAAI,KAAK,CACb,uEAAuE,CACxE,CAAC;IACJ,CAAC;IAED,OAAO,OAAO,CAAC;AACjB,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,4BAA4B;IAC1C,OAAO,UAAU,CAAC,qBAAqB,CAAC,CAAC;AAC3C,CAAC"}