@seed-ship/mcp-ui-solid 2.0.1 → 2.1.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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 +199 -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 +199 -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 +177 -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 +177 -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 +242 -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 +242 -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/esbuild-why-Full bundle (with deps).html +51 -0
- package/esbuild-why-Hooks only.html +51 -0
- package/esbuild-why-Streaming renderer.html +51 -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 +268 -0
- package/src/components/GhostText.tsx +262 -0
- package/src/components/ResizeHandle.tsx +267 -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 +482 -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,274 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* DraggableGridItem Component
|
|
3
|
+
* Wrapper for grid items that enables drag-and-drop reordering and resizing
|
|
4
|
+
*
|
|
5
|
+
* Sprint Drag-Drop Feature
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
import { Component, JSX, Show, createMemo, mergeProps } from 'solid-js'
|
|
9
|
+
import type { GridPosition, ResizeConstraints } from '../types'
|
|
10
|
+
import { ResizeHandle } from './ResizeHandle'
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* Props for DraggableGridItem
|
|
14
|
+
*/
|
|
15
|
+
export interface DraggableGridItemProps {
|
|
16
|
+
/**
|
|
17
|
+
* Component ID
|
|
18
|
+
*/
|
|
19
|
+
id: string
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* Grid position
|
|
23
|
+
*/
|
|
24
|
+
position: GridPosition
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* Whether dragging is enabled
|
|
28
|
+
*/
|
|
29
|
+
draggable?: boolean
|
|
30
|
+
|
|
31
|
+
/**
|
|
32
|
+
* Whether resizing is enabled
|
|
33
|
+
*/
|
|
34
|
+
resizable?: boolean
|
|
35
|
+
|
|
36
|
+
/**
|
|
37
|
+
* Resize constraints
|
|
38
|
+
*/
|
|
39
|
+
constraints?: ResizeConstraints
|
|
40
|
+
|
|
41
|
+
/**
|
|
42
|
+
* Whether this item is currently being dragged
|
|
43
|
+
*/
|
|
44
|
+
isDragging?: boolean
|
|
45
|
+
|
|
46
|
+
/**
|
|
47
|
+
* Whether this item is a drop target
|
|
48
|
+
*/
|
|
49
|
+
isDropTarget?: boolean
|
|
50
|
+
|
|
51
|
+
/**
|
|
52
|
+
* Preview position during resize
|
|
53
|
+
*/
|
|
54
|
+
previewPosition?: GridPosition | null
|
|
55
|
+
|
|
56
|
+
/**
|
|
57
|
+
* Drag props from useDragDrop
|
|
58
|
+
*/
|
|
59
|
+
dragProps?: {
|
|
60
|
+
draggable: boolean
|
|
61
|
+
onDragStart: (e: DragEvent) => void
|
|
62
|
+
onDragOver: (e: DragEvent) => void
|
|
63
|
+
onDragEnter: (e: DragEvent) => void
|
|
64
|
+
onDragLeave: (e: DragEvent) => void
|
|
65
|
+
onDrop: (e: DragEvent) => void
|
|
66
|
+
onDragEnd: (e: DragEvent) => void
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
/**
|
|
70
|
+
* Callback when resize starts
|
|
71
|
+
*/
|
|
72
|
+
onResizeStart?: (edge: 'left' | 'right' | 'top' | 'bottom', event: PointerEvent) => void
|
|
73
|
+
|
|
74
|
+
/**
|
|
75
|
+
* Callback for resize preview
|
|
76
|
+
*/
|
|
77
|
+
onResizePreview?: (position: GridPosition) => void
|
|
78
|
+
|
|
79
|
+
/**
|
|
80
|
+
* Callback when resize completes
|
|
81
|
+
*/
|
|
82
|
+
onResize?: (position: GridPosition) => void
|
|
83
|
+
|
|
84
|
+
/**
|
|
85
|
+
* Whether resize is in progress
|
|
86
|
+
*/
|
|
87
|
+
isResizing?: boolean
|
|
88
|
+
|
|
89
|
+
/**
|
|
90
|
+
* Show grid overlay during drag/resize
|
|
91
|
+
*/
|
|
92
|
+
showGridOverlay?: boolean
|
|
93
|
+
|
|
94
|
+
/**
|
|
95
|
+
* Custom CSS class
|
|
96
|
+
*/
|
|
97
|
+
class?: string
|
|
98
|
+
|
|
99
|
+
/**
|
|
100
|
+
* Custom styles
|
|
101
|
+
*/
|
|
102
|
+
style?: JSX.CSSProperties
|
|
103
|
+
|
|
104
|
+
/**
|
|
105
|
+
* Children to render
|
|
106
|
+
*/
|
|
107
|
+
children?: JSX.Element
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
/**
|
|
111
|
+
* Generate CSS Grid style string from position
|
|
112
|
+
*/
|
|
113
|
+
function getGridStyle(position: GridPosition): JSX.CSSProperties {
|
|
114
|
+
return {
|
|
115
|
+
'grid-column': `${position.colStart} / span ${position.colSpan}`,
|
|
116
|
+
'grid-row': position.rowStart
|
|
117
|
+
? `${position.rowStart} / span ${position.rowSpan || 1}`
|
|
118
|
+
: undefined
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
/**
|
|
123
|
+
* DraggableGridItem Component
|
|
124
|
+
*/
|
|
125
|
+
export const DraggableGridItem: Component<DraggableGridItemProps> = (props) => {
|
|
126
|
+
const merged = mergeProps(
|
|
127
|
+
{
|
|
128
|
+
draggable: false,
|
|
129
|
+
resizable: false,
|
|
130
|
+
isDragging: false,
|
|
131
|
+
isDropTarget: false,
|
|
132
|
+
isResizing: false,
|
|
133
|
+
showGridOverlay: false
|
|
134
|
+
},
|
|
135
|
+
props
|
|
136
|
+
)
|
|
137
|
+
|
|
138
|
+
// Use preview position during resize if available
|
|
139
|
+
const effectivePosition = createMemo(() =>
|
|
140
|
+
merged.previewPosition || props.position
|
|
141
|
+
)
|
|
142
|
+
|
|
143
|
+
// Compute grid style
|
|
144
|
+
const gridStyle = createMemo(() => getGridStyle(effectivePosition()))
|
|
145
|
+
|
|
146
|
+
// Compute combined style
|
|
147
|
+
const combinedStyle = createMemo((): JSX.CSSProperties => {
|
|
148
|
+
const base: JSX.CSSProperties = {
|
|
149
|
+
...gridStyle(),
|
|
150
|
+
position: 'relative',
|
|
151
|
+
transition: merged.isResizing ? 'none' : 'all 200ms ease-out'
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
// Add drag/drop visual feedback
|
|
155
|
+
if (merged.isDragging) {
|
|
156
|
+
base.opacity = '0.5'
|
|
157
|
+
base.transform = 'scale(1.02)'
|
|
158
|
+
base['z-index'] = '100'
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
if (merged.isDropTarget && !merged.isDragging) {
|
|
162
|
+
base['box-shadow'] = '0 0 0 2px #3b82f6'
|
|
163
|
+
base['border-radius'] = '4px'
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
if (merged.isResizing) {
|
|
167
|
+
base['z-index'] = '100'
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
// Merge with custom styles
|
|
171
|
+
if (props.style) {
|
|
172
|
+
Object.assign(base, props.style)
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
return base
|
|
176
|
+
})
|
|
177
|
+
|
|
178
|
+
// Build class names
|
|
179
|
+
const classNames = createMemo(() => {
|
|
180
|
+
const classes = ['mcp-draggable-grid-item']
|
|
181
|
+
|
|
182
|
+
if (merged.draggable) classes.push('mcp-draggable')
|
|
183
|
+
if (merged.resizable) classes.push('mcp-resizable')
|
|
184
|
+
if (merged.isDragging) classes.push('mcp-dragging')
|
|
185
|
+
if (merged.isDropTarget) classes.push('mcp-drop-target')
|
|
186
|
+
if (merged.isResizing) classes.push('mcp-resizing')
|
|
187
|
+
if (props.class) classes.push(props.class)
|
|
188
|
+
|
|
189
|
+
return classes.join(' ')
|
|
190
|
+
})
|
|
191
|
+
|
|
192
|
+
// Handle resize start
|
|
193
|
+
const handleResizeStart = (edge: 'left' | 'right' | 'top' | 'bottom', event: PointerEvent) => {
|
|
194
|
+
props.onResizeStart?.(edge, event)
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
return (
|
|
198
|
+
<div
|
|
199
|
+
class={classNames()}
|
|
200
|
+
style={combinedStyle()}
|
|
201
|
+
data-component-id={props.id}
|
|
202
|
+
{...(merged.draggable && props.dragProps ? props.dragProps : {})}
|
|
203
|
+
>
|
|
204
|
+
{/* Drag handle indicator */}
|
|
205
|
+
<Show when={merged.draggable && !merged.isResizing}>
|
|
206
|
+
<div
|
|
207
|
+
class="mcp-drag-handle"
|
|
208
|
+
style={{
|
|
209
|
+
position: 'absolute',
|
|
210
|
+
top: '4px',
|
|
211
|
+
left: '50%',
|
|
212
|
+
transform: 'translateX(-50%)',
|
|
213
|
+
width: '40px',
|
|
214
|
+
height: '4px',
|
|
215
|
+
'background-color': 'rgba(0, 0, 0, 0.2)',
|
|
216
|
+
'border-radius': '2px',
|
|
217
|
+
cursor: 'grab',
|
|
218
|
+
opacity: '0',
|
|
219
|
+
transition: 'opacity 150ms ease',
|
|
220
|
+
'z-index': '5'
|
|
221
|
+
}}
|
|
222
|
+
/>
|
|
223
|
+
</Show>
|
|
224
|
+
|
|
225
|
+
{/* Resize handles */}
|
|
226
|
+
<Show when={merged.resizable && !merged.isDragging}>
|
|
227
|
+
<ResizeHandle
|
|
228
|
+
edge="left"
|
|
229
|
+
onResizeStart={handleResizeStart}
|
|
230
|
+
disabled={merged.constraints?.lockHorizontal}
|
|
231
|
+
/>
|
|
232
|
+
<ResizeHandle
|
|
233
|
+
edge="right"
|
|
234
|
+
onResizeStart={handleResizeStart}
|
|
235
|
+
disabled={merged.constraints?.lockHorizontal}
|
|
236
|
+
/>
|
|
237
|
+
<ResizeHandle
|
|
238
|
+
edge="top"
|
|
239
|
+
onResizeStart={handleResizeStart}
|
|
240
|
+
disabled={merged.constraints?.lockVertical}
|
|
241
|
+
/>
|
|
242
|
+
<ResizeHandle
|
|
243
|
+
edge="bottom"
|
|
244
|
+
onResizeStart={handleResizeStart}
|
|
245
|
+
disabled={merged.constraints?.lockVertical}
|
|
246
|
+
/>
|
|
247
|
+
</Show>
|
|
248
|
+
|
|
249
|
+
{/* Drop indicator line */}
|
|
250
|
+
<Show when={merged.isDropTarget && !merged.isDragging}>
|
|
251
|
+
<div
|
|
252
|
+
class="mcp-drop-indicator"
|
|
253
|
+
style={{
|
|
254
|
+
position: 'absolute',
|
|
255
|
+
top: '-2px',
|
|
256
|
+
left: '0',
|
|
257
|
+
right: '0',
|
|
258
|
+
height: '4px',
|
|
259
|
+
'background-color': '#3b82f6',
|
|
260
|
+
'border-radius': '2px',
|
|
261
|
+
'z-index': '20'
|
|
262
|
+
}}
|
|
263
|
+
/>
|
|
264
|
+
</Show>
|
|
265
|
+
|
|
266
|
+
{/* Content */}
|
|
267
|
+
<div class="mcp-grid-item-content" style={{ position: 'relative', 'z-index': '1' }}>
|
|
268
|
+
{props.children}
|
|
269
|
+
</div>
|
|
270
|
+
</div>
|
|
271
|
+
)
|
|
272
|
+
}
|
|
273
|
+
|
|
274
|
+
export default DraggableGridItem
|
|
@@ -0,0 +1,268 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* EditableUIResourceRenderer Component
|
|
3
|
+
* Extends UIResourceRenderer with drag-and-drop reordering and resizing capabilities
|
|
4
|
+
*
|
|
5
|
+
* Sprint Drag-Drop Feature
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
import {
|
|
9
|
+
Component,
|
|
10
|
+
For,
|
|
11
|
+
Show,
|
|
12
|
+
createSignal,
|
|
13
|
+
createMemo,
|
|
14
|
+
createEffect,
|
|
15
|
+
on,
|
|
16
|
+
JSX
|
|
17
|
+
} from 'solid-js'
|
|
18
|
+
import type {
|
|
19
|
+
UIComponent,
|
|
20
|
+
UILayout,
|
|
21
|
+
RendererError,
|
|
22
|
+
GridPosition,
|
|
23
|
+
DragDropConfig
|
|
24
|
+
} from '../types'
|
|
25
|
+
import { useDragDrop } from '../hooks/useDragDrop'
|
|
26
|
+
import { useResize, ResizeEdge } from '../hooks/useResize'
|
|
27
|
+
import { DraggableGridItem } from './DraggableGridItem'
|
|
28
|
+
import { UIResourceRenderer } from './UIResourceRenderer'
|
|
29
|
+
|
|
30
|
+
/**
|
|
31
|
+
* Props for EditableUIResourceRenderer
|
|
32
|
+
*/
|
|
33
|
+
export interface EditableUIResourceRendererProps {
|
|
34
|
+
/**
|
|
35
|
+
* Layout to render (must be UILayout, not single component)
|
|
36
|
+
*/
|
|
37
|
+
layout: UILayout
|
|
38
|
+
|
|
39
|
+
/**
|
|
40
|
+
* Drag-drop configuration
|
|
41
|
+
*/
|
|
42
|
+
dragDrop?: DragDropConfig
|
|
43
|
+
|
|
44
|
+
/**
|
|
45
|
+
* Error callback
|
|
46
|
+
*/
|
|
47
|
+
onError?: (error: RendererError) => void
|
|
48
|
+
|
|
49
|
+
/**
|
|
50
|
+
* Callback when layout changes (reorder or resize)
|
|
51
|
+
*/
|
|
52
|
+
onLayoutChange?: (layout: UILayout) => void
|
|
53
|
+
|
|
54
|
+
/**
|
|
55
|
+
* Custom CSS class
|
|
56
|
+
*/
|
|
57
|
+
class?: string
|
|
58
|
+
|
|
59
|
+
/**
|
|
60
|
+
* Show grid overlay during editing
|
|
61
|
+
*/
|
|
62
|
+
showGridOverlay?: boolean
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
/**
|
|
66
|
+
* Grid overlay component for visual feedback
|
|
67
|
+
*/
|
|
68
|
+
const GridOverlay: Component<{ columns: number; visible: boolean }> = (props) => {
|
|
69
|
+
return (
|
|
70
|
+
<Show when={props.visible}>
|
|
71
|
+
<div
|
|
72
|
+
class="mcp-grid-overlay"
|
|
73
|
+
style={{
|
|
74
|
+
position: 'absolute',
|
|
75
|
+
inset: '0',
|
|
76
|
+
display: 'grid',
|
|
77
|
+
'grid-template-columns': `repeat(${props.columns}, 1fr)`,
|
|
78
|
+
gap: '1rem',
|
|
79
|
+
padding: '0',
|
|
80
|
+
'pointer-events': 'none',
|
|
81
|
+
'z-index': '0'
|
|
82
|
+
}}
|
|
83
|
+
>
|
|
84
|
+
<For each={Array(props.columns).fill(0)}>
|
|
85
|
+
{() => (
|
|
86
|
+
<div
|
|
87
|
+
class="mcp-grid-overlay-column"
|
|
88
|
+
style={{
|
|
89
|
+
'background-color': 'rgba(59, 130, 246, 0.05)',
|
|
90
|
+
border: '1px dashed rgba(59, 130, 246, 0.2)',
|
|
91
|
+
'border-radius': '4px'
|
|
92
|
+
}}
|
|
93
|
+
/>
|
|
94
|
+
)}
|
|
95
|
+
</For>
|
|
96
|
+
</div>
|
|
97
|
+
</Show>
|
|
98
|
+
)
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
/**
|
|
102
|
+
* EditableUIResourceRenderer Component
|
|
103
|
+
*/
|
|
104
|
+
export const EditableUIResourceRenderer: Component<EditableUIResourceRendererProps> = (props) => {
|
|
105
|
+
// Internal state for components (allows editing)
|
|
106
|
+
const [components, setComponents] = createSignal<UIComponent[]>(props.layout.components)
|
|
107
|
+
const [activeResizeId, setActiveResizeId] = createSignal<string | null>(null)
|
|
108
|
+
const [previewPositions, setPreviewPositions] = createSignal<Map<string, GridPosition>>(new Map())
|
|
109
|
+
const [gridContainerRef, setGridContainerRef] = createSignal<HTMLElement | null>(null)
|
|
110
|
+
|
|
111
|
+
// Sync with external layout changes
|
|
112
|
+
createEffect(on(() => props.layout.components, (newComponents) => {
|
|
113
|
+
setComponents(newComponents)
|
|
114
|
+
}))
|
|
115
|
+
|
|
116
|
+
// Drag-drop configuration
|
|
117
|
+
const dragDropConfig = createMemo(() => ({
|
|
118
|
+
enabled: props.dragDrop?.enabled ?? false,
|
|
119
|
+
reorder: props.dragDrop?.reorder ?? true,
|
|
120
|
+
resize: props.dragDrop?.resize ?? true,
|
|
121
|
+
constraints: props.dragDrop?.constraints ?? {},
|
|
122
|
+
showGridLines: props.dragDrop?.showGridLines ?? true,
|
|
123
|
+
animationDuration: props.dragDrop?.animationDuration ?? 200
|
|
124
|
+
}))
|
|
125
|
+
|
|
126
|
+
// Handle reorder from drag-drop
|
|
127
|
+
const handleReorder = (newComponents: UIComponent[]) => {
|
|
128
|
+
setComponents(newComponents)
|
|
129
|
+
|
|
130
|
+
const newLayout: UILayout = {
|
|
131
|
+
...props.layout,
|
|
132
|
+
components: newComponents
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
props.dragDrop?.onReorder?.(newComponents)
|
|
136
|
+
props.dragDrop?.onChange?.(newLayout)
|
|
137
|
+
props.onLayoutChange?.(newLayout)
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
// Handle resize completion
|
|
141
|
+
const handleResize = (componentId: string, newPosition: GridPosition) => {
|
|
142
|
+
const updatedComponents = components().map(c =>
|
|
143
|
+
c.id === componentId ? { ...c, position: newPosition } : c
|
|
144
|
+
)
|
|
145
|
+
|
|
146
|
+
setComponents(updatedComponents)
|
|
147
|
+
setActiveResizeId(null)
|
|
148
|
+
setPreviewPositions(new Map())
|
|
149
|
+
|
|
150
|
+
const newLayout: UILayout = {
|
|
151
|
+
...props.layout,
|
|
152
|
+
components: updatedComponents
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
props.dragDrop?.onResize?.(componentId, newPosition)
|
|
156
|
+
props.dragDrop?.onChange?.(newLayout)
|
|
157
|
+
props.onLayoutChange?.(newLayout)
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
// Handle resize preview
|
|
161
|
+
const handleResizePreview = (componentId: string, previewPosition: GridPosition) => {
|
|
162
|
+
setPreviewPositions(prev => {
|
|
163
|
+
const next = new Map(prev)
|
|
164
|
+
next.set(componentId, previewPosition)
|
|
165
|
+
return next
|
|
166
|
+
})
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
// Initialize drag-drop hook
|
|
170
|
+
const dragDrop = useDragDrop({
|
|
171
|
+
components,
|
|
172
|
+
onReorder: handleReorder,
|
|
173
|
+
enabled: dragDropConfig().enabled && dragDropConfig().reorder
|
|
174
|
+
})
|
|
175
|
+
|
|
176
|
+
// Grid container style
|
|
177
|
+
const gridContainerStyle = createMemo((): JSX.CSSProperties => ({
|
|
178
|
+
display: 'grid',
|
|
179
|
+
'grid-template-columns': `repeat(${props.layout.grid.columns}, 1fr)`,
|
|
180
|
+
gap: props.layout.grid.gap,
|
|
181
|
+
position: 'relative'
|
|
182
|
+
}))
|
|
183
|
+
|
|
184
|
+
// Check if we should show grid overlay
|
|
185
|
+
const showOverlay = createMemo(() =>
|
|
186
|
+
dragDropConfig().showGridLines && (dragDrop.isDragging() || activeResizeId() !== null)
|
|
187
|
+
)
|
|
188
|
+
|
|
189
|
+
// Get effective position for a component (preview if resizing, otherwise actual)
|
|
190
|
+
const getEffectivePosition = (component: UIComponent): GridPosition => {
|
|
191
|
+
const preview = previewPositions().get(component.id)
|
|
192
|
+
return preview || component.position
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
// If drag-drop is not enabled, just render the standard UIResourceRenderer
|
|
196
|
+
if (!props.dragDrop?.enabled) {
|
|
197
|
+
return (
|
|
198
|
+
<UIResourceRenderer
|
|
199
|
+
content={props.layout}
|
|
200
|
+
onError={props.onError}
|
|
201
|
+
class={props.class}
|
|
202
|
+
/>
|
|
203
|
+
)
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
return (
|
|
207
|
+
<div class={`w-full editable-ui-renderer ${props.class || ''}`}>
|
|
208
|
+
<div
|
|
209
|
+
ref={setGridContainerRef}
|
|
210
|
+
class="grid relative"
|
|
211
|
+
style={gridContainerStyle()}
|
|
212
|
+
data-grid-container
|
|
213
|
+
>
|
|
214
|
+
{/* Grid overlay */}
|
|
215
|
+
<GridOverlay
|
|
216
|
+
columns={props.layout.grid.columns}
|
|
217
|
+
visible={showOverlay()}
|
|
218
|
+
/>
|
|
219
|
+
|
|
220
|
+
{/* Render components with drag-drop wrappers */}
|
|
221
|
+
<For each={components()}>
|
|
222
|
+
{(component) => {
|
|
223
|
+
// Create resize hook for each component
|
|
224
|
+
const resize = useResize({
|
|
225
|
+
componentId: component.id,
|
|
226
|
+
currentPosition: () => component.position,
|
|
227
|
+
onResize: (pos) => handleResize(component.id, pos),
|
|
228
|
+
onResizePreview: (pos) => handleResizePreview(component.id, pos),
|
|
229
|
+
constraints: dragDropConfig().constraints,
|
|
230
|
+
gridContainer: gridContainerRef,
|
|
231
|
+
gridColumns: props.layout.grid.columns,
|
|
232
|
+
enabled: dragDropConfig().enabled && dragDropConfig().resize
|
|
233
|
+
})
|
|
234
|
+
|
|
235
|
+
const effectivePosition = () => getEffectivePosition(component)
|
|
236
|
+
|
|
237
|
+
return (
|
|
238
|
+
<DraggableGridItem
|
|
239
|
+
id={component.id}
|
|
240
|
+
position={effectivePosition()}
|
|
241
|
+
draggable={dragDropConfig().enabled && dragDropConfig().reorder}
|
|
242
|
+
resizable={dragDropConfig().enabled && dragDropConfig().resize}
|
|
243
|
+
constraints={dragDropConfig().constraints}
|
|
244
|
+
isDragging={dragDrop.isComponentDragging(component.id)}
|
|
245
|
+
isDropTarget={dragDrop.isDropTarget(component.id)}
|
|
246
|
+
isResizing={activeResizeId() === component.id}
|
|
247
|
+
previewPosition={previewPositions().get(component.id) || null}
|
|
248
|
+
dragProps={dragDrop.getDragProps(component.id)}
|
|
249
|
+
onResizeStart={(edge, event) => {
|
|
250
|
+
setActiveResizeId(component.id)
|
|
251
|
+
resize.handleResizeStart(event, edge as ResizeEdge)
|
|
252
|
+
}}
|
|
253
|
+
>
|
|
254
|
+
{/* Render component using UIResourceRenderer for single component */}
|
|
255
|
+
<UIResourceRenderer
|
|
256
|
+
content={component}
|
|
257
|
+
onError={props.onError}
|
|
258
|
+
/>
|
|
259
|
+
</DraggableGridItem>
|
|
260
|
+
)
|
|
261
|
+
}}
|
|
262
|
+
</For>
|
|
263
|
+
</div>
|
|
264
|
+
</div>
|
|
265
|
+
)
|
|
266
|
+
}
|
|
267
|
+
|
|
268
|
+
export default EditableUIResourceRenderer
|