@seed-ship/mcp-ui-solid 4.3.3 → 4.3.5

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 CHANGED
@@ -5,6 +5,26 @@ 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
+ ## [4.3.5] - 2026-04-11
9
+
10
+ ### Fixed — Sticky Table Header on Scroll
11
+ - Table scroll container now has bounded `max-height` (400px chat, 70vh fullscreen) when rows > 8
12
+ - Combined with existing `sticky top-0` thead, header stays visible while scrolling
13
+ - Works in both chat view and fullscreen modal
14
+
15
+ ## [4.3.4] - 2026-04-11
16
+
17
+ ### Added — Context-Aware Table Pagination (chat vs fullscreen)
18
+
19
+ #### `useExpanded` context from ExpandableWrapper
20
+ - ExpandableWrapper now provides `isExpanded` signal via SolidJS context
21
+ - TableRenderer adapts pageSize automatically: compact in chat view, full in expanded view
22
+ - Chat view: `Math.min(10, pageSize)` rows — keeps chat compact
23
+ - Fullscreen: full `pageSize` rows — room to browse
24
+ - Optional `chatPageSize` override (default: `min(10, pageSize)`)
25
+ - Zero server changes needed — just send `pageSize: 20` as before
26
+ - `useExpanded()` hook exported for custom components that need the same behavior
27
+
8
28
  ## [4.3.3] - 2026-04-11
9
29
 
10
30
  ### Added — Table Search Filter
@@ -12,6 +12,8 @@ var _tmpl$ = /* @__PURE__ */ web.template(`<svg class="w-5 h-5"fill=none viewBox
12
12
  to { opacity: 1; transform: scale(1); }
13
13
  }
14
14
  `), _tmpl$5 = /* @__PURE__ */ web.template(`<div class="relative group"><div><div></div></div><button class="absolute top-2 right-2 z-10 opacity-0 group-hover:opacity-70 hover:!opacity-100 p-1.5 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=Expand aria-label="Expand to fullscreen"><svg class="w-3.5 h-3.5 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="M4 8V4m0 0h4M4 4l5 5m11-1V4m0 0h-4m4 0l-5 5M4 16v4m0 0h4m-4 0l5-5m11 5v-4m0 4h-4m4 0l-5-5"></path></svg></button><!$><!/>`), _tmpl$6 = /* @__PURE__ */ web.template(`<svg class="w-5 h-5 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">`);
