@seed-ship/mcp-ui-solid 1.1.0 → 1.2.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (64) hide show
  1. package/CHANGELOG.md +41 -0
  2. package/README.md +94 -3
  3. package/dist/components/FooterRenderer.cjs +75 -0
  4. package/dist/components/FooterRenderer.cjs.map +1 -0
  5. package/dist/components/FooterRenderer.js +75 -0
  6. package/dist/components/FooterRenderer.js.map +1 -0
  7. package/dist/components/GridRenderer.cjs +82 -0
  8. package/dist/components/GridRenderer.cjs.map +1 -0
  9. package/dist/components/GridRenderer.d.ts +49 -0
  10. package/dist/components/GridRenderer.d.ts.map +1 -0
  11. package/dist/components/GridRenderer.js +82 -0
  12. package/dist/components/GridRenderer.js.map +1 -0
  13. package/dist/components/UIResourceRenderer.cjs +304 -174
  14. package/dist/components/UIResourceRenderer.cjs.map +1 -1
  15. package/dist/components/UIResourceRenderer.d.ts.map +1 -1
  16. package/dist/components/UIResourceRenderer.js +306 -176
  17. package/dist/components/UIResourceRenderer.js.map +1 -1
  18. package/dist/context/MCPActionContext.cjs +149 -0
  19. package/dist/context/MCPActionContext.cjs.map +1 -0
  20. package/dist/context/MCPActionContext.d.ts +158 -0
  21. package/dist/context/MCPActionContext.d.ts.map +1 -0
  22. package/dist/context/MCPActionContext.js +149 -0
  23. package/dist/context/MCPActionContext.js.map +1 -0
  24. package/dist/context/index.d.ts +8 -0
  25. package/dist/context/index.d.ts.map +1 -0
  26. package/dist/hooks/index.d.ts +2 -0
  27. package/dist/hooks/index.d.ts.map +1 -1
  28. package/dist/hooks/useAction.cjs +49 -0
  29. package/dist/hooks/useAction.cjs.map +1 -0
  30. package/dist/hooks/useAction.d.ts +79 -0
  31. package/dist/hooks/useAction.d.ts.map +1 -0
  32. package/dist/hooks/useAction.js +49 -0
  33. package/dist/hooks/useAction.js.map +1 -0
  34. package/dist/hooks/useStreamingUI.cjs +4 -1
  35. package/dist/hooks/useStreamingUI.cjs.map +1 -1
  36. package/dist/hooks/useStreamingUI.d.ts +2 -0
  37. package/dist/hooks/useStreamingUI.d.ts.map +1 -1
  38. package/dist/hooks/useStreamingUI.js +4 -1
  39. package/dist/hooks/useStreamingUI.js.map +1 -1
  40. package/dist/hooks.cjs +3 -0
  41. package/dist/hooks.cjs.map +1 -1
  42. package/dist/hooks.d.ts +2 -0
  43. package/dist/hooks.js +4 -1
  44. package/dist/hooks.js.map +1 -1
  45. package/dist/index.cjs +8 -0
  46. package/dist/index.cjs.map +1 -1
  47. package/dist/index.d.ts +5 -3
  48. package/dist/index.d.ts.map +1 -1
  49. package/dist/index.js +8 -0
  50. package/dist/index.js.map +1 -1
  51. package/dist/types/index.d.ts +41 -2
  52. package/dist/types/index.d.ts.map +1 -1
  53. package/dist/types.d.ts +41 -2
  54. package/package.json +1 -1
  55. package/src/components/GridRenderer.tsx +140 -0
  56. package/src/components/UIResourceRenderer.tsx +144 -28
  57. package/src/context/MCPActionContext.tsx +350 -0
  58. package/src/context/index.ts +19 -0
  59. package/src/hooks/index.ts +4 -0
  60. package/src/hooks/useAction.ts +138 -0
  61. package/src/hooks/useStreamingUI.ts +7 -1
  62. package/src/index.ts +14 -1
  63. package/src/types/index.ts +48 -1
  64. package/tsconfig.tsbuildinfo +1 -1
package/CHANGELOG.md CHANGED
@@ -5,6 +5,47 @@ All notable changes to this project will be documented in this file.
5
5
  The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
6
6
  and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
7
7
 
8
+ ## [1.2.0] - 2025-11-25
9
+
10
+ ### Added - Phase 5.0 Quick Wins
11
+
12
+ #### GridRenderer (NEW)
13
+ - **Nested CSS Grid layouts** for complex template builder layouts
14
+ - Supports `columns`, `gap`, `minRowHeight`, and `areas` configuration
15
+ - Recursive rendering of child components via `UIResourceRenderer`
16
+ - Enables sidebar + main + footer dashboard layouts
17
+
18
+ #### MCPActionContext + useAction() (NEW)
19
+ - **Context Provider pattern** replaces CustomEvent for action dispatch
20
+ - `MCPActionProvider` wrapper for orchestration (Mastra integration ready)
21
+ - `useAction()` hook with execute, isExecuting state, and error handling
22
+ - `useMCPActionSafe()` for components outside provider (fallback to CustomEvent)
23
+ - `useToolAction()` for binding to specific tool names
24
+ - Typed `ActionRequest` and `ActionResult` interfaces
25
+ - Support for audit callbacks (`onAction`) and webhook events (`onWebhook`)
26
+
27
+ #### FooterRenderer Auto-Injection (NEW)
28
+ - Automatically inject footer when layout has metadata (executionTime, sourceCount, llmModel)
29
+ - Opt-out via `layout.metadata.hideFooter: true`
30
+ - Respects explicit footer components if already present
31
+ - Shows "Powered by Deposium" with execution metrics
32
+
33
+ ### Changed
34
+ - **ActionRenderer refactored** to use `useAction()` hook internally
35
+ - Added loading spinner state during tool-call execution
36
+ - Button auto-disables while action is executing
37
+
38
+ ### Types
39
+ - Added `GridComponentParams` interface for grid configuration
40
+ - Added `footer`, `carousel`, `artifact` to `ComponentType` union
41
+ - Extended `UILayout.metadata` with `executionTime`, `sourceCount`, `hideFooter`
42
+ - New exports: `MCPActionProvider`, `MCPActionContext`, `useMCPAction`, `useAction`, `useToolAction`
43
+
44
+ ### Technical
45
+ - New directories: `src/context/`, `src/hooks/useAction.ts`
46
+ - Full TypeScript support with strict types
47
+ - SSR-compatible with `isServer` guards
48
+
8
49
  ## [1.1.0] - 2025-11-25
9
50
 
10
51
  ### Documentation
