revert: property editor

This commit is contained in:
hypercross 2026-02-27 14:02:11 +08:00
parent fdecd0fb6e
commit 14ce2e1a6b
3 changed files with 13 additions and 275 deletions

View File

@ -1,156 +0,0 @@
import {Component, For, Show} from 'solid-js';
import type { FieldSchema } from './hooks/types';
export interface FieldEditorProps {
/** 字段 Schema 定义 */
field: FieldSchema;
/** 当前值 */
value: string | number | boolean;
/** 值变化回调 */
onChange: (value: string | number | boolean) => void;
/** 是否禁用 */
disabled?: boolean;
}
/**
*
*
*/
export const FieldEditor: Component<FieldEditorProps> = (props) => {
const handleChange = (e: Event) => {
const target = e.target as HTMLInputElement | HTMLTextAreaElement | HTMLSelectElement;
let value: string | number | boolean;
if (props.field.type === 'boolean') {
value = (target as HTMLInputElement).checked;
} else if (props.field.type === 'number') {
value = Number(target.value);
} else {
value = target.value;
}
props.onChange(value);
};
const label = props.field.label || props.field.key;
return (
<div>
<label class="block text-sm font-medium text-gray-700 mb-1">
{label}
<Show when={props.field.required}>
<span class="text-red-500 ml-1">*</span>
</Show>
</label>
{/* 字符串输入 */}
<Show when={props.field.type === 'string'}>
<input
type="text"
class="w-full border border-gray-300 rounded px-2 py-1 text-sm focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-transparent"
placeholder={props.field.placeholder}
value={props.value as string}
onInput={handleChange}
disabled={props.disabled}
/>
</Show>
{/* 多行文本输入 */}
<Show when={props.field.type === 'text'}>
<textarea
class="w-full border border-gray-300 rounded px-2 py-1 text-sm focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-transparent"
placeholder={props.field.placeholder}
rows={props.field.rows || 3}
value={props.value as string}
onInput={handleChange}
disabled={props.disabled}
/>
</Show>
{/* 数字输入 */}
<Show when={props.field.type === 'number'}>
<input
type="number"
class="w-full border border-gray-300 rounded px-2 py-1 text-sm focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-transparent"
placeholder={props.field.placeholder}
min={props.field.min}
max={props.field.max}
value={props.value as number}
onInput={handleChange}
disabled={props.disabled}
/>
</Show>
{/* 布尔输入 */}
<Show when={props.field.type === 'boolean'}>
<div class="flex items-center">
<input
type="checkbox"
class="w-4 h-4 text-blue-600 border-gray-300 rounded focus:ring-blue-500"
checked={props.value as boolean}
onChange={handleChange}
disabled={props.disabled}
/>
<Show when={props.field.description}>
<span class="ml-2 text-sm text-gray-600">{props.field.description}</span>
</Show>
</div>
</Show>
{/* 选择输入 */}
<Show when={props.field.type === 'select'}>
<select
class="w-full border border-gray-300 rounded px-2 py-1 text-sm focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-transparent"
value={props.value as string}
onChange={handleChange}
disabled={props.disabled}
>
<Show when={props.field.placeholder}>
<option value="">{props.field.placeholder}</option>
</Show>
<For each={props.field.options}>
{(option) => (
<option value={option.value}>{option.label}</option>
)}
</For>
</select>
</Show>
<Show when={props.field.description && props.field.type !== 'boolean'}>
<p class="mt-1 text-xs text-gray-500">{props.field.description}</p>
</Show>
</div>
);
};
/**
*
* Schema
*/
export interface PropertyFormProps<T extends Record<string, string | number | boolean>> {
/** Schema 定义 */
schema: import('./hooks/types').Schema;
/** 当前值 */
values: T;
/** 值变化回调 */
onChange: (key: string, value: string | number | boolean) => void;
/** 是否禁用 */
disabled?: boolean;
}
export const PropertyForm: Component<PropertyFormProps<any>> = (props) => {
return (
<div class="space-y-3">
<For each={props.schema.fields}>
{(field) => (
<FieldEditor
field={field}
value={props.values[field.key]}
onChange={(value) => props.onChange(field.key, value)}
disabled={props.disabled}
/>
)}
</For>
</div>
);
};

View File

