@seed-ship/mcp-ui-solid 4.2.2 → 4.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +36 -0
- package/README.md +13 -8
- package/dist/components/FormFieldRenderer.cjs +132 -52
- package/dist/components/FormFieldRenderer.cjs.map +1 -1
- package/dist/components/FormFieldRenderer.js +133 -53
- package/dist/components/FormFieldRenderer.js.map +1 -1
- package/dist/components/FormRenderer.cjs +25 -6
- package/dist/components/FormRenderer.cjs.map +1 -1
- package/dist/components/FormRenderer.d.ts.map +1 -1
- package/dist/components/FormRenderer.js +25 -6
- package/dist/components/FormRenderer.js.map +1 -1
- package/dist/components/ScratchpadPanel.cjs +329 -276
- package/dist/components/ScratchpadPanel.cjs.map +1 -1
- package/dist/components/ScratchpadPanel.js +329 -276
- package/dist/components/ScratchpadPanel.js.map +1 -1
- package/dist/services/validation.cjs +8 -0
- package/dist/services/validation.cjs.map +1 -1
- package/dist/services/validation.d.ts.map +1 -1
- package/dist/services/validation.js +8 -0
- package/dist/services/validation.js.map +1 -1
- package/dist/types/index.d.ts +8 -0
- package/dist/types/index.d.ts.map +1 -1
- package/dist/types.d.cts +8 -0
- package/dist/types.d.ts +8 -0
- package/package.json +1 -1
- package/src/components/FormFieldRenderer.tsx +89 -2
- package/src/components/FormRenderer.tsx +12 -0
- package/src/components/ScratchpadPanel.tsx +35 -0
- package/src/services/validation.ts +10 -0
- package/src/types/index.ts +8 -0
- package/tsconfig.tsbuildinfo +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -5,6 +5,42 @@ All notable changes to this project will be documented in this file.
|
|
|
5
5
|
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
|
|
6
6
|
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
7
7
|
|
|
8
|
+
## [4.3.0] - 2026-04-11
|
|
9
|
+
|
|
10
|
+
### Added — Prefill Enhancements (Phase B)
|
|
11
|
+
|
|
12
|
+
#### `prefillMode: "resolve"` for autocomplete fields (Proposal 1)
|
|
13
|
+
- Autocomplete fields can receive display names (e.g. "Paris") instead of codes
|
|
14
|
+
- MCP-UI calls `apiUrl` to resolve to `valueField` (e.g. code "75056") client-side
|
|
15
|
+
- Reduces server-side complexity — no async value resolution needed before emitting forms
|
|
16
|
+
- Fallback: raw prefill value used if API call fails
|
|
17
|
+
|
|
18
|
+
#### Smart tag display (Proposal 2)
|
|
19
|
+
- Select/multi-select fields show `label` not `value` for prefilled codes
|
|
20
|
+
- Autocomplete shows `displayHint` or resolved label as chip text instead of raw code
|
|
21
|
+
|
|
22
|
+
#### Prefill confidence summary (Proposal 3)
|
|
23
|
+
- Shows "N champ(s) pré-rempli(s) sur M" when at least one field is prefilled
|
|
24
|
+
- Displayed in both FormRenderer and EmbeddedFormSection (scratchpad forms)
|
|
25
|
+
|
|
26
|
+
#### Auto-submit toast mode (Proposal 4)
|
|
27
|
+
- When ALL fields are prefilled + `autoSubmitDelay` set, shows compact toast instead of full form
|
|
28
|
+
- Toast shows prefilled values summary with countdown, "Modifier" to expand, × to cancel
|
|
29
|
+
- Any interaction cancels countdown and expands full form
|
|
30
|
+
|
|
31
|
+
#### `valueFormat` validation (Proposal 5)
|
|
32
|
+
- Optional regex pattern on form fields — validates submitted value format
|
|
33
|
+
- `valueFormatHint` for human-readable error message on failure
|
|
34
|
+
- Runs after type-specific validation, supports arrays (multi-select)
|
|
35
|
+
|
|
36
|
+
#### Autocomplete always submits `valueField` (Proposal 6)
|
|
37
|
+
- On blur without selection, auto-resolves typed text to first API result
|
|
38
|
+
- Ensures form never submits display names when `valueField` is configured
|
|
39
|
+
- Fixes silent data corruption when users type instead of selecting
|
|
40
|
+
|
|
41
|
+
### Changed
|
|
42
|
+
- `@seed-ship/mcp-ui-spec` bumped to 3.2.0 (`prefillMode`, `valueFormat`, `valueFormatHint`)
|
|
43
|
+
|
|
8
44
|
## [4.2.2] - 2026-04-11
|
|
9
45
|
|
|
10
46
|
### Added — Prefilled Forms with Source Indicators
|
package/README.md
CHANGED
|
@@ -5,13 +5,15 @@ SolidJS components + chat toolkit for MCP-generated UI. Part of the [MCP UI ecos
|
|
|
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 v4.
|
|
8
|
+
## What's New in v4.3
|
|
9
9
|
|
|
10
10
|
- **Prefilled Forms** — Fields render with pre-populated values + source indicators (detected/inferred/default/user)
|
|
11
|
-
-
|
|
12
|
-
- **
|
|
13
|
-
- **
|
|
14
|
-
- **Auto-submit
|
|
11
|
+
- **`prefillMode: "resolve"`** — Autocomplete fields accept display names ("Paris"), resolve to codes ("75056") client-side
|
|
12
|
+
- **Smart tag display** — Select/autocomplete show labels not codes for prefilled values
|
|
13
|
+
- **Prefill summary** — "N champs pré-remplis sur M" shown when fields are prefilled
|
|
14
|
+
- **Auto-submit toast** — Compact summary with countdown when ALL fields are prefilled
|
|
15
|
+
- **`valueFormat` validation** — Regex-based format validation on form values (e.g. `"^\\d{5}$"` for INSEE codes)
|
|
16
|
+
- **Autocomplete valueField guarantee** — Always submits resolved code, never display text
|
|
15
17
|
|
|
16
18
|
### Prefilled Form Example
|
|
17
19
|
|
|
@@ -28,8 +30,11 @@ SolidJS components + chat toolkit for MCP-generated UI. Part of the [MCP UI ecos
|
|
|
28
30
|
muted: true,
|
|
29
31
|
},
|
|
30
32
|
{
|
|
31
|
-
name: 'commune', type: '
|
|
32
|
-
|
|
33
|
+
name: 'commune', type: 'autocomplete',
|
|
34
|
+
apiUrl: 'https://geo.api.gouv.fr/communes',
|
|
35
|
+
searchParam: 'nom', labelField: 'nom', valueField: 'code',
|
|
36
|
+
prefill: ['Lyon'],
|
|
37
|
+
prefillMode: 'resolve', // MCP-UI resolves "Lyon" → code "69123"
|
|
33
38
|
source: 'detected',
|
|
34
39
|
muted: true,
|
|
35
40
|
},
|
|
@@ -39,7 +44,7 @@ SolidJS components + chat toolkit for MCP-generated UI. Part of the [MCP UI ecos
|
|
|
39
44
|
// No prefill — user must choose
|
|
40
45
|
},
|
|
41
46
|
],
|
|
42
|
-
autoSubmitDelay: 3000, // optional countdown
|
|
47
|
+
autoSubmitDelay: 3000, // optional countdown + toast when all prefilled
|
|
43
48
|
}
|
|
44
49
|
```
|
|
45
50
|
|
|
@@ -3,7 +3,7 @@ Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
|
3
3
|
const web = require("solid-js/web");
|
|
4
4
|
const solidJs = require("solid-js");
|
|
5
5
|
const useConditionalField = require("../hooks/useConditionalField.cjs");
|
|
6
|
-
var _tmpl$ = /* @__PURE__ */ web.template(`<span class=mr-1>`), _tmpl$2 = /* @__PURE__ */ web.template(`<span class="text-red-500 ml-1"aria-hidden=true>*`), _tmpl$3 = /* @__PURE__ */ web.template(`<span class="ml-2 text-[10px] font-medium bg-orange-100 dark:bg-orange-900/30 text-orange-600 dark:text-orange-400 px-1.5 py-0.5 rounded">Not supported`), _tmpl$4 = /* @__PURE__ */ web.template(`<span class="ml-2 text-[10px] font-medium bg-yellow-100 dark:bg-yellow-900/30 text-yellow-600 dark:text-yellow-400 px-1.5 py-0.5 rounded">?`), _tmpl$5 = /* @__PURE__ */ web.template(`<label><!$><!/><!$><!/><!$><!/><!$><!/><!$><!/>`), _tmpl$6 = /* @__PURE__ */ web.template(`<input>`), _tmpl$7 = /* @__PURE__ */ web.template(`<input type=number>`), _tmpl$8 = /* @__PURE__ */ web.template(`<input type=date>`), _tmpl$9 = /* @__PURE__ */ web.template(`<textarea>`), _tmpl$0 = /* @__PURE__ */ web.template(`<option value disabled>`), _tmpl$1 = /* @__PURE__ */ web.template(`<select><!$><!/><!$><!/>`), _tmpl$10 = /* @__PURE__ */ web.template(`<label class="flex items-center gap-2 cursor-pointer"><input type=checkbox class="w-4 h-4 rounded border-gray-300 text-blue-600 focus:ring-blue-500 dark:border-gray-600 dark:bg-gray-700"><span class="text-sm text-gray-700 dark:text-gray-300"><!$><!/><!$><!/>`), _tmpl$11 = /* @__PURE__ */ web.template(`<div class=space-y-2 role=radiogroup>`), _tmpl$12 = /* @__PURE__ */ web.template(`<div class="flex items-center gap-3"><input type=range class="flex-1 h-2 bg-gray-200 dark:bg-gray-600 rounded-lg appearance-none cursor-pointer accent-blue-600"><span class="text-sm font-mono text-gray-700 dark:text-gray-300 min-w-[3rem] text-right">`), _tmpl$13 = /* @__PURE__ */ web.template(`<label class="flex items-center gap-2 cursor-pointer"><button type=button role=switch><span></span></button><span class="text-sm text-gray-700 dark:text-gray-300">`), _tmpl$14 = /* @__PURE__ */ web.template(`<fieldset class="border border-gray-200 dark:border-gray-600 rounded-lg p-3"><legend class="text-xs font-medium text-gray-500 dark:text-gray-400 px-1"></legend><p class="text-xs text-gray-400">`), _tmpl$15 = /* @__PURE__ */ web.template(`<input type=text>`), _tmpl$16 = /* @__PURE__ */ web.template(`<p class="text-xs text-amber-500 mt-0.5">Unknown field type: <!$><!/>`), _tmpl$17 = /* @__PURE__ */ web.template(`<p>`), _tmpl$18 = /* @__PURE__ */ web.template(`<p class="text-xs text-gray-500 dark:text-gray-400">`), _tmpl$19 = /* @__PURE__ */ web.template(`<p role=alert class="text-xs text-red-600 dark:text-red-400">`), _tmpl$20 = /* @__PURE__ */ web.template(`<div class=space-y-1><!$><!/><!$><!/><!$><!/><!$><!/><!$><!/><!$><!/>`), _tmpl$21 = /* @__PURE__ */ web.template(`<option>`), _tmpl$22 = /* @__PURE__ */ web.template(`<label class="flex items-center gap-2 cursor-pointer"><input type=radio class="w-4 h-4 border-gray-300 text-blue-600 focus:ring-blue-500 dark:border-gray-600"><span class="text-sm text-gray-700 dark:text-gray-300">`), _tmpl$23 = /* @__PURE__ */ web.template(`<div class="flex flex-wrap gap-1 mb-1">`), _tmpl$24 = /* @__PURE__ */ web.template(`<div class="p-2 border-b border-gray-200 dark:border-gray-600 flex-shrink-0"><input type=text placeholder=Filter... class="w-full px-2 py-1 text-sm border border-gray-200 dark:border-gray-600 rounded bg-white dark:bg-gray-700 text-gray-900 dark:text-white focus:border-blue-400 outline-none"autofocus>`), _tmpl$25 = /* @__PURE__ */ web.template(`<p class="px-3 py-2 text-sm text-gray-400">No matches`), _tmpl$26 = /* @__PURE__ */ web.template(`<div class="absolute z-50 mt-1 w-full bg-white dark:bg-gray-800 border border-gray-200 dark:border-gray-600 rounded-md shadow-lg"style=max-height:320px;display:flex;flex-direction:column><!$><!/><div style=overflow-y:auto;flex:1;-webkit-overflow-scrolling:touch><!$><!/><!$><!/>`), _tmpl$27 = /* @__PURE__ */ web.template(`<div class=relative><!$><!/><button type=button><span></span><svg class="w-4 h-4 text-gray-400"fill=none viewBox="0 0 24 24"stroke=currentColor><path stroke-linecap=round stroke-linejoin=round stroke-width=2 d="M19 9l-7 7-7-7"></path></svg></button><!$><!/>`), _tmpl$28 = /* @__PURE__ */ web.template(`<span class="inline-flex items-center gap-1 px-2 py-0.5 text-xs font-medium bg-blue-100 dark:bg-blue-900/30 text-blue-700 dark:text-blue-300 rounded-full"><!$><!/><button type=button class="hover:text-blue-900 dark:hover:text-blue-100">×`), _tmpl$29 = /* @__PURE__ */ web.template(`<label class="flex items-center gap-2 px-3 py-2 hover:bg-gray-100 dark:hover:bg-gray-700 cursor-pointer text-sm"><input type=checkbox class="w-4 h-4 rounded border-gray-300 text-blue-600 focus:ring-blue-500 dark:border-gray-600"><span class="text-gray-900 dark:text-white">`), _tmpl$30 = /* @__PURE__ */ web.template(`<div class="absolute z-20 mt-1 w-full bg-white dark:bg-gray-800 border border-gray-200 dark:border-gray-600 rounded-md shadow-lg max-h-72 overflow-y-auto">`), _tmpl$
|
|
6
|
+
var _tmpl$ = /* @__PURE__ */ web.template(`<span class=mr-1>`), _tmpl$2 = /* @__PURE__ */ web.template(`<span class="text-red-500 ml-1"aria-hidden=true>*`), _tmpl$3 = /* @__PURE__ */ web.template(`<span class="ml-2 text-[10px] font-medium bg-orange-100 dark:bg-orange-900/30 text-orange-600 dark:text-orange-400 px-1.5 py-0.5 rounded">Not supported`), _tmpl$4 = /* @__PURE__ */ web.template(`<span class="ml-2 text-[10px] font-medium bg-yellow-100 dark:bg-yellow-900/30 text-yellow-600 dark:text-yellow-400 px-1.5 py-0.5 rounded">?`), _tmpl$5 = /* @__PURE__ */ web.template(`<label><!$><!/><!$><!/><!$><!/><!$><!/><!$><!/>`), _tmpl$6 = /* @__PURE__ */ web.template(`<input>`), _tmpl$7 = /* @__PURE__ */ web.template(`<input type=number>`), _tmpl$8 = /* @__PURE__ */ web.template(`<input type=date>`), _tmpl$9 = /* @__PURE__ */ web.template(`<textarea>`), _tmpl$0 = /* @__PURE__ */ web.template(`<option value disabled>`), _tmpl$1 = /* @__PURE__ */ web.template(`<select><!$><!/><!$><!/>`), _tmpl$10 = /* @__PURE__ */ web.template(`<label class="flex items-center gap-2 cursor-pointer"><input type=checkbox class="w-4 h-4 rounded border-gray-300 text-blue-600 focus:ring-blue-500 dark:border-gray-600 dark:bg-gray-700"><span class="text-sm text-gray-700 dark:text-gray-300"><!$><!/><!$><!/>`), _tmpl$11 = /* @__PURE__ */ web.template(`<div class=space-y-2 role=radiogroup>`), _tmpl$12 = /* @__PURE__ */ web.template(`<div class="flex items-center gap-3"><input type=range class="flex-1 h-2 bg-gray-200 dark:bg-gray-600 rounded-lg appearance-none cursor-pointer accent-blue-600"><span class="text-sm font-mono text-gray-700 dark:text-gray-300 min-w-[3rem] text-right">`), _tmpl$13 = /* @__PURE__ */ web.template(`<label class="flex items-center gap-2 cursor-pointer"><button type=button role=switch><span></span></button><span class="text-sm text-gray-700 dark:text-gray-300">`), _tmpl$14 = /* @__PURE__ */ web.template(`<fieldset class="border border-gray-200 dark:border-gray-600 rounded-lg p-3"><legend class="text-xs font-medium text-gray-500 dark:text-gray-400 px-1"></legend><p class="text-xs text-gray-400">`), _tmpl$15 = /* @__PURE__ */ web.template(`<input type=text>`), _tmpl$16 = /* @__PURE__ */ web.template(`<p class="text-xs text-amber-500 mt-0.5">Unknown field type: <!$><!/>`), _tmpl$17 = /* @__PURE__ */ web.template(`<p>`), _tmpl$18 = /* @__PURE__ */ web.template(`<p class="text-xs text-gray-500 dark:text-gray-400">`), _tmpl$19 = /* @__PURE__ */ web.template(`<p role=alert class="text-xs text-red-600 dark:text-red-400">`), _tmpl$20 = /* @__PURE__ */ web.template(`<div class=space-y-1><!$><!/><!$><!/><!$><!/><!$><!/><!$><!/><!$><!/>`), _tmpl$21 = /* @__PURE__ */ web.template(`<option>`), _tmpl$22 = /* @__PURE__ */ web.template(`<label class="flex items-center gap-2 cursor-pointer"><input type=radio class="w-4 h-4 border-gray-300 text-blue-600 focus:ring-blue-500 dark:border-gray-600"><span class="text-sm text-gray-700 dark:text-gray-300">`), _tmpl$23 = /* @__PURE__ */ web.template(`<div class="flex flex-wrap gap-1 mb-1">`), _tmpl$24 = /* @__PURE__ */ web.template(`<div class="p-2 border-b border-gray-200 dark:border-gray-600 flex-shrink-0"><input type=text placeholder=Filter... class="w-full px-2 py-1 text-sm border border-gray-200 dark:border-gray-600 rounded bg-white dark:bg-gray-700 text-gray-900 dark:text-white focus:border-blue-400 outline-none"autofocus>`), _tmpl$25 = /* @__PURE__ */ web.template(`<p class="px-3 py-2 text-sm text-gray-400">No matches`), _tmpl$26 = /* @__PURE__ */ web.template(`<div class="absolute z-50 mt-1 w-full bg-white dark:bg-gray-800 border border-gray-200 dark:border-gray-600 rounded-md shadow-lg"style=max-height:320px;display:flex;flex-direction:column><!$><!/><div style=overflow-y:auto;flex:1;-webkit-overflow-scrolling:touch><!$><!/><!$><!/>`), _tmpl$27 = /* @__PURE__ */ web.template(`<div class=relative><!$><!/><button type=button><span></span><svg class="w-4 h-4 text-gray-400"fill=none viewBox="0 0 24 24"stroke=currentColor><path stroke-linecap=round stroke-linejoin=round stroke-width=2 d="M19 9l-7 7-7-7"></path></svg></button><!$><!/>`), _tmpl$28 = /* @__PURE__ */ web.template(`<span class="inline-flex items-center gap-1 px-2 py-0.5 text-xs font-medium bg-blue-100 dark:bg-blue-900/30 text-blue-700 dark:text-blue-300 rounded-full"><!$><!/><button type=button class="hover:text-blue-900 dark:hover:text-blue-100">×`), _tmpl$29 = /* @__PURE__ */ web.template(`<label class="flex items-center gap-2 px-3 py-2 hover:bg-gray-100 dark:hover:bg-gray-700 cursor-pointer text-sm"><input type=checkbox class="w-4 h-4 rounded border-gray-300 text-blue-600 focus:ring-blue-500 dark:border-gray-600"><span class="text-gray-900 dark:text-white">`), _tmpl$30 = /* @__PURE__ */ web.template(`<div class="flex items-center gap-1 mb-1 text-xs text-gray-400"><span class="animate-spin h-3 w-3 border border-gray-400 border-t-transparent rounded-full"></span>Resolving...`), _tmpl$31 = /* @__PURE__ */ web.template(`<div class="absolute z-20 mt-1 w-full bg-white dark:bg-gray-800 border border-gray-200 dark:border-gray-600 rounded-md shadow-lg max-h-72 overflow-y-auto">`), _tmpl$32 = /* @__PURE__ */ web.template(`<div class=relative><!$><!/><!$><!/><input type=text autocomplete=off><!$><!/>`), _tmpl$33 = /* @__PURE__ */ web.template(`<span class="ml-2 text-xs">✓`), _tmpl$34 = /* @__PURE__ */ web.template(`<button type=button><!$><!/><!$><!/>`), _tmpl$35 = /* @__PURE__ */ web.template(`<div><!$><!/><input type=text>`);
|
|
7
7
|
const SOURCE_BADGES = {
|
|
8
8
|
detected: {
|
|
9
9
|
icon: "✅",
|
|
@@ -721,6 +721,7 @@ const AutocompleteField = (props) => {
|
|
|
721
721
|
const [suggestions, setSuggestions] = solidJs.createSignal([]);
|
|
722
722
|
const [isOpen, setIsOpen] = solidJs.createSignal(false);
|
|
723
723
|
const [selectedLabels, setSelectedLabels] = solidJs.createSignal(/* @__PURE__ */ new Map());
|
|
724
|
+
const [resolving, setResolving] = solidJs.createSignal(false);
|
|
724
725
|
let debounceTimer = null;
|
|
725
726
|
const isMultiple = () => props.field.multiple === true;
|
|
726
727
|
const selectedValues = () => isMultiple() ? Array.isArray(props.value) ? props.value : [] : [];
|
|
@@ -752,6 +753,69 @@ const AutocompleteField = (props) => {
|
|
|
752
753
|
setSuggestions([]);
|
|
753
754
|
}
|
|
754
755
|
};
|
|
756
|
+
const resolvePrefill = async (prefillValues) => {
|
|
757
|
+
if (!props.field.apiUrl || !props.field.searchParam) return;
|
|
758
|
+
setResolving(true);
|
|
759
|
+
const labelField = props.field.labelField || "label";
|
|
760
|
+
const valueField = props.field.valueField || "value";
|
|
761
|
+
try {
|
|
762
|
+
const resolvedValues = [];
|
|
763
|
+
for (const pv of prefillValues) {
|
|
764
|
+
const params = new URLSearchParams({
|
|
765
|
+
[props.field.searchParam]: pv,
|
|
766
|
+
limit: "1"
|
|
767
|
+
});
|
|
768
|
+
if (props.field.extraParams) {
|
|
769
|
+
for (const [k, v] of Object.entries(props.field.extraParams)) params.set(k, v);
|
|
770
|
+
}
|
|
771
|
+
const res = await fetch(`${props.field.apiUrl}?${params}`);
|
|
772
|
+
if (!res.ok) {
|
|
773
|
+
resolvedValues.push(pv);
|
|
774
|
+
continue;
|
|
775
|
+
}
|
|
776
|
+
const data = await res.json();
|
|
777
|
+
const items = Array.isArray(data) ? data : data.results || data.features || [];
|
|
778
|
+
if (items.length > 0) {
|
|
779
|
+
const code = String(items[0][valueField] || pv);
|
|
780
|
+
const label = items[0][labelField] || pv;
|
|
781
|
+
resolvedValues.push(code);
|
|
782
|
+
setSelectedLabels((prev) => new Map(prev).set(code, label));
|
|
783
|
+
} else {
|
|
784
|
+
resolvedValues.push(pv);
|
|
785
|
+
setSelectedLabels((prev) => new Map(prev).set(pv, pv));
|
|
786
|
+
}
|
|
787
|
+
}
|
|
788
|
+
if (isMultiple()) {
|
|
789
|
+
props.onChange(resolvedValues);
|
|
790
|
+
} else {
|
|
791
|
+
props.onChange(resolvedValues[0] || "");
|
|
792
|
+
const label = selectedLabels().get(resolvedValues[0]);
|
|
793
|
+
if (label) setQuery(label);
|
|
794
|
+
}
|
|
795
|
+
} catch {
|
|
796
|
+
} finally {
|
|
797
|
+
setResolving(false);
|
|
798
|
+
}
|
|
799
|
+
};
|
|
800
|
+
solidJs.createEffect(() => {
|
|
801
|
+
const prefill = props.field.prefill;
|
|
802
|
+
if (!prefill) return;
|
|
803
|
+
const values = Array.isArray(prefill) ? prefill : [prefill];
|
|
804
|
+
if (values.length === 0) return;
|
|
805
|
+
if (props.field.prefillMode === "resolve") {
|
|
806
|
+
resolvePrefill(values);
|
|
807
|
+
} else {
|
|
808
|
+
for (const v of values) {
|
|
809
|
+
if (!selectedLabels().has(v)) {
|
|
810
|
+
setSelectedLabels((prev) => new Map(prev).set(v, props.field.displayHint || v));
|
|
811
|
+
}
|
|
812
|
+
}
|
|
813
|
+
if (!isMultiple() && values[0]) {
|
|
814
|
+
const label = props.field.displayHint || values[0];
|
|
815
|
+
setQuery(label);
|
|
816
|
+
}
|
|
817
|
+
}
|
|
818
|
+
});
|
|
755
819
|
const handleInput = (value) => {
|
|
756
820
|
setQuery(value);
|
|
757
821
|
if (!isMultiple()) {
|
|
@@ -786,6 +850,14 @@ const AutocompleteField = (props) => {
|
|
|
786
850
|
setSuggestions([]);
|
|
787
851
|
}
|
|
788
852
|
};
|
|
853
|
+
const handleBlur = () => {
|
|
854
|
+
setTimeout(() => {
|
|
855
|
+
setIsOpen(false);
|
|
856
|
+
if (!isMultiple() && query() && !props.value && props.field.valueField && suggestions().length > 0) {
|
|
857
|
+
selectSuggestion(suggestions()[0]);
|
|
858
|
+
}
|
|
859
|
+
}, 200);
|
|
860
|
+
};
|
|
789
861
|
const removeChip = (val) => {
|
|
790
862
|
props.onChange(selectedValues().filter((v) => v !== val));
|
|
791
863
|
setSelectedLabels((prev) => {
|
|
@@ -799,88 +871,96 @@ const AutocompleteField = (props) => {
|
|
|
799
871
|
if (debounceTimer) clearTimeout(debounceTimer);
|
|
800
872
|
});
|
|
801
873
|
return (() => {
|
|
802
|
-
var _el$95 = web.getNextElement(_tmpl$
|
|
874
|
+
var _el$95 = web.getNextElement(_tmpl$32), _el$100 = _el$95.firstChild, [_el$101, _co$21] = web.getNextMarker(_el$100.nextSibling), _el$102 = _el$101.nextSibling, [_el$103, _co$22] = web.getNextMarker(_el$102.nextSibling), _el$98 = _el$103.nextSibling, _el$104 = _el$98.nextSibling, [_el$105, _co$23] = web.getNextMarker(_el$104.nextSibling);
|
|
875
|
+
web.insert(_el$95, web.createComponent(solidJs.Show, {
|
|
876
|
+
get when() {
|
|
877
|
+
return resolving();
|
|
878
|
+
},
|
|
879
|
+
get children() {
|
|
880
|
+
return web.getNextElement(_tmpl$30);
|
|
881
|
+
}
|
|
882
|
+
}), _el$101, _co$21);
|
|
803
883
|
web.insert(_el$95, web.createComponent(solidJs.Show, {
|
|
804
884
|
get when() {
|
|
805
885
|
return web.memo(() => !!isMultiple())() && selectedValues().length > 0;
|
|
806
886
|
},
|
|
807
887
|
get children() {
|
|
808
|
-
var _el$
|
|
809
|
-
web.insert(_el$
|
|
888
|
+
var _el$97 = web.getNextElement(_tmpl$23);
|
|
889
|
+
web.insert(_el$97, web.createComponent(solidJs.For, {
|
|
810
890
|
get each() {
|
|
811
891
|
return selectedValues();
|
|
812
892
|
},
|
|
813
893
|
children: (val) => (() => {
|
|
814
|
-
var _el$
|
|
815
|
-
web.insert(_el$
|
|
816
|
-
_el$
|
|
817
|
-
web.effect(() => web.setAttribute(_el$
|
|
894
|
+
var _el$106 = web.getNextElement(_tmpl$28), _el$108 = _el$106.firstChild, [_el$109, _co$24] = web.getNextMarker(_el$108.nextSibling), _el$107 = _el$109.nextSibling;
|
|
895
|
+
web.insert(_el$106, () => getLabel(val), _el$109, _co$24);
|
|
896
|
+
_el$107.$$click = () => removeChip(val);
|
|
897
|
+
web.effect(() => web.setAttribute(_el$107, "aria-label", `Remove ${getLabel(val)}`));
|
|
818
898
|
web.runHydrationEvents();
|
|
819
|
-
return _el$
|
|
899
|
+
return _el$106;
|
|
820
900
|
})()
|
|
821
901
|
}));
|
|
822
|
-
return _el$
|
|
902
|
+
return _el$97;
|
|
823
903
|
}
|
|
824
|
-
}), _el$
|
|
825
|
-
_el$
|
|
826
|
-
_el$
|
|
904
|
+
}), _el$103, _co$22);
|
|
905
|
+
_el$98.addEventListener("blur", handleBlur);
|
|
906
|
+
_el$98.addEventListener("focus", () => {
|
|
827
907
|
if (suggestions().length) setIsOpen(true);
|
|
828
908
|
});
|
|
829
|
-
_el$
|
|
909
|
+
_el$98.$$input = (e) => handleInput(e.currentTarget.value);
|
|
830
910
|
web.insert(_el$95, web.createComponent(solidJs.Show, {
|
|
831
911
|
get when() {
|
|
832
912
|
return web.memo(() => !!isOpen())() && suggestions().length > 0;
|
|
833
913
|
},
|
|
834
914
|
get children() {
|
|
835
|
-
var _el$
|
|
836
|
-
web.insert(_el$
|
|
915
|
+
var _el$99 = web.getNextElement(_tmpl$31);
|
|
916
|
+
web.insert(_el$99, web.createComponent(solidJs.For, {
|
|
837
917
|
get each() {
|
|
838
918
|
return suggestions();
|
|
839
919
|
},
|
|
840
920
|
children: (item) => {
|
|
841
921
|
const isSelected = () => isMultiple() && selectedValues().includes(item.value);
|
|
842
922
|
return (() => {
|
|
843
|
-
var _el$
|
|
844
|
-
_el$
|
|
845
|
-
_el$
|
|
846
|
-
web.insert(_el$
|
|
847
|
-
web.insert(_el$
|
|
923
|
+
var _el$110 = web.getNextElement(_tmpl$34), _el$112 = _el$110.firstChild, [_el$113, _co$25] = web.getNextMarker(_el$112.nextSibling), _el$114 = _el$113.nextSibling, [_el$115, _co$26] = web.getNextMarker(_el$114.nextSibling);
|
|
924
|
+
_el$110.$$click = () => selectSuggestion(item);
|
|
925
|
+
_el$110.$$mousedown = (e) => e.preventDefault();
|
|
926
|
+
web.insert(_el$110, () => item.label, _el$113, _co$25);
|
|
927
|
+
web.insert(_el$110, web.createComponent(solidJs.Show, {
|
|
848
928
|
get when() {
|
|
849
929
|
return isSelected();
|
|
850
930
|
},
|
|
851
931
|
get children() {
|
|
852
|
-
return web.getNextElement(_tmpl$
|
|
932
|
+
return web.getNextElement(_tmpl$33);
|
|
853
933
|
}
|
|
854
|
-
}), _el$
|
|
934
|
+
}), _el$115, _co$26);
|
|
855
935
|
web.effect((_p$) => {
|
|
856
936
|
var _v$83 = `w-full text-left px-3 py-2 text-sm hover:bg-blue-50 dark:hover:bg-blue-900/20 ${isSelected() ? "text-blue-600 dark:text-blue-400 bg-blue-50/50 dark:bg-blue-900/10" : "text-gray-900 dark:text-white"}`, _v$84 = isSelected();
|
|
857
|
-
_v$83 !== _p$.e && web.className(_el$
|
|
858
|
-
_v$84 !== _p$.t && web.setProperty(_el$
|
|
937
|
+
_v$83 !== _p$.e && web.className(_el$110, _p$.e = _v$83);
|
|
938
|
+
_v$84 !== _p$.t && web.setProperty(_el$110, "disabled", _p$.t = _v$84);
|
|
859
939
|
return _p$;
|
|
860
940
|
}, {
|
|
861
941
|
e: void 0,
|
|
862
942
|
t: void 0
|
|
863
943
|
});
|
|
864
944
|
web.runHydrationEvents();
|
|
865
|
-
return _el$
|
|
945
|
+
return _el$110;
|
|
866
946
|
})();
|
|
867
947
|
}
|
|
868
948
|
}));
|
|
869
|
-
return _el$
|
|
949
|
+
return _el$99;
|
|
870
950
|
}
|
|
871
|
-
}), _el$
|
|
951
|
+
}), _el$105, _co$23);
|
|
872
952
|
web.effect((_p$) => {
|
|
873
|
-
var _v$80 = isMultiple() && selectedValues().length ? "Add more..." : props.field.placeholder, _v$81 = props.disabled, _v$82 = props.baseClass;
|
|
874
|
-
_v$80 !== _p$.e && web.setAttribute(_el$
|
|
875
|
-
_v$81 !== _p$.t && web.setProperty(_el$
|
|
876
|
-
_v$82 !== _p$.a && web.className(_el$
|
|
953
|
+
var _v$80 = isMultiple() && selectedValues().length ? "Add more..." : props.field.placeholder, _v$81 = props.disabled || resolving(), _v$82 = props.baseClass;
|
|
954
|
+
_v$80 !== _p$.e && web.setAttribute(_el$98, "placeholder", _p$.e = _v$80);
|
|
955
|
+
_v$81 !== _p$.t && web.setProperty(_el$98, "disabled", _p$.t = _v$81);
|
|
956
|
+
_v$82 !== _p$.a && web.className(_el$98, _p$.a = _v$82);
|
|
877
957
|
return _p$;
|
|
878
958
|
}, {
|
|
879
959
|
e: void 0,
|
|
880
960
|
t: void 0,
|
|
881
961
|
a: void 0
|
|
882
962
|
});
|
|
883
|
-
web.effect(() => web.setProperty(_el$
|
|
963
|
+
web.effect(() => web.setProperty(_el$98, "value", query()));
|
|
884
964
|
web.runHydrationEvents();
|
|
885
965
|
return _el$95;
|
|
886
966
|
})();
|
|
@@ -907,46 +987,46 @@ const TagsField = (props) => {
|
|
|
907
987
|
}
|
|
908
988
|
};
|
|
909
989
|
return (() => {
|
|
910
|
-
var _el$
|
|
911
|
-
web.insert(_el$
|
|
990
|
+
var _el$116 = web.getNextElement(_tmpl$35), _el$119 = _el$116.firstChild, [_el$120, _co$27] = web.getNextMarker(_el$119.nextSibling), _el$118 = _el$120.nextSibling;
|
|
991
|
+
web.insert(_el$116, web.createComponent(solidJs.Show, {
|
|
912
992
|
get when() {
|
|
913
993
|
return (props.value || []).length > 0;
|
|
914
994
|
},
|
|
915
995
|
get children() {
|
|
916
|
-
var _el$
|
|
917
|
-
web.insert(_el$
|
|
996
|
+
var _el$117 = web.getNextElement(_tmpl$23);
|
|
997
|
+
web.insert(_el$117, web.createComponent(solidJs.For, {
|
|
918
998
|
get each() {
|
|
919
999
|
return props.value || [];
|
|
920
1000
|
},
|
|
921
1001
|
children: (tag) => (() => {
|
|
922
|
-
var _el$
|
|
923
|
-
web.insert(_el$
|
|
924
|
-
_el$
|
|
925
|
-
web.setAttribute(_el$
|
|
1002
|
+
var _el$121 = web.getNextElement(_tmpl$28), _el$123 = _el$121.firstChild, [_el$124, _co$28] = web.getNextMarker(_el$123.nextSibling), _el$122 = _el$124.nextSibling;
|
|
1003
|
+
web.insert(_el$121, tag, _el$124, _co$28);
|
|
1004
|
+
_el$122.$$click = () => removeTag(tag);
|
|
1005
|
+
web.setAttribute(_el$122, "aria-label", `Remove ${tag}`);
|
|
926
1006
|
web.runHydrationEvents();
|
|
927
|
-
return _el$
|
|
1007
|
+
return _el$121;
|
|
928
1008
|
})()
|
|
929
1009
|
}));
|
|
930
|
-
return _el$
|
|
1010
|
+
return _el$117;
|
|
931
1011
|
}
|
|
932
|
-
}), _el$
|
|
933
|
-
_el$
|
|
934
|
-
_el$
|
|
935
|
-
_el$
|
|
1012
|
+
}), _el$120, _co$27);
|
|
1013
|
+
_el$118.addEventListener("blur", addTag);
|
|
1014
|
+
_el$118.$$keydown = handleKeyDown;
|
|
1015
|
+
_el$118.$$input = (e) => setInput(e.currentTarget.value);
|
|
936
1016
|
web.effect((_p$) => {
|
|
937
1017
|
var _v$85 = props.placeholder || "Type and press Enter...", _v$86 = props.disabled, _v$87 = props.baseClass;
|
|
938
|
-
_v$85 !== _p$.e && web.setAttribute(_el$
|
|
939
|
-
_v$86 !== _p$.t && web.setProperty(_el$
|
|
940
|
-
_v$87 !== _p$.a && web.className(_el$
|
|
1018
|
+
_v$85 !== _p$.e && web.setAttribute(_el$118, "placeholder", _p$.e = _v$85);
|
|
1019
|
+
_v$86 !== _p$.t && web.setProperty(_el$118, "disabled", _p$.t = _v$86);
|
|
1020
|
+
_v$87 !== _p$.a && web.className(_el$118, _p$.a = _v$87);
|
|
941
1021
|
return _p$;
|
|
942
1022
|
}, {
|
|
943
1023
|
e: void 0,
|
|
944
1024
|
t: void 0,
|
|
945
1025
|
a: void 0
|
|
946
1026
|
});
|
|
947
|
-
web.effect(() => web.setProperty(_el$
|
|
1027
|
+
web.effect(() => web.setProperty(_el$118, "value", input()));
|
|
948
1028
|
web.runHydrationEvents();
|
|
949
|
-
return _el$
|
|
1029
|
+
return _el$116;
|
|
950
1030
|
})();
|
|
951
1031
|
};
|
|
952
1032
|
web.delegateEvents(["focusin", "click", "input", "mousedown", "keydown"]);
|