@seed-ship/mcp-ui-solid 4.2.0 → 4.2.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/ScratchpadPanel.cjs +327 -249
- package/dist/components/ScratchpadPanel.cjs.map +1 -1
- package/dist/components/ScratchpadPanel.js +327 -249
- package/dist/components/ScratchpadPanel.js.map +1 -1
- package/package.json +1 -1
- package/src/components/ScratchpadPanel.tsx +86 -4
- package/tsconfig.tsbuildinfo +1 -1
package/package.json
CHANGED
|
@@ -525,15 +525,83 @@ const EmbeddedFormSection: Component<{
|
|
|
525
525
|
onAction?: (action: string, data?: unknown) => void
|
|
526
526
|
onSubmit?: (sectionId: string, values: Record<string, unknown>) => void
|
|
527
527
|
}> = (props) => {
|
|
528
|
-
const [formData, setFormData] = createSignal<Record<string, any>>({})
|
|
529
528
|
const [dynamicOptions, setDynamicOptions] = createSignal<Record<string, Array<{ label: string; value: string }>>>({})
|
|
530
529
|
|
|
531
530
|
const config = () => {
|
|
532
531
|
const c = props.content as any
|
|
533
|
-
return {
|
|
532
|
+
return {
|
|
533
|
+
fields: c?.fields || [],
|
|
534
|
+
submitLabel: c?.submitLabel || 'Submit',
|
|
535
|
+
autoSubmitDelay: c?.autoSubmitDelay as number | undefined,
|
|
536
|
+
}
|
|
537
|
+
}
|
|
538
|
+
|
|
539
|
+
// Initialize form data with prefill values (v4.2.0)
|
|
540
|
+
const buildInitial = () => {
|
|
541
|
+
const initial: Record<string, any> = {}
|
|
542
|
+
for (const field of config().fields) {
|
|
543
|
+
initial[field.name] = field.prefill ?? field.defaultValue ?? ''
|
|
544
|
+
}
|
|
545
|
+
return initial
|
|
546
|
+
}
|
|
547
|
+
|
|
548
|
+
const [formData, setFormData] = createSignal<Record<string, any>>(buildInitial())
|
|
549
|
+
|
|
550
|
+
// Re-init when content changes (streaming updates)
|
|
551
|
+
createEffect(() => {
|
|
552
|
+
const fields = config().fields
|
|
553
|
+
if (fields.length > 0) {
|
|
554
|
+
setFormData((prev) => {
|
|
555
|
+
const next = { ...prev }
|
|
556
|
+
for (const field of fields) {
|
|
557
|
+
// Only apply prefill if the user hasn't changed the field yet
|
|
558
|
+
if (field.prefill != null && (next[field.name] === undefined || next[field.name] === '')) {
|
|
559
|
+
next[field.name] = field.prefill
|
|
560
|
+
}
|
|
561
|
+
}
|
|
562
|
+
return next
|
|
563
|
+
})
|
|
564
|
+
}
|
|
565
|
+
})
|
|
566
|
+
|
|
567
|
+
// Auto-submit countdown (v4.2.0)
|
|
568
|
+
const [countdown, setCountdown] = createSignal<number | null>(null)
|
|
569
|
+
let countdownTimer: ReturnType<typeof setInterval> | null = null
|
|
570
|
+
const [userInteracted, setUserInteracted] = createSignal(false)
|
|
571
|
+
|
|
572
|
+
const cancelCountdown = () => {
|
|
573
|
+
if (countdownTimer) { clearInterval(countdownTimer); countdownTimer = null }
|
|
574
|
+
setCountdown(null)
|
|
534
575
|
}
|
|
535
576
|
|
|
536
|
-
|
|
577
|
+
onCleanup(() => cancelCountdown())
|
|
578
|
+
|
|
579
|
+
createEffect(() => {
|
|
580
|
+
const delay = config().autoSubmitDelay
|
|
581
|
+
if (!delay || userInteracted()) return
|
|
582
|
+
const allRequiredPrefilled = config().fields
|
|
583
|
+
.filter((f: any) => f.required)
|
|
584
|
+
.every((f: any) => f.prefill != null)
|
|
585
|
+
if (!allRequiredPrefilled) return
|
|
586
|
+
|
|
587
|
+
let remaining = Math.ceil(delay / 1000)
|
|
588
|
+
setCountdown(remaining)
|
|
589
|
+
countdownTimer = setInterval(() => {
|
|
590
|
+
remaining--
|
|
591
|
+
if (remaining <= 0) {
|
|
592
|
+
cancelCountdown()
|
|
593
|
+
const form = document.querySelector(`#scratchpad-form-${props.sectionId}`) as HTMLFormElement | null
|
|
594
|
+
if (form) form.requestSubmit()
|
|
595
|
+
} else {
|
|
596
|
+
setCountdown(remaining)
|
|
597
|
+
}
|
|
598
|
+
}, 1000)
|
|
599
|
+
})
|
|
600
|
+
|
|
601
|
+
const updateField = (name: string, value: any) => {
|
|
602
|
+
if (!userInteracted()) { setUserInteracted(true); cancelCountdown() }
|
|
603
|
+
setFormData(prev => ({ ...prev, [name]: value }))
|
|
604
|
+
}
|
|
537
605
|
|
|
538
606
|
// depends_on reactive (#9)
|
|
539
607
|
createEffect(() => {
|
|
@@ -587,7 +655,7 @@ const EmbeddedFormSection: Component<{
|
|
|
587
655
|
}
|
|
588
656
|
|
|
589
657
|
return (
|
|
590
|
-
<form onSubmit={handleSubmit} class="flex flex-col gap-3">
|
|
658
|
+
<form id={`scratchpad-form-${props.sectionId}`} onSubmit={handleSubmit} class="flex flex-col gap-3">
|
|
591
659
|
<For each={config().fields}>
|
|
592
660
|
{(field) => (
|
|
593
661
|
<FormFieldRenderer
|
|
@@ -598,6 +666,20 @@ const EmbeddedFormSection: Component<{
|
|
|
598
666
|
/>
|
|
599
667
|
)}
|
|
600
668
|
</For>
|
|
669
|
+
<Show when={countdown() != null}>
|
|
670
|
+
<div class="flex items-center gap-3 p-2 bg-blue-50 dark:bg-blue-900/20 border border-blue-200 dark:border-blue-800 rounded-md text-sm">
|
|
671
|
+
<span class="text-blue-700 dark:text-blue-300">
|
|
672
|
+
{config().submitLabel} in {countdown()}s...
|
|
673
|
+
</span>
|
|
674
|
+
<button
|
|
675
|
+
type="button"
|
|
676
|
+
onClick={() => { cancelCountdown(); setUserInteracted(true) }}
|
|
677
|
+
class="text-blue-600 dark:text-blue-400 underline hover:text-blue-800 dark:hover:text-blue-200"
|
|
678
|
+
>
|
|
679
|
+
Cancel
|
|
680
|
+
</button>
|
|
681
|
+
</div>
|
|
682
|
+
</Show>
|
|
601
683
|
<div class="flex justify-end">
|
|
602
684
|
<button type="submit" class="px-4 py-2 text-sm font-medium rounded-lg text-white bg-blue-600 hover:bg-blue-700 transition-colors">
|
|
603
685
|
{config().submitLabel}
|