@seed-ship/mcp-ui-solid 2.0.1 → 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/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/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/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
|
@@ -0,0 +1,262 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* GhostText Component
|
|
3
|
+
* Displays LLM-style ghost text completion overlay
|
|
4
|
+
*
|
|
5
|
+
* Sprint Autocomplete Feature
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
import { Component, Show, JSX, createMemo } from 'solid-js'
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* Props for GhostText component
|
|
12
|
+
*/
|
|
13
|
+
export interface GhostTextProps {
|
|
14
|
+
/**
|
|
15
|
+
* Current input value
|
|
16
|
+
*/
|
|
17
|
+
inputValue: string
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* Ghost text to show (the completion after input)
|
|
21
|
+
*/
|
|
22
|
+
ghostText: string
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* Whether ghost text is visible
|
|
26
|
+
*/
|
|
27
|
+
visible?: boolean
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* Custom class for the container
|
|
31
|
+
*/
|
|
32
|
+
class?: string
|
|
33
|
+
|
|
34
|
+
/**
|
|
35
|
+
* Custom class for the ghost text
|
|
36
|
+
*/
|
|
37
|
+
ghostClass?: string
|
|
38
|
+
|
|
39
|
+
/**
|
|
40
|
+
* Accept hint text (e.g., "Tab to accept")
|
|
41
|
+
*/
|
|
42
|
+
hintText?: string
|
|
43
|
+
|
|
44
|
+
/**
|
|
45
|
+
* Whether loading
|
|
46
|
+
*/
|
|
47
|
+
isLoading?: boolean
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
/**
|
|
51
|
+
* GhostText Component
|
|
52
|
+
* Overlays ghost text on an input field to show completion suggestions
|
|
53
|
+
*/
|
|
54
|
+
export const GhostText: Component<GhostTextProps> = (props) => {
|
|
55
|
+
const shouldShow = createMemo(() =>
|
|
56
|
+
props.visible !== false && props.ghostText && props.ghostText.length > 0
|
|
57
|
+
)
|
|
58
|
+
|
|
59
|
+
return (
|
|
60
|
+
<div
|
|
61
|
+
class={`mcp-ghost-text-container ${props.class || ''}`}
|
|
62
|
+
style={{
|
|
63
|
+
position: 'relative',
|
|
64
|
+
display: 'inline-block',
|
|
65
|
+
width: '100%'
|
|
66
|
+
}}
|
|
67
|
+
>
|
|
68
|
+
{/* Ghost text overlay */}
|
|
69
|
+
<Show when={shouldShow()}>
|
|
70
|
+
<div
|
|
71
|
+
class="mcp-ghost-text-overlay"
|
|
72
|
+
style={{
|
|
73
|
+
position: 'absolute',
|
|
74
|
+
top: '0',
|
|
75
|
+
left: '0',
|
|
76
|
+
right: '0',
|
|
77
|
+
bottom: '0',
|
|
78
|
+
'pointer-events': 'none',
|
|
79
|
+
overflow: 'hidden',
|
|
80
|
+
'white-space': 'pre',
|
|
81
|
+
padding: 'inherit',
|
|
82
|
+
font: 'inherit',
|
|
83
|
+
'line-height': 'inherit',
|
|
84
|
+
'letter-spacing': 'inherit'
|
|
85
|
+
}}
|
|
86
|
+
aria-hidden="true"
|
|
87
|
+
>
|
|
88
|
+
{/* Invisible placeholder for input text */}
|
|
89
|
+
<span style={{ visibility: 'hidden' }}>{props.inputValue}</span>
|
|
90
|
+
{/* Visible ghost text */}
|
|
91
|
+
<span
|
|
92
|
+
class={`mcp-ghost-text ${props.ghostClass || ''}`}
|
|
93
|
+
style={{
|
|
94
|
+
color: '#9ca3af',
|
|
95
|
+
opacity: '0.7'
|
|
96
|
+
}}
|
|
97
|
+
>
|
|
98
|
+
{props.ghostText}
|
|
99
|
+
</span>
|
|
100
|
+
</div>
|
|
101
|
+
</Show>
|
|
102
|
+
|
|
103
|
+
{/* Hint text */}
|
|
104
|
+
<Show when={shouldShow() && props.hintText}>
|
|
105
|
+
<div
|
|
106
|
+
class="mcp-ghost-text-hint"
|
|
107
|
+
style={{
|
|
108
|
+
position: 'absolute',
|
|
109
|
+
right: '8px',
|
|
110
|
+
top: '50%',
|
|
111
|
+
transform: 'translateY(-50%)',
|
|
112
|
+
'font-size': '0.75rem',
|
|
113
|
+
color: '#6b7280',
|
|
114
|
+
'background-color': 'rgba(255, 255, 255, 0.9)',
|
|
115
|
+
padding: '2px 6px',
|
|
116
|
+
'border-radius': '4px',
|
|
117
|
+
'pointer-events': 'none'
|
|
118
|
+
}}
|
|
119
|
+
>
|
|
120
|
+
{props.hintText}
|
|
121
|
+
</div>
|
|
122
|
+
</Show>
|
|
123
|
+
|
|
124
|
+
{/* Loading indicator */}
|
|
125
|
+
<Show when={props.isLoading}>
|
|
126
|
+
<div
|
|
127
|
+
class="mcp-ghost-text-loading"
|
|
128
|
+
style={{
|
|
129
|
+
position: 'absolute',
|
|
130
|
+
right: '8px',
|
|
131
|
+
top: '50%',
|
|
132
|
+
transform: 'translateY(-50%)'
|
|
133
|
+
}}
|
|
134
|
+
>
|
|
135
|
+
<span
|
|
136
|
+
style={{
|
|
137
|
+
display: 'inline-block',
|
|
138
|
+
width: '12px',
|
|
139
|
+
height: '12px',
|
|
140
|
+
border: '2px solid #e5e7eb',
|
|
141
|
+
'border-top-color': '#3b82f6',
|
|
142
|
+
'border-radius': '50%',
|
|
143
|
+
animation: 'mcp-spin 0.6s linear infinite'
|
|
144
|
+
}}
|
|
145
|
+
/>
|
|
146
|
+
</div>
|
|
147
|
+
</Show>
|
|
148
|
+
</div>
|
|
149
|
+
)
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
/**
|
|
153
|
+
* Input wrapper that includes ghost text functionality
|
|
154
|
+
*/
|
|
155
|
+
export interface GhostTextInputProps {
|
|
156
|
+
/**
|
|
157
|
+
* Current input value
|
|
158
|
+
*/
|
|
159
|
+
value: string
|
|
160
|
+
|
|
161
|
+
/**
|
|
162
|
+
* Ghost text to show
|
|
163
|
+
*/
|
|
164
|
+
ghostText: string
|
|
165
|
+
|
|
166
|
+
/**
|
|
167
|
+
* onChange handler
|
|
168
|
+
*/
|
|
169
|
+
onInput?: (value: string) => void
|
|
170
|
+
|
|
171
|
+
/**
|
|
172
|
+
* onKeyDown handler
|
|
173
|
+
*/
|
|
174
|
+
onKeyDown?: (e: KeyboardEvent) => void
|
|
175
|
+
|
|
176
|
+
/**
|
|
177
|
+
* Placeholder text
|
|
178
|
+
*/
|
|
179
|
+
placeholder?: string
|
|
180
|
+
|
|
181
|
+
/**
|
|
182
|
+
* Input type
|
|
183
|
+
*/
|
|
184
|
+
type?: 'text' | 'email' | 'search'
|
|
185
|
+
|
|
186
|
+
/**
|
|
187
|
+
* Whether input is disabled
|
|
188
|
+
*/
|
|
189
|
+
disabled?: boolean
|
|
190
|
+
|
|
191
|
+
/**
|
|
192
|
+
* Input name
|
|
193
|
+
*/
|
|
194
|
+
name?: string
|
|
195
|
+
|
|
196
|
+
/**
|
|
197
|
+
* Input ID
|
|
198
|
+
*/
|
|
199
|
+
id?: string
|
|
200
|
+
|
|
201
|
+
/**
|
|
202
|
+
* Custom class for input
|
|
203
|
+
*/
|
|
204
|
+
class?: string
|
|
205
|
+
|
|
206
|
+
/**
|
|
207
|
+
* Accept hint
|
|
208
|
+
*/
|
|
209
|
+
hintText?: string
|
|
210
|
+
|
|
211
|
+
/**
|
|
212
|
+
* Whether loading
|
|
213
|
+
*/
|
|
214
|
+
isLoading?: boolean
|
|
215
|
+
|
|
216
|
+
/**
|
|
217
|
+
* Whether ghost text is visible
|
|
218
|
+
*/
|
|
219
|
+
showGhost?: boolean
|
|
220
|
+
|
|
221
|
+
/**
|
|
222
|
+
* Additional input attributes
|
|
223
|
+
*/
|
|
224
|
+
inputProps?: JSX.InputHTMLAttributes<HTMLInputElement>
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
/**
|
|
228
|
+
* GhostTextInput Component
|
|
229
|
+
* Input field with integrated ghost text overlay
|
|
230
|
+
*/
|
|
231
|
+
export const GhostTextInput: Component<GhostTextInputProps> = (props) => {
|
|
232
|
+
return (
|
|
233
|
+
<div class="mcp-ghost-text-input-wrapper" style={{ position: 'relative' }}>
|
|
234
|
+
<GhostText
|
|
235
|
+
inputValue={props.value}
|
|
236
|
+
ghostText={props.ghostText}
|
|
237
|
+
visible={props.showGhost}
|
|
238
|
+
hintText={props.hintText}
|
|
239
|
+
isLoading={props.isLoading}
|
|
240
|
+
/>
|
|
241
|
+
<input
|
|
242
|
+
type={props.type || 'text'}
|
|
243
|
+
id={props.id}
|
|
244
|
+
name={props.name}
|
|
245
|
+
value={props.value}
|
|
246
|
+
placeholder={props.placeholder}
|
|
247
|
+
disabled={props.disabled}
|
|
248
|
+
class={`mcp-ghost-text-input ${props.class || ''}`}
|
|
249
|
+
style={{
|
|
250
|
+
position: 'relative',
|
|
251
|
+
'background-color': 'transparent',
|
|
252
|
+
'caret-color': 'inherit'
|
|
253
|
+
}}
|
|
254
|
+
onInput={(e) => props.onInput?.(e.currentTarget.value)}
|
|
255
|
+
onKeyDown={(e) => props.onKeyDown?.(e)}
|
|
256
|
+
{...(props.inputProps || {})}
|
|
257
|
+
/>
|
|
258
|
+
</div>
|
|
259
|
+
)
|
|
260
|
+
}
|
|
261
|
+
|
|
262
|
+
export default GhostText
|
|
@@ -0,0 +1,262 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* ResizeHandle Component
|
|
3
|
+
* Visual handle for resizing grid components
|
|
4
|
+
*
|
|
5
|
+
* Sprint Drag-Drop Feature
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
import { Component, JSX, createMemo, mergeProps } from 'solid-js'
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* Resize edge types
|
|
12
|
+
*/
|
|
13
|
+
export type ResizeEdge = 'left' | 'right' | 'top' | 'bottom'
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* Props for ResizeHandle
|
|
17
|
+
*/
|
|
18
|
+
export interface ResizeHandleProps {
|
|
19
|
+
/**
|
|
20
|
+
* Which edge this handle is on
|
|
21
|
+
*/
|
|
22
|
+
edge: ResizeEdge
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* Callback when resize starts
|
|
26
|
+
*/
|
|
27
|
+
onResizeStart?: (edge: ResizeEdge) => void
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* Whether the handle is disabled
|
|
31
|
+
*/
|
|
32
|
+
disabled?: boolean
|
|
33
|
+
|
|
34
|
+
/**
|
|
35
|
+
* Whether resize is active
|
|
36
|
+
*/
|
|
37
|
+
isActive?: boolean
|
|
38
|
+
|
|
39
|
+
/**
|
|
40
|
+
* Custom class
|
|
41
|
+
*/
|
|
42
|
+
class?: string
|
|
43
|
+
|
|
44
|
+
/**
|
|
45
|
+
* Handle size in pixels
|
|
46
|
+
*/
|
|
47
|
+
size?: number
|
|
48
|
+
|
|
49
|
+
/**
|
|
50
|
+
* Hit area size in pixels (larger than visible size for easier grabbing)
|
|
51
|
+
*/
|
|
52
|
+
hitAreaSize?: number
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
/**
|
|
56
|
+
* Get cursor style for edge
|
|
57
|
+
*/
|
|
58
|
+
function getCursor(edge: ResizeEdge): string {
|
|
59
|
+
switch (edge) {
|
|
60
|
+
case 'left':
|
|
61
|
+
case 'right':
|
|
62
|
+
return 'ew-resize'
|
|
63
|
+
case 'top':
|
|
64
|
+
case 'bottom':
|
|
65
|
+
return 'ns-resize'
|
|
66
|
+
default:
|
|
67
|
+
return 'default'
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
/**
|
|
72
|
+
* Get position styles for edge
|
|
73
|
+
*/
|
|
74
|
+
function getPositionStyle(
|
|
75
|
+
edge: ResizeEdge,
|
|
76
|
+
hitAreaSize: number
|
|
77
|
+
): JSX.CSSProperties {
|
|
78
|
+
const halfSize = hitAreaSize / 2
|
|
79
|
+
|
|
80
|
+
switch (edge) {
|
|
81
|
+
case 'left':
|
|
82
|
+
return {
|
|
83
|
+
left: `-${halfSize}px`,
|
|
84
|
+
top: '0',
|
|
85
|
+
width: `${hitAreaSize}px`,
|
|
86
|
+
height: '100%'
|
|
87
|
+
}
|
|
88
|
+
case 'right':
|
|
89
|
+
return {
|
|
90
|
+
right: `-${halfSize}px`,
|
|
91
|
+
top: '0',
|
|
92
|
+
width: `${hitAreaSize}px`,
|
|
93
|
+
height: '100%'
|
|
94
|
+
}
|
|
95
|
+
case 'top':
|
|
96
|
+
return {
|
|
97
|
+
top: `-${halfSize}px`,
|
|
98
|
+
left: '0',
|
|
99
|
+
width: '100%',
|
|
100
|
+
height: `${hitAreaSize}px`
|
|
101
|
+
}
|
|
102
|
+
case 'bottom':
|
|
103
|
+
return {
|
|
104
|
+
bottom: `-${halfSize}px`,
|
|
105
|
+
left: '0',
|
|
106
|
+
width: '100%',
|
|
107
|
+
height: `${hitAreaSize}px`
|
|
108
|
+
}
|
|
109
|
+
default:
|
|
110
|
+
return {}
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
/**
|
|
115
|
+
* Get visual indicator styles for edge
|
|
116
|
+
*/
|
|
117
|
+
function getIndicatorStyle(
|
|
118
|
+
edge: ResizeEdge,
|
|
119
|
+
size: number,
|
|
120
|
+
isActive: boolean
|
|
121
|
+
): JSX.CSSProperties {
|
|
122
|
+
const baseColor = isActive ? '#3b82f6' : '#9ca3af'
|
|
123
|
+
|
|
124
|
+
const common: JSX.CSSProperties = {
|
|
125
|
+
position: 'absolute',
|
|
126
|
+
'background-color': baseColor,
|
|
127
|
+
'border-radius': `${size / 2}px`,
|
|
128
|
+
transition: 'background-color 150ms ease, opacity 150ms ease',
|
|
129
|
+
opacity: isActive ? '1' : '0'
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
switch (edge) {
|
|
133
|
+
case 'left':
|
|
134
|
+
return {
|
|
135
|
+
...common,
|
|
136
|
+
left: '50%',
|
|
137
|
+
top: '50%',
|
|
138
|
+
transform: 'translate(-50%, -50%)',
|
|
139
|
+
width: `${size}px`,
|
|
140
|
+
height: '40px',
|
|
141
|
+
'max-height': '60%'
|
|
142
|
+
}
|
|
143
|
+
case 'right':
|
|
144
|
+
return {
|
|
145
|
+
...common,
|
|
146
|
+
right: '50%',
|
|
147
|
+
top: '50%',
|
|
148
|
+
transform: 'translate(50%, -50%)',
|
|
149
|
+
width: `${size}px`,
|
|
150
|
+
height: '40px',
|
|
151
|
+
'max-height': '60%'
|
|
152
|
+
}
|
|
153
|
+
case 'top':
|
|
154
|
+
return {
|
|
155
|
+
...common,
|
|
156
|
+
top: '50%',
|
|
157
|
+
left: '50%',
|
|
158
|
+
transform: 'translate(-50%, -50%)',
|
|
159
|
+
width: '40px',
|
|
160
|
+
'max-width': '60%',
|
|
161
|
+
height: `${size}px`
|
|
162
|
+
}
|
|
163
|
+
case 'bottom':
|
|
164
|
+
return {
|
|
165
|
+
...common,
|
|
166
|
+
bottom: '50%',
|
|
167
|
+
left: '50%',
|
|
168
|
+
transform: 'translate(-50%, 50%)',
|
|
169
|
+
width: '40px',
|
|
170
|
+
'max-width': '60%',
|
|
171
|
+
height: `${size}px`
|
|
172
|
+
}
|
|
173
|
+
default:
|
|
174
|
+
return common
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
/**
|
|
179
|
+
* ResizeHandle Component
|
|
180
|
+
*/
|
|
181
|
+
export const ResizeHandle: Component<ResizeHandleProps> = (props) => {
|
|
182
|
+
const merged = mergeProps(
|
|
183
|
+
{
|
|
184
|
+
disabled: false,
|
|
185
|
+
isActive: false,
|
|
186
|
+
size: 4,
|
|
187
|
+
hitAreaSize: 12
|
|
188
|
+
},
|
|
189
|
+
props
|
|
190
|
+
)
|
|
191
|
+
|
|
192
|
+
const handlePointerDown = (e: PointerEvent) => {
|
|
193
|
+
if (merged.disabled) return
|
|
194
|
+
|
|
195
|
+
e.preventDefault()
|
|
196
|
+
e.stopPropagation()
|
|
197
|
+
|
|
198
|
+
props.onResizeStart?.(props.edge)
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
// Container styles
|
|
202
|
+
const containerStyle = createMemo((): JSX.CSSProperties => ({
|
|
203
|
+
position: 'absolute',
|
|
204
|
+
'z-index': '10',
|
|
205
|
+
cursor: merged.disabled ? 'default' : getCursor(props.edge),
|
|
206
|
+
'user-select': 'none',
|
|
207
|
+
'touch-action': 'none',
|
|
208
|
+
...getPositionStyle(props.edge, merged.hitAreaSize)
|
|
209
|
+
}))
|
|
210
|
+
|
|
211
|
+
// Indicator styles
|
|
212
|
+
const indicatorStyle = createMemo(() =>
|
|
213
|
+
getIndicatorStyle(props.edge, merged.size, merged.isActive)
|
|
214
|
+
)
|
|
215
|
+
|
|
216
|
+
// Class names
|
|
217
|
+
const classNames = createMemo(() => {
|
|
218
|
+
const classes = [
|
|
219
|
+
'mcp-resize-handle',
|
|
220
|
+
`mcp-resize-handle-${props.edge}`
|
|
221
|
+
]
|
|
222
|
+
|
|
223
|
+
if (merged.disabled) classes.push('mcp-resize-handle-disabled')
|
|
224
|
+
if (merged.isActive) classes.push('mcp-resize-handle-active')
|
|
225
|
+
if (props.class) classes.push(props.class)
|
|
226
|
+
|
|
227
|
+
return classes.join(' ')
|
|
228
|
+
})
|
|
229
|
+
|
|
230
|
+
return (
|
|
231
|
+
<div
|
|
232
|
+
class={classNames()}
|
|
233
|
+
style={containerStyle()}
|
|
234
|
+
onPointerDown={handlePointerDown}
|
|
235
|
+
data-resize-edge={props.edge}
|
|
236
|
+
role="separator"
|
|
237
|
+
aria-orientation={
|
|
238
|
+
props.edge === 'left' || props.edge === 'right'
|
|
239
|
+
? 'vertical'
|
|
240
|
+
: 'horizontal'
|
|
241
|
+
}
|
|
242
|
+
aria-valuenow={undefined}
|
|
243
|
+
tabIndex={merged.disabled ? -1 : 0}
|
|
244
|
+
onKeyDown={(e) => {
|
|
245
|
+
// Allow keyboard resizing
|
|
246
|
+
if (merged.disabled) return
|
|
247
|
+
if (e.key === 'Enter' || e.key === ' ') {
|
|
248
|
+
e.preventDefault()
|
|
249
|
+
props.onResizeStart?.(props.edge)
|
|
250
|
+
}
|
|
251
|
+
}}
|
|
252
|
+
>
|
|
253
|
+
{/* Visual indicator */}
|
|
254
|
+
<div
|
|
255
|
+
class="mcp-resize-indicator"
|
|
256
|
+
style={indicatorStyle()}
|
|
257
|
+
/>
|
|
258
|
+
</div>
|
|
259
|
+
)
|
|
260
|
+
}
|
|
261
|
+
|
|
262
|
+
export default ResizeHandle
|