@ -1,7 +1,5 @@
import { Show, For } from 'solid-js'; import { Show, For } from 'solid-js';
import type { CardData, LayerConfig } from './types'; import type { CardData, LayerConfig } from './types';
import { FieldEditor, PropertyForm } from './FieldEditor';
import type { FieldSchema } from './hooks/types';
export interface DataEditorPanelProps { export interface DataEditorPanelProps {
cards: CardData[]; cards: CardData[];
@ -25,41 +23,28 @@ export interface PropertiesEditorPanelProps {
onCopyCode: () => void; onCopyCode: () => void;
} }
/**
* CardData Schema
*/
function createCardDataSchema(keys: string[]): FieldSchema[] {
return keys.map((key) => ({
key,
label: key.charAt(0).toUpperCase() + key.slice(1),
type: 'text',
rows: 3
}));
}
/** /**
* CSV * CSV
* 使 FieldEditor
*/ */
export function DataEditorPanel(props: DataEditorPanelProps) { export function DataEditorPanel(props: DataEditorPanelProps) {
const currentCard = () => props.cards[props.activeTab] || {};
const fieldKeys = () => Object.keys(currentCard());
const schema = () => ({ fields: createCardDataSchema(fieldKeys()) });
const handleChange = (key: string, value: string | number | boolean) => {
props.updateCardData(key, String(value));
};
return ( return (
<div class="w-64 flex-shrink-0"> <div class="w-64 flex-shrink-0">
<h3 class="font-bold mb-2"></h3> <h3 class="font-bold mb-2"></h3>
<div class="space-y-2 max-h-96 overflow-y-auto"> <div class="space-y-2 max-h-96 overflow-y-auto">
<PropertyForm <For each={Object.keys(props.cards[props.activeTab] || {})}>
schema={schema()} {(key) => (
values={currentCard()} <div>
onChange={handleChange} <label class="block text-sm font-medium text-gray-700">{key}</label>
<textarea
class="w-full border border-gray-300 rounded px-2 py-1 text-sm"
rows={3}
value={props.cards[props.activeTab]?.[key] || ''}
onInput={(e) => props.updateCardData(key, e.target.value)}
/> />
</div> </div>
)}
</For>
</div>
</div> </div>
); );
} }

View File

@ -1,91 +0,0 @@
import { createSignal, createMemo, For } from 'solid-js';
import type { Schema, PropertyValues, UsePropertyEditorReturn, FieldSchema } from './types';
/**
* Hook
*
* @param schema - Schema
* @param initialValues -
* @returns
*/
export function usePropertyEditor<T extends PropertyValues>(
schema: Schema,
initialValues: T
): UsePropertyEditorReturn<T> & {
/** Schema 定义 */
schema: Schema;
/** 字段信号 Map */
fieldSignals: Map<keyof T, ReturnType<typeof createSignal<string | number | boolean>>>;
} {
// 为每个字段创建独立的 signal
const fieldSignals = new Map<keyof T, ReturnType<typeof createSignal<string | number | boolean>>>();
for (const field of schema.fields) {
const key = field.key as keyof T;
const initialValue = initialValues[key] ?? field.default ?? '';
fieldSignals.set(key, createSignal(initialValue as any));
}
const get = <K extends keyof T>(key: K): T[K] => {
const signal = fieldSignals.get(key);
if (!signal) {
throw new Error(`Field "${String(key)}" not found in schema`);
}
return signal[0]() as T[K];
};
const set = <K extends keyof T>(key: K, value: T[K]) => {
const signal = fieldSignals.get(key);
if (!signal) {
throw new Error(`Field "${String(key)}" not found in schema`);
}
signal[1](value as any);
};
const getAll = (): T => {
const result = {} as T;
for (const field of schema.fields) {
const key = field.key as keyof T;
result[key] = get(key);
}
return result;
};
const setAll = (values: T) => {
for (const field of schema.fields) {
const key = field.key as keyof T;
if (key in values) {
set(key, values[key]);
}
}
};
const reset = () => {
for (const field of schema.fields) {
const key = field.key as keyof T;
const defaultValue = field.default ?? '';
set(key, defaultValue as T[keyof T]);
}
};
return {
schema,
fieldSignals,
get,
set,
getAll,
setAll,
reset
};
}
/**
* Schema
*/
export function createDefaultValues<T extends PropertyValues>(schema: Schema): T {
const result = {} as T;
for (const field of schema.fields) {
result[field.key as keyof T] = (field.default ?? '') as T[keyof T];
}
return result;
}