修复角色中心组件中的类型不匹配错误,改进skinId和capeId的类型处理逻辑

This commit is contained in:
Mikuisnotavailable
2025-10-16 01:59:17 +08:00
parent d9a15dd13d
commit 167c51b20d
21 changed files with 4548 additions and 329 deletions

View File

@@ -0,0 +1,185 @@
import * as React from 'react';
// 创建Select上下文
const SelectContext = React.createContext<{
value: string;
setValue: (value: string) => void;
open: boolean;
setOpen: (open: boolean) => void;
} | null>(null);
// Select组件接口
export interface SelectProps {
defaultValue?: string;
value?: string;
onValueChange?: (value: string) => void;
children: React.ReactNode;
className?: string;
}
// SelectTrigger组件接口
export interface SelectTriggerProps {
children: React.ReactNode;
className?: string;
}
// SelectValue组件接口
export interface SelectValueProps {
placeholder?: string;
children?: React.ReactNode;
}
// SelectContent组件接口
export interface SelectContentProps {
children: React.ReactNode;
className?: string;
}
// SelectItem组件接口
export interface SelectItemProps {
value: string;
children: React.ReactNode;
className?: string;
}
/**
* Select组件 - 管理选择器的状态
*/
export const Select: React.FC<SelectProps> = ({
defaultValue = '',
value: valueProp,
onValueChange,
children,
className = ''
}) => {
const [valueState, setValueState] = React.useState(defaultValue);
const [open, setOpen] = React.useState(false);
const value = valueProp !== undefined ? valueProp : valueState;
const setValue = valueProp !== undefined && onValueChange
? onValueChange
: setValueState;
// 点击外部关闭下拉菜单
React.useEffect(() => {
if (open) {
const handleClickOutside = (event: MouseEvent) => {
const target = event.target as HTMLElement;
if (!target.closest(`.${className}`) && !target.closest('.select-trigger')) {
setOpen(false);
}
};
document.addEventListener('mousedown', handleClickOutside);
return () => {
document.removeEventListener('mousedown', handleClickOutside);
};
}
}, [open, className]);
return (
<SelectContext.Provider value={{ value, setValue, open, setOpen }}>
<div className={className}>{children}</div>
</SelectContext.Provider>
);
};
/**
* SelectTrigger组件 - 选择器的触发器按钮
*/
export const SelectTrigger: React.FC<SelectTriggerProps> = ({ children, className = '' }) => {
const context = React.useContext(SelectContext);
if (!context) {
throw new Error('SelectTrigger must be used within a Select component');
}
const handleClick = () => {
context.setOpen(!context.open);
};
return (
<button
type="button"
onClick={handleClick}
className={`px-4 py-2 border rounded-md flex items-center justify-between w-full select-trigger ${className}`}
>
{children}
<span className="ml-2"></span>
</button>
);
};
/**
* SelectValue组件 - 显示当前选中的值或占位符
*/
export const SelectValue: React.FC<SelectValueProps> = ({ placeholder, children }) => {
const context = React.useContext(SelectContext);
if (!context) {
throw new Error('SelectValue must be used within a Select component');
}
if (context.value && children) {
return <span>{children}</span>;
}
return placeholder ? (
<span className="text-gray-500">{placeholder}</span>
) : null;
};
/**
* SelectContent组件 - 包含选项的下拉菜单
*/
export const SelectContent: React.FC<SelectContentProps> = ({ children, className = '' }) => {
const context = React.useContext(SelectContext);
if (!context) {
throw new Error('SelectContent must be used within a Select component');
}
if (!context.open) {
return null;
}
return (
<div className={`absolute mt-1 border rounded-md bg-white shadow-lg z-10 max-h-60 overflow-auto ${className}`}>
{children}
</div>
);
};
/**
* SelectItem组件 - 选择器中的单个选项
*/
export const SelectItem: React.FC<SelectItemProps> = ({
value,
children,
className = ''
}) => {
const context = React.useContext(SelectContext);
if (!context) {
throw new Error('SelectItem must be used within a Select component');
}
const isSelected = context.value === value;
const handleClick = () => {
context.setValue(value);
context.setOpen(false);
};
return (
<button
type="button"
onClick={handleClick}
className={`block w-full text-left px-4 py-2 hover:bg-gray-100 ${isSelected ? 'bg-blue-50 text-blue-500' : ''} ${className}`}
>
{children}
</button>
);
};
export default Select;