1
This commit is contained in:
+16
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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;
|
||||
+2
@@ -0,0 +1,2 @@
|
||||
import type { InputRef } from '../Input';
|
||||
export default function useRemovePasswordTimeout(inputRef: React.RefObject<InputRef | null>, triggerOnMount?: boolean): () => void;
|
||||
+22
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -0,0 +1,2 @@
|
||||
declare const _default: (prefixCls: string, rootCls?: string) => readonly [string, string];
|
||||
export default _default;
|
||||
+61
@@ -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
@@ -0,0 +1,2 @@
|
||||
declare const _default: (prefixCls: string, rootCls?: string) => readonly [string, string];
|
||||
export default _default;
|
||||
+27
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -0,0 +1,3 @@
|
||||
export function hasPrefixSuffix(props) {
|
||||
return !!(props.prefix || props.suffix || props.allowClear || props.showCount);
|
||||
}
|
||||
Reference in New Issue
Block a user