feat(components): 添加 Input 组件
- 实现了一个通用的 Input 组件,支持多种变体和自定义样式 - 组件属性包括 name、variant、left、right、value、defaultValue 等 - 支持 onInput 事件处理 - 优化了组件的默认值设置和响应式行为
This commit is contained in:
73
src/components/Input.tsx
Normal file
73
src/components/Input.tsx
Normal file
@@ -0,0 +1,73 @@
|
||||
import cx from 'clsx';
|
||||
import { isNotNil } from 'es-toolkit';
|
||||
import { Component, createEffect, createSignal, JSX, mergeProps, onMount, Show } from 'solid-js';
|
||||
|
||||
interface InputProps extends JSX.HTMLAttributes<HTMLInputElement> {
|
||||
name?: string;
|
||||
variant?: 'normal' | 'underlined' | 'immersive';
|
||||
left?: JSX.Element;
|
||||
right?: JSX.Element;
|
||||
value?: string;
|
||||
defaultValue?: string;
|
||||
placeholder?: string;
|
||||
disabled?: boolean;
|
||||
onInput?: (value: string | null) => void;
|
||||
wrapperClass?: JSX.HTMLAttributes<HTMLDivElement>['class'];
|
||||
inputClass?: JSX.HTMLAttributes<HTMLInputElement>['class'];
|
||||
}
|
||||
|
||||
const Input: Component<InputProps> = (props) => {
|
||||
const mProps = mergeProps<InputProps[]>(
|
||||
{
|
||||
variant: 'normal',
|
||||
disabled: false,
|
||||
placeholder: '',
|
||||
},
|
||||
props,
|
||||
);
|
||||
const [internalValue, setInternalValue] = createSignal<string>('');
|
||||
onMount(() => {
|
||||
if (isNotNil(mProps.defaultValue)) {
|
||||
setInternalValue(mProps.defaultValue);
|
||||
}
|
||||
});
|
||||
createEffect(() => {
|
||||
if (isNotNil(mProps.value) && mProps.value !== internalValue()) {
|
||||
setInternalValue(mProps.value);
|
||||
}
|
||||
});
|
||||
|
||||
const handleInput: JSX.EventHandler<HTMLInputElement, InputEvent> = (evt) => {
|
||||
const value = evt.currentTarget.value;
|
||||
setInternalValue(value);
|
||||
mProps.onInput?.(value);
|
||||
};
|
||||
|
||||
return (
|
||||
<div
|
||||
aria-disabled={mProps.disabled}
|
||||
class={cx(
|
||||
'flex flex-row items-center gap-2 min-h-[1em] px-3 py-1.5',
|
||||
mProps.variant === 'normal' &&
|
||||
'rounded-sm bg-neutral text-on-neutral aria-disabled:cursor-not-allowed aria-disabled:bg-neutral-disabled aria-disabled:text-on-neutral-disabled disabled:bg-neutral-disabled disabled:text-on-neutral-disabled',
|
||||
mProps.variant === 'underlined' &&
|
||||
'border-b border-solid pb-[calc(var(--spacing)*1.5-1px)] border-on-surface text-on-surface aria-disabled:border-neutral-disabled aria-disabled:text-neutral-disabled',
|
||||
mProps.variant === 'immersive' && 'text-on-surface aria-disabled:text-neutral-disabled',
|
||||
mProps.wrapperClass,
|
||||
)}>
|
||||
<Show when={isNotNil(mProps.left)}>{mProps.left}</Show>
|
||||
<input
|
||||
name={mProps.name}
|
||||
type={mProps.type}
|
||||
placeholder={mProps.placeholder}
|
||||
disabled={mProps.disabled}
|
||||
value={internalValue()}
|
||||
class={cx('min-h-[1em] grow focus:outline-none placeholder:italic', mProps.inputClass)}
|
||||
onInput={handleInput}
|
||||
/>
|
||||
<Show when={isNotNil(mProps.right)}>{mProps.right}</Show>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default Input;
|
Reference in New Issue
Block a user