@seed-ship/mcp-ui-solid 6.19.1 → 6.20.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +519 -0
- package/README.md +791 -1
- package/dist/adapters/connector.cjs +15 -4
- package/dist/adapters/connector.cjs.map +1 -1
- package/dist/adapters/connector.d.ts +38 -0
- package/dist/adapters/connector.d.ts.map +1 -1
- package/dist/adapters/connector.js +15 -4
- package/dist/adapters/connector.js.map +1 -1
- package/dist/adapters/index.d.ts +4 -3
- package/dist/adapters/index.d.ts.map +1 -1
- package/dist/adapters/macro-run.cjs +25 -13
- package/dist/adapters/macro-run.cjs.map +1 -1
- package/dist/adapters/macro-run.d.ts +37 -2
- package/dist/adapters/macro-run.d.ts.map +1 -1
- package/dist/adapters/macro-run.js +25 -13
- package/dist/adapters/macro-run.js.map +1 -1
- package/dist/adapters.cjs +2 -0
- package/dist/adapters.cjs.map +1 -1
- package/dist/adapters.js +4 -2
- package/dist/components/ActionGroupRenderer.cjs +3 -1
- package/dist/components/ActionGroupRenderer.cjs.map +1 -1
- package/dist/components/ActionGroupRenderer.d.ts.map +1 -1
- package/dist/components/ActionGroupRenderer.js +3 -1
- package/dist/components/ActionGroupRenderer.js.map +1 -1
- package/dist/components/AgentCard.cjs +11 -8
- package/dist/components/AgentCard.cjs.map +1 -1
- package/dist/components/AgentCard.d.ts.map +1 -1
- package/dist/components/AgentCard.js +11 -8
- package/dist/components/AgentCard.js.map +1 -1
- package/dist/components/AgentHandoff.cjs +6 -1
- package/dist/components/AgentHandoff.cjs.map +1 -1
- package/dist/components/AgentHandoff.d.ts.map +1 -1
- package/dist/components/AgentHandoff.js +6 -1
- package/dist/components/AgentHandoff.js.map +1 -1
- package/dist/components/ArtifactRenderer.cjs +25 -6
- package/dist/components/ArtifactRenderer.cjs.map +1 -1
- package/dist/components/ArtifactRenderer.d.ts.map +1 -1
- package/dist/components/ArtifactRenderer.js +25 -6
- package/dist/components/ArtifactRenderer.js.map +1 -1
- package/dist/components/AutocompleteDropdown.cjs +30 -24
- package/dist/components/AutocompleteDropdown.cjs.map +1 -1
- package/dist/components/AutocompleteDropdown.d.ts.map +1 -1
- package/dist/components/AutocompleteDropdown.js +30 -24
- package/dist/components/AutocompleteDropdown.js.map +1 -1
- package/dist/components/AutocompleteFormField.cjs +3 -1
- package/dist/components/AutocompleteFormField.cjs.map +1 -1
- package/dist/components/AutocompleteFormField.d.ts.map +1 -1
- package/dist/components/AutocompleteFormField.js +4 -2
- package/dist/components/AutocompleteFormField.js.map +1 -1
- package/dist/components/BriefingDiff.cjs +45 -39
- package/dist/components/BriefingDiff.cjs.map +1 -1
- package/dist/components/BriefingDiff.d.ts.map +1 -1
- package/dist/components/BriefingDiff.js +45 -39
- package/dist/components/BriefingDiff.js.map +1 -1
- package/dist/components/CarouselRenderer.cjs +8 -2
- package/dist/components/CarouselRenderer.cjs.map +1 -1
- package/dist/components/CarouselRenderer.d.ts.map +1 -1
- package/dist/components/CarouselRenderer.js +8 -2
- package/dist/components/CarouselRenderer.js.map +1 -1
- package/dist/components/ChartJSRenderer.cjs +60 -36
- package/dist/components/ChartJSRenderer.cjs.map +1 -1
- package/dist/components/ChartJSRenderer.d.ts.map +1 -1
- package/dist/components/ChartJSRenderer.js +61 -37
- package/dist/components/ChartJSRenderer.js.map +1 -1
- package/dist/components/ChatPrompt.cjs +15 -9
- package/dist/components/ChatPrompt.cjs.map +1 -1
- package/dist/components/ChatPrompt.d.ts.map +1 -1
- package/dist/components/ChatPrompt.js +15 -9
- package/dist/components/ChatPrompt.js.map +1 -1
- package/dist/components/CodeBlockRenderer.cjs +34 -16
- package/dist/components/CodeBlockRenderer.cjs.map +1 -1
- package/dist/components/CodeBlockRenderer.d.ts.map +1 -1
- package/dist/components/CodeBlockRenderer.js +34 -16
- package/dist/components/CodeBlockRenderer.js.map +1 -1
- package/dist/components/DataPreviewSection.cjs +91 -44
- package/dist/components/DataPreviewSection.cjs.map +1 -1
- package/dist/components/DataPreviewSection.d.ts.map +1 -1
- package/dist/components/DataPreviewSection.js +92 -45
- package/dist/components/DataPreviewSection.js.map +1 -1
- package/dist/components/DegradedFallback.cjs +20 -16
- package/dist/components/DegradedFallback.cjs.map +1 -1
- package/dist/components/DegradedFallback.d.ts.map +1 -1
- package/dist/components/DegradedFallback.js +20 -16
- package/dist/components/DegradedFallback.js.map +1 -1
- package/dist/components/FooterRenderer.cjs +21 -17
- package/dist/components/FooterRenderer.cjs.map +1 -1
- package/dist/components/FooterRenderer.d.ts.map +1 -1
- package/dist/components/FooterRenderer.js +21 -17
- package/dist/components/FooterRenderer.js.map +1 -1
- package/dist/components/FormFieldRenderer.cjs +116 -93
- package/dist/components/FormFieldRenderer.cjs.map +1 -1
- package/dist/components/FormFieldRenderer.d.ts.map +1 -1
- package/dist/components/FormFieldRenderer.js +116 -93
- package/dist/components/FormFieldRenderer.js.map +1 -1
- package/dist/components/FormRenderer.cjs +55 -31
- package/dist/components/FormRenderer.cjs.map +1 -1
- package/dist/components/FormRenderer.d.ts.map +1 -1
- package/dist/components/FormRenderer.js +55 -31
- package/dist/components/FormRenderer.js.map +1 -1
- package/dist/components/GenerativeUIErrorBoundary.cjs +20 -15
- package/dist/components/GenerativeUIErrorBoundary.cjs.map +1 -1
- package/dist/components/GenerativeUIErrorBoundary.d.ts.map +1 -1
- package/dist/components/GenerativeUIErrorBoundary.js +20 -15
- package/dist/components/GenerativeUIErrorBoundary.js.map +1 -1
- package/dist/components/GraphRenderer.cjs +56 -33
- package/dist/components/GraphRenderer.cjs.map +1 -1
- package/dist/components/GraphRenderer.d.ts.map +1 -1
- package/dist/components/GraphRenderer.js +56 -33
- package/dist/components/GraphRenderer.js.map +1 -1
- package/dist/components/ImageGalleryRenderer.cjs +13 -4
- package/dist/components/ImageGalleryRenderer.cjs.map +1 -1
- package/dist/components/ImageGalleryRenderer.d.ts.map +1 -1
- package/dist/components/ImageGalleryRenderer.js +13 -4
- package/dist/components/ImageGalleryRenderer.js.map +1 -1
- package/dist/components/LightboxOverlay.cjs +16 -8
- package/dist/components/LightboxOverlay.cjs.map +1 -1
- package/dist/components/LightboxOverlay.d.ts.map +1 -1
- package/dist/components/LightboxOverlay.js +17 -9
- package/dist/components/LightboxOverlay.js.map +1 -1
- package/dist/components/MapRenderer.cjs +59 -29
- package/dist/components/MapRenderer.cjs.map +1 -1
- package/dist/components/MapRenderer.d.ts +10 -2
- package/dist/components/MapRenderer.d.ts.map +1 -1
- package/dist/components/MapRenderer.js +60 -30
- package/dist/components/MapRenderer.js.map +1 -1
- package/dist/components/ModalRenderer.cjs +4 -1
- package/dist/components/ModalRenderer.cjs.map +1 -1
- package/dist/components/ModalRenderer.d.ts.map +1 -1
- package/dist/components/ModalRenderer.js +5 -2
- package/dist/components/ModalRenderer.js.map +1 -1
- package/dist/components/ScratchpadPanel.cjs +578 -535
- package/dist/components/ScratchpadPanel.cjs.map +1 -1
- package/dist/components/ScratchpadPanel.d.ts.map +1 -1
- package/dist/components/ScratchpadPanel.js +578 -535
- package/dist/components/ScratchpadPanel.js.map +1 -1
- package/dist/components/StreamingUIRenderer.cjs +92 -28
- package/dist/components/StreamingUIRenderer.cjs.map +1 -1
- package/dist/components/StreamingUIRenderer.d.ts.map +1 -1
- package/dist/components/StreamingUIRenderer.js +92 -28
- package/dist/components/StreamingUIRenderer.js.map +1 -1
- package/dist/components/UIResourceRenderer.cjs +456 -363
- package/dist/components/UIResourceRenderer.cjs.map +1 -1
- package/dist/components/UIResourceRenderer.d.ts +21 -0
- package/dist/components/UIResourceRenderer.d.ts.map +1 -1
- package/dist/components/UIResourceRenderer.js +458 -365
- package/dist/components/UIResourceRenderer.js.map +1 -1
- package/dist/components/VerifiedText.cjs +39 -20
- package/dist/components/VerifiedText.cjs.map +1 -1
- package/dist/components/VerifiedText.d.ts +2 -1
- package/dist/components/VerifiedText.d.ts.map +1 -1
- package/dist/components/VerifiedText.js +39 -20
- package/dist/components/VerifiedText.js.map +1 -1
- package/dist/components/VideoRenderer.cjs +10 -5
- package/dist/components/VideoRenderer.cjs.map +1 -1
- package/dist/components/VideoRenderer.d.ts.map +1 -1
- package/dist/components/VideoRenderer.js +10 -5
- package/dist/components/VideoRenderer.js.map +1 -1
- package/dist/components/chart-data-table.cjs +38 -17
- package/dist/components/chart-data-table.cjs.map +1 -1
- package/dist/components/chart-data-table.d.ts +30 -1
- package/dist/components/chart-data-table.d.ts.map +1 -1
- package/dist/components/chart-data-table.js +38 -17
- package/dist/components/chart-data-table.js.map +1 -1
- package/dist/context/MCPActionContext.cjs +3 -1
- package/dist/context/MCPActionContext.cjs.map +1 -1
- package/dist/context/MCPActionContext.d.ts.map +1 -1
- package/dist/context/MCPActionContext.js +3 -1
- package/dist/context/MCPActionContext.js.map +1 -1
- package/dist/context/MCPUIStringsContext.cjs +285 -2
- package/dist/context/MCPUIStringsContext.cjs.map +1 -1
- package/dist/context/MCPUIStringsContext.d.ts +600 -3
- package/dist/context/MCPUIStringsContext.d.ts.map +1 -1
- package/dist/context/MCPUIStringsContext.js +285 -2
- package/dist/context/MCPUIStringsContext.js.map +1 -1
- package/dist/hooks/index.d.ts +2 -2
- package/dist/hooks/index.d.ts.map +1 -1
- package/dist/hooks/useStreamingUI.cjs +28 -10
- package/dist/hooks/useStreamingUI.cjs.map +1 -1
- package/dist/hooks/useStreamingUI.d.ts +37 -0
- package/dist/hooks/useStreamingUI.d.ts.map +1 -1
- package/dist/hooks/useStreamingUI.js +28 -10
- package/dist/hooks/useStreamingUI.js.map +1 -1
- package/dist/hooks.cjs +1 -0
- package/dist/hooks.cjs.map +1 -1
- package/dist/hooks.js +2 -1
- package/dist/index.cjs +23 -8
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +9 -3
- package/dist/index.d.ts +9 -3
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +18 -3
- package/dist/index.js.map +1 -1
- package/dist/services/validation.cjs +41 -16
- package/dist/services/validation.cjs.map +1 -1
- package/dist/services/validation.d.ts +47 -2
- package/dist/services/validation.d.ts.map +1 -1
- package/dist/services/validation.js +41 -16
- package/dist/services/validation.js.map +1 -1
- package/dist/utils/degraded-projections.cjs +37 -12
- package/dist/utils/degraded-projections.cjs.map +1 -1
- package/dist/utils/degraded-projections.d.ts +39 -3
- package/dist/utils/degraded-projections.d.ts.map +1 -1
- package/dist/utils/degraded-projections.js +37 -12
- package/dist/utils/degraded-projections.js.map +1 -1
- package/dist/utils/format-string.cjs +10 -0
- package/dist/utils/format-string.cjs.map +1 -0
- package/dist/utils/format-string.d.ts +26 -0
- package/dist/utils/format-string.d.ts.map +1 -0
- package/dist/utils/format-string.js +10 -0
- package/dist/utils/format-string.js.map +1 -0
- package/dist/validation.cjs +3 -0
- package/dist/validation.cjs.map +1 -1
- package/dist/validation.d.cts +2 -1
- package/dist/validation.d.ts +2 -1
- package/dist/validation.d.ts.map +1 -1
- package/dist/validation.js +4 -1
- package/package.json +1 -1
- package/src/adapters/connector.ts +58 -4
- package/src/adapters/index.ts +12 -2
- package/src/adapters/macro-run.ts +71 -11
- package/src/components/ActionGroupRenderer.tsx +3 -1
- package/src/components/AgentCard.tsx +27 -9
- package/src/components/AgentHandoff.tsx +4 -1
- package/src/components/ArtifactRenderer.tsx +17 -5
- package/src/components/AutocompleteDropdown.tsx +8 -6
- package/src/components/AutocompleteFormField.tsx +5 -1
- package/src/components/BriefingDiff.tsx +11 -3
- package/src/components/CarouselRenderer.tsx +4 -2
- package/src/components/ChartJSRenderer.tsx +18 -9
- package/src/components/ChatPrompt.tsx +13 -8
- package/src/components/CodeBlockRenderer.tsx +12 -10
- package/src/components/DataPreviewSection.tsx +92 -26
- package/src/components/DegradedFallback.tsx +4 -2
- package/src/components/FooterRenderer.tsx +3 -1
- package/src/components/FormFieldRenderer.tsx +34 -19
- package/src/components/FormRenderer.tsx +38 -10
- package/src/components/GenerativeUIErrorBoundary.tsx +8 -3
- package/src/components/GraphRenderer.tsx +31 -16
- package/src/components/ImageGalleryRenderer.tsx +8 -4
- package/src/components/LightboxOverlay.tsx +6 -4
- package/src/components/MapRenderer.tsx +57 -20
- package/src/components/ModalRenderer.tsx +3 -1
- package/src/components/ScratchpadPanel.tsx +95 -44
- package/src/components/StreamingUIRenderer.tsx +41 -11
- package/src/components/UIResourceRenderer.tsx +145 -63
- package/src/components/VerifiedText.tsx +19 -9
- package/src/components/VideoRenderer.tsx +6 -4
- package/src/components/chart-data-table.ts +68 -14
- package/src/context/MCPActionContext.tsx +4 -1
- package/src/context/MCPUIStringsContext.tsx +1004 -1
- package/src/hooks/index.ts +2 -1
- package/src/hooks/useStreamingUI.ts +64 -10
- package/src/index.ts +23 -0
- package/src/services/validation.ts +93 -16
- package/src/utils/degraded-projections.ts +75 -12
- package/src/utils/format-string.ts +33 -0
- package/src/validation.ts +5 -0
|
@@ -2,7 +2,9 @@
|
|
|
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
|
-
|
|
5
|
+
const MCPUIStringsContext = require("../context/MCPUIStringsContext.cjs");
|
|
6
|
+
const formatString = require("../utils/format-string.cjs");
|
|
7
|
+
var _tmpl$ = /* @__PURE__ */ web.template(`<div class="verified-text text-sm leading-relaxed"><!$><!/><!$><!/>`), _tmpl$2 = /* @__PURE__ */ web.template(`<span>`), _tmpl$3 = /* @__PURE__ */ web.template(`<span class="inline-flex items-center gap-0.5 px-0.5 rounded bg-green-50 dark:bg-green-900/20 text-green-800 dark:text-green-300"><!$><!/><span class="text-xs opacity-70">✅`), _tmpl$4 = /* @__PURE__ */ web.template(`<span class="inline-flex items-center px-1 rounded bg-amber-50 dark:bg-amber-900/20 text-amber-700 dark:text-amber-300 italic text-xs">`), _tmpl$5 = /* @__PURE__ */ web.template(`<span class="inline-flex items-center gap-0.5 px-0.5 rounded bg-amber-50 dark:bg-amber-900/20 text-amber-800 dark:text-amber-300 cursor-help"><!$><!/><span class=text-xs>⚠️`), _tmpl$6 = /* @__PURE__ */ web.template(`<div class="mt-2 flex items-center gap-2 text-xs text-gray-500 dark:text-gray-400"><div class="flex-1 h-1.5 bg-gray-200 dark:bg-gray-700 rounded-full overflow-hidden"><div class="h-full rounded-full transition-all"></div></div><span><!$><!/> <!$><!/>`);
|
|
6
8
|
function buildAnnotatedSegments(text, validation) {
|
|
7
9
|
const hallucinatedPositions = /* @__PURE__ */ new Map();
|
|
8
10
|
for (const h of validation.hallucinated) {
|
|
@@ -63,6 +65,7 @@ function buildAnnotatedSegments(text, validation) {
|
|
|
63
65
|
return segments;
|
|
64
66
|
}
|
|
65
67
|
function VerifiedText(props) {
|
|
68
|
+
const strings = MCPUIStringsContext.useMCPUIStrings();
|
|
66
69
|
const mode = () => props.mode || "highlight";
|
|
67
70
|
const segments = solidJs.createMemo(() => {
|
|
68
71
|
if (!props.validation || props.validation.valid) {
|
|
@@ -89,42 +92,55 @@ function VerifiedText(props) {
|
|
|
89
92
|
}
|
|
90
93
|
if (seg.type === "verified") {
|
|
91
94
|
return (() => {
|
|
92
|
-
var _el$7 = web.getNextElement(_tmpl$3), _el$9 = _el$7.firstChild, [_el$0, _co$3] = web.getNextMarker(_el$9.nextSibling);
|
|
93
|
-
_el$0.nextSibling;
|
|
95
|
+
var _el$7 = web.getNextElement(_tmpl$3), _el$9 = _el$7.firstChild, [_el$0, _co$3] = web.getNextMarker(_el$9.nextSibling), _el$8 = _el$0.nextSibling;
|
|
94
96
|
web.insert(_el$7, () => seg.content, _el$0, _co$3);
|
|
97
|
+
web.effect((_p$) => {
|
|
98
|
+
var _v$ = strings.verifiedTitle, _v$2 = strings.verifiedAria;
|
|
99
|
+
_v$ !== _p$.e && web.setAttribute(_el$7, "title", _p$.e = _v$);
|
|
100
|
+
_v$2 !== _p$.t && web.setAttribute(_el$8, "aria-label", _p$.t = _v$2);
|
|
101
|
+
return _p$;
|
|
102
|
+
}, {
|
|
103
|
+
e: void 0,
|
|
104
|
+
t: void 0
|
|
105
|
+
});
|
|
95
106
|
return _el$7;
|
|
96
107
|
})();
|
|
97
108
|
}
|
|
98
109
|
const h = seg.item;
|
|
99
110
|
const tooltipText = () => {
|
|
100
111
|
if (h.closest != null && h.distance != null) {
|
|
101
|
-
return
|
|
112
|
+
return formatString.formatMCPUIString(strings.verifiedNotFoundClosest, {
|
|
113
|
+
closest: h.closest,
|
|
114
|
+
pct: Math.round(h.distance * 100)
|
|
115
|
+
});
|
|
102
116
|
}
|
|
103
|
-
return
|
|
117
|
+
return strings.verifiedNotFound;
|
|
104
118
|
};
|
|
105
119
|
if (mode() === "strip") {
|
|
106
120
|
return (() => {
|
|
107
121
|
var _el$1 = web.getNextElement(_tmpl$4);
|
|
122
|
+
web.insert(_el$1, () => strings.verifiedStripLabel);
|
|
108
123
|
web.effect(() => web.setAttribute(_el$1, "title", tooltipText()));
|
|
109
124
|
return _el$1;
|
|
110
125
|
})();
|
|
111
126
|
}
|
|
112
127
|
return (() => {
|
|
113
|
-
var _el$10 = web.getNextElement(_tmpl$5), _el$12 = _el$10.firstChild, [_el$13, _co$4] = web.getNextMarker(_el$12.nextSibling);
|
|
114
|
-
_el$13.nextSibling;
|
|
128
|
+
var _el$10 = web.getNextElement(_tmpl$5), _el$12 = _el$10.firstChild, [_el$13, _co$4] = web.getNextMarker(_el$12.nextSibling), _el$11 = _el$13.nextSibling;
|
|
115
129
|
_el$10.$$click = () => {
|
|
116
130
|
var _a;
|
|
117
131
|
return (_a = props.onHallucinationClick) == null ? void 0 : _a.call(props, h);
|
|
118
132
|
};
|
|
119
133
|
web.insert(_el$10, () => seg.content, _el$13, _co$4);
|
|
120
134
|
web.effect((_p$) => {
|
|
121
|
-
var _v$ = tooltipText(), _v$
|
|
122
|
-
_v$ !== _p$.e && web.setAttribute(_el$10, "title", _p$.e = _v$);
|
|
123
|
-
_v$
|
|
135
|
+
var _v$3 = tooltipText(), _v$4 = props.onHallucinationClick ? "button" : void 0, _v$5 = strings.unverifiedAria;
|
|
136
|
+
_v$3 !== _p$.e && web.setAttribute(_el$10, "title", _p$.e = _v$3);
|
|
137
|
+
_v$4 !== _p$.t && web.setAttribute(_el$10, "role", _p$.t = _v$4);
|
|
138
|
+
_v$5 !== _p$.a && web.setAttribute(_el$11, "aria-label", _p$.a = _v$5);
|
|
124
139
|
return _p$;
|
|
125
140
|
}, {
|
|
126
141
|
e: void 0,
|
|
127
|
-
t: void 0
|
|
142
|
+
t: void 0,
|
|
143
|
+
a: void 0
|
|
128
144
|
});
|
|
129
145
|
web.runHydrationEvents();
|
|
130
146
|
return _el$10;
|
|
@@ -134,16 +150,19 @@ function VerifiedText(props) {
|
|
|
134
150
|
web.insert(_el$, (() => {
|
|
135
151
|
var _c$ = web.memo(() => !!(props.validation && !props.validation.valid));
|
|
136
152
|
return () => _c$() && (() => {
|
|
137
|
-
var _el$14 = web.getNextElement(_tmpl$6), _el$15 = _el$14.firstChild, _el$16 = _el$15.firstChild, _el$17 = _el$15.nextSibling, _el$
|
|
138
|
-
_el$
|
|
139
|
-
|
|
140
|
-
|
|
153
|
+
var _el$14 = web.getNextElement(_tmpl$6), _el$15 = _el$14.firstChild, _el$16 = _el$15.firstChild, _el$17 = _el$15.nextSibling, _el$19 = _el$17.firstChild, [_el$20, _co$5] = web.getNextMarker(_el$19.nextSibling), _el$18 = _el$20.nextSibling, _el$21 = _el$18.nextSibling, [_el$22, _co$6] = web.getNextMarker(_el$21.nextSibling);
|
|
154
|
+
web.insert(_el$17, () => formatString.formatMCPUIString(strings.verifiedConfidence, {
|
|
155
|
+
pct: Math.round(props.validation.confidence * 100)
|
|
156
|
+
}), _el$20, _co$5);
|
|
157
|
+
web.insert(_el$17, () => formatString.formatMCPUIString(strings.verifiedUnverifiedCount, {
|
|
158
|
+
count: props.validation.hallucinated.length
|
|
159
|
+
}), _el$22, _co$6);
|
|
141
160
|
web.effect((_p$) => {
|
|
142
|
-
var _v$
|
|
143
|
-
_v$
|
|
144
|
-
_v$
|
|
145
|
-
_v$
|
|
146
|
-
_v$
|
|
161
|
+
var _v$6 = !!(props.validation.confidence >= 0.8), _v$7 = !!(props.validation.confidence >= 0.5 && props.validation.confidence < 0.8), _v$8 = !!(props.validation.confidence < 0.5), _v$9 = `${Math.round(props.validation.confidence * 100)}%`;
|
|
162
|
+
_v$6 !== _p$.e && _el$16.classList.toggle("bg-green-500", _p$.e = _v$6);
|
|
163
|
+
_v$7 !== _p$.t && _el$16.classList.toggle("bg-amber-500", _p$.t = _v$7);
|
|
164
|
+
_v$8 !== _p$.a && _el$16.classList.toggle("bg-red-500", _p$.a = _v$8);
|
|
165
|
+
_v$9 !== _p$.o && web.setStyleProperty(_el$16, "width", _p$.o = _v$9);
|
|
147
166
|
return _p$;
|
|
148
167
|
}, {
|
|
149
168
|
e: void 0,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"VerifiedText.cjs","sources":["../../src/components/VerifiedText.tsx"],"sourcesContent":["/**\n * VerifiedText — renders LLM text with inline verification badges\n * v3.1.0: Highlights verified vs hallucinated numbers\n *\n * @experimental\n *\n * Modes:\n * - highlight: ✅/⚠️ badges next to numbers (default)\n * - strip: replaces hallucinated numbers with [non vérifié]\n * - annotate: tooltip on hover with closest source number\n */\n\nimport { createMemo, For } from 'solid-js'\nimport type { DataValidation, HallucinatedNumber } from '../types/chat-bus'\n\nexport interface VerifiedTextProps {\n text: string\n validation: DataValidation\n /** Display mode (default: 'highlight') */\n mode?: 'highlight' | 'strip' | 'annotate'\n /** Callback when a hallucinated number is clicked */\n onHallucinationClick?: (item: HallucinatedNumber) => void\n}\n\ninterface TextSegment {\n type: 'text' | 'verified' | 'hallucinated'\n content: string\n item?: HallucinatedNumber\n}\n\n/**\n * Build annotated segments by splitting text at number positions.\n * Verified numbers get ✅, hallucinated get ⚠️.\n */\nfunction buildAnnotatedSegments(text: string, validation: DataValidation): TextSegment[] {\n // Build position maps\n const hallucinatedPositions = new Map<number, HallucinatedNumber>()\n for (const h of validation.hallucinated) {\n hallucinatedPositions.set(h.position, h)\n }\n\n const verifiedPositions = new Set<number>()\n for (const n of validation.llmNumbers) {\n if (!hallucinatedPositions.has(n.position)) {\n verifiedPositions.add(n.position)\n }\n }\n\n // Re-extract number lengths from text for precise splitting\n const numberRegex = /\\d[\\d\\s,.]*\\d|\\d+/g\n const matches: Array<{ start: number; end: number }> = []\n let m: RegExpExecArray | null\n while ((m = numberRegex.exec(text)) !== null) {\n matches.push({ start: m.index, end: m.index + m[0].length })\n }\n\n // Build a lookup from position → match\n const matchByPosition = new Map<number, { start: number; end: number }>()\n for (const match of matches) {\n matchByPosition.set(match.start, match)\n }\n\n // Build segments\n const segments: TextSegment[] = []\n let cursor = 0\n\n for (const num of validation.llmNumbers) {\n const match = matchByPosition.get(num.position)\n if (!match) continue\n\n // Text before this number\n if (match.start > cursor) {\n segments.push({ type: 'text', content: text.slice(cursor, match.start) })\n }\n\n const numberText = text.slice(match.start, match.end)\n const hallucinated = hallucinatedPositions.get(num.position)\n\n if (hallucinated) {\n segments.push({ type: 'hallucinated', content: numberText, item: hallucinated })\n } else {\n segments.push({ type: 'verified', content: numberText })\n }\n\n cursor = match.end\n }\n\n // Remaining text\n if (cursor < text.length) {\n segments.push({ type: 'text', content: text.slice(cursor) })\n }\n\n return segments\n}\n\nexport function VerifiedText(props: VerifiedTextProps) {\n const mode = () => props.mode || 'highlight'\n\n const segments = createMemo<TextSegment[]>(() => {\n if (!props.validation || props.validation.valid) {\n return [{ type: 'text' as const, content: props.text }]\n }\n return buildAnnotatedSegments(props.text, props.validation)\n })\n\n return (\n <div class=\"verified-text text-sm leading-relaxed\">\n <For each={segments()}>\n {(seg) => {\n if (seg.type === 'text') {\n return <span>{seg.content}</span>\n }\n\n if (seg.type === 'verified') {\n return (\n <span\n class=\"inline-flex items-center gap-0.5 px-0.5 rounded bg-green-50 dark:bg-green-900/20 text-green-800 dark:text-green-300\"\n title=\"Verified against source data\"\n >\n {seg.content}\n <span class=\"text-xs opacity-70\" aria-label=\"verified\">✅</span>\n </span>\n )\n }\n\n // hallucinated\n const h = seg.item!\n const tooltipText = () => {\n if (h.closest != null && h.distance != null) {\n return `Not found in source data. Closest: ${h.closest} (${Math.round(h.distance * 100)}% off)`\n }\n return 'Not found in source data'\n }\n\n if (mode() === 'strip') {\n return (\n <span\n class=\"inline-flex items-center px-1 rounded bg-amber-50 dark:bg-amber-900/20 text-amber-700 dark:text-amber-300 italic text-xs\"\n title={tooltipText()}\n >\n [non vérifié]\n </span>\n )\n }\n\n return (\n <span\n class=\"inline-flex items-center gap-0.5 px-0.5 rounded bg-amber-50 dark:bg-amber-900/20 text-amber-800 dark:text-amber-300 cursor-help\"\n title={tooltipText()}\n onClick={() => props.onHallucinationClick?.(h)}\n role={props.onHallucinationClick ? 'button' : undefined}\n >\n {seg.content}\n <span class=\"text-xs\" aria-label=\"unverified\">⚠️</span>\n </span>\n )\n }}\n </For>\n\n {/* Confidence bar */}\n {props.validation && !props.validation.valid && (\n <div class=\"mt-2 flex items-center gap-2 text-xs text-gray-500 dark:text-gray-400\">\n <div class=\"flex-1 h-1.5 bg-gray-200 dark:bg-gray-700 rounded-full overflow-hidden\">\n <div\n class=\"h-full rounded-full transition-all\"\n classList={{\n 'bg-green-500': props.validation.confidence >= 0.8,\n 'bg-amber-500': props.validation.confidence >= 0.5 && props.validation.confidence < 0.8,\n 'bg-red-500': props.validation.confidence < 0.5,\n }}\n style={{ width: `${Math.round(props.validation.confidence * 100)}%` }}\n />\n </div>\n <span>\n {Math.round(props.validation.confidence * 100)}% verified\n ({props.validation.hallucinated.length} unverified)\n </span>\n </div>\n )}\n </div>\n )\n}\n"],"names":["buildAnnotatedSegments","text","validation","hallucinatedPositions","Map","h","hallucinated","set","position","verifiedPositions","Set","n","llmNumbers","has","add","numberRegex","matches","m","exec","push","start","index","end","length","matchByPosition","match","segments","cursor","num","get","type","content","slice","numberText","item","VerifiedText","props","mode","createMemo","valid","_el$","_$getNextElement","_tmpl$","_el$2","firstChild","_el$3","_co$","_$getNextMarker","nextSibling","_el$4","_el$5","_co$2","_$insert","_$createComponent","For","each","children","seg","_el$6","_tmpl$2","_el$7","_tmpl$3","_el$9","_el$0","_co$3","tooltipText","closest","distance","Math","round","_el$1","_tmpl$4","_$effect","_$setAttribute","_el$10","_tmpl$5","_el$12","_el$13","_co$4","$$click","onHallucinationClick","_p$","_v$","_v$2","undefined","e","t","_$runHydrationEvents","_c$","_$memo","_el$14","_tmpl$6","_el$15","_el$16","_el$17","_el$20","_el$21","_co$5","_el$18","_el$22","_el$23","_co$6","confidence","_v$3","_v$4","_v$5","_v$6","classList","toggle","a","o","_$setStyleProperty","_$delegateEvents"],"mappings":";;;;;AAkCA,SAASA,uBAAuBC,MAAcC,YAA2C;AAEvF,QAAMC,4CAA4BC,IAAAA;AAClC,aAAWC,KAAKH,WAAWI,cAAc;AACvCH,0BAAsBI,IAAIF,EAAEG,UAAUH,CAAC;AAAA,EACzC;AAEA,QAAMI,wCAAwBC,IAAAA;AAC9B,aAAWC,KAAKT,WAAWU,YAAY;AACrC,QAAI,CAACT,sBAAsBU,IAAIF,EAAEH,QAAQ,GAAG;AAC1CC,wBAAkBK,IAAIH,EAAEH,QAAQ;AAAA,IAClC;AAAA,EACF;AAGA,QAAMO,cAAc;AACpB,QAAMC,UAAiD,CAAA;AACvD,MAAIC;AACJ,UAAQA,IAAIF,YAAYG,KAAKjB,IAAI,OAAO,MAAM;AAC5Ce,YAAQG,KAAK;AAAA,MAAEC,OAAOH,EAAEI;AAAAA,MAAOC,KAAKL,EAAEI,QAAQJ,EAAE,CAAC,EAAEM;AAAAA,IAAAA,CAAQ;AAAA,EAC7D;AAGA,QAAMC,sCAAsBpB,IAAAA;AAC5B,aAAWqB,SAAST,SAAS;AAC3BQ,oBAAgBjB,IAAIkB,MAAML,OAAOK,KAAK;AAAA,EACxC;AAGA,QAAMC,WAA0B,CAAA;AAChC,MAAIC,SAAS;AAEb,aAAWC,OAAO1B,WAAWU,YAAY;AACvC,UAAMa,QAAQD,gBAAgBK,IAAID,IAAIpB,QAAQ;AAC9C,QAAI,CAACiB,MAAO;AAGZ,QAAIA,MAAML,QAAQO,QAAQ;AACxBD,eAASP,KAAK;AAAA,QAAEW,MAAM;AAAA,QAAQC,SAAS9B,KAAK+B,MAAML,QAAQF,MAAML,KAAK;AAAA,MAAA,CAAG;AAAA,IAC1E;AAEA,UAAMa,aAAahC,KAAK+B,MAAMP,MAAML,OAAOK,MAAMH,GAAG;AACpD,UAAMhB,eAAeH,sBAAsB0B,IAAID,IAAIpB,QAAQ;AAE3D,QAAIF,cAAc;AAChBoB,eAASP,KAAK;AAAA,QAAEW,MAAM;AAAA,QAAgBC,SAASE;AAAAA,QAAYC,MAAM5B;AAAAA,MAAAA,CAAc;AAAA,IACjF,OAAO;AACLoB,eAASP,KAAK;AAAA,QAAEW,MAAM;AAAA,QAAYC,SAASE;AAAAA,MAAAA,CAAY;AAAA,IACzD;AAEAN,aAASF,MAAMH;AAAAA,EACjB;AAGA,MAAIK,SAAS1B,KAAKsB,QAAQ;AACxBG,aAASP,KAAK;AAAA,MAAEW,MAAM;AAAA,MAAQC,SAAS9B,KAAK+B,MAAML,MAAM;AAAA,IAAA,CAAG;AAAA,EAC7D;AAEA,SAAOD;AACT;AAEO,SAASS,aAAaC,OAA0B;AACrD,QAAMC,OAAOA,MAAMD,MAAMC,QAAQ;AAEjC,QAAMX,WAAWY,QAAAA,WAA0B,MAAM;AAC/C,QAAI,CAACF,MAAMlC,cAAckC,MAAMlC,WAAWqC,OAAO;AAC/C,aAAO,CAAC;AAAA,QAAET,MAAM;AAAA,QAAiBC,SAASK,MAAMnC;AAAAA,MAAAA,CAAM;AAAA,IACxD;AACA,WAAOD,uBAAuBoC,MAAMnC,MAAMmC,MAAMlC,UAAU;AAAA,EAC5D,CAAC;AAED,UAAA,MAAA;AAAA,QAAAsC,OAAAC,IAAAA,eAAAC,MAAA,GAAAC,QAAAH,KAAAI,YAAA,CAAAC,OAAAC,IAAA,IAAAC,IAAAA,cAAAJ,MAAAK,WAAA,GAAAC,QAAAJ,MAAAG,aAAA,CAAAE,OAAAC,KAAA,IAAAJ,IAAAA,cAAAE,MAAAD,WAAA;AAAAI,eAAAZ,MAAAa,IAAAA,gBAEKC,aAAG;AAAA,MAAA,IAACC,OAAI;AAAA,eAAE7B,SAAAA;AAAAA,MAAU;AAAA,MAAA8B,UACjBC,CAAAA,QAAQ;AACR,YAAIA,IAAI3B,SAAS,QAAQ;AACvB,kBAAA,MAAA;AAAA,gBAAA4B,QAAAjB,IAAAA,eAAAkB,OAAA;AAAAP,gBAAAA,OAAAM,OAAA,MAAcD,IAAI1B,OAAO;AAAA,mBAAA2B;AAAAA,UAAA,GAAA;AAAA,QAC3B;AAEA,YAAID,IAAI3B,SAAS,YAAY;AAC3B,kBAAA,MAAA;AAAA,gBAAA8B,QAAAnB,IAAAA,eAAAoB,OAAA,GAAAC,QAAAF,MAAAhB,YAAA,CAAAmB,OAAAC,KAAA,IAAAjB,IAAAA,cAAAe,MAAAd,WAAA;AAAAe,kBAAAf;AAAAI,gBAAAA,OAAAQ,OAAA,MAKKH,IAAI1B,SAAOgC,OAAAC,KAAA;AAAA,mBAAAJ;AAAAA,UAAA,GAAA;AAAA,QAIlB;AAGA,cAAMvD,IAAIoD,IAAIvB;AACd,cAAM+B,cAAcA,MAAM;AACxB,cAAI5D,EAAE6D,WAAW,QAAQ7D,EAAE8D,YAAY,MAAM;AAC3C,mBAAO,sCAAsC9D,EAAE6D,OAAO,KAAKE,KAAKC,MAAMhE,EAAE8D,WAAW,GAAG,CAAC;AAAA,UACzF;AACA,iBAAO;AAAA,QACT;AAEA,YAAI9B,KAAAA,MAAW,SAAS;AACtB,kBAAA,MAAA;AAAA,gBAAAiC,QAAA7B,IAAAA,eAAA8B,OAAA;AAAAC,gBAAAA,aAAAC,IAAAA,aAAAH,OAAA,SAGWL,YAAAA,CAAa,CAAA;AAAA,mBAAAK;AAAAA,UAAA,GAAA;AAAA,QAK1B;AAEA,gBAAA,MAAA;AAAA,cAAAI,SAAAjC,IAAAA,eAAAkC,OAAA,GAAAC,SAAAF,OAAA9B,YAAA,CAAAiC,QAAAC,KAAA,IAAA/B,IAAAA,cAAA6B,OAAA5B,WAAA;AAAA6B,iBAAA7B;AAAA0B,iBAAAK,UAIa,MAAA;;AAAM3C,+BAAM4C,yBAAN5C,+BAA6B/B;AAAAA;AAAE+C,cAAAA,OAAAsB,QAAA,MAG7CjB,IAAI1B,SAAO8C,QAAAC,KAAA;AAAAN,cAAAA,OAAAS,CAAAA,QAAA;AAAA,gBAAAC,MAJLjB,eAAakB,OAEd/C,MAAM4C,uBAAuB,WAAWI;AAASF,oBAAAD,IAAAI,KAAAZ,IAAAA,aAAAC,QAAA,SAAAO,IAAAI,IAAAH,GAAA;AAAAC,qBAAAF,IAAAK,KAAAb,IAAAA,aAAAC,QAAA,QAAAO,IAAAK,IAAAH,IAAA;AAAA,mBAAAF;AAAAA,UAAA,GAAA;AAAA,YAAAI,GAAAD;AAAAA,YAAAE,GAAAF;AAAAA,UAAAA,CAAA;AAAAG,iCAAAA;AAAA,iBAAAb;AAAAA,QAAA,GAAA;AAAA,MAM7D;AAAA,IAAA,CAAC,GAAA7B,OAAAC,IAAA;AAAAM,QAAAA,OAAAZ,OAAA,MAAA;AAAA,UAAAgD,MAAAC,SAAA,MAAA,CAAA,EAIFrD,MAAMlC,cAAc,CAACkC,MAAMlC,WAAWqC,MAAK;AAAA,aAAA,MAA3CiD,IAAAA,MAAA,MAAA;AAAA,YAAAE,SAAAjD,IAAAA,eAAAkD,OAAA,GAAAC,SAAAF,OAAA9C,YAAAiD,SAAAD,OAAAhD,YAAAkD,SAAAF,OAAA5C,aAAA+C,SAAAD,OAAAlD,YAAA,CAAAoD,QAAAC,KAAA,IAAAlD,IAAAA,cAAAgD,OAAA/C,WAAA,GAAAkD,SAAAF,OAAAhD,aAAAmD,SAAAD,OAAAlD,aAAA,CAAAoD,QAAAC,KAAA,IAAAtD,IAAAA,cAAAoD,OAAAnD,WAAA;AAAAoD,eAAApD;AAAAI,YAAAA,OAAA0C,QAAA,MAcM1B,KAAKC,MAAMjC,MAAMlC,WAAWoG,aAAa,GAAG,GAACN,QAAAC,KAAA;AAAA7C,mBAAA0C,QAAA,MAC5C1D,MAAMlC,WAAWI,aAAaiB,QAAM6E,QAAAC,KAAA;AAAA7B,YAAAA,OAAAS,CAAAA,QAAA;AAAA,cAAAsB,UATlBnE,MAAMlC,WAAWoG,cAAc,MAAGE,OAAA,CAAA,EAClCpE,MAAMlC,WAAWoG,cAAc,OAAOlE,MAAMlC,WAAWoG,aAAa,MAAGG,UACzErE,MAAMlC,WAAWoG,aAAa,MAAGI,OAEjC,GAAGtC,KAAKC,MAAMjC,MAAMlC,WAAWoG,aAAa,GAAG,CAAC;AAAGC,mBAAAtB,IAAAI,KAAAQ,OAAAc,UAAAC,OAAA,gBAAA3B,IAAAI,IAAAkB,IAAA;AAAAC,mBAAAvB,IAAAK,KAAAO,OAAAc,UAAAC,OAAA,gBAAA3B,IAAAK,IAAAkB,IAAA;AAAAC,mBAAAxB,IAAA4B,KAAAhB,OAAAc,UAAAC,OAAA,cAAA3B,IAAA4B,IAAAJ,IAAA;AAAAC,mBAAAzB,IAAA6B,KAAAC,IAAAA,iBAAAlB,QAAA,SAAAZ,IAAA6B,IAAAJ,IAAA;AAAA,iBAAAzB;AAAAA,QAAA,GAAA;AAAA,UAAAI,GAAAD;AAAAA,UAAAE,GAAAF;AAAAA,UAAAyB,GAAAzB;AAAAA,UAAA0B,GAAA1B;AAAAA,QAAAA,CAAA;AAAA,eAAAM;AAAAA,MAAA,GAAA;AAAA,IAQ1E,GAAA,GAAAxC,OAAAC,KAAA;AAAA,WAAAX;AAAAA,EAAA,GAAA;AAGP;AAACwE,IAAAA,eAAA,CAAA,OAAA,CAAA;;"}
|
|
1
|
+
{"version":3,"file":"VerifiedText.cjs","sources":["../../src/components/VerifiedText.tsx"],"sourcesContent":["/**\n * VerifiedText — renders LLM text with inline verification badges\n * v3.1.0: Highlights verified vs hallucinated numbers\n *\n * @experimental\n *\n * Modes:\n * - highlight: ✅/⚠️ badges next to numbers (default)\n * - strip: replaces hallucinated numbers with the `verifiedStripLabel`\n * chrome string ('[unverified]' by default)\n * - annotate: tooltip on hover with closest source number\n */\n\nimport { createMemo, For } from 'solid-js'\nimport type { DataValidation, HallucinatedNumber } from '../types/chat-bus'\nimport { formatMCPUIString, useMCPUIStrings } from '../context/MCPUIStringsContext'\n\nexport interface VerifiedTextProps {\n text: string\n validation: DataValidation\n /** Display mode (default: 'highlight') */\n mode?: 'highlight' | 'strip' | 'annotate'\n /** Callback when a hallucinated number is clicked */\n onHallucinationClick?: (item: HallucinatedNumber) => void\n}\n\ninterface TextSegment {\n type: 'text' | 'verified' | 'hallucinated'\n content: string\n item?: HallucinatedNumber\n}\n\n/**\n * Build annotated segments by splitting text at number positions.\n * Verified numbers get ✅, hallucinated get ⚠️.\n */\nfunction buildAnnotatedSegments(text: string, validation: DataValidation): TextSegment[] {\n // Build position maps\n const hallucinatedPositions = new Map<number, HallucinatedNumber>()\n for (const h of validation.hallucinated) {\n hallucinatedPositions.set(h.position, h)\n }\n\n const verifiedPositions = new Set<number>()\n for (const n of validation.llmNumbers) {\n if (!hallucinatedPositions.has(n.position)) {\n verifiedPositions.add(n.position)\n }\n }\n\n // Re-extract number lengths from text for precise splitting\n const numberRegex = /\\d[\\d\\s,.]*\\d|\\d+/g\n const matches: Array<{ start: number; end: number }> = []\n let m: RegExpExecArray | null\n while ((m = numberRegex.exec(text)) !== null) {\n matches.push({ start: m.index, end: m.index + m[0].length })\n }\n\n // Build a lookup from position → match\n const matchByPosition = new Map<number, { start: number; end: number }>()\n for (const match of matches) {\n matchByPosition.set(match.start, match)\n }\n\n // Build segments\n const segments: TextSegment[] = []\n let cursor = 0\n\n for (const num of validation.llmNumbers) {\n const match = matchByPosition.get(num.position)\n if (!match) continue\n\n // Text before this number\n if (match.start > cursor) {\n segments.push({ type: 'text', content: text.slice(cursor, match.start) })\n }\n\n const numberText = text.slice(match.start, match.end)\n const hallucinated = hallucinatedPositions.get(num.position)\n\n if (hallucinated) {\n segments.push({ type: 'hallucinated', content: numberText, item: hallucinated })\n } else {\n segments.push({ type: 'verified', content: numberText })\n }\n\n cursor = match.end\n }\n\n // Remaining text\n if (cursor < text.length) {\n segments.push({ type: 'text', content: text.slice(cursor) })\n }\n\n return segments\n}\n\nexport function VerifiedText(props: VerifiedTextProps) {\n const strings = useMCPUIStrings()\n const mode = () => props.mode || 'highlight'\n\n const segments = createMemo<TextSegment[]>(() => {\n if (!props.validation || props.validation.valid) {\n return [{ type: 'text' as const, content: props.text }]\n }\n return buildAnnotatedSegments(props.text, props.validation)\n })\n\n return (\n <div class=\"verified-text text-sm leading-relaxed\">\n <For each={segments()}>\n {(seg) => {\n if (seg.type === 'text') {\n return <span>{seg.content}</span>\n }\n\n if (seg.type === 'verified') {\n return (\n <span\n class=\"inline-flex items-center gap-0.5 px-0.5 rounded bg-green-50 dark:bg-green-900/20 text-green-800 dark:text-green-300\"\n title={strings.verifiedTitle}\n >\n {seg.content}\n <span class=\"text-xs opacity-70\" aria-label={strings.verifiedAria}>✅</span>\n </span>\n )\n }\n\n // hallucinated\n const h = seg.item!\n const tooltipText = () => {\n if (h.closest != null && h.distance != null) {\n return formatMCPUIString(strings.verifiedNotFoundClosest, {\n closest: h.closest,\n pct: Math.round(h.distance * 100),\n })\n }\n return strings.verifiedNotFound\n }\n\n if (mode() === 'strip') {\n return (\n <span\n class=\"inline-flex items-center px-1 rounded bg-amber-50 dark:bg-amber-900/20 text-amber-700 dark:text-amber-300 italic text-xs\"\n title={tooltipText()}\n >\n {strings.verifiedStripLabel}\n </span>\n )\n }\n\n return (\n <span\n class=\"inline-flex items-center gap-0.5 px-0.5 rounded bg-amber-50 dark:bg-amber-900/20 text-amber-800 dark:text-amber-300 cursor-help\"\n title={tooltipText()}\n onClick={() => props.onHallucinationClick?.(h)}\n role={props.onHallucinationClick ? 'button' : undefined}\n >\n {seg.content}\n <span class=\"text-xs\" aria-label={strings.unverifiedAria}>⚠️</span>\n </span>\n )\n }}\n </For>\n\n {/* Confidence bar */}\n {props.validation && !props.validation.valid && (\n <div class=\"mt-2 flex items-center gap-2 text-xs text-gray-500 dark:text-gray-400\">\n <div class=\"flex-1 h-1.5 bg-gray-200 dark:bg-gray-700 rounded-full overflow-hidden\">\n <div\n class=\"h-full rounded-full transition-all\"\n classList={{\n 'bg-green-500': props.validation.confidence >= 0.8,\n 'bg-amber-500': props.validation.confidence >= 0.5 && props.validation.confidence < 0.8,\n 'bg-red-500': props.validation.confidence < 0.5,\n }}\n style={{ width: `${Math.round(props.validation.confidence * 100)}%` }}\n />\n </div>\n <span>\n {formatMCPUIString(strings.verifiedConfidence, {\n pct: Math.round(props.validation.confidence * 100),\n })}{' '}\n {formatMCPUIString(strings.verifiedUnverifiedCount, {\n count: props.validation.hallucinated.length,\n })}\n </span>\n </div>\n )}\n </div>\n )\n}\n"],"names":["buildAnnotatedSegments","text","validation","hallucinatedPositions","Map","h","hallucinated","set","position","verifiedPositions","Set","n","llmNumbers","has","add","numberRegex","matches","m","exec","push","start","index","end","length","matchByPosition","match","segments","cursor","num","get","type","content","slice","numberText","item","VerifiedText","props","strings","useMCPUIStrings","mode","createMemo","valid","_el$","_$getNextElement","_tmpl$","_el$2","firstChild","_el$3","_co$","_$getNextMarker","nextSibling","_el$4","_el$5","_co$2","_$insert","_$createComponent","For","each","children","seg","_el$6","_tmpl$2","_el$7","_tmpl$3","_el$9","_el$0","_co$3","_el$8","_$effect","_p$","_v$","verifiedTitle","_v$2","verifiedAria","e","_$setAttribute","t","undefined","tooltipText","closest","distance","formatMCPUIString","verifiedNotFoundClosest","pct","Math","round","verifiedNotFound","_el$1","_tmpl$4","verifiedStripLabel","_el$10","_tmpl$5","_el$12","_el$13","_co$4","_el$11","$$click","onHallucinationClick","_v$3","_v$4","_v$5","unverifiedAria","a","_$runHydrationEvents","_c$","_$memo","_el$14","_tmpl$6","_el$15","_el$16","_el$17","_el$19","_el$20","_co$5","_el$18","_el$21","_el$22","_co$6","verifiedConfidence","confidence","verifiedUnverifiedCount","count","_v$6","_v$7","_v$8","_v$9","classList","toggle","o","_$setStyleProperty","_$delegateEvents"],"mappings":"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"}
|
|
@@ -6,7 +6,8 @@
|
|
|
6
6
|
*
|
|
7
7
|
* Modes:
|
|
8
8
|
* - highlight: ✅/⚠️ badges next to numbers (default)
|
|
9
|
-
* - strip: replaces hallucinated numbers with
|
|
9
|
+
* - strip: replaces hallucinated numbers with the `verifiedStripLabel`
|
|
10
|
+
* chrome string ('[unverified]' by default)
|
|
10
11
|
* - annotate: tooltip on hover with closest source number
|
|
11
12
|
*/
|
|
12
13
|
import type { DataValidation, HallucinatedNumber } from '../types/chat-bus';
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"VerifiedText.d.ts","sourceRoot":"","sources":["../../src/components/VerifiedText.tsx"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"VerifiedText.d.ts","sourceRoot":"","sources":["../../src/components/VerifiedText.tsx"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAGH,OAAO,KAAK,EAAE,cAAc,EAAE,kBAAkB,EAAE,MAAM,mBAAmB,CAAA;AAG3E,MAAM,WAAW,iBAAiB;IAChC,IAAI,EAAE,MAAM,CAAA;IACZ,UAAU,EAAE,cAAc,CAAA;IAC1B,0CAA0C;IAC1C,IAAI,CAAC,EAAE,WAAW,GAAG,OAAO,GAAG,UAAU,CAAA;IACzC,qDAAqD;IACrD,oBAAoB,CAAC,EAAE,CAAC,IAAI,EAAE,kBAAkB,KAAK,IAAI,CAAA;CAC1D;AAyED,wBAAgB,YAAY,CAAC,KAAK,EAAE,iBAAiB,kCA8FpD"}
|
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
import { getNextElement, getNextMarker, insert, createComponent, effect, setAttribute, runHydrationEvents, memo, setStyleProperty, template, delegateEvents } from "solid-js/web";
|
|
2
2
|
import { createMemo, For } from "solid-js";
|
|
3
|
-
|
|
3
|
+
import { useMCPUIStrings } from "../context/MCPUIStringsContext.js";
|
|
4
|
+
import { formatMCPUIString } from "../utils/format-string.js";
|
|
5
|
+
var _tmpl$ = /* @__PURE__ */ template(`<div class="verified-text text-sm leading-relaxed"><!$><!/><!$><!/>`), _tmpl$2 = /* @__PURE__ */ template(`<span>`), _tmpl$3 = /* @__PURE__ */ template(`<span class="inline-flex items-center gap-0.5 px-0.5 rounded bg-green-50 dark:bg-green-900/20 text-green-800 dark:text-green-300"><!$><!/><span class="text-xs opacity-70">✅`), _tmpl$4 = /* @__PURE__ */ template(`<span class="inline-flex items-center px-1 rounded bg-amber-50 dark:bg-amber-900/20 text-amber-700 dark:text-amber-300 italic text-xs">`), _tmpl$5 = /* @__PURE__ */ template(`<span class="inline-flex items-center gap-0.5 px-0.5 rounded bg-amber-50 dark:bg-amber-900/20 text-amber-800 dark:text-amber-300 cursor-help"><!$><!/><span class=text-xs>⚠️`), _tmpl$6 = /* @__PURE__ */ template(`<div class="mt-2 flex items-center gap-2 text-xs text-gray-500 dark:text-gray-400"><div class="flex-1 h-1.5 bg-gray-200 dark:bg-gray-700 rounded-full overflow-hidden"><div class="h-full rounded-full transition-all"></div></div><span><!$><!/> <!$><!/>`);
|
|
4
6
|
function buildAnnotatedSegments(text, validation) {
|
|
5
7
|
const hallucinatedPositions = /* @__PURE__ */ new Map();
|
|
6
8
|
for (const h of validation.hallucinated) {
|
|
@@ -61,6 +63,7 @@ function buildAnnotatedSegments(text, validation) {
|
|
|
61
63
|
return segments;
|
|
62
64
|
}
|
|
63
65
|
function VerifiedText(props) {
|
|
66
|
+
const strings = useMCPUIStrings();
|
|
64
67
|
const mode = () => props.mode || "highlight";
|
|
65
68
|
const segments = createMemo(() => {
|
|
66
69
|
if (!props.validation || props.validation.valid) {
|
|
@@ -87,42 +90,55 @@ function VerifiedText(props) {
|
|
|
87
90
|
}
|
|
88
91
|
if (seg.type === "verified") {
|
|
89
92
|
return (() => {
|
|
90
|
-
var _el$7 = getNextElement(_tmpl$3), _el$9 = _el$7.firstChild, [_el$0, _co$3] = getNextMarker(_el$9.nextSibling);
|
|
91
|
-
_el$0.nextSibling;
|
|
93
|
+
var _el$7 = getNextElement(_tmpl$3), _el$9 = _el$7.firstChild, [_el$0, _co$3] = getNextMarker(_el$9.nextSibling), _el$8 = _el$0.nextSibling;
|
|
92
94
|
insert(_el$7, () => seg.content, _el$0, _co$3);
|
|
95
|
+
effect((_p$) => {
|
|
96
|
+
var _v$ = strings.verifiedTitle, _v$2 = strings.verifiedAria;
|
|
97
|
+
_v$ !== _p$.e && setAttribute(_el$7, "title", _p$.e = _v$);
|
|
98
|
+
_v$2 !== _p$.t && setAttribute(_el$8, "aria-label", _p$.t = _v$2);
|
|
99
|
+
return _p$;
|
|
100
|
+
}, {
|
|
101
|
+
e: void 0,
|
|
102
|
+
t: void 0
|
|
103
|
+
});
|
|
93
104
|
return _el$7;
|
|
94
105
|
})();
|
|
95
106
|
}
|
|
96
107
|
const h = seg.item;
|
|
97
108
|
const tooltipText = () => {
|
|
98
109
|
if (h.closest != null && h.distance != null) {
|
|
99
|
-
return
|
|
110
|
+
return formatMCPUIString(strings.verifiedNotFoundClosest, {
|
|
111
|
+
closest: h.closest,
|
|
112
|
+
pct: Math.round(h.distance * 100)
|
|
113
|
+
});
|
|
100
114
|
}
|
|
101
|
-
return
|
|
115
|
+
return strings.verifiedNotFound;
|
|
102
116
|
};
|
|
103
117
|
if (mode() === "strip") {
|
|
104
118
|
return (() => {
|
|
105
119
|
var _el$1 = getNextElement(_tmpl$4);
|
|
120
|
+
insert(_el$1, () => strings.verifiedStripLabel);
|
|
106
121
|
effect(() => setAttribute(_el$1, "title", tooltipText()));
|
|
107
122
|
return _el$1;
|
|
108
123
|
})();
|
|
109
124
|
}
|
|
110
125
|
return (() => {
|
|
111
|
-
var _el$10 = getNextElement(_tmpl$5), _el$12 = _el$10.firstChild, [_el$13, _co$4] = getNextMarker(_el$12.nextSibling);
|
|
112
|
-
_el$13.nextSibling;
|
|
126
|
+
var _el$10 = getNextElement(_tmpl$5), _el$12 = _el$10.firstChild, [_el$13, _co$4] = getNextMarker(_el$12.nextSibling), _el$11 = _el$13.nextSibling;
|
|
113
127
|
_el$10.$$click = () => {
|
|
114
128
|
var _a;
|
|
115
129
|
return (_a = props.onHallucinationClick) == null ? void 0 : _a.call(props, h);
|
|
116
130
|
};
|
|
117
131
|
insert(_el$10, () => seg.content, _el$13, _co$4);
|
|
118
132
|
effect((_p$) => {
|
|
119
|
-
var _v$ = tooltipText(), _v$
|
|
120
|
-
_v$ !== _p$.e && setAttribute(_el$10, "title", _p$.e = _v$);
|
|
121
|
-
_v$
|
|
133
|
+
var _v$3 = tooltipText(), _v$4 = props.onHallucinationClick ? "button" : void 0, _v$5 = strings.unverifiedAria;
|
|
134
|
+
_v$3 !== _p$.e && setAttribute(_el$10, "title", _p$.e = _v$3);
|
|
135
|
+
_v$4 !== _p$.t && setAttribute(_el$10, "role", _p$.t = _v$4);
|
|
136
|
+
_v$5 !== _p$.a && setAttribute(_el$11, "aria-label", _p$.a = _v$5);
|
|
122
137
|
return _p$;
|
|
123
138
|
}, {
|
|
124
139
|
e: void 0,
|
|
125
|
-
t: void 0
|
|
140
|
+
t: void 0,
|
|
141
|
+
a: void 0
|
|
126
142
|
});
|
|
127
143
|
runHydrationEvents();
|
|
128
144
|
return _el$10;
|
|
@@ -132,16 +148,19 @@ function VerifiedText(props) {
|
|
|
132
148
|
insert(_el$, (() => {
|
|
133
149
|
var _c$ = memo(() => !!(props.validation && !props.validation.valid));
|
|
134
150
|
return () => _c$() && (() => {
|
|
135
|
-
var _el$14 = getNextElement(_tmpl$6), _el$15 = _el$14.firstChild, _el$16 = _el$15.firstChild, _el$17 = _el$15.nextSibling, _el$
|
|
136
|
-
_el$
|
|
137
|
-
|
|
138
|
-
|
|
151
|
+
var _el$14 = getNextElement(_tmpl$6), _el$15 = _el$14.firstChild, _el$16 = _el$15.firstChild, _el$17 = _el$15.nextSibling, _el$19 = _el$17.firstChild, [_el$20, _co$5] = getNextMarker(_el$19.nextSibling), _el$18 = _el$20.nextSibling, _el$21 = _el$18.nextSibling, [_el$22, _co$6] = getNextMarker(_el$21.nextSibling);
|
|
152
|
+
insert(_el$17, () => formatMCPUIString(strings.verifiedConfidence, {
|
|
153
|
+
pct: Math.round(props.validation.confidence * 100)
|
|
154
|
+
}), _el$20, _co$5);
|
|
155
|
+
insert(_el$17, () => formatMCPUIString(strings.verifiedUnverifiedCount, {
|
|
156
|
+
count: props.validation.hallucinated.length
|
|
157
|
+
}), _el$22, _co$6);
|
|
139
158
|
effect((_p$) => {
|
|
140
|
-
var _v$
|
|
141
|
-
_v$
|
|
142
|
-
_v$
|
|
143
|
-
_v$
|
|
144
|
-
_v$
|
|
159
|
+
var _v$6 = !!(props.validation.confidence >= 0.8), _v$7 = !!(props.validation.confidence >= 0.5 && props.validation.confidence < 0.8), _v$8 = !!(props.validation.confidence < 0.5), _v$9 = `${Math.round(props.validation.confidence * 100)}%`;
|
|
160
|
+
_v$6 !== _p$.e && _el$16.classList.toggle("bg-green-500", _p$.e = _v$6);
|
|
161
|
+
_v$7 !== _p$.t && _el$16.classList.toggle("bg-amber-500", _p$.t = _v$7);
|
|
162
|
+
_v$8 !== _p$.a && _el$16.classList.toggle("bg-red-500", _p$.a = _v$8);
|
|
163
|
+
_v$9 !== _p$.o && setStyleProperty(_el$16, "width", _p$.o = _v$9);
|
|
145
164
|
return _p$;
|
|
146
165
|
}, {
|
|
147
166
|
e: void 0,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"VerifiedText.js","sources":["../../src/components/VerifiedText.tsx"],"sourcesContent":["/**\n * VerifiedText — renders LLM text with inline verification badges\n * v3.1.0: Highlights verified vs hallucinated numbers\n *\n * @experimental\n *\n * Modes:\n * - highlight: ✅/⚠️ badges next to numbers (default)\n * - strip: replaces hallucinated numbers with [non vérifié]\n * - annotate: tooltip on hover with closest source number\n */\n\nimport { createMemo, For } from 'solid-js'\nimport type { DataValidation, HallucinatedNumber } from '../types/chat-bus'\n\nexport interface VerifiedTextProps {\n text: string\n validation: DataValidation\n /** Display mode (default: 'highlight') */\n mode?: 'highlight' | 'strip' | 'annotate'\n /** Callback when a hallucinated number is clicked */\n onHallucinationClick?: (item: HallucinatedNumber) => void\n}\n\ninterface TextSegment {\n type: 'text' | 'verified' | 'hallucinated'\n content: string\n item?: HallucinatedNumber\n}\n\n/**\n * Build annotated segments by splitting text at number positions.\n * Verified numbers get ✅, hallucinated get ⚠️.\n */\nfunction buildAnnotatedSegments(text: string, validation: DataValidation): TextSegment[] {\n // Build position maps\n const hallucinatedPositions = new Map<number, HallucinatedNumber>()\n for (const h of validation.hallucinated) {\n hallucinatedPositions.set(h.position, h)\n }\n\n const verifiedPositions = new Set<number>()\n for (const n of validation.llmNumbers) {\n if (!hallucinatedPositions.has(n.position)) {\n verifiedPositions.add(n.position)\n }\n }\n\n // Re-extract number lengths from text for precise splitting\n const numberRegex = /\\d[\\d\\s,.]*\\d|\\d+/g\n const matches: Array<{ start: number; end: number }> = []\n let m: RegExpExecArray | null\n while ((m = numberRegex.exec(text)) !== null) {\n matches.push({ start: m.index, end: m.index + m[0].length })\n }\n\n // Build a lookup from position → match\n const matchByPosition = new Map<number, { start: number; end: number }>()\n for (const match of matches) {\n matchByPosition.set(match.start, match)\n }\n\n // Build segments\n const segments: TextSegment[] = []\n let cursor = 0\n\n for (const num of validation.llmNumbers) {\n const match = matchByPosition.get(num.position)\n if (!match) continue\n\n // Text before this number\n if (match.start > cursor) {\n segments.push({ type: 'text', content: text.slice(cursor, match.start) })\n }\n\n const numberText = text.slice(match.start, match.end)\n const hallucinated = hallucinatedPositions.get(num.position)\n\n if (hallucinated) {\n segments.push({ type: 'hallucinated', content: numberText, item: hallucinated })\n } else {\n segments.push({ type: 'verified', content: numberText })\n }\n\n cursor = match.end\n }\n\n // Remaining text\n if (cursor < text.length) {\n segments.push({ type: 'text', content: text.slice(cursor) })\n }\n\n return segments\n}\n\nexport function VerifiedText(props: VerifiedTextProps) {\n const mode = () => props.mode || 'highlight'\n\n const segments = createMemo<TextSegment[]>(() => {\n if (!props.validation || props.validation.valid) {\n return [{ type: 'text' as const, content: props.text }]\n }\n return buildAnnotatedSegments(props.text, props.validation)\n })\n\n return (\n <div class=\"verified-text text-sm leading-relaxed\">\n <For each={segments()}>\n {(seg) => {\n if (seg.type === 'text') {\n return <span>{seg.content}</span>\n }\n\n if (seg.type === 'verified') {\n return (\n <span\n class=\"inline-flex items-center gap-0.5 px-0.5 rounded bg-green-50 dark:bg-green-900/20 text-green-800 dark:text-green-300\"\n title=\"Verified against source data\"\n >\n {seg.content}\n <span class=\"text-xs opacity-70\" aria-label=\"verified\">✅</span>\n </span>\n )\n }\n\n // hallucinated\n const h = seg.item!\n const tooltipText = () => {\n if (h.closest != null && h.distance != null) {\n return `Not found in source data. Closest: ${h.closest} (${Math.round(h.distance * 100)}% off)`\n }\n return 'Not found in source data'\n }\n\n if (mode() === 'strip') {\n return (\n <span\n class=\"inline-flex items-center px-1 rounded bg-amber-50 dark:bg-amber-900/20 text-amber-700 dark:text-amber-300 italic text-xs\"\n title={tooltipText()}\n >\n [non vérifié]\n </span>\n )\n }\n\n return (\n <span\n class=\"inline-flex items-center gap-0.5 px-0.5 rounded bg-amber-50 dark:bg-amber-900/20 text-amber-800 dark:text-amber-300 cursor-help\"\n title={tooltipText()}\n onClick={() => props.onHallucinationClick?.(h)}\n role={props.onHallucinationClick ? 'button' : undefined}\n >\n {seg.content}\n <span class=\"text-xs\" aria-label=\"unverified\">⚠️</span>\n </span>\n )\n }}\n </For>\n\n {/* Confidence bar */}\n {props.validation && !props.validation.valid && (\n <div class=\"mt-2 flex items-center gap-2 text-xs text-gray-500 dark:text-gray-400\">\n <div class=\"flex-1 h-1.5 bg-gray-200 dark:bg-gray-700 rounded-full overflow-hidden\">\n <div\n class=\"h-full rounded-full transition-all\"\n classList={{\n 'bg-green-500': props.validation.confidence >= 0.8,\n 'bg-amber-500': props.validation.confidence >= 0.5 && props.validation.confidence < 0.8,\n 'bg-red-500': props.validation.confidence < 0.5,\n }}\n style={{ width: `${Math.round(props.validation.confidence * 100)}%` }}\n />\n </div>\n <span>\n {Math.round(props.validation.confidence * 100)}% verified\n ({props.validation.hallucinated.length} unverified)\n </span>\n </div>\n )}\n </div>\n )\n}\n"],"names":["buildAnnotatedSegments","text","validation","hallucinatedPositions","Map","h","hallucinated","set","position","verifiedPositions","Set","n","llmNumbers","has","add","numberRegex","matches","m","exec","push","start","index","end","length","matchByPosition","match","segments","cursor","num","get","type","content","slice","numberText","item","VerifiedText","props","mode","createMemo","valid","_el$","_$getNextElement","_tmpl$","_el$2","firstChild","_el$3","_co$","_$getNextMarker","nextSibling","_el$4","_el$5","_co$2","_$insert","_$createComponent","For","each","children","seg","_el$6","_tmpl$2","_el$7","_tmpl$3","_el$9","_el$0","_co$3","tooltipText","closest","distance","Math","round","_el$1","_tmpl$4","_$effect","_$setAttribute","_el$10","_tmpl$5","_el$12","_el$13","_co$4","$$click","onHallucinationClick","_p$","_v$","_v$2","undefined","e","t","_$runHydrationEvents","_c$","_$memo","_el$14","_tmpl$6","_el$15","_el$16","_el$17","_el$20","_el$21","_co$5","_el$18","_el$22","_el$23","_co$6","confidence","_v$3","_v$4","_v$5","_v$6","classList","toggle","a","o","_$setStyleProperty","_$delegateEvents"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"VerifiedText.js","sources":["../../src/components/VerifiedText.tsx"],"sourcesContent":["/**\n * VerifiedText — renders LLM text with inline verification badges\n * v3.1.0: Highlights verified vs hallucinated numbers\n *\n * @experimental\n *\n * Modes:\n * - highlight: ✅/⚠️ badges next to numbers (default)\n * - strip: replaces hallucinated numbers with the `verifiedStripLabel`\n * chrome string ('[unverified]' by default)\n * - annotate: tooltip on hover with closest source number\n */\n\nimport { createMemo, For } from 'solid-js'\nimport type { DataValidation, HallucinatedNumber } from '../types/chat-bus'\nimport { formatMCPUIString, useMCPUIStrings } from '../context/MCPUIStringsContext'\n\nexport interface VerifiedTextProps {\n text: string\n validation: DataValidation\n /** Display mode (default: 'highlight') */\n mode?: 'highlight' | 'strip' | 'annotate'\n /** Callback when a hallucinated number is clicked */\n onHallucinationClick?: (item: HallucinatedNumber) => void\n}\n\ninterface TextSegment {\n type: 'text' | 'verified' | 'hallucinated'\n content: string\n item?: HallucinatedNumber\n}\n\n/**\n * Build annotated segments by splitting text at number positions.\n * Verified numbers get ✅, hallucinated get ⚠️.\n */\nfunction buildAnnotatedSegments(text: string, validation: DataValidation): TextSegment[] {\n // Build position maps\n const hallucinatedPositions = new Map<number, HallucinatedNumber>()\n for (const h of validation.hallucinated) {\n hallucinatedPositions.set(h.position, h)\n }\n\n const verifiedPositions = new Set<number>()\n for (const n of validation.llmNumbers) {\n if (!hallucinatedPositions.has(n.position)) {\n verifiedPositions.add(n.position)\n }\n }\n\n // Re-extract number lengths from text for precise splitting\n const numberRegex = /\\d[\\d\\s,.]*\\d|\\d+/g\n const matches: Array<{ start: number; end: number }> = []\n let m: RegExpExecArray | null\n while ((m = numberRegex.exec(text)) !== null) {\n matches.push({ start: m.index, end: m.index + m[0].length })\n }\n\n // Build a lookup from position → match\n const matchByPosition = new Map<number, { start: number; end: number }>()\n for (const match of matches) {\n matchByPosition.set(match.start, match)\n }\n\n // Build segments\n const segments: TextSegment[] = []\n let cursor = 0\n\n for (const num of validation.llmNumbers) {\n const match = matchByPosition.get(num.position)\n if (!match) continue\n\n // Text before this number\n if (match.start > cursor) {\n segments.push({ type: 'text', content: text.slice(cursor, match.start) })\n }\n\n const numberText = text.slice(match.start, match.end)\n const hallucinated = hallucinatedPositions.get(num.position)\n\n if (hallucinated) {\n segments.push({ type: 'hallucinated', content: numberText, item: hallucinated })\n } else {\n segments.push({ type: 'verified', content: numberText })\n }\n\n cursor = match.end\n }\n\n // Remaining text\n if (cursor < text.length) {\n segments.push({ type: 'text', content: text.slice(cursor) })\n }\n\n return segments\n}\n\nexport function VerifiedText(props: VerifiedTextProps) {\n const strings = useMCPUIStrings()\n const mode = () => props.mode || 'highlight'\n\n const segments = createMemo<TextSegment[]>(() => {\n if (!props.validation || props.validation.valid) {\n return [{ type: 'text' as const, content: props.text }]\n }\n return buildAnnotatedSegments(props.text, props.validation)\n })\n\n return (\n <div class=\"verified-text text-sm leading-relaxed\">\n <For each={segments()}>\n {(seg) => {\n if (seg.type === 'text') {\n return <span>{seg.content}</span>\n }\n\n if (seg.type === 'verified') {\n return (\n <span\n class=\"inline-flex items-center gap-0.5 px-0.5 rounded bg-green-50 dark:bg-green-900/20 text-green-800 dark:text-green-300\"\n title={strings.verifiedTitle}\n >\n {seg.content}\n <span class=\"text-xs opacity-70\" aria-label={strings.verifiedAria}>✅</span>\n </span>\n )\n }\n\n // hallucinated\n const h = seg.item!\n const tooltipText = () => {\n if (h.closest != null && h.distance != null) {\n return formatMCPUIString(strings.verifiedNotFoundClosest, {\n closest: h.closest,\n pct: Math.round(h.distance * 100),\n })\n }\n return strings.verifiedNotFound\n }\n\n if (mode() === 'strip') {\n return (\n <span\n class=\"inline-flex items-center px-1 rounded bg-amber-50 dark:bg-amber-900/20 text-amber-700 dark:text-amber-300 italic text-xs\"\n title={tooltipText()}\n >\n {strings.verifiedStripLabel}\n </span>\n )\n }\n\n return (\n <span\n class=\"inline-flex items-center gap-0.5 px-0.5 rounded bg-amber-50 dark:bg-amber-900/20 text-amber-800 dark:text-amber-300 cursor-help\"\n title={tooltipText()}\n onClick={() => props.onHallucinationClick?.(h)}\n role={props.onHallucinationClick ? 'button' : undefined}\n >\n {seg.content}\n <span class=\"text-xs\" aria-label={strings.unverifiedAria}>⚠️</span>\n </span>\n )\n }}\n </For>\n\n {/* Confidence bar */}\n {props.validation && !props.validation.valid && (\n <div class=\"mt-2 flex items-center gap-2 text-xs text-gray-500 dark:text-gray-400\">\n <div class=\"flex-1 h-1.5 bg-gray-200 dark:bg-gray-700 rounded-full overflow-hidden\">\n <div\n class=\"h-full rounded-full transition-all\"\n classList={{\n 'bg-green-500': props.validation.confidence >= 0.8,\n 'bg-amber-500': props.validation.confidence >= 0.5 && props.validation.confidence < 0.8,\n 'bg-red-500': props.validation.confidence < 0.5,\n }}\n style={{ width: `${Math.round(props.validation.confidence * 100)}%` }}\n />\n </div>\n <span>\n {formatMCPUIString(strings.verifiedConfidence, {\n pct: Math.round(props.validation.confidence * 100),\n })}{' '}\n {formatMCPUIString(strings.verifiedUnverifiedCount, {\n count: props.validation.hallucinated.length,\n })}\n </span>\n </div>\n )}\n </div>\n )\n}\n"],"names":["buildAnnotatedSegments","text","validation","hallucinatedPositions","Map","h","hallucinated","set","position","verifiedPositions","Set","n","llmNumbers","has","add","numberRegex","matches","m","exec","push","start","index","end","length","matchByPosition","match","segments","cursor","num","get","type","content","slice","numberText","item","VerifiedText","props","strings","useMCPUIStrings","mode","createMemo","valid","_el$","_$getNextElement","_tmpl$","_el$2","firstChild","_el$3","_co$","_$getNextMarker","nextSibling","_el$4","_el$5","_co$2","_$insert","_$createComponent","For","each","children","seg","_el$6","_tmpl$2","_el$7","_tmpl$3","_el$9","_el$0","_co$3","_el$8","_$effect","_p$","_v$","verifiedTitle","_v$2","verifiedAria","e","_$setAttribute","t","undefined","tooltipText","closest","distance","formatMCPUIString","verifiedNotFoundClosest","pct","Math","round","verifiedNotFound","_el$1","_tmpl$4","verifiedStripLabel","_el$10","_tmpl$5","_el$12","_el$13","_co$4","_el$11","$$click","onHallucinationClick","_v$3","_v$4","_v$5","unverifiedAria","a","_$runHydrationEvents","_c$","_$memo","_el$14","_tmpl$6","_el$15","_el$16","_el$17","_el$19","_el$20","_co$5","_el$18","_el$21","_el$22","_co$6","verifiedConfidence","confidence","verifiedUnverifiedCount","count","_v$6","_v$7","_v$8","_v$9","classList","toggle","o","_$setStyleProperty","_$delegateEvents"],"mappings":"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"}
|
|
@@ -3,7 +3,8 @@ Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
|
3
3
|
const web = require("solid-js/web");
|
|
4
4
|
const solidJs = require("solid-js");
|
|
5
5
|
const ExpandableWrapper = require("./ExpandableWrapper.cjs");
|
|
6
|
-
|
|
6
|
+
const MCPUIStringsContext = require("../context/MCPUIStringsContext.cjs");
|
|
7
|
+
var _tmpl$ = /* @__PURE__ */ web.template(`<div class="px-4 py-3 border-b border-gray-200 dark:border-gray-700"><h3 class="text-sm font-semibold text-gray-900 dark:text-white">`), _tmpl$2 = /* @__PURE__ */ web.template(`<iframe class="absolute inset-0 w-full h-full"allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share"allowfullscreen loading=lazy>`, true, false, false), _tmpl$3 = /* @__PURE__ */ web.template(`<div class="px-4 py-3 border-t border-gray-200 dark:border-gray-700 flex-shrink-0"><p class="text-sm text-gray-600 dark:text-gray-400">`), _tmpl$4 = /* @__PURE__ */ web.template(`<div><!$><!/><div></div><!$><!/>`), _tmpl$5 = /* @__PURE__ */ web.template(`<video playsinline class="absolute inset-0 w-full h-full object-contain"><track kind=captions><!$><!/>`);
|
|
7
8
|
function parseVideoUrl(url) {
|
|
8
9
|
const youtubeMatch = url.match(/(?:youtube\.com\/(?:watch\?v=|embed\/|v\/)|youtu\.be\/)([a-zA-Z0-9_-]{11})/);
|
|
9
10
|
if (youtubeMatch) {
|
|
@@ -24,6 +25,7 @@ function parseVideoUrl(url) {
|
|
|
24
25
|
};
|
|
25
26
|
}
|
|
26
27
|
const VideoRenderer = (props) => {
|
|
28
|
+
const strings = MCPUIStringsContext.useMCPUIStrings();
|
|
27
29
|
const params = () => {
|
|
28
30
|
var _a;
|
|
29
31
|
return props.params || ((_a = props.component) == null ? void 0 : _a.params);
|
|
@@ -84,13 +86,15 @@ const VideoRenderer = (props) => {
|
|
|
84
86
|
return web.createComponent(ExpandableWrapper.ExpandableWrapper, {
|
|
85
87
|
get title() {
|
|
86
88
|
var _a;
|
|
87
|
-
return ((_a = params()) == null ? void 0 : _a.title) ||
|
|
89
|
+
return ((_a = params()) == null ? void 0 : _a.title) || strings.videoTitle;
|
|
88
90
|
},
|
|
89
91
|
get copyData() {
|
|
90
92
|
var _a;
|
|
91
93
|
return ((_a = params()) == null ? void 0 : _a.url) || "";
|
|
92
94
|
},
|
|
93
|
-
copyLabel
|
|
95
|
+
get copyLabel() {
|
|
96
|
+
return strings.videoCopy;
|
|
97
|
+
},
|
|
94
98
|
get toolbarVariant() {
|
|
95
99
|
return props.toolbarVariant;
|
|
96
100
|
},
|
|
@@ -115,8 +119,9 @@ const VideoRenderer = (props) => {
|
|
|
115
119
|
return (
|
|
116
120
|
// Direct video file
|
|
117
121
|
(() => {
|
|
118
|
-
var _el$10 = web.getNextElement(_tmpl$5);
|
|
122
|
+
var _el$10 = web.getNextElement(_tmpl$5), _el$11 = _el$10.firstChild, _el$12 = _el$11.nextSibling, [_el$13, _co$3] = web.getNextMarker(_el$12.nextSibling);
|
|
119
123
|
_el$10.addEventListener("error", handleVideoError);
|
|
124
|
+
web.insert(_el$10, () => strings.videoUnsupported, _el$13, _co$3);
|
|
120
125
|
web.effect((_p$) => {
|
|
121
126
|
var _a, _b, _c, _d, _e, _f;
|
|
122
127
|
var _v$5 = (_a = params()) == null ? void 0 : _a.url, _v$6 = (_b = params()) == null ? void 0 : _b.poster, _v$7 = (_c = params()) == null ? void 0 : _c.autoplay, _v$8 = ((_d = params()) == null ? void 0 : _d.controls) !== false, _v$9 = (_e = params()) == null ? void 0 : _e.loop, _v$0 = (_f = params()) == null ? void 0 : _f.muted;
|
|
@@ -143,7 +148,7 @@ const VideoRenderer = (props) => {
|
|
|
143
148
|
var _el$5 = web.getNextElement(_tmpl$2);
|
|
144
149
|
web.effect((_p$) => {
|
|
145
150
|
var _a;
|
|
146
|
-
var _v$ = embedUrl(), _v$2 = ((_a = params()) == null ? void 0 : _a.title) ||
|
|
151
|
+
var _v$ = embedUrl(), _v$2 = ((_a = params()) == null ? void 0 : _a.title) || strings.videoTitle;
|
|
147
152
|
_v$ !== _p$.e && web.setAttribute(_el$5, "src", _p$.e = _v$);
|
|
148
153
|
_v$2 !== _p$.t && web.setAttribute(_el$5, "title", _p$.t = _v$2);
|
|
149
154
|
return _p$;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"VideoRenderer.cjs","sources":["../../src/components/VideoRenderer.tsx"],"sourcesContent":["/**\n * VideoRenderer - Video embed component\n * Sprint 5: Media Components\n *\n * Supports YouTube, Vimeo, and direct video files\n */\n\nimport { Component, createMemo, Show } from 'solid-js'\nimport type { UIComponent, VideoComponentParams } from '../types'\nimport { ExpandableWrapper, useExpanded } from './ExpandableWrapper'\n\nexport interface VideoRendererProps {\n /**\n * UIComponent containing video params\n */\n component?: UIComponent\n\n /**\n * Direct video params (alternative to component)\n */\n params?: VideoComponentParams\n\n /**\n * Error callback\n */\n onError?: (error: Error) => void\n\n /**\n * Forwarded to the underlying `<ExpandableWrapper>` (v6.3.1).\n * @see ExpandableWrapperProps.toolbarVariant\n */\n toolbarVariant?: 'hover' | 'always-visible'\n}\n\n/**\n * Video provider type\n */\ntype VideoProvider = 'youtube' | 'vimeo' | 'direct'\n\n/**\n * Parsed video info\n */\ninterface VideoInfo {\n provider: VideoProvider\n videoId?: string\n}\n\n/**\n * Extract video ID and provider from URL\n */\nfunction parseVideoUrl(url: string): VideoInfo {\n // YouTube patterns:\n // - youtube.com/watch?v=VIDEO_ID\n // - youtube.com/embed/VIDEO_ID\n // - youtube.com/v/VIDEO_ID\n // - youtu.be/VIDEO_ID\n const youtubeMatch = url.match(\n /(?:youtube\\.com\\/(?:watch\\?v=|embed\\/|v\\/)|youtu\\.be\\/)([a-zA-Z0-9_-]{11})/\n )\n if (youtubeMatch) {\n return { provider: 'youtube', videoId: youtubeMatch[1] }\n }\n\n // Vimeo patterns:\n // - vimeo.com/VIDEO_ID\n // - player.vimeo.com/video/VIDEO_ID\n const vimeoMatch = url.match(/(?:vimeo\\.com\\/|player\\.vimeo\\.com\\/video\\/)(\\d+)/)\n if (vimeoMatch) {\n return { provider: 'vimeo', videoId: vimeoMatch[1] }\n }\n\n // Direct video file\n return { provider: 'direct' }\n}\n\nexport const VideoRenderer: Component<VideoRendererProps> = (props) => {\n const params = () => props.params || (props.component?.params as VideoComponentParams)\n const isExpanded = useExpanded()\n\n const videoInfo = createMemo(() => parseVideoUrl(params()?.url || ''))\n\n const embedUrl = createMemo(() => {\n const info = videoInfo()\n const p = params()\n\n if (!p?.url) return null\n\n switch (info.provider) {\n case 'youtube': {\n const ytParams = new URLSearchParams({\n autoplay: p.autoplay ? '1' : '0',\n controls: p.controls !== false ? '1' : '0',\n loop: p.loop ? '1' : '0',\n mute: p.muted ? '1' : '0',\n })\n if (p.startTime) {\n ytParams.set('start', String(p.startTime))\n }\n // Use youtube-nocookie.com for privacy\n return `https://www.youtube-nocookie.com/embed/${info.videoId}?${ytParams}`\n }\n\n case 'vimeo': {\n const vParams = new URLSearchParams({\n autoplay: p.autoplay ? '1' : '0',\n loop: p.loop ? '1' : '0',\n muted: p.muted ? '1' : '0',\n })\n return `https://player.vimeo.com/video/${info.videoId}?${vParams}`\n }\n\n default:\n return null\n }\n })\n\n const aspectClass = () => {\n switch (params()?.aspectRatio) {\n case '1:1':\n return 'aspect-square'\n case '4:3':\n return 'aspect-[4/3]'\n case '21:9':\n return 'aspect-[21/9]'\n default:\n return 'aspect-video' // 16:9\n }\n }\n\n const handleVideoError = (e: Event) => {\n const error = new Error('Video failed to load')\n console.error('Video error:', e)\n props.onError?.(error)\n }\n\n return (\n <ExpandableWrapper\n title={params()?.title || 'Video'}\n copyData={params()?.url || ''}\n copyLabel=\"Copy video URL\"\n toolbarVariant={props.toolbarVariant}\n >\n <div class={`w-full bg-white dark:bg-gray-800 rounded-lg shadow-sm border border-gray-200 dark:border-gray-700 overflow-hidden ${\n isExpanded() ? 'flex-1 min-h-0 flex flex-col' : ''\n }`}>\n {/* Title */}\n <Show when={params()?.title}>\n <div class=\"px-4 py-3 border-b border-gray-200 dark:border-gray-700\">\n <h3 class=\"text-sm font-semibold text-gray-900 dark:text-white\">{params()!.title}</h3>\n </div>\n </Show>\n\n {/* Video Container — when expanded, fill remaining space (override aspect ratio) */}\n <div class={`relative bg-black ${isExpanded() ? 'flex-1 min-h-0' : aspectClass()}`}>\n <Show\n when={embedUrl()}\n fallback={\n // Direct video file\n <video\n src={params()?.url}\n poster={params()?.poster}\n autoplay={params()?.autoplay}\n controls={params()?.controls !== false}\n loop={params()?.loop}\n muted={params()?.muted}\n playsinline\n class=\"absolute inset-0 w-full h-full object-contain\"\n onError={handleVideoError}\n >\n <track kind=\"captions\" />\n Your browser does not support the video tag.\n </video>\n }\n >\n {/* YouTube/Vimeo embed */}\n <iframe\n src={embedUrl()!}\n title={params()?.title || 'Video'}\n class=\"absolute inset-0 w-full h-full\"\n allow=\"accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share\"\n allowfullscreen\n loading=\"lazy\"\n />\n </Show>\n </div>\n\n {/* Caption */}\n <Show when={params()?.caption}>\n <div class=\"px-4 py-3 border-t border-gray-200 dark:border-gray-700 flex-shrink-0\">\n <p class=\"text-sm text-gray-600 dark:text-gray-400\">{params()!.caption}</p>\n </div>\n </Show>\n </div>\n </ExpandableWrapper>\n )\n}\n\n/**\n * Check if a URL is from a supported video provider\n */\nexport function isSupportedVideoUrl(url: string): boolean {\n const info = parseVideoUrl(url)\n return info.provider !== 'direct' || url.match(/\\.(mp4|webm|ogg|mov)$/i) !== null\n}\n\n/**\n * Get video provider from URL\n */\nexport function getVideoProvider(url: string): VideoProvider {\n return parseVideoUrl(url).provider\n}\n"],"names":["parseVideoUrl","url","youtubeMatch","match","provider","videoId","vimeoMatch","VideoRenderer","props","params","component","isExpanded","useExpanded","videoInfo","createMemo","embedUrl","info","p","ytParams","URLSearchParams","autoplay","controls","loop","mute","muted","startTime","set","String","vParams","aspectClass","aspectRatio","handleVideoError","e","error","Error","console","onError","_$createComponent","ExpandableWrapper","title","copyData","copyLabel","toolbarVariant","children","_el$","_$getNextElement","_tmpl$4","_el$8","firstChild","_el$9","_co$","_$getNextMarker","nextSibling","_el$4","_el$0","_el$1","_co$2","_$insert","Show","when","_el$2","_tmpl$","_el$3","fallback","_el$10","_tmpl$5","addEventListener","_$effect","_p$","_v$5","_v$6","poster","_v$7","_v$8","_v$9","_v$0","_$setAttribute","t","a","_$setProperty","o","i","n","undefined","_el$5","_tmpl$2","_v$","_v$2","caption","_el$6","_tmpl$3","_el$7","_v$3","_v$4","_$className","isSupportedVideoUrl","getVideoProvider"],"mappings":";;;;;;AAkDA,SAASA,cAAcC,KAAwB;AAM7C,QAAMC,eAAeD,IAAIE,MACvB,4EACF;AACA,MAAID,cAAc;AAChB,WAAO;AAAA,MAAEE,UAAU;AAAA,MAAWC,SAASH,aAAa,CAAC;AAAA,IAAA;AAAA,EACvD;AAKA,QAAMI,aAAaL,IAAIE,MAAM,mDAAmD;AAChF,MAAIG,YAAY;AACd,WAAO;AAAA,MAAEF,UAAU;AAAA,MAASC,SAASC,WAAW,CAAC;AAAA,IAAA;AAAA,EACnD;AAGA,SAAO;AAAA,IAAEF,UAAU;AAAA,EAAA;AACrB;AAEO,MAAMG,gBAAgDC,CAAAA,UAAU;AACrE,QAAMC,SAASA,MAAAA;;AAAMD,iBAAMC,YAAWD,WAAME,cAANF,mBAAiBC;AAAAA;AACvD,QAAME,aAAaC,kBAAAA,YAAAA;AAEnB,QAAMC,YAAYC,QAAAA,WAAW,MAAA;;AAAMd,2BAAcS,kBAAAA,mBAAUR,QAAO,EAAE;AAAA,GAAC;AAErE,QAAMc,WAAWD,QAAAA,WAAW,MAAM;AAChC,UAAME,OAAOH,UAAAA;AACb,UAAMI,IAAIR,OAAAA;AAEV,QAAI,EAACQ,uBAAGhB,KAAK,QAAO;AAEpB,YAAQe,KAAKZ,UAAAA;AAAAA,MACX,KAAK,WAAW;AACd,cAAMc,WAAW,IAAIC,gBAAgB;AAAA,UACnCC,UAAUH,EAAEG,WAAW,MAAM;AAAA,UAC7BC,UAAUJ,EAAEI,aAAa,QAAQ,MAAM;AAAA,UACvCC,MAAML,EAAEK,OAAO,MAAM;AAAA,UACrBC,MAAMN,EAAEO,QAAQ,MAAM;AAAA,QAAA,CACvB;AACD,YAAIP,EAAEQ,WAAW;AACfP,mBAASQ,IAAI,SAASC,OAAOV,EAAEQ,SAAS,CAAC;AAAA,QAC3C;AAEA,eAAO,0CAA0CT,KAAKX,OAAO,IAAIa,QAAQ;AAAA,MAC3E;AAAA,MAEA,KAAK,SAAS;AACZ,cAAMU,UAAU,IAAIT,gBAAgB;AAAA,UAClCC,UAAUH,EAAEG,WAAW,MAAM;AAAA,UAC7BE,MAAML,EAAEK,OAAO,MAAM;AAAA,UACrBE,OAAOP,EAAEO,QAAQ,MAAM;AAAA,QAAA,CACxB;AACD,eAAO,kCAAkCR,KAAKX,OAAO,IAAIuB,OAAO;AAAA,MAClE;AAAA,MAEA;AACE,eAAO;AAAA,IAAA;AAAA,EAEb,CAAC;AAED,QAAMC,cAAcA,MAAM;;AACxB,aAAQpB,YAAAA,MAAAA,mBAAUqB,aAAAA;AAAAA,MAChB,KAAK;AACH,eAAO;AAAA,MACT,KAAK;AACH,eAAO;AAAA,MACT,KAAK;AACH,eAAO;AAAA,MACT;AACE,eAAO;AAAA,IAAA;AAAA,EAEb;AAEA,QAAMC,mBAAmBA,CAACC,MAAa;;AACrC,UAAMC,QAAQ,IAAIC,MAAM,sBAAsB;AAC9CC,YAAQF,MAAM,gBAAgBD,CAAC;AAC/BxB,gBAAM4B,YAAN5B,+BAAgByB;AAAAA,EAClB;AAEA,SAAAI,IAAAA,gBACGC,kBAAAA,mBAAiB;AAAA,IAAA,IAChBC,QAAK;;AAAA,eAAE9B,YAAAA,MAAAA,mBAAU8B,UAAS;AAAA,IAAO;AAAA,IAAA,IACjCC,WAAQ;;AAAA,eAAE/B,YAAAA,MAAAA,mBAAUR,QAAO;AAAA,IAAE;AAAA,IAC7BwC,WAAS;AAAA,IAAA,IACTC,iBAAc;AAAA,aAAElC,MAAMkC;AAAAA,IAAc;AAAA,IAAA,IAAAC,WAAA;AAAA,UAAAC,OAAAC,IAAAA,eAAAC,OAAA,GAAAC,QAAAH,KAAAI,YAAA,CAAAC,OAAAC,IAAA,IAAAC,IAAAA,cAAAJ,MAAAK,WAAA,GAAAC,QAAAJ,MAAAG,aAAAE,QAAAD,MAAAD,aAAA,CAAAG,OAAAC,KAAA,IAAAL,kBAAAG,MAAAF,WAAA;AAAAK,iBAAAb,MAAAP,IAAAA,gBAMnCqB,cAAI;AAAA,QAAA,IAACC,OAAI;;AAAA,kBAAElD,kBAAAA,mBAAU8B;AAAAA,QAAK;AAAA,QAAA,IAAAI,WAAA;AAAA,cAAAiB,QAAAf,IAAAA,eAAAgB,MAAA,GAAAC,QAAAF,MAAAZ;AAAAS,cAAAA,OAAAK,OAAA,MAE0CrD,OAAAA,EAAU8B,KAAK;AAAA,iBAAAqB;AAAAA,QAAA;AAAA,MAAA,CAAA,GAAAX,OAAAC,IAAA;AAAAO,iBAAAJ,OAAAhB,IAAAA,gBAMjFqB,cAAI;AAAA,QAAA,IACHC,OAAI;AAAA,iBAAE5C,SAAAA;AAAAA,QAAU;AAAA,QAAA,IAChBgD,WAAQ;AAAA;AAAA;AAAA,aACN,MAAA;AAAA,kBAAAC,SAAAnB,IAAAA,eAAAoB,OAAA;AAAAD,qBAAAE,iBAAA,SAUWnC,gBAAgB;AAAAoC,kBAAAA,OAAAC,CAAAA,QAAA;;AAAA,oBAAAC,QARpB5D,kBAAAA,mBAAUR,KAAGqE,QACV7D,YAAAA,MAAAA,mBAAU8D,QAAMC,QACd/D,kBAAAA,mBAAUW,UAAQqD,SAClBhE,YAAAA,MAAAA,mBAAUY,cAAa,OAAKqD,QAChCjE,kBAAAA,mBAAUa,MAAIqD,QACblE,YAAAA,MAAAA,mBAAUe;AAAK6C,yBAAAD,IAAApC,KAAA4C,IAAAA,aAAAZ,QAAA,OAAAI,IAAApC,IAAAqC,IAAA;AAAAC,yBAAAF,IAAAS,KAAAD,IAAAA,aAAAZ,QAAA,UAAAI,IAAAS,IAAAP,IAAA;AAAAE,yBAAAJ,IAAAU,KAAAC,IAAAA,YAAAf,QAAA,YAAAI,IAAAU,IAAAN,IAAA;AAAAC,yBAAAL,IAAAY,KAAAD,IAAAA,YAAAf,QAAA,YAAAI,IAAAY,IAAAP,IAAA;AAAAC,yBAAAN,IAAAa,KAAAF,IAAAA,YAAAf,QAAA,QAAAI,IAAAa,IAAAP,IAAA;AAAAC,yBAAAP,IAAAc,KAAAH,IAAAA,YAAAf,QAAA,SAAAI,IAAAc,IAAAP,IAAA;AAAA,uBAAAP;AAAAA,cAAA,GAAA;AAAA,gBAAApC,GAAAmD;AAAAA,gBAAAN,GAAAM;AAAAA,gBAAAL,GAAAK;AAAAA,gBAAAH,GAAAG;AAAAA,gBAAAF,GAAAE;AAAAA,gBAAAD,GAAAC;AAAAA,cAAAA,CAAA;AAAA,qBAAAnB;AAAAA,YAAA,GAAA;AAAA;AAAA,QAAA;AAAA,QAAA,IAAArB,WAAA;AAAA,cAAAyC,QAAAvC,IAAAA,eAAAwC,OAAA;AAAAlB,cAAAA,OAAAC,CAAAA,QAAA;;AAAA,gBAAAkB,MAYnBvE,SAAAA,GAAWwE,SACT9E,YAAAA,MAAAA,mBAAU8B,UAAS;AAAO+C,oBAAAlB,IAAApC,KAAA4C,IAAAA,aAAAQ,OAAA,OAAAhB,IAAApC,IAAAsD,GAAA;AAAAC,qBAAAnB,IAAAS,KAAAD,IAAAA,aAAAQ,OAAA,SAAAhB,IAAAS,IAAAU,IAAA;AAAA,mBAAAnB;AAAAA,UAAA,GAAA;AAAA,YAAApC,GAAAmD;AAAAA,YAAAN,GAAAM;AAAAA,UAAAA,CAAA;AAAA,iBAAAC;AAAAA,QAAA;AAAA,MAAA,CAAA,CAAA;AAAA3B,iBAAAb,MAAAP,IAAAA,gBAUtCqB,cAAI;AAAA,QAAA,IAACC,OAAI;;AAAA,kBAAElD,kBAAAA,mBAAU+E;AAAAA,QAAO;AAAA,QAAA,IAAA7C,WAAA;AAAA,cAAA8C,QAAA5C,IAAAA,eAAA6C,OAAA,GAAAC,QAAAF,MAAAzC;AAAAS,cAAAA,OAAAkC,OAAA,MAE4BlF,OAAAA,EAAU+E,OAAO;AAAA,iBAAAC;AAAAA,QAAA;AAAA,MAAA,CAAA,GAAAlC,OAAAC,KAAA;AAAAW,UAAAA,OAAAC,CAAAA,QAAA;AAAA,YAAAwB,OA/ChE,qHACVjF,WAAAA,IAAe,iCAAiC,EAAE,IAClDkF,OASY,qBAAqBlF,WAAAA,IAAe,mBAAmBkB,aAAa;AAAE+D,iBAAAxB,IAAApC,KAAA8D,IAAAA,UAAAlD,MAAAwB,IAAApC,IAAA4D,IAAA;AAAAC,iBAAAzB,IAAAS,KAAAiB,IAAAA,UAAAzC,OAAAe,IAAAS,IAAAgB,IAAA;AAAA,eAAAzB;AAAAA,MAAA,GAAA;AAAA,QAAApC,GAAAmD;AAAAA,QAAAN,GAAAM;AAAAA,MAAAA,CAAA;AAAA,aAAAvC;AAAAA,IAAA;AAAA,EAAA,CAAA;AA0CxF;AAKO,SAASmD,oBAAoB9F,KAAsB;AACxD,QAAMe,OAAOhB,cAAcC,GAAG;AAC9B,SAAOe,KAAKZ,aAAa,YAAYH,IAAIE,MAAM,wBAAwB,MAAM;AAC/E;AAKO,SAAS6F,iBAAiB/F,KAA4B;AAC3D,SAAOD,cAAcC,GAAG,EAAEG;AAC5B;;;;"}
|
|
1
|
+
{"version":3,"file":"VideoRenderer.cjs","sources":["../../src/components/VideoRenderer.tsx"],"sourcesContent":["/**\n * VideoRenderer - Video embed component\n * Sprint 5: Media Components\n *\n * Supports YouTube, Vimeo, and direct video files\n */\n\nimport { Component, createMemo, Show } from 'solid-js'\nimport type { UIComponent, VideoComponentParams } from '../types'\nimport { ExpandableWrapper, useExpanded } from './ExpandableWrapper'\nimport { useMCPUIStrings } from '../context/MCPUIStringsContext'\n\nexport interface VideoRendererProps {\n /**\n * UIComponent containing video params\n */\n component?: UIComponent\n\n /**\n * Direct video params (alternative to component)\n */\n params?: VideoComponentParams\n\n /**\n * Error callback\n */\n onError?: (error: Error) => void\n\n /**\n * Forwarded to the underlying `<ExpandableWrapper>` (v6.3.1).\n * @see ExpandableWrapperProps.toolbarVariant\n */\n toolbarVariant?: 'hover' | 'always-visible'\n}\n\n/**\n * Video provider type\n */\ntype VideoProvider = 'youtube' | 'vimeo' | 'direct'\n\n/**\n * Parsed video info\n */\ninterface VideoInfo {\n provider: VideoProvider\n videoId?: string\n}\n\n/**\n * Extract video ID and provider from URL\n */\nfunction parseVideoUrl(url: string): VideoInfo {\n // YouTube patterns:\n // - youtube.com/watch?v=VIDEO_ID\n // - youtube.com/embed/VIDEO_ID\n // - youtube.com/v/VIDEO_ID\n // - youtu.be/VIDEO_ID\n const youtubeMatch = url.match(\n /(?:youtube\\.com\\/(?:watch\\?v=|embed\\/|v\\/)|youtu\\.be\\/)([a-zA-Z0-9_-]{11})/\n )\n if (youtubeMatch) {\n return { provider: 'youtube', videoId: youtubeMatch[1] }\n }\n\n // Vimeo patterns:\n // - vimeo.com/VIDEO_ID\n // - player.vimeo.com/video/VIDEO_ID\n const vimeoMatch = url.match(/(?:vimeo\\.com\\/|player\\.vimeo\\.com\\/video\\/)(\\d+)/)\n if (vimeoMatch) {\n return { provider: 'vimeo', videoId: vimeoMatch[1] }\n }\n\n // Direct video file\n return { provider: 'direct' }\n}\n\nexport const VideoRenderer: Component<VideoRendererProps> = (props) => {\n const strings = useMCPUIStrings()\n const params = () => props.params || (props.component?.params as VideoComponentParams)\n const isExpanded = useExpanded()\n\n const videoInfo = createMemo(() => parseVideoUrl(params()?.url || ''))\n\n const embedUrl = createMemo(() => {\n const info = videoInfo()\n const p = params()\n\n if (!p?.url) return null\n\n switch (info.provider) {\n case 'youtube': {\n const ytParams = new URLSearchParams({\n autoplay: p.autoplay ? '1' : '0',\n controls: p.controls !== false ? '1' : '0',\n loop: p.loop ? '1' : '0',\n mute: p.muted ? '1' : '0',\n })\n if (p.startTime) {\n ytParams.set('start', String(p.startTime))\n }\n // Use youtube-nocookie.com for privacy\n return `https://www.youtube-nocookie.com/embed/${info.videoId}?${ytParams}`\n }\n\n case 'vimeo': {\n const vParams = new URLSearchParams({\n autoplay: p.autoplay ? '1' : '0',\n loop: p.loop ? '1' : '0',\n muted: p.muted ? '1' : '0',\n })\n return `https://player.vimeo.com/video/${info.videoId}?${vParams}`\n }\n\n default:\n return null\n }\n })\n\n const aspectClass = () => {\n switch (params()?.aspectRatio) {\n case '1:1':\n return 'aspect-square'\n case '4:3':\n return 'aspect-[4/3]'\n case '21:9':\n return 'aspect-[21/9]'\n default:\n return 'aspect-video' // 16:9\n }\n }\n\n const handleVideoError = (e: Event) => {\n const error = new Error('Video failed to load')\n console.error('Video error:', e)\n props.onError?.(error)\n }\n\n return (\n <ExpandableWrapper\n title={params()?.title || strings.videoTitle}\n copyData={params()?.url || ''}\n copyLabel={strings.videoCopy}\n toolbarVariant={props.toolbarVariant}\n >\n <div class={`w-full bg-white dark:bg-gray-800 rounded-lg shadow-sm border border-gray-200 dark:border-gray-700 overflow-hidden ${\n isExpanded() ? 'flex-1 min-h-0 flex flex-col' : ''\n }`}>\n {/* Title */}\n <Show when={params()?.title}>\n <div class=\"px-4 py-3 border-b border-gray-200 dark:border-gray-700\">\n <h3 class=\"text-sm font-semibold text-gray-900 dark:text-white\">{params()!.title}</h3>\n </div>\n </Show>\n\n {/* Video Container — when expanded, fill remaining space (override aspect ratio) */}\n <div class={`relative bg-black ${isExpanded() ? 'flex-1 min-h-0' : aspectClass()}`}>\n <Show\n when={embedUrl()}\n fallback={\n // Direct video file\n <video\n src={params()?.url}\n poster={params()?.poster}\n autoplay={params()?.autoplay}\n controls={params()?.controls !== false}\n loop={params()?.loop}\n muted={params()?.muted}\n playsinline\n class=\"absolute inset-0 w-full h-full object-contain\"\n onError={handleVideoError}\n >\n <track kind=\"captions\" />\n {strings.videoUnsupported}\n </video>\n }\n >\n {/* YouTube/Vimeo embed */}\n <iframe\n src={embedUrl()!}\n title={params()?.title || strings.videoTitle}\n class=\"absolute inset-0 w-full h-full\"\n allow=\"accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share\"\n allowfullscreen\n loading=\"lazy\"\n />\n </Show>\n </div>\n\n {/* Caption */}\n <Show when={params()?.caption}>\n <div class=\"px-4 py-3 border-t border-gray-200 dark:border-gray-700 flex-shrink-0\">\n <p class=\"text-sm text-gray-600 dark:text-gray-400\">{params()!.caption}</p>\n </div>\n </Show>\n </div>\n </ExpandableWrapper>\n )\n}\n\n/**\n * Check if a URL is from a supported video provider\n */\nexport function isSupportedVideoUrl(url: string): boolean {\n const info = parseVideoUrl(url)\n return info.provider !== 'direct' || url.match(/\\.(mp4|webm|ogg|mov)$/i) !== null\n}\n\n/**\n * Get video provider from URL\n */\nexport function getVideoProvider(url: string): VideoProvider {\n return parseVideoUrl(url).provider\n}\n"],"names":["parseVideoUrl","url","youtubeMatch","match","provider","videoId","vimeoMatch","VideoRenderer","props","strings","useMCPUIStrings","params","component","isExpanded","useExpanded","videoInfo","createMemo","embedUrl","info","p","ytParams","URLSearchParams","autoplay","controls","loop","mute","muted","startTime","set","String","vParams","aspectClass","aspectRatio","handleVideoError","e","error","Error","console","onError","_$createComponent","ExpandableWrapper","title","videoTitle","copyData","copyLabel","videoCopy","toolbarVariant","children","_el$","_$getNextElement","_tmpl$4","_el$8","firstChild","_el$9","_co$","_$getNextMarker","nextSibling","_el$4","_el$0","_el$1","_co$2","_$insert","Show","when","_el$2","_tmpl$","_el$3","fallback","_el$10","_tmpl$5","_el$11","_el$12","_el$13","_co$3","addEventListener","videoUnsupported","_$effect","_p$","_v$5","_v$6","poster","_v$7","_v$8","_v$9","_v$0","_$setAttribute","t","a","_$setProperty","o","i","n","undefined","_el$5","_tmpl$2","_v$","_v$2","caption","_el$6","_tmpl$3","_el$7","_v$3","_v$4","_$className","isSupportedVideoUrl","getVideoProvider"],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"VideoRenderer.d.ts","sourceRoot":"","sources":["../../src/components/VideoRenderer.tsx"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,EAAE,SAAS,EAAoB,MAAM,UAAU,CAAA;AACtD,OAAO,KAAK,EAAE,WAAW,EAAE,oBAAoB,EAAE,MAAM,UAAU,CAAA;
|
|
1
|
+
{"version":3,"file":"VideoRenderer.d.ts","sourceRoot":"","sources":["../../src/components/VideoRenderer.tsx"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,EAAE,SAAS,EAAoB,MAAM,UAAU,CAAA;AACtD,OAAO,KAAK,EAAE,WAAW,EAAE,oBAAoB,EAAE,MAAM,UAAU,CAAA;AAIjE,MAAM,WAAW,kBAAkB;IACjC;;OAEG;IACH,SAAS,CAAC,EAAE,WAAW,CAAA;IAEvB;;OAEG;IACH,MAAM,CAAC,EAAE,oBAAoB,CAAA;IAE7B;;OAEG;IACH,OAAO,CAAC,EAAE,CAAC,KAAK,EAAE,KAAK,KAAK,IAAI,CAAA;IAEhC;;;OAGG;IACH,cAAc,CAAC,EAAE,OAAO,GAAG,gBAAgB,CAAA;CAC5C;AAED;;GAEG;AACH,KAAK,aAAa,GAAG,SAAS,GAAG,OAAO,GAAG,QAAQ,CAAA;AAsCnD,eAAO,MAAM,aAAa,EAAE,SAAS,CAAC,kBAAkB,CAyHvD,CAAA;AAED;;GAEG;AACH,wBAAgB,mBAAmB,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAGxD;AAED;;GAEG;AACH,wBAAgB,gBAAgB,CAAC,GAAG,EAAE,MAAM,GAAG,aAAa,CAE3D"}
|
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
import { createComponent, getNextElement, getNextMarker, insert, effect, setAttribute, setProperty, className, template } from "solid-js/web";
|
|
2
2
|
import { createMemo, Show } from "solid-js";
|
|
3
3
|
import { useExpanded, ExpandableWrapper } from "./ExpandableWrapper.js";
|
|
4
|
-
|
|
4
|
+
import { useMCPUIStrings } from "../context/MCPUIStringsContext.js";
|
|
5
|
+
var _tmpl$ = /* @__PURE__ */ template(`<div class="px-4 py-3 border-b border-gray-200 dark:border-gray-700"><h3 class="text-sm font-semibold text-gray-900 dark:text-white">`), _tmpl$2 = /* @__PURE__ */ template(`<iframe class="absolute inset-0 w-full h-full"allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share"allowfullscreen loading=lazy>`, true, false, false), _tmpl$3 = /* @__PURE__ */ template(`<div class="px-4 py-3 border-t border-gray-200 dark:border-gray-700 flex-shrink-0"><p class="text-sm text-gray-600 dark:text-gray-400">`), _tmpl$4 = /* @__PURE__ */ template(`<div><!$><!/><div></div><!$><!/>`), _tmpl$5 = /* @__PURE__ */ template(`<video playsinline class="absolute inset-0 w-full h-full object-contain"><track kind=captions><!$><!/>`);
|
|
5
6
|
function parseVideoUrl(url) {
|
|
6
7
|
const youtubeMatch = url.match(/(?:youtube\.com\/(?:watch\?v=|embed\/|v\/)|youtu\.be\/)([a-zA-Z0-9_-]{11})/);
|
|
7
8
|
if (youtubeMatch) {
|
|
@@ -22,6 +23,7 @@ function parseVideoUrl(url) {
|
|
|
22
23
|
};
|
|
23
24
|
}
|
|
24
25
|
const VideoRenderer = (props) => {
|
|
26
|
+
const strings = useMCPUIStrings();
|
|
25
27
|
const params = () => {
|
|
26
28
|
var _a;
|
|
27
29
|
return props.params || ((_a = props.component) == null ? void 0 : _a.params);
|
|
@@ -82,13 +84,15 @@ const VideoRenderer = (props) => {
|
|
|
82
84
|
return createComponent(ExpandableWrapper, {
|
|
83
85
|
get title() {
|
|
84
86
|
var _a;
|
|
85
|
-
return ((_a = params()) == null ? void 0 : _a.title) ||
|
|
87
|
+
return ((_a = params()) == null ? void 0 : _a.title) || strings.videoTitle;
|
|
86
88
|
},
|
|
87
89
|
get copyData() {
|
|
88
90
|
var _a;
|
|
89
91
|
return ((_a = params()) == null ? void 0 : _a.url) || "";
|
|
90
92
|
},
|
|
91
|
-
copyLabel
|
|
93
|
+
get copyLabel() {
|
|
94
|
+
return strings.videoCopy;
|
|
95
|
+
},
|
|
92
96
|
get toolbarVariant() {
|
|
93
97
|
return props.toolbarVariant;
|
|
94
98
|
},
|
|
@@ -113,8 +117,9 @@ const VideoRenderer = (props) => {
|
|
|
113
117
|
return (
|
|
114
118
|
// Direct video file
|
|
115
119
|
(() => {
|
|
116
|
-
var _el$10 = getNextElement(_tmpl$5);
|
|
120
|
+
var _el$10 = getNextElement(_tmpl$5), _el$11 = _el$10.firstChild, _el$12 = _el$11.nextSibling, [_el$13, _co$3] = getNextMarker(_el$12.nextSibling);
|
|
117
121
|
_el$10.addEventListener("error", handleVideoError);
|
|
122
|
+
insert(_el$10, () => strings.videoUnsupported, _el$13, _co$3);
|
|
118
123
|
effect((_p$) => {
|
|
119
124
|
var _a, _b, _c, _d, _e, _f;
|
|
120
125
|
var _v$5 = (_a = params()) == null ? void 0 : _a.url, _v$6 = (_b = params()) == null ? void 0 : _b.poster, _v$7 = (_c = params()) == null ? void 0 : _c.autoplay, _v$8 = ((_d = params()) == null ? void 0 : _d.controls) !== false, _v$9 = (_e = params()) == null ? void 0 : _e.loop, _v$0 = (_f = params()) == null ? void 0 : _f.muted;
|
|
@@ -141,7 +146,7 @@ const VideoRenderer = (props) => {
|
|
|
141
146
|
var _el$5 = getNextElement(_tmpl$2);
|
|
142
147
|
effect((_p$) => {
|
|
143
148
|
var _a;
|
|
144
|
-
var _v$ = embedUrl(), _v$2 = ((_a = params()) == null ? void 0 : _a.title) ||
|
|
149
|
+
var _v$ = embedUrl(), _v$2 = ((_a = params()) == null ? void 0 : _a.title) || strings.videoTitle;
|
|
145
150
|
_v$ !== _p$.e && setAttribute(_el$5, "src", _p$.e = _v$);
|
|
146
151
|
_v$2 !== _p$.t && setAttribute(_el$5, "title", _p$.t = _v$2);
|
|
147
152
|
return _p$;
|