@seed-ship/mcp-ui-solid 6.5.0 → 6.6.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (104) hide show
  1. package/CHANGELOG.md +161 -0
  2. package/README.md +37 -0
  3. package/dist/adapters/connector.cjs +112 -0
  4. package/dist/adapters/connector.cjs.map +1 -0
  5. package/dist/adapters/connector.d.ts +71 -0
  6. package/dist/adapters/connector.d.ts.map +1 -0
  7. package/dist/adapters/connector.js +112 -0
  8. package/dist/adapters/connector.js.map +1 -0
  9. package/dist/adapters/index.d.ts +18 -0
  10. package/dist/adapters/index.d.ts.map +1 -0
  11. package/dist/adapters.cjs +6 -0
  12. package/dist/adapters.cjs.map +1 -0
  13. package/dist/adapters.d.cts +18 -0
  14. package/dist/adapters.d.ts +18 -0
  15. package/dist/adapters.js +6 -0
  16. package/dist/adapters.js.map +1 -0
  17. package/dist/components/ActionGroupRenderer.cjs +12 -3
  18. package/dist/components/ActionGroupRenderer.cjs.map +1 -1
  19. package/dist/components/ActionGroupRenderer.d.ts.map +1 -1
  20. package/dist/components/ActionGroupRenderer.js +12 -3
  21. package/dist/components/ActionGroupRenderer.js.map +1 -1
  22. package/dist/components/ExpandableWrapper.cjs +24 -6
  23. package/dist/components/ExpandableWrapper.cjs.map +1 -1
  24. package/dist/components/ExpandableWrapper.d.ts.map +1 -1
  25. package/dist/components/ExpandableWrapper.js +24 -6
  26. package/dist/components/ExpandableWrapper.js.map +1 -1
  27. package/dist/components/FeedbackInline.cjs +6 -2
  28. package/dist/components/FeedbackInline.cjs.map +1 -1
  29. package/dist/components/FeedbackInline.d.ts +2 -2
  30. package/dist/components/FeedbackInline.d.ts.map +1 -1
  31. package/dist/components/FeedbackInline.js +7 -3
  32. package/dist/components/FeedbackInline.js.map +1 -1
  33. package/dist/components/PresentationFeedback.cjs +207 -0
  34. package/dist/components/PresentationFeedback.cjs.map +1 -0
  35. package/dist/components/PresentationFeedback.d.ts +113 -0
  36. package/dist/components/PresentationFeedback.d.ts.map +1 -0
  37. package/dist/components/PresentationFeedback.js +207 -0
  38. package/dist/components/PresentationFeedback.js.map +1 -0
  39. package/dist/components/StreamingUIRenderer.cjs +82 -195
  40. package/dist/components/StreamingUIRenderer.cjs.map +1 -1
  41. package/dist/components/StreamingUIRenderer.d.ts +25 -5
  42. package/dist/components/StreamingUIRenderer.d.ts.map +1 -1
  43. package/dist/components/StreamingUIRenderer.js +84 -197
  44. package/dist/components/StreamingUIRenderer.js.map +1 -1
  45. package/dist/components/UIResourceRenderer.cjs +22 -15
  46. package/dist/components/UIResourceRenderer.cjs.map +1 -1
  47. package/dist/components/UIResourceRenderer.d.ts.map +1 -1
  48. package/dist/components/UIResourceRenderer.js +22 -15
  49. package/dist/components/UIResourceRenderer.js.map +1 -1
  50. package/dist/components/index.d.ts +2 -0
  51. package/dist/components/index.d.ts.map +1 -1
  52. package/dist/components.cjs +3 -0
  53. package/dist/components.cjs.map +1 -1
  54. package/dist/components.d.cts +2 -0
  55. package/dist/components.d.ts +2 -0
  56. package/dist/components.js +3 -0
  57. package/dist/components.js.map +1 -1
  58. package/dist/context/MCPActionContext.cjs +4 -1
  59. package/dist/context/MCPActionContext.cjs.map +1 -1
  60. package/dist/context/MCPActionContext.d.ts +13 -1
  61. package/dist/context/MCPActionContext.d.ts.map +1 -1
  62. package/dist/context/MCPActionContext.js +4 -1
  63. package/dist/context/MCPActionContext.js.map +1 -1
  64. package/dist/context/MCPUIStringsContext.cjs +38 -0
  65. package/dist/context/MCPUIStringsContext.cjs.map +1 -0
  66. package/dist/context/MCPUIStringsContext.d.ts +95 -0
  67. package/dist/context/MCPUIStringsContext.d.ts.map +1 -0
  68. package/dist/context/MCPUIStringsContext.js +38 -0
  69. package/dist/context/MCPUIStringsContext.js.map +1 -0
  70. package/dist/index.cjs +8 -0
  71. package/dist/index.cjs.map +1 -1
  72. package/dist/index.d.cts +5 -0
  73. package/dist/index.d.ts +5 -0
  74. package/dist/index.d.ts.map +1 -1
  75. package/dist/index.js +8 -0
  76. package/dist/index.js.map +1 -1
  77. package/dist/mcp-ui-spec/dist/schemas.cjs +103 -0
  78. package/dist/mcp-ui-spec/dist/schemas.cjs.map +1 -1
  79. package/dist/mcp-ui-spec/dist/schemas.js +103 -0
  80. package/dist/mcp-ui-spec/dist/schemas.js.map +1 -1
  81. package/docs/briefs/ROADMAP-opendata-macro-mcpui.md +912 -0
  82. package/package.json +17 -5
  83. package/src/adapters/connector.test.ts +165 -0
  84. package/src/adapters/connector.ts +234 -0
  85. package/src/adapters/index.ts +24 -0
  86. package/src/components/ActionGroupRenderer.test.tsx +1 -0
  87. package/src/components/ActionGroupRenderer.tsx +19 -4
  88. package/src/components/ActionSubmit.test.tsx +188 -0
  89. package/src/components/ExpandableWrapper.test.tsx +5 -2
  90. package/src/components/ExpandableWrapper.tsx +8 -6
  91. package/src/components/FeedbackInline.test.tsx +6 -3
  92. package/src/components/FeedbackInline.tsx +8 -6
  93. package/src/components/PresentationFeedback.test.tsx +163 -0
  94. package/src/components/PresentationFeedback.tsx +326 -0
  95. package/src/components/StreamingUIRenderer.parity.test.tsx +158 -0
  96. package/src/components/StreamingUIRenderer.tsx +42 -166
  97. package/src/components/UIResourceRenderer.tsx +19 -6
  98. package/src/components/index.ts +10 -0
  99. package/src/context/MCPActionContext.tsx +17 -1
  100. package/src/context/MCPUIStringsContext.test.tsx +116 -0
  101. package/src/context/MCPUIStringsContext.tsx +128 -0
  102. package/src/index.ts +27 -0
  103. package/tsconfig.tsbuildinfo +1 -1
  104. package/vite.config.ts +1 -0
