This commit is contained in:
2026-05-25 17:08:18 +08:00
parent df501f6151
commit f1259b71b5
9178 changed files with 1626125 additions and 0 deletions
+16
View File
@@ -0,0 +1,16 @@
import * as React from 'react';
export interface GroupProps {
className?: string;
size?: 'large' | 'small' | 'default';
children?: React.ReactNode;
style?: React.CSSProperties;
onMouseEnter?: React.MouseEventHandler<HTMLSpanElement>;
onMouseLeave?: React.MouseEventHandler<HTMLSpanElement>;
onFocus?: React.FocusEventHandler<HTMLSpanElement>;
onBlur?: React.FocusEventHandler<HTMLSpanElement>;
prefixCls?: string;
compact?: boolean;
}
/** @deprecated Please use `Space.Compact` */
declare const Group: React.FC<GroupProps>;
export default Group;
+50
View File
@@ -0,0 +1,50 @@
"use client";
import * as React from 'react';
import { useContext, useMemo } from 'react';
import { clsx } from 'clsx';
import { devUseWarning } from '../_util/warning';
import { ConfigContext } from '../config-provider';
import { FormItemInputContext } from '../form/context';
import Space from '../space';
import useStyle from './style';
/** @deprecated Please use `Space.Compact` */
const Group = props => {
const {
getPrefixCls,
direction
} = useContext(ConfigContext);
const {
prefixCls: customizePrefixCls,
className
} = props;
const prefixCls = getPrefixCls('input-group', customizePrefixCls);
const inputPrefixCls = getPrefixCls('input');
const [hashId, cssVarCls] = useStyle(inputPrefixCls);
const cls = clsx(prefixCls, cssVarCls, {
[`${prefixCls}-lg`]: props.size === 'large',
[`${prefixCls}-sm`]: props.size === 'small',
[`${prefixCls}-compact`]: props.compact,
[`${prefixCls}-rtl`]: direction === 'rtl'
}, hashId, className);
const formItemContext = useContext(FormItemInputContext);
const groupFormItemContext = useMemo(() => ({
...formItemContext,
isFormItemInput: false
}), [formItemContext]);
if (process.env.NODE_ENV !== 'production') {
const warning = devUseWarning('Input.Group');
warning.deprecated(false, 'Input.Group', 'Space.Compact');
}
return /*#__PURE__*/React.createElement(FormItemInputContext.Provider, {
value: groupFormItemContext
}, /*#__PURE__*/React.createElement(Space.Compact, {
className: cls,
style: props.style,
onMouseEnter: props.onMouseEnter,
onMouseLeave: props.onMouseLeave,
onFocus: props.onFocus,
onBlur: props.onBlur
}, props.children));
};
export default Group;
+74
View File
@@ -0,0 +1,74 @@
import React from 'react';
import type { InputRef, InputProps as RcInputProps } from '@rc-component/input';
import type { InputFocusOptions } from '@rc-component/util/lib/Dom/focus';
import { triggerFocus } from '@rc-component/util/lib/Dom/focus';
import type { SemanticClassNamesType, SemanticStylesType } from '../_util/hooks';
import type { InputStatus } from '../_util/statusUtils';
import type { Variant } from '../config-provider';
import type { SizeType } from '../config-provider/SizeContext';
export type { InputFocusOptions };
export type { InputRef };
export { triggerFocus };
export type InputSemanticName = keyof InputSemanticClassNames & keyof InputSemanticStyles;
export type InputSemanticClassNames = {
root?: string;
prefix?: string;
suffix?: string;
input?: string;
count?: string;
};
export type InputSemanticStyles = {
root?: React.CSSProperties;
prefix?: React.CSSProperties;
suffix?: React.CSSProperties;
input?: React.CSSProperties;
count?: React.CSSProperties;
};
export type InputClassNamesType = SemanticClassNamesType<InputProps, InputSemanticClassNames>;
export type InputStylesType = SemanticStylesType<InputProps, InputSemanticStyles>;
export interface InputProps extends Omit<RcInputProps, 'wrapperClassName' | 'groupClassName' | 'inputClassName' | 'affixWrapperClassName' | 'classes' | 'classNames' | 'styles'> {
rootClassName?: string;
size?: SizeType;
disabled?: boolean;
status?: InputStatus;
/**
* @deprecated Use `Space.Compact` instead.
*
* @example
* ```tsx
* import { Space, Input } from 'antd';
*
* <Space.Compact>
* {addon}
* <Input defaultValue="name" />
* </Space.Compact>
* ```
*/
addonBefore?: React.ReactNode;
/**
* @deprecated Use `Space.Compact` instead.
*
* @example
* ```tsx
* import { Space, Input } from 'antd';
*
* <Space.Compact>
* <Input defaultValue="name" />
* {addon}
* </Space.Compact>
* ```
*/
addonAfter?: React.ReactNode;
/** @deprecated Use `variant="borderless"` instead. */
bordered?: boolean;
/**
* @since 5.13.0
* @default "outlined"
*/
variant?: Variant;
classNames?: InputClassNamesType;
styles?: InputStylesType;
[key: `data-${string}`]: string | undefined;
}
declare const Input: React.ForwardRefExoticComponent<InputProps & React.RefAttributes<InputRef>>;
export default Input;
+184
View File
@@ -0,0 +1,184 @@
"use client";
import React, { forwardRef, useContext, useEffect, useRef } from 'react';
import RcInput from '@rc-component/input';
import { triggerFocus } from "@rc-component/util/es/Dom/focus";
import { composeRef } from "@rc-component/util/es/ref";
import { clsx } from 'clsx';
import ContextIsolator from '../_util/ContextIsolator';
import getAllowClear from '../_util/getAllowClear';
import { useMergeSemantic } from '../_util/hooks';
import { getMergedStatus, getStatusClassNames } from '../_util/statusUtils';
import { devUseWarning } from '../_util/warning';
import { useComponentConfig } from '../config-provider/context';
import DisabledContext from '../config-provider/DisabledContext';
import useCSSVarCls from '../config-provider/hooks/useCSSVarCls';
import useSize from '../config-provider/hooks/useSize';
import { FormItemInputContext } from '../form/context';
import useVariant from '../form/hooks/useVariants';
import { useCompactItemContext } from '../space/Compact';
import useRemovePasswordTimeout from './hooks/useRemovePasswordTimeout';
import useStyle, { useSharedStyle } from './style';
import { hasPrefixSuffix } from './utils';
export { triggerFocus };
const Input = /*#__PURE__*/forwardRef((props, ref) => {
const {
prefixCls: customizePrefixCls,
bordered = true,
status: customStatus,
size: customSize,
disabled: customDisabled,
onBlur,
onFocus,
suffix,
allowClear,
addonAfter,
addonBefore,
className,
style,
styles,
rootClassName,
onChange,
classNames,
variant: customVariant,
...rest
} = props;
if (process.env.NODE_ENV !== 'production') {
const {
deprecated
} = devUseWarning('Input');
[['bordered', 'variant'], ['addonAfter', 'Space.Compact'], ['addonBefore', 'Space.Compact']].forEach(([prop, newProp]) => {
deprecated(!(prop in props), prop, newProp);
});
}
const {
getPrefixCls,
direction,
allowClear: contextAllowClear,
autoComplete: contextAutoComplete,
className: contextClassName,
style: contextStyle,
classNames: contextClassNames,
styles: contextStyles
} = useComponentConfig('input');
const prefixCls = getPrefixCls('input', customizePrefixCls);
const inputRef = useRef(null);
// Style
const rootCls = useCSSVarCls(prefixCls);
const [hashId, cssVarCls] = useSharedStyle(prefixCls, rootClassName);
useStyle(prefixCls, rootCls);
// ===================== Compact Item =====================
const {
compactSize,
compactItemClassnames
} = useCompactItemContext(prefixCls, direction);
// ===================== Size =====================
const mergedSize = useSize(ctx => customSize ?? compactSize ?? ctx);
// ===================== Disabled =====================
const disabled = React.useContext(DisabledContext);
const mergedDisabled = customDisabled ?? disabled;
// =========== Merged Props for Semantic ==========
const mergedProps = {
...props,
size: mergedSize,
disabled: mergedDisabled
};
const [mergedClassNames, mergedStyles] = useMergeSemantic([contextClassNames, classNames], [contextStyles, styles], {
props: mergedProps
});
// ===================== Status =====================
const {
status: contextStatus,
hasFeedback,
feedbackIcon
} = useContext(FormItemInputContext);
const mergedStatus = getMergedStatus(contextStatus, customStatus);
// ===================== Focus warning =====================
const inputHasPrefixSuffix = hasPrefixSuffix(props) || !!hasFeedback;
const prevHasPrefixSuffixRef = useRef(inputHasPrefixSuffix);
/* eslint-disable react-hooks/rules-of-hooks */
if (process.env.NODE_ENV !== 'production') {
const warning = devUseWarning('Input');
// biome-ignore lint/correctness/useHookAtTopLevel: Development-only warning hook called conditionally
useEffect(() => {
if (inputHasPrefixSuffix && !prevHasPrefixSuffixRef.current) {
process.env.NODE_ENV !== "production" ? warning(document.activeElement === inputRef.current?.input, 'usage', `When Input is focused, dynamic add or remove prefix / suffix will make it lose focus caused by dom structure change. Read more: https://ant.design/components/input/#FAQ`) : void 0;
}
prevHasPrefixSuffixRef.current = inputHasPrefixSuffix;
}, [inputHasPrefixSuffix]);
}
/* eslint-enable */
// ===================== Remove Password value =====================
const removePasswordTimeout = useRemovePasswordTimeout(inputRef, true);
const handleBlur = e => {
removePasswordTimeout();
onBlur?.(e);
};
const handleFocus = e => {
removePasswordTimeout();
onFocus?.(e);
};
const handleChange = e => {
removePasswordTimeout();
onChange?.(e);
};
const suffixNode = (hasFeedback || suffix) && (/*#__PURE__*/React.createElement(React.Fragment, null, suffix, hasFeedback && feedbackIcon));
const mergedAllowClear = getAllowClear(allowClear ?? contextAllowClear);
const [variant, enableVariantCls] = useVariant('input', customVariant, bordered);
return /*#__PURE__*/React.createElement(RcInput, {
ref: composeRef(ref, inputRef),
prefixCls: prefixCls,
autoComplete: contextAutoComplete,
...rest,
disabled: mergedDisabled,
onBlur: handleBlur,
onFocus: handleFocus,
style: {
...mergedStyles.root,
...contextStyle,
...style
},
styles: mergedStyles,
suffix: suffixNode,
allowClear: mergedAllowClear,
className: clsx(className, rootClassName, cssVarCls, rootCls, compactItemClassnames, contextClassName, mergedClassNames.root),
onChange: handleChange,
addonBefore: addonBefore && (/*#__PURE__*/React.createElement(ContextIsolator, {
form: true,
space: true
}, addonBefore)),
addonAfter: addonAfter && (/*#__PURE__*/React.createElement(ContextIsolator, {
form: true,
space: true
}, addonAfter)),
classNames: {
...mergedClassNames,
input: clsx({
[`${prefixCls}-sm`]: mergedSize === 'small',
[`${prefixCls}-lg`]: mergedSize === 'large',
[`${prefixCls}-rtl`]: direction === 'rtl'
}, mergedClassNames.input, hashId),
variant: clsx({
[`${prefixCls}-${variant}`]: enableVariantCls
}, getStatusClassNames(prefixCls, mergedStatus)),
affixWrapper: clsx({
[`${prefixCls}-affix-wrapper-sm`]: mergedSize === 'small',
[`${prefixCls}-affix-wrapper-lg`]: mergedSize === 'large',
[`${prefixCls}-affix-wrapper-rtl`]: direction === 'rtl'
}, hashId),
wrapper: clsx({
[`${prefixCls}-group-rtl`]: direction === 'rtl'
}, hashId),
groupWrapper: clsx({
[`${prefixCls}-group-wrapper-sm`]: mergedSize === 'small',
[`${prefixCls}-group-wrapper-lg`]: mergedSize === 'large',
[`${prefixCls}-group-wrapper-rtl`]: direction === 'rtl',
[`${prefixCls}-group-wrapper-${variant}`]: enableVariantCls
}, getStatusClassNames(`${prefixCls}-group-wrapper`, mergedStatus, hasFeedback), hashId)
}
});
});
if (process.env.NODE_ENV !== 'production') {
Input.displayName = 'Input';
}
export default Input;
+11
View File
@@ -0,0 +1,11 @@
import * as React from 'react';
import type { InputProps, InputRef } from '../Input';
export interface OTPInputProps extends Omit<InputProps, 'onChange'> {
index: number;
onChange: (index: number, value: string) => void;
/** Tell parent to do active offset */
onActiveChange: (nextIndex: number) => void;
mask?: boolean | string;
}
declare const OTPInput: React.ForwardRefExoticComponent<OTPInputProps & React.RefAttributes<InputRef>>;
export default OTPInput;
+85
View File
@@ -0,0 +1,85 @@
"use client";
import * as React from 'react';
import raf from "@rc-component/util/es/raf";
import { clsx } from 'clsx';
import { ConfigContext } from '../../config-provider';
import Input from '../Input';
const OTPInput = /*#__PURE__*/React.forwardRef((props, ref) => {
const {
className,
value,
onChange,
onActiveChange,
index,
mask,
onFocus,
...restProps
} = props;
const {
getPrefixCls
} = React.useContext(ConfigContext);
const prefixCls = getPrefixCls('otp');
const maskValue = typeof mask === 'string' ? mask : value;
// ========================== Ref ===========================
const inputRef = React.useRef(null);
React.useImperativeHandle(ref, () => inputRef.current);
// ========================= Input ==========================
const onInternalChange = e => {
onChange(index, e.target.value);
};
// ========================= Focus ==========================
const syncSelection = () => {
raf(() => {
const inputEle = inputRef.current?.input;
if (document.activeElement === inputEle && inputEle) {
inputEle.select();
}
});
};
const onInternalFocus = e => {
onFocus?.(e);
syncSelection();
};
// ======================== Keyboard ========================
const onInternalKeyDown = event => {
const {
key,
ctrlKey,
metaKey
} = event;
if (key === 'ArrowLeft') {
onActiveChange(index - 1);
} else if (key === 'ArrowRight') {
onActiveChange(index + 1);
} else if (key === 'z' && (ctrlKey || metaKey)) {
event.preventDefault();
} else if (key === 'Backspace' && !value) {
onActiveChange(index - 1);
}
syncSelection();
};
// ========================= Render =========================
return /*#__PURE__*/React.createElement("span", {
className: `${prefixCls}-input-wrapper`,
role: "presentation"
}, mask && value !== '' && value !== undefined && (/*#__PURE__*/React.createElement("span", {
className: `${prefixCls}-mask-icon`,
"aria-hidden": "true"
}, maskValue)), /*#__PURE__*/React.createElement(Input, {
"aria-label": `OTP Input ${index + 1}`,
type: mask === true ? 'password' : 'text',
...restProps,
ref: inputRef,
value: value,
onInput: onInternalChange,
onFocus: onInternalFocus,
onKeyDown: onInternalKeyDown,
onMouseDown: syncSelection,
onMouseUp: syncSelection,
className: clsx(className, {
[`${prefixCls}-mask-input`]: mask
})
}));
});
export default OTPInput;
+46
View File
@@ -0,0 +1,46 @@
import * as React from 'react';
import type { SemanticClassNamesType, SemanticStylesType } from '../../_util/hooks';
import type { InputStatus } from '../../_util/statusUtils';
import type { Variant } from '../../config-provider';
import type { SizeType } from '../../config-provider/SizeContext';
export type OTPSemanticClassNames = {
root?: string;
input?: string;
separator?: string;
};
export type OTPSemanticStyles = {
root?: React.CSSProperties;
input?: React.CSSProperties;
separator?: React.CSSProperties;
};
export type OTPClassNamesType = SemanticClassNamesType<OTPProps, OTPSemanticClassNames>;
export type OTPStylesType = SemanticStylesType<OTPProps, OTPSemanticStyles>;
export interface OTPRef {
focus: VoidFunction;
blur: VoidFunction;
nativeElement: HTMLDivElement;
}
export interface OTPProps extends Omit<React.HTMLAttributes<HTMLDivElement>, 'onChange' | 'onInput'> {
prefixCls?: string;
length?: number;
variant?: Variant;
rootClassName?: string;
className?: string;
style?: React.CSSProperties;
size?: SizeType;
defaultValue?: string;
value?: string;
onChange?: (value: string) => void;
formatter?: (value: string) => string;
separator?: ((index: number) => React.ReactNode) | React.ReactNode;
disabled?: boolean;
status?: InputStatus;
mask?: boolean | string;
type?: React.HTMLInputTypeAttribute;
autoComplete?: string;
onInput?: (value: string[]) => void;
classNames?: OTPClassNamesType;
styles?: OTPStylesType;
}
declare const OTP: React.ForwardRefExoticComponent<OTPProps & React.RefAttributes<OTPRef>>;
export default OTP;
+245
View File
@@ -0,0 +1,245 @@
"use client";
import _toConsumableArray from "@babel/runtime/helpers/esm/toConsumableArray";
import * as React from 'react';
import { useEvent } from '@rc-component/util';
import pickAttrs from "@rc-component/util/es/pickAttrs";
import { clsx } from 'clsx';
import { useMergeSemantic } from '../../_util/hooks';
import { getMergedStatus } from '../../_util/statusUtils';
import { devUseWarning } from '../../_util/warning';
import { useComponentConfig } from '../../config-provider/context';
import useSize from '../../config-provider/hooks/useSize';
import { FormItemInputContext } from '../../form/context';
import useStyle from '../style/otp';
import OTPInput from './OTPInput';
function strToArr(str) {
return (str || '').split('');
}
const Separator = props => {
const {
index,
prefixCls,
separator,
className: semanticClassName,
style: semanticStyle
} = props;
const separatorNode = typeof separator === 'function' ? separator(index) : separator;
if (!separatorNode) {
return null;
}
return /*#__PURE__*/React.createElement("span", {
className: clsx(`${prefixCls}-separator`, semanticClassName),
style: semanticStyle
}, separatorNode);
};
const OTP = /*#__PURE__*/React.forwardRef((props, ref) => {
const {
prefixCls: customizePrefixCls,
length = 6,
size: customSize,
defaultValue,
value,
onChange,
formatter,
separator,
variant,
disabled,
status: customStatus,
autoFocus,
mask,
type,
autoComplete,
onInput,
onFocus,
inputMode,
classNames,
styles,
className,
style,
...restProps
} = props;
if (process.env.NODE_ENV !== 'production') {
const warning = devUseWarning('Input.OTP');
process.env.NODE_ENV !== "production" ? warning(!(typeof mask === 'string' && mask.length > 1), 'usage', '`mask` prop should be a single character.') : void 0;
}
const {
classNames: contextClassNames,
styles: contextStyles,
getPrefixCls,
direction,
style: contextStyle,
className: contextClassName
} = useComponentConfig('otp');
const prefixCls = getPrefixCls('otp', customizePrefixCls);
const mergedProps = {
...props,
length
};
const [mergedClassNames, mergedStyles] = useMergeSemantic([contextClassNames, classNames], [contextStyles, styles], {
props: mergedProps
});
const domAttrs = pickAttrs(restProps, {
aria: true,
data: true,
attr: true
});
// ========================= Root =========================
// Style
const [hashId, cssVarCls] = useStyle(prefixCls);
// ========================= Size =========================
const mergedSize = useSize(ctx => customSize ?? ctx);
// ======================== Status ========================
const formContext = React.useContext(FormItemInputContext);
const mergedStatus = getMergedStatus(formContext.status, customStatus);
const proxyFormContext = React.useMemo(() => ({
...formContext,
status: mergedStatus,
hasFeedback: false,
feedbackIcon: null
}), [formContext, mergedStatus]);
// ========================= Refs =========================
const containerRef = React.useRef(null);
const inputsRef = React.useRef({});
React.useImperativeHandle(ref, () => ({
focus: () => {
inputsRef.current[0]?.focus();
},
blur: () => {
for (let i = 0; i < length; i += 1) {
inputsRef.current[i]?.blur();
}
},
nativeElement: containerRef.current
}));
// ======================= Formatter ======================
const internalFormatter = txt => formatter ? formatter(txt) : txt;
// ======================== Values ========================
const [valueCells, setValueCells] = React.useState(() => strToArr(internalFormatter(defaultValue || '')));
React.useEffect(() => {
if (value !== undefined) {
setValueCells(strToArr(value));
}
}, [value]);
const triggerValueCellsChange = useEvent(nextValueCells => {
setValueCells(nextValueCells);
if (onInput) {
onInput(nextValueCells);
}
// Trigger if all cells are filled
if (onChange && nextValueCells.length === length && nextValueCells.every(c => c) && nextValueCells.some((c, index) => valueCells[index] !== c)) {
onChange(nextValueCells.join(''));
}
});
const patchValue = useEvent((index, txt) => {
let nextCells = _toConsumableArray(valueCells);
// Fill cells till index
for (let i = 0; i < index; i += 1) {
if (!nextCells[i]) {
nextCells[i] = '';
}
}
if (txt.length <= 1) {
nextCells[index] = txt;
} else {
nextCells = nextCells.slice(0, index).concat(strToArr(txt));
}
nextCells = nextCells.slice(0, length);
// Clean the last empty cell
for (let i = nextCells.length - 1; i >= 0; i -= 1) {
if (nextCells[i]) {
break;
}
nextCells.pop();
}
// Format if needed
const formattedValue = internalFormatter(nextCells.map(c => c || ' ').join(''));
nextCells = strToArr(formattedValue).map((c, i) => {
if (c === ' ' && !nextCells[i]) {
return nextCells[i];
}
return c;
});
return nextCells;
});
// ======================== Change ========================
const onInputChange = (index, txt) => {
const nextCells = patchValue(index, txt);
const nextIndex = Math.min(index + txt.length, length - 1);
if (nextIndex !== index && nextCells[index] !== undefined) {
inputsRef.current[nextIndex]?.focus();
}
triggerValueCellsChange(nextCells);
};
const onInputActiveChange = nextIndex => {
inputsRef.current[nextIndex]?.focus();
};
// ======================== Focus ========================
const onInputFocus = (event, index) => {
// keep focus on the first empty cell
for (let i = 0; i < index; i += 1) {
if (!inputsRef.current[i]?.input?.value) {
inputsRef.current[i]?.focus();
break;
}
}
onFocus?.(event);
};
// ======================== Render ========================
const inputSharedProps = {
variant,
disabled,
status: mergedStatus,
mask,
type,
inputMode,
autoComplete
};
return /*#__PURE__*/React.createElement("div", {
...domAttrs,
ref: containerRef,
className: clsx(className, prefixCls, {
[`${prefixCls}-sm`]: mergedSize === 'small',
[`${prefixCls}-lg`]: mergedSize === 'large',
[`${prefixCls}-rtl`]: direction === 'rtl'
}, cssVarCls, hashId, contextClassName, mergedClassNames.root),
style: {
...mergedStyles.root,
...contextStyle,
...style
},
role: "group"
}, /*#__PURE__*/React.createElement(FormItemInputContext.Provider, {
value: proxyFormContext
}, Array.from({
length
}).map((_, index) => {
const key = `otp-${index}`;
const singleValue = valueCells[index] || '';
return /*#__PURE__*/React.createElement(React.Fragment, {
key: key
}, /*#__PURE__*/React.createElement(OTPInput, {
ref: inputEle => {
inputsRef.current[index] = inputEle;
},
index: index,
size: mergedSize,
htmlSize: 1,
className: clsx(mergedClassNames.input, `${prefixCls}-input`),
style: mergedStyles.input,
onChange: onInputChange,
value: singleValue,
onActiveChange: onInputActiveChange,
autoFocus: index === 0 && autoFocus,
onFocus: event => onInputFocus(event, index),
...inputSharedProps
}), index < length - 1 && (/*#__PURE__*/React.createElement(Separator, {
separator: separator,
index: index,
prefixCls: prefixCls,
className: clsx(mergedClassNames.separator),
style: mergedStyles.separator
})));
})));
});
export default OTP;
+18
View File
@@ -0,0 +1,18 @@
import * as React from 'react';
import type { InputProps, InputRef } from './Input';
interface VisibilityToggle {
visible?: boolean;
onVisibleChange?: (visible: boolean) => void;
}
export interface PasswordProps extends InputProps {
readonly inputPrefixCls?: string;
readonly action?: 'click' | 'hover';
visibilityToggle?: boolean | VisibilityToggle;
/**
* @since 5.27.0
*/
suffix?: React.ReactNode;
iconRender?: (visible: boolean) => React.ReactNode;
}
declare const Password: React.ForwardRefExoticComponent<PasswordProps & React.RefAttributes<InputRef>>;
export default Password;
+108
View File
@@ -0,0 +1,108 @@
"use client";
import * as React from 'react';
import { useRef, useState } from 'react';
import EyeInvisibleOutlined from "@ant-design/icons/es/icons/EyeInvisibleOutlined";
import EyeOutlined from "@ant-design/icons/es/icons/EyeOutlined";
import { omit } from '@rc-component/util';
import { composeRef } from "@rc-component/util/es/ref";
import { clsx } from 'clsx';
import { isPlainObject } from '../_util/is';
import { ConfigContext } from '../config-provider';
import DisabledContext from '../config-provider/DisabledContext';
import useRemovePasswordTimeout from './hooks/useRemovePasswordTimeout';
import Input from './Input';
const defaultIconRender = visible => visible ? /*#__PURE__*/React.createElement(EyeOutlined, null) : /*#__PURE__*/React.createElement(EyeInvisibleOutlined, null);
const actionMap = {
click: 'onClick',
hover: 'onMouseOver'
};
const Password = /*#__PURE__*/React.forwardRef((props, ref) => {
const {
disabled: customDisabled,
action = 'click',
visibilityToggle = true,
iconRender = defaultIconRender,
suffix
} = props;
// ===================== Disabled =====================
const disabled = React.useContext(DisabledContext);
const mergedDisabled = customDisabled ?? disabled;
const visibilityControlled = isPlainObject(visibilityToggle) && visibilityToggle.visible !== undefined;
const [visible, setVisible] = useState(() => visibilityControlled ? visibilityToggle.visible : false);
const inputRef = useRef(null);
React.useEffect(() => {
if (visibilityControlled) {
setVisible(visibilityToggle.visible);
}
}, [visibilityControlled, visibilityToggle]);
// Remove Password value
const removePasswordTimeout = useRemovePasswordTimeout(inputRef);
const onVisibleChange = () => {
if (mergedDisabled) {
return;
}
if (visible) {
removePasswordTimeout();
}
const nextVisible = !visible;
setVisible(nextVisible);
if (isPlainObject(visibilityToggle)) {
visibilityToggle.onVisibleChange?.(nextVisible);
}
};
const getIcon = prefixCls => {
const iconTrigger = actionMap[action] || '';
const icon = iconRender(visible);
const iconProps = {
[iconTrigger]: onVisibleChange,
className: `${prefixCls}-icon`,
key: 'passwordIcon',
onMouseDown: e => {
// Prevent focused state lost
// https://github.com/ant-design/ant-design/issues/15173
e.preventDefault();
},
onMouseUp: e => {
// Prevent caret position change
// https://github.com/ant-design/ant-design/issues/23524
e.preventDefault();
}
};
return /*#__PURE__*/React.cloneElement(/*#__PURE__*/React.isValidElement(icon) ? icon : /*#__PURE__*/React.createElement("span", null, icon), iconProps);
};
const {
className,
prefixCls: customizePrefixCls,
inputPrefixCls: customizeInputPrefixCls,
size,
...restProps
} = props;
const {
getPrefixCls
} = React.useContext(ConfigContext);
const inputPrefixCls = getPrefixCls('input', customizeInputPrefixCls);
const prefixCls = getPrefixCls('input-password', customizePrefixCls);
const suffixIcon = visibilityToggle && getIcon(prefixCls);
const inputClassName = clsx(prefixCls, className, {
[`${prefixCls}-${size}`]: !!size
});
const omittedProps = {
...omit(restProps, ['suffix', 'iconRender', 'visibilityToggle']),
type: visible ? 'text' : 'password',
className: inputClassName,
prefixCls: inputPrefixCls,
suffix: (/*#__PURE__*/React.createElement(React.Fragment, null, suffixIcon, suffix))
};
if (size) {
omittedProps.size = size;
}
return /*#__PURE__*/React.createElement(Input, {
ref: composeRef(ref, inputRef),
...omittedProps
});
});
if (process.env.NODE_ENV !== 'production') {
Password.displayName = 'Input.Password';
}
export default Password;
+38
View File
@@ -0,0 +1,38 @@
import * as React from 'react';
import type { SemanticClassNamesType, SemanticStylesType } from '../_util/hooks';
import type { ButtonSemanticClassNames, ButtonSemanticStyles } from '../button/Button';
import type { InputProps, InputRef } from './Input';
export type InputSearchSemanticName = keyof InputSearchSemanticClassNames & keyof InputSearchSemanticStyles;
export type InputSearchSemanticClassNames = {
root?: string;
input?: string;
prefix?: string;
suffix?: string;
count?: string;
};
export type InputSearchSemanticStyles = {
root?: React.CSSProperties;
input?: React.CSSProperties;
prefix?: React.CSSProperties;
suffix?: React.CSSProperties;
count?: React.CSSProperties;
};
export type InputSearchClassNamesType = SemanticClassNamesType<SearchProps, InputSearchSemanticClassNames> & {
button?: ButtonSemanticClassNames;
};
export type InputSearchStylesType = SemanticStylesType<SearchProps, InputSearchSemanticStyles> & {
button?: ButtonSemanticStyles;
};
export interface SearchProps extends InputProps {
inputPrefixCls?: string;
onSearch?: (value: string, event?: React.ChangeEvent<HTMLInputElement> | React.MouseEvent<HTMLElement> | React.KeyboardEvent<HTMLInputElement>, info?: {
source?: 'clear' | 'input';
}) => void;
enterButton?: React.ReactNode;
loading?: boolean;
onPressEnter?: (e: React.KeyboardEvent<HTMLInputElement>) => void;
classNames?: InputSearchClassNamesType;
styles?: InputSearchStylesType;
}
declare const Search: React.ForwardRefExoticComponent<SearchProps & React.RefAttributes<InputRef>>;
export default Search;
+182
View File
@@ -0,0 +1,182 @@
"use client";
import * as React from 'react';
import SearchOutlined from "@ant-design/icons/es/icons/SearchOutlined";
import omit from "@rc-component/util/es/omit";
import pickAttrs from "@rc-component/util/es/pickAttrs";
import { composeRef } from "@rc-component/util/es/ref";
import { clsx } from 'clsx';
import { useMergeSemantic } from '../_util/hooks';
import { cloneElement } from '../_util/reactNode';
import Button from '../button/Button';
import { useComponentConfig } from '../config-provider/context';
import useSize from '../config-provider/hooks/useSize';
import Compact, { useCompactItemContext } from '../space/Compact';
import Input from './Input';
import useStyle from './style/search';
const Search = /*#__PURE__*/React.forwardRef((props, ref) => {
const {
prefixCls: customizePrefixCls,
inputPrefixCls: customizeInputPrefixCls,
className,
size: customizeSize,
style,
enterButton = false,
addonAfter,
loading,
disabled,
onSearch: customOnSearch,
onChange: customOnChange,
onCompositionStart,
onCompositionEnd,
variant,
onPressEnter: customOnPressEnter,
classNames,
styles,
hidden,
...restProps
} = props;
const {
direction,
getPrefixCls,
classNames: contextClassNames,
styles: contextStyles
} = useComponentConfig('inputSearch');
const mergedProps = {
...props,
enterButton
};
const [mergedClassNames, mergedStyles] = useMergeSemantic([contextClassNames, classNames], [contextStyles, styles], {
props: mergedProps
}, {
button: {
_default: 'root'
}
});
const composedRef = React.useRef(false);
const prefixCls = getPrefixCls('input-search', customizePrefixCls);
const inputPrefixCls = getPrefixCls('input', customizeInputPrefixCls);
const [hashId, cssVarCls] = useStyle(prefixCls);
const {
compactSize
} = useCompactItemContext(prefixCls, direction);
const size = useSize(ctx => customizeSize ?? compactSize ?? ctx);
const inputRef = React.useRef(null);
const onChange = e => {
if (e?.target && e.type === 'click' && customOnSearch) {
customOnSearch(e.target.value, e, {
source: 'clear'
});
}
customOnChange?.(e);
};
const onMouseDown = e => {
if (document.activeElement === inputRef.current?.input) {
e.preventDefault();
}
};
const onSearch = e => {
if (customOnSearch) {
customOnSearch(inputRef.current?.input?.value, e, {
source: 'input'
});
}
};
const onPressEnter = e => {
if (composedRef.current || loading) {
return;
}
customOnPressEnter?.(e);
onSearch(e);
};
const searchIcon = typeof enterButton === 'boolean' ? /*#__PURE__*/React.createElement(SearchOutlined, null) : null;
const btnPrefixCls = `${prefixCls}-btn`;
const btnClassName = clsx(btnPrefixCls, {
[`${btnPrefixCls}-${variant}`]: variant
});
let button;
const enterButtonAsElement = enterButton || {};
const isAntdButton = enterButtonAsElement.type && enterButtonAsElement.type.__ANT_BUTTON === true;
if (isAntdButton || enterButtonAsElement.type === 'button') {
button = cloneElement(enterButtonAsElement, {
onMouseDown,
onClick: e => {
enterButtonAsElement?.props?.onClick?.(e);
onSearch(e);
},
key: 'enterButton',
...(isAntdButton ? {
className: btnClassName,
size
} : {})
});
} else {
button = /*#__PURE__*/React.createElement(Button, {
classNames: mergedClassNames.button,
styles: mergedStyles.button,
className: btnClassName,
color: enterButton ? 'primary' : 'default',
size: size,
disabled: disabled,
key: "enterButton",
onMouseDown: onMouseDown,
onClick: onSearch,
loading: loading,
icon: searchIcon,
variant: variant === 'borderless' || variant === 'filled' || variant === 'underlined' ? 'text' : enterButton ? 'solid' : undefined
}, enterButton);
}
if (addonAfter) {
button = [button, cloneElement(addonAfter, {
key: 'addonAfter'
})];
}
const mergedClassName = clsx(prefixCls, cssVarCls, {
[`${prefixCls}-rtl`]: direction === 'rtl',
[`${prefixCls}-${size}`]: !!size,
[`${prefixCls}-with-button`]: !!enterButton
}, className, hashId, mergedClassNames.root);
const handleOnCompositionStart = e => {
composedRef.current = true;
onCompositionStart?.(e);
};
const handleOnCompositionEnd = e => {
composedRef.current = false;
onCompositionEnd?.(e);
};
// ========================== Render ==========================
// >>> Root Props
const rootProps = pickAttrs(restProps, {
data: true
});
const inputProps = omit({
...restProps,
classNames: omit(mergedClassNames, ['button', 'root']),
styles: omit(mergedStyles, ['button', 'root']),
prefixCls: inputPrefixCls,
type: 'search',
size,
variant,
onPressEnter,
onCompositionStart: handleOnCompositionStart,
onCompositionEnd: handleOnCompositionEnd,
onChange,
disabled
}, Object.keys(rootProps));
return /*#__PURE__*/React.createElement(Compact, {
className: mergedClassName,
style: {
...style,
...mergedStyles.root
},
...rootProps,
hidden: hidden
}, /*#__PURE__*/React.createElement(Input, {
ref: composeRef(inputRef, ref),
...inputProps
}), button);
});
if (process.env.NODE_ENV !== 'production') {
Search.displayName = 'Search';
}
export default Search;
+42
View File
@@ -0,0 +1,42 @@
import * as React from 'react';
import type { TextAreaProps as RcTextAreaProps, TextAreaRef as RcTextAreaRef } from '@rc-component/textarea';
import type { SemanticClassNamesType, SemanticStylesType } from '../_util/hooks';
import type { InputStatus } from '../_util/statusUtils';
import type { Variant } from '../config-provider';
import type { SizeType } from '../config-provider/SizeContext';
import type { InputFocusOptions } from './Input';
export type TextAreaSemanticName = keyof TextAreaSemanticClassNames & keyof TextAreaSemanticStyles;
export type TextAreaSemanticClassNames = {
root?: string;
textarea?: string;
count?: string;
};
export type TextAreaSemanticStyles = {
root?: React.CSSProperties;
textarea?: React.CSSProperties;
count?: React.CSSProperties;
};
export type TextAreaClassNamesType = SemanticClassNamesType<TextAreaProps, TextAreaSemanticClassNames>;
export type TextAreaStylesType = SemanticStylesType<TextAreaProps, TextAreaSemanticStyles>;
export interface TextAreaProps extends Omit<RcTextAreaProps, 'suffix' | 'classNames' | 'styles'> {
/** @deprecated Use `variant` instead */
bordered?: boolean;
size?: SizeType;
status?: InputStatus;
rootClassName?: string;
/**
* @since 5.13.0
* @default "outlined"
*/
variant?: Variant;
classNames?: TextAreaClassNamesType;
styles?: TextAreaStylesType;
}
export interface TextAreaRef {
focus: (options?: InputFocusOptions) => void;
blur: () => void;
resizableTextArea?: RcTextAreaRef['resizableTextArea'];
nativeElement: HTMLElement | null;
}
declare const TextArea: React.ForwardRefExoticComponent<TextAreaProps & React.RefAttributes<TextAreaRef>>;
export default TextArea;
+160
View File
@@ -0,0 +1,160 @@
"use client";
import * as React from 'react';
import { forwardRef } from 'react';
import RcTextArea from '@rc-component/textarea';
import { clsx } from 'clsx';
import getAllowClear from '../_util/getAllowClear';
import { useMergeSemantic } from '../_util/hooks';
import { getMergedStatus, getStatusClassNames } from '../_util/statusUtils';
import { devUseWarning } from '../_util/warning';
import { useComponentConfig } from '../config-provider/context';
import DisabledContext from '../config-provider/DisabledContext';
import useCSSVarCls from '../config-provider/hooks/useCSSVarCls';
import useSize from '../config-provider/hooks/useSize';
import { FormItemInputContext } from '../form/context';
import useVariant from '../form/hooks/useVariants';
import { useCompactItemContext } from '../space/Compact';
import { triggerFocus } from './Input';
import { useSharedStyle } from './style';
import useStyle from './style/textarea';
const TextArea = /*#__PURE__*/forwardRef((props, ref) => {
const {
prefixCls: customizePrefixCls,
bordered = true,
size: customizeSize,
disabled: customDisabled,
status: customStatus,
allowClear,
classNames,
rootClassName,
className,
style,
styles,
variant: customVariant,
showCount,
onMouseDown,
onResize,
...rest
} = props;
if (process.env.NODE_ENV !== 'production') {
const {
deprecated
} = devUseWarning('TextArea');
deprecated(!('bordered' in props), 'bordered', 'variant');
}
const {
getPrefixCls,
direction,
allowClear: contextAllowClear,
autoComplete: contextAutoComplete,
className: contextClassName,
style: contextStyle,
classNames: contextClassNames,
styles: contextStyles
} = useComponentConfig('textArea');
// =================== Disabled ===================
const disabled = React.useContext(DisabledContext);
const mergedDisabled = customDisabled ?? disabled;
// ==================== Status ====================
const {
status: contextStatus,
hasFeedback,
feedbackIcon
} = React.useContext(FormItemInputContext);
const mergedStatus = getMergedStatus(contextStatus, customStatus);
const [mergedClassNames, mergedStyles] = useMergeSemantic([contextClassNames, classNames], [contextStyles, styles], {
props
});
// ===================== Ref ======================
const innerRef = React.useRef(null);
React.useImperativeHandle(ref, () => ({
resizableTextArea: innerRef.current?.resizableTextArea,
focus: option => {
triggerFocus(innerRef.current?.resizableTextArea?.textArea, option);
},
blur: () => innerRef.current?.blur(),
nativeElement: innerRef.current?.nativeElement || null
}));
const prefixCls = getPrefixCls('input', customizePrefixCls);
// ==================== Style =====================
const rootCls = useCSSVarCls(prefixCls);
const [hashId, cssVarCls] = useSharedStyle(prefixCls, rootClassName);
useStyle(prefixCls, rootCls);
// ================= Compact Item =================
const {
compactSize,
compactItemClassnames
} = useCompactItemContext(prefixCls, direction);
// ===================== Size =====================
const mergedSize = useSize(ctx => customizeSize ?? compactSize ?? ctx);
const [variant, enableVariantCls] = useVariant('textArea', customVariant, bordered);
const mergedAllowClear = getAllowClear(allowClear ?? contextAllowClear);
// ==================== Resize ====================
// https://github.com/ant-design/ant-design/issues/51594
const [isMouseDown, setIsMouseDown] = React.useState(false);
// When has wrapper, resize will make as dirty for `resize: both` style
const [resizeDirty, setResizeDirty] = React.useState(false);
const onInternalMouseDown = e => {
setIsMouseDown(true);
onMouseDown?.(e);
const onMouseUp = () => {
setIsMouseDown(false);
document.removeEventListener('mouseup', onMouseUp);
};
document.addEventListener('mouseup', onMouseUp);
};
const onInternalResize = size => {
onResize?.(size);
// Change to dirty since this maybe from the `resize: both` style
if (isMouseDown && typeof getComputedStyle === 'function') {
const ele = innerRef.current?.nativeElement?.querySelector('textarea');
if (ele && getComputedStyle(ele).resize === 'both') {
setResizeDirty(true);
}
}
};
// ==================== Render ====================
return /*#__PURE__*/React.createElement(RcTextArea, {
autoComplete: contextAutoComplete,
...rest,
style: {
...mergedStyles.root,
...contextStyle,
...style
},
styles: mergedStyles,
disabled: mergedDisabled,
allowClear: mergedAllowClear,
className: clsx(cssVarCls, rootCls, className, rootClassName, compactItemClassnames, contextClassName, mergedClassNames.root,
// Only for wrapper
{
[`${prefixCls}-textarea-affix-wrapper-resize-dirty`]: resizeDirty
}),
classNames: {
...mergedClassNames,
textarea: clsx({
[`${prefixCls}-sm`]: mergedSize === 'small',
[`${prefixCls}-lg`]: mergedSize === 'large'
}, hashId, mergedClassNames.textarea, isMouseDown && `${prefixCls}-mouse-active`),
variant: clsx({
[`${prefixCls}-${variant}`]: enableVariantCls
}, getStatusClassNames(prefixCls, mergedStatus)),
affixWrapper: clsx(`${prefixCls}-textarea-affix-wrapper`, {
[`${prefixCls}-affix-wrapper-rtl`]: direction === 'rtl',
[`${prefixCls}-affix-wrapper-sm`]: mergedSize === 'small',
[`${prefixCls}-affix-wrapper-lg`]: mergedSize === 'large',
[`${prefixCls}-textarea-show-count`]: showCount || props.count?.show
}, hashId)
},
prefixCls: prefixCls,
suffix: hasFeedback && /*#__PURE__*/React.createElement("span", {
className: `${prefixCls}-textarea-suffix`
}, feedbackIcon),
showCount: showCount,
ref: innerRef,
onResize: onInternalResize,
onMouseDown: onInternalMouseDown
});
});
export default TextArea;
@@ -0,0 +1,2 @@
import type { InputRef } from '../Input';
export default function useRemovePasswordTimeout(inputRef: React.RefObject<InputRef | null>, triggerOnMount?: boolean): () => void;
@@ -0,0 +1,22 @@
import { useEffect, useRef } from 'react';
export default function useRemovePasswordTimeout(inputRef, triggerOnMount) {
const removePasswordTimeoutRef = useRef([]);
const removePasswordTimeout = () => {
removePasswordTimeoutRef.current.push(setTimeout(() => {
if (inputRef.current?.input && inputRef.current?.input.getAttribute('type') === 'password' && inputRef.current?.input.hasAttribute('value')) {
inputRef.current?.input.removeAttribute('value');
}
}));
};
useEffect(() => {
if (triggerOnMount) {
removePasswordTimeout();
}
return () => removePasswordTimeoutRef.current.forEach(timer => {
if (timer) {
clearTimeout(timer);
}
});
}, []);
return removePasswordTimeout;
}
+21
View File
@@ -0,0 +1,21 @@
import Group from './Group';
import InternalInput from './Input';
import OTP from './OTP';
import Password from './Password';
import Search from './Search';
import TextArea from './TextArea';
export type { GroupProps } from './Group';
export type { InputProps, InputRef, InputSemanticClassNames, InputSemanticName, InputSemanticStyles, } from './Input';
export type { PasswordProps } from './Password';
export type { InputSearchSemanticClassNames, InputSearchSemanticName, InputSearchSemanticStyles, SearchProps, } from './Search';
export type { TextAreaProps, TextAreaSemanticClassNames, TextAreaSemanticName, TextAreaSemanticStyles, } from './TextArea';
type CompoundedComponent = typeof InternalInput & {
/** @deprecated Please use `Space.Compact` */
Group: typeof Group;
Search: typeof Search;
TextArea: typeof TextArea;
Password: typeof Password;
OTP: typeof OTP;
};
declare const Input: CompoundedComponent;
export default Input;
+15
View File
@@ -0,0 +1,15 @@
"use client";
import Group from './Group';
import InternalInput from './Input';
import OTP from './OTP';
import Password from './Password';
import Search from './Search';
import TextArea from './TextArea';
const Input = InternalInput;
Input.Group = Group;
Input.Search = Search;
Input.TextArea = TextArea;
Input.Password = Password;
Input.OTP = OTP;
export default Input;
+20
View File
@@ -0,0 +1,20 @@
import type { CSSObject } from '@ant-design/cssinjs';
import type { GenerateStyle } from '../../theme/internal';
import type { ComponentToken, InputToken } from './token';
import { initComponentToken, initInputToken } from './token';
export type { ComponentToken };
export { initComponentToken, initInputToken };
export declare const genPlaceholderStyle: (color: string) => CSSObject;
export declare const genActiveStyle: GenerateStyle<InputToken, CSSObject>;
export declare const genInputLargeStyle: GenerateStyle<InputToken, CSSObject>;
export declare const genInputSmallStyle: GenerateStyle<InputToken, CSSObject>;
export declare const genBasicInputStyle: (token: InputToken, option?: {
largeStyle?: CSSObject;
smallStyle?: CSSObject;
}) => CSSObject;
export declare const genInputGroupStyle: GenerateStyle<InputToken, CSSObject>;
export declare const genInputStyle: GenerateStyle<InputToken, CSSObject>;
export declare const genAffixStyle: GenerateStyle<InputToken, CSSObject>;
export declare const useSharedStyle: (prefixCls: string, rootCls?: string) => readonly [string, string];
declare const _default: (prefixCls: string, rootCls?: string) => readonly [string, string];
export default _default;
+567
View File
@@ -0,0 +1,567 @@
import { unit } from '@ant-design/cssinjs';
import { clearFix, genFocusOutline, resetComponent } from '../../style';
import { genCompactItemStyle } from '../../style/compact-item';
import { genStyleHooks, mergeToken } from '../../theme/internal';
import { initComponentToken, initInputToken } from './token';
import { genBorderlessStyle, genFilledGroupStyle, genFilledStyle, genOutlinedGroupStyle, genOutlinedStyle, genUnderlinedStyle } from './variants';
export { initComponentToken, initInputToken };
export const genPlaceholderStyle = color => ({
// Firefox
'&::-moz-placeholder': {
opacity: 1
},
'&::placeholder': {
color,
userSelect: 'none' // https://github.com/ant-design/ant-design/pull/32639
},
'&:placeholder-shown': {
textOverflow: 'ellipsis'
}
});
export const genActiveStyle = token => ({
borderColor: token.activeBorderColor,
boxShadow: token.activeShadow,
outline: 0,
backgroundColor: token.activeBg
});
export const genInputLargeStyle = token => {
const {
paddingBlockLG,
lineHeightLG,
borderRadiusLG,
paddingInlineLG
} = token;
return {
padding: `${unit(paddingBlockLG)} ${unit(paddingInlineLG)}`,
fontSize: token.inputFontSizeLG,
lineHeight: lineHeightLG,
borderRadius: borderRadiusLG
};
};
export const genInputSmallStyle = token => ({
padding: `${unit(token.paddingBlockSM)} ${unit(token.paddingInlineSM)}`,
fontSize: token.inputFontSizeSM,
borderRadius: token.borderRadiusSM
});
export const genBasicInputStyle = (token, option = {}) => ({
position: 'relative',
display: 'inline-block',
width: '100%',
minWidth: 0,
padding: `${unit(token.paddingBlock)} ${unit(token.paddingInline)}`,
color: token.colorText,
fontSize: token.inputFontSize,
lineHeight: token.lineHeight,
borderRadius: token.borderRadius,
transition: `all ${token.motionDurationMid}`,
...genPlaceholderStyle(token.colorTextPlaceholder),
// Size
'&-lg': {
...genInputLargeStyle(token),
...option.largeStyle
},
'&-sm': {
...genInputSmallStyle(token),
...option.smallStyle
},
// RTL
'&-rtl, &-textarea-rtl': {
direction: 'rtl'
}
});
export const genInputGroupStyle = token => {
const {
componentCls,
antCls
} = token;
return {
position: 'relative',
display: 'table',
width: '100%',
borderCollapse: 'separate',
borderSpacing: 0,
// Undo padding and float of grid classes
"&[class*='col-']": {
paddingInlineEnd: token.paddingXS,
'&:last-child': {
paddingInlineEnd: 0
}
},
// Sizing options
[`&-lg ${componentCls}, &-lg > ${componentCls}-group-addon`]: {
...genInputLargeStyle(token)
},
[`&-sm ${componentCls}, &-sm > ${componentCls}-group-addon`]: {
...genInputSmallStyle(token)
},
// Fix https://github.com/ant-design/ant-design/issues/5754
[`&-lg ${antCls}-select-single`]: {
height: token.controlHeightLG
},
[`&-sm ${antCls}-select-single`]: {
height: token.controlHeightSM
},
[`> ${componentCls}`]: {
display: 'table-cell',
'&:not(:first-child):not(:last-child)': {
borderRadius: 0
}
},
[`${componentCls}-group`]: {
'&-addon, &-wrap': {
display: 'table-cell',
width: 1,
whiteSpace: 'nowrap',
verticalAlign: 'middle',
'&:not(:first-child):not(:last-child)': {
borderRadius: 0
}
},
'&-wrap > *': {
display: 'block !important'
},
'&-addon': {
position: 'relative',
padding: `0 ${unit(token.paddingInline)}`,
color: token.colorText,
fontWeight: 'normal',
fontSize: token.inputFontSize,
textAlign: 'center',
borderRadius: token.borderRadius,
transition: `all ${token.motionDurationSlow}`,
lineHeight: 1,
// Reset Select's style in addon
[`${antCls}-select`]: {
margin: `${unit(token.calc(token.paddingBlock).add(1).mul(-1).equal())} ${unit(token.calc(token.paddingInline).mul(-1).equal())}`,
[`&${antCls}-select-single:not(${antCls}-select-customize-input):not(${antCls}-pagination-size-changer)`]: {
backgroundColor: 'inherit',
border: `${unit(token.lineWidth)} ${token.lineType} transparent`,
boxShadow: 'none'
}
},
// https://github.com/ant-design/ant-design/issues/31333
[`${antCls}-cascader-picker`]: {
margin: `-9px ${unit(token.calc(token.paddingInline).mul(-1).equal())}`,
backgroundColor: 'transparent',
[`${antCls}-cascader-input`]: {
textAlign: 'start',
border: 0,
boxShadow: 'none'
}
}
}
},
[componentCls]: {
width: '100%',
marginBottom: 0,
textAlign: 'inherit',
'&:focus': {
zIndex: 1,
// Fix https://gw.alipayobjects.com/zos/rmsportal/DHNpoqfMXSfrSnlZvhsJ.png
borderInlineEndWidth: 1
},
'&:hover': {
zIndex: 1,
borderInlineEndWidth: 1
}
},
// Reset rounded corners
[`> ${componentCls}:first-child, ${componentCls}-group-addon:first-child`]: {
borderStartEndRadius: 0,
borderEndEndRadius: 0,
// Reset Select's style in addon
[`${antCls}-select`]: {
borderStartEndRadius: 0,
borderEndEndRadius: 0
}
},
[`> ${componentCls}-affix-wrapper`]: {
[`&:not(:first-child) ${componentCls}`]: {
borderStartStartRadius: 0,
borderEndStartRadius: 0
},
[`&:not(:last-child) ${componentCls}`]: {
borderStartEndRadius: 0,
borderEndEndRadius: 0
}
},
[`> ${componentCls}:last-child, ${componentCls}-group-addon:last-child`]: {
borderStartStartRadius: 0,
borderEndStartRadius: 0,
// Reset Select's style in addon
[`${antCls}-select`]: {
borderStartStartRadius: 0,
borderEndStartRadius: 0
}
},
[`${componentCls}-affix-wrapper`]: {
'&:not(:last-child)': {
borderStartEndRadius: 0,
borderEndEndRadius: 0
},
'&:not(:first-child)': {
borderStartStartRadius: 0,
borderEndStartRadius: 0
}
},
[`&${componentCls}-group-compact`]: {
display: 'block',
...clearFix(),
[`${componentCls}-group-addon, ${componentCls}-group-wrap, > ${componentCls}`]: {
'&:not(:first-child):not(:last-child)': {
borderInlineEndWidth: token.lineWidth,
'&:hover, &:focus': {
zIndex: 1
}
}
},
'& > *': {
display: 'inline-flex',
float: 'none',
verticalAlign: 'top',
// https://github.com/ant-design/ant-design-pro/issues/139
borderRadius: 0
},
[`
& > ${componentCls}-affix-wrapper,
& > ${componentCls}-number-affix-wrapper,
& > ${antCls}-picker-range
`]: {
display: 'inline-flex'
},
'& > *:not(:last-child)': {
marginInlineEnd: token.calc(token.lineWidth).mul(-1).equal(),
borderInlineEndWidth: token.lineWidth
},
// Undo float for .ant-input-group .ant-input
[componentCls]: {
float: 'none'
},
// reset border for Select, DatePicker, AutoComplete, Cascader, Mention, TimePicker, Input
[`& > ${antCls}-select,
& > ${antCls}-select-auto-complete ${componentCls},
& > ${antCls}-cascader-picker ${componentCls},
& > ${componentCls}-group-wrapper ${componentCls}`]: {
borderInlineEndWidth: token.lineWidth,
borderRadius: 0,
'&:hover, &:focus': {
zIndex: 1
}
},
[`& > ${antCls}-select-focused`]: {
zIndex: 1
},
// update z-index for arrow icon
[`& > ${antCls}-select > ${antCls}-select-arrow`]: {
zIndex: 1 // https://github.com/ant-design/ant-design/issues/20371
},
[`& > *:first-child,
& > ${antCls}-select:first-child,
& > ${antCls}-select-auto-complete:first-child ${componentCls},
& > ${antCls}-cascader-picker:first-child ${componentCls}`]: {
borderStartStartRadius: token.borderRadius,
borderEndStartRadius: token.borderRadius
},
[`& > *:last-child,
& > ${antCls}-select:last-child,
& > ${antCls}-cascader-picker:last-child ${componentCls},
& > ${antCls}-cascader-picker-focused:last-child ${componentCls}`]: {
borderInlineEndWidth: token.lineWidth,
borderStartEndRadius: token.borderRadius,
borderEndEndRadius: token.borderRadius
},
// https://github.com/ant-design/ant-design/issues/12493
[`& > ${antCls}-select-auto-complete ${componentCls}`]: {
verticalAlign: 'top'
},
[`${componentCls}-group-wrapper + ${componentCls}-group-wrapper`]: {
marginInlineStart: token.calc(token.lineWidth).mul(-1).equal(),
[`${componentCls}-affix-wrapper`]: {
// borderRadius: 0,
}
}
}
};
};
export const genInputStyle = token => {
const {
componentCls,
controlHeightSM,
lineWidth,
calc
} = token;
const FIXED_CHROME_COLOR_HEIGHT = 16;
const colorSmallPadding = calc(controlHeightSM).sub(calc(lineWidth).mul(2)).sub(FIXED_CHROME_COLOR_HEIGHT).div(2).equal();
return {
[componentCls]: {
...resetComponent(token),
...genBasicInputStyle(token),
// Variants
...genOutlinedStyle(token),
...genFilledStyle(token),
...genBorderlessStyle(token),
...genUnderlinedStyle(token),
'&[type="color"]': {
height: token.controlHeight,
[`&${componentCls}-lg`]: {
height: token.controlHeightLG
},
[`&${componentCls}-sm`]: {
height: controlHeightSM,
paddingTop: colorSmallPadding,
paddingBottom: colorSmallPadding
}
},
'&[type="search"]::-webkit-search-cancel-button, &[type="search"]::-webkit-search-decoration': {
appearance: 'none'
}
}
};
};
const genAllowClearStyle = token => {
const {
componentCls
} = token;
return {
// ========================= Input =========================
[`${componentCls}-clear-icon`]: {
margin: 0,
padding: 0,
lineHeight: 0,
color: token.colorTextQuaternary,
fontSize: token.fontSizeIcon,
verticalAlign: -1,
// https://github.com/ant-design/ant-design/pull/18151
// https://codesandbox.io/s/wizardly-sun-u10br
cursor: 'pointer',
transition: `color ${token.motionDurationSlow}`,
border: 'none',
outline: 'none',
backgroundColor: 'transparent',
'&:hover': {
color: token.colorIcon
},
'&:focus-visible': {
color: token.colorIcon,
borderRadius: token.borderRadiusSM,
...genFocusOutline(token)
},
'&:active': {
color: token.colorText
},
'&-hidden': {
visibility: 'hidden'
},
'&-has-suffix': {
margin: `0 ${unit(token.inputAffixPadding)}`
}
}
};
};
export const genAffixStyle = token => {
const {
componentCls,
inputAffixPadding,
colorTextDescription,
motionDurationSlow,
colorIcon,
colorIconHover,
iconCls
} = token;
const affixCls = `${componentCls}-affix-wrapper`;
const affixClsDisabled = `${componentCls}-affix-wrapper-disabled`;
return {
[affixCls]: {
...genBasicInputStyle(token),
display: 'inline-flex',
'&-focused, &:focus': {
zIndex: 1
},
[`> input${componentCls}`]: {
padding: 0
},
[`> input${componentCls}, > textarea${componentCls}`]: {
fontSize: 'inherit',
border: 'none',
borderRadius: 0,
outline: 'none',
background: 'transparent',
color: 'inherit',
'&::-ms-reveal': {
display: 'none'
},
'&:focus': {
boxShadow: 'none !important'
}
},
'&::before': {
display: 'inline-block',
width: 0,
visibility: 'hidden',
content: '"\\a0"'
},
[componentCls]: {
'&-prefix, &-suffix': {
display: 'flex',
flex: 'none',
alignItems: 'center',
'> *:not(:last-child)': {
marginInlineEnd: token.paddingXS
}
},
'&-show-count-suffix': {
color: colorTextDescription,
direction: 'ltr'
},
'&-show-count-has-suffix': {
marginInlineEnd: token.paddingXXS
},
'&-prefix': {
marginInlineEnd: inputAffixPadding
},
'&-suffix': {
marginInlineStart: inputAffixPadding
}
},
...genAllowClearStyle(token),
// password
[`${iconCls}${componentCls}-password-icon`]: {
color: colorIcon,
cursor: 'pointer',
transition: `all ${motionDurationSlow}`,
'&:hover': {
color: colorIconHover
}
}
},
// 覆盖 affix-wrapper borderRadius
[`${componentCls}-underlined`]: {
borderRadius: 0
},
[affixClsDisabled]: {
// password disabled
[`${iconCls}${componentCls}-password-icon`]: {
color: colorIcon,
cursor: 'not-allowed',
'&:hover': {
color: colorIcon
}
}
}
};
};
const genGroupStyle = token => {
const {
componentCls,
borderRadiusLG,
borderRadiusSM
} = token;
return {
[`${componentCls}-group`]: {
// Style for input-group: input with label, with button or dropdown...
...resetComponent(token),
...genInputGroupStyle(token),
'&-rtl': {
direction: 'rtl'
},
'&-wrapper': {
display: 'inline-block',
width: '100%',
textAlign: 'start',
verticalAlign: 'top',
// https://github.com/ant-design/ant-design/issues/6403
'&-rtl': {
direction: 'rtl'
},
// Size
'&-lg': {
[`${componentCls}-group-addon`]: {
borderRadius: borderRadiusLG,
fontSize: token.inputFontSizeLG
}
},
'&-sm': {
[`${componentCls}-group-addon`]: {
borderRadius: borderRadiusSM
}
},
// Variants
...genOutlinedGroupStyle(token),
...genFilledGroupStyle(token),
// '&-disabled': {
// [`${componentCls}-group-addon`]: {
// ...genDisabledStyle(token),
// },
// },
// Fix the issue of using icons in Space Compact mode
// https://github.com/ant-design/ant-design/issues/42122
[`&:not(${componentCls}-compact-first-item):not(${componentCls}-compact-last-item)${componentCls}-compact-item`]: {
[`${componentCls}, ${componentCls}-group-addon`]: {
borderRadius: 0
}
},
[`&:not(${componentCls}-compact-last-item)${componentCls}-compact-first-item`]: {
[`${componentCls}, ${componentCls}-group-addon`]: {
borderStartEndRadius: 0,
borderEndEndRadius: 0
}
},
[`&:not(${componentCls}-compact-first-item)${componentCls}-compact-last-item`]: {
[`${componentCls}, ${componentCls}-group-addon`]: {
borderStartStartRadius: 0,
borderEndStartRadius: 0
}
},
// Fix the issue of input use show-count param in space compact mode
// https://github.com/ant-design/ant-design/issues/46872
[`&:not(${componentCls}-compact-last-item)${componentCls}-compact-item`]: {
[`${componentCls}-affix-wrapper`]: {
borderStartEndRadius: 0,
borderEndEndRadius: 0
}
},
// Fix the issue of input use `addonAfter` param in space compact mode
// https://github.com/ant-design/ant-design/issues/52483
[`&:not(${componentCls}-compact-first-item)${componentCls}-compact-item`]: {
[`${componentCls}-affix-wrapper`]: {
borderStartStartRadius: 0,
borderEndStartRadius: 0
}
}
}
}
};
};
// ============================== Range ===============================
const genRangeStyle = token => {
const {
componentCls
} = token;
return {
[`${componentCls}-out-of-range`]: {
[`&, & input, & textarea, ${componentCls}-show-count-suffix, ${componentCls}-data-count`]: {
color: token.colorError
}
}
};
};
// ============================== Export ==============================
export const useSharedStyle = genStyleHooks(['Input', 'Shared'], token => {
const inputToken = mergeToken(token, initInputToken(token));
return [genInputStyle(inputToken), genAffixStyle(inputToken)];
}, initComponentToken, {
resetFont: false
});
export default genStyleHooks(['Input', 'Component'], token => {
const inputToken = mergeToken(token, initInputToken(token));
return [genGroupStyle(inputToken), genRangeStyle(inputToken),
// =====================================================
// == Space Compact ==
// =====================================================
genCompactItemStyle(inputToken, {
focus: true,
focusElCls: `${inputToken.componentCls}-affix-wrapper-focused`
})];
}, initComponentToken, {
resetFont: false
});
+2
View File
@@ -0,0 +1,2 @@
declare const _default: (prefixCls: string, rootCls?: string) => readonly [string, string];
export default _default;
+61
View File
@@ -0,0 +1,61 @@
import { genStyleHooks, mergeToken } from '../../theme/internal';
import { initComponentToken, initInputToken } from './token';
// =============================== OTP ================================
const genOTPStyle = token => {
const {
componentCls,
paddingXS
} = token;
return {
[componentCls]: {
display: 'inline-flex',
alignItems: 'center',
flexWrap: 'nowrap',
columnGap: paddingXS,
[`${componentCls}-input-wrapper`]: {
position: 'relative',
[`${componentCls}-mask-icon`]: {
position: 'absolute',
zIndex: '1',
top: '50%',
right: '50%',
transform: 'translate(50%, -50%)',
pointerEvents: 'none'
},
[`${componentCls}-mask-input`]: {
color: 'transparent',
caretColor: token.colorText,
'&::selection': {
color: 'transparent'
}
},
[`${componentCls}-mask-input[type=number]::-webkit-inner-spin-button`]: {
'-webkit-appearance': 'none',
margin: 0
},
[`${componentCls}-mask-input[type=number]`]: {
'-moz-appearance': 'textfield'
}
},
'&-rtl': {
direction: 'rtl'
},
[`${componentCls}-input`]: {
textAlign: 'center',
paddingInline: token.paddingXXS
},
// ================= Size =================
[`&${componentCls}-sm ${componentCls}-input`]: {
paddingInline: token.calc(token.paddingXXS).div(2).equal()
},
[`&${componentCls}-lg ${componentCls}-input`]: {
paddingInline: token.paddingXS
}
}
};
};
// ============================== Export ==============================
export default genStyleHooks(['Input', 'OTP'], token => {
const inputToken = mergeToken(token, initInputToken(token));
return genOTPStyle(inputToken);
}, initComponentToken);
+2
View File
@@ -0,0 +1,2 @@
declare const _default: (prefixCls: string, rootCls?: string) => readonly [string, string];
export default _default;
+27
View File
@@ -0,0 +1,27 @@
import { genStyleHooks } from '../../theme/internal';
const genSearchStyle = token => {
const {
componentCls
} = token;
const btnCls = `${componentCls}-btn`;
return {
[componentCls]: {
width: '100%',
// =========================== Button ===========================
[btnCls]: {
'&-filled': {
background: token.colorFillTertiary,
'&:not(:disabled)': {
'&:hover': {
background: token.colorFillSecondary
},
'&:active': {
background: token.colorFill
}
}
}
}
}
};
};
export default genStyleHooks(['Input', 'Search'], genSearchStyle);
+6
View File
@@ -0,0 +1,6 @@
import type { ComponentToken } from './token';
import { initComponentToken, initInputToken } from './token';
export type { ComponentToken };
export { initComponentToken, initInputToken };
declare const _default: (prefixCls: string, rootCls?: string) => readonly [string, string];
export default _default;
+108
View File
@@ -0,0 +1,108 @@
import { genStyleHooks, mergeToken } from '../../theme/internal';
import { initComponentToken, initInputToken } from './token';
export { initComponentToken, initInputToken };
const genTextAreaStyle = token => {
const {
componentCls,
paddingLG
} = token;
const textareaPrefixCls = `${componentCls}-textarea`;
return {
// Raw Textarea
[`textarea${componentCls}`]: {
maxWidth: '100%',
// prevent textarea resize from coming out of its container
height: 'auto',
minHeight: token.controlHeight,
lineHeight: token.lineHeight,
verticalAlign: 'bottom',
transition: `all ${token.motionDurationSlow}`,
resize: 'vertical',
[`&${componentCls}-mouse-active`]: {
transition: `all ${token.motionDurationSlow}, height 0s, width 0s`
}
},
// Wrapper for resize
[`${componentCls}-textarea-affix-wrapper-resize-dirty`]: {
width: 'auto'
},
[textareaPrefixCls]: {
position: 'relative',
'&-show-count': {
[`${componentCls}-data-count`]: {
position: 'absolute',
bottom: token.calc(token.fontSize).mul(token.lineHeight).mul(-1).equal(),
insetInlineEnd: 0,
color: token.colorTextDescription,
whiteSpace: 'nowrap',
pointerEvents: 'none'
}
},
[`
&-allow-clear > ${componentCls},
&-affix-wrapper${textareaPrefixCls}-has-feedback ${componentCls}
`]: {
paddingInlineEnd: paddingLG
},
[`&-affix-wrapper${componentCls}-affix-wrapper`]: {
padding: 0,
[`> textarea${componentCls}`]: {
fontSize: 'inherit',
border: 'none',
outline: 'none',
background: 'transparent',
minHeight: token.calc(token.controlHeight).sub(token.calc(token.lineWidth).mul(2)).equal(),
'&:focus': {
boxShadow: 'none !important'
}
},
[`${componentCls}-suffix`]: {
margin: 0,
'> *:not(:last-child)': {
marginInline: 0
},
// Clear Icon
[`${componentCls}-clear-icon`]: {
position: 'absolute',
insetInlineEnd: token.paddingInline,
insetBlockStart: token.paddingXS
},
// Feedback Icon
[`${textareaPrefixCls}-suffix`]: {
position: 'absolute',
top: 0,
insetInlineEnd: token.paddingInline,
bottom: 0,
zIndex: 1,
display: 'inline-flex',
alignItems: 'center',
margin: 'auto',
pointerEvents: 'none'
}
}
},
[`&-affix-wrapper${componentCls}-affix-wrapper-rtl`]: {
[`${componentCls}-suffix`]: {
[`${componentCls}-data-count`]: {
direction: 'ltr',
insetInlineStart: 0
}
}
},
[`&-affix-wrapper${componentCls}-affix-wrapper-sm`]: {
[`${componentCls}-suffix`]: {
[`${componentCls}-clear-icon`]: {
insetInlineEnd: token.paddingInlineSM
}
}
}
}
};
};
// ============================== Export ==============================
export default genStyleHooks(['Input', 'TextArea'], token => {
const inputToken = mergeToken(token, initInputToken(token));
return genTextAreaStyle(inputToken);
}, initComponentToken, {
resetFont: false
});
+97
View File
@@ -0,0 +1,97 @@
import type { AliasToken, FullToken } from '../../theme/internal';
export interface SharedComponentToken {
/**
* @desc 输入框横向内边距
* @descEN Horizontal padding of input
*/
paddingInline: number;
/**
* @desc 小号输入框横向内边距
* @descEN Horizontal padding of small input
*/
paddingInlineSM: number;
/**
* @desc 大号输入框横向内边距
* @descEN Horizontal padding of large input
*/
paddingInlineLG: number;
/**
* @desc 输入框纵向内边距
* @descEN Vertical padding of input
*/
paddingBlock: number;
/**
* @desc 小号输入框纵向内边距
* @descEN Vertical padding of small input
*/
paddingBlockSM: number;
/**
* @desc 大号输入框纵向内边距
* @descEN Vertical padding of large input
*/
paddingBlockLG: number;
/**
* @desc 前/后置标签背景色
* @descEN Background color of addon
*/
addonBg: string;
/**
* @desc 悬浮态边框色
* @descEN Hover border color
*/
hoverBorderColor: string;
/**
* @desc 激活态边框色
* @descEN Active border color
*/
activeBorderColor: string;
/**
* @desc 激活态阴影
* @descEN Box-shadow when active
*/
activeShadow: string;
/**
* @desc 错误状态时激活态阴影
* @descEN Box-shadow when active in error status
*/
errorActiveShadow: string;
/**
* @desc 警告状态时激活态阴影
* @descEN Box-shadow when active in warning status
*/
warningActiveShadow: string;
/**
* @desc 输入框hover状态时背景颜色
* @descEN Background color when the input box hovers
*/
hoverBg: string;
/**
* @desc 输入框激活状态时背景颜色
* @descEN Background color when the input box is activated
*/
activeBg: string;
/**
* @desc 字体大小
* @descEN Font size
*/
inputFontSize: number;
/**
* @desc 大号字体大小
* @descEN Font size of large
*/
inputFontSizeLG: number;
/**
* @desc 小号字体大小
* @descEN Font size of small
*/
inputFontSizeSM: number;
}
export interface ComponentToken extends SharedComponentToken {
}
export interface SharedInputToken {
inputAffixPadding: number;
}
export interface InputToken extends FullToken<'Input'>, SharedInputToken {
}
export declare function initInputToken(token: AliasToken): SharedInputToken;
export declare const initComponentToken: (token: AliasToken & Partial<SharedComponentToken>) => SharedComponentToken;
+57
View File
@@ -0,0 +1,57 @@
import { mergeToken } from '../../theme/internal';
export function initInputToken(token) {
return mergeToken(token, {
inputAffixPadding: token.paddingXXS
});
}
export const initComponentToken = token => {
const {
controlHeight,
fontSize,
lineHeight,
lineWidth,
controlHeightSM,
controlHeightLG,
fontSizeLG,
lineHeightLG,
paddingSM,
controlPaddingHorizontalSM,
controlPaddingHorizontal,
colorFillAlter,
colorPrimaryHover,
colorPrimary,
controlOutlineWidth,
controlOutline,
colorErrorOutline,
colorWarningOutline,
colorBgContainer,
inputFontSize,
inputFontSizeLG,
inputFontSizeSM
} = token;
const mergedFontSize = inputFontSize || fontSize;
const mergedFontSizeSM = inputFontSizeSM || mergedFontSize;
const mergedFontSizeLG = inputFontSizeLG || fontSizeLG;
const paddingBlock = Math.round((controlHeight - mergedFontSize * lineHeight) / 2 * 10) / 10 - lineWidth;
const paddingBlockSM = Math.round((controlHeightSM - mergedFontSizeSM * lineHeight) / 2 * 10) / 10 - lineWidth;
const paddingBlockLG = Math.ceil((controlHeightLG - mergedFontSizeLG * lineHeightLG) / 2 * 10) / 10 - lineWidth;
return {
paddingBlock: Math.max(paddingBlock, 0),
paddingBlockSM: Math.max(paddingBlockSM, 0),
paddingBlockLG: Math.max(paddingBlockLG, 0),
paddingInline: paddingSM - lineWidth,
paddingInlineSM: controlPaddingHorizontalSM - lineWidth,
paddingInlineLG: controlPaddingHorizontal - lineWidth,
addonBg: colorFillAlter,
activeBorderColor: colorPrimary,
hoverBorderColor: colorPrimaryHover,
activeShadow: `0 0 0 ${controlOutlineWidth}px ${controlOutline}`,
errorActiveShadow: `0 0 0 ${controlOutlineWidth}px ${colorErrorOutline}`,
warningActiveShadow: `0 0 0 ${controlOutlineWidth}px ${colorWarningOutline}`,
hoverBg: colorBgContainer,
activeBg: colorBgContainer,
inputFontSize: mergedFontSize,
inputFontSizeLG: mergedFontSizeLG,
inputFontSizeSM: mergedFontSizeSM
};
};
+23
View File
@@ -0,0 +1,23 @@
import type { CSSObject } from '@ant-design/cssinjs';
import type { GenerateStyle } from '../../theme/internal';
import type { InputToken } from './token';
export declare const genHoverStyle: GenerateStyle<InputToken, CSSObject>;
export declare const genDisabledStyle: GenerateStyle<InputToken, CSSObject>;
export declare const genBaseOutlinedStyle: (token: InputToken, options: {
borderColor: string;
hoverBorderColor: string;
activeBorderColor: string;
activeShadow: string;
}) => CSSObject;
export declare const genOutlinedStyle: (token: InputToken, extraStyles?: CSSObject) => CSSObject;
export declare const genOutlinedGroupStyle: GenerateStyle<InputToken, CSSObject>;
export declare const genBorderlessStyle: (token: InputToken, extraStyles?: CSSObject) => CSSObject;
export declare const genFilledStyle: (token: InputToken, extraStyles?: CSSObject) => CSSObject;
export declare const genFilledGroupStyle: GenerateStyle<InputToken, CSSObject>;
export declare const genBaseUnderlinedStyle: (token: InputToken, options: {
borderColor: string;
hoverBorderColor: string;
activeBorderColor: string;
activeShadow: string;
}) => CSSObject;
export declare const genUnderlinedStyle: (token: InputToken, extraStyles?: CSSObject) => CSSObject;
+331
View File
@@ -0,0 +1,331 @@
import { unit } from '@ant-design/cssinjs';
import { mergeToken } from '../../theme/internal';
export const genHoverStyle = token => ({
borderColor: token.hoverBorderColor,
backgroundColor: token.hoverBg
});
export const genDisabledStyle = token => ({
color: token.colorTextDisabled,
backgroundColor: token.colorBgContainerDisabled,
borderColor: token.colorBorderDisabled,
boxShadow: 'none',
cursor: 'not-allowed',
opacity: 1,
'input[disabled], textarea[disabled]': {
cursor: 'not-allowed'
},
'&:hover:not([disabled])': {
...genHoverStyle(mergeToken(token, {
hoverBorderColor: token.colorBorderDisabled,
hoverBg: token.colorBgContainerDisabled
}))
}
});
/* ============== Outlined ============== */
export const genBaseOutlinedStyle = (token, options) => ({
background: token.colorBgContainer,
borderWidth: token.lineWidth,
borderStyle: token.lineType,
borderColor: options.borderColor,
'&:hover': {
borderColor: options.hoverBorderColor,
backgroundColor: token.hoverBg
},
'&:focus, &:focus-within': {
borderColor: options.activeBorderColor,
boxShadow: options.activeShadow,
outline: 0,
backgroundColor: token.activeBg
}
});
const genOutlinedStatusStyle = (token, options) => ({
[`&${token.componentCls}-status-${options.status}:not(${token.componentCls}-disabled)`]: {
...genBaseOutlinedStyle(token, options),
[`${token.componentCls}-prefix, ${token.componentCls}-suffix`]: {
color: options.affixColor
}
},
[`&${token.componentCls}-status-${options.status}${token.componentCls}-disabled`]: {
borderColor: options.borderColor
}
});
export const genOutlinedStyle = (token, extraStyles) => ({
'&-outlined': {
...genBaseOutlinedStyle(token, {
borderColor: token.colorBorder,
hoverBorderColor: token.hoverBorderColor,
activeBorderColor: token.activeBorderColor,
activeShadow: token.activeShadow
}),
[`&${token.componentCls}-disabled, &[disabled]`]: {
...genDisabledStyle(token)
},
...genOutlinedStatusStyle(token, {
status: 'error',
borderColor: token.colorError,
hoverBorderColor: token.colorErrorBorderHover,
activeBorderColor: token.colorError,
activeShadow: token.errorActiveShadow,
affixColor: token.colorError
}),
...genOutlinedStatusStyle(token, {
status: 'warning',
borderColor: token.colorWarning,
hoverBorderColor: token.colorWarningBorderHover,
activeBorderColor: token.colorWarning,
activeShadow: token.warningActiveShadow,
affixColor: token.colorWarning
}),
...extraStyles
}
});
const genOutlinedGroupStatusStyle = (token, options) => ({
[`&${token.componentCls}-group-wrapper-status-${options.status}`]: {
[`${token.componentCls}-group-addon`]: {
borderColor: options.addonBorderColor,
color: options.addonColor
}
}
});
export const genOutlinedGroupStyle = token => ({
'&-outlined': {
[`${token.componentCls}-group`]: {
'&-addon': {
background: token.addonBg,
border: `${unit(token.lineWidth)} ${token.lineType} ${token.colorBorder}`
},
'&-addon:first-child': {
borderInlineEnd: 0
},
'&-addon:last-child': {
borderInlineStart: 0
}
},
...genOutlinedGroupStatusStyle(token, {
status: 'error',
addonBorderColor: token.colorError,
addonColor: token.colorErrorText
}),
...genOutlinedGroupStatusStyle(token, {
status: 'warning',
addonBorderColor: token.colorWarning,
addonColor: token.colorWarningText
}),
[`&${token.componentCls}-group-wrapper-disabled`]: {
[`${token.componentCls}-group-addon`]: {
...genDisabledStyle(token)
}
}
}
});
/* ============ Borderless ============ */
export const genBorderlessStyle = (token, extraStyles) => {
const {
componentCls
} = token;
return {
'&-borderless': {
background: 'transparent',
border: 'none',
// Compensate for the removed border to maintain consistent height with other components
// (e.g. Select borderless) that keep a transparent border.
paddingBlock: token.calc(token.paddingBlock).add(token.lineWidth).equal(),
[`&${componentCls}-sm, &${componentCls}-affix-wrapper-sm`]: {
paddingBlock: token.calc(token.paddingBlockSM).add(token.lineWidth).equal()
},
[`&${componentCls}-lg, &${componentCls}-affix-wrapper-lg`]: {
paddingBlock: token.calc(token.paddingBlockLG).add(token.lineWidth).equal()
},
'&:focus, &:focus-within': {
outline: 'none'
},
// >>>>> Disabled
[`&${componentCls}-disabled, &[disabled]`]: {
color: token.colorTextDisabled,
cursor: 'not-allowed'
},
// >>>>> Status
[`&${componentCls}-status-error`]: {
'&, & input, & textarea': {
color: token.colorError
}
},
[`&${componentCls}-status-warning`]: {
'&, & input, & textarea': {
color: token.colorWarning
}
},
...extraStyles
}
};
};
/* ============== Filled ============== */
const genBaseFilledStyle = (token, options) => ({
background: options.bg,
borderWidth: token.lineWidth,
borderStyle: token.lineType,
borderColor: 'transparent',
'input&, & input, textarea&, & textarea': {
color: options?.inputColor ?? 'unset'
},
'&:hover': {
background: options.hoverBg
},
'&:focus, &:focus-within': {
outline: 0,
borderColor: options.activeBorderColor,
backgroundColor: token.activeBg
}
});
const genFilledStatusStyle = (token, options) => ({
[`&${token.componentCls}-status-${options.status}:not(${token.componentCls}-disabled)`]: {
...genBaseFilledStyle(token, options),
[`${token.componentCls}-prefix, ${token.componentCls}-suffix`]: {
color: options.affixColor
}
}
});
export const genFilledStyle = (token, extraStyles) => ({
'&-filled': {
...genBaseFilledStyle(token, {
bg: token.colorFillTertiary,
hoverBg: token.colorFillSecondary,
activeBorderColor: token.activeBorderColor,
inputColor: token.colorText
}),
[`&${token.componentCls}-disabled, &[disabled]`]: {
...genDisabledStyle(token)
},
...genFilledStatusStyle(token, {
status: 'error',
bg: token.colorErrorBg,
hoverBg: token.colorErrorBgHover,
activeBorderColor: token.colorError,
inputColor: token.colorErrorText,
affixColor: token.colorError
}),
...genFilledStatusStyle(token, {
status: 'warning',
bg: token.colorWarningBg,
hoverBg: token.colorWarningBgHover,
activeBorderColor: token.colorWarning,
inputColor: token.colorWarningText,
affixColor: token.colorWarning
}),
...extraStyles
}
});
const genFilledGroupStatusStyle = (token, options) => ({
[`&${token.componentCls}-group-wrapper-status-${options.status}`]: {
[`${token.componentCls}-group-addon`]: {
background: options.addonBg,
color: options.addonColor
}
}
});
export const genFilledGroupStyle = token => ({
'&-filled': {
[`${token.componentCls}-group-addon`]: {
background: token.colorFillTertiary,
'&:last-child': {
position: 'static'
}
},
...genFilledGroupStatusStyle(token, {
status: 'error',
addonBg: token.colorErrorBg,
addonColor: token.colorErrorText
}),
...genFilledGroupStatusStyle(token, {
status: 'warning',
addonBg: token.colorWarningBg,
addonColor: token.colorWarningText
}),
[`&${token.componentCls}-group-wrapper-disabled`]: {
[`${token.componentCls}-group`]: {
'&-addon': {
background: token.colorFillTertiary,
color: token.colorTextDisabled
},
'&-addon:first-child': {
borderInlineStart: `${unit(token.lineWidth)} ${token.lineType} ${token.colorBorder}`,
borderTop: `${unit(token.lineWidth)} ${token.lineType} ${token.colorBorder}`,
borderBottom: `${unit(token.lineWidth)} ${token.lineType} ${token.colorBorder}`
},
'&-addon:last-child': {
borderInlineEnd: `${unit(token.lineWidth)} ${token.lineType} ${token.colorBorder}`,
borderTop: `${unit(token.lineWidth)} ${token.lineType} ${token.colorBorder}`,
borderBottom: `${unit(token.lineWidth)} ${token.lineType} ${token.colorBorder}`
}
}
}
}
});
/* ============== Underlined ============== */
// https://github.com/ant-design/ant-design/issues/51379
export const genBaseUnderlinedStyle = (token, options) => ({
background: token.colorBgContainer,
borderWidth: `${unit(token.lineWidth)} 0`,
borderStyle: `${token.lineType} none`,
borderColor: `transparent transparent ${options.borderColor} transparent`,
borderRadius: 0,
'&:hover': {
borderColor: `transparent transparent ${options.hoverBorderColor} transparent`,
backgroundColor: token.hoverBg
},
'&:focus, &:focus-within': {
borderColor: `transparent transparent ${options.activeBorderColor} transparent`,
outline: 0,
backgroundColor: token.activeBg
}
});
const genUnderlinedStatusStyle = (token, options) => ({
[`&${token.componentCls}-status-${options.status}:not(${token.componentCls}-disabled)`]: {
...genBaseUnderlinedStyle(token, options),
[`${token.componentCls}-prefix, ${token.componentCls}-suffix`]: {
color: options.affixColor
}
},
[`&${token.componentCls}-status-${options.status}${token.componentCls}-disabled`]: {
borderColor: `transparent transparent ${options.borderColor} transparent`
}
});
export const genUnderlinedStyle = (token, extraStyles) => ({
'&-underlined': {
...genBaseUnderlinedStyle(token, {
borderColor: token.colorBorder,
hoverBorderColor: token.hoverBorderColor,
activeBorderColor: token.activeBorderColor,
activeShadow: token.activeShadow
}),
// >>>>> Disabled
[`&${token.componentCls}-disabled, &[disabled]`]: {
color: token.colorTextDisabled,
boxShadow: 'none',
cursor: 'not-allowed',
'&:hover': {
borderColor: `transparent transparent ${token.colorBorder} transparent`
}
},
'input[disabled], textarea[disabled]': {
cursor: 'not-allowed'
},
...genUnderlinedStatusStyle(token, {
status: 'error',
borderColor: token.colorError,
hoverBorderColor: token.colorErrorBorderHover,
activeBorderColor: token.colorError,
activeShadow: token.errorActiveShadow,
affixColor: token.colorError
}),
...genUnderlinedStatusStyle(token, {
status: 'warning',
borderColor: token.colorWarning,
hoverBorderColor: token.colorWarningBorderHover,
activeBorderColor: token.colorWarning,
activeShadow: token.warningActiveShadow,
affixColor: token.colorWarning
}),
...extraStyles
}
});
+8
View File
@@ -0,0 +1,8 @@
import type { ReactNode } from 'react';
import type { InputProps } from './Input';
export declare function hasPrefixSuffix(props: {
prefix?: ReactNode;
suffix?: ReactNode;
allowClear?: InputProps['allowClear'];
showCount?: InputProps['showCount'];
}): boolean;
+3
View File
@@ -0,0 +1,3 @@
export function hasPrefixSuffix(props) {
return !!(props.prefix || props.suffix || props.allowClear || props.showCount);
}