@seed-ship/mcp-ui-solid 6.1.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.
Files changed (36) hide show
  1. package/CHANGELOG.md +65 -0
  2. package/dist/components/CarouselRenderer.cjs +41 -30
  3. package/dist/components/CarouselRenderer.cjs.map +1 -1
  4. package/dist/components/CarouselRenderer.d.ts.map +1 -1
  5. package/dist/components/CarouselRenderer.js +42 -31
  6. package/dist/components/CarouselRenderer.js.map +1 -1
  7. package/dist/components/CodeBlockRenderer.cjs +88 -25
  8. package/dist/components/CodeBlockRenderer.cjs.map +1 -1
  9. package/dist/components/CodeBlockRenderer.d.ts.map +1 -1
  10. package/dist/components/CodeBlockRenderer.js +89 -26
  11. package/dist/components/CodeBlockRenderer.js.map +1 -1
  12. package/dist/components/ImageGalleryRenderer.cjs +101 -77
  13. package/dist/components/ImageGalleryRenderer.cjs.map +1 -1
  14. package/dist/components/ImageGalleryRenderer.d.ts.map +1 -1
  15. package/dist/components/ImageGalleryRenderer.js +102 -78
  16. package/dist/components/ImageGalleryRenderer.js.map +1 -1
  17. package/dist/components/MapRenderer.cjs +94 -34
  18. package/dist/components/MapRenderer.cjs.map +1 -1
  19. package/dist/components/MapRenderer.d.ts.map +1 -1
  20. package/dist/components/MapRenderer.js +107 -47
  21. package/dist/components/MapRenderer.js.map +1 -1
  22. package/dist/components/VideoRenderer.cjs +95 -74
  23. package/dist/components/VideoRenderer.cjs.map +1 -1
  24. package/dist/components/VideoRenderer.d.ts.map +1 -1
  25. package/dist/components/VideoRenderer.js +96 -75
  26. package/dist/components/VideoRenderer.js.map +1 -1
  27. package/dist/index.cjs +3 -3
  28. package/dist/index.js +1 -1
  29. package/package.json +1 -1
  30. package/src/components/CarouselRenderer.tsx +9 -1
  31. package/src/components/CodeBlockRenderer.tsx +65 -5
  32. package/src/components/ImageGalleryRenderer.test.tsx +18 -7
  33. package/src/components/ImageGalleryRenderer.tsx +22 -3
  34. package/src/components/MapRenderer.tsx +68 -14
  35. package/src/components/VideoRenderer.tsx +14 -4
  36. package/tsconfig.tsbuildinfo +1 -1
package/CHANGELOG.md CHANGED
@@ -5,6 +5,71 @@ 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
+
8
73
  ## [6.1.0] - 2026-05-03
9
74
 
10
75
  UX consistency / fluidity release. Three small but visible
