feat: 浏览器类型字段改为下拉选择
- catalog.json: WebBrowser_Create/V2/V3/CreateBackground 的 type 字段补 options(内置运行浏览器/Chrome/Edge,label 与存储值分离)
- shared/types.ts: CatalogField.options 支持字符串或 {label,value} 对象
- Properties.tsx: select/radio 选项归一化渲染 label;当前值不在选项中时追加显示(兼容历史手填值如 zexplorer)
- typecheck 通过;全量 vitest 除 4 项依赖真实 COM 的历史失败外全部通过
This commit is contained in:
parent
3d64392eb0
commit
f28b5ffc5e
@ -100005,7 +100005,21 @@
|
||||
"placeholder": "",
|
||||
"description": "",
|
||||
"advanced": false,
|
||||
"valueTypes": []
|
||||
"valueTypes": [],
|
||||
"options": [
|
||||
{
|
||||
"label": "内置运行浏览器",
|
||||
"value": "zexplorer"
|
||||
},
|
||||
{
|
||||
"label": "Chrome 浏览器",
|
||||
"value": "chrome"
|
||||
},
|
||||
{
|
||||
"label": "Edge 浏览器",
|
||||
"value": "edge"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"key": "url",
|
||||
@ -101046,7 +101060,21 @@
|
||||
"placeholder": "",
|
||||
"description": "选择浏览器类型",
|
||||
"advanced": false,
|
||||
"valueTypes": []
|
||||
"valueTypes": [],
|
||||
"options": [
|
||||
{
|
||||
"label": "内置运行浏览器",
|
||||
"value": "zexplorer"
|
||||
},
|
||||
{
|
||||
"label": "Chrome 浏览器",
|
||||
"value": "chrome"
|
||||
},
|
||||
{
|
||||
"label": "Edge 浏览器",
|
||||
"value": "edge"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"key": "url",
|
||||
@ -103389,7 +103417,21 @@
|
||||
"placeholder": "",
|
||||
"description": "选择浏览器类型",
|
||||
"advanced": false,
|
||||
"valueTypes": []
|
||||
"valueTypes": [],
|
||||
"options": [
|
||||
{
|
||||
"label": "内置运行浏览器",
|
||||
"value": "zexplorer"
|
||||
},
|
||||
{
|
||||
"label": "Chrome 浏览器",
|
||||
"value": "chrome"
|
||||
},
|
||||
{
|
||||
"label": "Edge 浏览器",
|
||||
"value": "edge"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"key": "url",
|
||||
@ -106333,7 +106375,21 @@
|
||||
"placeholder": "",
|
||||
"description": "选择浏览器类型",
|
||||
"advanced": false,
|
||||
"valueTypes": []
|
||||
"valueTypes": [],
|
||||
"options": [
|
||||
{
|
||||
"label": "内置运行浏览器",
|
||||
"value": "zexplorer"
|
||||
},
|
||||
{
|
||||
"label": "Chrome 浏览器",
|
||||
"value": "chrome"
|
||||
},
|
||||
{
|
||||
"label": "Edge 浏览器",
|
||||
"value": "edge"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"key": "url",
|
||||
@ -113804,4 +113860,4 @@
|
||||
"slots": []
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
@ -46,6 +46,23 @@ function numberOr(value: unknown, fallback: number): number {
|
||||
return Number.isFinite(parsed) ? parsed : fallback;
|
||||
}
|
||||
|
||||
interface SelectOption {
|
||||
label: string;
|
||||
value: string;
|
||||
}
|
||||
|
||||
/** 归一化下拉/单选选项:字符串 → {label,value};当前值不在选项中时追加进去(兼容历史手填值) */
|
||||
function selectOptionsWith(field: CatalogField, rawValue: unknown): SelectOption[] {
|
||||
const normalized = (field.options ?? []).map((option): SelectOption =>
|
||||
typeof option === "string" ? { label: option, value: option } : { label: option.label, value: option.value }
|
||||
);
|
||||
const current = textOf(rawValue);
|
||||
if (current && !normalized.some((option) => option.value === current)) {
|
||||
normalized.unshift({ label: `${current}(当前值)`, value: current });
|
||||
}
|
||||
return normalized;
|
||||
}
|
||||
|
||||
export function Properties({ catalog, onToast }: PropertiesProps) {
|
||||
const [tab, setTab] = useState<Tab>("props");
|
||||
const flow = useEditorStore((state) => state.flow);
|
||||
@ -575,22 +592,22 @@ function FieldControl({
|
||||
) : field.widget === "select" && field.options?.length ? (
|
||||
<select className="select-input" value={textOf(raw)} onChange={(event) => onChange(field.key, event.target.value)}>
|
||||
<option value="">请选择</option>
|
||||
{field.options.map((option) => (
|
||||
<option key={option} value={option}>
|
||||
{option}
|
||||
{selectOptionsWith(field, raw).map((option) => (
|
||||
<option key={option.value} value={option.value}>
|
||||
{option.label}
|
||||
</option>
|
||||
))}
|
||||
</select>
|
||||
) : field.widget === "radio" && field.options?.length ? (
|
||||
<div className="chip-row">
|
||||
{field.options.map((option) => (
|
||||
{selectOptionsWith(field, raw).map((option) => (
|
||||
<button
|
||||
type="button"
|
||||
key={option}
|
||||
className={`option-chip${textOf(raw) === option ? " active" : ""}`}
|
||||
onClick={() => onChange(field.key, option)}
|
||||
key={option.value}
|
||||
className={`option-chip${textOf(raw) === option.value ? " active" : ""}`}
|
||||
onClick={() => onChange(field.key, option.value)}
|
||||
>
|
||||
{option}
|
||||
{option.label}
|
||||
</button>
|
||||
))}
|
||||
</div>
|
||||
|
||||
@ -25,7 +25,8 @@ export interface CatalogField {
|
||||
description: string;
|
||||
advanced: boolean;
|
||||
valueTypes: string[];
|
||||
options?: string[];
|
||||
/** 下拉/单选选项:字符串(显示=存储值)或 { label, value }(显示与存储分离) */
|
||||
options?: Array<string | { label: string; value: string }>;
|
||||
unit?: string;
|
||||
}
|
||||
|
||||
|
||||
Loading…
Reference in New Issue
Block a user