package/README.md CHANGED
@@ -111,14 +111,20 @@ function StreamingDashboard() {
111
111
  | `LinkRenderer` | `link` | External links with security attributes |
112
112
  | `IframeRenderer` | `iframe` | Secure iframe embedding (sandboxed) |
113
113
 
114
+ ### Layout Renderers
115
+
116
+ | Component | Type | Description |
117
+ |-----------|------|-------------|
118
+ | `GridRenderer` | `grid` | **NEW v1.2.0** - Nested CSS Grid layouts for complex dashboards |
119
+
114
120
  ### Interactive Renderers
115
121
 
116
122
  | Component | Type | Description |
117
123
  |-----------|------|-------------|
118
- | `ActionRenderer` | `action` | Interactive buttons with callbacks |
124
+ | `ActionRenderer` | `action` | Interactive buttons with MCP tool calls |
119
125
  | `ArtifactRenderer` | `artifact` | File download/preview |
120
126
  | `CarouselRenderer` | `carousel` | Image/content carousel |
121
- | `FooterRenderer` | `footer` | Metadata and attribution display |
127
+ | `FooterRenderer` | `footer` | Metadata and attribution display (auto-injected)
122
128
 
123
129
  ## Exports
124
130
 
@@ -142,12 +148,55 @@ import {
142
148
  ### Hooks
143
149
 
144
150
  ```typescript
145
- import { useStreamingUI } from '@seed-ship/mcp-ui-solid/hooks'
151
+ import { useStreamingUI, useAction, useToolAction } from '@seed-ship/mcp-ui-solid'
146
152
 
153
+ // Streaming hook
147
154
  const { components, isComplete, error, metadata } = useStreamingUI({
148
155
  query: 'Show revenue data',
149
156
  spaceIds: ['space-1']
150
157
  })
158
+
159
+ // Action hooks (NEW v1.2.0)
160
+ const { execute, isExecuting, lastError } = useAction()
161
+ await execute('search.hub', { query: 'revenue Q4' })
162
+
163
+ // Bound to specific tool
164
+ const { execute: searchExecute } = useToolAction('search.hub')
165
+ await searchExecute({ query: 'test' })
166
+ ```
167
+
168
+ ### Context Provider (NEW v1.2.0)
169
+
170
+ ```typescript
171
+ import { MCPActionProvider, useMCPAction } from '@seed-ship/mcp-ui-solid'
172
+
173
+ // Wrap your app to enable typed action dispatch
174
+ function App() {
175
+ return (
176
+ <MCPActionProvider
177
+ spaceIds={['space-123']}
178
+ macroId="dashboard_template"
179
+ onAction={(req, res) => auditLog(req, res)}
180
+ onWebhook={(event) => triggerN8n(event)}
181
+ >
182
+ <UIResourceRenderer content={layout} />
183
+ </MCPActionProvider>
184
+ )
185
+ }
186
+
187
+ // Inside any component
188
+ function ActionButton() {
189
+ const { executeAction, isExecuting } = useMCPAction()
190
+
191
+ return (
192
+ <button
193
+ onClick={() => executeAction({ toolName: 'search.hub', params: { query: 'test' } })}
194
+ disabled={isExecuting()}
195
+ >
196
+ Search
197
+ </button>
198
+ )
199
+ }
151
200
  ```
152
201
 
153
202
  ### Validation (SSR-Safe)
@@ -231,6 +280,48 @@ interface GridPosition {
231
280
 
232
281
  ## Advanced Usage
233
282
 
283
+ ### Nested Grid Layouts (NEW v1.2.0)
284
+
285
+ Use `GridRenderer` for complex dashboard layouts:
286
+
287
+ ```typescript
288
+ const dashboardLayout = {
289
+ id: 'dashboard',
290
+ type: 'grid',
291
+ params: {
292
+ columns: 12,
293
+ gap: '1rem',
294
+ areas: [
295
+ ['header', 'header', 'header'],
296
+ ['sidebar', 'main', 'main'],
297
+ ['footer', 'footer', 'footer']
298
+ ],
299
+ children: [
300
+ { id: 'nav', type: 'text', params: { content: 'Navigation' }, position: { colStart: 1, colSpan: 3 } },
301
+ { id: 'content', type: 'chart', params: { /* ... */ }, position: { colStart: 4, colSpan: 9 } }
302
+ ]
303
+ }
304
+ }
305
+ ```
306
+
307
+ ### Auto-Footer (NEW v1.2.0)
308
+
309
+ Footers are automatically injected when `layout.metadata` contains execution info:
310
+
311
+ ```typescript
312
+ const layout = {
313
+ id: 'report',
314
+ components: [/* ... */],
315
+ metadata: {
316
+ executionTime: 1234, // Shows "1234ms"
317
+ sourceCount: 5, // Shows "5 sources"
318
+ llmModel: 'gpt-4', // Shows model name
319
+ // hideFooter: true // Opt-out of auto-footer
320
+ }
321
+ }
322
+ // Footer automatically added showing "Powered by Deposium | 1234ms | gpt-4 | 5 sources"
323
+ ```
324
+
234
325
  ### Custom Component Registry
235
326
 
236
327
  ```typescript
@@ -0,0 +1,75 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
3
+ const web = require("solid-js/web");
4
+ const solidJs = require("solid-js");
5
+ var _tmpl$ = /* @__PURE__ */ web.template(`<span class=font-medium>`), _tmpl$2 = /* @__PURE__ */ web.template(`<span class="flex items-center gap-1"><svg class="w-3 h-3"fill=none viewBox="0 0 24 24"stroke=currentColor><path stroke-linecap=round stroke-linejoin=round stroke-width=2 d="M12 8v4l3 3m6-3a9 9 0 11-18 0 9 9 0 0118 0z"></path></svg><!$><!/>ms`), _tmpl$3 = /* @__PURE__ */ web.template(`<span class="flex items-center gap-1"><svg class="w-3 h-3"fill=none viewBox="0 0 24 24"stroke=currentColor><path stroke-linecap=round stroke-linejoin=round stroke-width=2 d="M19.428 15.428a2 2 0 00-1.022-.547l-2.384-.477a6 6 0 00-3.86.517l-.318.158a6 6 0 01-3.86.517L6.05 15.21a2 2 0 00-1.806.547M8 4h8l-1 1v5.172a2 2 0 00.586 1.414l5 5c1.26 1.26.367 3.414-1.415 3.414H4.828c-1.782 0-2.674-2.154-1.414-3.414l5-5A2 2 0 009 10.172V5L8 4z"></path></svg><!$><!/>`), _tmpl$4 = /* @__PURE__ */ web.template(`<span class="flex items-center gap-1"><svg class="w-3 h-3"fill=none viewBox="0 0 24 24"stroke=currentColor><path stroke-linecap=round stroke-linejoin=round stroke-width=2 d="M9 12h6m-6 4h6m2 5H7a2 2 0 01-2-2V5a2 2 0 012-2h5.586a1 1 0 01.707.293l5.414 5.414a1 1 0 01.293.707V19a2 2 0 01-2 2z"></path></svg><!$><!/> sources`), _tmpl$5 = /* @__PURE__ */ web.template(`<div class="flex gap-3">`), _tmpl$6 = /* @__PURE__ */ web.template(`<div class="mt-4 pt-3 border-t border-gray-200 dark:border-gray-700 text-xs text-gray-500 dark:text-gray-400 flex flex-wrap items-center gap-4"><!$><!/><!$><!/><!$><!/><!$><!/><div class=flex-grow></div><!$><!/>`), _tmpl$7 = /* @__PURE__ */ web.template(`<a target=_blank rel="noopener noreferrer"class="hover:text-blue-600 dark:hover:text-blue-400 transition-colors">`);
6
+ const FooterRenderer = (props) => {
7
+ return (() => {
8
+ var _el$ = web.getNextElement(_tmpl$6), _el$17 = _el$.firstChild, [_el$18, _co$4] = web.getNextMarker(_el$17.nextSibling), _el$19 = _el$18.nextSibling, [_el$20, _co$5] = web.getNextMarker(_el$19.nextSibling), _el$21 = _el$20.nextSibling, [_el$22, _co$6] = web.getNextMarker(_el$21.nextSibling), _el$23 = _el$22.nextSibling, [_el$24, _co$7] = web.getNextMarker(_el$23.nextSibling), _el$15 = _el$24.nextSibling, _el$25 = _el$15.nextSibling, [_el$26, _co$8] = web.getNextMarker(_el$25.nextSibling);
9
+ web.insert(_el$, web.createComponent(solidJs.Show, {
10
+ get when() {
11
+ return props.params.poweredBy;
12
+ },
13
+ get children() {
14
+ var _el$2 = web.getNextElement(_tmpl$);
15
+ web.insert(_el$2, () => props.params.poweredBy);
16
+ return _el$2;
17
+ }
18
+ }), _el$18, _co$4);
19
+ web.insert(_el$, web.createComponent(solidJs.Show, {
20
+ get when() {
21
+ return props.params.executionTime;
22
+ },
23
+ get children() {
24
+ var _el$3 = web.getNextElement(_tmpl$2), _el$4 = _el$3.firstChild, _el$6 = _el$4.nextSibling, [_el$7, _co$] = web.getNextMarker(_el$6.nextSibling);
25
+ _el$7.nextSibling;
26
+ web.insert(_el$3, () => props.params.executionTime, _el$7, _co$);
27
+ return _el$3;
28
+ }
29
+ }), _el$20, _co$5);
30
+ web.insert(_el$, web.createComponent(solidJs.Show, {
31
+ get when() {
32
+ return props.params.model;
33
+ },
34
+ get children() {
35
+ var _el$8 = web.getNextElement(_tmpl$3), _el$9 = _el$8.firstChild, _el$0 = _el$9.nextSibling, [_el$1, _co$2] = web.getNextMarker(_el$0.nextSibling);
36
+ web.insert(_el$8, () => props.params.model, _el$1, _co$2);
37
+ return _el$8;
38
+ }
39
+ }), _el$22, _co$6);
40
+ web.insert(_el$, web.createComponent(solidJs.Show, {
41
+ get when() {
42
+ return props.params.sourceCount;
43
+ },
44
+ get children() {
45
+ var _el$10 = web.getNextElement(_tmpl$4), _el$11 = _el$10.firstChild, _el$13 = _el$11.nextSibling, [_el$14, _co$3] = web.getNextMarker(_el$13.nextSibling);
46
+ _el$14.nextSibling;
47
+ web.insert(_el$10, () => props.params.sourceCount, _el$14, _co$3);
48
+ return _el$10;
49
+ }
50
+ }), _el$24, _co$7);
51
+ web.insert(_el$, web.createComponent(solidJs.Show, {
52
+ get when() {
53
+ return props.params.links;
54
+ },
55
+ get children() {
56
+ var _el$16 = web.getNextElement(_tmpl$5);
57
+ web.insert(_el$16, web.createComponent(solidJs.For, {
58
+ get each() {
59
+ return props.params.links;
60
+ },
61
+ children: (link) => (() => {
62
+ var _el$27 = web.getNextElement(_tmpl$7);
63
+ web.insert(_el$27, () => link.label);
64
+ web.effect(() => web.setAttribute(_el$27, "href", link.url));
65
+ return _el$27;
66
+ })()
67
+ }));
68
+ return _el$16;
69
+ }
70
+ }), _el$26, _co$8);
71
+ return _el$;
72
+ })();
73
+ };
74
+ exports.FooterRenderer = FooterRenderer;
75
+ //# sourceMappingURL=FooterRenderer.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"FooterRenderer.cjs","sources":["../../src/components/FooterRenderer.tsx"],"sourcesContent":["import { Component, Show, For } from 'solid-js'\n\nexport interface FooterComponentParams {\n poweredBy?: string\n executionTime?: number\n model?: string\n sourceCount?: number\n customText?: string\n links?: { label: string; url: string }[]\n}\n\nexport const FooterRenderer: Component<{ params: FooterComponentParams }> = (props) => {\n return (\n <div class=\"mt-4 pt-3 border-t border-gray-200 dark:border-gray-700 text-xs text-gray-500 dark:text-gray-400 flex flex-wrap items-center gap-4\">\n <Show when={props.params.poweredBy}>\n <span class=\"font-medium\">{props.params.poweredBy}</span>\n </Show>\n\n <Show when={props.params.executionTime}>\n <span class=\"flex items-center gap-1\">\n <svg class=\"w-3 h-3\" fill=\"none\" viewBox=\"0 0 24 24\" stroke=\"currentColor\">\n <path stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"2\" d=\"M12 8v4l3 3m6-3a9 9 0 11-18 0 9 9 0 0118 0z\" />\n </svg>\n {props.params.executionTime}ms\n </span>\n </Show>\n\n <Show when={props.params.model}>\n <span class=\"flex items-center gap-1\">\n <svg class=\"w-3 h-3\" fill=\"none\" viewBox=\"0 0 24 24\" stroke=\"currentColor\">\n <path stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"2\" d=\"M19.428 15.428a2 2 0 00-1.022-.547l-2.384-.477a6 6 0 00-3.86.517l-.318.158a6 6 0 01-3.86.517L6.05 15.21a2 2 0 00-1.806.547M8 4h8l-1 1v5.172a2 2 0 00.586 1.414l5 5c1.26 1.26.367 3.414-1.415 3.414H4.828c-1.782 0-2.674-2.154-1.414-3.414l5-5A2 2 0 009 10.172V5L8 4z\" />\n </svg>\n {props.params.model}\n </span>\n </Show>\n\n <Show when={props.params.sourceCount}>\n <span class=\"flex items-center gap-1\">\n <svg class=\"w-3 h-3\" fill=\"none\" viewBox=\"0 0 24 24\" stroke=\"currentColor\">\n <path stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"2\" d=\"M9 12h6m-6 4h6m2 5H7a2 2 0 01-2-2V5a2 2 0 012-2h5.586a1 1 0 01.707.293l5.414 5.414a1 1 0 01.293.707V19a2 2 0 01-2 2z\" />\n </svg>\n {props.params.sourceCount} sources\n </span>\n </Show>\n\n <div class=\"flex-grow\" />\n\n <Show when={props.params.links}>\n <div class=\"flex gap-3\">\n <For each={props.params.links}>\n {(link) => (\n <a\n href={link.url}\n target=\"_blank\"\n rel=\"noopener noreferrer\"\n class=\"hover:text-blue-600 dark:hover:text-blue-400 transition-colors\"\n >\n {link.label}\n </a>\n )}\n </For>\n </div>\n </Show>\n </div>\n )\n}\n"],"names":["FooterRenderer","props","_el$","_$getNextElement","_tmpl$6","_el$17","firstChild","_el$18","_co$4","_$getNextMarker","nextSibling","_el$19","_el$20","_co$5","_el$21","_el$22","_co$6","_el$23","_el$24","_co$7","_el$15","_el$25","_el$26","_co$8","_$insert","_$createComponent","Show","when","params","poweredBy","children","_el$2","_tmpl$","executionTime","_el$3","_tmpl$2","_el$4","_el$6","_el$7","_co$","model","_el$8","_tmpl$3","_el$9","_el$0","_el$1","_co$2","sourceCount","_el$10","_tmpl$4","_el$11","_el$13","_el$14","_co$3","links","_el$16","_tmpl$5","For","each","link","_el$27","_tmpl$7","label","_$effect","_$setAttribute","url"],"mappings":";;;;;AAWO,MAAMA,iBAAgEC,CAAAA,UAAU;AACnF,UAAA,MAAA;AAAA,QAAAC,OAAAC,IAAAA,eAAAC,OAAA,GAAAC,SAAAH,KAAAI,YAAA,CAAAC,QAAAC,KAAA,IAAAC,IAAAA,cAAAJ,OAAAK,WAAA,GAAAC,SAAAJ,OAAAG,aAAA,CAAAE,QAAAC,KAAA,IAAAJ,kBAAAE,OAAAD,WAAA,GAAAI,SAAAF,OAAAF,aAAA,CAAAK,QAAAC,KAAA,IAAAP,IAAAA,cAAAK,OAAAJ,WAAA,GAAAO,SAAAF,OAAAL,aAAA,CAAAQ,QAAAC,KAAA,IAAAV,IAAAA,cAAAQ,OAAAP,WAAA,GAAAU,SAAAF,OAAAR,aAAAW,SAAAD,OAAAV,aAAA,CAAAY,QAAAC,KAAA,IAAAd,kBAAAY,OAAAX,WAAA;AAAAc,eAAAtB,MAAAuB,IAAAA,gBAESC,cAAI;AAAA,MAAA,IAACC,OAAI;AAAA,eAAE1B,MAAM2B,OAAOC;AAAAA,MAAS;AAAA,MAAA,IAAAC,WAAA;AAAA,YAAAC,QAAA5B,IAAAA,eAAA6B,MAAA;AAAAR,YAAAA,OAAAO,OAAA,MACH9B,MAAM2B,OAAOC,SAAS;AAAA,eAAAE;AAAAA,MAAA;AAAA,IAAA,CAAA,GAAAxB,QAAAC,KAAA;AAAAgB,eAAAtB,MAAAuB,IAAAA,gBAGpDC,cAAI;AAAA,MAAA,IAACC,OAAI;AAAA,eAAE1B,MAAM2B,OAAOK;AAAAA,MAAa;AAAA,MAAA,IAAAH,WAAA;AAAA,YAAAI,QAAA/B,IAAAA,eAAAgC,OAAA,GAAAC,QAAAF,MAAA5B,YAAA+B,QAAAD,MAAA1B,aAAA,CAAA4B,OAAAC,IAAA,IAAA9B,IAAAA,cAAA4B,MAAA3B,WAAA;AAAA4B,cAAA5B;AAAAc,YAAAA,OAAAU,OAAA,MAK7BjC,MAAM2B,OAAOK,eAAaK,OAAAC,IAAA;AAAA,eAAAL;AAAAA,MAAA;AAAA,IAAA,CAAA,GAAAtB,QAAAC,KAAA;AAAAW,eAAAtB,MAAAuB,IAAAA,gBAIlCC,cAAI;AAAA,MAAA,IAACC,OAAI;AAAA,eAAE1B,MAAM2B,OAAOY;AAAAA,MAAK;AAAA,MAAA,IAAAV,WAAA;AAAA,YAAAW,QAAAtC,IAAAA,eAAAuC,OAAA,GAAAC,QAAAF,MAAAnC,YAAAsC,QAAAD,MAAAjC,aAAA,CAAAmC,OAAAC,KAAA,IAAArC,IAAAA,cAAAmC,MAAAlC,WAAA;AAAAc,YAAAA,OAAAiB,OAAA,MAKrBxC,MAAM2B,OAAOY,OAAKK,OAAAC,KAAA;AAAA,eAAAL;AAAAA,MAAA;AAAA,IAAA,CAAA,GAAA1B,QAAAC,KAAA;AAAAQ,eAAAtB,MAAAuB,IAAAA,gBAI1BC,cAAI;AAAA,MAAA,IAACC,OAAI;AAAA,eAAE1B,MAAM2B,OAAOmB;AAAAA,MAAW;AAAA,MAAA,IAAAjB,WAAA;AAAA,YAAAkB,SAAA7C,IAAAA,eAAA8C,OAAA,GAAAC,SAAAF,OAAA1C,YAAA6C,SAAAD,OAAAxC,aAAA,CAAA0C,QAAAC,KAAA,IAAA5C,IAAAA,cAAA0C,OAAAzC,WAAA;AAAA0C,eAAA1C;AAAAc,YAAAA,OAAAwB,QAAA,MAK3B/C,MAAM2B,OAAOmB,aAAWK,QAAAC,KAAA;AAAA,eAAAL;AAAAA,MAAA;AAAA,IAAA,CAAA,GAAA9B,QAAAC,KAAA;AAAAK,eAAAtB,MAAAuB,IAAAA,gBAMhCC,cAAI;AAAA,MAAA,IAACC,OAAI;AAAA,eAAE1B,MAAM2B,OAAO0B;AAAAA,MAAK;AAAA,MAAA,IAAAxB,WAAA;AAAA,YAAAyB,SAAApD,IAAAA,eAAAqD,OAAA;AAAAhC,mBAAA+B,QAAA9B,IAAAA,gBAErBgC,aAAG;AAAA,UAAA,IAACC,OAAI;AAAA,mBAAEzD,MAAM2B,OAAO0B;AAAAA,UAAK;AAAA,UAAAxB,UACvB6B,WAAI,MAAA;AAAA,gBAAAC,SAAAzD,IAAAA,eAAA0D,OAAA;AAAArC,gBAAAA,OAAAoC,QAAA,MAOGD,KAAKG,KAAK;AAAAC,gBAAAA,aAAAC,IAAAA,aAAAJ,QAAA,QALLD,KAAKM,GAAG,CAAA;AAAA,mBAAAL;AAAAA,UAAA,GAAA;AAAA,QAAA,CAOrB,CAAA;AAAA,eAAAL;AAAAA,MAAA;AAAA,IAAA,CAAA,GAAAjC,QAAAC,KAAA;AAAA,WAAArB;AAAAA,EAAA,GAAA;AAMzB;;"}
@@ -0,0 +1,75 @@
1
+ import { getNextElement, template, getNextMarker, insert, createComponent, effect, setAttribute } from "solid-js/web";
2
+ import { Show, For } from "solid-js";
3
+ var _tmpl$ = /* @__PURE__ */ template(`<span class=font-medium>`), _tmpl$2 = /* @__PURE__ */ template(`<span class="flex items-center gap-1"><svg class="w-3 h-3"fill=none viewBox="0 0 24 24"stroke=currentColor><path stroke-linecap=round stroke-linejoin=round stroke-width=2 d="M12 8v4l3 3m6-3a9 9 0 11-18 0 9 9 0 0118 0z"></path></svg><!$><!/>ms`), _tmpl$3 = /* @__PURE__ */ template(`<span class="flex items-center gap-1"><svg class="w-3 h-3"fill=none viewBox="0 0 24 24"stroke=currentColor><path stroke-linecap=round stroke-linejoin=round stroke-width=2 d="M19.428 15.428a2 2 0 00-1.022-.547l-2.384-.477a6 6 0 00-3.86.517l-.318.158a6 6 0 01-3.86.517L6.05 15.21a2 2 0 00-1.806.547M8 4h8l-1 1v5.172a2 2 0 00.586 1.414l5 5c1.26 1.26.367 3.414-1.415 3.414H4.828c-1.782 0-2.674-2.154-1.414-3.414l5-5A2 2 0 009 10.172V5L8 4z"></path></svg><!$><!/>`), _tmpl$4 = /* @__PURE__ */ template(`<span class="flex items-center gap-1"><svg class="w-3 h-3"fill=none viewBox="0 0 24 24"stroke=currentColor><path stroke-linecap=round stroke-linejoin=round stroke-width=2 d="M9 12h6m-6 4h6m2 5H7a2 2 0 01-2-2V5a2 2 0 012-2h5.586a1 1 0 01.707.293l5.414 5.414a1 1 0 01.293.707V19a2 2 0 01-2 2z"></path></svg><!$><!/> sources`), _tmpl$5 = /* @__PURE__ */ template(`<div class="flex gap-3">`), _tmpl$6 = /* @__PURE__ */ template(`<div class="mt-4 pt-3 border-t border-gray-200 dark:border-gray-700 text-xs text-gray-500 dark:text-gray-400 flex flex-wrap items-center gap-4"><!$><!/><!$><!/><!$><!/><!$><!/><div class=flex-grow></div><!$><!/>`), _tmpl$7 = /* @__PURE__ */ template(`<a target=_blank rel="noopener noreferrer"class="hover:text-blue-600 dark:hover:text-blue-400 transition-colors">`);
4
+ const FooterRenderer = (props) => {
5
+ return (() => {
6
+ var _el$ = getNextElement(_tmpl$6), _el$17 = _el$.firstChild, [_el$18, _co$4] = getNextMarker(_el$17.nextSibling), _el$19 = _el$18.nextSibling, [_el$20, _co$5] = getNextMarker(_el$19.nextSibling), _el$21 = _el$20.nextSibling, [_el$22, _co$6] = getNextMarker(_el$21.nextSibling), _el$23 = _el$22.nextSibling, [_el$24, _co$7] = getNextMarker(_el$23.nextSibling), _el$15 = _el$24.nextSibling, _el$25 = _el$15.nextSibling, [_el$26, _co$8] = getNextMarker(_el$25.nextSibling);
7
+ insert(_el$, createComponent(Show, {
8
+ get when() {
9
+ return props.params.poweredBy;
10
+ },
11
+ get children() {
12
+ var _el$2 = getNextElement(_tmpl$);
13
+ insert(_el$2, () => props.params.poweredBy);
14
+ return _el$2;
15
+ }
16
+ }), _el$18, _co$4);
17
+ insert(_el$, createComponent(Show, {
18
+ get when() {
19
+ return props.params.executionTime;
20
+ },
21
+ get children() {
22
+ var _el$3 = getNextElement(_tmpl$2), _el$4 = _el$3.firstChild, _el$6 = _el$4.nextSibling, [_el$7, _co$] = getNextMarker(_el$6.nextSibling);
23
+ _el$7.nextSibling;
24
+ insert(_el$3, () => props.params.executionTime, _el$7, _co$);
25
+ return _el$3;
26
+ }
27
+ }), _el$20, _co$5);
28
+ insert(_el$, createComponent(Show, {
29
+ get when() {
30
+ return props.params.model;
31
+ },
32
+ get children() {
33
+ var _el$8 = getNextElement(_tmpl$3), _el$9 = _el$8.firstChild, _el$0 = _el$9.nextSibling, [_el$1, _co$2] = getNextMarker(_el$0.nextSibling);
34
+ insert(_el$8, () => props.params.model, _el$1, _co$2);
35
+ return _el$8;
36
+ }
37
+ }), _el$22, _co$6);
38
+ insert(_el$, createComponent(Show, {
39
+ get when() {
40
+ return props.params.sourceCount;
41
+ },
42
+ get children() {
43
+ var _el$10 = getNextElement(_tmpl$4), _el$11 = _el$10.firstChild, _el$13 = _el$11.nextSibling, [_el$14, _co$3] = getNextMarker(_el$13.nextSibling);
44
+ _el$14.nextSibling;
45
+ insert(_el$10, () => props.params.sourceCount, _el$14, _co$3);
46
+ return _el$10;
47
+ }
48
+ }), _el$24, _co$7);
49
+ insert(_el$, createComponent(Show, {
50
+ get when() {
51
+ return props.params.links;
52
+ },
53
+ get children() {
54
+ var _el$16 = getNextElement(_tmpl$5);
55
+ insert(_el$16, createComponent(For, {
56
+ get each() {
57
+ return props.params.links;
58
+ },
59
+ children: (link) => (() => {
60
+ var _el$27 = getNextElement(_tmpl$7);
61
+ insert(_el$27, () => link.label);
62
+ effect(() => setAttribute(_el$27, "href", link.url));
63
+ return _el$27;
64
+ })()
65
+ }));
66
+ return _el$16;
67
+ }
68
+ }), _el$26, _co$8);
69
+ return _el$;
70
+ })();
71
+ };
72
+ export {
73
+ FooterRenderer
74
+ };
75
+ //# sourceMappingURL=FooterRenderer.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"FooterRenderer.js","sources":["../../src/components/FooterRenderer.tsx"],"sourcesContent":["import { Component, Show, For } from 'solid-js'\n\nexport interface FooterComponentParams {\n poweredBy?: string\n executionTime?: number\n model?: string\n sourceCount?: number\n customText?: string\n links?: { label: string; url: string }[]\n}\n\nexport const FooterRenderer: Component<{ params: FooterComponentParams }> = (props) => {\n return (\n <div class=\"mt-4 pt-3 border-t border-gray-200 dark:border-gray-700 text-xs text-gray-500 dark:text-gray-400 flex flex-wrap items-center gap-4\">\n <Show when={props.params.poweredBy}>\n <span class=\"font-medium\">{props.params.poweredBy}</span>\n </Show>\n\n <Show when={props.params.executionTime}>\n <span class=\"flex items-center gap-1\">\n <svg class=\"w-3 h-3\" fill=\"none\" viewBox=\"0 0 24 24\" stroke=\"currentColor\">\n <path stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"2\" d=\"M12 8v4l3 3m6-3a9 9 0 11-18 0 9 9 0 0118 0z\" />\n </svg>\n {props.params.executionTime}ms\n </span>\n </Show>\n\n <Show when={props.params.model}>\n <span class=\"flex items-center gap-1\">\n <svg class=\"w-3 h-3\" fill=\"none\" viewBox=\"0 0 24 24\" stroke=\"currentColor\">\n <path stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"2\" d=\"M19.428 15.428a2 2 0 00-1.022-.547l-2.384-.477a6 6 0 00-3.86.517l-.318.158a6 6 0 01-3.86.517L6.05 15.21a2 2 0 00-1.806.547M8 4h8l-1 1v5.172a2 2 0 00.586 1.414l5 5c1.26 1.26.367 3.414-1.415 3.414H4.828c-1.782 0-2.674-2.154-1.414-3.414l5-5A2 2 0 009 10.172V5L8 4z\" />\n </svg>\n {props.params.model}\n </span>\n </Show>\n\n <Show when={props.params.sourceCount}>\n <span class=\"flex items-center gap-1\">\n <svg class=\"w-3 h-3\" fill=\"none\" viewBox=\"0 0 24 24\" stroke=\"currentColor\">\n <path stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"2\" d=\"M9 12h6m-6 4h6m2 5H7a2 2 0 01-2-2V5a2 2 0 012-2h5.586a1 1 0 01.707.293l5.414 5.414a1 1 0 01.293.707V19a2 2 0 01-2 2z\" />\n </svg>\n {props.params.sourceCount} sources\n </span>\n </Show>\n\n <div class=\"flex-grow\" />\n\n <Show when={props.params.links}>\n <div class=\"flex gap-3\">\n <For each={props.params.links}>\n {(link) => (\n <a\n href={link.url}\n target=\"_blank\"\n rel=\"noopener noreferrer\"\n class=\"hover:text-blue-600 dark:hover:text-blue-400 transition-colors\"\n >\n {link.label}\n </a>\n )}\n </For>\n </div>\n </Show>\n </div>\n )\n}\n"],"names":["FooterRenderer","props","_el$","_$getNextElement","_tmpl$6","_el$17","firstChild","_el$18","_co$4","_$getNextMarker","nextSibling","_el$19","_el$20","_co$5","_el$21","_el$22","_co$6","_el$23","_el$24","_co$7","_el$15","_el$25","_el$26","_co$8","_$insert","_$createComponent","Show","when","params","poweredBy","children","_el$2","_tmpl$","executionTime","_el$3","_tmpl$2","_el$4","_el$6","_el$7","_co$","model","_el$8","_tmpl$3","_el$9","_el$0","_el$1","_co$2","sourceCount","_el$10","_tmpl$4","_el$11","_el$13","_el$14","_co$3","links","_el$16","_tmpl$5","For","each","link","_el$27","_tmpl$7","label","_$effect","_$setAttribute","url"],"mappings":"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"}
@@ -0,0 +1,82 @@
1
+ "use strict";
2
+ Object.defineProperties(exports, { __esModule: { value: true }, [Symbol.toStringTag]: { value: "Module" } });
3
+ const web = require("solid-js/web");
4
+ const solidJs = require("solid-js");
5
+ const UIResourceRenderer = require("./UIResourceRenderer.cjs");
6
+ var _tmpl$ = /* @__PURE__ */ web.template(`<div class="w-full h-full bg-white dark:bg-gray-800 rounded-lg shadow-sm border border-gray-200 dark:border-gray-700 overflow-hidden"data-component-type=grid><div class="p-4 h-full">`), _tmpl$2 = /* @__PURE__ */ web.template(`<div class="min-w-0 h-full">`);
7
+ function getGridItemStyle(position, areas) {
8
+ if (!position) {
9
+ return "grid-column: 1 / -1; grid-row: auto";
10
+ }
11
+ const {
12
+ colStart,
13
+ colSpan,
14
+ rowStart,
15
+ rowSpan = 1
16
+ } = position;
17
+ let style = `grid-column: ${colStart} / span ${colSpan}`;
18
+ if (rowStart) {
19
+ style += `; grid-row: ${rowStart} / span ${rowSpan}`;
20
+ } else {
21
+ style += "; grid-row: auto";
22
+ }
23
+ return style;
24
+ }
25
+ function buildGridTemplateAreas(areas) {
26
+ return areas.map((row) => `"${row.join(" ")}"`).join(" ");
27
+ }
28
+ const GridRenderer = (props) => {
29
+ const params = solidJs.createMemo(() => {
30
+ const p = props.component.params;
31
+ return {
32
+ columns: p.columns ?? 12,
33
+ gap: p.gap ?? "1rem",
34
+ minRowHeight: p.minRowHeight,
35
+ areas: p.areas,
36
+ children: p.children ?? []
37
+ };
38
+ });
39
+ const gridContainerStyle = solidJs.createMemo(() => {
40
+ const p = params();
41
+ let style = `display: grid; grid-template-columns: repeat(${p.columns}, 1fr); gap: ${p.gap}`;
42
+ if (p.minRowHeight) {
43
+ style += `; grid-auto-rows: minmax(${p.minRowHeight}, auto)`;
44
+ }
45
+ if (p.areas && p.areas.length > 0) {
46
+ style += `; grid-template-areas: ${buildGridTemplateAreas(p.areas)}`;
47
+ }
48
+ return style;
49
+ });
50
+ return (() => {
51
+ var _el$ = web.getNextElement(_tmpl$), _el$2 = _el$.firstChild;
52
+ web.insert(_el$2, web.createComponent(solidJs.For, {
53
+ get each() {
54
+ return params().children;
55
+ },
56
+ children: (child) => (() => {
57
+ var _el$3 = web.getNextElement(_tmpl$2);
58
+ web.insert(_el$3, web.createComponent(UIResourceRenderer.UIResourceRenderer, {
59
+ content: child,
60
+ get onError() {
61
+ return props.onError;
62
+ }
63
+ }));
64
+ web.effect((_$p) => web.style(_el$3, getGridItemStyle(child.position, params().areas), _$p));
65
+ return _el$3;
66
+ })()
67
+ }));
68
+ web.effect((_p$) => {
69
+ var _v$ = props.component.id, _v$2 = gridContainerStyle();
70
+ _v$ !== _p$.e && web.setAttribute(_el$, "data-component-id", _p$.e = _v$);
71
+ _p$.t = web.style(_el$2, _v$2, _p$.t);
72
+ return _p$;
73
+ }, {
74
+ e: void 0,
75
+ t: void 0
76
+ });
77
+ return _el$;
78
+ })();
79
+ };
80
+ exports.GridRenderer = GridRenderer;
81
+ exports.default = GridRenderer;
82
+ //# sourceMappingURL=GridRenderer.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"GridRenderer.cjs","sources":["../../src/components/GridRenderer.tsx"],"sourcesContent":["/**\n * GridRenderer - CSS Grid layout component for nested layouts\n * Phase 5.0: Quick Wins - Enables template builder layouts\n */\n\nimport { Component, For, createMemo } from 'solid-js'\nimport type { UIComponent, GridPosition } from '../types'\nimport { UIResourceRenderer } from './UIResourceRenderer'\n\n/**\n * Parameters for GridRenderer component\n */\nexport interface GridComponentParams {\n /**\n * Number of columns (default: 12)\n */\n columns?: number\n\n /**\n * Gap between grid items (default: '1rem')\n */\n gap?: string\n\n /**\n * Minimum row height (optional)\n */\n minRowHeight?: string\n\n /**\n * CSS Grid template areas for named regions\n * Example: [['header', 'header'], ['sidebar', 'main'], ['footer', 'footer']]\n */\n areas?: string[][]\n\n /**\n * Child components to render within the grid\n */\n children: UIComponent[]\n}\n\nexport interface GridRendererProps {\n /**\n * Grid component with params\n */\n component: UIComponent\n\n /**\n * Error callback\n */\n onError?: (error: any) => void\n}\n\n/**\n * Convert grid position to CSS style string\n */\nfunction getGridItemStyle(position: GridPosition | undefined, areas?: string[][]): string {\n // Default to full width if no position specified\n if (!position) {\n return 'grid-column: 1 / -1; grid-row: auto'\n }\n\n const { colStart, colSpan, rowStart, rowSpan = 1 } = position\n\n // If using named areas and component has area name, use grid-area\n // Otherwise use explicit grid-column/grid-row\n let style = `grid-column: ${colStart} / span ${colSpan}`\n\n if (rowStart) {\n style += `; grid-row: ${rowStart} / span ${rowSpan}`\n } else {\n style += '; grid-row: auto'\n }\n\n return style\n}\n\n/**\n * Build CSS grid-template-areas string from areas array\n */\nfunction buildGridTemplateAreas(areas: string[][]): string {\n return areas.map((row) => `\"${row.join(' ')}\"`).join(' ')\n}\n\n/**\n * GridRenderer Component\n * Renders a CSS Grid container with nested UIComponents\n */\nexport const GridRenderer: Component<GridRendererProps> = (props) => {\n // Extract params with defaults\n const params = createMemo(() => {\n const p = props.component.params as GridComponentParams\n return {\n columns: p.columns ?? 12,\n gap: p.gap ?? '1rem',\n minRowHeight: p.minRowHeight,\n areas: p.areas,\n children: p.children ?? [],\n }\n })\n\n // Build grid container style\n const gridContainerStyle = createMemo(() => {\n const p = params()\n let style = `display: grid; grid-template-columns: repeat(${p.columns}, 1fr); gap: ${p.gap}`\n\n if (p.minRowHeight) {\n style += `; grid-auto-rows: minmax(${p.minRowHeight}, auto)`\n }\n\n if (p.areas && p.areas.length > 0) {\n style += `; grid-template-areas: ${buildGridTemplateAreas(p.areas)}`\n }\n\n return style\n })\n\n return (\n <div\n class=\"w-full h-full bg-white dark:bg-gray-800 rounded-lg shadow-sm border border-gray-200 dark:border-gray-700 overflow-hidden\"\n data-component-type=\"grid\"\n data-component-id={props.component.id}\n >\n <div class=\"p-4 h-full\" style={gridContainerStyle()}>\n <For each={params().children}>\n {(child) => (\n <div\n style={getGridItemStyle(child.position, params().areas)}\n class=\"min-w-0 h-full\"\n >\n {/* Use UIResourceRenderer for recursive rendering */}\n <UIResourceRenderer content={child} onError={props.onError} />\n </div>\n )}\n </For>\n </div>\n </div>\n )\n}\n\nexport default GridRenderer\n"],"names":["getGridItemStyle","position","areas","colStart","colSpan","rowStart","rowSpan","style","buildGridTemplateAreas","map","row","join","GridRenderer","props","params","createMemo","p","component","columns","gap","minRowHeight","children","gridContainerStyle","length","_el$","_$getNextElement","_tmpl$","_el$2","firstChild","_$insert","_$createComponent","For","each","child","_el$3","_tmpl$2","UIResourceRenderer","content","onError","_$effect","_$p","_$style","_p$","_v$","id","_v$2","e","_$setAttribute","t","undefined"],"mappings":";;;;;;AAuDA,SAASA,iBAAiBC,UAAoCC,OAA4B;AAExF,MAAI,CAACD,UAAU;AACb,WAAO;AAAA,EACT;AAEA,QAAM;AAAA,IAAEE;AAAAA,IAAUC;AAAAA,IAASC;AAAAA,IAAUC,UAAU;AAAA,EAAA,IAAML;AAIrD,MAAIM,QAAQ,gBAAgBJ,QAAQ,WAAWC,OAAO;AAEtD,MAAIC,UAAU;AACZE,aAAS,eAAeF,QAAQ,WAAWC,OAAO;AAAA,EACpD,OAAO;AACLC,aAAS;AAAA,EACX;AAEA,SAAOA;AACT;AAKA,SAASC,uBAAuBN,OAA2B;AACzD,SAAOA,MAAMO,IAAKC,CAAAA,QAAQ,IAAIA,IAAIC,KAAK,GAAG,CAAC,GAAG,EAAEA,KAAK,GAAG;AAC1D;AAMO,MAAMC,eAA8CC,CAAAA,UAAU;AAEnE,QAAMC,SAASC,QAAAA,WAAW,MAAM;AAC9B,UAAMC,IAAIH,MAAMI,UAAUH;AAC1B,WAAO;AAAA,MACLI,SAASF,EAAEE,WAAW;AAAA,MACtBC,KAAKH,EAAEG,OAAO;AAAA,MACdC,cAAcJ,EAAEI;AAAAA,MAChBlB,OAAOc,EAAEd;AAAAA,MACTmB,UAAUL,EAAEK,YAAY,CAAA;AAAA,IAAA;AAAA,EAE5B,CAAC;AAGD,QAAMC,qBAAqBP,QAAAA,WAAW,MAAM;AAC1C,UAAMC,IAAIF,OAAAA;AACV,QAAIP,QAAQ,gDAAgDS,EAAEE,OAAO,gBAAgBF,EAAEG,GAAG;AAE1F,QAAIH,EAAEI,cAAc;AAClBb,eAAS,4BAA4BS,EAAEI,YAAY;AAAA,IACrD;AAEA,QAAIJ,EAAEd,SAASc,EAAEd,MAAMqB,SAAS,GAAG;AACjChB,eAAS,0BAA0BC,uBAAuBQ,EAAEd,KAAK,CAAC;AAAA,IACpE;AAEA,WAAOK;AAAAA,EACT,CAAC;AAED,UAAA,MAAA;AAAA,QAAAiB,OAAAC,IAAAA,eAAAC,MAAA,GAAAC,QAAAH,KAAAI;AAAAC,eAAAF,OAAAG,IAAAA,gBAOOC,aAAG;AAAA,MAAA,IAACC,OAAI;AAAA,eAAElB,SAASO;AAAAA,MAAQ;AAAA,MAAAA,UACxBY,YAAK,MAAA;AAAA,YAAAC,QAAAT,IAAAA,eAAAU,OAAA;AAAAN,mBAAAK,OAAAJ,IAAAA,gBAMFM,uCAAkB;AAAA,UAACC,SAASJ;AAAAA,UAAK,IAAEK,UAAO;AAAA,mBAAEzB,MAAMyB;AAAAA,UAAO;AAAA,QAAA,CAAA,CAAA;AAAAC,YAAAA,OAAAC,CAAAA,QAAAC,IAAAA,MAAAP,OAJnDlC,iBAAiBiC,MAAMhC,UAAUa,OAAAA,EAASZ,KAAK,GAACsC,GAAA,CAAA;AAAA,eAAAN;AAAAA,MAAA,GAAA;AAAA,IAAA,CAM1D,CAAA;AAAAK,QAAAA,OAAAG,CAAAA,QAAA;AAAA,UAAAC,MAZc9B,MAAMI,UAAU2B,IAAEC,OAENvB,mBAAAA;AAAoBqB,cAAAD,IAAAI,KAAAC,IAAAA,aAAAvB,MAAA,qBAAAkB,IAAAI,IAAAH,GAAA;AAAAD,UAAAM,IAAAP,IAAAA,MAAAd,OAAAkB,MAAAH,IAAAM,CAAA;AAAA,aAAAN;AAAAA,IAAA,GAAA;AAAA,MAAAI,GAAAG;AAAAA,MAAAD,GAAAC;AAAAA,IAAAA,CAAA;AAAA,WAAAzB;AAAAA,EAAA,GAAA;AAezD;;;"}
@@ -0,0 +1,49 @@
1
+ /**
2
+ * GridRenderer - CSS Grid layout component for nested layouts
3
+ * Phase 5.0: Quick Wins - Enables template builder layouts
4
+ */
5
+ import { Component } from 'solid-js';
6
+ import type { UIComponent } from '../types';
7
+ /**
8
+ * Parameters for GridRenderer component
9
+ */
10
+ export interface GridComponentParams {
11
+ /**
12
+ * Number of columns (default: 12)
13
+ */
14
+ columns?: number;
15
+ /**
16
+ * Gap between grid items (default: '1rem')
17
+ */
18
+ gap?: string;
19
+ /**
20
+ * Minimum row height (optional)
21
+ */
22
+ minRowHeight?: string;
23
+ /**
24
+ * CSS Grid template areas for named regions
25
+ * Example: [['header', 'header'], ['sidebar', 'main'], ['footer', 'footer']]
26
+ */
27
+ areas?: string[][];
28
+ /**
29
+ * Child components to render within the grid
30
+ */
31
+ children: UIComponent[];
32
+ }
33
+ export interface GridRendererProps {
34
+ /**
35
+ * Grid component with params
36
+ */
37
+ component: UIComponent;
38
+ /**
39
+ * Error callback
40
+ */
41
+ onError?: (error: any) => void;
42
+ }
43
+ /**
44
+ * GridRenderer Component
45
+ * Renders a CSS Grid container with nested UIComponents
46
+ */
47
+ export declare const GridRenderer: Component<GridRendererProps>;
48
+ export default GridRenderer;
49
+ //# sourceMappingURL=GridRenderer.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"GridRenderer.d.ts","sourceRoot":"","sources":["../../src/components/GridRenderer.tsx"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAE,SAAS,EAAmB,MAAM,UAAU,CAAA;AACrD,OAAO,KAAK,EAAE,WAAW,EAAgB,MAAM,UAAU,CAAA;AAGzD;;GAEG;AACH,MAAM,WAAW,mBAAmB;IAClC;;OAEG;IACH,OAAO,CAAC,EAAE,MAAM,CAAA;IAEhB;;OAEG;IACH,GAAG,CAAC,EAAE,MAAM,CAAA;IAEZ;;OAEG;IACH,YAAY,CAAC,EAAE,MAAM,CAAA;IAErB;;;OAGG;IACH,KAAK,CAAC,EAAE,MAAM,EAAE,EAAE,CAAA;IAElB;;OAEG;IACH,QAAQ,EAAE,WAAW,EAAE,CAAA;CACxB;AAED,MAAM,WAAW,iBAAiB;IAChC;;OAEG;IACH,SAAS,EAAE,WAAW,CAAA;IAEtB;;OAEG;IACH,OAAO,CAAC,EAAE,CAAC,KAAK,EAAE,GAAG,KAAK,IAAI,CAAA;CAC/B;AAiCD;;;GAGG;AACH,eAAO,MAAM,YAAY,EAAE,SAAS,CAAC,iBAAiB,CAkDrD,CAAA;AAED,eAAe,YAAY,CAAA"}
@@ -0,0 +1,82 @@
1
+ import { getNextElement, template, insert, createComponent, effect, style, setAttribute } from "solid-js/web";
2
+ import { createMemo, For } from "solid-js";
3
+ import { UIResourceRenderer } from "./UIResourceRenderer.js";
4
+ var _tmpl$ = /* @__PURE__ */ template(`<div class="w-full h-full bg-white dark:bg-gray-800 rounded-lg shadow-sm border border-gray-200 dark:border-gray-700 overflow-hidden"data-component-type=grid><div class="p-4 h-full">`), _tmpl$2 = /* @__PURE__ */ template(`<div class="min-w-0 h-full">`);
5
+ function getGridItemStyle(position, areas) {
6
+ if (!position) {
7
+ return "grid-column: 1 / -1; grid-row: auto";
8
+ }
9
+ const {
10
+ colStart,
11
+ colSpan,
12
+ rowStart,
13
+ rowSpan = 1
14
+ } = position;
15
+ let style2 = `grid-column: ${colStart} / span ${colSpan}`;
16
+ if (rowStart) {
17
+ style2 += `; grid-row: ${rowStart} / span ${rowSpan}`;
18
+ } else {
19
+ style2 += "; grid-row: auto";
20
+ }
21
+ return style2;
22
+ }
23
+ function buildGridTemplateAreas(areas) {
24
+ return areas.map((row) => `"${row.join(" ")}"`).join(" ");
25
+ }
26
+ const GridRenderer = (props) => {
27
+ const params = createMemo(() => {
28
+ const p = props.component.params;
29
+ return {
30
+ columns: p.columns ?? 12,
31
+ gap: p.gap ?? "1rem",
32
+ minRowHeight: p.minRowHeight,
33
+ areas: p.areas,
34
+ children: p.children ?? []
35
+ };
36
+ });
37
+ const gridContainerStyle = createMemo(() => {
38
+ const p = params();
39
+ let style2 = `display: grid; grid-template-columns: repeat(${p.columns}, 1fr); gap: ${p.gap}`;
40
+ if (p.minRowHeight) {
41
+ style2 += `; grid-auto-rows: minmax(${p.minRowHeight}, auto)`;
42
+ }
43
+ if (p.areas && p.areas.length > 0) {
44
+ style2 += `; grid-template-areas: ${buildGridTemplateAreas(p.areas)}`;
45
+ }
46
+ return style2;
47
+ });
48
+ return (() => {
49
+ var _el$ = getNextElement(_tmpl$), _el$2 = _el$.firstChild;
50
+ insert(_el$2, createComponent(For, {
51
+ get each() {
52
+ return params().children;
53
+ },
54
+ children: (child) => (() => {
55
+ var _el$3 = getNextElement(_tmpl$2);
56
+ insert(_el$3, createComponent(UIResourceRenderer, {
57
+ content: child,
58
+ get onError() {
59
+ return props.onError;
60
+ }
61
+ }));
62
+ effect((_$p) => style(_el$3, getGridItemStyle(child.position, params().areas), _$p));
63
+ return _el$3;
64
+ })()
65
+ }));
66
+ effect((_p$) => {
67
+ var _v$ = props.component.id, _v$2 = gridContainerStyle();
68
+ _v$ !== _p$.e && setAttribute(_el$, "data-component-id", _p$.e = _v$);
69
+ _p$.t = style(_el$2, _v$2, _p$.t);
70
+ return _p$;
71
+ }, {
72
+ e: void 0,
73
+ t: void 0
74
+ });
75
+ return _el$;
76
+ })();
77
+ };
78
+ export {
79
+ GridRenderer,
80
+ GridRenderer as default
81
+ };
82
+ //# sourceMappingURL=GridRenderer.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"GridRenderer.js","sources":["../../src/components/GridRenderer.tsx"],"sourcesContent":["/**\n * GridRenderer - CSS Grid layout component for nested layouts\n * Phase 5.0: Quick Wins - Enables template builder layouts\n */\n\nimport { Component, For, createMemo } from 'solid-js'\nimport type { UIComponent, GridPosition } from '../types'\nimport { UIResourceRenderer } from './UIResourceRenderer'\n\n/**\n * Parameters for GridRenderer component\n */\nexport interface GridComponentParams {\n /**\n * Number of columns (default: 12)\n */\n columns?: number\n\n /**\n * Gap between grid items (default: '1rem')\n */\n gap?: string\n\n /**\n * Minimum row height (optional)\n */\n minRowHeight?: string\n\n /**\n * CSS Grid template areas for named regions\n * Example: [['header', 'header'], ['sidebar', 'main'], ['footer', 'footer']]\n */\n areas?: string[][]\n\n /**\n * Child components to render within the grid\n */\n children: UIComponent[]\n}\n\nexport interface GridRendererProps {\n /**\n * Grid component with params\n */\n component: UIComponent\n\n /**\n * Error callback\n */\n onError?: (error: any) => void\n}\n\n/**\n * Convert grid position to CSS style string\n */\nfunction getGridItemStyle(position: GridPosition | undefined, areas?: string[][]): string {\n // Default to full width if no position specified\n if (!position) {\n return 'grid-column: 1 / -1; grid-row: auto'\n }\n\n const { colStart, colSpan, rowStart, rowSpan = 1 } = position\n\n // If using named areas and component has area name, use grid-area\n // Otherwise use explicit grid-column/grid-row\n let style = `grid-column: ${colStart} / span ${colSpan}`\n\n if (rowStart) {\n style += `; grid-row: ${rowStart} / span ${rowSpan}`\n } else {\n style += '; grid-row: auto'\n }\n\n return style\n}\n\n/**\n * Build CSS grid-template-areas string from areas array\n */\nfunction buildGridTemplateAreas(areas: string[][]): string {\n return areas.map((row) => `\"${row.join(' ')}\"`).join(' ')\n}\n\n/**\n * GridRenderer Component\n * Renders a CSS Grid container with nested UIComponents\n */\nexport const GridRenderer: Component<GridRendererProps> = (props) => {\n // Extract params with defaults\n const params = createMemo(() => {\n const p = props.component.params as GridComponentParams\n return {\n columns: p.columns ?? 12,\n gap: p.gap ?? '1rem',\n minRowHeight: p.minRowHeight,\n areas: p.areas,\n children: p.children ?? [],\n }\n })\n\n // Build grid container style\n const gridContainerStyle = createMemo(() => {\n const p = params()\n let style = `display: grid; grid-template-columns: repeat(${p.columns}, 1fr); gap: ${p.gap}`\n\n if (p.minRowHeight) {\n style += `; grid-auto-rows: minmax(${p.minRowHeight}, auto)`\n }\n\n if (p.areas && p.areas.length > 0) {\n style += `; grid-template-areas: ${buildGridTemplateAreas(p.areas)}`\n }\n\n return style\n })\n\n return (\n <div\n class=\"w-full h-full bg-white dark:bg-gray-800 rounded-lg shadow-sm border border-gray-200 dark:border-gray-700 overflow-hidden\"\n data-component-type=\"grid\"\n data-component-id={props.component.id}\n >\n <div class=\"p-4 h-full\" style={gridContainerStyle()}>\n <For each={params().children}>\n {(child) => (\n <div\n style={getGridItemStyle(child.position, params().areas)}\n class=\"min-w-0 h-full\"\n >\n {/* Use UIResourceRenderer for recursive rendering */}\n <UIResourceRenderer content={child} onError={props.onError} />\n </div>\n )}\n </For>\n </div>\n </div>\n )\n}\n\nexport default GridRenderer\n"],"names":["getGridItemStyle","position","areas","colStart","colSpan","rowStart","rowSpan","style","buildGridTemplateAreas","map","row","join","GridRenderer","props","params","createMemo","p","component","columns","gap","minRowHeight","children","gridContainerStyle","length","_el$","_$getNextElement","_tmpl$","_el$2","firstChild","_$insert","_$createComponent","For","each","child","_el$3","_tmpl$2","UIResourceRenderer","content","onError","_$effect","_$p","_$style","_p$","_v$","id","_v$2","e","_$setAttribute","t","undefined"],"mappings":";;;;AAuDA,SAASA,iBAAiBC,UAAoCC,OAA4B;AAExF,MAAI,CAACD,UAAU;AACb,WAAO;AAAA,EACT;AAEA,QAAM;AAAA,IAAEE;AAAAA,IAAUC;AAAAA,IAASC;AAAAA,IAAUC,UAAU;AAAA,EAAA,IAAML;AAIrD,MAAIM,SAAQ,gBAAgBJ,QAAQ,WAAWC,OAAO;AAEtD,MAAIC,UAAU;AACZE,IAAAA,UAAS,eAAeF,QAAQ,WAAWC,OAAO;AAAA,EACpD,OAAO;AACLC,IAAAA,UAAS;AAAA,EACX;AAEA,SAAOA;AACT;AAKA,SAASC,uBAAuBN,OAA2B;AACzD,SAAOA,MAAMO,IAAKC,CAAAA,QAAQ,IAAIA,IAAIC,KAAK,GAAG,CAAC,GAAG,EAAEA,KAAK,GAAG;AAC1D;AAMO,MAAMC,eAA8CC,CAAAA,UAAU;AAEnE,QAAMC,SAASC,WAAW,MAAM;AAC9B,UAAMC,IAAIH,MAAMI,UAAUH;AAC1B,WAAO;AAAA,MACLI,SAASF,EAAEE,WAAW;AAAA,MACtBC,KAAKH,EAAEG,OAAO;AAAA,MACdC,cAAcJ,EAAEI;AAAAA,MAChBlB,OAAOc,EAAEd;AAAAA,MACTmB,UAAUL,EAAEK,YAAY,CAAA;AAAA,IAAA;AAAA,EAE5B,CAAC;AAGD,QAAMC,qBAAqBP,WAAW,MAAM;AAC1C,UAAMC,IAAIF,OAAAA;AACV,QAAIP,SAAQ,gDAAgDS,EAAEE,OAAO,gBAAgBF,EAAEG,GAAG;AAE1F,QAAIH,EAAEI,cAAc;AAClBb,MAAAA,UAAS,4BAA4BS,EAAEI,YAAY;AAAA,IACrD;AAEA,QAAIJ,EAAEd,SAASc,EAAEd,MAAMqB,SAAS,GAAG;AACjChB,MAAAA,UAAS,0BAA0BC,uBAAuBQ,EAAEd,KAAK,CAAC;AAAA,IACpE;AAEA,WAAOK;AAAAA,EACT,CAAC;AAED,UAAA,MAAA;AAAA,QAAAiB,OAAAC,eAAAC,MAAA,GAAAC,QAAAH,KAAAI;AAAAC,WAAAF,OAAAG,gBAOOC,KAAG;AAAA,MAAA,IAACC,OAAI;AAAA,eAAElB,SAASO;AAAAA,MAAQ;AAAA,MAAAA,UACxBY,YAAK,MAAA;AAAA,YAAAC,QAAAT,eAAAU,OAAA;AAAAN,eAAAK,OAAAJ,gBAMFM,oBAAkB;AAAA,UAACC,SAASJ;AAAAA,UAAK,IAAEK,UAAO;AAAA,mBAAEzB,MAAMyB;AAAAA,UAAO;AAAA,QAAA,CAAA,CAAA;AAAAC,eAAAC,CAAAA,QAAAC,MAAAP,OAJnDlC,iBAAiBiC,MAAMhC,UAAUa,OAAAA,EAASZ,KAAK,GAACsC,GAAA,CAAA;AAAA,eAAAN;AAAAA,MAAA,GAAA;AAAA,IAAA,CAM1D,CAAA;AAAAK,WAAAG,CAAAA,QAAA;AAAA,UAAAC,MAZc9B,MAAMI,UAAU2B,IAAEC,OAENvB,mBAAAA;AAAoBqB,cAAAD,IAAAI,KAAAC,aAAAvB,MAAA,qBAAAkB,IAAAI,IAAAH,GAAA;AAAAD,UAAAM,IAAAP,MAAAd,OAAAkB,MAAAH,IAAAM,CAAA;AAAA,aAAAN;AAAAA,IAAA,GAAA;AAAA,MAAAI,GAAAG;AAAAA,MAAAD,GAAAC;AAAAA,IAAAA,CAAA;AAAA,WAAAzB;AAAAA,EAAA,GAAA;AAezD;"}