@@ -7,18 +7,27 @@ var _tmpl$ = /* @__PURE__ */ web.template(`<span class=text-current>`), _tmpl$2
7
7
  const ActionButton = (props) => {
8
8
  const {
9
9
  execute,
10
+ executeAction,
10
11
  isExecuting
11
12
  } = useAction.useAction();
13
+ const isExecutable = () => props.action.action === "tool-call" || props.action.action === "submit";
12
14
  const handleClick = async (e) => {
13
15
  if (props.action.disabled) return;
14
16
  if (props.action.action === "tool-call" && props.action.toolName) {
15
17
  e.preventDefault();
16
18
  await execute(props.action.toolName, props.action.params || {});
19
+ } else if (props.action.action === "submit") {
20
+ e.preventDefault();
21
+ await executeAction({
22
+ action: "submit",
23
+ toolName: props.action.toolName || "submit",
24
+ params: props.action.params || {}
25
+ });
17
26
  } else if (props.action.action === "link" && props.action.url) {
18
27
  window.open(props.action.url, "_blank", "noopener,noreferrer");
19
28
  }
20
29
  };
21
- const isDisabled = () => props.action.disabled || props.action.action === "tool-call" && isExecuting();
30
+ const isDisabled = () => props.action.disabled || isExecutable() && isExecuting();
22
31
  const variantClass = () => {
23
32
  switch (props.action.variant) {
24
33
  case "primary":
@@ -76,7 +85,7 @@ const ActionButton = (props) => {
76
85
  _el$7.$$click = handleClick;
77
86
  web.insert(_el$7, web.createComponent(solidJs.Show, {
78
87
  get when() {
79
- return web.memo(() => !!isExecuting())() && props.action.action === "tool-call";
88
+ return web.memo(() => !!isExecuting())() && isExecutable();
80
89
  },
81
90
  get children() {
82
91
  return web.getNextElement(_tmpl$3);
@@ -84,7 +93,7 @@ const ActionButton = (props) => {
84
93
  }), _el$1, _co$3);
85
94
  web.insert(_el$7, web.createComponent(solidJs.Show, {
86
95
  get when() {
87
- return web.memo(() => !!props.action.icon)() && !(isExecuting() && props.action.action === "tool-call");
96
+ return web.memo(() => !!props.action.icon)() && !(isExecuting() && isExecutable());
88
97
  },
89
98
  get children() {
90
99
  var _el$9 = web.getNextElement(_tmpl$);
@@ -1 +1 @@
1
- {"version":3,"file":"ActionGroupRenderer.cjs","sources":["../../src/components/ActionGroupRenderer.tsx"],"sourcesContent":["/**\n * ActionGroupRenderer - Group of actions with layout options\n * Sprint 3: UX Improvements\n */\n\nimport { Component, For, Show } from 'solid-js'\nimport type { UIComponent, ActionGroupParams, ActionComponentParams } from '../types'\nimport { useAction } from '../hooks/useAction'\n\nexport interface ActionGroupRendererProps {\n /**\n * UIComponent with action-group params (for declarative use)\n */\n component?: UIComponent\n\n /**\n * Direct action group params (alternative to component)\n */\n params?: ActionGroupParams\n}\n\n/**\n * Render a single action button with variants and click handling\n */\nconst ActionButton: Component<{\n action: ActionComponentParams\n index: number\n}> = (props) => {\n const { execute, isExecuting } = useAction()\n\n const handleClick = async (e: MouseEvent) => {\n if (props.action.disabled) return\n\n if (props.action.action === 'tool-call' && props.action.toolName) {\n e.preventDefault()\n await execute(props.action.toolName, props.action.params || {})\n } else if (props.action.action === 'link' && props.action.url) {\n window.open(props.action.url, '_blank', 'noopener,noreferrer')\n }\n }\n\n const isDisabled = () =>\n props.action.disabled || (props.action.action === 'tool-call' && isExecuting())\n\n const variantClass = () => {\n switch (props.action.variant) {\n case 'primary':\n return 'bg-blue-600 text-white hover:bg-blue-700 focus:ring-blue-500'\n case 'secondary':\n return 'bg-gray-200 text-gray-800 hover:bg-gray-300 dark:bg-gray-700 dark:text-white dark:hover:bg-gray-600 focus:ring-gray-500'\n case 'outline':\n return 'border border-gray-300 dark:border-gray-600 text-gray-700 dark:text-gray-300 hover:bg-gray-50 dark:hover:bg-gray-700 focus:ring-gray-500'\n case 'ghost':\n return 'text-gray-700 dark:text-gray-300 hover:bg-gray-100 dark:hover:bg-gray-700 focus:ring-gray-500'\n case 'danger':\n return 'bg-red-600 text-white hover:bg-red-700 focus:ring-red-500'\n default:\n return 'bg-blue-600 text-white hover:bg-blue-700 focus:ring-blue-500'\n }\n }\n\n const sizeClass = () => {\n switch (props.action.size) {\n case 'sm':\n return 'px-2 py-1 text-xs'\n case 'lg':\n return 'px-6 py-3 text-base'\n default:\n return 'px-4 py-2 text-sm'\n }\n }\n\n // Render as link if it's a link action\n if (props.action.type === 'link' || (props.action.action === 'link' && props.action.url)) {\n return (\n <a\n href={props.action.url || '#'}\n target=\"_blank\"\n rel=\"noopener noreferrer\"\n class={`inline-flex items-center justify-center gap-2 rounded-md font-medium transition-colors focus:outline-none focus:ring-2 focus:ring-offset-2 ${variantClass()} ${sizeClass()} ${\n isDisabled() ? 'opacity-50 cursor-not-allowed pointer-events-none' : ''\n }`}\n >\n <Show when={props.action.icon}>\n <span class=\"text-current\">{props.action.icon}</span>\n </Show>\n {props.action.label}\n </a>\n )\n }\n\n return (\n <button\n type=\"button\"\n onClick={handleClick}\n disabled={isDisabled()}\n class={`inline-flex items-center justify-center gap-2 rounded-md font-medium transition-colors focus:outline-none focus:ring-2 focus:ring-offset-2 ${variantClass()} ${sizeClass()} ${\n isDisabled() ? 'opacity-50 cursor-not-allowed' : ''\n }`}\n >\n <Show when={isExecuting() && props.action.action === 'tool-call'}>\n <span class=\"animate-spin h-4 w-4 border-2 border-current border-t-transparent rounded-full\" />\n </Show>\n <Show when={props.action.icon && !(isExecuting() && props.action.action === 'tool-call')}>\n <span class=\"text-current\">{props.action.icon}</span>\n </Show>\n {props.action.label}\n </button>\n )\n}\n\n/**\n * Action group component for rendering multiple actions with consistent layout\n *\n * @example\n * ```tsx\n * const actionGroup: UIComponent = {\n * id: 'form-actions',\n * type: 'action-group',\n * position: { colStart: 1, colSpan: 12 },\n * params: {\n * layout: 'end',\n * gap: 'md',\n * actions: [\n * { label: 'Cancel', variant: 'outline', action: 'link', url: '/back' },\n * { label: 'Save', variant: 'primary', action: 'tool-call', toolName: 'save' },\n * ],\n * },\n * }\n * <ActionGroupRenderer component={actionGroup} />\n * ```\n */\nexport const ActionGroupRenderer: Component<ActionGroupRendererProps> = (props) => {\n const params = () => props.params || (props.component?.params as ActionGroupParams) || { actions: [] }\n\n const layoutClass = () => {\n switch (params()?.layout) {\n case 'vertical':\n return 'flex flex-col'\n case 'space-between':\n return 'flex justify-between'\n case 'end':\n return 'flex justify-end'\n case 'center':\n return 'flex justify-center'\n default: // horizontal\n return 'flex'\n }\n }\n\n const gapClass = () => {\n switch (params()?.gap) {\n case 'none':\n return 'gap-0'\n case 'sm':\n return 'gap-1'\n case 'lg':\n return 'gap-4'\n default: // md\n return 'gap-2'\n }\n }\n\n return (\n <div\n class={`${layoutClass()} ${gapClass()} ${params()?.fullWidth ? 'w-full' : ''}`}\n role=\"group\"\n aria-label={params()?.label || 'Action group'}\n >\n <For each={params()?.actions || []}>\n {(action, index) => <ActionButton action={action} index={index()} />}\n </For>\n </div>\n )\n}\n"],"names":["ActionButton","props","execute","isExecuting","useAction","handleClick","e","action","disabled","toolName","preventDefault","params","url","window","open","isDisabled","variantClass","variant","sizeClass","size","type","_el$","_$getNextElement","_tmpl$2","_el$3","firstChild","_el$4","_co$","_$getNextMarker","nextSibling","_el$5","_el$6","_co$2","_$insert","_$createComponent","Show","when","icon","children","_el$2","_tmpl$","label","_$effect","_p$","_v$","_v$2","_$setAttribute","t","_$className","undefined","_el$7","_tmpl$4","_el$0","_el$1","_co$3","_el$10","_el$11","_co$4","_el$12","_el$13","_co$5","$$click","_$memo","_tmpl$3","_el$9","_v$3","_v$4","_$setProperty","_$runHydrationEvents","ActionGroupRenderer","component","actions","layoutClass","layout","gapClass","gap","_el$14","_tmpl$5","For","each","index","_v$5","fullWidth","_v$6","_$delegateEvents"],"mappings":"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"}
1
+ {"version":3,"file":"ActionGroupRenderer.cjs","sources":["../../src/components/ActionGroupRenderer.tsx"],"sourcesContent":["/**\n * ActionGroupRenderer - Group of actions with layout options\n * Sprint 3: UX Improvements\n */\n\nimport { Component, For, Show } from 'solid-js'\nimport type { UIComponent, ActionGroupParams, ActionComponentParams } from '../types'\nimport { useAction } from '../hooks/useAction'\n\nexport interface ActionGroupRendererProps {\n /**\n * UIComponent with action-group params (for declarative use)\n */\n component?: UIComponent\n\n /**\n * Direct action group params (alternative to component)\n */\n params?: ActionGroupParams\n}\n\n/**\n * Render a single action button with variants and click handling\n */\nconst ActionButton: Component<{\n action: ActionComponentParams\n index: number\n}> = (props) => {\n const { execute, executeAction, isExecuting } = useAction()\n\n // tool-call and submit both go through the host executor — they show a\n // loading state and gate disabled while running. link does neither.\n const isExecutable = () =>\n props.action.action === 'tool-call' || props.action.action === 'submit'\n\n const handleClick = async (e: MouseEvent) => {\n if (props.action.disabled) return\n\n if (props.action.action === 'tool-call' && props.action.toolName) {\n e.preventDefault()\n await execute(props.action.toolName, props.action.params || {})\n } else if (props.action.action === 'submit') {\n // submit is NOT a tool call — route it through the executor with the\n // `action: 'submit'` kind preserved so the host can POST to\n // params.submit_url etc. Works without a surrounding <form>.\n e.preventDefault()\n await executeAction({\n action: 'submit',\n toolName: props.action.toolName || 'submit',\n params: props.action.params || {},\n })\n } else if (props.action.action === 'link' && props.action.url) {\n window.open(props.action.url, '_blank', 'noopener,noreferrer')\n }\n }\n\n const isDisabled = () =>\n props.action.disabled || (isExecutable() && isExecuting())\n\n const variantClass = () => {\n switch (props.action.variant) {\n case 'primary':\n return 'bg-blue-600 text-white hover:bg-blue-700 focus:ring-blue-500'\n case 'secondary':\n return 'bg-gray-200 text-gray-800 hover:bg-gray-300 dark:bg-gray-700 dark:text-white dark:hover:bg-gray-600 focus:ring-gray-500'\n case 'outline':\n return 'border border-gray-300 dark:border-gray-600 text-gray-700 dark:text-gray-300 hover:bg-gray-50 dark:hover:bg-gray-700 focus:ring-gray-500'\n case 'ghost':\n return 'text-gray-700 dark:text-gray-300 hover:bg-gray-100 dark:hover:bg-gray-700 focus:ring-gray-500'\n case 'danger':\n return 'bg-red-600 text-white hover:bg-red-700 focus:ring-red-500'\n default:\n return 'bg-blue-600 text-white hover:bg-blue-700 focus:ring-blue-500'\n }\n }\n\n const sizeClass = () => {\n switch (props.action.size) {\n case 'sm':\n return 'px-2 py-1 text-xs'\n case 'lg':\n return 'px-6 py-3 text-base'\n default:\n return 'px-4 py-2 text-sm'\n }\n }\n\n // Render as link if it's a link action\n if (props.action.type === 'link' || (props.action.action === 'link' && props.action.url)) {\n return (\n <a\n href={props.action.url || '#'}\n target=\"_blank\"\n rel=\"noopener noreferrer\"\n class={`inline-flex items-center justify-center gap-2 rounded-md font-medium transition-colors focus:outline-none focus:ring-2 focus:ring-offset-2 ${variantClass()} ${sizeClass()} ${\n isDisabled() ? 'opacity-50 cursor-not-allowed pointer-events-none' : ''\n }`}\n >\n <Show when={props.action.icon}>\n <span class=\"text-current\">{props.action.icon}</span>\n </Show>\n {props.action.label}\n </a>\n )\n }\n\n return (\n <button\n type=\"button\"\n onClick={handleClick}\n disabled={isDisabled()}\n class={`inline-flex items-center justify-center gap-2 rounded-md font-medium transition-colors focus:outline-none focus:ring-2 focus:ring-offset-2 ${variantClass()} ${sizeClass()} ${\n isDisabled() ? 'opacity-50 cursor-not-allowed' : ''\n }`}\n >\n <Show when={isExecuting() && isExecutable()}>\n <span class=\"animate-spin h-4 w-4 border-2 border-current border-t-transparent rounded-full\" />\n </Show>\n <Show when={props.action.icon && !(isExecuting() && isExecutable())}>\n <span class=\"text-current\">{props.action.icon}</span>\n </Show>\n {props.action.label}\n </button>\n )\n}\n\n/**\n * Action group component for rendering multiple actions with consistent layout\n *\n * @example\n * ```tsx\n * const actionGroup: UIComponent = {\n * id: 'form-actions',\n * type: 'action-group',\n * position: { colStart: 1, colSpan: 12 },\n * params: {\n * layout: 'end',\n * gap: 'md',\n * actions: [\n * { label: 'Cancel', variant: 'outline', action: 'link', url: '/back' },\n * { label: 'Save', variant: 'primary', action: 'tool-call', toolName: 'save' },\n * ],\n * },\n * }\n * <ActionGroupRenderer component={actionGroup} />\n * ```\n */\nexport const ActionGroupRenderer: Component<ActionGroupRendererProps> = (props) => {\n const params = () => props.params || (props.component?.params as ActionGroupParams) || { actions: [] }\n\n const layoutClass = () => {\n switch (params()?.layout) {\n case 'vertical':\n return 'flex flex-col'\n case 'space-between':\n return 'flex justify-between'\n case 'end':\n return 'flex justify-end'\n case 'center':\n return 'flex justify-center'\n default: // horizontal\n return 'flex'\n }\n }\n\n const gapClass = () => {\n switch (params()?.gap) {\n case 'none':\n return 'gap-0'\n case 'sm':\n return 'gap-1'\n case 'lg':\n return 'gap-4'\n default: // md\n return 'gap-2'\n }\n }\n\n return (\n <div\n class={`${layoutClass()} ${gapClass()} ${params()?.fullWidth ? 'w-full' : ''}`}\n role=\"group\"\n aria-label={params()?.label || 'Action group'}\n >\n <For each={params()?.actions || []}>\n {(action, index) => <ActionButton action={action} index={index()} />}\n </For>\n </div>\n )\n}\n"],"names":["ActionButton","props","execute","executeAction","isExecuting","useAction","isExecutable","action","handleClick","e","disabled","toolName","preventDefault","params","url","window","open","isDisabled","variantClass","variant","sizeClass","size","type","_el$","_$getNextElement","_tmpl$2","_el$3","firstChild","_el$4","_co$","_$getNextMarker","nextSibling","_el$5","_el$6","_co$2","_$insert","_$createComponent","Show","when","icon","children","_el$2","_tmpl$","label","_$effect","_p$","_v$","_v$2","_$setAttribute","t","_$className","undefined","_el$7","_tmpl$4","_el$0","_el$1","_co$3","_el$10","_el$11","_co$4","_el$12","_el$13","_co$5","$$click","_$memo","_tmpl$3","_el$9","_v$3","_v$4","_$setProperty","_$runHydrationEvents","ActionGroupRenderer","component","actions","layoutClass","layout","gapClass","gap","_el$14","_tmpl$5","For","each","index","_v$5","fullWidth","_v$6","_$delegateEvents"],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"ActionGroupRenderer.d.ts","sourceRoot":"","sources":["../../src/components/ActionGroupRenderer.tsx"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAE,SAAS,EAAa,MAAM,UAAU,CAAA;AAC/C,OAAO,KAAK,EAAE,WAAW,EAAE,iBAAiB,EAAyB,MAAM,UAAU,CAAA;AAGrF,MAAM,WAAW,wBAAwB;IACvC;;OAEG;IACH,SAAS,CAAC,EAAE,WAAW,CAAA;IAEvB;;OAEG;IACH,MAAM,CAAC,EAAE,iBAAiB,CAAA;CAC3B;AA4FD;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,eAAO,MAAM,mBAAmB,EAAE,SAAS,CAAC,wBAAwB,CA0CnE,CAAA"}
1
+ {"version":3,"file":"ActionGroupRenderer.d.ts","sourceRoot":"","sources":["../../src/components/ActionGroupRenderer.tsx"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAE,SAAS,EAAa,MAAM,UAAU,CAAA;AAC/C,OAAO,KAAK,EAAE,WAAW,EAAE,iBAAiB,EAAyB,MAAM,UAAU,CAAA;AAGrF,MAAM,WAAW,wBAAwB;IACvC;;OAEG;IACH,SAAS,CAAC,EAAE,WAAW,CAAA;IAEvB;;OAEG;IACH,MAAM,CAAC,EAAE,iBAAiB,CAAA;CAC3B;AA2GD;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,eAAO,MAAM,mBAAmB,EAAE,SAAS,CAAC,wBAAwB,CA0CnE,CAAA"}
@@ -5,18 +5,27 @@ var _tmpl$ = /* @__PURE__ */ template(`<span class=text-current>`), _tmpl$2 = /*
5
5
  const ActionButton = (props) => {
6
6
  const {
7
7
  execute,
8
+ executeAction,
8
9
  isExecuting
9
10
  } = useAction();
11
+ const isExecutable = () => props.action.action === "tool-call" || props.action.action === "submit";
10
12
  const handleClick = async (e) => {
11
13
  if (props.action.disabled) return;
12
14
  if (props.action.action === "tool-call" && props.action.toolName) {
13
15
  e.preventDefault();
14
16
  await execute(props.action.toolName, props.action.params || {});
17
+ } else if (props.action.action === "submit") {
18
+ e.preventDefault();
19
+ await executeAction({
20
+ action: "submit",
21
+ toolName: props.action.toolName || "submit",
22
+ params: props.action.params || {}
23
+ });
15
24
  } else if (props.action.action === "link" && props.action.url) {
16
25
  window.open(props.action.url, "_blank", "noopener,noreferrer");
17
26
  }
18
27
  };
19
- const isDisabled = () => props.action.disabled || props.action.action === "tool-call" && isExecuting();
28
+ const isDisabled = () => props.action.disabled || isExecutable() && isExecuting();
20
29
  const variantClass = () => {
21
30
  switch (props.action.variant) {
22
31
  case "primary":
@@ -74,7 +83,7 @@ const ActionButton = (props) => {
74
83
  _el$7.$$click = handleClick;
75
84
  insert(_el$7, createComponent(Show, {
76
85
  get when() {
77
- return memo(() => !!isExecuting())() && props.action.action === "tool-call";
86
+ return memo(() => !!isExecuting())() && isExecutable();
78
87
  },
79
88
  get children() {
80
89
  return getNextElement(_tmpl$3);
@@ -82,7 +91,7 @@ const ActionButton = (props) => {
82
91
  }), _el$1, _co$3);
83
92
  insert(_el$7, createComponent(Show, {
84
93
  get when() {
85
- return memo(() => !!props.action.icon)() && !(isExecuting() && props.action.action === "tool-call");
94
+ return memo(() => !!props.action.icon)() && !(isExecuting() && isExecutable());
86
95
  },
87
96
  get children() {
88
97
  var _el$9 = getNextElement(_tmpl$);
@@ -1 +1 @@
1
- {"version":3,"file":"ActionGroupRenderer.js","sources":["../../src/components/ActionGroupRenderer.tsx"],"sourcesContent":["/**\n * ActionGroupRenderer - Group of actions with layout options\n * Sprint 3: UX Improvements\n */\n\nimport { Component, For, Show } from 'solid-js'\nimport type { UIComponent, ActionGroupParams, ActionComponentParams } from '../types'\nimport { useAction } from '../hooks/useAction'\n\nexport interface ActionGroupRendererProps {\n /**\n * UIComponent with action-group params (for declarative use)\n */\n component?: UIComponent\n\n /**\n * Direct action group params (alternative to component)\n */\n params?: ActionGroupParams\n}\n\n/**\n * Render a single action button with variants and click handling\n */\nconst ActionButton: Component<{\n action: ActionComponentParams\n index: number\n}> = (props) => {\n const { execute, isExecuting } = useAction()\n\n const handleClick = async (e: MouseEvent) => {\n if (props.action.disabled) return\n\n if (props.action.action === 'tool-call' && props.action.toolName) {\n e.preventDefault()\n await execute(props.action.toolName, props.action.params || {})\n } else if (props.action.action === 'link' && props.action.url) {\n window.open(props.action.url, '_blank', 'noopener,noreferrer')\n }\n }\n\n const isDisabled = () =>\n props.action.disabled || (props.action.action === 'tool-call' && isExecuting())\n\n const variantClass = () => {\n switch (props.action.variant) {\n case 'primary':\n return 'bg-blue-600 text-white hover:bg-blue-700 focus:ring-blue-500'\n case 'secondary':\n return 'bg-gray-200 text-gray-800 hover:bg-gray-300 dark:bg-gray-700 dark:text-white dark:hover:bg-gray-600 focus:ring-gray-500'\n case 'outline':\n return 'border border-gray-300 dark:border-gray-600 text-gray-700 dark:text-gray-300 hover:bg-gray-50 dark:hover:bg-gray-700 focus:ring-gray-500'\n case 'ghost':\n return 'text-gray-700 dark:text-gray-300 hover:bg-gray-100 dark:hover:bg-gray-700 focus:ring-gray-500'\n case 'danger':\n return 'bg-red-600 text-white hover:bg-red-700 focus:ring-red-500'\n default:\n return 'bg-blue-600 text-white hover:bg-blue-700 focus:ring-blue-500'\n }\n }\n\n const sizeClass = () => {\n switch (props.action.size) {\n case 'sm':\n return 'px-2 py-1 text-xs'\n case 'lg':\n return 'px-6 py-3 text-base'\n default:\n return 'px-4 py-2 text-sm'\n }\n }\n\n // Render as link if it's a link action\n if (props.action.type === 'link' || (props.action.action === 'link' && props.action.url)) {\n return (\n <a\n href={props.action.url || '#'}\n target=\"_blank\"\n rel=\"noopener noreferrer\"\n class={`inline-flex items-center justify-center gap-2 rounded-md font-medium transition-colors focus:outline-none focus:ring-2 focus:ring-offset-2 ${variantClass()} ${sizeClass()} ${\n isDisabled() ? 'opacity-50 cursor-not-allowed pointer-events-none' : ''\n }`}\n >\n <Show when={props.action.icon}>\n <span class=\"text-current\">{props.action.icon}</span>\n </Show>\n {props.action.label}\n </a>\n )\n }\n\n return (\n <button\n type=\"button\"\n onClick={handleClick}\n disabled={isDisabled()}\n class={`inline-flex items-center justify-center gap-2 rounded-md font-medium transition-colors focus:outline-none focus:ring-2 focus:ring-offset-2 ${variantClass()} ${sizeClass()} ${\n isDisabled() ? 'opacity-50 cursor-not-allowed' : ''\n }`}\n >\n <Show when={isExecuting() && props.action.action === 'tool-call'}>\n <span class=\"animate-spin h-4 w-4 border-2 border-current border-t-transparent rounded-full\" />\n </Show>\n <Show when={props.action.icon && !(isExecuting() && props.action.action === 'tool-call')}>\n <span class=\"text-current\">{props.action.icon}</span>\n </Show>\n {props.action.label}\n </button>\n )\n}\n\n/**\n * Action group component for rendering multiple actions with consistent layout\n *\n * @example\n * ```tsx\n * const actionGroup: UIComponent = {\n * id: 'form-actions',\n * type: 'action-group',\n * position: { colStart: 1, colSpan: 12 },\n * params: {\n * layout: 'end',\n * gap: 'md',\n * actions: [\n * { label: 'Cancel', variant: 'outline', action: 'link', url: '/back' },\n * { label: 'Save', variant: 'primary', action: 'tool-call', toolName: 'save' },\n * ],\n * },\n * }\n * <ActionGroupRenderer component={actionGroup} />\n * ```\n */\nexport const ActionGroupRenderer: Component<ActionGroupRendererProps> = (props) => {\n const params = () => props.params || (props.component?.params as ActionGroupParams) || { actions: [] }\n\n const layoutClass = () => {\n switch (params()?.layout) {\n case 'vertical':\n return 'flex flex-col'\n case 'space-between':\n return 'flex justify-between'\n case 'end':\n return 'flex justify-end'\n case 'center':\n return 'flex justify-center'\n default: // horizontal\n return 'flex'\n }\n }\n\n const gapClass = () => {\n switch (params()?.gap) {\n case 'none':\n return 'gap-0'\n case 'sm':\n return 'gap-1'\n case 'lg':\n return 'gap-4'\n default: // md\n return 'gap-2'\n }\n }\n\n return (\n <div\n class={`${layoutClass()} ${gapClass()} ${params()?.fullWidth ? 'w-full' : ''}`}\n role=\"group\"\n aria-label={params()?.label || 'Action group'}\n >\n <For each={params()?.actions || []}>\n {(action, index) => <ActionButton action={action} index={index()} />}\n </For>\n </div>\n )\n}\n"],"names":["ActionButton","props","execute","isExecuting","useAction","handleClick","e","action","disabled","toolName","preventDefault","params","url","window","open","isDisabled","variantClass","variant","sizeClass","size","type","_el$","_$getNextElement","_tmpl$2","_el$3","firstChild","_el$4","_co$","_$getNextMarker","nextSibling","_el$5","_el$6","_co$2","_$insert","_$createComponent","Show","when","icon","children","_el$2","_tmpl$","label","_$effect","_p$","_v$","_v$2","_$setAttribute","t","_$className","undefined","_el$7","_tmpl$4","_el$0","_el$1","_co$3","_el$10","_el$11","_co$4","_el$12","_el$13","_co$5","$$click","_$memo","_tmpl$3","_el$9","_v$3","_v$4","_$setProperty","_$runHydrationEvents","ActionGroupRenderer","component","actions","layoutClass","layout","gapClass","gap","_el$14","_tmpl$5","For","each","index","_v$5","fullWidth","_v$6","_$delegateEvents"],"mappings":"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"}
1
+ {"version":3,"file":"ActionGroupRenderer.js","sources":["../../src/components/ActionGroupRenderer.tsx"],"sourcesContent":["/**\n * ActionGroupRenderer - Group of actions with layout options\n * Sprint 3: UX Improvements\n */\n\nimport { Component, For, Show } from 'solid-js'\nimport type { UIComponent, ActionGroupParams, ActionComponentParams } from '../types'\nimport { useAction } from '../hooks/useAction'\n\nexport interface ActionGroupRendererProps {\n /**\n * UIComponent with action-group params (for declarative use)\n */\n component?: UIComponent\n\n /**\n * Direct action group params (alternative to component)\n */\n params?: ActionGroupParams\n}\n\n/**\n * Render a single action button with variants and click handling\n */\nconst ActionButton: Component<{\n action: ActionComponentParams\n index: number\n}> = (props) => {\n const { execute, executeAction, isExecuting } = useAction()\n\n // tool-call and submit both go through the host executor — they show a\n // loading state and gate disabled while running. link does neither.\n const isExecutable = () =>\n props.action.action === 'tool-call' || props.action.action === 'submit'\n\n const handleClick = async (e: MouseEvent) => {\n if (props.action.disabled) return\n\n if (props.action.action === 'tool-call' && props.action.toolName) {\n e.preventDefault()\n await execute(props.action.toolName, props.action.params || {})\n } else if (props.action.action === 'submit') {\n // submit is NOT a tool call — route it through the executor with the\n // `action: 'submit'` kind preserved so the host can POST to\n // params.submit_url etc. Works without a surrounding <form>.\n e.preventDefault()\n await executeAction({\n action: 'submit',\n toolName: props.action.toolName || 'submit',\n params: props.action.params || {},\n })\n } else if (props.action.action === 'link' && props.action.url) {\n window.open(props.action.url, '_blank', 'noopener,noreferrer')\n }\n }\n\n const isDisabled = () =>\n props.action.disabled || (isExecutable() && isExecuting())\n\n const variantClass = () => {\n switch (props.action.variant) {\n case 'primary':\n return 'bg-blue-600 text-white hover:bg-blue-700 focus:ring-blue-500'\n case 'secondary':\n return 'bg-gray-200 text-gray-800 hover:bg-gray-300 dark:bg-gray-700 dark:text-white dark:hover:bg-gray-600 focus:ring-gray-500'\n case 'outline':\n return 'border border-gray-300 dark:border-gray-600 text-gray-700 dark:text-gray-300 hover:bg-gray-50 dark:hover:bg-gray-700 focus:ring-gray-500'\n case 'ghost':\n return 'text-gray-700 dark:text-gray-300 hover:bg-gray-100 dark:hover:bg-gray-700 focus:ring-gray-500'\n case 'danger':\n return 'bg-red-600 text-white hover:bg-red-700 focus:ring-red-500'\n default:\n return 'bg-blue-600 text-white hover:bg-blue-700 focus:ring-blue-500'\n }\n }\n\n const sizeClass = () => {\n switch (props.action.size) {\n case 'sm':\n return 'px-2 py-1 text-xs'\n case 'lg':\n return 'px-6 py-3 text-base'\n default:\n return 'px-4 py-2 text-sm'\n }\n }\n\n // Render as link if it's a link action\n if (props.action.type === 'link' || (props.action.action === 'link' && props.action.url)) {\n return (\n <a\n href={props.action.url || '#'}\n target=\"_blank\"\n rel=\"noopener noreferrer\"\n class={`inline-flex items-center justify-center gap-2 rounded-md font-medium transition-colors focus:outline-none focus:ring-2 focus:ring-offset-2 ${variantClass()} ${sizeClass()} ${\n isDisabled() ? 'opacity-50 cursor-not-allowed pointer-events-none' : ''\n }`}\n >\n <Show when={props.action.icon}>\n <span class=\"text-current\">{props.action.icon}</span>\n </Show>\n {props.action.label}\n </a>\n )\n }\n\n return (\n <button\n type=\"button\"\n onClick={handleClick}\n disabled={isDisabled()}\n class={`inline-flex items-center justify-center gap-2 rounded-md font-medium transition-colors focus:outline-none focus:ring-2 focus:ring-offset-2 ${variantClass()} ${sizeClass()} ${\n isDisabled() ? 'opacity-50 cursor-not-allowed' : ''\n }`}\n >\n <Show when={isExecuting() && isExecutable()}>\n <span class=\"animate-spin h-4 w-4 border-2 border-current border-t-transparent rounded-full\" />\n </Show>\n <Show when={props.action.icon && !(isExecuting() && isExecutable())}>\n <span class=\"text-current\">{props.action.icon}</span>\n </Show>\n {props.action.label}\n </button>\n )\n}\n\n/**\n * Action group component for rendering multiple actions with consistent layout\n *\n * @example\n * ```tsx\n * const actionGroup: UIComponent = {\n * id: 'form-actions',\n * type: 'action-group',\n * position: { colStart: 1, colSpan: 12 },\n * params: {\n * layout: 'end',\n * gap: 'md',\n * actions: [\n * { label: 'Cancel', variant: 'outline', action: 'link', url: '/back' },\n * { label: 'Save', variant: 'primary', action: 'tool-call', toolName: 'save' },\n * ],\n * },\n * }\n * <ActionGroupRenderer component={actionGroup} />\n * ```\n */\nexport const ActionGroupRenderer: Component<ActionGroupRendererProps> = (props) => {\n const params = () => props.params || (props.component?.params as ActionGroupParams) || { actions: [] }\n\n const layoutClass = () => {\n switch (params()?.layout) {\n case 'vertical':\n return 'flex flex-col'\n case 'space-between':\n return 'flex justify-between'\n case 'end':\n return 'flex justify-end'\n case 'center':\n return 'flex justify-center'\n default: // horizontal\n return 'flex'\n }\n }\n\n const gapClass = () => {\n switch (params()?.gap) {\n case 'none':\n return 'gap-0'\n case 'sm':\n return 'gap-1'\n case 'lg':\n return 'gap-4'\n default: // md\n return 'gap-2'\n }\n }\n\n return (\n <div\n class={`${layoutClass()} ${gapClass()} ${params()?.fullWidth ? 'w-full' : ''}`}\n role=\"group\"\n aria-label={params()?.label || 'Action group'}\n >\n <For each={params()?.actions || []}>\n {(action, index) => <ActionButton action={action} index={index()} />}\n </For>\n </div>\n )\n}\n"],"names":["ActionButton","props","execute","executeAction","isExecuting","useAction","isExecutable","action","handleClick","e","disabled","toolName","preventDefault","params","url","window","open","isDisabled","variantClass","variant","sizeClass","size","type","_el$","_$getNextElement","_tmpl$2","_el$3","firstChild","_el$4","_co$","_$getNextMarker","nextSibling","_el$5","_el$6","_co$2","_$insert","_$createComponent","Show","when","icon","children","_el$2","_tmpl$","label","_$effect","_p$","_v$","_v$2","_$setAttribute","t","_$className","undefined","_el$7","_tmpl$4","_el$0","_el$1","_co$3","_el$10","_el$11","_co$4","_el$12","_el$13","_co$5","$$click","_$memo","_tmpl$3","_el$9","_v$3","_v$4","_$setProperty","_$runHydrationEvents","ActionGroupRenderer","component","actions","layoutClass","layout","gapClass","gap","_el$14","_tmpl$5","For","each","index","_v$5","fullWidth","_v$6","_$delegateEvents"],"mappings":"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"}
@@ -2,7 +2,8 @@
2
2
  Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
3
3
  const web = require("solid-js/web");
4
4
  const solidJs = require("solid-js");
5
- var _tmpl$ = /* @__PURE__ */ web.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__ */ web.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__ */ web.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 min-h-0 overflow-auto p-4 flex flex-col">`), _tmpl$4 = /* @__PURE__ */ web.template(`<style>
5
+ const MCPUIStringsContext = require("../context/MCPUIStringsContext.cjs");
6
+ var _tmpl$ = /* @__PURE__ */ web.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__ */ web.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__ */ web.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"><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 min-h-0 overflow-auto p-4 flex flex-col">`), _tmpl$4 = /* @__PURE__ */ web.template(`<style>
6
7
  @keyframes expandable-fade-in {
7
8
  from { opacity: 0; }
8
9
  to { opacity: 1; }
@@ -11,12 +12,13 @@ var _tmpl$ = /* @__PURE__ */ web.template(`<svg class="w-5 h-5"fill=none viewBox
11
12
  from { opacity: 0; transform: scale(0.97); }
12
13
  to { opacity: 1; transform: scale(1); }
13
14
  }
14
- `), _tmpl$5 = /* @__PURE__ */ web.template(`<div class="relative group"><div><div></div></div><button 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
+ `), _tmpl$5 = /* @__PURE__ */ web.template(`<div class="relative group"><div><div></div></div><button 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
16
  const ExpandedContext = solidJs.createContext(() => false);
16
17
  const useExpanded = () => solidJs.useContext(ExpandedContext);
17
18
  const ExpandableWrapper = (props) => {
18
19
  const [isExpanded, setIsExpanded] = solidJs.createSignal(false);
19
20
  const [copied, setCopied] = solidJs.createSignal(false);
21
+ const strings = MCPUIStringsContext.useMCPUIStrings();
20
22
  let dialogRef;
21
23
  let contentRef;
22
24
  let inlineSlotRef;
@@ -91,7 +93,7 @@ const ExpandableWrapper = (props) => {
91
93
  typeof _ref$3 === "function" ? web.use(_ref$3, _el$5) : dialogRef = _el$5;
92
94
  _el$5.$$click = handleBackdropClick;
93
95
  _el$6.$$click = (e) => e.stopPropagation();
94
- web.insert(_el$8, () => props.title || "Expanded View");
96
+ web.insert(_el$8, () => props.title || strings.expandedView);
95
97
  web.insert(_el$9, web.createComponent(solidJs.Show, {
96
98
  get when() {
97
99
  return props.copyData;
@@ -111,7 +113,7 @@ const ExpandableWrapper = (props) => {
111
113
  }
112
114
  }));
113
115
  web.effect((_p$) => {
114
- var _v$ = props.copyLabel || "Copy to clipboard", _v$2 = props.copyLabel || "Copy to clipboard";
116
+ var _v$ = props.copyLabel || strings.copyToClipboard, _v$2 = props.copyLabel || strings.copyToClipboard;
115
117
  _v$ !== _p$.e && web.setAttribute(_el$0, "title", _p$.e = _v$);
116
118
  _v$2 !== _p$.t && web.setAttribute(_el$0, "aria-label", _p$.t = _v$2);
117
119
  return _p$;
@@ -126,7 +128,15 @@ const ExpandableWrapper = (props) => {
126
128
  _el$10.$$click = handleClose;
127
129
  var _ref$4 = modalSlotRef;
128
130
  typeof _ref$4 === "function" ? web.use(_ref$4, _el$13) : modalSlotRef = _el$13;
129
- web.effect(() => web.setAttribute(_el$5, "aria-label", props.title || "Expanded view"));
131
+ web.effect((_p$) => {
132
+ var _v$3 = props.title || strings.expandedView, _v$4 = strings.closeExpandedView;
133
+ _v$3 !== _p$.e && web.setAttribute(_el$5, "aria-label", _p$.e = _v$3);
134
+ _v$4 !== _p$.t && web.setAttribute(_el$10, "aria-label", _p$.t = _v$4);
135
+ return _p$;
136
+ }, {
137
+ e: void 0,
138
+ t: void 0
139
+ });
130
140
  web.runHydrationEvents();
131
141
  return _el$5;
132
142
  })(), web.getNextElement(_tmpl$4)];
@@ -134,7 +144,15 @@ const ExpandableWrapper = (props) => {
134
144
  });
135
145
  }
136
146
  }), _el$16, _co$2);
137
- web.effect(() => web.className(_el$4, `absolute top-2 right-2 z-10 ${props.toolbarVariant === "always-visible" ? "opacity-60 hover:opacity-100" : "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`));
147
+ web.effect((_p$) => {
148
+ var _v$5 = `absolute top-2 right-2 z-10 ${props.toolbarVariant === "always-visible" ? "opacity-60 hover:opacity-100" : "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`, _v$6 = strings.expand;
149
+ _v$5 !== _p$.e && web.className(_el$4, _p$.e = _v$5);
150
+ _v$6 !== _p$.t && web.setAttribute(_el$4, "title", _p$.t = _v$6);
151
+ return _p$;
152
+ }, {
153
+ e: void 0,
154
+ t: void 0
155
+ });
138
156
  web.runHydrationEvents();
139
157
  return _el$;
140
158
  })();
@@ -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, 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 * Visibility behavior of the inline expand button (v6.3.0 — axe 4 deposium handoff).\n * - `'hover'` (default) : opacity 0, fades to 0.7 on parent group hover.\n * Backwards-compatible — pre-v6.3.0 behavior.\n * - `'always-visible'` : opacity 0.6 permanent, 1 on hover. Use this when\n * the inline button needs to be discoverable without hovering — esp.\n * on touch surfaces and consumer themes where the hover-only pattern\n * hides the affordance.\n */\n toolbarVariant?: 'hover' | 'always-visible'\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 — visibility per `toolbarVariant` (default 'hover') */}\n <button\n onClick={handleOpen}\n class={`absolute top-2 right-2 z-10 ${\n props.toolbarVariant === 'always-visible'\n ? 'opacity-60 hover:opacity-100'\n : 'opacity-0 group-hover:opacity-70 hover:!opacity-100'\n } 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 v6.1.0 : `flex flex-col` lets aware children opt into\n `flex-1 min-h-0` to fill the modal vertically (chart,\n table, map, graph). Unaware children keep working\n thanks to `overflow-auto` (their natural height\n scrolls if it overflows the slot). */}\n <div class=\"flex-1 min-h-0 overflow-auto p-4 flex flex-col\" 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","_$className","toolbarVariant","_$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'\nimport { useMCPUIStrings } from '../context/MCPUIStringsContext'\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 * Visibility behavior of the inline expand button (v6.3.0 — axe 4 deposium handoff).\n * - `'hover'` (default) : opacity 0, fades to 0.7 on parent group hover.\n * Backwards-compatible — pre-v6.3.0 behavior.\n * - `'always-visible'` : opacity 0.6 permanent, 1 on hover. Use this when\n * the inline button needs to be discoverable without hovering — esp.\n * on touch surfaces and consumer themes where the hover-only pattern\n * hides the affordance.\n */\n toolbarVariant?: 'hover' | 'always-visible'\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 const strings = useMCPUIStrings()\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 — visibility per `toolbarVariant` (default 'hover') */}\n <button\n onClick={handleOpen}\n class={`absolute top-2 right-2 z-10 ${\n props.toolbarVariant === 'always-visible'\n ? 'opacity-60 hover:opacity-100'\n : 'opacity-0 group-hover:opacity-70 hover:!opacity-100'\n } 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={strings.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 || strings.expandedView}\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 || strings.expandedView}\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 || strings.copyToClipboard}\n aria-label={props.copyLabel || strings.copyToClipboard}\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={strings.closeExpandedView}\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 v6.1.0 : `flex flex-col` lets aware children opt into\n `flex-1 min-h-0` to fill the modal vertically (chart,\n table, map, graph). Unaware children keep working\n thanks to `overflow-auto` (their natural height\n scrolls if it overflows the slot). */}\n <div class=\"flex-1 min-h-0 overflow-auto p-4 flex flex-col\" 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","strings","useMCPUIStrings","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","expandedView","_el$0","_tmpl$2","fallback","_tmpl$6","_tmpl$","_$effect","_p$","_v$","copyLabel","copyToClipboard","_v$2","_$setAttribute","t","undefined","_$runHydrationEvents","_ref$4","_v$3","_v$4","closeExpandedView","_tmpl$4","_v$5","toolbarVariant","_v$6","expand","_$className","_$delegateEvents"],"mappings":";;;;;;;;;;;;;;;AAaA,MAAMA,kBAAkBC,QAAAA,cAAiC,MAAM,KAAK;AAG7D,MAAMC,cAAcA,MAAMC,QAAAA,WAAWH,eAAe;AAkCpD,MAAMI,oBAAwDC,CAAAA,UAAU;AAC7E,QAAM,CAACC,YAAYC,aAAa,IAAIC,QAAAA,aAAa,KAAK;AACtD,QAAM,CAACC,QAAQC,SAAS,IAAIF,QAAAA,aAAa,KAAK;AAC9C,QAAMG,UAAUC,oBAAAA,gBAAAA;AAChB,MAAIC;AACJ,MAAIC;AACJ,MAAIC;AACJ,MAAIC;AAEJ,QAAMC,aAAaA,MAAMV,cAAc,IAAI;AAC3C,QAAMW,cAAcA,MAAMX,cAAc,KAAK;AAG7CY,UAAAA,aAAa,MAAM;AACjB,QAAI,CAACL,WAAY;AAEjB,QAAIR,cAAc;AAEhBU,mDAAcI,YAAYN;AAAAA,IAC5B,OAAO;AAELC,qDAAeK,YAAYN;AAAAA,IAC7B;AAAA,EACF,CAAC;AAGDK,UAAAA,aAAa,MAAM;AACjB,QAAI,CAACb,aAAc;AAEnB,UAAMe,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,QAAIb,cAAc;AAChB,YAAMuB,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,CAACjC,MAAMkC,SAAU;AACrB,QAAI;AACF,YAAMC,UAAUC,UAAUC,UAAUrC,MAAMkC,QAAQ;AAClD7B,gBAAU,IAAI;AACduB,iBAAW,MAAMvB,UAAU,KAAK,GAAG,GAAI;AAAA,IACzC,SAASiC,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,oBACjB9D,gBAAgB+D,UAAQ;AAAA,MAACC,OAAO1D;AAAAA,MAAU,IAAA2D,WAAA;AAAA,eACxC5D,MAAM4D;AAAAA,MAAQ;AAAA,IAAA,CAAA,CAAA;AAAAb,UAAAc,UAOVjD;AAAU4C,eAAAf,MAAAgB,IAAAA,gBAepBK,cAAI;AAAA,MAAA,IAACC,OAAI;AAAA,eAAE9D,WAAAA;AAAAA,MAAY;AAAA,MAAA,IAAA2D,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,MAK9BrE,MAAM8E,SAASxE,QAAQyE,YAAY;AAAAvB,yBAAAc,OAAAb,IAAAA,gBAInCK,cAAI;AAAA,gBAAA,IAACC,OAAI;AAAA,yBAAE/D,MAAMkC;AAAAA,gBAAQ;AAAA,gBAAA,IAAA0B,WAAA;AAAA,sBAAAoB,QAAAtC,IAAAA,eAAAuC,OAAA;AAAAD,wBAAAnB,UAEb5B;AAAUuB,6BAAAwB,OAAAvB,IAAAA,gBAKlBK,cAAI;AAAA,oBAAA,IACHC,OAAI;AAAA,6BAAE,CAAC3D,OAAAA;AAAAA,oBAAQ;AAAA,oBAAA,IACf8E,WAAQ;AAAA,6BAAAxC,IAAAA,eAAAyC,OAAA;AAAA,oBAAA;AAAA,oBAAA,IAAAvB,WAAA;AAAA,6BAAAlB,IAAAA,eAAA0C,MAAA;AAAA,oBAAA;AAAA,kBAAA,CAAA,CAAA;AAAAC,sBAAAA,OAAAC,CAAAA,QAAA;AAAA,wBAAAC,MALHvF,MAAMwF,aAAalF,QAAQmF,iBAAeC,OACrC1F,MAAMwF,aAAalF,QAAQmF;AAAeF,4BAAAD,IAAArE,KAAA0E,IAAAA,aAAAX,OAAA,SAAAM,IAAArE,IAAAsE,GAAA;AAAAG,6BAAAJ,IAAAM,KAAAD,IAAAA,aAAAX,OAAA,cAAAM,IAAAM,IAAAF,IAAA;AAAA,2BAAAJ;AAAAA,kBAAA,GAAA;AAAA,oBAAArE,GAAA4E;AAAAA,oBAAAD,GAAAC;AAAAA,kBAAAA,CAAA;AAAAC,yCAAAA;AAAA,yBAAAd;AAAAA,gBAAA;AAAA,cAAA,CAAA,GAAAR,QAAAC,IAAA;AAAAC,qBAAAb,UAkB/ChD;AAAW,kBAAAkF,SAiBuCpF;AAAY,qBAAAoF,WAAA,aAAAzC,IAAAA,IAAAyC,QAAApB,MAAA,IAAZhE,eAAYgE;AAAAU,kBAAAA,OAAAC,CAAAA,QAAA;AAAA,oBAAAU,OAzDnEhG,MAAM8E,SAASxE,QAAQyE,cAAYkB,OA0C3B3F,QAAQ4F;AAAiBF,yBAAAV,IAAArE,KAAA0E,IAAAA,aAAA1B,OAAA,cAAAqB,IAAArE,IAAA+E,IAAA;AAAAC,yBAAAX,IAAAM,KAAAD,IAAAA,aAAAjB,QAAA,cAAAY,IAAAM,IAAAK,IAAA;AAAA,uBAAAX;AAAAA,cAAA,GAAA;AAAA,gBAAArE,GAAA4E;AAAAA,gBAAAD,GAAAC;AAAAA,cAAAA,CAAA;AAAAC,qCAAAA;AAAA,qBAAA7B;AAAAA,YAAA,GAAA,GAAAvB,mBAAAyD,OAAA,CAAA;AAAA,UAAA;AAAA,QAAA,CAAA;AAAA,MAAA;AAAA,IAAA,CAAA,GAAAjD,QAAAC,KAAA;AAAAkC,QAAAA,OAAAC,CAAAA,QAAA;AAAA,UAAAc,OAhE1C,+BACLpG,MAAMqG,mBAAmB,mBACrB,iCACA,qDAAqD,+JACkGC,OACtJhG,QAAQiG;AAAMH,eAAAd,IAAArE,KAAAuF,IAAAA,UAAAzD,OAAAuC,IAAArE,IAAAmF,IAAA;AAAAE,eAAAhB,IAAAM,KAAAD,IAAAA,aAAA5C,OAAA,SAAAuC,IAAAM,IAAAU,IAAA;AAAA,aAAAhB;AAAAA,IAAA,GAAA;AAAA,MAAArE,GAAA4E;AAAAA,MAAAD,GAAAC;AAAAA,IAAAA,CAAA;AAAAC,2BAAAA;AAAA,WAAArD;AAAAA,EAAA,GAAA;AA4F7B;AAACgE,IAAAA,eAAA,CAAA,OAAA,CAAA;;;"}
@@ -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,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;IAClB;;;;;;;;OAQG;IACH,cAAc,CAAC,EAAE,OAAO,GAAG,gBAAgB,CAAA;CAC5C;AAED;;;;;;;;;;GAUG;AACH,eAAO,MAAM,iBAAiB,EAAE,SAAS,CAAC,sBAAsB,CAkL/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;AAO3H,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;IAClB;;;;;;;;OAQG;IACH,cAAc,CAAC,EAAE,OAAO,GAAG,gBAAgB,CAAA;CAC5C;AAED;;;;;;;;;;GAUG;AACH,eAAO,MAAM,iBAAiB,EAAE,SAAS,CAAC,sBAAsB,CAmL/D,CAAA"}
@@ -1,6 +1,7 @@
1
1
  import { delegateEvents, getNextElement, template, getNextMarker, insert, createComponent, Portal, use, effect, setAttribute, runHydrationEvents, className } from "solid-js/web";
2
2
  import { createContext, useContext, createSignal, createEffect, onCleanup, Show } from "solid-js";
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 min-h-0 overflow-auto p-4 flex flex-col">`), _tmpl$4 = /* @__PURE__ */ template(`<style>
3
+ import { useMCPUIStrings } from "../context/MCPUIStringsContext.js";
4
+ 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"><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 min-h-0 overflow-auto p-4 flex flex-col">`), _tmpl$4 = /* @__PURE__ */ template(`<style>
4
5
  @keyframes expandable-fade-in {
5
6
  from { opacity: 0; }
6
7
  to { opacity: 1; }
@@ -9,12 +10,13 @@ var _tmpl$ = /* @__PURE__ */ template(`<svg class="w-5 h-5"fill=none viewBox="0
9
10
  from { opacity: 0; transform: scale(0.97); }
10
11
  to { opacity: 1; transform: scale(1); }
11
12
  }
12
- `), _tmpl$5 = /* @__PURE__ */ template(`<div class="relative group"><div><div></div></div><button 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
+ `), _tmpl$5 = /* @__PURE__ */ template(`<div class="relative group"><div><div></div></div><button 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
14
  const ExpandedContext = createContext(() => false);
14
15
  const useExpanded = () => useContext(ExpandedContext);
15
16
  const ExpandableWrapper = (props) => {
16
17
  const [isExpanded, setIsExpanded] = createSignal(false);
17
18
  const [copied, setCopied] = createSignal(false);
19
+ const strings = useMCPUIStrings();
18
20
  let dialogRef;
19
21
  let contentRef;
20
22
  let inlineSlotRef;
@@ -89,7 +91,7 @@ const ExpandableWrapper = (props) => {
89
91
  typeof _ref$3 === "function" ? use(_ref$3, _el$5) : dialogRef = _el$5;
90
92
  _el$5.$$click = handleBackdropClick;
91
93
  _el$6.$$click = (e) => e.stopPropagation();
92
- insert(_el$8, () => props.title || "Expanded View");
94
+ insert(_el$8, () => props.title || strings.expandedView);
93
95
  insert(_el$9, createComponent(Show, {
94
96
  get when() {
95
97
  return props.copyData;
@@ -109,7 +111,7 @@ const ExpandableWrapper = (props) => {
109
111
  }
110
112
  }));
111
113
  effect((_p$) => {
112
- var _v$ = props.copyLabel || "Copy to clipboard", _v$2 = props.copyLabel || "Copy to clipboard";
114
+ var _v$ = props.copyLabel || strings.copyToClipboard, _v$2 = props.copyLabel || strings.copyToClipboard;
113
115
  _v$ !== _p$.e && setAttribute(_el$0, "title", _p$.e = _v$);
114
116
  _v$2 !== _p$.t && setAttribute(_el$0, "aria-label", _p$.t = _v$2);
115
117
  return _p$;
@@ -124,7 +126,15 @@ const ExpandableWrapper = (props) => {
124
126
  _el$10.$$click = handleClose;
125
127
  var _ref$4 = modalSlotRef;
126
128
  typeof _ref$4 === "function" ? use(_ref$4, _el$13) : modalSlotRef = _el$13;
127
- effect(() => setAttribute(_el$5, "aria-label", props.title || "Expanded view"));
129
+ effect((_p$) => {
130
+ var _v$3 = props.title || strings.expandedView, _v$4 = strings.closeExpandedView;
131
+ _v$3 !== _p$.e && setAttribute(_el$5, "aria-label", _p$.e = _v$3);
132
+ _v$4 !== _p$.t && setAttribute(_el$10, "aria-label", _p$.t = _v$4);
133
+ return _p$;
134
+ }, {
135
+ e: void 0,
136
+ t: void 0
137
+ });
128
138
  runHydrationEvents();
129
139
  return _el$5;
130
140
  })(), getNextElement(_tmpl$4)];
@@ -132,7 +142,15 @@ const ExpandableWrapper = (props) => {
132
142
  });
133
143
  }
134
144
  }), _el$16, _co$2);
135
- effect(() => className(_el$4, `absolute top-2 right-2 z-10 ${props.toolbarVariant === "always-visible" ? "opacity-60 hover:opacity-100" : "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`));
145
+ effect((_p$) => {
146
+ var _v$5 = `absolute top-2 right-2 z-10 ${props.toolbarVariant === "always-visible" ? "opacity-60 hover:opacity-100" : "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`, _v$6 = strings.expand;
147
+ _v$5 !== _p$.e && className(_el$4, _p$.e = _v$5);
148
+ _v$6 !== _p$.t && setAttribute(_el$4, "title", _p$.t = _v$6);
149
+ return _p$;
150
+ }, {
151
+ e: void 0,
152
+ t: void 0
153
+ });
136
154
  runHydrationEvents();
137
155
  return _el$;
138
156
  })();
@@ -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, 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 * Visibility behavior of the inline expand button (v6.3.0 — axe 4 deposium handoff).\n * - `'hover'` (default) : opacity 0, fades to 0.7 on parent group hover.\n * Backwards-compatible — pre-v6.3.0 behavior.\n * - `'always-visible'` : opacity 0.6 permanent, 1 on hover. Use this when\n * the inline button needs to be discoverable without hovering — esp.\n * on touch surfaces and consumer themes where the hover-only pattern\n * hides the affordance.\n */\n toolbarVariant?: 'hover' | 'always-visible'\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 — visibility per `toolbarVariant` (default 'hover') */}\n <button\n onClick={handleOpen}\n class={`absolute top-2 right-2 z-10 ${\n props.toolbarVariant === 'always-visible'\n ? 'opacity-60 hover:opacity-100'\n : 'opacity-0 group-hover:opacity-70 hover:!opacity-100'\n } 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 v6.1.0 : `flex flex-col` lets aware children opt into\n `flex-1 min-h-0` to fill the modal vertically (chart,\n table, map, graph). Unaware children keep working\n thanks to `overflow-auto` (their natural height\n scrolls if it overflows the slot). */}\n <div class=\"flex-1 min-h-0 overflow-auto p-4 flex flex-col\" 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","_$className","toolbarVariant","_$delegateEvents"],"mappings":";;;;;;;;;;;;AAYA,MAAMA,kBAAkBC,cAAiC,MAAM,KAAK;AAG7D,MAAMC,cAAcA,MAAMC,WAAWH,eAAe;AAkCpD,MAAMI,oBAAwDC,CAAAA,UAAU;AAC7E,QAAM,CAACC,YAAYC,aAAa,IAAIC,aAAa,KAAK;AACtD,QAAM,CAACC,QAAQC,SAAS,IAAIF,aAAa,KAAK;AAC9C,MAAIG;AACJ,MAAIC;AACJ,MAAIC;AACJ,MAAIC;AAEJ,QAAMC,aAAaA,MAAMR,cAAc,IAAI;AAC3C,QAAMS,cAAcA,MAAMT,cAAc,KAAK;AAG7CU,eAAa,MAAM;AACjB,QAAI,CAACL,WAAY;AAEjB,QAAIN,cAAc;AAEhBQ,mDAAcI,YAAYN;AAAAA,IAC5B,OAAO;AAELC,qDAAeK,YAAYN;AAAAA,IAC7B;AAAA,EACF,CAAC;AAGDK,eAAa,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,cAAU,MAAMF,SAASG,oBAAoB,WAAWP,SAAS,CAAC;AAAA,EACpE,CAAC;AAGDF,eAAa,MAAM;AACjB,QAAIX,cAAc;AAChB,YAAMqB,OAAOJ,SAASK,KAAKC,MAAMC;AACjCP,eAASK,KAAKC,MAAMC,WAAW;AAE/BC,iBAAW,MAAMpB,uCAAWqB,SAAS,EAAE;AACvCP,gBAAU,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,eAAAC,OAAA,GAAAC,QAAAH,KAAAI,YAAAC,QAAAF,MAAAC,YAAAE,QAAAH,MAAAI,aAAAC,SAAAF,MAAAC,aAAA,CAAAE,QAAAC,KAAA,IAAAC,cAAAH,OAAAD,WAAA;AAAA,QAAAK,QAGc3C;AAAa,WAAA2C,UAAA,aAAAC,IAAAD,OAAAT,KAAA,IAAblC,gBAAakC;AAAA,QAAAW,SACX9C;AAAU,WAAA8C,WAAA,aAAAD,IAAAC,QAAAT,KAAA,IAAVrC,aAAUqC;AAAAU,WAAAV,OAAAW,gBACjB5D,gBAAgB6D,UAAQ;AAAA,MAACC,OAAOxD;AAAAA,MAAU,IAAAyD,WAAA;AAAA,eACxC1D,MAAM0D;AAAAA,MAAQ;AAAA,IAAA,CAAA,CAAA;AAAAb,UAAAc,UAOVjD;AAAU4C,WAAAf,MAAAgB,gBAepBK,MAAI;AAAA,MAAA,IAACC,OAAI;AAAA,eAAE5D,WAAAA;AAAAA,MAAY;AAAA,MAAA,IAAAyD,WAAA;AAAA,eAAAH,gBACrBO,QAAM;AAAA,UAAA,IAAAJ,WAAA;AAAA,mBAAA,EAAA,MAAA;AAAA,kBAAAK,QAAAvB,eAAAwB,OAAA,GAAAC,QAAAF,MAAApB,YAAAuB,QAAAD,MAAAtB,YAAAwB,QAAAD,MAAAvB,YAAAyB,QAAAD,MAAArB,aAAAuB,SAAAD,MAAAzB,YAAA,CAAA2B,QAAAC,IAAA,IAAArB,cAAAmB,OAAAvB,WAAA,GAAA0B,SAAAF,OAAAxB,aAAA2B,SAAAP,MAAApB;AAAA,kBAAA4B,SASEpE;AAAS,qBAAAoE,WAAA,aAAAtB,IAAAsB,QAAAX,KAAA,IAATzD,YAASyD;AAAAA,oBAAAJ,UALL/B;AAAmBqC,oBAAAN,UAWhB5C,CAAAA,MAAMA,EAAE4D,gBAAAA;AAAiBrB,qBAAAa,OAAA,MAK9BnE,MAAM4E,SAAS,eAAe;AAAAtB,qBAAAc,OAAAb,gBAI9BK,MAAI;AAAA,gBAAA,IAACC,OAAI;AAAA,yBAAE7D,MAAMgC;AAAAA,gBAAQ;AAAA,gBAAA,IAAA0B,WAAA;AAAA,sBAAAmB,QAAArC,eAAAsC,OAAA;AAAAD,wBAAAlB,UAEb5B;AAAUuB,yBAAAuB,OAAAtB,gBAKlBK,MAAI;AAAA,oBAAA,IACHC,OAAI;AAAA,6BAAE,CAACzD,OAAAA;AAAAA,oBAAQ;AAAA,oBAAA,IACf2E,WAAQ;AAAA,6BAAAvC,eAAAwC,OAAA;AAAA,oBAAA;AAAA,oBAAA,IAAAtB,WAAA;AAAA,6BAAAlB,eAAAyC,MAAA;AAAA,oBAAA;AAAA,kBAAA,CAAA,CAAA;AAAAC,yBAAAC,CAAAA,QAAA;AAAA,wBAAAC,MALHpF,MAAMqF,aAAa,qBAAmBC,OACjCtF,MAAMqF,aAAa;AAAmBD,4BAAAD,IAAApE,KAAAwE,aAAAV,OAAA,SAAAM,IAAApE,IAAAqE,GAAA;AAAAE,6BAAAH,IAAAK,KAAAD,aAAAV,OAAA,cAAAM,IAAAK,IAAAF,IAAA;AAAA,2BAAAH;AAAAA,kBAAA,GAAA;AAAA,oBAAApE,GAAA0E;AAAAA,oBAAAD,GAAAC;AAAAA,kBAAAA,CAAA;AAAAC,qCAAAA;AAAA,yBAAAb;AAAAA,gBAAA;AAAA,cAAA,CAAA,GAAAP,QAAAC,IAAA;AAAAC,qBAAAb,UAkB3ChD;AAAW,kBAAAgF,SAiBuClF;AAAY,qBAAAkF,WAAA,aAAAvC,IAAAuC,QAAAlB,MAAA,IAAZhE,eAAYgE;AAAAS,qBAAA,MAAAK,aAAAxB,qBAzDnE/D,MAAM4E,SAAS,eAAe,CAAA;AAAAc,iCAAAA;AAAA,qBAAA3B;AAAAA,YAAA,GAAA,GAAAvB,eAAAoD,OAAA,CAAA;AAAA,UAAA;AAAA,QAAA,CAAA;AAAA,MAAA;AAAA,IAAA,CAAA,GAAA5C,QAAAC,KAAA;AAAAiC,WAAA,MAAAW,UAAAhD,OAtBvC,+BACL7C,MAAM8F,mBAAmB,mBACrB,iCACA,qDAAqD,6JACkG,CAAA;AAAAJ,uBAAAA;AAAA,WAAAnD;AAAAA,EAAA,GAAA;AA6FrK;AAACwD,eAAA,CAAA,OAAA,CAAA;"}
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'\nimport { useMCPUIStrings } from '../context/MCPUIStringsContext'\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 * Visibility behavior of the inline expand button (v6.3.0 — axe 4 deposium handoff).\n * - `'hover'` (default) : opacity 0, fades to 0.7 on parent group hover.\n * Backwards-compatible — pre-v6.3.0 behavior.\n * - `'always-visible'` : opacity 0.6 permanent, 1 on hover. Use this when\n * the inline button needs to be discoverable without hovering — esp.\n * on touch surfaces and consumer themes where the hover-only pattern\n * hides the affordance.\n */\n toolbarVariant?: 'hover' | 'always-visible'\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 const strings = useMCPUIStrings()\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 — visibility per `toolbarVariant` (default 'hover') */}\n <button\n onClick={handleOpen}\n class={`absolute top-2 right-2 z-10 ${\n props.toolbarVariant === 'always-visible'\n ? 'opacity-60 hover:opacity-100'\n : 'opacity-0 group-hover:opacity-70 hover:!opacity-100'\n } 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={strings.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 || strings.expandedView}\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 || strings.expandedView}\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 || strings.copyToClipboard}\n aria-label={props.copyLabel || strings.copyToClipboard}\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={strings.closeExpandedView}\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 v6.1.0 : `flex flex-col` lets aware children opt into\n `flex-1 min-h-0` to fill the modal vertically (chart,\n table, map, graph). Unaware children keep working\n thanks to `overflow-auto` (their natural height\n scrolls if it overflows the slot). */}\n <div class=\"flex-1 min-h-0 overflow-auto p-4 flex flex-col\" 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","strings","useMCPUIStrings","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","expandedView","_el$0","_tmpl$2","fallback","_tmpl$6","_tmpl$","_$effect","_p$","_v$","copyLabel","copyToClipboard","_v$2","_$setAttribute","t","undefined","_$runHydrationEvents","_ref$4","_v$3","_v$4","closeExpandedView","_tmpl$4","_v$5","toolbarVariant","_v$6","expand","_$className","_$delegateEvents"],"mappings":";;;;;;;;;;;;;AAaA,MAAMA,kBAAkBC,cAAiC,MAAM,KAAK;AAG7D,MAAMC,cAAcA,MAAMC,WAAWH,eAAe;AAkCpD,MAAMI,oBAAwDC,CAAAA,UAAU;AAC7E,QAAM,CAACC,YAAYC,aAAa,IAAIC,aAAa,KAAK;AACtD,QAAM,CAACC,QAAQC,SAAS,IAAIF,aAAa,KAAK;AAC9C,QAAMG,UAAUC,gBAAAA;AAChB,MAAIC;AACJ,MAAIC;AACJ,MAAIC;AACJ,MAAIC;AAEJ,QAAMC,aAAaA,MAAMV,cAAc,IAAI;AAC3C,QAAMW,cAAcA,MAAMX,cAAc,KAAK;AAG7CY,eAAa,MAAM;AACjB,QAAI,CAACL,WAAY;AAEjB,QAAIR,cAAc;AAEhBU,mDAAcI,YAAYN;AAAAA,IAC5B,OAAO;AAELC,qDAAeK,YAAYN;AAAAA,IAC7B;AAAA,EACF,CAAC;AAGDK,eAAa,MAAM;AACjB,QAAI,CAACb,aAAc;AAEnB,UAAMe,YAAYA,CAACC,MAAqB;AACtC,UAAIA,EAAEC,QAAQ,UAAU;AACtBD,UAAEE,eAAAA;AACFN,oBAAAA;AAAAA,MACF;AAAA,IACF;AAEAO,aAASC,iBAAiB,WAAWL,SAAS;AAC9CM,cAAU,MAAMF,SAASG,oBAAoB,WAAWP,SAAS,CAAC;AAAA,EACpE,CAAC;AAGDF,eAAa,MAAM;AACjB,QAAIb,cAAc;AAChB,YAAMuB,OAAOJ,SAASK,KAAKC,MAAMC;AACjCP,eAASK,KAAKC,MAAMC,WAAW;AAE/BC,iBAAW,MAAMpB,uCAAWqB,SAAS,EAAE;AACvCP,gBAAU,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,CAACjC,MAAMkC,SAAU;AACrB,QAAI;AACF,YAAMC,UAAUC,UAAUC,UAAUrC,MAAMkC,QAAQ;AAClD7B,gBAAU,IAAI;AACduB,iBAAW,MAAMvB,UAAU,KAAK,GAAG,GAAI;AAAA,IACzC,SAASiC,KAAK;AACZC,cAAQC,MAAM,mBAAmBF,GAAG;AAAA,IACtC;AAAA,EACF;AAEA,UAAA,MAAA;AAAA,QAAAG,OAAAC,eAAAC,OAAA,GAAAC,QAAAH,KAAAI,YAAAC,QAAAF,MAAAC,YAAAE,QAAAH,MAAAI,aAAAC,SAAAF,MAAAC,aAAA,CAAAE,QAAAC,KAAA,IAAAC,cAAAH,OAAAD,WAAA;AAAA,QAAAK,QAGc3C;AAAa,WAAA2C,UAAA,aAAAC,IAAAD,OAAAT,KAAA,IAAblC,gBAAakC;AAAA,QAAAW,SACX9C;AAAU,WAAA8C,WAAA,aAAAD,IAAAC,QAAAT,KAAA,IAAVrC,aAAUqC;AAAAU,WAAAV,OAAAW,gBACjB9D,gBAAgB+D,UAAQ;AAAA,MAACC,OAAO1D;AAAAA,MAAU,IAAA2D,WAAA;AAAA,eACxC5D,MAAM4D;AAAAA,MAAQ;AAAA,IAAA,CAAA,CAAA;AAAAb,UAAAc,UAOVjD;AAAU4C,WAAAf,MAAAgB,gBAepBK,MAAI;AAAA,MAAA,IAACC,OAAI;AAAA,eAAE9D,WAAAA;AAAAA,MAAY;AAAA,MAAA,IAAA2D,WAAA;AAAA,eAAAH,gBACrBO,QAAM;AAAA,UAAA,IAAAJ,WAAA;AAAA,mBAAA,EAAA,MAAA;AAAA,kBAAAK,QAAAvB,eAAAwB,OAAA,GAAAC,QAAAF,MAAApB,YAAAuB,QAAAD,MAAAtB,YAAAwB,QAAAD,MAAAvB,YAAAyB,QAAAD,MAAArB,aAAAuB,SAAAD,MAAAzB,YAAA,CAAA2B,QAAAC,IAAA,IAAArB,cAAAmB,OAAAvB,WAAA,GAAA0B,SAAAF,OAAAxB,aAAA2B,SAAAP,MAAApB;AAAA,kBAAA4B,SASEpE;AAAS,qBAAAoE,WAAA,aAAAtB,IAAAsB,QAAAX,KAAA,IAATzD,YAASyD;AAAAA,oBAAAJ,UALL/B;AAAmBqC,oBAAAN,UAWhB5C,CAAAA,MAAMA,EAAE4D,gBAAAA;AAAiBrB,qBAAAa,OAAA,MAK9BrE,MAAM8E,SAASxE,QAAQyE,YAAY;AAAAvB,qBAAAc,OAAAb,gBAInCK,MAAI;AAAA,gBAAA,IAACC,OAAI;AAAA,yBAAE/D,MAAMkC;AAAAA,gBAAQ;AAAA,gBAAA,IAAA0B,WAAA;AAAA,sBAAAoB,QAAAtC,eAAAuC,OAAA;AAAAD,wBAAAnB,UAEb5B;AAAUuB,yBAAAwB,OAAAvB,gBAKlBK,MAAI;AAAA,oBAAA,IACHC,OAAI;AAAA,6BAAE,CAAC3D,OAAAA;AAAAA,oBAAQ;AAAA,oBAAA,IACf8E,WAAQ;AAAA,6BAAAxC,eAAAyC,OAAA;AAAA,oBAAA;AAAA,oBAAA,IAAAvB,WAAA;AAAA,6BAAAlB,eAAA0C,MAAA;AAAA,oBAAA;AAAA,kBAAA,CAAA,CAAA;AAAAC,yBAAAC,CAAAA,QAAA;AAAA,wBAAAC,MALHvF,MAAMwF,aAAalF,QAAQmF,iBAAeC,OACrC1F,MAAMwF,aAAalF,QAAQmF;AAAeF,4BAAAD,IAAArE,KAAA0E,aAAAX,OAAA,SAAAM,IAAArE,IAAAsE,GAAA;AAAAG,6BAAAJ,IAAAM,KAAAD,aAAAX,OAAA,cAAAM,IAAAM,IAAAF,IAAA;AAAA,2BAAAJ;AAAAA,kBAAA,GAAA;AAAA,oBAAArE,GAAA4E;AAAAA,oBAAAD,GAAAC;AAAAA,kBAAAA,CAAA;AAAAC,qCAAAA;AAAA,yBAAAd;AAAAA,gBAAA;AAAA,cAAA,CAAA,GAAAR,QAAAC,IAAA;AAAAC,qBAAAb,UAkB/ChD;AAAW,kBAAAkF,SAiBuCpF;AAAY,qBAAAoF,WAAA,aAAAzC,IAAAyC,QAAApB,MAAA,IAAZhE,eAAYgE;AAAAU,qBAAAC,CAAAA,QAAA;AAAA,oBAAAU,OAzDnEhG,MAAM8E,SAASxE,QAAQyE,cAAYkB,OA0C3B3F,QAAQ4F;AAAiBF,yBAAAV,IAAArE,KAAA0E,aAAA1B,OAAA,cAAAqB,IAAArE,IAAA+E,IAAA;AAAAC,yBAAAX,IAAAM,KAAAD,aAAAjB,QAAA,cAAAY,IAAAM,IAAAK,IAAA;AAAA,uBAAAX;AAAAA,cAAA,GAAA;AAAA,gBAAArE,GAAA4E;AAAAA,gBAAAD,GAAAC;AAAAA,cAAAA,CAAA;AAAAC,iCAAAA;AAAA,qBAAA7B;AAAAA,YAAA,GAAA,GAAAvB,eAAAyD,OAAA,CAAA;AAAA,UAAA;AAAA,QAAA,CAAA;AAAA,MAAA;AAAA,IAAA,CAAA,GAAAjD,QAAAC,KAAA;AAAAkC,WAAAC,CAAAA,QAAA;AAAA,UAAAc,OAhE1C,+BACLpG,MAAMqG,mBAAmB,mBACrB,iCACA,qDAAqD,+JACkGC,OACtJhG,QAAQiG;AAAMH,eAAAd,IAAArE,KAAAuF,UAAAzD,OAAAuC,IAAArE,IAAAmF,IAAA;AAAAE,eAAAhB,IAAAM,KAAAD,aAAA5C,OAAA,SAAAuC,IAAAM,IAAAU,IAAA;AAAA,aAAAhB;AAAAA,IAAA,GAAA;AAAA,MAAArE,GAAA4E;AAAAA,MAAAD,GAAAC;AAAAA,IAAAA,CAAA;AAAAC,uBAAAA;AAAA,WAAArD;AAAAA,EAAA,GAAA;AA4F7B;AAACgE,eAAA,CAAA,OAAA,CAAA;"}