docs: add comments to the src/components directory

This commit is contained in:
zhaoying
2026-02-02 16:14:39 +08:00
parent 9a38e8a4a0
commit a191e32f71
55 changed files with 1417 additions and 375 deletions

View File

@@ -1,24 +1,59 @@
/*
* @Author: ZhaoYing
* @Date: 2026-02-02 15:19:30
* @Last Modified by: ZhaoYing
* @Last Modified time: 2026-02-02 15:19:30
*/
/**
* RadioGroupCard Component
*
* A radio group component that displays options as selectable cards with:
* - Visual card-based selection interface
* - Optional icons and descriptions
* - Support for clear selection
* - Block or inline layout modes
* - Custom item rendering
*
* @component
*/
import { type FC, type Key, type ReactNode, useEffect } from 'react';
import { type RadioGroupProps } from 'antd';
import clsx from 'clsx'
/** Radio card option interface */
interface RadioCardOption {
/** Option value */
value: string | number | boolean | null | undefined | Key;
/** Option label text */
label: string;
/** Optional description text */
labelDesc?: string;
/** Optional icon URL */
icon?: string;
/** Whether the option is disabled */
disabled?: boolean;
/** Additional properties */
[key: string]: string | number | boolean | undefined | null | Key;
}
/** Props interface for RadioGroupCard component */
interface RadioCardProps extends Omit<RadioGroupProps, 'onChange'> {
/** Array of radio card options */
options: RadioCardOption[];
/** Callback fired when value changes (for side effects) */
onValueChange?: (value: string | null | undefined, option?: RadioCardOption) => void;
/** Callback fired when selection changes */
onChange?: (value: string | null | undefined, option?: RadioCardOption) => void;
/** Custom render function for each option */
itemRender?: (option: RadioCardOption) => ReactNode;
/** Whether clicking selected option clears selection */
allowClear?: boolean;
/** Whether to display cards in block (vertical) layout */
block?: boolean;
}
/** Radio group card component that displays options as selectable cards */
const RadioGroupCard: FC<RadioCardProps> = ({
options,
value,
@@ -28,16 +63,19 @@ const RadioGroupCard: FC<RadioCardProps> = ({
allowClear = true,
block = false,
}) => {
// 监听value变化
/** Listen to value changes and trigger side effects via onValueChange callback */
useEffect(() => {
if (onValueChange) {
onValueChange(value);
}
}, [value, onValueChange]);
/** Handle option selection with support for clear and disabled states */
const handleChange = (option: RadioCardOption) => {
// Ignore clicks on disabled options
if (option.disabled) return
if (onChange) {
// Clear selection if allowClear is true and option is already selected
if (allowClear && value === option.value) {
onChange(null, undefined);
} else {
@@ -51,6 +89,7 @@ const RadioGroupCard: FC<RadioCardProps> = ({
'rb:gap-3': !block,
'rb:gap-4': block,
})}>
{/* Render each option as a selectable card */}
{options.map(option => (
<div key={String(option.value)} className={clsx("rb:border rb:rounded-lg rb:w-full rb:p-[20px_12px] rb:text-center rb:cursor-pointer", {
'rb:bg-[rgba(21,94,239,0.06)] rb:border-[#155EEF]': option.value === value,
@@ -58,6 +97,7 @@ const RadioGroupCard: FC<RadioCardProps> = ({
'rb:opacity-[0.75]': option.disabled,
'rb:flex rb:items-center rb:text-left rb:gap-4': block,
})} onClick={() => handleChange(option)}>
{/* Use custom render or default card layout */}
{itemRender ? itemRender(option) : (
<>
{option.icon && <img src={option.icon} className={clsx("rb:w-10 rb:h-10", {