feat(ui): add select primitive and readonly control states
This commit is contained in:
1 parent
fb7e2eb3da
commit
291cbee485
6 files changed
+133
-2
No files matched your search
@@ -33,6 +33,7 @@ export function Input({
|
||||
wrapperClassName,
|
||||
className,
|
||||
disabled,
|
||||
readOnly,
|
||||
...inputProps
|
||||
}: InputProps): React.JSX.Element {
|
||||
const wrapperClass = classNames(
|
||||
@@ -45,9 +46,10 @@ export function Input({
|
||||
)
|
||||
|
||||
return (
|
||||
<div className={wrapperClass} data-disabled={disabled ? 'true' : undefined}>
|
||||
<div className={wrapperClass} data-disabled={disabled ? 'true' : undefined}
|
||||
data-readonly={readOnly ? 'true' : undefined}>
|
||||
{prefix ? <span className="yc-input__prefix">{prefix}</span> : null}
|
||||
<input className={classNames('yc-input__inner', className)} disabled={disabled} {...inputProps} />
|
||||
<input className={classNames('yc-input__inner', className)} disabled={disabled} readOnly={readOnly} {...inputProps} />
|
||||
{suffix ? <span className="yc-input__suffix">{suffix}</span> : null}
|
||||
</div>
|
||||
)
|
||||
|
||||
@@ -0,0 +1,82 @@
|
||||
/**
|
||||
* YCode UI Select(P3)。
|
||||
*
|
||||
* 外观壳与行为复用 `components/source-select/SourceSelect.tsx`(RecoveredSelect),
|
||||
* 不重写闭合态标记、弹层与键盘行为;这里只做尺寸命名映射与只读入口。
|
||||
*
|
||||
* 契约见 `docs/界面基础组件规范-2026-10-18.md` 的 Select 章节:
|
||||
* 对外尺寸 sm|md|lg,内部映射 small|medium|large,几何沿用恢复样式。
|
||||
*/
|
||||
import SourceSelect, { type SourceSelectProps } from '../components/source-select/SourceSelect'
|
||||
import './select.css'
|
||||
|
||||
export type SelectSize = 'sm' | 'md' | 'lg'
|
||||
|
||||
const SOURCE_SIZE: Record<SelectSize, 'small' | 'medium' | 'large'> = {
|
||||
sm: 'small',
|
||||
md: 'medium',
|
||||
lg: 'large'
|
||||
}
|
||||
|
||||
export interface SelectProps extends Omit<SourceSelectProps, 'size'> {
|
||||
size?: SelectSize
|
||||
}
|
||||
|
||||
function classNames(...values: Array<string | false | null | undefined>): string {
|
||||
return values.filter(Boolean).join(' ')
|
||||
}
|
||||
|
||||
/** 统一下拉:透传 source-select 的全部现有 props,仅替换 size 命名。 */
|
||||
export function Select({ size = 'md', className, ...props }: SelectProps): React.JSX.Element {
|
||||
return (
|
||||
<SourceSelect
|
||||
{...props}
|
||||
className={classNames('yc-select', `yc-select--${size}`, className)}
|
||||
size={SOURCE_SIZE[size]}
|
||||
/>
|
||||
)
|
||||
}
|
||||
|
||||
export interface StaticSelectProps {
|
||||
/** 闭合态显示值(原样渲染,不做截断/格式化)。 */
|
||||
value: string
|
||||
'aria-label': string
|
||||
/** 外层不可用提示文案,例如「暂未接入」。 */
|
||||
hint?: string
|
||||
size?: SelectSize
|
||||
/** 落到闭合态按钮上,保留页面级 `.xxx.wb-select` 布局覆盖的选择器命中。 */
|
||||
className?: string
|
||||
}
|
||||
|
||||
const noop = (): void => {}
|
||||
|
||||
/**
|
||||
* 只读/不可用的静态下拉:复用同一个 Select 闭合态壳,但停在闭合态。
|
||||
*
|
||||
* - `disabled` 让 RecoveredSelect/Popover 都拒绝展开,同时把按钮移出 Tab 顺序;
|
||||
* - 恢复样式的 `.wb-select--disabled` 会降低前景对比度,`select.css` 按
|
||||
* --yc-select-* token 把它还原成普通闭合态(不可用行要求保持原版外观);
|
||||
* - 外层保留 data-settings-unavailable / aria-disabled / title 语义。
|
||||
*/
|
||||
export function StaticSelect({
|
||||
value,
|
||||
hint,
|
||||
size = 'md',
|
||||
className,
|
||||
'aria-label': ariaLabel
|
||||
}: StaticSelectProps): React.JSX.Element {
|
||||
return (
|
||||
<span className="yc-select-static source-select-host" data-settings-unavailable="true" aria-disabled="true" title={hint}>
|
||||
<SourceSelect
|
||||
className={classNames('yc-select', `yc-select--${size}`, 'yc-select--static', className)}
|
||||
size={SOURCE_SIZE[size]}
|
||||
value={value}
|
||||
options={[{ value, label: value }]}
|
||||
displayLabel={value}
|
||||
disabled
|
||||
onChange={noop}
|
||||
ariaLabel={ariaLabel}
|
||||
/>
|
||||
</span>
|
||||
)
|
||||
}
|
||||
@@ -16,6 +16,7 @@ export interface SwitchProps {
|
||||
onCheckedChange?(checked: boolean): void
|
||||
disabled?: boolean
|
||||
readOnly?: boolean
|
||||
tabIndex?: number
|
||||
size?: SwitchSize
|
||||
'aria-label': string
|
||||
className?: string
|
||||
@@ -30,6 +31,7 @@ export function Switch({
|
||||
onCheckedChange,
|
||||
disabled = false,
|
||||
readOnly = false,
|
||||
tabIndex,
|
||||
size = 'md',
|
||||
className,
|
||||
'aria-label': ariaLabel
|
||||
@@ -54,6 +56,7 @@ export function Switch({
|
||||
aria-readonly={readOnly || undefined}
|
||||
checked={checked}
|
||||
disabled={disabled}
|
||||
tabIndex={tabIndex}
|
||||
onChange={handleChange}
|
||||
/>
|
||||
<span className="yc-switch__track">
|
||||
|
||||
@@ -38,6 +38,11 @@
|
||||
outline: none;
|
||||
}
|
||||
|
||||
.yc-input[data-readonly='true'],
|
||||
.yc-input[data-readonly='true'] .yc-input__inner {
|
||||
cursor: default;
|
||||
}
|
||||
|
||||
.yc-input__inner::placeholder {
|
||||
color: var(--yc-input-placeholder);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,32 @@
|
||||
/**
|
||||
* YCode UI Select 样式(P3)。
|
||||
*
|
||||
* 常规 `Select` 直接复用 source-select 的恢复样式(闭合态几何与状态一律不重写),
|
||||
* 因此本文件不定义基础尺寸/边框/宽度,避免盖掉页面级
|
||||
* `.general-settings-panel .wb-select`、`.power-save-blocker-settings__select.wb-select`
|
||||
* 这类同元素(0,2,0)覆盖。
|
||||
*
|
||||
* 本文件只处理 `StaticSelect`:恢复样式用 `.wb-select--disabled` 表达不可用,
|
||||
* 而设置页不可用行必须保持「普通闭合态」外观(不允许 disabled 降低前景对比度),
|
||||
* 所以按 --yc-select-* token 把颜色与光标还原回闭合态。
|
||||
* 选择器权重 (0,3,0)/(0,4,0) 高于 `.source-select-host .wb-select--disabled`
|
||||
* 的 (0,2,0)/(0,3,0),不依赖样式表先后顺序。
|
||||
*/
|
||||
|
||||
.yc-select-static {
|
||||
display: inline-flex;
|
||||
min-width: 0;
|
||||
}
|
||||
|
||||
.source-select-host .yc-select--static.wb-select--disabled {
|
||||
color: var(--yc-select-fg-static);
|
||||
cursor: default;
|
||||
}
|
||||
|
||||
.source-select-host .yc-select--static.wb-select--disabled:hover {
|
||||
border-color: var(--yc-select-border-hover);
|
||||
}
|
||||
|
||||
.source-select-host .yc-select--static.wb-select--disabled .wb-select__caret {
|
||||
color: var(--yc-select-icon-static);
|
||||
}
|
||||
@@ -160,6 +160,10 @@
|
||||
--yc-select-bg-disabled: #f7f7f7;
|
||||
--yc-select-fg-disabled: rgba(0, 0, 0, 0.3);
|
||||
|
||||
/* Select 静态只读闭合态:等价恢复样式 .wb-select 的非 disabled 外观,深色见下方覆盖 */
|
||||
--yc-select-fg-static: #000;
|
||||
--yc-select-icon-static: rgba(0, 0, 0, 0.5);
|
||||
|
||||
/* Dialog */
|
||||
--yc-dialog-bg: #ffffff;
|
||||
--yc-dialog-border: #dedede;
|
||||
@@ -274,6 +278,9 @@ html[data-theme='dark'] {
|
||||
--yc-select-bg-disabled: #171717;
|
||||
--yc-select-fg-disabled: rgba(255, 255, 255, 0.3);
|
||||
|
||||
--yc-select-fg-static: #fff;
|
||||
--yc-select-icon-static: rgba(255, 255, 255, 0.5);
|
||||
|
||||
--yc-dialog-bg: #1f1f1f;
|
||||
--yc-dialog-border: #3d3d3d;
|
||||
--yc-dialog-overlay: rgba(0, 0, 0, 0.4);
|
||||
|
||||
Reference in new issue
Block a user