@@ -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
- var _tmpl$ = /* @__PURE__ */ web.template(`<div class="relative group"><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">`);
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
- var _el$ = web.getNextElement(_tmpl$), _el$2 = _el$.firstChild, _el$3 = _el$2.nextSibling, _el$4 = _el$3.nextSibling;
29
- _el$2.$$click = () => scroll("left");
30
- _el$3.$$click = () => scroll("right");
31
- _el$4.addEventListener("scroll", checkScroll);
32
- var _ref$ = scrollContainer;
33
- typeof _ref$ === "function" ? web.use(_ref$, _el$4) : scrollContainer = _el$4;
34
- web.insert(_el$4, web.createComponent(solidJs.For, {
35
- get each() {
36
- return props.items;
37
- },
38
- children: (item) => (() => {
39
- var _el$5 = web.getNextElement(_tmpl$2), _el$6 = _el$5.firstChild;
40
- web.insert(_el$6, () => renderComponent(item));
41
- return _el$5;
42
- })()
43
- }));
44
- web.effect((_p$) => {
45
- var _v$ = `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$2 = `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"}`;
46
- _v$ !== _p$.e && web.className(_el$2, _p$.e = _v$);
47
- _v$2 !== _p$.t && web.className(_el$3, _p$.t = _v$2);
48
- return _p$;
49
- }, {
50
- e: void 0,
51
- t: void 0
52
- });
53
- web.runHydrationEvents();
54
- return _el$;
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 <div class=\"relative group\">\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 )\n}\n"],"names":["CarouselRenderer","props","scrollContainer","canScrollLeft","setCanScrollLeft","createSignal","canScrollRight","setCanScrollRight","renderComponent","useRenderContext","checkScroll","isServer","scrollLeft","scrollWidth","clientWidth","scroll","direction","scrollAmount","scrollBy","left","behavior","_el$","_$getNextElement","_tmpl$","_el$2","firstChild","_el$3","nextSibling","_el$4","$$click","addEventListener","_ref$","_$use","_$insert","_$createComponent","For","each","items","children","item","_el$5","_tmpl$2","_el$6","_$effect","_p$","_v$","_v$2","e","_$className","t","undefined","_$runHydrationEvents","_$delegateEvents"],"mappings":";;;;;;AAUO,MAAMA,mBAAsDC,CAAAA,UAAU;AACzE,MAAIC;AACJ,QAAM,CAACC,eAAeC,gBAAgB,IAAIC,QAAAA,aAAa,KAAK;AAC5D,QAAM,CAACC,gBAAgBC,iBAAiB,IAAIF,QAAAA,aAAa,IAAI;AAG7D,QAAM;AAAA,IAAEG;AAAAA,EAAAA,IAAoBC,+BAAAA;AAE5B,QAAMC,cAAcA,MAAM;AACtB,QAAIC,IAAAA,YAAY,CAACT,gBAAiB;AAClCE,qBAAiBF,gBAAgBU,aAAa,CAAC;AAC/CL,sBACIL,gBAAgBU,aAAaV,gBAAgBW,cAAcX,gBAAgBY,cAAc,EAC7F;AAAA,EACJ;AAEA,QAAMC,SAASA,CAACC,cAAgC;AAC5C,QAAIL,IAAAA,YAAY,CAACT,gBAAiB;AAClC,UAAMe,eAAef,gBAAgBY,cAAc;AACnDZ,oBAAgBgB,SAAS;AAAA,MACrBC,MAAMH,cAAc,SAAS,CAACC,eAAeA;AAAAA,MAC7CG,UAAU;AAAA,IAAA,CACb;AAAA,EACL;AAEA,UAAA,MAAA;AAAA,QAAAC,OAAAC,IAAAA,eAAAC,MAAA,GAAAC,QAAAH,KAAAI,YAAAC,QAAAF,MAAAG,aAAAC,QAAAF,MAAAC;AAAAH,UAAAK,UAIqB,MAAMd,OAAO,MAAM;AAACW,UAAAG,UAUpB,MAAMd,OAAO,OAAO;AAACa,UAAAE,iBAAA,UAYpBpB,WAAW;AAAA,QAAAqB,QADhB7B;AAAe,WAAA6B,UAAA,aAAAC,IAAAA,IAAAD,OAAAH,KAAA,IAAf1B,kBAAe0B;AAAAK,eAAAL,OAAAM,IAAAA,gBAKnBC,aAAG;AAAA,MAAA,IAACC,OAAI;AAAA,eAAEnC,MAAMoC;AAAAA,MAAK;AAAA,MAAAC,UAChBC,WAAI,MAAA;AAAA,YAAAC,QAAAlB,IAAAA,eAAAmB,OAAA,GAAAC,QAAAF,MAAAf;AAAAQ,YAAAA,OAAAS,OAAA,MAGOlC,gBAAgB+B,IAAI,CAAC;AAAA,eAAAC;AAAAA,MAAA,GAAA;AAAA,IAAA,CAGjC,CAAA;AAAAG,QAAAA,OAAAC,CAAAA,QAAA;AAAA,UAAAC,MAhCE,4LAA4L1C,cAAAA,IAAkB,sCAAsC,+BAA+B,IACpR2C,OASC,6LAA6LxC,eAAAA,IAAmB,sCAAsC,+BAA+B;AACtRuC,cAAAD,IAAAG,KAAAC,IAAAA,UAAAxB,OAAAoB,IAAAG,IAAAF,GAAA;AAAAC,eAAAF,IAAAK,KAAAD,IAAAA,UAAAtB,OAAAkB,IAAAK,IAAAH,IAAA;AAAA,aAAAF;AAAAA,IAAA,GAAA;AAAA,MAAAG,GAAAG;AAAAA,MAAAD,GAAAC;AAAAA,IAAAA,CAAA;AAAAC,2BAAAA;AAAA,WAAA9B;AAAAA,EAAA,GAAA;AA0BtB;AAAC+B,IAAAA,eAAA,CAAA,OAAA,CAAA;;"}
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;AAE3C,MAAM,WAAW,qBAAqB;IAClC,KAAK,EAAE,WAAW,EAAE,CAAA;IACpB,MAAM,CAAC,EAAE,MAAM,CAAA;CAClB;AAED,eAAO,MAAM,gBAAgB,EAAE,SAAS,CAAC,qBAAqB,CAmE7D,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, createComponent, effect, className, runHydrationEvents, isServer, use } from "solid-js/web";
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
- var _tmpl$ = /* @__PURE__ */ template(`<div class="relative group"><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">`);
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
- var _el$ = getNextElement(_tmpl$), _el$2 = _el$.firstChild, _el$3 = _el$2.nextSibling, _el$4 = _el$3.nextSibling;
27
- _el$2.$$click = () => scroll("left");
28
- _el$3.$$click = () => scroll("right");
29
- _el$4.addEventListener("scroll", checkScroll);
30
- var _ref$ = scrollContainer;
31
- typeof _ref$ === "function" ? use(_ref$, _el$4) : scrollContainer = _el$4;
32
- insert(_el$4, createComponent(For, {
33
- get each() {
34
- return props.items;
35
- },
36
- children: (item) => (() => {
37
- var _el$5 = getNextElement(_tmpl$2), _el$6 = _el$5.firstChild;
38
- insert(_el$6, () => renderComponent(item));
39
- return _el$5;
40
- })()
41
- }));
42
- effect((_p$) => {
43
- var _v$ = `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$2 = `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"}`;
44
- _v$ !== _p$.e && className(_el$2, _p$.e = _v$);
45
- _v$2 !== _p$.t && className(_el$3, _p$.t = _v$2);
46
- return _p$;
47
- }, {
48
- e: void 0,
49
- t: void 0
50
- });
51
- runHydrationEvents();
52
- return _el$;
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 <div class=\"relative group\">\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 )\n}\n"],"names":["CarouselRenderer","props","scrollContainer","canScrollLeft","setCanScrollLeft","createSignal","canScrollRight","setCanScrollRight","renderComponent","useRenderContext","checkScroll","isServer","scrollLeft","scrollWidth","clientWidth","scroll","direction","scrollAmount","scrollBy","left","behavior","_el$","_$getNextElement","_tmpl$","_el$2","firstChild","_el$3","nextSibling","_el$4","$$click","addEventListener","_ref$","_$use","_$insert","_$createComponent","For","each","items","children","item","_el$5","_tmpl$2","_el$6","_$effect","_p$","_v$","_v$2","e","_$className","t","undefined","_$runHydrationEvents","_$delegateEvents"],"mappings":";;;;AAUO,MAAMA,mBAAsDC,CAAAA,UAAU;AACzE,MAAIC;AACJ,QAAM,CAACC,eAAeC,gBAAgB,IAAIC,aAAa,KAAK;AAC5D,QAAM,CAACC,gBAAgBC,iBAAiB,IAAIF,aAAa,IAAI;AAG7D,QAAM;AAAA,IAAEG;AAAAA,EAAAA,IAAoBC,iBAAAA;AAE5B,QAAMC,cAAcA,MAAM;AACtB,QAAIC,YAAY,CAACT,gBAAiB;AAClCE,qBAAiBF,gBAAgBU,aAAa,CAAC;AAC/CL,sBACIL,gBAAgBU,aAAaV,gBAAgBW,cAAcX,gBAAgBY,cAAc,EAC7F;AAAA,EACJ;AAEA,QAAMC,SAASA,CAACC,cAAgC;AAC5C,QAAIL,YAAY,CAACT,gBAAiB;AAClC,UAAMe,eAAef,gBAAgBY,cAAc;AACnDZ,oBAAgBgB,SAAS;AAAA,MACrBC,MAAMH,cAAc,SAAS,CAACC,eAAeA;AAAAA,MAC7CG,UAAU;AAAA,IAAA,CACb;AAAA,EACL;AAEA,UAAA,MAAA;AAAA,QAAAC,OAAAC,eAAAC,MAAA,GAAAC,QAAAH,KAAAI,YAAAC,QAAAF,MAAAG,aAAAC,QAAAF,MAAAC;AAAAH,UAAAK,UAIqB,MAAMd,OAAO,MAAM;AAACW,UAAAG,UAUpB,MAAMd,OAAO,OAAO;AAACa,UAAAE,iBAAA,UAYpBpB,WAAW;AAAA,QAAAqB,QADhB7B;AAAe,WAAA6B,UAAA,aAAAC,IAAAD,OAAAH,KAAA,IAAf1B,kBAAe0B;AAAAK,WAAAL,OAAAM,gBAKnBC,KAAG;AAAA,MAAA,IAACC,OAAI;AAAA,eAAEnC,MAAMoC;AAAAA,MAAK;AAAA,MAAAC,UAChBC,WAAI,MAAA;AAAA,YAAAC,QAAAlB,eAAAmB,OAAA,GAAAC,QAAAF,MAAAf;AAAAQ,eAAAS,OAAA,MAGOlC,gBAAgB+B,IAAI,CAAC;AAAA,eAAAC;AAAAA,MAAA,GAAA;AAAA,IAAA,CAGjC,CAAA;AAAAG,WAAAC,CAAAA,QAAA;AAAA,UAAAC,MAhCE,4LAA4L1C,cAAAA,IAAkB,sCAAsC,+BAA+B,IACpR2C,OASC,6LAA6LxC,eAAAA,IAAmB,sCAAsC,+BAA+B;AACtRuC,cAAAD,IAAAG,KAAAC,UAAAxB,OAAAoB,IAAAG,IAAAF,GAAA;AAAAC,eAAAF,IAAAK,KAAAD,UAAAtB,OAAAkB,IAAAK,IAAAH,IAAA;AAAA,aAAAF;AAAAA,IAAA,GAAA;AAAA,MAAAG,GAAAG;AAAAA,MAAAD,GAAAC;AAAAA,IAAAA,CAAA;AAAAC,uBAAAA;AAAA,WAAA9B;AAAAA,EAAA,GAAA;AA0BtB;AAAC+B,eAAA,CAAA,OAAA,CAAA;"}
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;"}
@@ -3,7 +3,37 @@ 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 ExpandableWrapper = require("./ExpandableWrapper.cjs");
6
- var _tmpl$ = /* @__PURE__ */ web.template(`<svg class="w-4 h-4 text-green-500"fill=none viewBox="0 0 24 24"stroke=currentColor><path stroke-linecap=round stroke-linejoin=round stroke-width=2 d="M5 13l4 4L19 7">`), _tmpl$2 = /* @__PURE__ */ web.template(`<div class="flex-none text-right select-none bg-gray-100 dark:bg-gray-800 border-r border-gray-200 dark:border-gray-700 py-4 px-2 text-gray-400 font-mono text-xs leading-5">`), _tmpl$3 = /* @__PURE__ */ web.template(`<div class="w-full bg-gray-50 dark:bg-gray-900 rounded-lg border border-gray-200 dark:border-gray-700 overflow-hidden text-sm flex flex-col"><div class="flex items-center justify-between px-4 py-2 bg-gray-100 dark:bg-gray-800 border-b border-gray-200 dark:border-gray-700 shrink-0"><div class="font-mono text-xs text-gray-600 dark:text-gray-400"></div><div class="flex items-center gap-2"><button aria-label="Toggle word wrap"><svg class="w-4 h-4"fill=none viewBox="0 0 24 24"stroke=currentColor><path stroke-linecap=round stroke-linejoin=round stroke-width=2 d="M3 10h10a4 4 0 010 8H9m4 0l-3-3m3 3l-3 3M3 6h18M3 14h4"></path></svg></button><button class="text-gray-500 hover:text-gray-700 dark:text-gray-400 dark:hover:text-gray-200 focus:outline-none transition-colors"aria-label="Copy code"title="Copy code"></button></div></div><div class="relative overflow-auto flex"><!$><!/><pre class="flex-1 m-0 p-4 font-mono text-gray-800 dark:text-gray-100 bg-transparent leading-5"><code>`), _tmpl$4 = /* @__PURE__ */ web.template(`<svg class="w-4 h-4"fill=none viewBox="0 0 24 24"stroke=currentColor><path stroke-linecap=round stroke-linejoin=round stroke-width=2 d="M8 16H6a2 2 0 01-2-2V6a2 2 0 012-2h8a2 2 0 012 2v2m-6 12h8a2 2 0 002-2v-8a2 2 0 00-2-2h-8a2 2 0 00-2 2v8a2 2 0 002 2z">`), _tmpl$5 = /* @__PURE__ */ web.template(`<div class=px-2>`);
6
+ const UIResourceRenderer = require("./UIResourceRenderer.cjs");
7
+ var _tmpl$ = /* @__PURE__ */ web.template(`<svg class="w-4 h-4 text-green-500"fill=none viewBox="0 0 24 24"stroke=currentColor><path stroke-linecap=round stroke-linejoin=round stroke-width=2 d="M5 13l4 4L19 7">`), _tmpl$2 = /* @__PURE__ */ web.template(`<div class="flex-none text-right select-none bg-gray-100 dark:bg-gray-800 border-r border-gray-200 dark:border-gray-700 py-4 px-2 text-gray-400 font-mono text-xs leading-5">`), _tmpl$3 = /* @__PURE__ */ web.template(`<div><div class="flex items-center justify-between px-4 py-2 bg-gray-100 dark:bg-gray-800 border-b border-gray-200 dark:border-gray-700 shrink-0"><div class="font-mono text-xs text-gray-600 dark:text-gray-400"></div><div class="flex items-center gap-2"><input type=text placeholder=Search… class="px-2 py-0.5 text-xs border border-gray-200 dark:border-gray-600 rounded bg-white dark:bg-gray-700 text-gray-900 dark:text-white placeholder-gray-400 focus:border-blue-400 focus:ring-1 focus:ring-blue-400 outline-none w-32"aria-label="Search in code"><button class="text-gray-500 hover:text-gray-700 dark:text-gray-400 dark:hover:text-gray-200 focus:outline-none transition-colors"aria-label="Download code as file"title="Download code"><svg class="w-4 h-4"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"></path></svg></button><button aria-label="Toggle word wrap"><svg class="w-4 h-4"fill=none viewBox="0 0 24 24"stroke=currentColor><path stroke-linecap=round stroke-linejoin=round stroke-width=2 d="M3 10h10a4 4 0 010 8H9m4 0l-3-3m3 3l-3 3M3 6h18M3 14h4"></path></svg></button><button class="text-gray-500 hover:text-gray-700 dark:text-gray-400 dark:hover:text-gray-200 focus:outline-none transition-colors"aria-label="Copy code"title="Copy code"></button></div></div><div><!$><!/><pre class="flex-1 m-0 p-4 font-mono text-gray-800 dark:text-gray-100 bg-transparent leading-5"><code>`), _tmpl$4 = /* @__PURE__ */ web.template(`<svg class="w-4 h-4"fill=none viewBox="0 0 24 24"stroke=currentColor><path stroke-linecap=round stroke-linejoin=round stroke-width=2 d="M8 16H6a2 2 0 01-2-2V6a2 2 0 012-2h8a2 2 0 012 2v2m-6 12h8a2 2 0 002-2v-8a2 2 0 00-2-2h-8a2 2 0 00-2 2v8a2 2 0 002 2z">`), _tmpl$5 = /* @__PURE__ */ web.template(`<div class=px-2>`);
8
+ const LANGUAGE_EXTENSIONS = {
9
+ typescript: "ts",
10
+ tsx: "tsx",
11
+ javascript: "js",
12
+ jsx: "jsx",
13
+ python: "py",
14
+ ruby: "rb",
15
+ go: "go",
16
+ rust: "rs",
17
+ java: "java",
18
+ kotlin: "kt",
19
+ swift: "swift",
20
+ php: "php",
21
+ csharp: "cs",
22
+ cpp: "cpp",
23
+ c: "c",
24
+ sql: "sql",
25
+ json: "json",
26
+ yaml: "yml",
27
+ toml: "toml",
28
+ bash: "sh",
29
+ shell: "sh",
30
+ html: "html",
31
+ css: "css",
32
+ scss: "scss",
33
+ markdown: "md",
34
+ xml: "xml",
35
+ graphql: "graphql"
36
+ };
7
37
  let hljs = null;