15
+ const ExpandedContext = solidJs.createContext(() => false);
16
+ const useExpanded = () => solidJs.useContext(ExpandedContext);
15
17
  const ExpandableWrapper = (props) => {
16
18
  const [isExpanded, setIsExpanded] = solidJs.createSignal(false);
17
19
  const [copied, setCopied] = solidJs.createSignal(false);
@@ -69,7 +71,12 @@ const ExpandableWrapper = (props) => {
69
71
  typeof _ref$ === "function" ? web.use(_ref$, _el$2) : inlineSlotRef = _el$2;
70
72
  var _ref$2 = contentRef;
71
73
  typeof _ref$2 === "function" ? web.use(_ref$2, _el$3) : contentRef = _el$3;
72
- web.insert(_el$3, () => props.children);
74
+ web.insert(_el$3, web.createComponent(ExpandedContext.Provider, {
75
+ value: isExpanded,
76
+ get children() {
77
+ return props.children;
78
+ }
79
+ }));
73
80
  _el$4.$$click = handleOpen;
74
81
  web.insert(_el$, web.createComponent(solidJs.Show, {
75
82
  get when() {
@@ -133,4 +140,5 @@ const ExpandableWrapper = (props) => {
133
140
  };
134
141
  web.delegateEvents(["click"]);
135
142
  exports.ExpandableWrapper = ExpandableWrapper;
143
+ exports.useExpanded = useExpanded;
136
144
  //# sourceMappingURL=ExpandableWrapper.cjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"ExpandableWrapper.cjs","sources":["../../src/components/ExpandableWrapper.tsx"],"sourcesContent":["/**\n * ExpandableWrapper - Generic expand/fullscreen wrapper for components\n * v2.2.0: Reusable wrapper that adds expand button + fullscreen modal\n *\n * Uses DOM reparenting to avoid rendering children twice — critical for\n * imperative components like ChartJS that bind instances to DOM nodes.\n */\n\nimport { Component, Show, createSignal, createEffect, onCleanup, JSX } from 'solid-js'\nimport { Portal } from 'solid-js/web'\n\nexport interface ExpandableWrapperProps {\n /** Content to render inline (and in expanded view) */\n children: JSX.Element\n /** Title shown in the expanded modal header */\n title?: string\n /** Data string for copy-to-clipboard in expanded view */\n copyData?: string\n /** Label for copy button tooltip */\n copyLabel?: string\n}\n\n/**\n * Wraps any component with an expand button (top-right corner).\n * Opens a fullscreen Portal modal. The children's DOM is physically\n * reparented into the modal (not duplicated), so imperative bindings\n * like Chart.js canvas refs stay intact.\n *\n * @example\n * <ExpandableWrapper title=\"Sales Data\" copyData={tsvData}>\n * <TableRenderer ... />\n * </ExpandableWrapper>\n */\nexport const ExpandableWrapper: Component<ExpandableWrapperProps> = (props) => {\n const [isExpanded, setIsExpanded] = createSignal(false)\n const [copied, setCopied] = createSignal(false)\n let dialogRef: HTMLDivElement | undefined\n let contentRef: HTMLDivElement | undefined\n let inlineSlotRef: HTMLDivElement | undefined\n let modalSlotRef: HTMLDivElement | undefined\n\n const handleOpen = () => setIsExpanded(true)\n const handleClose = () => setIsExpanded(false)\n\n // Reparent content DOM between inline and modal slots\n createEffect(() => {\n if (!contentRef) return\n\n if (isExpanded()) {\n // Move content into modal\n modalSlotRef?.appendChild(contentRef)\n } else {\n // Move content back to inline\n inlineSlotRef?.appendChild(contentRef)\n }\n })\n\n // Keyboard: Escape to close\n createEffect(() => {\n if (!isExpanded()) return\n\n const onKeyDown = (e: KeyboardEvent) => {\n if (e.key === 'Escape') {\n e.preventDefault()\n handleClose()\n }\n }\n\n document.addEventListener('keydown', onKeyDown)\n onCleanup(() => document.removeEventListener('keydown', onKeyDown))\n })\n\n // Prevent body scroll when expanded\n createEffect(() => {\n if (isExpanded()) {\n const prev = document.body.style.overflow\n document.body.style.overflow = 'hidden'\n // Focus the dialog\n setTimeout(() => dialogRef?.focus(), 10)\n onCleanup(() => {\n document.body.style.overflow = prev\n })\n }\n })\n\n const handleBackdropClick = (e: MouseEvent) => {\n if (e.target === e.currentTarget) handleClose()\n }\n\n const handleCopy = async () => {\n if (!props.copyData) return\n try {\n await navigator.clipboard.writeText(props.copyData)\n setCopied(true)\n setTimeout(() => setCopied(false), 2000)\n } catch (err) {\n console.error('Failed to copy:', err)\n }\n }\n\n return (\n <div class=\"relative group\">\n {/* Inline slot — content lives here when not expanded */}\n <div ref={inlineSlotRef}>\n <div ref={contentRef}>\n {props.children}\n </div>\n </div>\n\n {/* Expand button — visible on hover */}\n <button\n onClick={handleOpen}\n class=\"absolute top-2 right-2 z-10 opacity-0 group-hover:opacity-70 hover:!opacity-100 p-1.5 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\"\n title=\"Expand\"\n aria-label=\"Expand to fullscreen\"\n >\n <svg class=\"w-3.5 h-3.5 text-gray-500 dark:text-gray-400\" fill=\"none\" viewBox=\"0 0 24 24\" stroke=\"currentColor\">\n <path stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"2\" d=\"M4 8V4m0 0h4M4 4l5 5m11-1V4m0 0h-4m4 0l-5 5M4 16v4m0 0h4m-4 0l5-5m11 5v-4m0 4h-4m4 0l-5-5\" />\n </svg>\n </button>\n\n {/* Fullscreen modal via Portal */}\n <Show when={isExpanded()}>\n <Portal>\n <div\n class=\"fixed inset-0 z-50 flex flex-col bg-black/50 backdrop-blur-sm\"\n style={{ animation: 'expandable-fade-in 0.15s ease-out' }}\n onClick={handleBackdropClick}\n role=\"dialog\"\n aria-modal=\"true\"\n aria-label={props.title || 'Expanded view'}\n tabIndex={-1}\n ref={dialogRef}\n >\n {/* Modal panel */}\n <div\n class=\"relative flex flex-col m-4 flex-1 bg-white dark:bg-gray-800 rounded-lg shadow-xl overflow-hidden\"\n style={{ animation: 'expandable-scale-in 0.15s ease-out' }}\n onClick={(e) => e.stopPropagation()}\n >\n {/* Header */}\n <div class=\"flex items-center justify-between px-4 py-3 border-b border-gray-200 dark:border-gray-700 flex-shrink-0\">\n <h2 class=\"text-lg font-semibold text-gray-900 dark:text-white truncate\">\n {props.title || 'Expanded View'}\n </h2>\n <div class=\"flex items-center gap-2\">\n {/* Copy button */}\n <Show when={props.copyData}>\n <button\n onClick={handleCopy}\n class=\"p-1.5 text-gray-400 hover:text-gray-600 dark:hover:text-gray-300 rounded-full hover:bg-gray-100 dark:hover:bg-gray-700 transition-colors\"\n title={props.copyLabel || 'Copy to clipboard'}\n aria-label={props.copyLabel || 'Copy to clipboard'}\n >\n <Show\n when={!copied()}\n fallback={\n <svg class=\"w-5 h-5 text-green-500\" fill=\"none\" viewBox=\"0 0 24 24\" stroke=\"currentColor\">\n <path stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"2\" d=\"M5 13l4 4L19 7\" />\n </svg>\n }\n >\n <svg class=\"w-5 h-5\" fill=\"none\" viewBox=\"0 0 24 24\" stroke=\"currentColor\">\n <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\" />\n </svg>\n </Show>\n </button>\n </Show>\n {/* Close button */}\n <button\n onClick={handleClose}\n class=\"p-1.5 text-gray-400 hover:text-gray-600 dark:hover:text-gray-300 rounded-full hover:bg-gray-100 dark:hover:bg-gray-700 transition-colors\"\n aria-label=\"Close expanded view\"\n >\n <svg class=\"w-5 h-5\" fill=\"none\" viewBox=\"0 0 24 24\" stroke=\"currentColor\">\n <path stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"2\" d=\"M6 18L18 6M6 6l12 12\" />\n </svg>\n </button>\n </div>\n </div>\n\n {/* Modal slot — content is reparented here when expanded */}\n <div class=\"flex-1 overflow-auto p-4\" ref={modalSlotRef} />\n </div>\n </div>\n\n <style>{`\n @keyframes expandable-fade-in {\n from { opacity: 0; }\n to { opacity: 1; }\n }\n @keyframes expandable-scale-in {\n from { opacity: 0; transform: scale(0.97); }\n to { opacity: 1; transform: scale(1); }\n }\n `}</style>\n </Portal>\n </Show>\n </div>\n )\n}\n"],"names":["ExpandableWrapper","props","isExpanded","setIsExpanded","createSignal","copied","setCopied","dialogRef","contentRef","inlineSlotRef","modalSlotRef","handleOpen","handleClose","createEffect","appendChild","onKeyDown","e","key","preventDefault","document","addEventListener","onCleanup","removeEventListener","prev","body","style","overflow","setTimeout","focus","handleBackdropClick","target","currentTarget","handleCopy","copyData","navigator","clipboard","writeText","err","console","error","_el$","_$getNextElement","_tmpl$5","_el$2","firstChild","_el$3","_el$4","nextSibling","_el$15","_el$16","_co$2","_$getNextMarker","_ref$","_$use","_ref$2","_$insert","children","$$click","_$createComponent","Show","when","Portal","_el$5","_tmpl$3","_el$6","_el$7","_el$8","_el$9","_el$11","_el$12","_co$","_el$10","_el$13","_ref$3","stopPropagation","title","_el$0","_tmpl$2","fallback","_tmpl$6","_tmpl$","_$effect","_p$","_v$","copyLabel","_v$2","_$setAttribute","t","undefined","_$runHydrationEvents","_ref$4","_tmpl$4","_$delegateEvents"],"mappings":"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"}
1
+ {"version":3,"file":"ExpandableWrapper.cjs","sources":["../../src/components/ExpandableWrapper.tsx"],"sourcesContent":["/**\n * ExpandableWrapper - Generic expand/fullscreen wrapper for components\n * v2.2.0: Reusable wrapper that adds expand button + fullscreen modal\n *\n * Uses DOM reparenting to avoid rendering children twice — critical for\n * imperative components like ChartJS that bind instances to DOM nodes.\n */\n\nimport { Component, Show, createSignal, createEffect, onCleanup, JSX, createContext, useContext, Accessor } from 'solid-js'\nimport { Portal } from 'solid-js/web'\n\n/** Context for child components to know if they're in expanded/fullscreen view */\nconst ExpandedContext = createContext<Accessor<boolean>>(() => false)\n\n/** Hook for child components to read expanded state */\nexport const useExpanded = () => useContext(ExpandedContext)\n\nexport interface ExpandableWrapperProps {\n /** Content to render inline (and in expanded view) */\n children: JSX.Element\n /** Title shown in the expanded modal header */\n title?: string\n /** Data string for copy-to-clipboard in expanded view */\n copyData?: string\n /** Label for copy button tooltip */\n copyLabel?: string\n}\n\n/**\n * Wraps any component with an expand button (top-right corner).\n * Opens a fullscreen Portal modal. The children's DOM is physically\n * reparented into the modal (not duplicated), so imperative bindings\n * like Chart.js canvas refs stay intact.\n *\n * @example\n * <ExpandableWrapper title=\"Sales Data\" copyData={tsvData}>\n * <TableRenderer ... />\n * </ExpandableWrapper>\n */\nexport const ExpandableWrapper: Component<ExpandableWrapperProps> = (props) => {\n const [isExpanded, setIsExpanded] = createSignal(false)\n const [copied, setCopied] = createSignal(false)\n let dialogRef: HTMLDivElement | undefined\n let contentRef: HTMLDivElement | undefined\n let inlineSlotRef: HTMLDivElement | undefined\n let modalSlotRef: HTMLDivElement | undefined\n\n const handleOpen = () => setIsExpanded(true)\n const handleClose = () => setIsExpanded(false)\n\n // Reparent content DOM between inline and modal slots\n createEffect(() => {\n if (!contentRef) return\n\n if (isExpanded()) {\n // Move content into modal\n modalSlotRef?.appendChild(contentRef)\n } else {\n // Move content back to inline\n inlineSlotRef?.appendChild(contentRef)\n }\n })\n\n // Keyboard: Escape to close\n createEffect(() => {\n if (!isExpanded()) return\n\n const onKeyDown = (e: KeyboardEvent) => {\n if (e.key === 'Escape') {\n e.preventDefault()\n handleClose()\n }\n }\n\n document.addEventListener('keydown', onKeyDown)\n onCleanup(() => document.removeEventListener('keydown', onKeyDown))\n })\n\n // Prevent body scroll when expanded\n createEffect(() => {\n if (isExpanded()) {\n const prev = document.body.style.overflow\n document.body.style.overflow = 'hidden'\n // Focus the dialog\n setTimeout(() => dialogRef?.focus(), 10)\n onCleanup(() => {\n document.body.style.overflow = prev\n })\n }\n })\n\n const handleBackdropClick = (e: MouseEvent) => {\n if (e.target === e.currentTarget) handleClose()\n }\n\n const handleCopy = async () => {\n if (!props.copyData) return\n try {\n await navigator.clipboard.writeText(props.copyData)\n setCopied(true)\n setTimeout(() => setCopied(false), 2000)\n } catch (err) {\n console.error('Failed to copy:', err)\n }\n }\n\n return (\n <div class=\"relative group\">\n {/* Inline slot — content lives here when not expanded */}\n <div ref={inlineSlotRef}>\n <div ref={contentRef}>\n <ExpandedContext.Provider value={isExpanded}>\n {props.children}\n </ExpandedContext.Provider>\n </div>\n </div>\n\n {/* Expand button — visible on hover */}\n <button\n onClick={handleOpen}\n class=\"absolute top-2 right-2 z-10 opacity-0 group-hover:opacity-70 hover:!opacity-100 p-1.5 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\"\n title=\"Expand\"\n aria-label=\"Expand to fullscreen\"\n >\n <svg class=\"w-3.5 h-3.5 text-gray-500 dark:text-gray-400\" fill=\"none\" viewBox=\"0 0 24 24\" stroke=\"currentColor\">\n <path stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"2\" d=\"M4 8V4m0 0h4M4 4l5 5m11-1V4m0 0h-4m4 0l-5 5M4 16v4m0 0h4m-4 0l5-5m11 5v-4m0 4h-4m4 0l-5-5\" />\n </svg>\n </button>\n\n {/* Fullscreen modal via Portal */}\n <Show when={isExpanded()}>\n <Portal>\n <div\n class=\"fixed inset-0 z-50 flex flex-col bg-black/50 backdrop-blur-sm\"\n style={{ animation: 'expandable-fade-in 0.15s ease-out' }}\n onClick={handleBackdropClick}\n role=\"dialog\"\n aria-modal=\"true\"\n aria-label={props.title || 'Expanded view'}\n tabIndex={-1}\n ref={dialogRef}\n >\n {/* Modal panel */}\n <div\n class=\"relative flex flex-col m-4 flex-1 bg-white dark:bg-gray-800 rounded-lg shadow-xl overflow-hidden\"\n style={{ animation: 'expandable-scale-in 0.15s ease-out' }}\n onClick={(e) => e.stopPropagation()}\n >\n {/* Header */}\n <div class=\"flex items-center justify-between px-4 py-3 border-b border-gray-200 dark:border-gray-700 flex-shrink-0\">\n <h2 class=\"text-lg font-semibold text-gray-900 dark:text-white truncate\">\n {props.title || 'Expanded View'}\n </h2>\n <div class=\"flex items-center gap-2\">\n {/* Copy button */}\n <Show when={props.copyData}>\n <button\n onClick={handleCopy}\n class=\"p-1.5 text-gray-400 hover:text-gray-600 dark:hover:text-gray-300 rounded-full hover:bg-gray-100 dark:hover:bg-gray-700 transition-colors\"\n title={props.copyLabel || 'Copy to clipboard'}\n aria-label={props.copyLabel || 'Copy to clipboard'}\n >\n <Show\n when={!copied()}\n fallback={\n <svg class=\"w-5 h-5 text-green-500\" fill=\"none\" viewBox=\"0 0 24 24\" stroke=\"currentColor\">\n <path stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"2\" d=\"M5 13l4 4L19 7\" />\n </svg>\n }\n >\n <svg class=\"w-5 h-5\" fill=\"none\" viewBox=\"0 0 24 24\" stroke=\"currentColor\">\n <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\" />\n </svg>\n </Show>\n </button>\n </Show>\n {/* Close button */}\n <button\n onClick={handleClose}\n class=\"p-1.5 text-gray-400 hover:text-gray-600 dark:hover:text-gray-300 rounded-full hover:bg-gray-100 dark:hover:bg-gray-700 transition-colors\"\n aria-label=\"Close expanded view\"\n >\n <svg class=\"w-5 h-5\" fill=\"none\" viewBox=\"0 0 24 24\" stroke=\"currentColor\">\n <path stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"2\" d=\"M6 18L18 6M6 6l12 12\" />\n </svg>\n </button>\n </div>\n </div>\n\n {/* Modal slot — content is reparented here when expanded */}\n <div class=\"flex-1 overflow-auto p-4\" ref={modalSlotRef} />\n </div>\n </div>\n\n <style>{`\n @keyframes expandable-fade-in {\n from { opacity: 0; }\n to { opacity: 1; }\n }\n @keyframes expandable-scale-in {\n from { opacity: 0; transform: scale(0.97); }\n to { opacity: 1; transform: scale(1); }\n }\n `}</style>\n </Portal>\n </Show>\n </div>\n )\n}\n"],"names":["ExpandedContext","createContext","useExpanded","useContext","ExpandableWrapper","props","isExpanded","setIsExpanded","createSignal","copied","setCopied","dialogRef","contentRef","inlineSlotRef","modalSlotRef","handleOpen","handleClose","createEffect","appendChild","onKeyDown","e","key","preventDefault","document","addEventListener","onCleanup","removeEventListener","prev","body","style","overflow","setTimeout","focus","handleBackdropClick","target","currentTarget","handleCopy","copyData","navigator","clipboard","writeText","err","console","error","_el$","_$getNextElement","_tmpl$5","_el$2","firstChild","_el$3","_el$4","nextSibling","_el$15","_el$16","_co$2","_$getNextMarker","_ref$","_$use","_ref$2","_$insert","_$createComponent","Provider","value","children","$$click","Show","when","Portal","_el$5","_tmpl$3","_el$6","_el$7","_el$8","_el$9","_el$11","_el$12","_co$","_el$10","_el$13","_ref$3","stopPropagation","title","_el$0","_tmpl$2","fallback","_tmpl$6","_tmpl$","_$effect","_p$","_v$","copyLabel","_v$2","_$setAttribute","t","undefined","_$runHydrationEvents","_ref$4","_tmpl$4","_$delegateEvents"],"mappings":";;;;;;;;;;;;;;AAYA,MAAMA,kBAAkBC,QAAAA,cAAiC,MAAM,KAAK;AAG7D,MAAMC,cAAcA,MAAMC,QAAAA,WAAWH,eAAe;AAwBpD,MAAMI,oBAAwDC,CAAAA,UAAU;AAC7E,QAAM,CAACC,YAAYC,aAAa,IAAIC,QAAAA,aAAa,KAAK;AACtD,QAAM,CAACC,QAAQC,SAAS,IAAIF,QAAAA,aAAa,KAAK;AAC9C,MAAIG;AACJ,MAAIC;AACJ,MAAIC;AACJ,MAAIC;AAEJ,QAAMC,aAAaA,MAAMR,cAAc,IAAI;AAC3C,QAAMS,cAAcA,MAAMT,cAAc,KAAK;AAG7CU,UAAAA,aAAa,MAAM;AACjB,QAAI,CAACL,WAAY;AAEjB,QAAIN,cAAc;AAEhBQ,mDAAcI,YAAYN;AAAAA,IAC5B,OAAO;AAELC,qDAAeK,YAAYN;AAAAA,IAC7B;AAAA,EACF,CAAC;AAGDK,UAAAA,aAAa,MAAM;AACjB,QAAI,CAACX,aAAc;AAEnB,UAAMa,YAAYA,CAACC,MAAqB;AACtC,UAAIA,EAAEC,QAAQ,UAAU;AACtBD,UAAEE,eAAAA;AACFN,oBAAAA;AAAAA,MACF;AAAA,IACF;AAEAO,aAASC,iBAAiB,WAAWL,SAAS;AAC9CM,YAAAA,UAAU,MAAMF,SAASG,oBAAoB,WAAWP,SAAS,CAAC;AAAA,EACpE,CAAC;AAGDF,UAAAA,aAAa,MAAM;AACjB,QAAIX,cAAc;AAChB,YAAMqB,OAAOJ,SAASK,KAAKC,MAAMC;AACjCP,eAASK,KAAKC,MAAMC,WAAW;AAE/BC,iBAAW,MAAMpB,uCAAWqB,SAAS,EAAE;AACvCP,cAAAA,UAAU,MAAM;AACdF,iBAASK,KAAKC,MAAMC,WAAWH;AAAAA,MACjC,CAAC;AAAA,IACH;AAAA,EACF,CAAC;AAED,QAAMM,sBAAsBA,CAACb,MAAkB;AAC7C,QAAIA,EAAEc,WAAWd,EAAEe,cAAenB,aAAAA;AAAAA,EACpC;AAEA,QAAMoB,aAAa,YAAY;AAC7B,QAAI,CAAC/B,MAAMgC,SAAU;AACrB,QAAI;AACF,YAAMC,UAAUC,UAAUC,UAAUnC,MAAMgC,QAAQ;AAClD3B,gBAAU,IAAI;AACdqB,iBAAW,MAAMrB,UAAU,KAAK,GAAG,GAAI;AAAA,IACzC,SAAS+B,KAAK;AACZC,cAAQC,MAAM,mBAAmBF,GAAG;AAAA,IACtC;AAAA,EACF;AAEA,UAAA,MAAA;AAAA,QAAAG,OAAAC,mBAAAC,OAAA,GAAAC,QAAAH,KAAAI,YAAAC,QAAAF,MAAAC,YAAAE,QAAAH,MAAAI,aAAAC,SAAAF,MAAAC,aAAA,CAAAE,QAAAC,KAAA,IAAAC,IAAAA,cAAAH,OAAAD,WAAA;AAAA,QAAAK,QAGc3C;AAAa,WAAA2C,UAAA,aAAAC,IAAAA,IAAAD,OAAAT,KAAA,IAAblC,gBAAakC;AAAA,QAAAW,SACX9C;AAAU,WAAA8C,WAAA,aAAAD,IAAAA,IAAAC,QAAAT,KAAA,IAAVrC,aAAUqC;AAAAU,QAAAA,OAAAV,OAAAW,oBACjB5D,gBAAgB6D,UAAQ;AAAA,MAACC,OAAOxD;AAAAA,MAAU,IAAAyD,WAAA;AAAA,eACxC1D,MAAM0D;AAAAA,MAAQ;AAAA,IAAA,CAAA,CAAA;AAAAb,UAAAc,UAOVjD;AAAU4C,eAAAf,MAAAgB,IAAAA,gBAWpBK,cAAI;AAAA,MAAA,IAACC,OAAI;AAAA,eAAE5D,WAAAA;AAAAA,MAAY;AAAA,MAAA,IAAAyD,WAAA;AAAA,eAAAH,IAAAA,gBACrBO,IAAAA,QAAM;AAAA,UAAA,IAAAJ,WAAA;AAAA,mBAAA,EAAA,MAAA;AAAA,kBAAAK,QAAAvB,IAAAA,eAAAwB,OAAA,GAAAC,QAAAF,MAAApB,YAAAuB,QAAAD,MAAAtB,YAAAwB,QAAAD,MAAAvB,YAAAyB,QAAAD,MAAArB,aAAAuB,SAAAD,MAAAzB,YAAA,CAAA2B,QAAAC,IAAA,IAAArB,IAAAA,cAAAmB,OAAAvB,WAAA,GAAA0B,SAAAF,OAAAxB,aAAA2B,SAAAP,MAAApB;AAAA,kBAAA4B,SASEpE;AAAS,qBAAAoE,WAAA,aAAAtB,IAAAA,IAAAsB,QAAAX,KAAA,IAATzD,YAASyD;AAAAA,oBAAAJ,UALL/B;AAAmBqC,oBAAAN,UAWhB5C,CAAAA,MAAMA,EAAE4D,gBAAAA;AAAiBrB,kBAAAA,OAAAa,OAAA,MAK9BnE,MAAM4E,SAAS,eAAe;AAAAtB,yBAAAc,OAAAb,IAAAA,gBAI9BK,cAAI;AAAA,gBAAA,IAACC,OAAI;AAAA,yBAAE7D,MAAMgC;AAAAA,gBAAQ;AAAA,gBAAA,IAAA0B,WAAA;AAAA,sBAAAmB,QAAArC,IAAAA,eAAAsC,OAAA;AAAAD,wBAAAlB,UAEb5B;AAAUuB,6BAAAuB,OAAAtB,IAAAA,gBAKlBK,cAAI;AAAA,oBAAA,IACHC,OAAI;AAAA,6BAAE,CAACzD,OAAAA;AAAAA,oBAAQ;AAAA,oBAAA,IACf2E,WAAQ;AAAA,6BAAAvC,IAAAA,eAAAwC,OAAA;AAAA,oBAAA;AAAA,oBAAA,IAAAtB,WAAA;AAAA,6BAAAlB,IAAAA,eAAAyC,MAAA;AAAA,oBAAA;AAAA,kBAAA,CAAA,CAAA;AAAAC,sBAAAA,OAAAC,CAAAA,QAAA;AAAA,wBAAAC,MALHpF,MAAMqF,aAAa,qBAAmBC,OACjCtF,MAAMqF,aAAa;AAAmBD,4BAAAD,IAAApE,KAAAwE,IAAAA,aAAAV,OAAA,SAAAM,IAAApE,IAAAqE,GAAA;AAAAE,6BAAAH,IAAAK,KAAAD,IAAAA,aAAAV,OAAA,cAAAM,IAAAK,IAAAF,IAAA;AAAA,2BAAAH;AAAAA,kBAAA,GAAA;AAAA,oBAAApE,GAAA0E;AAAAA,oBAAAD,GAAAC;AAAAA,kBAAAA,CAAA;AAAAC,yCAAAA;AAAA,yBAAAb;AAAAA,gBAAA;AAAA,cAAA,CAAA,GAAAP,QAAAC,IAAA;AAAAC,qBAAAb,UAkB3ChD;AAAW,kBAAAgF,SAYiBlF;AAAY,qBAAAkF,WAAA,aAAAvC,IAAAA,IAAAuC,QAAAlB,MAAA,IAAZhE,eAAYgE;AAAAS,kBAAAA,OAAA,MAAAK,IAAAA,aAAAxB,qBApD7C/D,MAAM4E,SAAS,eAAe,CAAA;AAAAc,qCAAAA;AAAA,qBAAA3B;AAAAA,YAAA,GAAA,GAAAvB,mBAAAoD,OAAA,CAAA;AAAA,UAAA;AAAA,QAAA,CAAA;AAAA,MAAA;AAAA,IAAA,CAAA,GAAA5C,QAAAC,KAAA;AAAAyC,2BAAAA;AAAA,WAAAnD;AAAAA,EAAA,GAAA;AAsEtD;AAACsD,IAAAA,eAAA,CAAA,OAAA,CAAA;;;"}
@@ -5,7 +5,9 @@
5
5
  * Uses DOM reparenting to avoid rendering children twice — critical for
6
6
  * imperative components like ChartJS that bind instances to DOM nodes.
7
7
  */
8
- import { Component, JSX } from 'solid-js';
8
+ import { Component, JSX, Accessor } from 'solid-js';
9
+ /** Hook for child components to read expanded state */
10
+ export declare const useExpanded: () => Accessor<boolean>;
9
11
  export interface ExpandableWrapperProps {
10
12
  /** Content to render inline (and in expanded view) */
11
13
  children: JSX.Element;
@@ -1 +1 @@
1
- {"version":3,"file":"ExpandableWrapper.d.ts","sourceRoot":"","sources":["../../src/components/ExpandableWrapper.tsx"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,EAAE,SAAS,EAA+C,GAAG,EAAE,MAAM,UAAU,CAAA;AAGtF,MAAM,WAAW,sBAAsB;IACrC,sDAAsD;IACtD,QAAQ,EAAE,GAAG,CAAC,OAAO,CAAA;IACrB,+CAA+C;IAC/C,KAAK,CAAC,EAAE,MAAM,CAAA;IACd,yDAAyD;IACzD,QAAQ,CAAC,EAAE,MAAM,CAAA;IACjB,oCAAoC;IACpC,SAAS,CAAC,EAAE,MAAM,CAAA;CACnB;AAED;;;;;;;;;;GAUG;AACH,eAAO,MAAM,iBAAiB,EAAE,SAAS,CAAC,sBAAsB,CAuK/D,CAAA"}
1
+ {"version":3,"file":"ExpandableWrapper.d.ts","sourceRoot":"","sources":["../../src/components/ExpandableWrapper.tsx"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,EAAE,SAAS,EAA+C,GAAG,EAA6B,QAAQ,EAAE,MAAM,UAAU,CAAA;AAM3H,uDAAuD;AACvD,eAAO,MAAM,WAAW,yBAAoC,CAAA;AAE5D,MAAM,WAAW,sBAAsB;IACrC,sDAAsD;IACtD,QAAQ,EAAE,GAAG,CAAC,OAAO,CAAA;IACrB,+CAA+C;IAC/C,KAAK,CAAC,EAAE,MAAM,CAAA;IACd,yDAAyD;IACzD,QAAQ,CAAC,EAAE,MAAM,CAAA;IACjB,oCAAoC;IACpC,SAAS,CAAC,EAAE,MAAM,CAAA;CACnB;AAED;;;;;;;;;;GAUG;AACH,eAAO,MAAM,iBAAiB,EAAE,SAAS,CAAC,sBAAsB,CAyK/D,CAAA"}
@@ -1,5 +1,5 @@
1
1
  import { delegateEvents, getNextElement, template, getNextMarker, insert, createComponent, Portal, use, effect, setAttribute, runHydrationEvents } from "solid-js/web";
2
- import { createSignal, createEffect, onCleanup, Show } from "solid-js";
2
+ import { createContext, useContext, createSignal, createEffect, onCleanup, Show } from "solid-js";
3
3
  var _tmpl$ = /* @__PURE__ */ template(`<svg class="w-5 h-5"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$2 = /* @__PURE__ */ template(`<button class="p-1.5 text-gray-400 hover:text-gray-600 dark:hover:text-gray-300 rounded-full hover:bg-gray-100 dark:hover:bg-gray-700 transition-colors">`), _tmpl$3 = /* @__PURE__ */ template(`<div class="fixed inset-0 z-50 flex flex-col bg-black/50 backdrop-blur-sm"role=dialog aria-modal=true tabindex=-1 style="animation:expandable-fade-in 0.15s ease-out"><div class="relative flex flex-col m-4 flex-1 bg-white dark:bg-gray-800 rounded-lg shadow-xl overflow-hidden"style="animation:expandable-scale-in 0.15s ease-out"><div class="flex items-center justify-between px-4 py-3 border-b border-gray-200 dark:border-gray-700 flex-shrink-0"><h2 class="text-lg font-semibold text-gray-900 dark:text-white truncate"></h2><div class="flex items-center gap-2"><!$><!/><button class="p-1.5 text-gray-400 hover:text-gray-600 dark:hover:text-gray-300 rounded-full hover:bg-gray-100 dark:hover:bg-gray-700 transition-colors"aria-label="Close expanded view"><svg class="w-5 h-5"fill=none viewBox="0 0 24 24"stroke=currentColor><path stroke-linecap=round stroke-linejoin=round stroke-width=2 d="M6 18L18 6M6 6l12 12"></path></svg></button></div></div><div class="flex-1 overflow-auto p-4">`), _tmpl$4 = /* @__PURE__ */ template(`<style>
4
4
  @keyframes expandable-fade-in {
5
5
  from { opacity: 0; }
@@ -10,6 +10,8 @@ var _tmpl$ = /* @__PURE__ */ template(`<svg class="w-5 h-5"fill=none viewBox="0
10
10
  to { opacity: 1; transform: scale(1); }
11
11
  }
12
12
  `), _tmpl$5 = /* @__PURE__ */ template(`<div class="relative group"><div><div></div></div><button class="absolute top-2 right-2 z-10 opacity-0 group-hover:opacity-70 hover:!opacity-100 p-1.5 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=Expand aria-label="Expand to fullscreen"><svg class="w-3.5 h-3.5 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="M4 8V4m0 0h4M4 4l5 5m11-1V4m0 0h-4m4 0l-5 5M4 16v4m0 0h4m-4 0l5-5m11 5v-4m0 4h-4m4 0l-5-5"></path></svg></button><!$><!/>`), _tmpl$6 = /* @__PURE__ */ template(`<svg class="w-5 h-5 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">`);
13
+ const ExpandedContext = createContext(() => false);
14
+ const useExpanded = () => useContext(ExpandedContext);
13
15
  const ExpandableWrapper = (props) => {
14
16
  const [isExpanded, setIsExpanded] = createSignal(false);
15
17
  const [copied, setCopied] = createSignal(false);
@@ -67,7 +69,12 @@ const ExpandableWrapper = (props) => {
67
69
  typeof _ref$ === "function" ? use(_ref$, _el$2) : inlineSlotRef = _el$2;
68
70
  var _ref$2 = contentRef;
69
71
  typeof _ref$2 === "function" ? use(_ref$2, _el$3) : contentRef = _el$3;
70
- insert(_el$3, () => props.children);
72
+ insert(_el$3, createComponent(ExpandedContext.Provider, {
73
+ value: isExpanded,
74
+ get children() {
75
+ return props.children;
76
+ }
77
+ }));
71
78
  _el$4.$$click = handleOpen;
72
79
  insert(_el$, createComponent(Show, {
73
80
  get when() {
@@ -131,6 +138,7 @@ const ExpandableWrapper = (props) => {
131
138
  };
132
139
  delegateEvents(["click"]);
133
140
  export {
134
- ExpandableWrapper
141
+ ExpandableWrapper,
142
+ useExpanded
135
143
  };
136
144
  //# sourceMappingURL=ExpandableWrapper.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"ExpandableWrapper.js","sources":["../../src/components/ExpandableWrapper.tsx"],"sourcesContent":["/**\n * ExpandableWrapper - Generic expand/fullscreen wrapper for components\n * v2.2.0: Reusable wrapper that adds expand button + fullscreen modal\n *\n * Uses DOM reparenting to avoid rendering children twice — critical for\n * imperative components like ChartJS that bind instances to DOM nodes.\n */\n\nimport { Component, Show, createSignal, createEffect, onCleanup, JSX } from 'solid-js'\nimport { Portal } from 'solid-js/web'\n\nexport interface ExpandableWrapperProps {\n /** Content to render inline (and in expanded view) */\n children: JSX.Element\n /** Title shown in the expanded modal header */\n title?: string\n /** Data string for copy-to-clipboard in expanded view */\n copyData?: string\n /** Label for copy button tooltip */\n copyLabel?: string\n}\n\n/**\n * Wraps any component with an expand button (top-right corner).\n * Opens a fullscreen Portal modal. The children's DOM is physically\n * reparented into the modal (not duplicated), so imperative bindings\n * like Chart.js canvas refs stay intact.\n *\n * @example\n * <ExpandableWrapper title=\"Sales Data\" copyData={tsvData}>\n * <TableRenderer ... />\n * </ExpandableWrapper>\n */\nexport const ExpandableWrapper: Component<ExpandableWrapperProps> = (props) => {\n const [isExpanded, setIsExpanded] = createSignal(false)\n const [copied, setCopied] = createSignal(false)\n let dialogRef: HTMLDivElement | undefined\n let contentRef: HTMLDivElement | undefined\n let inlineSlotRef: HTMLDivElement | undefined\n let modalSlotRef: HTMLDivElement | undefined\n\n const handleOpen = () => setIsExpanded(true)\n const handleClose = () => setIsExpanded(false)\n\n // Reparent content DOM between inline and modal slots\n createEffect(() => {\n if (!contentRef) return\n\n if (isExpanded()) {\n // Move content into modal\n modalSlotRef?.appendChild(contentRef)\n } else {\n // Move content back to inline\n inlineSlotRef?.appendChild(contentRef)\n }\n })\n\n // Keyboard: Escape to close\n createEffect(() => {\n if (!isExpanded()) return\n\n const onKeyDown = (e: KeyboardEvent) => {\n if (e.key === 'Escape') {\n e.preventDefault()\n handleClose()\n }\n }\n\n document.addEventListener('keydown', onKeyDown)\n onCleanup(() => document.removeEventListener('keydown', onKeyDown))\n })\n\n // Prevent body scroll when expanded\n createEffect(() => {\n if (isExpanded()) {\n const prev = document.body.style.overflow\n document.body.style.overflow = 'hidden'\n // Focus the dialog\n setTimeout(() => dialogRef?.focus(), 10)\n onCleanup(() => {\n document.body.style.overflow = prev\n })\n }\n })\n\n const handleBackdropClick = (e: MouseEvent) => {\n if (e.target === e.currentTarget) handleClose()\n }\n\n const handleCopy = async () => {\n if (!props.copyData) return\n try {\n await navigator.clipboard.writeText(props.copyData)\n setCopied(true)\n setTimeout(() => setCopied(false), 2000)\n } catch (err) {\n console.error('Failed to copy:', err)\n }\n }\n\n return (\n <div class=\"relative group\">\n {/* Inline slot — content lives here when not expanded */}\n <div ref={inlineSlotRef}>\n <div ref={contentRef}>\n {props.children}\n </div>\n </div>\n\n {/* Expand button — visible on hover */}\n <button\n onClick={handleOpen}\n class=\"absolute top-2 right-2 z-10 opacity-0 group-hover:opacity-70 hover:!opacity-100 p-1.5 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\"\n title=\"Expand\"\n aria-label=\"Expand to fullscreen\"\n >\n <svg class=\"w-3.5 h-3.5 text-gray-500 dark:text-gray-400\" fill=\"none\" viewBox=\"0 0 24 24\" stroke=\"currentColor\">\n <path stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"2\" d=\"M4 8V4m0 0h4M4 4l5 5m11-1V4m0 0h-4m4 0l-5 5M4 16v4m0 0h4m-4 0l5-5m11 5v-4m0 4h-4m4 0l-5-5\" />\n </svg>\n </button>\n\n {/* Fullscreen modal via Portal */}\n <Show when={isExpanded()}>\n <Portal>\n <div\n class=\"fixed inset-0 z-50 flex flex-col bg-black/50 backdrop-blur-sm\"\n style={{ animation: 'expandable-fade-in 0.15s ease-out' }}\n onClick={handleBackdropClick}\n role=\"dialog\"\n aria-modal=\"true\"\n aria-label={props.title || 'Expanded view'}\n tabIndex={-1}\n ref={dialogRef}\n >\n {/* Modal panel */}\n <div\n class=\"relative flex flex-col m-4 flex-1 bg-white dark:bg-gray-800 rounded-lg shadow-xl overflow-hidden\"\n style={{ animation: 'expandable-scale-in 0.15s ease-out' }}\n onClick={(e) => e.stopPropagation()}\n >\n {/* Header */}\n <div class=\"flex items-center justify-between px-4 py-3 border-b border-gray-200 dark:border-gray-700 flex-shrink-0\">\n <h2 class=\"text-lg font-semibold text-gray-900 dark:text-white truncate\">\n {props.title || 'Expanded View'}\n </h2>\n <div class=\"flex items-center gap-2\">\n {/* Copy button */}\n <Show when={props.copyData}>\n <button\n onClick={handleCopy}\n class=\"p-1.5 text-gray-400 hover:text-gray-600 dark:hover:text-gray-300 rounded-full hover:bg-gray-100 dark:hover:bg-gray-700 transition-colors\"\n title={props.copyLabel || 'Copy to clipboard'}\n aria-label={props.copyLabel || 'Copy to clipboard'}\n >\n <Show\n when={!copied()}\n fallback={\n <svg class=\"w-5 h-5 text-green-500\" fill=\"none\" viewBox=\"0 0 24 24\" stroke=\"currentColor\">\n <path stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"2\" d=\"M5 13l4 4L19 7\" />\n </svg>\n }\n >\n <svg class=\"w-5 h-5\" fill=\"none\" viewBox=\"0 0 24 24\" stroke=\"currentColor\">\n <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\" />\n </svg>\n </Show>\n </button>\n </Show>\n {/* Close button */}\n <button\n onClick={handleClose}\n class=\"p-1.5 text-gray-400 hover:text-gray-600 dark:hover:text-gray-300 rounded-full hover:bg-gray-100 dark:hover:bg-gray-700 transition-colors\"\n aria-label=\"Close expanded view\"\n >\n <svg class=\"w-5 h-5\" fill=\"none\" viewBox=\"0 0 24 24\" stroke=\"currentColor\">\n <path stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"2\" d=\"M6 18L18 6M6 6l12 12\" />\n </svg>\n </button>\n </div>\n </div>\n\n {/* Modal slot — content is reparented here when expanded */}\n <div class=\"flex-1 overflow-auto p-4\" ref={modalSlotRef} />\n </div>\n </div>\n\n <style>{`\n @keyframes expandable-fade-in {\n from { opacity: 0; }\n to { opacity: 1; }\n }\n @keyframes expandable-scale-in {\n from { opacity: 0; transform: scale(0.97); }\n to { opacity: 1; transform: scale(1); }\n }\n `}</style>\n </Portal>\n </Show>\n </div>\n )\n}\n"],"names":["ExpandableWrapper","props","isExpanded","setIsExpanded","createSignal","copied","setCopied","dialogRef","contentRef","inlineSlotRef","modalSlotRef","handleOpen","handleClose","createEffect","appendChild","onKeyDown","e","key","preventDefault","document","addEventListener","onCleanup","removeEventListener","prev","body","style","overflow","setTimeout","focus","handleBackdropClick","target","currentTarget","handleCopy","copyData","navigator","clipboard","writeText","err","console","error","_el$","_$getNextElement","_tmpl$5","_el$2","firstChild","_el$3","_el$4","nextSibling","_el$15","_el$16","_co$2","_$getNextMarker","_ref$","_$use","_ref$2","_$insert","children","$$click","_$createComponent","Show","when","Portal","_el$5","_tmpl$3","_el$6","_el$7","_el$8","_el$9","_el$11","_el$12","_co$","_el$10","_el$13","_ref$3","stopPropagation","title","_el$0","_tmpl$2","fallback","_tmpl$6","_tmpl$","_$effect","_p$","_v$","copyLabel","_v$2","_$setAttribute","t","undefined","_$runHydrationEvents","_ref$4","_tmpl$4","_$delegateEvents"],"mappings":"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"}
1
+ {"version":3,"file":"ExpandableWrapper.js","sources":["../../src/components/ExpandableWrapper.tsx"],"sourcesContent":["/**\n * ExpandableWrapper - Generic expand/fullscreen wrapper for components\n * v2.2.0: Reusable wrapper that adds expand button + fullscreen modal\n *\n * Uses DOM reparenting to avoid rendering children twice — critical for\n * imperative components like ChartJS that bind instances to DOM nodes.\n */\n\nimport { Component, Show, createSignal, createEffect, onCleanup, JSX, createContext, useContext, Accessor } from 'solid-js'\nimport { Portal } from 'solid-js/web'\n\n/** Context for child components to know if they're in expanded/fullscreen view */\nconst ExpandedContext = createContext<Accessor<boolean>>(() => false)\n\n/** Hook for child components to read expanded state */\nexport const useExpanded = () => useContext(ExpandedContext)\n\nexport interface ExpandableWrapperProps {\n /** Content to render inline (and in expanded view) */\n children: JSX.Element\n /** Title shown in the expanded modal header */\n title?: string\n /** Data string for copy-to-clipboard in expanded view */\n copyData?: string\n /** Label for copy button tooltip */\n copyLabel?: string\n}\n\n/**\n * Wraps any component with an expand button (top-right corner).\n * Opens a fullscreen Portal modal. The children's DOM is physically\n * reparented into the modal (not duplicated), so imperative bindings\n * like Chart.js canvas refs stay intact.\n *\n * @example\n * <ExpandableWrapper title=\"Sales Data\" copyData={tsvData}>\n * <TableRenderer ... />\n * </ExpandableWrapper>\n */\nexport const ExpandableWrapper: Component<ExpandableWrapperProps> = (props) => {\n const [isExpanded, setIsExpanded] = createSignal(false)\n const [copied, setCopied] = createSignal(false)\n let dialogRef: HTMLDivElement | undefined\n let contentRef: HTMLDivElement | undefined\n let inlineSlotRef: HTMLDivElement | undefined\n let modalSlotRef: HTMLDivElement | undefined\n\n const handleOpen = () => setIsExpanded(true)\n const handleClose = () => setIsExpanded(false)\n\n // Reparent content DOM between inline and modal slots\n createEffect(() => {\n if (!contentRef) return\n\n if (isExpanded()) {\n // Move content into modal\n modalSlotRef?.appendChild(contentRef)\n } else {\n // Move content back to inline\n inlineSlotRef?.appendChild(contentRef)\n }\n })\n\n // Keyboard: Escape to close\n createEffect(() => {\n if (!isExpanded()) return\n\n const onKeyDown = (e: KeyboardEvent) => {\n if (e.key === 'Escape') {\n e.preventDefault()\n handleClose()\n }\n }\n\n document.addEventListener('keydown', onKeyDown)\n onCleanup(() => document.removeEventListener('keydown', onKeyDown))\n })\n\n // Prevent body scroll when expanded\n createEffect(() => {\n if (isExpanded()) {\n const prev = document.body.style.overflow\n document.body.style.overflow = 'hidden'\n // Focus the dialog\n setTimeout(() => dialogRef?.focus(), 10)\n onCleanup(() => {\n document.body.style.overflow = prev\n })\n }\n })\n\n const handleBackdropClick = (e: MouseEvent) => {\n if (e.target === e.currentTarget) handleClose()\n }\n\n const handleCopy = async () => {\n if (!props.copyData) return\n try {\n await navigator.clipboard.writeText(props.copyData)\n setCopied(true)\n setTimeout(() => setCopied(false), 2000)\n } catch (err) {\n console.error('Failed to copy:', err)\n }\n }\n\n return (\n <div class=\"relative group\">\n {/* Inline slot — content lives here when not expanded */}\n <div ref={inlineSlotRef}>\n <div ref={contentRef}>\n <ExpandedContext.Provider value={isExpanded}>\n {props.children}\n </ExpandedContext.Provider>\n </div>\n </div>\n\n {/* Expand button — visible on hover */}\n <button\n onClick={handleOpen}\n class=\"absolute top-2 right-2 z-10 opacity-0 group-hover:opacity-70 hover:!opacity-100 p-1.5 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\"\n title=\"Expand\"\n aria-label=\"Expand to fullscreen\"\n >\n <svg class=\"w-3.5 h-3.5 text-gray-500 dark:text-gray-400\" fill=\"none\" viewBox=\"0 0 24 24\" stroke=\"currentColor\">\n <path stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"2\" d=\"M4 8V4m0 0h4M4 4l5 5m11-1V4m0 0h-4m4 0l-5 5M4 16v4m0 0h4m-4 0l5-5m11 5v-4m0 4h-4m4 0l-5-5\" />\n </svg>\n </button>\n\n {/* Fullscreen modal via Portal */}\n <Show when={isExpanded()}>\n <Portal>\n <div\n class=\"fixed inset-0 z-50 flex flex-col bg-black/50 backdrop-blur-sm\"\n style={{ animation: 'expandable-fade-in 0.15s ease-out' }}\n onClick={handleBackdropClick}\n role=\"dialog\"\n aria-modal=\"true\"\n aria-label={props.title || 'Expanded view'}\n tabIndex={-1}\n ref={dialogRef}\n >\n {/* Modal panel */}\n <div\n class=\"relative flex flex-col m-4 flex-1 bg-white dark:bg-gray-800 rounded-lg shadow-xl overflow-hidden\"\n style={{ animation: 'expandable-scale-in 0.15s ease-out' }}\n onClick={(e) => e.stopPropagation()}\n >\n {/* Header */}\n <div class=\"flex items-center justify-between px-4 py-3 border-b border-gray-200 dark:border-gray-700 flex-shrink-0\">\n <h2 class=\"text-lg font-semibold text-gray-900 dark:text-white truncate\">\n {props.title || 'Expanded View'}\n </h2>\n <div class=\"flex items-center gap-2\">\n {/* Copy button */}\n <Show when={props.copyData}>\n <button\n onClick={handleCopy}\n class=\"p-1.5 text-gray-400 hover:text-gray-600 dark:hover:text-gray-300 rounded-full hover:bg-gray-100 dark:hover:bg-gray-700 transition-colors\"\n title={props.copyLabel || 'Copy to clipboard'}\n aria-label={props.copyLabel || 'Copy to clipboard'}\n >\n <Show\n when={!copied()}\n fallback={\n <svg class=\"w-5 h-5 text-green-500\" fill=\"none\" viewBox=\"0 0 24 24\" stroke=\"currentColor\">\n <path stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"2\" d=\"M5 13l4 4L19 7\" />\n </svg>\n }\n >\n <svg class=\"w-5 h-5\" fill=\"none\" viewBox=\"0 0 24 24\" stroke=\"currentColor\">\n <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\" />\n </svg>\n </Show>\n </button>\n </Show>\n {/* Close button */}\n <button\n onClick={handleClose}\n class=\"p-1.5 text-gray-400 hover:text-gray-600 dark:hover:text-gray-300 rounded-full hover:bg-gray-100 dark:hover:bg-gray-700 transition-colors\"\n aria-label=\"Close expanded view\"\n >\n <svg class=\"w-5 h-5\" fill=\"none\" viewBox=\"0 0 24 24\" stroke=\"currentColor\">\n <path stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"2\" d=\"M6 18L18 6M6 6l12 12\" />\n </svg>\n </button>\n </div>\n </div>\n\n {/* Modal slot — content is reparented here when expanded */}\n <div class=\"flex-1 overflow-auto p-4\" ref={modalSlotRef} />\n </div>\n </div>\n\n <style>{`\n @keyframes expandable-fade-in {\n from { opacity: 0; }\n to { opacity: 1; }\n }\n @keyframes expandable-scale-in {\n from { opacity: 0; transform: scale(0.97); }\n to { opacity: 1; transform: scale(1); }\n }\n `}</style>\n </Portal>\n </Show>\n </div>\n )\n}\n"],"names":["ExpandedContext","createContext","useExpanded","useContext","ExpandableWrapper","props","isExpanded","setIsExpanded","createSignal","copied","setCopied","dialogRef","contentRef","inlineSlotRef","modalSlotRef","handleOpen","handleClose","createEffect","appendChild","onKeyDown","e","key","preventDefault","document","addEventListener","onCleanup","removeEventListener","prev","body","style","overflow","setTimeout","focus","handleBackdropClick","target","currentTarget","handleCopy","copyData","navigator","clipboard","writeText","err","console","error","_el$","_$getNextElement","_tmpl$5","_el$2","firstChild","_el$3","_el$4","nextSibling","_el$15","_el$16","_co$2","_$getNextMarker","_ref$","_$use","_ref$2","_$insert","_$createComponent","Provider","value","children","$$click","Show","when","Portal","_el$5","_tmpl$3","_el$6","_el$7","_el$8","_el$9","_el$11","_el$12","_co$","_el$10","_el$13","_ref$3","stopPropagation","title","_el$0","_tmpl$2","fallback","_tmpl$6","_tmpl$","_$effect","_p$","_v$","copyLabel","_v$2","_$setAttribute","t","undefined","_$runHydrationEvents","_ref$4","_tmpl$4","_$delegateEvents"],"mappings":"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"}
@@ -337,7 +337,10 @@ function TableRenderer(props) {
337
337
  return normalize(String(val)).includes(q);
338
338
  }));
339
339
  });
340
- const clientPageSize = () => tableParams.pageSize ?? 25;
340
+ const isExpanded = ExpandableWrapper.useExpanded();
341
+ const fullPageSize = () => tableParams.pageSize ?? 25;
342
+ const chatPageSize = () => tableParams.chatPageSize ?? Math.min(10, fullPageSize());
343
+ const clientPageSize = () => isExpanded() ? fullPageSize() : chatPageSize();
341
344
  const hasServerPagination = () => !!tableParams.pagination;
342
345
  const isProgressiveMode = () => !!tableParams.showAllLabel;
343
346
  const needsClientPagination = () => !hasServerPagination() && clientPageSize() > 0 && filteredRows().length > clientPageSize();
@@ -456,7 +459,7 @@ ${dataRows}`;
456
459
  URL.revokeObjectURL(url);
457
460
  };
458
461
  const exportable = tableParams.exportable;
459
- const exportFormats = typeof exportable === "object" && (exportable == null ? void 0 : exportable.formats) ? exportable.formats : ["csv", "tsv", "json"];
462
+ const exportFormats = typeof exportable === "object" && (exportable == null ? void 0 : exportable.formats) ? exportable.formats : ["csv", "json"];
460
463
  const exportFilename = typeof exportable === "object" && (exportable == null ? void 0 : exportable.filename) || `table-${Math.random().toString(36).slice(2, 9)}`;
461
464
  const [showExportMenu, setShowExportMenu] = solidJs.createSignal(false);
462
465
  const handleExport = (format) => {
@@ -546,17 +549,17 @@ ${dataRows}`;
546
549
  return tableParams.title || "Table";
547
550
  },
548
551
  get copyData() {
549
- return getTableText();
552
+ return getTableCSV();
550
553
  },
551
- copyLabel: "Copy table (TSV)",
554
+ copyLabel: "Copy table (CSV)",
552
555
  get children() {
553
556
  var _el$29 = web.getNextElement(_tmpl$26), _el$142 = _el$29.firstChild, [_el$143, _co$35] = web.getNextMarker(_el$142.nextSibling), _el$44 = _el$143.nextSibling, _el$132 = _el$44.firstChild, [_el$133, _co$30] = web.getNextMarker(_el$132.nextSibling), _el$134 = _el$133.nextSibling, [_el$135, _co$31] = web.getNextMarker(_el$134.nextSibling), _el$70 = _el$135.nextSibling, _el$71 = _el$70.firstChild, _el$72 = _el$71.firstChild, _el$73 = _el$72.firstChild, _el$74 = _el$72.nextSibling, [_el$75, _co$14] = web.getNextMarker(_el$74.nextSibling), _el$136 = _el$70.nextSibling, [_el$137, _co$32] = web.getNextMarker(_el$136.nextSibling), _el$138 = _el$137.nextSibling, [_el$139, _co$33] = web.getNextMarker(_el$138.nextSibling), _el$140 = _el$139.nextSibling, [_el$141, _co$34] = web.getNextMarker(_el$140.nextSibling);
554
557
  web.insert(_el$29, web.createComponent(solidJs.Show, {
555
558
  when: exportable,
556
559
  get fallback() {
557
560
  return web.createComponent(CopyButton, {
558
- getText: getTableText,
559
- title: "Copy table data",
561
+ getText: getTableCSV,
562
+ title: "Copy table (CSV)",
560
563
  position: "top-right"
561
564
  });
562
565
  },
@@ -785,6 +788,9 @@ ${dataRows}`;
785
788
  var _v$0 = isVirtualizing() ? {
786
789
  "max-height": "500px",
787
790
  "overflow-y": "auto"
791
+ } : clientVisibleRows().length > 8 ? {
792
+ "max-height": isExpanded() ? "70vh" : "400px",
793
+ "overflow-y": "auto"
788
794
  } : {}, _v$1 = tableParams.title || "Data table", _v$10 = tableParams.title ? `${tableId}-title` : void 0;
789
795
  _p$.e = web.style(_el$70, _v$0, _p$.e);
790
796
  _v$1 !== _p$.t && web.setAttribute(_el$70, "aria-label", _p$.t = _v$1);