@seed-ship/mcp-ui-solid 2.0.0 → 2.1.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/README.md +50 -1
- package/dist/components/AutocompleteDropdown.cjs +201 -0
- package/dist/components/AutocompleteDropdown.cjs.map +1 -0
- package/dist/components/AutocompleteDropdown.d.ts +71 -0
- package/dist/components/AutocompleteDropdown.d.ts.map +1 -0
- package/dist/components/AutocompleteDropdown.js +201 -0
- package/dist/components/AutocompleteDropdown.js.map +1 -0
- package/dist/components/AutocompleteFormField.cjs +289 -0
- package/dist/components/AutocompleteFormField.cjs.map +1 -0
- package/dist/components/AutocompleteFormField.d.ts +52 -0
- package/dist/components/AutocompleteFormField.d.ts.map +1 -0
- package/dist/components/AutocompleteFormField.js +289 -0
- package/dist/components/AutocompleteFormField.js.map +1 -0
- package/dist/components/DraggableGridItem.cjs +133 -0
- package/dist/components/DraggableGridItem.cjs.map +1 -0
- package/dist/components/DraggableGridItem.d.ts +95 -0
- package/dist/components/DraggableGridItem.d.ts.map +1 -0
- package/dist/components/DraggableGridItem.js +133 -0
- package/dist/components/DraggableGridItem.js.map +1 -0
- package/dist/components/EditableUIResourceRenderer.cjs +203 -0
- package/dist/components/EditableUIResourceRenderer.cjs.map +1 -0
- package/dist/components/EditableUIResourceRenderer.d.ts +43 -0
- package/dist/components/EditableUIResourceRenderer.d.ts.map +1 -0
- package/dist/components/EditableUIResourceRenderer.js +203 -0
- package/dist/components/EditableUIResourceRenderer.js.map +1 -0
- package/dist/components/GhostText.cjs +105 -0
- package/dist/components/GhostText.cjs.map +1 -0
- package/dist/components/GhostText.d.ts +113 -0
- package/dist/components/GhostText.d.ts.map +1 -0
- package/dist/components/GhostText.js +105 -0
- package/dist/components/GhostText.js.map +1 -0
- package/dist/components/ResizeHandle.cjs +173 -0
- package/dist/components/ResizeHandle.cjs.map +1 -0
- package/dist/components/ResizeHandle.d.ts +50 -0
- package/dist/components/ResizeHandle.d.ts.map +1 -0
- package/dist/components/ResizeHandle.js +173 -0
- package/dist/components/ResizeHandle.js.map +1 -0
- package/dist/context/AutocompleteContext.cjs +158 -0
- package/dist/context/AutocompleteContext.cjs.map +1 -0
- package/dist/context/AutocompleteContext.d.ts +77 -0
- package/dist/context/AutocompleteContext.d.ts.map +1 -0
- package/dist/context/AutocompleteContext.js +158 -0
- package/dist/context/AutocompleteContext.js.map +1 -0
- package/dist/hooks/index.d.ts +6 -0
- package/dist/hooks/index.d.ts.map +1 -1
- package/dist/hooks/useAutocomplete.cjs +234 -0
- package/dist/hooks/useAutocomplete.cjs.map +1 -0
- package/dist/hooks/useAutocomplete.d.ts +119 -0
- package/dist/hooks/useAutocomplete.d.ts.map +1 -0
- package/dist/hooks/useAutocomplete.js +234 -0
- package/dist/hooks/useAutocomplete.js.map +1 -0
- package/dist/hooks/useDragDrop.cjs +170 -0
- package/dist/hooks/useDragDrop.cjs.map +1 -0
- package/dist/hooks/useDragDrop.d.ts +100 -0
- package/dist/hooks/useDragDrop.d.ts.map +1 -0
- package/dist/hooks/useDragDrop.js +170 -0
- package/dist/hooks/useDragDrop.js.map +1 -0
- package/dist/hooks/useResize.cjs +209 -0
- package/dist/hooks/useResize.cjs.map +1 -0
- package/dist/hooks/useResize.d.ts +87 -0
- package/dist/hooks/useResize.d.ts.map +1 -0
- package/dist/hooks/useResize.js +209 -0
- package/dist/hooks/useResize.js.map +1 -0
- package/dist/hooks.cjs +6 -0
- package/dist/hooks.cjs.map +1 -1
- package/dist/hooks.d.cts +6 -0
- package/dist/hooks.d.ts +6 -0
- package/dist/hooks.js +6 -0
- package/dist/hooks.js.map +1 -1
- package/dist/index.cjs +29 -0
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +18 -3
- package/dist/index.d.ts +18 -3
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +29 -0
- package/dist/index.js.map +1 -1
- package/dist/plugins/duckdb.cjs +192 -0
- package/dist/plugins/duckdb.cjs.map +1 -0
- package/dist/plugins/duckdb.d.ts +20 -0
- package/dist/plugins/duckdb.d.ts.map +1 -0
- package/dist/plugins/duckdb.js +170 -0
- package/dist/plugins/duckdb.js.map +1 -0
- package/dist/plugins/groq.cjs +97 -0
- package/dist/plugins/groq.cjs.map +1 -0
- package/dist/plugins/groq.d.ts +13 -0
- package/dist/plugins/groq.d.ts.map +1 -0
- package/dist/plugins/groq.js +97 -0
- package/dist/plugins/groq.js.map +1 -0
- package/dist/plugins/index.d.ts +10 -0
- package/dist/plugins/index.d.ts.map +1 -0
- package/dist/plugins/rest.cjs +92 -0
- package/dist/plugins/rest.cjs.map +1 -0
- package/dist/plugins/rest.d.ts +13 -0
- package/dist/plugins/rest.d.ts.map +1 -0
- package/dist/plugins/rest.js +92 -0
- package/dist/plugins/rest.js.map +1 -0
- package/dist/plugins/supabase.cjs +79 -0
- package/dist/plugins/supabase.cjs.map +1 -0
- package/dist/plugins/supabase.d.ts +13 -0
- package/dist/plugins/supabase.d.ts.map +1 -0
- package/dist/plugins/supabase.js +79 -0
- package/dist/plugins/supabase.js.map +1 -0
- package/dist/services/validation.cjs +40 -1
- package/dist/services/validation.cjs.map +1 -1
- package/dist/services/validation.d.ts.map +1 -1
- package/dist/services/validation.js +40 -1
- package/dist/services/validation.js.map +1 -1
- package/dist/types/index.d.ts +430 -0
- package/dist/types/index.d.ts.map +1 -1
- package/dist/types.d.cts +430 -0
- package/dist/types.d.ts +430 -0
- package/package.json +16 -1
- package/src/components/AutocompleteDropdown.tsx +329 -0
- package/src/components/AutocompleteFormField.tsx +288 -0
- package/src/components/DraggableGridItem.tsx +274 -0
- package/src/components/EditableUIResourceRenderer.tsx +273 -0
- package/src/components/GhostText.tsx +262 -0
- package/src/components/ResizeHandle.tsx +262 -0
- package/src/context/AutocompleteContext.tsx +317 -0
- package/src/hooks/index.ts +23 -0
- package/src/hooks/useAutocomplete.test.ts +334 -0
- package/src/hooks/useAutocomplete.ts +466 -0
- package/src/hooks/useDragDrop.test.ts +355 -0
- package/src/hooks/useDragDrop.ts +379 -0
- package/src/hooks/useResize.test.ts +313 -0
- package/src/hooks/useResize.ts +372 -0
- package/src/index.ts +71 -0
- package/src/plugins/duckdb.ts +269 -0
- package/src/plugins/groq.ts +137 -0
- package/src/plugins/index.ts +14 -0
- package/src/plugins/rest.ts +147 -0
- package/src/plugins/supabase.ts +120 -0
- package/src/services/validation.ts +46 -0
- package/src/styles/autocomplete.css +356 -0
- package/src/styles/drag-drop.css +297 -0
- package/src/styles/index.css +7 -0
- package/src/types/index.ts +529 -0
- package/src/vite-env.d.ts +18 -0
- package/tsconfig.tsbuildinfo +1 -1
- package/vite.config.ts +2 -0
package/README.md
CHANGED
|
@@ -5,6 +5,55 @@ SolidJS components for rendering MCP-generated UI resources. Part of the MCP UI
|
|
|
5
5
|
[](https://www.npmjs.com/package/@seed-ship/mcp-ui-solid)
|
|
6
6
|
[](https://opensource.org/licenses/MIT)
|
|
7
7
|
|
|
8
|
+
## What's New in v2.0.0
|
|
9
|
+
|
|
10
|
+
### Highlights
|
|
11
|
+
|
|
12
|
+
- **Configurable Iframe Whitelist** - Control iframe security with `IframePolicy`: `strict`, `extend`, or `allow-all`
|
|
13
|
+
- **60+ Whitelisted Domains** - Expanded default whitelist for business use cases
|
|
14
|
+
- **New Component Types** - Forms, Modals, Action Groups, Image Gallery, Video, Code, Map
|
|
15
|
+
- **Table Virtualization** - Handle 10,000+ rows with smooth scrolling
|
|
16
|
+
- **Map Clustering** - Auto-cluster markers for large datasets
|
|
17
|
+
- **Native Chart.js Support** - Optional direct Chart.js rendering (no iframe)
|
|
18
|
+
|
|
19
|
+
### Configurable Iframe Security
|
|
20
|
+
|
|
21
|
+
```typescript
|
|
22
|
+
import { validateComponent, DEFAULT_IFRAME_DOMAINS } from '@seed-ship/mcp-ui-solid'
|
|
23
|
+
|
|
24
|
+
// Default: strict whitelist
|
|
25
|
+
validateComponent(component)
|
|
26
|
+
|
|
27
|
+
// Extend whitelist with custom domains
|
|
28
|
+
validateComponent(component, {
|
|
29
|
+
iframePolicy: 'extend',
|
|
30
|
+
customIframeDomains: ['my-trusted-site.com']
|
|
31
|
+
})
|
|
32
|
+
|
|
33
|
+
// Disable whitelist (use with caution)
|
|
34
|
+
validateComponent(component, { iframePolicy: 'allow-all' })
|
|
35
|
+
|
|
36
|
+
// View default whitelist
|
|
37
|
+
console.log(DEFAULT_IFRAME_DOMAINS)
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
### Whitelisted Domains (v2.0.0)
|
|
41
|
+
|
|
42
|
+
| Category | Domains |
|
|
43
|
+
|----------|---------|
|
|
44
|
+
| **Video** | youtube.com, vimeo.com, loom.com, cloudflarestream.com, streamable.com |
|
|
45
|
+
| **Diagrams** | mermaid.live, excalidraw.com, lucidchart.com, figma.com, miro.com |
|
|
46
|
+
| **Code** | github.com, gitlab.com, codepen.io, codesandbox.io, stackblitz.com, replit.com |
|
|
47
|
+
| **Google** | docs, sheets, slides, drive, maps, datastudio, lookerstudio |
|
|
48
|
+
| **Business** | notion.so, airtable.com, calendly.com, typeform.com, cal.com |
|
|
49
|
+
| **Analytics** | tableau.com, powerbi.com, observablehq.com |
|
|
50
|
+
| **Design** | canva.com, figma.com |
|
|
51
|
+
| **Maps** | maps.google.com, openstreetmap.org |
|
|
52
|
+
| **Previews** | vercel.app, netlify.app |
|
|
53
|
+
| **E-commerce** | amazon.com, amazon.fr, amazon.de, amazon.co.uk, etc. |
|
|
54
|
+
|
|
55
|
+
---
|
|
56
|
+
|
|
8
57
|
## Overview
|
|
9
58
|
|
|
10
59
|
`@seed-ship/mcp-ui-solid` provides a complete rendering solution for MCP (Model Context Protocol) generated UIs. It enables AI/LLM systems to generate structured, interactive dashboards that are rendered with SolidJS.
|
|
@@ -389,7 +438,7 @@ function CustomStreaming() {
|
|
|
389
438
|
|
|
390
439
|
This package follows [Semantic Versioning](https://semver.org/). See [CHANGELOG.md](./CHANGELOG.md) for release notes.
|
|
391
440
|
|
|
392
|
-
**Current Version:**
|
|
441
|
+
**Current Version:** 2.0.1
|
|
393
442
|
|
|
394
443
|
## License
|
|
395
444
|
|
|
@@ -0,0 +1,201 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperties(exports, { __esModule: { value: true }, [Symbol.toStringTag]: { value: "Module" } });
|
|
3
|
+
const web = require("solid-js/web");
|
|
4
|
+
const solidJs = require("solid-js");
|
|
5
|
+
var _tmpl$ = /* @__PURE__ */ web.template(`<strong class=mcp-autocomplete-highlight>`), _tmpl$2 = /* @__PURE__ */ web.template(`<span class=mcp-autocomplete-option-icon>`), _tmpl$3 = /* @__PURE__ */ web.template(`<span class=mcp-autocomplete-option-description>`), _tmpl$4 = /* @__PURE__ */ web.template(`<div class=mcp-autocomplete-option-content><!$><!/><div class=mcp-autocomplete-option-text><span class=mcp-autocomplete-option-label></span><!$><!/>`), _tmpl$5 = /* @__PURE__ */ web.template(`<div class=mcp-autocomplete-loading style="padding:12px 16px;color:#6b7280;font-size:0.875rem;display:flex;align-items:center;gap:8px"><span style="display:inline-block;width:14px;height:14px;border:2px solid #e5e7eb;border-top-color:#3b82f6;border-radius:50%;animation:mcp-spin 0.6s linear infinite"></span><!$><!/>`), _tmpl$6 = /* @__PURE__ */ web.template(`<div class=mcp-autocomplete-empty style="padding:12px 16px;color:#9ca3af;font-size:0.875rem;text-align:center">`), _tmpl$7 = /* @__PURE__ */ web.template(`<ul class=mcp-autocomplete-options style="margin:0;padding:4px 0;list-style:none">`), _tmpl$8 = /* @__PURE__ */ web.template(`<div class=mcp-autocomplete-footer style="padding:6px 12px;border-top:1px solid #e5e7eb;background-color:#f9fafb;font-size:0.75rem;color:#6b7280"><kbd style="background-color:#e5e7eb;padding:1px 4px;border-radius:2px;font-family:inherit;font-size:0.7rem">↑</kbd> <kbd style="background-color:#e5e7eb;padding:1px 4px;border-radius:2px;font-family:inherit;font-size:0.7rem">↓</kbd> to navigate, <kbd style="background-color:#e5e7eb;padding:1px 4px;border-radius:2px;font-family:inherit;font-size:0.7rem">Enter</kbd> to select, <kbd style="background-color:#e5e7eb;padding:1px 4px;border-radius:2px;font-family:inherit;font-size:0.7rem">Esc</kbd> to dismiss`), _tmpl$9 = /* @__PURE__ */ web.template(`<div role=listbox aria-label=Suggestions><!$><!/><!$><!/><!$><!/><!$><!/>`), _tmpl$0 = /* @__PURE__ */ web.template(`<li role=option style="padding:8px 16px;font-size:0.875rem;transition:background-color 150ms ease">`);
|
|
6
|
+
function highlightText(text, match) {
|
|
7
|
+
if (!match || !text) {
|
|
8
|
+
return text;
|
|
9
|
+
}
|
|
10
|
+
const lowerText = text.toLowerCase();
|
|
11
|
+
const lowerMatch = match.toLowerCase();
|
|
12
|
+
const startIndex = lowerText.indexOf(lowerMatch);
|
|
13
|
+
if (startIndex === -1) {
|
|
14
|
+
return text;
|
|
15
|
+
}
|
|
16
|
+
const before = text.slice(0, startIndex);
|
|
17
|
+
const matched = text.slice(startIndex, startIndex + match.length);
|
|
18
|
+
const after = text.slice(startIndex + match.length);
|
|
19
|
+
return [before, (() => {
|
|
20
|
+
var _el$ = web.getNextElement(_tmpl$);
|
|
21
|
+
web.insert(_el$, matched);
|
|
22
|
+
return _el$;
|
|
23
|
+
})(), after];
|
|
24
|
+
}
|
|
25
|
+
const DefaultOptionRenderer = (props) => {
|
|
26
|
+
const displayLabel = solidJs.createMemo(() => props.option.label || props.option.value);
|
|
27
|
+
return (() => {
|
|
28
|
+
var _el$2 = web.getNextElement(_tmpl$4), _el$9 = _el$2.firstChild, [_el$0, _co$2] = web.getNextMarker(_el$9.nextSibling), _el$4 = _el$0.nextSibling, _el$5 = _el$4.firstChild, _el$7 = _el$5.nextSibling, [_el$8, _co$] = web.getNextMarker(_el$7.nextSibling);
|
|
29
|
+
web.insert(_el$2, web.createComponent(solidJs.Show, {
|
|
30
|
+
get when() {
|
|
31
|
+
return props.option.icon;
|
|
32
|
+
},
|
|
33
|
+
get children() {
|
|
34
|
+
var _el$3 = web.getNextElement(_tmpl$2);
|
|
35
|
+
web.insert(_el$3, () => props.option.icon);
|
|
36
|
+
return _el$3;
|
|
37
|
+
}
|
|
38
|
+
}), _el$0, _co$2);
|
|
39
|
+
web.insert(_el$5, () => highlightText(displayLabel(), props.highlightMatch));
|
|
40
|
+
web.insert(_el$4, web.createComponent(solidJs.Show, {
|
|
41
|
+
get when() {
|
|
42
|
+
return props.option.description;
|
|
43
|
+
},
|
|
44
|
+
get children() {
|
|
45
|
+
var _el$6 = web.getNextElement(_tmpl$3);
|
|
46
|
+
web.insert(_el$6, () => props.option.description);
|
|
47
|
+
return _el$6;
|
|
48
|
+
}
|
|
49
|
+
}), _el$8, _co$);
|
|
50
|
+
return _el$2;
|
|
51
|
+
})();
|
|
52
|
+
};
|
|
53
|
+
const AutocompleteDropdown = (props) => {
|
|
54
|
+
const positionStyles = solidJs.createMemo(() => {
|
|
55
|
+
if (props.position === "top") {
|
|
56
|
+
return {
|
|
57
|
+
bottom: "100%",
|
|
58
|
+
"margin-bottom": "4px"
|
|
59
|
+
};
|
|
60
|
+
}
|
|
61
|
+
return {
|
|
62
|
+
top: "100%",
|
|
63
|
+
"margin-top": "4px"
|
|
64
|
+
};
|
|
65
|
+
});
|
|
66
|
+
const containerStyles = solidJs.createMemo(() => ({
|
|
67
|
+
position: "absolute",
|
|
68
|
+
left: "0",
|
|
69
|
+
right: "0",
|
|
70
|
+
"z-index": "50",
|
|
71
|
+
"background-color": "#ffffff",
|
|
72
|
+
border: "1px solid #e5e7eb",
|
|
73
|
+
"border-radius": "6px",
|
|
74
|
+
"box-shadow": "0 4px 6px -1px rgba(0, 0, 0, 0.1), 0 2px 4px -1px rgba(0, 0, 0, 0.06)",
|
|
75
|
+
"max-height": props.maxHeight || "240px",
|
|
76
|
+
overflow: "auto",
|
|
77
|
+
...positionStyles()
|
|
78
|
+
}));
|
|
79
|
+
return web.createComponent(solidJs.Show, {
|
|
80
|
+
get when() {
|
|
81
|
+
return props.isOpen;
|
|
82
|
+
},
|
|
83
|
+
get children() {
|
|
84
|
+
var _el$1 = web.getNextElement(_tmpl$9), _el$24 = _el$1.firstChild, [_el$25, _co$4] = web.getNextMarker(_el$24.nextSibling), _el$26 = _el$25.nextSibling, [_el$27, _co$5] = web.getNextMarker(_el$26.nextSibling), _el$28 = _el$27.nextSibling, [_el$29, _co$6] = web.getNextMarker(_el$28.nextSibling), _el$30 = _el$29.nextSibling, [_el$31, _co$7] = web.getNextMarker(_el$30.nextSibling);
|
|
85
|
+
web.insert(_el$1, web.createComponent(solidJs.Show, {
|
|
86
|
+
get when() {
|
|
87
|
+
return props.isLoading;
|
|
88
|
+
},
|
|
89
|
+
get children() {
|
|
90
|
+
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);
|
|
91
|
+
web.insert(_el$10, () => props.loadingMessage || "Loading...", _el$13, _co$3);
|
|
92
|
+
return _el$10;
|
|
93
|
+
}
|
|
94
|
+
}), _el$25, _co$4);
|
|
95
|
+
web.insert(_el$1, web.createComponent(solidJs.Show, {
|
|
96
|
+
get when() {
|
|
97
|
+
return web.memo(() => !!!props.isLoading)() && props.options.length === 0;
|
|
98
|
+
},
|
|
99
|
+
get children() {
|
|
100
|
+
var _el$14 = web.getNextElement(_tmpl$6);
|
|
101
|
+
web.insert(_el$14, () => props.emptyMessage || "No suggestions found");
|
|
102
|
+
return _el$14;
|
|
103
|
+
}
|
|
104
|
+
}), _el$27, _co$5);
|
|
105
|
+
web.insert(_el$1, web.createComponent(solidJs.Show, {
|
|
106
|
+
get when() {
|
|
107
|
+
return web.memo(() => !!!props.isLoading)() && props.options.length > 0;
|
|
108
|
+
},
|
|
109
|
+
get children() {
|
|
110
|
+
var _el$15 = web.getNextElement(_tmpl$7);
|
|
111
|
+
web.insert(_el$15, web.createComponent(solidJs.For, {
|
|
112
|
+
get each() {
|
|
113
|
+
return props.options;
|
|
114
|
+
},
|
|
115
|
+
children: (option, index) => {
|
|
116
|
+
const isSelected = () => index() === props.selectedIndex;
|
|
117
|
+
const isDisabled = () => option.disabled;
|
|
118
|
+
return (() => {
|
|
119
|
+
var _el$32 = web.getNextElement(_tmpl$0);
|
|
120
|
+
_el$32.addEventListener("mouseenter", () => {
|
|
121
|
+
var _a;
|
|
122
|
+
if (!isDisabled()) {
|
|
123
|
+
(_a = props.onHover) == null ? void 0 : _a.call(props, index());
|
|
124
|
+
}
|
|
125
|
+
});
|
|
126
|
+
_el$32.$$click = () => {
|
|
127
|
+
if (!isDisabled()) {
|
|
128
|
+
props.onSelect(option);
|
|
129
|
+
}
|
|
130
|
+
};
|
|
131
|
+
web.insert(_el$32, web.createComponent(solidJs.Show, {
|
|
132
|
+
get when() {
|
|
133
|
+
return props.renderOption;
|
|
134
|
+
},
|
|
135
|
+
get fallback() {
|
|
136
|
+
return web.createComponent(DefaultOptionRenderer, {
|
|
137
|
+
option,
|
|
138
|
+
get isSelected() {
|
|
139
|
+
return isSelected();
|
|
140
|
+
},
|
|
141
|
+
get highlightMatch() {
|
|
142
|
+
return props.highlightMatch;
|
|
143
|
+
}
|
|
144
|
+
});
|
|
145
|
+
},
|
|
146
|
+
get children() {
|
|
147
|
+
return props.renderOption(option, isSelected());
|
|
148
|
+
}
|
|
149
|
+
}));
|
|
150
|
+
web.effect((_p$) => {
|
|
151
|
+
var _v$3 = isSelected(), _v$4 = isDisabled(), _v$5 = `mcp-autocomplete-option ${isSelected() ? "mcp-autocomplete-option-selected" : ""} ${isDisabled() ? "mcp-autocomplete-option-disabled" : ""}`, _v$6 = isDisabled() ? "not-allowed" : "pointer", _v$7 = isSelected() ? "#eff6ff" : "transparent", _v$8 = isDisabled() ? "#9ca3af" : "#374151";
|
|
152
|
+
_v$3 !== _p$.e && web.setAttribute(_el$32, "aria-selected", _p$.e = _v$3);
|
|
153
|
+
_v$4 !== _p$.t && web.setAttribute(_el$32, "aria-disabled", _p$.t = _v$4);
|
|
154
|
+
_v$5 !== _p$.a && web.className(_el$32, _p$.a = _v$5);
|
|
155
|
+
_v$6 !== _p$.o && web.setStyleProperty(_el$32, "cursor", _p$.o = _v$6);
|
|
156
|
+
_v$7 !== _p$.i && web.setStyleProperty(_el$32, "background-color", _p$.i = _v$7);
|
|
157
|
+
_v$8 !== _p$.n && web.setStyleProperty(_el$32, "color", _p$.n = _v$8);
|
|
158
|
+
return _p$;
|
|
159
|
+
}, {
|
|
160
|
+
e: void 0,
|
|
161
|
+
t: void 0,
|
|
162
|
+
a: void 0,
|
|
163
|
+
o: void 0,
|
|
164
|
+
i: void 0,
|
|
165
|
+
n: void 0
|
|
166
|
+
});
|
|
167
|
+
web.runHydrationEvents();
|
|
168
|
+
return _el$32;
|
|
169
|
+
})();
|
|
170
|
+
}
|
|
171
|
+
}));
|
|
172
|
+
return _el$15;
|
|
173
|
+
}
|
|
174
|
+
}), _el$29, _co$6);
|
|
175
|
+
web.insert(_el$1, web.createComponent(solidJs.Show, {
|
|
176
|
+
get when() {
|
|
177
|
+
return web.memo(() => !!!props.isLoading)() && props.options.length > 0;
|
|
178
|
+
},
|
|
179
|
+
get children() {
|
|
180
|
+
var _el$16 = web.getNextElement(_tmpl$8), _el$17 = _el$16.firstChild, _el$18 = _el$17.nextSibling, _el$19 = _el$18.nextSibling, _el$20 = _el$19.nextSibling, _el$21 = _el$20.nextSibling, _el$22 = _el$21.nextSibling;
|
|
181
|
+
_el$22.nextSibling;
|
|
182
|
+
return _el$16;
|
|
183
|
+
}
|
|
184
|
+
}), _el$31, _co$7);
|
|
185
|
+
web.effect((_p$) => {
|
|
186
|
+
var _v$ = `mcp-autocomplete-dropdown ${props.class || ""}`, _v$2 = containerStyles();
|
|
187
|
+
_v$ !== _p$.e && web.className(_el$1, _p$.e = _v$);
|
|
188
|
+
_p$.t = web.style(_el$1, _v$2, _p$.t);
|
|
189
|
+
return _p$;
|
|
190
|
+
}, {
|
|
191
|
+
e: void 0,
|
|
192
|
+
t: void 0
|
|
193
|
+
});
|
|
194
|
+
return _el$1;
|
|
195
|
+
}
|
|
196
|
+
});
|
|
197
|
+
};
|
|
198
|
+
web.delegateEvents(["click"]);
|
|
199
|
+
exports.AutocompleteDropdown = AutocompleteDropdown;
|
|
200
|
+
exports.default = AutocompleteDropdown;
|
|
201
|
+
//# sourceMappingURL=AutocompleteDropdown.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"AutocompleteDropdown.cjs","sources":["../../src/components/AutocompleteDropdown.tsx"],"sourcesContent":["/**\n * AutocompleteDropdown Component\n * Displays data-driven dropdown suggestions\n *\n * Sprint Autocomplete Feature\n */\n\nimport { Component, For, Show, createMemo, JSX } from 'solid-js'\nimport type { AutocompleteOption } from '../types'\n\n/**\n * Props for AutocompleteDropdown\n */\nexport interface AutocompleteDropdownProps {\n /**\n * Options to display\n */\n options: AutocompleteOption[]\n\n /**\n * Currently selected index\n */\n selectedIndex: number\n\n /**\n * Whether dropdown is visible\n */\n isOpen: boolean\n\n /**\n * Callback when option is selected\n */\n onSelect: (option: AutocompleteOption) => void\n\n /**\n * Callback when option is hovered\n */\n onHover?: (index: number) => void\n\n /**\n * Whether loading\n */\n isLoading?: boolean\n\n /**\n * Custom class\n */\n class?: string\n\n /**\n * Max height\n */\n maxHeight?: string\n\n /**\n * Empty state message\n */\n emptyMessage?: string\n\n /**\n * Loading message\n */\n loadingMessage?: string\n\n /**\n * Highlight matching text in options\n */\n highlightMatch?: string\n\n /**\n * Position (default: 'bottom')\n */\n position?: 'top' | 'bottom'\n\n /**\n * Custom option renderer\n */\n renderOption?: (option: AutocompleteOption, isSelected: boolean) => JSX.Element\n}\n\n/**\n * Highlight matching text\n */\nfunction highlightText(text: string, match?: string): JSX.Element {\n if (!match || !text) {\n return <>{text}</>\n }\n\n const lowerText = text.toLowerCase()\n const lowerMatch = match.toLowerCase()\n const startIndex = lowerText.indexOf(lowerMatch)\n\n if (startIndex === -1) {\n return <>{text}</>\n }\n\n const before = text.slice(0, startIndex)\n const matched = text.slice(startIndex, startIndex + match.length)\n const after = text.slice(startIndex + match.length)\n\n return (\n <>\n {before}\n <strong class=\"mcp-autocomplete-highlight\">{matched}</strong>\n {after}\n </>\n )\n}\n\n/**\n * Default option renderer\n */\nconst DefaultOptionRenderer: Component<{\n option: AutocompleteOption\n isSelected: boolean\n highlightMatch?: string\n}> = (props) => {\n const displayLabel = createMemo(() =>\n props.option.label || props.option.value\n )\n\n return (\n <div class=\"mcp-autocomplete-option-content\">\n <Show when={props.option.icon}>\n <span class=\"mcp-autocomplete-option-icon\">{props.option.icon}</span>\n </Show>\n <div class=\"mcp-autocomplete-option-text\">\n <span class=\"mcp-autocomplete-option-label\">\n {highlightText(displayLabel(), props.highlightMatch)}\n </span>\n <Show when={props.option.description}>\n <span class=\"mcp-autocomplete-option-description\">\n {props.option.description}\n </span>\n </Show>\n </div>\n </div>\n )\n}\n\n/**\n * AutocompleteDropdown Component\n */\nexport const AutocompleteDropdown: Component<AutocompleteDropdownProps> = (props) => {\n const positionStyles = createMemo((): JSX.CSSProperties => {\n if (props.position === 'top') {\n return {\n bottom: '100%',\n 'margin-bottom': '4px'\n }\n }\n return {\n top: '100%',\n 'margin-top': '4px'\n }\n })\n\n const containerStyles = createMemo((): JSX.CSSProperties => ({\n position: 'absolute',\n left: '0',\n right: '0',\n 'z-index': '50',\n 'background-color': '#ffffff',\n border: '1px solid #e5e7eb',\n 'border-radius': '6px',\n 'box-shadow': '0 4px 6px -1px rgba(0, 0, 0, 0.1), 0 2px 4px -1px rgba(0, 0, 0, 0.06)',\n 'max-height': props.maxHeight || '240px',\n overflow: 'auto',\n ...positionStyles()\n }))\n\n return (\n <Show when={props.isOpen}>\n <div\n class={`mcp-autocomplete-dropdown ${props.class || ''}`}\n style={containerStyles()}\n role=\"listbox\"\n aria-label=\"Suggestions\"\n >\n {/* Loading state */}\n <Show when={props.isLoading}>\n <div\n class=\"mcp-autocomplete-loading\"\n style={{\n padding: '12px 16px',\n color: '#6b7280',\n 'font-size': '0.875rem',\n display: 'flex',\n 'align-items': 'center',\n gap: '8px'\n }}\n >\n <span\n style={{\n display: 'inline-block',\n width: '14px',\n height: '14px',\n border: '2px solid #e5e7eb',\n 'border-top-color': '#3b82f6',\n 'border-radius': '50%',\n animation: 'mcp-spin 0.6s linear infinite'\n }}\n />\n {props.loadingMessage || 'Loading...'}\n </div>\n </Show>\n\n {/* Empty state */}\n <Show when={!props.isLoading && props.options.length === 0}>\n <div\n class=\"mcp-autocomplete-empty\"\n style={{\n padding: '12px 16px',\n color: '#9ca3af',\n 'font-size': '0.875rem',\n 'text-align': 'center'\n }}\n >\n {props.emptyMessage || 'No suggestions found'}\n </div>\n </Show>\n\n {/* Options list */}\n <Show when={!props.isLoading && props.options.length > 0}>\n <ul\n class=\"mcp-autocomplete-options\"\n style={{ margin: '0', padding: '4px 0', 'list-style': 'none' }}\n >\n <For each={props.options}>\n {(option, index) => {\n const isSelected = () => index() === props.selectedIndex\n const isDisabled = () => option.disabled\n\n return (\n <li\n role=\"option\"\n aria-selected={isSelected()}\n aria-disabled={isDisabled()}\n class={`mcp-autocomplete-option ${isSelected() ? 'mcp-autocomplete-option-selected' : ''} ${isDisabled() ? 'mcp-autocomplete-option-disabled' : ''}`}\n style={{\n padding: '8px 16px',\n cursor: isDisabled() ? 'not-allowed' : 'pointer',\n 'background-color': isSelected() ? '#eff6ff' : 'transparent',\n color: isDisabled() ? '#9ca3af' : '#374151',\n 'font-size': '0.875rem',\n transition: 'background-color 150ms ease'\n }}\n onClick={() => {\n if (!isDisabled()) {\n props.onSelect(option)\n }\n }}\n onMouseEnter={() => {\n if (!isDisabled()) {\n props.onHover?.(index())\n }\n }}\n >\n <Show\n when={props.renderOption}\n fallback={\n <DefaultOptionRenderer\n option={option}\n isSelected={isSelected()}\n highlightMatch={props.highlightMatch}\n />\n }\n >\n {props.renderOption!(option, isSelected())}\n </Show>\n </li>\n )\n }}\n </For>\n </ul>\n </Show>\n\n {/* Footer hint */}\n <Show when={!props.isLoading && props.options.length > 0}>\n <div\n class=\"mcp-autocomplete-footer\"\n style={{\n padding: '6px 12px',\n 'border-top': '1px solid #e5e7eb',\n 'background-color': '#f9fafb',\n 'font-size': '0.75rem',\n color: '#6b7280'\n }}\n >\n <kbd style={{\n 'background-color': '#e5e7eb',\n padding: '1px 4px',\n 'border-radius': '2px',\n 'font-family': 'inherit',\n 'font-size': '0.7rem'\n }}>↑</kbd>\n {' '}\n <kbd style={{\n 'background-color': '#e5e7eb',\n padding: '1px 4px',\n 'border-radius': '2px',\n 'font-family': 'inherit',\n 'font-size': '0.7rem'\n }}>↓</kbd>\n {' to navigate, '}\n <kbd style={{\n 'background-color': '#e5e7eb',\n padding: '1px 4px',\n 'border-radius': '2px',\n 'font-family': 'inherit',\n 'font-size': '0.7rem'\n }}>Enter</kbd>\n {' to select, '}\n <kbd style={{\n 'background-color': '#e5e7eb',\n padding: '1px 4px',\n 'border-radius': '2px',\n 'font-family': 'inherit',\n 'font-size': '0.7rem'\n }}>Esc</kbd>\n {' to dismiss'}\n </div>\n </Show>\n </div>\n </Show>\n )\n}\n\nexport default AutocompleteDropdown\n"],"names":["highlightText","text","match","lowerText","toLowerCase","lowerMatch","startIndex","indexOf","before","slice","matched","length","after","_el$","_$getNextElement","_tmpl$","_$insert","DefaultOptionRenderer","props","displayLabel","createMemo","option","label","value","_el$2","_tmpl$4","_el$9","firstChild","_el$0","_co$2","_$getNextMarker","nextSibling","_el$4","_el$5","_el$7","_el$8","_co$","_$createComponent","Show","when","icon","children","_el$3","_tmpl$2","highlightMatch","description","_el$6","_tmpl$3","AutocompleteDropdown","positionStyles","position","bottom","top","containerStyles","left","right","border","maxHeight","overflow","isOpen","_el$1","_tmpl$9","_el$24","_el$25","_co$4","_el$26","_el$27","_co$5","_el$28","_el$29","_co$6","_el$30","_el$31","_co$7","isLoading","_el$10","_tmpl$5","_el$11","_el$12","_el$13","_co$3","loadingMessage","_$memo","options","_el$14","_tmpl$6","emptyMessage","_el$15","_tmpl$7","For","each","index","isSelected","selectedIndex","isDisabled","disabled","_el$32","_tmpl$0","addEventListener","onHover","$$click","onSelect","renderOption","fallback","_$effect","_p$","_v$3","_v$4","_v$5","_v$6","_v$7","_v$8","e","_$setAttribute","t","a","_$className","o","_$setStyleProperty","i","n","undefined","_$runHydrationEvents","_el$16","_tmpl$8","_el$17","_el$18","_el$19","_el$20","_el$21","_el$22","_v$","class","_v$2","_$style","_$delegateEvents"],"mappings":"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"}
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* AutocompleteDropdown Component
|
|
3
|
+
* Displays data-driven dropdown suggestions
|
|
4
|
+
*
|
|
5
|
+
* Sprint Autocomplete Feature
|
|
6
|
+
*/
|
|
7
|
+
import { Component, JSX } from 'solid-js';
|
|
8
|
+
import type { AutocompleteOption } from '../types';
|
|
9
|
+
/**
|
|
10
|
+
* Props for AutocompleteDropdown
|
|
11
|
+
*/
|
|
12
|
+
export interface AutocompleteDropdownProps {
|
|
13
|
+
/**
|
|
14
|
+
* Options to display
|
|
15
|
+
*/
|
|
16
|
+
options: AutocompleteOption[];
|
|
17
|
+
/**
|
|
18
|
+
* Currently selected index
|
|
19
|
+
*/
|
|
20
|
+
selectedIndex: number;
|
|
21
|
+
/**
|
|
22
|
+
* Whether dropdown is visible
|
|
23
|
+
*/
|
|
24
|
+
isOpen: boolean;
|
|
25
|
+
/**
|
|
26
|
+
* Callback when option is selected
|
|
27
|
+
*/
|
|
28
|
+
onSelect: (option: AutocompleteOption) => void;
|
|
29
|
+
/**
|
|
30
|
+
* Callback when option is hovered
|
|
31
|
+
*/
|
|
32
|
+
onHover?: (index: number) => void;
|
|
33
|
+
/**
|
|
34
|
+
* Whether loading
|
|
35
|
+
*/
|
|
36
|
+
isLoading?: boolean;
|
|
37
|
+
/**
|
|
38
|
+
* Custom class
|
|
39
|
+
*/
|
|
40
|
+
class?: string;
|
|
41
|
+
/**
|
|
42
|
+
* Max height
|
|
43
|
+
*/
|
|
44
|
+
maxHeight?: string;
|
|
45
|
+
/**
|
|
46
|
+
* Empty state message
|
|
47
|
+
*/
|
|
48
|
+
emptyMessage?: string;
|
|
49
|
+
/**
|
|
50
|
+
* Loading message
|
|
51
|
+
*/
|
|
52
|
+
loadingMessage?: string;
|
|
53
|
+
/**
|
|
54
|
+
* Highlight matching text in options
|
|
55
|
+
*/
|
|
56
|
+
highlightMatch?: string;
|
|
57
|
+
/**
|
|
58
|
+
* Position (default: 'bottom')
|
|
59
|
+
*/
|
|
60
|
+
position?: 'top' | 'bottom';
|
|
61
|
+
/**
|
|
62
|
+
* Custom option renderer
|
|
63
|
+
*/
|
|
64
|
+
renderOption?: (option: AutocompleteOption, isSelected: boolean) => JSX.Element;
|
|
65
|
+
}
|
|
66
|
+
/**
|
|
67
|
+
* AutocompleteDropdown Component
|
|
68
|
+
*/
|
|
69
|
+
export declare const AutocompleteDropdown: Component<AutocompleteDropdownProps>;
|
|
70
|
+
export default AutocompleteDropdown;
|
|
71
|
+
//# sourceMappingURL=AutocompleteDropdown.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"AutocompleteDropdown.d.ts","sourceRoot":"","sources":["../../src/components/AutocompleteDropdown.tsx"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,EAAE,SAAS,EAAyB,GAAG,EAAE,MAAM,UAAU,CAAA;AAChE,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,UAAU,CAAA;AAElD;;GAEG;AACH,MAAM,WAAW,yBAAyB;IACxC;;OAEG;IACH,OAAO,EAAE,kBAAkB,EAAE,CAAA;IAE7B;;OAEG;IACH,aAAa,EAAE,MAAM,CAAA;IAErB;;OAEG;IACH,MAAM,EAAE,OAAO,CAAA;IAEf;;OAEG;IACH,QAAQ,EAAE,CAAC,MAAM,EAAE,kBAAkB,KAAK,IAAI,CAAA;IAE9C;;OAEG;IACH,OAAO,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAA;IAEjC;;OAEG;IACH,SAAS,CAAC,EAAE,OAAO,CAAA;IAEnB;;OAEG;IACH,KAAK,CAAC,EAAE,MAAM,CAAA;IAEd;;OAEG;IACH,SAAS,CAAC,EAAE,MAAM,CAAA;IAElB;;OAEG;IACH,YAAY,CAAC,EAAE,MAAM,CAAA;IAErB;;OAEG;IACH,cAAc,CAAC,EAAE,MAAM,CAAA;IAEvB;;OAEG;IACH,cAAc,CAAC,EAAE,MAAM,CAAA;IAEvB;;OAEG;IACH,QAAQ,CAAC,EAAE,KAAK,GAAG,QAAQ,CAAA;IAE3B;;OAEG;IACH,YAAY,CAAC,EAAE,CAAC,MAAM,EAAE,kBAAkB,EAAE,UAAU,EAAE,OAAO,KAAK,GAAG,CAAC,OAAO,CAAA;CAChF;AA8DD;;GAEG;AACH,eAAO,MAAM,oBAAoB,EAAE,SAAS,CAAC,yBAAyB,CAuLrE,CAAA;AAED,eAAe,oBAAoB,CAAA"}
|
|
@@ -0,0 +1,201 @@
|
|
|
1
|
+
import { delegateEvents, createComponent, getNextElement, template, getNextMarker, insert, memo, effect, setAttribute, className, setStyleProperty, runHydrationEvents, style } from "solid-js/web";
|
|
2
|
+
import { createMemo, Show, For } from "solid-js";
|
|
3
|
+
var _tmpl$ = /* @__PURE__ */ template(`<strong class=mcp-autocomplete-highlight>`), _tmpl$2 = /* @__PURE__ */ template(`<span class=mcp-autocomplete-option-icon>`), _tmpl$3 = /* @__PURE__ */ template(`<span class=mcp-autocomplete-option-description>`), _tmpl$4 = /* @__PURE__ */ template(`<div class=mcp-autocomplete-option-content><!$><!/><div class=mcp-autocomplete-option-text><span class=mcp-autocomplete-option-label></span><!$><!/>`), _tmpl$5 = /* @__PURE__ */ template(`<div class=mcp-autocomplete-loading style="padding:12px 16px;color:#6b7280;font-size:0.875rem;display:flex;align-items:center;gap:8px"><span style="display:inline-block;width:14px;height:14px;border:2px solid #e5e7eb;border-top-color:#3b82f6;border-radius:50%;animation:mcp-spin 0.6s linear infinite"></span><!$><!/>`), _tmpl$6 = /* @__PURE__ */ template(`<div class=mcp-autocomplete-empty style="padding:12px 16px;color:#9ca3af;font-size:0.875rem;text-align:center">`), _tmpl$7 = /* @__PURE__ */ template(`<ul class=mcp-autocomplete-options style="margin:0;padding:4px 0;list-style:none">`), _tmpl$8 = /* @__PURE__ */ template(`<div class=mcp-autocomplete-footer style="padding:6px 12px;border-top:1px solid #e5e7eb;background-color:#f9fafb;font-size:0.75rem;color:#6b7280"><kbd style="background-color:#e5e7eb;padding:1px 4px;border-radius:2px;font-family:inherit;font-size:0.7rem">↑</kbd> <kbd style="background-color:#e5e7eb;padding:1px 4px;border-radius:2px;font-family:inherit;font-size:0.7rem">↓</kbd> to navigate, <kbd style="background-color:#e5e7eb;padding:1px 4px;border-radius:2px;font-family:inherit;font-size:0.7rem">Enter</kbd> to select, <kbd style="background-color:#e5e7eb;padding:1px 4px;border-radius:2px;font-family:inherit;font-size:0.7rem">Esc</kbd> to dismiss`), _tmpl$9 = /* @__PURE__ */ template(`<div role=listbox aria-label=Suggestions><!$><!/><!$><!/><!$><!/><!$><!/>`), _tmpl$0 = /* @__PURE__ */ template(`<li role=option style="padding:8px 16px;font-size:0.875rem;transition:background-color 150ms ease">`);
|
|
4
|
+
function highlightText(text, match) {
|
|
5
|
+
if (!match || !text) {
|
|
6
|
+
return text;
|
|
7
|
+
}
|
|
8
|
+
const lowerText = text.toLowerCase();
|
|
9
|
+
const lowerMatch = match.toLowerCase();
|
|
10
|
+
const startIndex = lowerText.indexOf(lowerMatch);
|
|
11
|
+
if (startIndex === -1) {
|
|
12
|
+
return text;
|
|
13
|
+
}
|
|
14
|
+
const before = text.slice(0, startIndex);
|
|
15
|
+
const matched = text.slice(startIndex, startIndex + match.length);
|
|
16
|
+
const after = text.slice(startIndex + match.length);
|
|
17
|
+
return [before, (() => {
|
|
18
|
+
var _el$ = getNextElement(_tmpl$);
|
|
19
|
+
insert(_el$, matched);
|
|
20
|
+
return _el$;
|
|
21
|
+
})(), after];
|
|
22
|
+
}
|
|
23
|
+
const DefaultOptionRenderer = (props) => {
|
|
24
|
+
const displayLabel = createMemo(() => props.option.label || props.option.value);
|
|
25
|
+
return (() => {
|
|
26
|
+
var _el$2 = getNextElement(_tmpl$4), _el$9 = _el$2.firstChild, [_el$0, _co$2] = getNextMarker(_el$9.nextSibling), _el$4 = _el$0.nextSibling, _el$5 = _el$4.firstChild, _el$7 = _el$5.nextSibling, [_el$8, _co$] = getNextMarker(_el$7.nextSibling);
|
|
27
|
+
insert(_el$2, createComponent(Show, {
|
|
28
|
+
get when() {
|
|
29
|
+
return props.option.icon;
|
|
30
|
+
},
|
|
31
|
+
get children() {
|
|
32
|
+
var _el$3 = getNextElement(_tmpl$2);
|
|
33
|
+
insert(_el$3, () => props.option.icon);
|
|
34
|
+
return _el$3;
|
|
35
|
+
}
|
|
36
|
+
}), _el$0, _co$2);
|
|
37
|
+
insert(_el$5, () => highlightText(displayLabel(), props.highlightMatch));
|
|
38
|
+
insert(_el$4, createComponent(Show, {
|
|
39
|
+
get when() {
|
|
40
|
+
return props.option.description;
|
|
41
|
+
},
|
|
42
|
+
get children() {
|
|
43
|
+
var _el$6 = getNextElement(_tmpl$3);
|
|
44
|
+
insert(_el$6, () => props.option.description);
|
|
45
|
+
return _el$6;
|
|
46
|
+
}
|
|
47
|
+
}), _el$8, _co$);
|
|
48
|
+
return _el$2;
|
|
49
|
+
})();
|
|
50
|
+
};
|
|
51
|
+
const AutocompleteDropdown = (props) => {
|
|
52
|
+
const positionStyles = createMemo(() => {
|
|
53
|
+
if (props.position === "top") {
|
|
54
|
+
return {
|
|
55
|
+
bottom: "100%",
|
|
56
|
+
"margin-bottom": "4px"
|
|
57
|
+
};
|
|
58
|
+
}
|
|
59
|
+
return {
|
|
60
|
+
top: "100%",
|
|
61
|
+
"margin-top": "4px"
|
|
62
|
+
};
|
|
63
|
+
});
|
|
64
|
+
const containerStyles = createMemo(() => ({
|
|
65
|
+
position: "absolute",
|
|
66
|
+
left: "0",
|
|
67
|
+
right: "0",
|
|
68
|
+
"z-index": "50",
|
|
69
|
+
"background-color": "#ffffff",
|
|
70
|
+
border: "1px solid #e5e7eb",
|
|
71
|
+
"border-radius": "6px",
|
|
72
|
+
"box-shadow": "0 4px 6px -1px rgba(0, 0, 0, 0.1), 0 2px 4px -1px rgba(0, 0, 0, 0.06)",
|
|
73
|
+
"max-height": props.maxHeight || "240px",
|
|
74
|
+
overflow: "auto",
|
|
75
|
+
...positionStyles()
|
|
76
|
+
}));
|
|
77
|
+
return createComponent(Show, {
|
|
78
|
+
get when() {
|
|
79
|
+
return props.isOpen;
|
|
80
|
+
},
|
|
81
|
+
get children() {
|
|
82
|
+
var _el$1 = getNextElement(_tmpl$9), _el$24 = _el$1.firstChild, [_el$25, _co$4] = getNextMarker(_el$24.nextSibling), _el$26 = _el$25.nextSibling, [_el$27, _co$5] = getNextMarker(_el$26.nextSibling), _el$28 = _el$27.nextSibling, [_el$29, _co$6] = getNextMarker(_el$28.nextSibling), _el$30 = _el$29.nextSibling, [_el$31, _co$7] = getNextMarker(_el$30.nextSibling);
|
|
83
|
+
insert(_el$1, createComponent(Show, {
|
|
84
|
+
get when() {
|
|
85
|
+
return props.isLoading;
|
|
86
|
+
},
|
|
87
|
+
get children() {
|
|
88
|
+
var _el$10 = getNextElement(_tmpl$5), _el$11 = _el$10.firstChild, _el$12 = _el$11.nextSibling, [_el$13, _co$3] = getNextMarker(_el$12.nextSibling);
|
|
89
|
+
insert(_el$10, () => props.loadingMessage || "Loading...", _el$13, _co$3);
|
|
90
|
+
return _el$10;
|
|
91
|
+
}
|
|
92
|
+
}), _el$25, _co$4);
|
|
93
|
+
insert(_el$1, createComponent(Show, {
|
|
94
|
+
get when() {
|
|
95
|
+
return memo(() => !!!props.isLoading)() && props.options.length === 0;
|
|
96
|
+
},
|
|
97
|
+
get children() {
|
|
98
|
+
var _el$14 = getNextElement(_tmpl$6);
|
|
99
|
+
insert(_el$14, () => props.emptyMessage || "No suggestions found");
|
|
100
|
+
return _el$14;
|
|
101
|
+
}
|
|
102
|
+
}), _el$27, _co$5);
|
|
103
|
+
insert(_el$1, createComponent(Show, {
|
|
104
|
+
get when() {
|
|
105
|
+
return memo(() => !!!props.isLoading)() && props.options.length > 0;
|
|
106
|
+
},
|
|
107
|
+
get children() {
|
|
108
|
+
var _el$15 = getNextElement(_tmpl$7);
|
|
109
|
+
insert(_el$15, createComponent(For, {
|
|
110
|
+
get each() {
|
|
111
|
+
return props.options;
|
|
112
|
+
},
|
|
113
|
+
children: (option, index) => {
|
|
114
|
+
const isSelected = () => index() === props.selectedIndex;
|
|
115
|
+
const isDisabled = () => option.disabled;
|
|
116
|
+
return (() => {
|
|
117
|
+
var _el$32 = getNextElement(_tmpl$0);
|
|
118
|
+
_el$32.addEventListener("mouseenter", () => {
|
|
119
|
+
var _a;
|
|
120
|
+
if (!isDisabled()) {
|
|
121
|
+
(_a = props.onHover) == null ? void 0 : _a.call(props, index());
|
|
122
|
+
}
|
|
123
|
+
});
|
|
124
|
+
_el$32.$$click = () => {
|
|
125
|
+
if (!isDisabled()) {
|
|
126
|
+
props.onSelect(option);
|
|
127
|
+
}
|
|
128
|
+
};
|
|
129
|
+
insert(_el$32, createComponent(Show, {
|
|
130
|
+
get when() {
|
|
131
|
+
return props.renderOption;
|
|
132
|
+
},
|
|
133
|
+
get fallback() {
|
|
134
|
+
return createComponent(DefaultOptionRenderer, {
|
|
135
|
+
option,
|
|
136
|
+
get isSelected() {
|
|
137
|
+
return isSelected();
|
|
138
|
+
},
|
|
139
|
+
get highlightMatch() {
|
|
140
|
+
return props.highlightMatch;
|
|
141
|
+
}
|
|
142
|
+
});
|
|
143
|
+
},
|
|
144
|
+
get children() {
|
|
145
|
+
return props.renderOption(option, isSelected());
|
|
146
|
+
}
|
|
147
|
+
}));
|
|
148
|
+
effect((_p$) => {
|
|
149
|
+
var _v$3 = isSelected(), _v$4 = isDisabled(), _v$5 = `mcp-autocomplete-option ${isSelected() ? "mcp-autocomplete-option-selected" : ""} ${isDisabled() ? "mcp-autocomplete-option-disabled" : ""}`, _v$6 = isDisabled() ? "not-allowed" : "pointer", _v$7 = isSelected() ? "#eff6ff" : "transparent", _v$8 = isDisabled() ? "#9ca3af" : "#374151";
|
|
150
|
+
_v$3 !== _p$.e && setAttribute(_el$32, "aria-selected", _p$.e = _v$3);
|
|
151
|
+
_v$4 !== _p$.t && setAttribute(_el$32, "aria-disabled", _p$.t = _v$4);
|
|
152
|
+
_v$5 !== _p$.a && className(_el$32, _p$.a = _v$5);
|
|
153
|
+
_v$6 !== _p$.o && setStyleProperty(_el$32, "cursor", _p$.o = _v$6);
|
|
154
|
+
_v$7 !== _p$.i && setStyleProperty(_el$32, "background-color", _p$.i = _v$7);
|
|
155
|
+
_v$8 !== _p$.n && setStyleProperty(_el$32, "color", _p$.n = _v$8);
|
|
156
|
+
return _p$;
|
|
157
|
+
}, {
|
|
158
|
+
e: void 0,
|
|
159
|
+
t: void 0,
|
|
160
|
+
a: void 0,
|
|
161
|
+
o: void 0,
|
|
162
|
+
i: void 0,
|
|
163
|
+
n: void 0
|
|
164
|
+
});
|
|
165
|
+
runHydrationEvents();
|
|
166
|
+
return _el$32;
|
|
167
|
+
})();
|
|
168
|
+
}
|
|
169
|
+
}));
|
|
170
|
+
return _el$15;
|
|
171
|
+
}
|
|
172
|
+
}), _el$29, _co$6);
|
|
173
|
+
insert(_el$1, createComponent(Show, {
|
|
174
|
+
get when() {
|
|
175
|
+
return memo(() => !!!props.isLoading)() && props.options.length > 0;
|
|
176
|
+
},
|
|
177
|
+
get children() {
|
|
178
|
+
var _el$16 = getNextElement(_tmpl$8), _el$17 = _el$16.firstChild, _el$18 = _el$17.nextSibling, _el$19 = _el$18.nextSibling, _el$20 = _el$19.nextSibling, _el$21 = _el$20.nextSibling, _el$22 = _el$21.nextSibling;
|
|
179
|
+
_el$22.nextSibling;
|
|
180
|
+
return _el$16;
|
|
181
|
+
}
|
|
182
|
+
}), _el$31, _co$7);
|
|
183
|
+
effect((_p$) => {
|
|
184
|
+
var _v$ = `mcp-autocomplete-dropdown ${props.class || ""}`, _v$2 = containerStyles();
|
|
185
|
+
_v$ !== _p$.e && className(_el$1, _p$.e = _v$);
|
|
186
|
+
_p$.t = style(_el$1, _v$2, _p$.t);
|
|
187
|
+
return _p$;
|
|
188
|
+
}, {
|
|
189
|
+
e: void 0,
|
|
190
|
+
t: void 0
|
|
191
|
+
});
|
|
192
|
+
return _el$1;
|
|
193
|
+
}
|
|
194
|
+
});
|
|
195
|
+
};
|
|
196
|
+
delegateEvents(["click"]);
|
|
197
|
+
export {
|
|
198
|
+
AutocompleteDropdown,
|
|
199
|
+
AutocompleteDropdown as default
|
|
200
|
+
};
|
|
201
|
+
//# sourceMappingURL=AutocompleteDropdown.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"AutocompleteDropdown.js","sources":["../../src/components/AutocompleteDropdown.tsx"],"sourcesContent":["/**\n * AutocompleteDropdown Component\n * Displays data-driven dropdown suggestions\n *\n * Sprint Autocomplete Feature\n */\n\nimport { Component, For, Show, createMemo, JSX } from 'solid-js'\nimport type { AutocompleteOption } from '../types'\n\n/**\n * Props for AutocompleteDropdown\n */\nexport interface AutocompleteDropdownProps {\n /**\n * Options to display\n */\n options: AutocompleteOption[]\n\n /**\n * Currently selected index\n */\n selectedIndex: number\n\n /**\n * Whether dropdown is visible\n */\n isOpen: boolean\n\n /**\n * Callback when option is selected\n */\n onSelect: (option: AutocompleteOption) => void\n\n /**\n * Callback when option is hovered\n */\n onHover?: (index: number) => void\n\n /**\n * Whether loading\n */\n isLoading?: boolean\n\n /**\n * Custom class\n */\n class?: string\n\n /**\n * Max height\n */\n maxHeight?: string\n\n /**\n * Empty state message\n */\n emptyMessage?: string\n\n /**\n * Loading message\n */\n loadingMessage?: string\n\n /**\n * Highlight matching text in options\n */\n highlightMatch?: string\n\n /**\n * Position (default: 'bottom')\n */\n position?: 'top' | 'bottom'\n\n /**\n * Custom option renderer\n */\n renderOption?: (option: AutocompleteOption, isSelected: boolean) => JSX.Element\n}\n\n/**\n * Highlight matching text\n */\nfunction highlightText(text: string, match?: string): JSX.Element {\n if (!match || !text) {\n return <>{text}</>\n }\n\n const lowerText = text.toLowerCase()\n const lowerMatch = match.toLowerCase()\n const startIndex = lowerText.indexOf(lowerMatch)\n\n if (startIndex === -1) {\n return <>{text}</>\n }\n\n const before = text.slice(0, startIndex)\n const matched = text.slice(startIndex, startIndex + match.length)\n const after = text.slice(startIndex + match.length)\n\n return (\n <>\n {before}\n <strong class=\"mcp-autocomplete-highlight\">{matched}</strong>\n {after}\n </>\n )\n}\n\n/**\n * Default option renderer\n */\nconst DefaultOptionRenderer: Component<{\n option: AutocompleteOption\n isSelected: boolean\n highlightMatch?: string\n}> = (props) => {\n const displayLabel = createMemo(() =>\n props.option.label || props.option.value\n )\n\n return (\n <div class=\"mcp-autocomplete-option-content\">\n <Show when={props.option.icon}>\n <span class=\"mcp-autocomplete-option-icon\">{props.option.icon}</span>\n </Show>\n <div class=\"mcp-autocomplete-option-text\">\n <span class=\"mcp-autocomplete-option-label\">\n {highlightText(displayLabel(), props.highlightMatch)}\n </span>\n <Show when={props.option.description}>\n <span class=\"mcp-autocomplete-option-description\">\n {props.option.description}\n </span>\n </Show>\n </div>\n </div>\n )\n}\n\n/**\n * AutocompleteDropdown Component\n */\nexport const AutocompleteDropdown: Component<AutocompleteDropdownProps> = (props) => {\n const positionStyles = createMemo((): JSX.CSSProperties => {\n if (props.position === 'top') {\n return {\n bottom: '100%',\n 'margin-bottom': '4px'\n }\n }\n return {\n top: '100%',\n 'margin-top': '4px'\n }\n })\n\n const containerStyles = createMemo((): JSX.CSSProperties => ({\n position: 'absolute',\n left: '0',\n right: '0',\n 'z-index': '50',\n 'background-color': '#ffffff',\n border: '1px solid #e5e7eb',\n 'border-radius': '6px',\n 'box-shadow': '0 4px 6px -1px rgba(0, 0, 0, 0.1), 0 2px 4px -1px rgba(0, 0, 0, 0.06)',\n 'max-height': props.maxHeight || '240px',\n overflow: 'auto',\n ...positionStyles()\n }))\n\n return (\n <Show when={props.isOpen}>\n <div\n class={`mcp-autocomplete-dropdown ${props.class || ''}`}\n style={containerStyles()}\n role=\"listbox\"\n aria-label=\"Suggestions\"\n >\n {/* Loading state */}\n <Show when={props.isLoading}>\n <div\n class=\"mcp-autocomplete-loading\"\n style={{\n padding: '12px 16px',\n color: '#6b7280',\n 'font-size': '0.875rem',\n display: 'flex',\n 'align-items': 'center',\n gap: '8px'\n }}\n >\n <span\n style={{\n display: 'inline-block',\n width: '14px',\n height: '14px',\n border: '2px solid #e5e7eb',\n 'border-top-color': '#3b82f6',\n 'border-radius': '50%',\n animation: 'mcp-spin 0.6s linear infinite'\n }}\n />\n {props.loadingMessage || 'Loading...'}\n </div>\n </Show>\n\n {/* Empty state */}\n <Show when={!props.isLoading && props.options.length === 0}>\n <div\n class=\"mcp-autocomplete-empty\"\n style={{\n padding: '12px 16px',\n color: '#9ca3af',\n 'font-size': '0.875rem',\n 'text-align': 'center'\n }}\n >\n {props.emptyMessage || 'No suggestions found'}\n </div>\n </Show>\n\n {/* Options list */}\n <Show when={!props.isLoading && props.options.length > 0}>\n <ul\n class=\"mcp-autocomplete-options\"\n style={{ margin: '0', padding: '4px 0', 'list-style': 'none' }}\n >\n <For each={props.options}>\n {(option, index) => {\n const isSelected = () => index() === props.selectedIndex\n const isDisabled = () => option.disabled\n\n return (\n <li\n role=\"option\"\n aria-selected={isSelected()}\n aria-disabled={isDisabled()}\n class={`mcp-autocomplete-option ${isSelected() ? 'mcp-autocomplete-option-selected' : ''} ${isDisabled() ? 'mcp-autocomplete-option-disabled' : ''}`}\n style={{\n padding: '8px 16px',\n cursor: isDisabled() ? 'not-allowed' : 'pointer',\n 'background-color': isSelected() ? '#eff6ff' : 'transparent',\n color: isDisabled() ? '#9ca3af' : '#374151',\n 'font-size': '0.875rem',\n transition: 'background-color 150ms ease'\n }}\n onClick={() => {\n if (!isDisabled()) {\n props.onSelect(option)\n }\n }}\n onMouseEnter={() => {\n if (!isDisabled()) {\n props.onHover?.(index())\n }\n }}\n >\n <Show\n when={props.renderOption}\n fallback={\n <DefaultOptionRenderer\n option={option}\n isSelected={isSelected()}\n highlightMatch={props.highlightMatch}\n />\n }\n >\n {props.renderOption!(option, isSelected())}\n </Show>\n </li>\n )\n }}\n </For>\n </ul>\n </Show>\n\n {/* Footer hint */}\n <Show when={!props.isLoading && props.options.length > 0}>\n <div\n class=\"mcp-autocomplete-footer\"\n style={{\n padding: '6px 12px',\n 'border-top': '1px solid #e5e7eb',\n 'background-color': '#f9fafb',\n 'font-size': '0.75rem',\n color: '#6b7280'\n }}\n >\n <kbd style={{\n 'background-color': '#e5e7eb',\n padding: '1px 4px',\n 'border-radius': '2px',\n 'font-family': 'inherit',\n 'font-size': '0.7rem'\n }}>↑</kbd>\n {' '}\n <kbd style={{\n 'background-color': '#e5e7eb',\n padding: '1px 4px',\n 'border-radius': '2px',\n 'font-family': 'inherit',\n 'font-size': '0.7rem'\n }}>↓</kbd>\n {' to navigate, '}\n <kbd style={{\n 'background-color': '#e5e7eb',\n padding: '1px 4px',\n 'border-radius': '2px',\n 'font-family': 'inherit',\n 'font-size': '0.7rem'\n }}>Enter</kbd>\n {' to select, '}\n <kbd style={{\n 'background-color': '#e5e7eb',\n padding: '1px 4px',\n 'border-radius': '2px',\n 'font-family': 'inherit',\n 'font-size': '0.7rem'\n }}>Esc</kbd>\n {' to dismiss'}\n </div>\n </Show>\n </div>\n </Show>\n )\n}\n\nexport default AutocompleteDropdown\n"],"names":["highlightText","text","match","lowerText","toLowerCase","lowerMatch","startIndex","indexOf","before","slice","matched","length","after","_el$","_$getNextElement","_tmpl$","_$insert","DefaultOptionRenderer","props","displayLabel","createMemo","option","label","value","_el$2","_tmpl$4","_el$9","firstChild","_el$0","_co$2","_$getNextMarker","nextSibling","_el$4","_el$5","_el$7","_el$8","_co$","_$createComponent","Show","when","icon","children","_el$3","_tmpl$2","highlightMatch","description","_el$6","_tmpl$3","AutocompleteDropdown","positionStyles","position","bottom","top","containerStyles","left","right","border","maxHeight","overflow","isOpen","_el$1","_tmpl$9","_el$24","_el$25","_co$4","_el$26","_el$27","_co$5","_el$28","_el$29","_co$6","_el$30","_el$31","_co$7","isLoading","_el$10","_tmpl$5","_el$11","_el$12","_el$13","_co$3","loadingMessage","_$memo","options","_el$14","_tmpl$6","emptyMessage","_el$15","_tmpl$7","For","each","index","isSelected","selectedIndex","isDisabled","disabled","_el$32","_tmpl$0","addEventListener","onHover","$$click","onSelect","renderOption","fallback","_$effect","_p$","_v$3","_v$4","_v$5","_v$6","_v$7","_v$8","e","_$setAttribute","t","a","_$className","o","_$setStyleProperty","i","n","undefined","_$runHydrationEvents","_el$16","_tmpl$8","_el$17","_el$18","_el$19","_el$20","_el$21","_el$22","_v$","class","_v$2","_$style","_$delegateEvents"],"mappings":"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"}
|