@seed-ship/mcp-ui-solid 6.0.0 → 6.2.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.
- package/CHANGELOG.md +176 -0
- package/dist/components/CarouselRenderer.cjs +41 -30
- package/dist/components/CarouselRenderer.cjs.map +1 -1
- package/dist/components/CarouselRenderer.d.ts.map +1 -1
- package/dist/components/CarouselRenderer.js +42 -31
- package/dist/components/CarouselRenderer.js.map +1 -1
- package/dist/components/ChartJSRenderer.cjs +27 -7
- package/dist/components/ChartJSRenderer.cjs.map +1 -1
- package/dist/components/ChartJSRenderer.d.ts.map +1 -1
- package/dist/components/ChartJSRenderer.js +29 -9
- package/dist/components/ChartJSRenderer.js.map +1 -1
- package/dist/components/CodeBlockRenderer.cjs +88 -25
- package/dist/components/CodeBlockRenderer.cjs.map +1 -1
- package/dist/components/CodeBlockRenderer.d.ts.map +1 -1
- package/dist/components/CodeBlockRenderer.js +89 -26
- package/dist/components/CodeBlockRenderer.js.map +1 -1
- package/dist/components/ExpandableWrapper.cjs +1 -1
- package/dist/components/ExpandableWrapper.cjs.map +1 -1
- package/dist/components/ExpandableWrapper.d.ts.map +1 -1
- package/dist/components/ExpandableWrapper.js +1 -1
- package/dist/components/ExpandableWrapper.js.map +1 -1
- package/dist/components/GraphRenderer.cjs +7 -4
- package/dist/components/GraphRenderer.cjs.map +1 -1
- package/dist/components/GraphRenderer.d.ts.map +1 -1
- package/dist/components/GraphRenderer.js +8 -5
- package/dist/components/GraphRenderer.js.map +1 -1
- package/dist/components/ImageGalleryRenderer.cjs +101 -77
- package/dist/components/ImageGalleryRenderer.cjs.map +1 -1
- package/dist/components/ImageGalleryRenderer.d.ts.map +1 -1
- package/dist/components/ImageGalleryRenderer.js +102 -78
- package/dist/components/ImageGalleryRenderer.js.map +1 -1
- package/dist/components/MapRenderer.cjs +94 -34
- package/dist/components/MapRenderer.cjs.map +1 -1
- package/dist/components/MapRenderer.d.ts.map +1 -1
- package/dist/components/MapRenderer.js +107 -47
- package/dist/components/MapRenderer.js.map +1 -1
- package/dist/components/UIResourceRenderer.cjs +66 -54
- package/dist/components/UIResourceRenderer.cjs.map +1 -1
- package/dist/components/UIResourceRenderer.d.ts.map +1 -1
- package/dist/components/UIResourceRenderer.js +66 -54
- package/dist/components/UIResourceRenderer.js.map +1 -1
- package/dist/components/VideoRenderer.cjs +95 -74
- package/dist/components/VideoRenderer.cjs.map +1 -1
- package/dist/components/VideoRenderer.d.ts.map +1 -1
- package/dist/components/VideoRenderer.js +96 -75
- package/dist/components/VideoRenderer.js.map +1 -1
- package/dist/index.cjs +3 -3
- package/dist/index.js +1 -1
- package/package.json +1 -1
- package/src/components/CarouselRenderer.tsx +9 -1
- package/src/components/ChartJSRenderer.tsx +30 -8
- package/src/components/CodeBlockRenderer.tsx +65 -5
- package/src/components/ExpandableWrapper.tsx +7 -2
- package/src/components/GraphRenderer.tsx +13 -4
- package/src/components/ImageGalleryRenderer.test.tsx +18 -7
- package/src/components/ImageGalleryRenderer.tsx +22 -3
- package/src/components/MapRenderer.tsx +68 -14
- package/src/components/UIResourceRenderer.fluidity.test.tsx +101 -0
- package/src/components/UIResourceRenderer.tsx +23 -9
- package/src/components/VideoRenderer.tsx +14 -4
- package/tsconfig.tsbuildinfo +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -5,6 +5,182 @@ 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
|
+
## [6.2.0] - 2026-05-03
|
|
9
|
+
|
|
10
|
+
Cross-renderer fluidity audit — completes the work started in v6.1.0
|
|
11
|
+
across 5 more renderers. Same UX pattern : `<ExpandableWrapper>` for
|
|
12
|
+
fullscreen, copy data via the modal-header copy button, responsive
|
|
13
|
+
expanded mode, format-specific export when relevant.
|
|
14
|
+
|
|
15
|
+
### Added — fullscreen + copy/export on 4 more renderers
|
|
16
|
+
|
|
17
|
+
- **`<MapRenderer>`** : wrapped in `<ExpandableWrapper>`. Copy data
|
|
18
|
+
exports markers as a **GeoJSON FeatureCollection** (`{ type:
|
|
19
|
+
'FeatureCollection', features: [...] }`). Both `[lat, lng]` tuple and
|
|
20
|
+
`{lat, lng}` object marker positions are normalized. When toggled
|
|
21
|
+
to fullscreen, the Leaflet container is given a tick to reflow then
|
|
22
|
+
`mapInstance.invalidateSize()` is called so tiles re-render at the
|
|
23
|
+
new size.
|
|
24
|
+
- **`<VideoRenderer>`** : wrapped, copy = video URL. Aspect ratio
|
|
25
|
+
preserved inline ; when expanded, the container fills (aspect
|
|
26
|
+
override) so the video occupies the modal.
|
|
27
|
+
- **`<CarouselRenderer>`** : wrapped, copy = items as JSON. When
|
|
28
|
+
expanded, the carousel fills the modal vertically (items keep their
|
|
29
|
+
horizontal scroll-snap layout, more visible at fullscreen size).
|
|
30
|
+
- **`<ImageGalleryRenderer>`** : wrapped, copy = newline-separated
|
|
31
|
+
URL list (with captions when present, tab-separated). When
|
|
32
|
+
expanded, the gallery grid fills the modal and gets its own
|
|
33
|
+
internal scroll instead of the modal scrolling.
|
|
34
|
+
|
|
35
|
+
### Added — `<CodeBlockRenderer>` search + download
|
|
36
|
+
|
|
37
|
+
- **Search input** in the header — incremental highlight via the same
|
|
38
|
+
`highlightQuery` helper `<TableRenderer>` uses. Wraps `<mark>`
|
|
39
|
+
around matches in the already-syntax-highlighted HTML output (no
|
|
40
|
+
conflict with hljs spans).
|
|
41
|
+
- **Download button** in the header — saves the code as a file with
|
|
42
|
+
the right extension picked from `params.language` (covers ts/tsx,
|
|
43
|
+
js/jsx, py, rb, go, rs, java, kt, swift, php, cs, cpp, c, sql,
|
|
44
|
+
json, yml, toml, sh, html, css, scss, md, xml, graphql ; falls
|
|
45
|
+
back to `.txt`). Filename uses `params.filename` when present,
|
|
46
|
+
else `code-<timestamp>.<ext>`.
|
|
47
|
+
- Responsive expanded mode : the code area drops its `maxHeight` and
|
|
48
|
+
uses `flex-1 min-h-0` so the syntax-highlighted code fills the
|
|
49
|
+
modal vertically with internal scroll.
|
|
50
|
+
|
|
51
|
+
### Tests
|
|
52
|
+
|
|
53
|
+
- `ImageGalleryRenderer.test.tsx` — 2 existing button-count tests
|
|
54
|
+
updated to filter by class so they ignore the new
|
|
55
|
+
`<ExpandableWrapper>` expand button (was counting all buttons).
|
|
56
|
+
- All v6.1.0 tests untouched. Total : 583 passed / 1 skipped / 584.
|
|
57
|
+
|
|
58
|
+
### Non-breaking
|
|
59
|
+
|
|
60
|
+
- All v6.1.0 APIs unchanged.
|
|
61
|
+
- All renderers accept the same params as before. Apps that didn't
|
|
62
|
+
use the expand / copy / search / download features see no
|
|
63
|
+
behavior change.
|
|
64
|
+
|
|
65
|
+
### What's NOT in this release
|
|
66
|
+
|
|
67
|
+
- ImageGallery ZIP-all download (would add JSZip dep — heavy).
|
|
68
|
+
- Map PNG snapshot export (would add leaflet-image plugin — heavy).
|
|
69
|
+
- ImageGallery / Map / Video search (low ROI vs other priorities).
|
|
70
|
+
|
|
71
|
+
These can come in v6.3.0+ if user demand surfaces.
|
|
72
|
+
|
|
73
|
+
## [6.1.0] - 2026-05-03
|
|
74
|
+
|
|
75
|
+
UX consistency / fluidity release. Three small but visible
|
|
76
|
+
behaviors that were inconsistent across renderers : fullscreen sizing,
|
|
77
|
+
chart export discoverability, table search discoverability.
|
|
78
|
+
|
|
79
|
+
### Fixed — fullscreen sizing for chart, table, graph
|
|
80
|
+
|
|
81
|
+
Pre-v6.1.0 bug : when the user clicked the expand button on a chart /
|
|
82
|
+
table / graph and went fullscreen, the visualization stayed at its
|
|
83
|
+
inline default size (`250px` for chart canvas, `400px` for graph,
|
|
84
|
+
`max-height: 400px` for non-virtualized tables, `500px` for
|
|
85
|
+
virtualized) instead of filling the modal. Tables in particular added
|
|
86
|
+
an inner scroll bar at less than half of the available modal height.
|
|
87
|
+
|
|
88
|
+
Cause : renderers had hard-coded heights and did not subscribe to
|
|
89
|
+
`useExpanded()` from `<ExpandableWrapper>`.
|
|
90
|
+
|
|
91
|
+
Fix :
|
|
92
|
+
- `<ExpandableWrapper>` modal slot adds `flex flex-col` so aware
|
|
93
|
+
children can opt into `flex-1 min-h-0` to fill vertically. Unaware
|
|
94
|
+
children keep working via the existing `overflow-auto` fallback.
|
|
95
|
+
- `<ChartJSRenderer>` (native canvas) : when expanded, outer card
|
|
96
|
+
becomes `flex-1 min-h-0 flex flex-col`, canvas wrapper drops the
|
|
97
|
+
fixed pixel height for `height: 100%`. Chart.js
|
|
98
|
+
`responsive: true` + `maintainAspectRatio: false` (already set)
|
|
99
|
+
triggers redraw on container resize.
|
|
100
|
+
- `<TableRenderer>` : when expanded, the wrapping card and inner
|
|
101
|
+
padding container both become flex columns, the scroll container
|
|
102
|
+
drops its `max-height` and uses `flex-1 min-h-0` to fill — so the
|
|
103
|
+
internal table body scroll happens inside the visualization, not
|
|
104
|
+
on the modal.
|
|
105
|
+
- `<GraphRenderer>` : same pattern as chart — outer card flex-fills,
|
|
106
|
+
G6 canvas container becomes `height: 100%` when expanded. G6
|
|
107
|
+
resize listener picks up the new size automatically.
|
|
108
|
+
|
|
109
|
+
Inline mode (not expanded) is **unchanged** — same heights, same
|
|
110
|
+
scroll heuristics as before.
|
|
111
|
+
|
|
112
|
+
### Changed — table search input default-on
|
|
113
|
+
|
|
114
|
+
`<TableRenderer>` : the search input was opt-in via `searchable: true`
|
|
115
|
+
or auto-shown only when rows > 10. Now visible by default :
|
|
116
|
+
|
|
117
|
+
```ts
|
|
118
|
+
// before — search hidden on small tables
|
|
119
|
+
const isSearchable = () =>
|
|
120
|
+
tableParams.searchable === true ||
|
|
121
|
+
(tableParams.searchable !== false && allRows().length > 10)
|
|
122
|
+
|
|
123
|
+
// v6.1.0 — opt-out only
|
|
124
|
+
const isSearchable = () => tableParams.searchable !== false
|
|
125
|
+
```
|
|
126
|
+
|
|
127
|
+
Backward compat : explicit `searchable: false` still hides the input.
|
|
128
|
+
Tables with `searchable: true` (was already on) unchanged. The change
|
|
129
|
+
only affects tables with no `searchable` prop and ≤ 10 rows — they
|
|
130
|
+
now show search.
|
|
131
|
+
|
|
132
|
+
### Changed — chart export button default-on + JSON copy added
|
|
133
|
+
|
|
134
|
+
`<ChartJSRenderer>` : the PNG export button was opt-in via
|
|
135
|
+
`exportable: true`. Now visible by default unless explicitly disabled :
|
|
136
|
+
|
|
137
|
+
```ts
|
|
138
|
+
// before
|
|
139
|
+
<Show when={params().exportable}>
|
|
140
|
+
|
|
141
|
+
// v6.1.0
|
|
142
|
+
<Show when={params().exportable !== false}>
|
|
143
|
+
```
|
|
144
|
+
|
|
145
|
+
Plus a new **copy data (JSON)** button is now wired into the
|
|
146
|
+
`<ExpandableWrapper>` header (visible in the fullscreen modal). Clicks
|
|
147
|
+
copy `{ type, data }` of the chart to the clipboard — useful for
|
|
148
|
+
debugging / re-emitting / sharing in markdown.
|
|
149
|
+
|
|
150
|
+
Backward compat : explicit `exportable: false` still hides the button.
|
|
151
|
+
Charts with `exportable: true` unchanged. Charts with no prop now show
|
|
152
|
+
the button (was hidden).
|
|
153
|
+
|
|
154
|
+
### Tests
|
|
155
|
+
|
|
156
|
+
- `src/components/UIResourceRenderer.fluidity.test.tsx` — **+5 tests**
|
|
157
|
+
covering : search visible by default on small + large tables, search
|
|
158
|
+
hidden when explicitly opted out, chart renders without throwing
|
|
159
|
+
when exportable is undefined or false. Responsive expanded-mode
|
|
160
|
+
tests left to manual verification (the modal Portal subtree is
|
|
161
|
+
awkward to assert in jsdom).
|
|
162
|
+
- All previous 578 tests untouched. Total : **583 passed / 1 skipped /
|
|
163
|
+
584 total**.
|
|
164
|
+
|
|
165
|
+
### Non-breaking
|
|
166
|
+
|
|
167
|
+
- All v6.0.0 APIs unchanged.
|
|
168
|
+
- Apps that were relying on the auto-hide of search / export get them
|
|
169
|
+
shown now — opt out with `searchable: false` / `exportable: false`
|
|
170
|
+
if undesired.
|
|
171
|
+
|
|
172
|
+
### What's NOT in this release (future "after" audit)
|
|
173
|
+
|
|
174
|
+
The user request was scoped to chart + table responsive + the export
|
|
175
|
+
discoverability gaps. A broader cross-renderer audit (map, image-
|
|
176
|
+
gallery, video, code, carousel — for consistent copy/export +
|
|
177
|
+
fullscreen + search behavior) is deferred to a follow-up release.
|
|
178
|
+
Notable known gaps :
|
|
179
|
+
- `<MapRenderer>` is NOT yet wrapped in `<ExpandableWrapper>` (no
|
|
180
|
+
fullscreen, no copy/export).
|
|
181
|
+
- `<ImageGalleryRenderer>`, `<VideoRenderer>`, `<CarouselRenderer>`
|
|
182
|
+
have no integrated copy/export menus.
|
|
183
|
+
|
|
8
184
|
## [6.0.0] - 2026-05-02
|
|
9
185
|
|
|
10
186
|
Major version marker — no API breakage. Bumps to `v6` to signal a
|
|
@@ -3,11 +3,13 @@ Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
|
3
3
|
const web = require("solid-js/web");
|
|
4
4
|
const solidJs = require("solid-js");
|
|
5
5
|
const RenderContext = require("./RenderContext.cjs");
|
|
6
|
-
|
|
6
|
+
const ExpandableWrapper = require("./ExpandableWrapper.cjs");
|
|
7
|
+
var _tmpl$ = /* @__PURE__ */ web.template(`<div><button><svg class="w-5 h-5 text-gray-700 dark:text-gray-300"fill=none viewBox="0 0 24 24"stroke=currentColor><path stroke-linecap=round stroke-linejoin=round stroke-width=2 d="M15 19l-7-7 7-7"></path></svg></button><button><svg class="w-5 h-5 text-gray-700 dark:text-gray-300"fill=none viewBox="0 0 24 24"stroke=currentColor><path stroke-linecap=round stroke-linejoin=round stroke-width=2 d="M9 5l7 7-7 7"></path></svg></button><div class="flex gap-4 overflow-x-auto snap-x snap-mandatory pb-4 scrollbar-hide"style=scroll-behavior:smooth>`), _tmpl$2 = /* @__PURE__ */ web.template(`<div class="flex-none w-[85%] sm:w-[45%] snap-center"><div class="h-full border border-gray-200 dark:border-gray-700 rounded-lg overflow-hidden bg-white dark:bg-gray-800">`);
|
|
7
8
|
const CarouselRenderer = (props) => {
|
|
8
9
|
let scrollContainer;
|
|
9
10
|
const [canScrollLeft, setCanScrollLeft] = solidJs.createSignal(false);
|
|
10
11
|
const [canScrollRight, setCanScrollRight] = solidJs.createSignal(true);
|
|
12
|
+
const isExpanded = ExpandableWrapper.useExpanded();
|
|
11
13
|
const {
|
|
12
14
|
renderComponent
|
|
13
15
|
} = RenderContext.useRenderContext();
|
|
@@ -24,35 +26,44 @@ const CarouselRenderer = (props) => {
|
|
|
24
26
|
behavior: "smooth"
|
|
25
27
|
});
|
|
26
28
|
};
|
|
27
|
-
return (
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
29
|
+
return web.createComponent(ExpandableWrapper.ExpandableWrapper, {
|
|
30
|
+
title: "Carousel",
|
|
31
|
+
get copyData() {
|
|
32
|
+
return JSON.stringify(props.items, null, 2);
|
|
33
|
+
},
|
|
34
|
+
copyLabel: "Copy items (JSON)",
|
|
35
|
+
get children() {
|
|
36
|
+
var _el$ = web.getNextElement(_tmpl$), _el$2 = _el$.firstChild, _el$3 = _el$2.nextSibling, _el$4 = _el$3.nextSibling;
|
|
37
|
+
_el$2.$$click = () => scroll("left");
|
|
38
|
+
_el$3.$$click = () => scroll("right");
|
|
39
|
+
_el$4.addEventListener("scroll", checkScroll);
|
|
40
|
+
var _ref$ = scrollContainer;
|
|
41
|
+
typeof _ref$ === "function" ? web.use(_ref$, _el$4) : scrollContainer = _el$4;
|
|
42
|
+
web.insert(_el$4, web.createComponent(solidJs.For, {
|
|
43
|
+
get each() {
|
|
44
|
+
return props.items;
|
|
45
|
+
},
|
|
46
|
+
children: (item) => (() => {
|
|
47
|
+
var _el$5 = web.getNextElement(_tmpl$2), _el$6 = _el$5.firstChild;
|
|
48
|
+
web.insert(_el$6, () => renderComponent(item));
|
|
49
|
+
return _el$5;
|
|
50
|
+
})()
|
|
51
|
+
}));
|
|
52
|
+
web.effect((_p$) => {
|
|
53
|
+
var _v$ = `relative group ${isExpanded() ? "flex-1 min-h-0 flex flex-col" : ""}`, _v$2 = `absolute left-2 top-1/2 -translate-y-1/2 z-10 p-2 bg-white/80 dark:bg-gray-800/80 backdrop-blur-sm rounded-full shadow-md border border-gray-200 dark:border-gray-700 transition-opacity ${canScrollLeft() ? "opacity-0 group-hover:opacity-100" : "opacity-0 pointer-events-none"}`, _v$3 = `absolute right-2 top-1/2 -translate-y-1/2 z-10 p-2 bg-white/80 dark:bg-gray-800/80 backdrop-blur-sm rounded-full shadow-md border border-gray-200 dark:border-gray-700 transition-opacity ${canScrollRight() ? "opacity-0 group-hover:opacity-100" : "opacity-0 pointer-events-none"}`;
|
|
54
|
+
_v$ !== _p$.e && web.className(_el$, _p$.e = _v$);
|
|
55
|
+
_v$2 !== _p$.t && web.className(_el$2, _p$.t = _v$2);
|
|
56
|
+
_v$3 !== _p$.a && web.className(_el$3, _p$.a = _v$3);
|
|
57
|
+
return _p$;
|
|
58
|
+
}, {
|
|
59
|
+
e: void 0,
|
|
60
|
+
t: void 0,
|
|
61
|
+
a: void 0
|
|
62
|
+
});
|
|
63
|
+
web.runHydrationEvents();
|
|
64
|
+
return _el$;
|
|
65
|
+
}
|
|
66
|
+
});
|
|
56
67
|
};
|
|
57
68
|
web.delegateEvents(["click"]);
|
|
58
69
|
exports.CarouselRenderer = CarouselRenderer;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"CarouselRenderer.cjs","sources":["../../src/components/CarouselRenderer.tsx"],"sourcesContent":["import { Component, For, createSignal } from 'solid-js'\nimport { isServer } from 'solid-js/web'\nimport { useRenderContext } from './RenderContext'\nimport type { UIComponent } from '../types'\n\nexport interface CarouselRendererProps {\n items: UIComponent[]\n height?: string\n}\n\nexport const CarouselRenderer: Component<CarouselRendererProps> = (props) => {\n let scrollContainer: HTMLDivElement | undefined\n const [canScrollLeft, setCanScrollLeft] = createSignal(false)\n const [canScrollRight, setCanScrollRight] = createSignal(true)\n\n // Use render context to avoid circular dependency\n const { renderComponent } = useRenderContext()\n\n const checkScroll = () => {\n if (isServer || !scrollContainer) return\n setCanScrollLeft(scrollContainer.scrollLeft > 0)\n setCanScrollRight(\n scrollContainer.scrollLeft < scrollContainer.scrollWidth - scrollContainer.clientWidth - 10\n )\n }\n\n const scroll = (direction: 'left' | 'right') => {\n if (isServer || !scrollContainer) return\n const scrollAmount = scrollContainer.clientWidth * 0.8\n scrollContainer.scrollBy({\n left: direction === 'left' ? -scrollAmount : scrollAmount,\n behavior: 'smooth'\n })\n }\n\n return (\n <
|
|
1
|
+
{"version":3,"file":"CarouselRenderer.cjs","sources":["../../src/components/CarouselRenderer.tsx"],"sourcesContent":["import { Component, For, createSignal } from 'solid-js'\nimport { isServer } from 'solid-js/web'\nimport { useRenderContext } from './RenderContext'\nimport type { UIComponent } from '../types'\nimport { ExpandableWrapper, useExpanded } from './ExpandableWrapper'\n\nexport interface CarouselRendererProps {\n items: UIComponent[]\n height?: string\n}\n\nexport const CarouselRenderer: Component<CarouselRendererProps> = (props) => {\n let scrollContainer: HTMLDivElement | undefined\n const [canScrollLeft, setCanScrollLeft] = createSignal(false)\n const [canScrollRight, setCanScrollRight] = createSignal(true)\n const isExpanded = useExpanded()\n\n // Use render context to avoid circular dependency\n const { renderComponent } = useRenderContext()\n\n const checkScroll = () => {\n if (isServer || !scrollContainer) return\n setCanScrollLeft(scrollContainer.scrollLeft > 0)\n setCanScrollRight(\n scrollContainer.scrollLeft < scrollContainer.scrollWidth - scrollContainer.clientWidth - 10\n )\n }\n\n const scroll = (direction: 'left' | 'right') => {\n if (isServer || !scrollContainer) return\n const scrollAmount = scrollContainer.clientWidth * 0.8\n scrollContainer.scrollBy({\n left: direction === 'left' ? -scrollAmount : scrollAmount,\n behavior: 'smooth'\n })\n }\n\n return (\n <ExpandableWrapper\n title={'Carousel'}\n copyData={JSON.stringify(props.items, null, 2)}\n copyLabel=\"Copy items (JSON)\"\n >\n <div class={`relative group ${isExpanded() ? 'flex-1 min-h-0 flex flex-col' : ''}`}>\n {/* Navigation Buttons */}\n <button\n onClick={() => scroll('left')}\n class={`absolute left-2 top-1/2 -translate-y-1/2 z-10 p-2 bg-white/80 dark:bg-gray-800/80 backdrop-blur-sm rounded-full shadow-md border border-gray-200 dark:border-gray-700 transition-opacity ${canScrollLeft() ? 'opacity-0 group-hover:opacity-100' : 'opacity-0 pointer-events-none'\n }`}\n >\n <svg class=\"w-5 h-5 text-gray-700 dark:text-gray-300\" fill=\"none\" viewBox=\"0 0 24 24\" stroke=\"currentColor\">\n <path stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"2\" d=\"M15 19l-7-7 7-7\" />\n </svg>\n </button>\n\n <button\n onClick={() => scroll('right')}\n class={`absolute right-2 top-1/2 -translate-y-1/2 z-10 p-2 bg-white/80 dark:bg-gray-800/80 backdrop-blur-sm rounded-full shadow-md border border-gray-200 dark:border-gray-700 transition-opacity ${canScrollRight() ? 'opacity-0 group-hover:opacity-100' : 'opacity-0 pointer-events-none'\n }`}\n >\n <svg class=\"w-5 h-5 text-gray-700 dark:text-gray-300\" fill=\"none\" viewBox=\"0 0 24 24\" stroke=\"currentColor\">\n <path stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"2\" d=\"M9 5l7 7-7 7\" />\n </svg>\n </button>\n\n {/* Scroll Container */}\n <div\n ref={scrollContainer}\n onScroll={checkScroll}\n class=\"flex gap-4 overflow-x-auto snap-x snap-mandatory pb-4 scrollbar-hide\"\n style={{ \"scroll-behavior\": \"smooth\" }}\n >\n <For each={props.items}>\n {(item) => (\n <div class=\"flex-none w-[85%] sm:w-[45%] snap-center\">\n <div class=\"h-full border border-gray-200 dark:border-gray-700 rounded-lg overflow-hidden bg-white dark:bg-gray-800\">\n {renderComponent(item)}\n </div>\n </div>\n )}\n </For>\n </div>\n </div>\n </ExpandableWrapper>\n )\n}\n"],"names":["CarouselRenderer","props","scrollContainer","canScrollLeft","setCanScrollLeft","createSignal","canScrollRight","setCanScrollRight","isExpanded","useExpanded","renderComponent","useRenderContext","checkScroll","isServer","scrollLeft","scrollWidth","clientWidth","scroll","direction","scrollAmount","scrollBy","left","behavior","_$createComponent","ExpandableWrapper","title","copyData","JSON","stringify","items","copyLabel","children","_el$","_$getNextElement","_tmpl$","_el$2","firstChild","_el$3","nextSibling","_el$4","$$click","addEventListener","_ref$","_$use","_$insert","For","each","item","_el$5","_tmpl$2","_el$6","_$effect","_p$","_v$","_v$2","_v$3","e","_$className","t","a","undefined","_$runHydrationEvents","_$delegateEvents"],"mappings":";;;;;;;AAWO,MAAMA,mBAAsDC,CAAAA,UAAU;AACzE,MAAIC;AACJ,QAAM,CAACC,eAAeC,gBAAgB,IAAIC,QAAAA,aAAa,KAAK;AAC5D,QAAM,CAACC,gBAAgBC,iBAAiB,IAAIF,QAAAA,aAAa,IAAI;AAC7D,QAAMG,aAAaC,kBAAAA,YAAAA;AAGnB,QAAM;AAAA,IAAEC;AAAAA,EAAAA,IAAoBC,+BAAAA;AAE5B,QAAMC,cAAcA,MAAM;AACtB,QAAIC,IAAAA,YAAY,CAACX,gBAAiB;AAClCE,qBAAiBF,gBAAgBY,aAAa,CAAC;AAC/CP,sBACIL,gBAAgBY,aAAaZ,gBAAgBa,cAAcb,gBAAgBc,cAAc,EAC7F;AAAA,EACJ;AAEA,QAAMC,SAASA,CAACC,cAAgC;AAC5C,QAAIL,IAAAA,YAAY,CAACX,gBAAiB;AAClC,UAAMiB,eAAejB,gBAAgBc,cAAc;AACnDd,oBAAgBkB,SAAS;AAAA,MACrBC,MAAMH,cAAc,SAAS,CAACC,eAAeA;AAAAA,MAC7CG,UAAU;AAAA,IAAA,CACb;AAAA,EACL;AAEA,SAAAC,IAAAA,gBACKC,kBAAAA,mBAAiB;AAAA,IACdC,OAAO;AAAA,IAAU,IACjBC,WAAQ;AAAA,aAAEC,KAAKC,UAAU3B,MAAM4B,OAAO,MAAM,CAAC;AAAA,IAAC;AAAA,IAC9CC,WAAS;AAAA,IAAA,IAAAC,WAAA;AAAA,UAAAC,OAAAC,IAAAA,eAAAC,MAAA,GAAAC,QAAAH,KAAAI,YAAAC,QAAAF,MAAAG,aAAAC,QAAAF,MAAAC;AAAAH,YAAAK,UAKI,MAAMvB,OAAO,MAAM;AAACoB,YAAAG,UAUpB,MAAMvB,OAAO,OAAO;AAACsB,YAAAE,iBAAA,UAYpB7B,WAAW;AAAA,UAAA8B,QADhBxC;AAAe,aAAAwC,UAAA,aAAAC,IAAAA,IAAAD,OAAAH,KAAA,IAAfrC,kBAAeqC;AAAAK,iBAAAL,OAAAhB,IAAAA,gBAKnBsB,aAAG;AAAA,QAAA,IAACC,OAAI;AAAA,iBAAE7C,MAAM4B;AAAAA,QAAK;AAAA,QAAAE,UAChBgB,WAAI,MAAA;AAAA,cAAAC,QAAAf,IAAAA,eAAAgB,OAAA,GAAAC,QAAAF,MAAAZ;AAAAQ,cAAAA,OAAAM,OAAA,MAGOxC,gBAAgBqC,IAAI,CAAC;AAAA,iBAAAC;AAAAA,QAAA,GAAA;AAAA,MAAA,CAGjC,CAAA;AAAAG,UAAAA,OAAAC,CAAAA,QAAA;AAAA,YAAAC,MApCD,kBAAkB7C,WAAAA,IAAe,iCAAiC,EAAE,IAAE8C,OAInE,4LAA4LnD,kBAAkB,sCAAsC,+BAA+B,IACpRoD,OASC,6LAA6LjD,eAAAA,IAAmB,sCAAsC,+BAA+B;AACtR+C,gBAAAD,IAAAI,KAAAC,IAAAA,UAAAzB,MAAAoB,IAAAI,IAAAH,GAAA;AAAAC,iBAAAF,IAAAM,KAAAD,IAAAA,UAAAtB,OAAAiB,IAAAM,IAAAJ,IAAA;AAAAC,iBAAAH,IAAAO,KAAAF,IAAAA,UAAApB,OAAAe,IAAAO,IAAAJ,IAAA;AAAA,eAAAH;AAAAA,MAAA,GAAA;AAAA,QAAAI,GAAAI;AAAAA,QAAAF,GAAAE;AAAAA,QAAAD,GAAAC;AAAAA,MAAAA,CAAA;AAAAC,6BAAAA;AAAA,aAAA7B;AAAAA,IAAA;AAAA,EAAA,CAAA;AA2BtB;AAAC8B,IAAAA,eAAA,CAAA,OAAA,CAAA;;"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"CarouselRenderer.d.ts","sourceRoot":"","sources":["../../src/components/CarouselRenderer.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAqB,MAAM,UAAU,CAAA;AAGvD,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,UAAU,CAAA;
|
|
1
|
+
{"version":3,"file":"CarouselRenderer.d.ts","sourceRoot":"","sources":["../../src/components/CarouselRenderer.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAqB,MAAM,UAAU,CAAA;AAGvD,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,UAAU,CAAA;AAG3C,MAAM,WAAW,qBAAqB;IAClC,KAAK,EAAE,WAAW,EAAE,CAAA;IACpB,MAAM,CAAC,EAAE,MAAM,CAAA;CAClB;AAED,eAAO,MAAM,gBAAgB,EAAE,SAAS,CAAC,qBAAqB,CA0E7D,CAAA"}
|
|
@@ -1,11 +1,13 @@
|
|
|
1
|
-
import { delegateEvents, getNextElement, template, insert,
|
|
1
|
+
import { delegateEvents, createComponent, getNextElement, template, insert, effect, className, runHydrationEvents, isServer, use } from "solid-js/web";
|
|
2
2
|
import { createSignal, For } from "solid-js";
|
|
3
3
|
import { useRenderContext } from "./RenderContext.js";
|
|
4
|
-
|
|
4
|
+
import { useExpanded, ExpandableWrapper } from "./ExpandableWrapper.js";
|
|
5
|
+
var _tmpl$ = /* @__PURE__ */ template(`<div><button><svg class="w-5 h-5 text-gray-700 dark:text-gray-300"fill=none viewBox="0 0 24 24"stroke=currentColor><path stroke-linecap=round stroke-linejoin=round stroke-width=2 d="M15 19l-7-7 7-7"></path></svg></button><button><svg class="w-5 h-5 text-gray-700 dark:text-gray-300"fill=none viewBox="0 0 24 24"stroke=currentColor><path stroke-linecap=round stroke-linejoin=round stroke-width=2 d="M9 5l7 7-7 7"></path></svg></button><div class="flex gap-4 overflow-x-auto snap-x snap-mandatory pb-4 scrollbar-hide"style=scroll-behavior:smooth>`), _tmpl$2 = /* @__PURE__ */ template(`<div class="flex-none w-[85%] sm:w-[45%] snap-center"><div class="h-full border border-gray-200 dark:border-gray-700 rounded-lg overflow-hidden bg-white dark:bg-gray-800">`);
|
|
5
6
|
const CarouselRenderer = (props) => {
|
|
6
7
|
let scrollContainer;
|
|
7
8
|
const [canScrollLeft, setCanScrollLeft] = createSignal(false);
|
|
8
9
|
const [canScrollRight, setCanScrollRight] = createSignal(true);
|
|
10
|
+
const isExpanded = useExpanded();
|
|
9
11
|
const {
|
|
10
12
|
renderComponent
|
|
11
13
|
} = useRenderContext();
|
|
@@ -22,35 +24,44 @@ const CarouselRenderer = (props) => {
|
|
|
22
24
|
behavior: "smooth"
|
|
23
25
|
});
|
|
24
26
|
};
|
|
25
|
-
return (
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
27
|
+
return createComponent(ExpandableWrapper, {
|
|
28
|
+
title: "Carousel",
|
|
29
|
+
get copyData() {
|
|
30
|
+
return JSON.stringify(props.items, null, 2);
|
|
31
|
+
},
|
|
32
|
+
copyLabel: "Copy items (JSON)",
|
|
33
|
+
get children() {
|
|
34
|
+
var _el$ = getNextElement(_tmpl$), _el$2 = _el$.firstChild, _el$3 = _el$2.nextSibling, _el$4 = _el$3.nextSibling;
|
|
35
|
+
_el$2.$$click = () => scroll("left");
|
|
36
|
+
_el$3.$$click = () => scroll("right");
|
|
37
|
+
_el$4.addEventListener("scroll", checkScroll);
|
|
38
|
+
var _ref$ = scrollContainer;
|
|
39
|
+
typeof _ref$ === "function" ? use(_ref$, _el$4) : scrollContainer = _el$4;
|
|
40
|
+
insert(_el$4, createComponent(For, {
|
|
41
|
+
get each() {
|
|
42
|
+
return props.items;
|
|
43
|
+
},
|
|
44
|
+
children: (item) => (() => {
|
|
45
|
+
var _el$5 = getNextElement(_tmpl$2), _el$6 = _el$5.firstChild;
|
|
46
|
+
insert(_el$6, () => renderComponent(item));
|
|
47
|
+
return _el$5;
|
|
48
|
+
})()
|
|
49
|
+
}));
|
|
50
|
+
effect((_p$) => {
|
|
51
|
+
var _v$ = `relative group ${isExpanded() ? "flex-1 min-h-0 flex flex-col" : ""}`, _v$2 = `absolute left-2 top-1/2 -translate-y-1/2 z-10 p-2 bg-white/80 dark:bg-gray-800/80 backdrop-blur-sm rounded-full shadow-md border border-gray-200 dark:border-gray-700 transition-opacity ${canScrollLeft() ? "opacity-0 group-hover:opacity-100" : "opacity-0 pointer-events-none"}`, _v$3 = `absolute right-2 top-1/2 -translate-y-1/2 z-10 p-2 bg-white/80 dark:bg-gray-800/80 backdrop-blur-sm rounded-full shadow-md border border-gray-200 dark:border-gray-700 transition-opacity ${canScrollRight() ? "opacity-0 group-hover:opacity-100" : "opacity-0 pointer-events-none"}`;
|
|
52
|
+
_v$ !== _p$.e && className(_el$, _p$.e = _v$);
|
|
53
|
+
_v$2 !== _p$.t && className(_el$2, _p$.t = _v$2);
|
|
54
|
+
_v$3 !== _p$.a && className(_el$3, _p$.a = _v$3);
|
|
55
|
+
return _p$;
|
|
56
|
+
}, {
|
|
57
|
+
e: void 0,
|
|
58
|
+
t: void 0,
|
|
59
|
+
a: void 0
|
|
60
|
+
});
|
|
61
|
+
runHydrationEvents();
|
|
62
|
+
return _el$;
|
|
63
|
+
}
|
|
64
|
+
});
|
|
54
65
|
};
|
|
55
66
|
delegateEvents(["click"]);
|
|
56
67
|
export {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"CarouselRenderer.js","sources":["../../src/components/CarouselRenderer.tsx"],"sourcesContent":["import { Component, For, createSignal } from 'solid-js'\nimport { isServer } from 'solid-js/web'\nimport { useRenderContext } from './RenderContext'\nimport type { UIComponent } from '../types'\n\nexport interface CarouselRendererProps {\n items: UIComponent[]\n height?: string\n}\n\nexport const CarouselRenderer: Component<CarouselRendererProps> = (props) => {\n let scrollContainer: HTMLDivElement | undefined\n const [canScrollLeft, setCanScrollLeft] = createSignal(false)\n const [canScrollRight, setCanScrollRight] = createSignal(true)\n\n // Use render context to avoid circular dependency\n const { renderComponent } = useRenderContext()\n\n const checkScroll = () => {\n if (isServer || !scrollContainer) return\n setCanScrollLeft(scrollContainer.scrollLeft > 0)\n setCanScrollRight(\n scrollContainer.scrollLeft < scrollContainer.scrollWidth - scrollContainer.clientWidth - 10\n )\n }\n\n const scroll = (direction: 'left' | 'right') => {\n if (isServer || !scrollContainer) return\n const scrollAmount = scrollContainer.clientWidth * 0.8\n scrollContainer.scrollBy({\n left: direction === 'left' ? -scrollAmount : scrollAmount,\n behavior: 'smooth'\n })\n }\n\n return (\n <
|
|
1
|
+
{"version":3,"file":"CarouselRenderer.js","sources":["../../src/components/CarouselRenderer.tsx"],"sourcesContent":["import { Component, For, createSignal } from 'solid-js'\nimport { isServer } from 'solid-js/web'\nimport { useRenderContext } from './RenderContext'\nimport type { UIComponent } from '../types'\nimport { ExpandableWrapper, useExpanded } from './ExpandableWrapper'\n\nexport interface CarouselRendererProps {\n items: UIComponent[]\n height?: string\n}\n\nexport const CarouselRenderer: Component<CarouselRendererProps> = (props) => {\n let scrollContainer: HTMLDivElement | undefined\n const [canScrollLeft, setCanScrollLeft] = createSignal(false)\n const [canScrollRight, setCanScrollRight] = createSignal(true)\n const isExpanded = useExpanded()\n\n // Use render context to avoid circular dependency\n const { renderComponent } = useRenderContext()\n\n const checkScroll = () => {\n if (isServer || !scrollContainer) return\n setCanScrollLeft(scrollContainer.scrollLeft > 0)\n setCanScrollRight(\n scrollContainer.scrollLeft < scrollContainer.scrollWidth - scrollContainer.clientWidth - 10\n )\n }\n\n const scroll = (direction: 'left' | 'right') => {\n if (isServer || !scrollContainer) return\n const scrollAmount = scrollContainer.clientWidth * 0.8\n scrollContainer.scrollBy({\n left: direction === 'left' ? -scrollAmount : scrollAmount,\n behavior: 'smooth'\n })\n }\n\n return (\n <ExpandableWrapper\n title={'Carousel'}\n copyData={JSON.stringify(props.items, null, 2)}\n copyLabel=\"Copy items (JSON)\"\n >\n <div class={`relative group ${isExpanded() ? 'flex-1 min-h-0 flex flex-col' : ''}`}>\n {/* Navigation Buttons */}\n <button\n onClick={() => scroll('left')}\n class={`absolute left-2 top-1/2 -translate-y-1/2 z-10 p-2 bg-white/80 dark:bg-gray-800/80 backdrop-blur-sm rounded-full shadow-md border border-gray-200 dark:border-gray-700 transition-opacity ${canScrollLeft() ? 'opacity-0 group-hover:opacity-100' : 'opacity-0 pointer-events-none'\n }`}\n >\n <svg class=\"w-5 h-5 text-gray-700 dark:text-gray-300\" fill=\"none\" viewBox=\"0 0 24 24\" stroke=\"currentColor\">\n <path stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"2\" d=\"M15 19l-7-7 7-7\" />\n </svg>\n </button>\n\n <button\n onClick={() => scroll('right')}\n class={`absolute right-2 top-1/2 -translate-y-1/2 z-10 p-2 bg-white/80 dark:bg-gray-800/80 backdrop-blur-sm rounded-full shadow-md border border-gray-200 dark:border-gray-700 transition-opacity ${canScrollRight() ? 'opacity-0 group-hover:opacity-100' : 'opacity-0 pointer-events-none'\n }`}\n >\n <svg class=\"w-5 h-5 text-gray-700 dark:text-gray-300\" fill=\"none\" viewBox=\"0 0 24 24\" stroke=\"currentColor\">\n <path stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"2\" d=\"M9 5l7 7-7 7\" />\n </svg>\n </button>\n\n {/* Scroll Container */}\n <div\n ref={scrollContainer}\n onScroll={checkScroll}\n class=\"flex gap-4 overflow-x-auto snap-x snap-mandatory pb-4 scrollbar-hide\"\n style={{ \"scroll-behavior\": \"smooth\" }}\n >\n <For each={props.items}>\n {(item) => (\n <div class=\"flex-none w-[85%] sm:w-[45%] snap-center\">\n <div class=\"h-full border border-gray-200 dark:border-gray-700 rounded-lg overflow-hidden bg-white dark:bg-gray-800\">\n {renderComponent(item)}\n </div>\n </div>\n )}\n </For>\n </div>\n </div>\n </ExpandableWrapper>\n )\n}\n"],"names":["CarouselRenderer","props","scrollContainer","canScrollLeft","setCanScrollLeft","createSignal","canScrollRight","setCanScrollRight","isExpanded","useExpanded","renderComponent","useRenderContext","checkScroll","isServer","scrollLeft","scrollWidth","clientWidth","scroll","direction","scrollAmount","scrollBy","left","behavior","_$createComponent","ExpandableWrapper","title","copyData","JSON","stringify","items","copyLabel","children","_el$","_$getNextElement","_tmpl$","_el$2","firstChild","_el$3","nextSibling","_el$4","$$click","addEventListener","_ref$","_$use","_$insert","For","each","item","_el$5","_tmpl$2","_el$6","_$effect","_p$","_v$","_v$2","_v$3","e","_$className","t","a","undefined","_$runHydrationEvents","_$delegateEvents"],"mappings":";;;;;AAWO,MAAMA,mBAAsDC,CAAAA,UAAU;AACzE,MAAIC;AACJ,QAAM,CAACC,eAAeC,gBAAgB,IAAIC,aAAa,KAAK;AAC5D,QAAM,CAACC,gBAAgBC,iBAAiB,IAAIF,aAAa,IAAI;AAC7D,QAAMG,aAAaC,YAAAA;AAGnB,QAAM;AAAA,IAAEC;AAAAA,EAAAA,IAAoBC,iBAAAA;AAE5B,QAAMC,cAAcA,MAAM;AACtB,QAAIC,YAAY,CAACX,gBAAiB;AAClCE,qBAAiBF,gBAAgBY,aAAa,CAAC;AAC/CP,sBACIL,gBAAgBY,aAAaZ,gBAAgBa,cAAcb,gBAAgBc,cAAc,EAC7F;AAAA,EACJ;AAEA,QAAMC,SAASA,CAACC,cAAgC;AAC5C,QAAIL,YAAY,CAACX,gBAAiB;AAClC,UAAMiB,eAAejB,gBAAgBc,cAAc;AACnDd,oBAAgBkB,SAAS;AAAA,MACrBC,MAAMH,cAAc,SAAS,CAACC,eAAeA;AAAAA,MAC7CG,UAAU;AAAA,IAAA,CACb;AAAA,EACL;AAEA,SAAAC,gBACKC,mBAAiB;AAAA,IACdC,OAAO;AAAA,IAAU,IACjBC,WAAQ;AAAA,aAAEC,KAAKC,UAAU3B,MAAM4B,OAAO,MAAM,CAAC;AAAA,IAAC;AAAA,IAC9CC,WAAS;AAAA,IAAA,IAAAC,WAAA;AAAA,UAAAC,OAAAC,eAAAC,MAAA,GAAAC,QAAAH,KAAAI,YAAAC,QAAAF,MAAAG,aAAAC,QAAAF,MAAAC;AAAAH,YAAAK,UAKI,MAAMvB,OAAO,MAAM;AAACoB,YAAAG,UAUpB,MAAMvB,OAAO,OAAO;AAACsB,YAAAE,iBAAA,UAYpB7B,WAAW;AAAA,UAAA8B,QADhBxC;AAAe,aAAAwC,UAAA,aAAAC,IAAAD,OAAAH,KAAA,IAAfrC,kBAAeqC;AAAAK,aAAAL,OAAAhB,gBAKnBsB,KAAG;AAAA,QAAA,IAACC,OAAI;AAAA,iBAAE7C,MAAM4B;AAAAA,QAAK;AAAA,QAAAE,UAChBgB,WAAI,MAAA;AAAA,cAAAC,QAAAf,eAAAgB,OAAA,GAAAC,QAAAF,MAAAZ;AAAAQ,iBAAAM,OAAA,MAGOxC,gBAAgBqC,IAAI,CAAC;AAAA,iBAAAC;AAAAA,QAAA,GAAA;AAAA,MAAA,CAGjC,CAAA;AAAAG,aAAAC,CAAAA,QAAA;AAAA,YAAAC,MApCD,kBAAkB7C,WAAAA,IAAe,iCAAiC,EAAE,IAAE8C,OAInE,4LAA4LnD,kBAAkB,sCAAsC,+BAA+B,IACpRoD,OASC,6LAA6LjD,eAAAA,IAAmB,sCAAsC,+BAA+B;AACtR+C,gBAAAD,IAAAI,KAAAC,UAAAzB,MAAAoB,IAAAI,IAAAH,GAAA;AAAAC,iBAAAF,IAAAM,KAAAD,UAAAtB,OAAAiB,IAAAM,IAAAJ,IAAA;AAAAC,iBAAAH,IAAAO,KAAAF,UAAApB,OAAAe,IAAAO,IAAAJ,IAAA;AAAA,eAAAH;AAAAA,MAAA,GAAA;AAAA,QAAAI,GAAAI;AAAAA,QAAAF,GAAAE;AAAAA,QAAAD,GAAAC;AAAAA,MAAAA,CAAA;AAAAC,yBAAAA;AAAA,aAAA7B;AAAAA,IAAA;AAAA,EAAA,CAAA;AA2BtB;AAAC8B,eAAA,CAAA,OAAA,CAAA;"}
|
|
@@ -25,7 +25,7 @@ Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
|
25
25
|
const web = require("solid-js/web");
|
|
26
26
|
const solidJs = require("solid-js");
|
|
27
27
|
const ExpandableWrapper = require("./ExpandableWrapper.cjs");
|
|
28
|
-
var _tmpl$ = /* @__PURE__ */ web.template(`<h3 class="text-sm font-semibold text-gray-900 dark:text-white">`), _tmpl$2 = /* @__PURE__ */ web.template(`<button class="opacity-0 group-hover:opacity-60 hover:!opacity-100 px-2 py-1 bg-white dark:bg-gray-800 border border-gray-200 dark:border-gray-600 rounded-full hover:bg-gray-100 dark:hover:bg-gray-700 transition-all shadow-sm"title="Download PNG"aria-label="Download chart as PNG"><svg class="w-3 h-3 text-gray-500 dark:text-gray-400"fill=none viewBox="0 0 24 24"stroke=currentColor><path stroke-linecap=round stroke-linejoin=round stroke-width=2 d="M12 10v6m0 0l-3-3m3 3l3-3m2 8H7a2 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">`), _tmpl$3 = /* @__PURE__ */ web.template(`<div class="flex items-center justify-between mb-3"><!$><!/><!$><!/>`), _tmpl$4 = /* @__PURE__ */ web.template(`<div class="absolute inset-0 flex items-center justify-center bg-white/80 dark:bg-gray-800/80"><div class="flex flex-col items-center gap-2"><div class="animate-spin rounded-full h-8 w-8 border-b-2 border-blue-600"></div><span class="text-sm text-gray-500 dark:text-gray-400">Loading chart...`), _tmpl$5 = /* @__PURE__ */ web.template(`<div class="absolute inset-0 flex items-center justify-center p-4 bg-white dark:bg-gray-800"><div class=text-center><div class="inline-flex items-center justify-center w-12 h-12 rounded-full bg-red-100 dark:bg-red-900/20 mb-3"><svg class="w-6 h-6 text-red-600 dark:text-red-400"fill=none viewBox="0 0 24 24"stroke=currentColor><path stroke-linecap=round stroke-linejoin=round stroke-width=2 d="M12 9v2m0 4h.01m-6.938 4h13.856c1.54 0 2.502-1.667 1.732-3L13.732 4c-.77-1.333-2.694-1.333-3.464 0L3.34 16c-.77 1.333.192 3 1.732 3z"></path></svg></div><p class="text-red-600 dark:text-red-400 text-sm font-medium">Chart Error</p><p class="text-gray-600 dark:text-gray-400 text-xs mt-1 max-w-xs">`), _tmpl$6 = /* @__PURE__ */ web.template(`<div
|
|
28
|
+
var _tmpl$ = /* @__PURE__ */ web.template(`<h3 class="text-sm font-semibold text-gray-900 dark:text-white">`), _tmpl$2 = /* @__PURE__ */ web.template(`<button class="opacity-0 group-hover:opacity-60 hover:!opacity-100 px-2 py-1 bg-white dark:bg-gray-800 border border-gray-200 dark:border-gray-600 rounded-full hover:bg-gray-100 dark:hover:bg-gray-700 transition-all shadow-sm"title="Download PNG"aria-label="Download chart as PNG"><svg class="w-3 h-3 text-gray-500 dark:text-gray-400"fill=none viewBox="0 0 24 24"stroke=currentColor><path stroke-linecap=round stroke-linejoin=round stroke-width=2 d="M12 10v6m0 0l-3-3m3 3l3-3m2 8H7a2 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">`), _tmpl$3 = /* @__PURE__ */ web.template(`<div class="flex items-center justify-between mb-3 flex-shrink-0"><!$><!/><!$><!/>`), _tmpl$4 = /* @__PURE__ */ web.template(`<div class="absolute inset-0 flex items-center justify-center bg-white/80 dark:bg-gray-800/80"><div class="flex flex-col items-center gap-2"><div class="animate-spin rounded-full h-8 w-8 border-b-2 border-blue-600"></div><span class="text-sm text-gray-500 dark:text-gray-400">Loading chart...`), _tmpl$5 = /* @__PURE__ */ web.template(`<div class="absolute inset-0 flex items-center justify-center p-4 bg-white dark:bg-gray-800"><div class=text-center><div class="inline-flex items-center justify-center w-12 h-12 rounded-full bg-red-100 dark:bg-red-900/20 mb-3"><svg class="w-6 h-6 text-red-600 dark:text-red-400"fill=none viewBox="0 0 24 24"stroke=currentColor><path stroke-linecap=round stroke-linejoin=round stroke-width=2 d="M12 9v2m0 4h.01m-6.938 4h13.856c1.54 0 2.502-1.667 1.732-3L13.732 4c-.77-1.333-2.694-1.333-3.464 0L3.34 16c-.77 1.333.192 3 1.732 3z"></path></svg></div><p class="text-red-600 dark:text-red-400 text-sm font-medium">Chart Error</p><p class="text-gray-600 dark:text-gray-400 text-xs mt-1 max-w-xs">`), _tmpl$6 = /* @__PURE__ */ web.template(`<div><!$><!/><!$><!/><!$><!/><div><canvas>`);
|
|
29
29
|
let ChartJS = null;
|
|
30
30
|
let chartJSLoadPromise = null;
|
|
31
31
|
const loadChartJS = async () => {
|
|
@@ -55,6 +55,12 @@ const ChartJSRenderer = (props) => {
|
|
|
55
55
|
let canvasRef;
|
|
56
56
|
let chartInstance;
|
|
57
57
|
const params = () => props.component.params;
|
|
58
|
+
const isExpanded = ExpandableWrapper.useExpanded();
|
|
59
|
+
const exportEnabled = () => params().exportable !== false;
|
|
60
|
+
const copyDataJSON = () => JSON.stringify({
|
|
61
|
+
type: params().type,
|
|
62
|
+
data: params().data
|
|
63
|
+
}, null, 2);
|
|
58
64
|
const handleExportPNG = () => {
|
|
59
65
|
if (!canvasRef) return;
|
|
60
66
|
const url = canvasRef.toDataURL("image/png");
|
|
@@ -132,11 +138,15 @@ const ChartJSRenderer = (props) => {
|
|
|
132
138
|
get title() {
|
|
133
139
|
return params().title || "Chart";
|
|
134
140
|
},
|
|
141
|
+
get copyData() {
|
|
142
|
+
return copyDataJSON();
|
|
143
|
+
},
|
|
144
|
+
copyLabel: "Copy chart data (JSON)",
|
|
135
145
|
get children() {
|
|
136
146
|
var _el$ = web.getNextElement(_tmpl$6), _el$15 = _el$.firstChild, [_el$16, _co$3] = web.getNextMarker(_el$15.nextSibling), _el$17 = _el$16.nextSibling, [_el$18, _co$4] = web.getNextMarker(_el$17.nextSibling), _el$19 = _el$18.nextSibling, [_el$20, _co$5] = web.getNextMarker(_el$19.nextSibling), _el$13 = _el$20.nextSibling, _el$14 = _el$13.firstChild;
|
|
137
147
|
web.insert(_el$, web.createComponent(solidJs.Show, {
|
|
138
148
|
get when() {
|
|
139
|
-
return params().title ||
|
|
149
|
+
return params().title || exportEnabled();
|
|
140
150
|
},
|
|
141
151
|
get children() {
|
|
142
152
|
var _el$2 = web.getNextElement(_tmpl$3), _el$5 = _el$2.firstChild, [_el$6, _co$] = web.getNextMarker(_el$5.nextSibling), _el$7 = _el$6.nextSibling, [_el$8, _co$2] = web.getNextMarker(_el$7.nextSibling);
|
|
@@ -152,7 +162,7 @@ const ChartJSRenderer = (props) => {
|
|
|
152
162
|
}), _el$6, _co$);
|
|
153
163
|
web.insert(_el$2, web.createComponent(solidJs.Show, {
|
|
154
164
|
get when() {
|
|
155
|
-
return
|
|
165
|
+
return exportEnabled();
|
|
156
166
|
},
|
|
157
167
|
get children() {
|
|
158
168
|
var _el$4 = web.getNextElement(_tmpl$2);
|
|
@@ -185,13 +195,23 @@ const ChartJSRenderer = (props) => {
|
|
|
185
195
|
var _ref$ = canvasRef;
|
|
186
196
|
typeof _ref$ === "function" ? web.use(_ref$, _el$14) : canvasRef = _el$14;
|
|
187
197
|
web.effect((_p$) => {
|
|
188
|
-
var _v$ =
|
|
189
|
-
|
|
190
|
-
|
|
198
|
+
var _v$ = `relative w-full bg-white dark:bg-gray-800 rounded-lg shadow-sm border border-gray-200 dark:border-gray-700 overflow-hidden p-4 group ${isExpanded() ? "flex-1 min-h-0 flex flex-col" : ""}`, _v$2 = `w-full ${isExpanded() ? "flex-1 min-h-0" : ""}`, _v$3 = error() ? {
|
|
199
|
+
display: "none"
|
|
200
|
+
} : isExpanded() ? {
|
|
201
|
+
height: "100%",
|
|
202
|
+
display: "block"
|
|
203
|
+
} : {
|
|
204
|
+
height: params().height || "250px",
|
|
205
|
+
display: "block"
|
|
206
|
+
};
|
|
207
|
+
_v$ !== _p$.e && web.className(_el$, _p$.e = _v$);
|
|
208
|
+
_v$2 !== _p$.t && web.className(_el$13, _p$.t = _v$2);
|
|
209
|
+
_p$.a = web.style(_el$13, _v$3, _p$.a);
|
|
191
210
|
return _p$;
|
|
192
211
|
}, {
|
|
193
212
|
e: void 0,
|
|
194
|
-
t: void 0
|
|
213
|
+
t: void 0,
|
|
214
|
+
a: void 0
|
|
195
215
|
});
|
|
196
216
|
return _el$;
|
|
197
217
|
}
|