8
38
  let stylesLoaded = false;
9
39
  const CodeBlockRenderer = (props) => {
@@ -16,6 +46,32 @@ const CodeBlockRenderer = (props) => {
16
46
  var _a;
17
47
  return props.params || ((_a = props.component) == null ? void 0 : _a.params);
18
48
  };
49
+ const isExpanded = ExpandableWrapper.useExpanded();
50
+ const [searchQuery, setSearchQuery] = solidJs.createSignal("");
51
+ const displayedHTML = () => {
52
+ const q = searchQuery().trim();
53
+ return q ? UIResourceRenderer.highlightQuery(highlightedCode(), q) : highlightedCode();
54
+ };
55
+ const handleDownload = () => {
56
+ var _a, _b, _c;
57
+ const code = (_a = params()) == null ? void 0 : _a.code;
58
+ if (!code) return;
59
+ const lang = (((_b = params()) == null ? void 0 : _b.language) || "").toLowerCase();
60
+ const ext = LANGUAGE_EXTENSIONS[lang] || "txt";
61
+ const stem = (((_c = params()) == null ? void 0 : _c.filename) || `code-${Date.now()}`).replace(/\.[^.]+$/, "");
62
+ const filename = stem.endsWith(`.${ext}`) ? stem : `${stem}.${ext}`;
63
+ const blob = new Blob([code], {
64
+ type: "text/plain"
65
+ });
66
+ const url = URL.createObjectURL(blob);
67
+ const a = document.createElement("a");
68
+ a.href = url;
69
+ a.download = filename;
70
+ document.body.appendChild(a);
71
+ a.click();
72
+ document.body.removeChild(a);
73
+ URL.revokeObjectURL(url);
74
+ };
19
75
  solidJs.createEffect(async () => {
20
76
  if (!hljs) {
21
77
  try {
@@ -119,14 +175,16 @@ const CodeBlockRenderer = (props) => {
119
175
  },
120
176
  copyLabel: "Copy code",
121
177
  get children() {
122
- var _el$ = web.getNextElement(_tmpl$3), _el$2 = _el$.firstChild, _el$3 = _el$2.firstChild, _el$4 = _el$3.nextSibling, _el$5 = _el$4.firstChild, _el$6 = _el$5.nextSibling, _el$8 = _el$2.nextSibling, _el$10 = _el$8.firstChild, [_el$11, _co$] = web.getNextMarker(_el$10.nextSibling), _el$0 = _el$11.nextSibling, _el$1 = _el$0.firstChild;
178
+ var _el$ = web.getNextElement(_tmpl$3), _el$2 = _el$.firstChild, _el$3 = _el$2.firstChild, _el$4 = _el$3.nextSibling, _el$5 = _el$4.firstChild, _el$6 = _el$5.nextSibling, _el$7 = _el$6.nextSibling, _el$8 = _el$7.nextSibling, _el$0 = _el$2.nextSibling, _el$12 = _el$0.firstChild, [_el$13, _co$] = web.getNextMarker(_el$12.nextSibling), _el$10 = _el$13.nextSibling, _el$11 = _el$10.firstChild;
123
179
  web.insert(_el$3, () => {
124
180
  var _a, _b;
125
181
  return ((_a = params()) == null ? void 0 : _a.filename) || ((_b = params()) == null ? void 0 : _b.language) || "Code";
126
182
  });
127
- _el$5.$$click = () => setWordWrap(!wordWrap());
128
- _el$6.$$click = handleCopy;
129
- web.insert(_el$6, web.createComponent(solidJs.Show, {
183
+ _el$5.$$input = (e) => setSearchQuery(e.currentTarget.value);
184
+ _el$6.$$click = handleDownload;
185
+ _el$7.$$click = () => setWordWrap(!wordWrap());
186
+ _el$8.$$click = handleCopy;
187
+ web.insert(_el$8, web.createComponent(solidJs.Show, {
130
188
  get when() {
131
189
  return isCopied();
132
190
  },
@@ -137,41 +195,43 @@ const CodeBlockRenderer = (props) => {
137
195
  return web.getNextElement(_tmpl$);
138
196
  }
139
197
  }));
140
- web.insert(_el$8, web.createComponent(solidJs.Show, {
198
+ web.insert(_el$0, web.createComponent(solidJs.Show, {
141
199
  get when() {
142
200
  var _a;
143
201
  return ((_a = params()) == null ? void 0 : _a.showLineNumbers) !== false;
144
202
  },
145
203
  get children() {
146
- var _el$9 = web.getNextElement(_tmpl$2);
147
- web.insert(_el$9, web.createComponent(solidJs.For, {
204
+ var _el$1 = web.getNextElement(_tmpl$2);
205
+ web.insert(_el$1, web.createComponent(solidJs.For, {
148
206
  get each() {
149
207
  return lineNumbers();
150
208
  },
151
209
  children: (num) => (() => {
152
- var _el$13 = web.getNextElement(_tmpl$5);
153
- web.insert(_el$13, num);
154
- return _el$13;
210
+ var _el$15 = web.getNextElement(_tmpl$5);
211
+ web.insert(_el$15, num);
212
+ return _el$15;
155
213
  })()
156
214
  }));
157
- return _el$9;
215
+ return _el$1;
158
216
  }
159
- }), _el$11, _co$);
217
+ }), _el$13, _co$);
160
218
  web.effect((_p$) => {
161
219
  var _a, _b, _c, _d;
162
- var _v$ = `focus:outline-none transition-colors ${wordWrap() ? "text-blue-500 dark:text-blue-400" : "text-gray-500 hover:text-gray-700 dark:text-gray-400 dark:hover:text-gray-200"}`, _v$2 = wordWrap() ? "Disable word wrap" : "Enable word wrap", _v$3 = ((_a = params()) == null ? void 0 : _a.maxHeight) ? {
220
+ var _v$ = `w-full bg-gray-50 dark:bg-gray-900 rounded-lg border border-gray-200 dark:border-gray-700 overflow-hidden text-sm flex flex-col ${isExpanded() ? "flex-1 min-h-0" : ""}`, _v$2 = `focus:outline-none transition-colors ${wordWrap() ? "text-blue-500 dark:text-blue-400" : "text-gray-500 hover:text-gray-700 dark:text-gray-400 dark:hover:text-gray-200"}`, _v$3 = wordWrap() ? "Disable word wrap" : "Enable word wrap", _v$4 = `relative overflow-auto flex ${isExpanded() ? "flex-1 min-h-0" : ""}`, _v$5 = !isExpanded() && ((_a = params()) == null ? void 0 : _a.maxHeight) ? {
163
221
  "max-height": (_b = params()) == null ? void 0 : _b.maxHeight
164
- } : {}, _v$4 = wordWrap() ? {
222
+ } : {}, _v$6 = wordWrap() ? {
165
223
  "white-space": "pre-wrap",
166
224
  "word-break": "break-all"
167
- } : {}, _v$5 = activeTheme(), _v$6 = `hljs ${((_c = params()) == null ? void 0 : _c.language) ? `language-${(_d = params()) == null ? void 0 : _d.language}` : ""}`, _v$7 = highlightedCode();
168
- _v$ !== _p$.e && web.className(_el$5, _p$.e = _v$);
169
- _v$2 !== _p$.t && web.setAttribute(_el$5, "title", _p$.t = _v$2);
170
- _p$.a = web.style(_el$8, _v$3, _p$.a);
171
- _p$.o = web.style(_el$0, _v$4, _p$.o);
172
- _v$5 !== _p$.i && web.setAttribute(_el$0, "data-theme", _p$.i = _v$5);
173
- _v$6 !== _p$.n && web.className(_el$1, _p$.n = _v$6);
174
- _v$7 !== _p$.s && web.setProperty(_el$1, "innerHTML", _p$.s = _v$7);
225
+ } : {}, _v$7 = activeTheme(), _v$8 = `hljs ${((_c = params()) == null ? void 0 : _c.language) ? `language-${(_d = params()) == null ? void 0 : _d.language}` : ""}`, _v$9 = displayedHTML();
226
+ _v$ !== _p$.e && web.className(_el$, _p$.e = _v$);
227
+ _v$2 !== _p$.t && web.className(_el$7, _p$.t = _v$2);
228
+ _v$3 !== _p$.a && web.setAttribute(_el$7, "title", _p$.a = _v$3);
229
+ _v$4 !== _p$.o && web.className(_el$0, _p$.o = _v$4);
230
+ _p$.i = web.style(_el$0, _v$5, _p$.i);
231
+ _p$.n = web.style(_el$10, _v$6, _p$.n);
232
+ _v$7 !== _p$.s && web.setAttribute(_el$10, "data-theme", _p$.s = _v$7);
233
+ _v$8 !== _p$.h && web.className(_el$11, _p$.h = _v$8);
234
+ _v$9 !== _p$.r && web.setProperty(_el$11, "innerHTML", _p$.r = _v$9);
175
235
  return _p$;
176
236
  }, {
177
237
  e: void 0,
@@ -180,13 +240,16 @@ const CodeBlockRenderer = (props) => {
180
240
  o: void 0,
181
241
  i: void 0,
182
242
  n: void 0,
183
- s: void 0
243
+ s: void 0,
244
+ h: void 0,
245
+ r: void 0
184
246
  });
247
+ web.effect(() => web.setProperty(_el$5, "value", searchQuery()));
185
248
  web.runHydrationEvents();
186
249
  return _el$;
187
250
  }
188
251
  });
189
252
  };
190
- web.delegateEvents(["click"]);
253
+ web.delegateEvents(["input", "click"]);
191
254
  exports.CodeBlockRenderer = CodeBlockRenderer;
192
255
  //# sourceMappingURL=CodeBlockRenderer.cjs.map