diff --git a/site/mobile/mobile.config.js b/site/mobile/mobile.config.js index f57b8fae..2cf97c94 100644 --- a/site/mobile/mobile.config.js +++ b/site/mobile/mobile.config.js @@ -33,7 +33,7 @@ export default { { title: 'Image 图片', name: 'image', - component: () => import('tdesign-mobile-react/image/_example/index.jsx'), + component: () => import('tdesign-mobile-react/image/_example/index.tsx'), }, { title: 'Overlay 遮罩层', @@ -222,5 +222,10 @@ export default { name: 'result', component: () => import('tdesign-mobile-react/result/_example/index.tsx'), }, + { + title: 'Link 链接', + name: 'link', + component: () => import('tdesign-mobile-react/link/_example/index.tsx'), + }, ], }; diff --git a/site/web/site.config.js b/site/web/site.config.js index 09c74e11..d5364146 100644 --- a/site/web/site.config.js +++ b/site/web/site.config.js @@ -40,13 +40,18 @@ export default { path: '/mobile-react/components/fab', component: () => import('tdesign-mobile-react/fab/fab.md'), }, - { title: 'Icon 图标', name: 'icon', path: '/mobile-react/components/icon', component: () => import('tdesign-mobile-react/icon/icon.md'), }, + { + title: 'Link 链接', + name: 'link', + path: '/mobile-react/components/link', + component: () => import('tdesign-mobile-react/link/link.md'), + }, ], }, { diff --git a/src/_common b/src/_common index 762c4d5d..cfcad47f 160000 --- a/src/_common +++ b/src/_common @@ -1 +1 @@ -Subproject commit 762c4d5d576db1262a4c26d03b133077422749ca +Subproject commit cfcad47f9c27eaf31ad50de07347f8c07685a090 diff --git a/src/image/Image.tsx b/src/image/Image.tsx index 6a726d85..aacb37a4 100644 --- a/src/image/Image.tsx +++ b/src/image/Image.tsx @@ -1,94 +1,132 @@ -import React, { FC, useCallback, useMemo, useRef, useState } from 'react'; -import ClassNames from 'classnames'; -import { CloseIcon, EllipsisIcon } from 'tdesign-icons-react'; -import { useInViewport } from 'ahooks'; -import useConfig from '../_util/useConfig'; +import React, { Fragment, useRef, useMemo, useState, useEffect } from 'react'; +import type { SyntheticEvent } from 'react'; +import classNames from 'classnames'; +import { CloseIcon as TdCloseIcon } from 'tdesign-icons-react'; +import Loading from '../loading'; +import observe from '../_common/js/utils/observe'; +import { StyledProps } from '../common'; import { TdImageProps } from './type'; +import { imageDefaultProps } from './defaultProps'; +import parseTNode from '../_util/parseTNode'; +import useDefaultProps from '../hooks/useDefaultProps'; +import { usePrefixClass } from '../hooks/useClass'; -export interface ImageProps extends TdImageProps, Omit, 'loading' | 'onError' | 'onLoad'> {} +export interface ImageProps extends TdImageProps, StyledProps {} -const Image: FC = React.memo((props) => { +const Image: React.FC = (props) => { const { + className, + style, src, alt, - fit = 'fill', - onLoad, - loading, - onError, + error, + fallback, + fit, lazy, - shape = 'round', + loading, + shape, position, - error, - className, - style, - ...others - } = props; - - const [isLoad, setIsLoad] = useState(true); - const [isError, setIsError] = useState(false); - const ref = useRef(null); - const hasLoad = useRef(false); + referrerpolicy, + srcset, + onError, + onLoad, + } = useDefaultProps(props, imageDefaultProps); - // 统一配置信息 - const { classPrefix } = useConfig(); + const imageClass = usePrefixClass('image'); + const imageRef = useRef(null); - // 观察元素是否在可见区域 - const [isInViewport] = useInViewport(ref); + const [imageSrc, setImageSrc] = useState(src); + const [isLoaded, setIsLoaded] = useState(false); + const [isError, setIsError] = useState(false); + const [shouldLoad, setShouldLoad] = useState(!lazy); - const prefix = useMemo(() => `${classPrefix}-image`, [classPrefix]); + const rootClasses = classNames( + { + [`${imageClass}`]: true, + [`${imageClass}--${shape}`]: true, + }, + className, + ); // Loading Element const LoadingStatus = useMemo(() => { - if (!isLoad) return null; - - return loading || ; - }, [isLoad, loading]); + if (!(isError || !shouldLoad) && !isLoaded) return loading || ; + }, [isError, shouldLoad, isLoaded, loading]); // Loading Failed Element const FailedStatus = useMemo(() => { - if (!isError) return null; - - return error || ; + if (isError) return error || ; }, [isError, error]); - // Image Src - const imgSrc = useMemo(() => { - if (!lazy || hasLoad.current) return src; - - if (isInViewport) return src; - - return ''; - }, [src, lazy, isInViewport]); + const handleLoadImage = () => { + setShouldLoad(true); + }; + + useEffect(() => { + if (!lazy || !imageRef?.current) { + return; + } + + const handleUnObserve = (element) => { + const observer = observe(element, null, handleLoadImage, 0); + return () => { + observer && observer.unobserve(element); + }; + }; + + return handleUnObserve(imageRef.current); + }, [lazy, imageRef]); + + // 图片加载完成回调 + const handleLoad = (e: SyntheticEvent) => { + setIsLoaded(true); + onLoad?.({ e }); + }; + + // 图片加载失败回调 + const handleError = (e: SyntheticEvent) => { + setIsError(true); + if (fallback) { + setImageSrc(fallback); + } + onError?.({ e }); + }; + + const renderMask = () => + LoadingStatus || FailedStatus ? ( +
{parseTNode(LoadingStatus || FailedStatus)}
+ ) : null; + + const renderImage = () => ( + {alt} + ); - // Get ClassName By Prefix - const getClass = useCallback((cls: string) => `${prefix}__${cls}`, [prefix]); + const renderImageSrcset = () => ( + + {Object.entries(srcset).map(([type, url]) => ( + + ))} + {src && renderImage()} + + ); return ( -
- {LoadingStatus || FailedStatus ?
{LoadingStatus || FailedStatus}
: null} - {alt} { - hasLoad.current = true; - setIsLoad(false); - setIsError(false); - onLoad && onLoad(); - }} - onError={() => { - if (imgSrc) { - hasLoad.current = true; - setIsLoad(false); - setIsError(true); - onError && onError(); - } - }} - /> +
+ {renderMask()} + {!isError && shouldLoad && ( + {srcset && Object.keys(srcset).length ? renderImageSrcset() : renderImage()} + )}
); -}); +}; + +Image.displayName = 'Image'; export default Image; diff --git a/src/image/_example/base.tsx b/src/image/_example/base.tsx new file mode 100644 index 00000000..3beb5f6a --- /dev/null +++ b/src/image/_example/base.tsx @@ -0,0 +1,60 @@ +import React from 'react'; +import { Image } from 'tdesign-mobile-react'; + +const imageSrc = 'https://tdesign.gtimg.com/demo/demo-image-1.png'; + +export default function BaseImage() { + return ( +
+
不同填充模式的图片
+
提供 fill、contain、cover、none、scale-down 5 种填充类型。
+
+
+

fill

+ +
+
+

contain

+ +
+
+

cover

+ +
+
+

none

+ +
+
+

scale-down

+ +
+
+
+ ); +} diff --git a/src/image/_example/crop.jsx b/src/image/_example/crop.jsx deleted file mode 100644 index ab30d3bd..00000000 --- a/src/image/_example/crop.jsx +++ /dev/null @@ -1,24 +0,0 @@ -import React from 'react'; -import { Image } from 'tdesign-mobile-react'; -import './style/index.less'; - -const CropDemo = React.memo(() => ( - <> -
-
- -
裁切
-
-
- -
适应高
-
-
- -
拉伸
-
-
- -)); - -export default CropDemo; diff --git a/src/image/_example/index.jsx b/src/image/_example/index.jsx deleted file mode 100644 index 82242995..00000000 --- a/src/image/_example/index.jsx +++ /dev/null @@ -1,33 +0,0 @@ -import React from 'react'; -import TDemoBlock from '../../../site/mobile/components/DemoBlock'; -import TDemoHeader from '../../../site/mobile/components/DemoHeader'; -import CropDemo from './crop'; -import RoundDemo from './rounded'; -import LoadingTipDemo from './loading-tip'; -import LoadingErrorDemo from './loading-error'; -import SizeDemo from './size'; - -export default function Base() { - return ( - <> - - - - - - - - - - - - - - - - - - - - ); -} diff --git a/src/image/_example/index.tsx b/src/image/_example/index.tsx new file mode 100644 index 00000000..12206621 --- /dev/null +++ b/src/image/_example/index.tsx @@ -0,0 +1,23 @@ +import React from 'react'; +import TDemoBlock from '../../../site/mobile/components/DemoBlock'; +import TDemoHeader from '../../../site/mobile/components/DemoHeader'; +import BaseImage from './base'; +import PositionImage from './position'; +import ShapeImage from './shape'; +import StatusImage from './status'; + +export default function ImageDemo() { + return ( + <> + + + + + + + + + + + ); +} diff --git a/src/image/_example/loading-error.jsx b/src/image/_example/loading-error.jsx deleted file mode 100644 index 2b684807..00000000 --- a/src/image/_example/loading-error.jsx +++ /dev/null @@ -1,24 +0,0 @@ -import React from 'react'; -import { Image } from 'tdesign-mobile-react'; -import './style/index.less'; - -const LoadingErrorDemo = React.memo(() => ( - <> -
-
- -
默认提示
-
-
- 加载失败} - style={{ width: 72, height: 72 }} - /> -
自定义提示
-
-
- -)); - -export default LoadingErrorDemo; diff --git a/src/image/_example/loading-tip.jsx b/src/image/_example/loading-tip.jsx deleted file mode 100644 index f8e8c681..00000000 --- a/src/image/_example/loading-tip.jsx +++ /dev/null @@ -1,21 +0,0 @@ -import React from 'react'; -import { Image } from 'tdesign-mobile-react'; -import { LoadingIcon } from 'tdesign-icons-react'; -import './style/index.less'; - -const LoadingTipDemo = React.memo(() => ( - <> -
-
- -
默认提示
-
-
- } style={{ width: 72, height: 72 }} /> -
自定义提示
-
-
- -)); - -export default LoadingTipDemo; diff --git a/src/image/_example/position.tsx b/src/image/_example/position.tsx new file mode 100644 index 00000000..e2a55fc4 --- /dev/null +++ b/src/image/_example/position.tsx @@ -0,0 +1,117 @@ +import React from 'react'; +import { Image } from 'tdesign-mobile-react'; + +import './style/index.less'; + +const imageSrc = 'https://tdesign.gtimg.com/demo/demo-image-1.png'; + +export default function PositionImage() { + return ( +
+
不同填充位置的图片
+
当图片过大时,提供显示图片的局部左侧对齐、或右侧对齐的不同位置。
+
+
+

cover center

+ +
+
+

cover left

+ +
+
+

cover right

+ +
+
+

cover top

+ +
+
+

cover bottom

+ +
+
+

contain top

+ +
+
+

contain bottom

+ +
+
+

contain center

+ +
+
+

contain left

+ +
+
+

contain right

+ +
+
+
+ ); +} diff --git a/src/image/_example/rounded.jsx b/src/image/_example/rounded.jsx deleted file mode 100644 index 2a39cd22..00000000 --- a/src/image/_example/rounded.jsx +++ /dev/null @@ -1,24 +0,0 @@ -import React from 'react'; -import { Image } from 'tdesign-mobile-react'; -import './style/index.less'; - -const RoundDemo = React.memo(() => ( - <> -
-
- -
方形
-
-
- -
圆角方形
-
-
- -
圆角
-
-
- -)); - -export default RoundDemo; diff --git a/src/image/_example/shape.tsx b/src/image/_example/shape.tsx new file mode 100644 index 00000000..9fb4e29b --- /dev/null +++ b/src/image/_example/shape.tsx @@ -0,0 +1,29 @@ +import React from 'react'; +import { Image } from 'tdesign-mobile-react'; + +const imageSrc = 'https://tdesign.gtimg.com/demo/demo-image-1.png'; + +export default function RoundDemo() { + return ( +
+
不同形状的图片
+
+ 提供方形、圆角方形、圆角 3 种形状。 当图片长宽不相等时,无法使用 circle 展示一个正圆。 +
+
+
+

方形

+ +
+
+

圆角方形

+ +
+
+

圆形

+ 一张图片 +
+
+
+ ); +} diff --git a/src/image/_example/size.jsx b/src/image/_example/size.jsx deleted file mode 100644 index 75b557fc..00000000 --- a/src/image/_example/size.jsx +++ /dev/null @@ -1,38 +0,0 @@ -import React from 'react'; -import { Image } from 'tdesign-mobile-react'; -import './style/index.less'; - -const SizeDemo = React.memo(() => ( -
-
- -
图片 56
-
- -
- -
图片 48
-
- -
- -
图片 32
-
- -
- -
图片 24
-
-
- -
图片 120
-
- -
- -
图片 72
-
-
-)); - -export default SizeDemo; diff --git a/src/image/_example/status.tsx b/src/image/_example/status.tsx new file mode 100644 index 00000000..c70c2b41 --- /dev/null +++ b/src/image/_example/status.tsx @@ -0,0 +1,34 @@ +import React from 'react'; +import { Image, Loading } from 'tdesign-mobile-react'; + +export default function RoundDemo() { + return ( + <> +
+
+

加载默认提示

+ +
+
+

加载自定义提示

+ } /> +
+
+
+
+

失败默认提示

+ +
+
+

失败自定义提示

+ 加载失败} + /> +
+
+ + ); +} diff --git a/src/image/_example/style/index.less b/src/image/_example/style/index.less index 681e68fc..c0eca4e9 100644 --- a/src/image/_example/style/index.less +++ b/src/image/_example/style/index.less @@ -1,27 +1,64 @@ -.t-image { - &__demo-base { - padding: 0 10px; +.image-example { + margin-bottom: 24px; + color: var(--td-text-color-secondary, rgba(0, 0, 0, 0.6)); + + &-title { + font-size: 14px; + line-height: 22px; } - &__demo-size { - padding: 0 10px; + &-desc { + font-size: 12px; + line-height: 20px; } +} - &__demo-wrap { - margin: 0 10px; - display: inline-block; - vertical-align: top; - text-align: center; +// shape +.image-group { + display: flex; + flex-wrap: wrap; - h5 { - margin-bottom: 5px; - font-size: 12px; - color: #999; + .image-demo { + margin-right: 24px; + .image-container { + height: 72px; + width: 72px; + background-color: #000; } - .t-image__demo-size & { - margin-bottom: 10px; - vertical-align: bottom; + .image-demo-tip { + color: var(--td-text-color-secondary, rgba(0, 0, 0, 0.6)); + font-size: 14px; + line-height: 22px; + margin: 16px 0; + white-space: nowrap; } } } + +// status +.row { + display: flex; + grid-gap: 24px; + padding: 0 16px; + margin-bottom: 16px; + + .image-container { + width: 72px; + height: 72px; + } +} + +.tips { + color: var(--td-text-color-secondary, rgba(0, 0, 0, 0.6)); + font-size: 14px; + line-height: 22px; + margin-bottom: 16px; + text-align: center; + white-space: nowrap; +} + +.error-tips { + color: var(--td-text-color-placeholder, rgba(0, 0, 0, 0.4)); + font-size: 10px; +} diff --git a/src/image/defaultProps.ts b/src/image/defaultProps.ts new file mode 100644 index 00000000..c7cf3a7f --- /dev/null +++ b/src/image/defaultProps.ts @@ -0,0 +1,7 @@ +/** + * 该文件为脚本自动生成文件,请勿随意修改。如需修改请联系 PMC + * */ + +import { TdImageProps } from './type'; + +export const imageDefaultProps: TdImageProps = { fit: 'fill', lazy: false, position: 'center', shape: 'square' }; diff --git a/src/image/image.en-US.md b/src/image/image.en-US.md new file mode 100644 index 00000000..6ba08b50 --- /dev/null +++ b/src/image/image.en-US.md @@ -0,0 +1,24 @@ +:: BASE_DOC :: + +## API + + +### Image Props + +name | type | default | description | required +-- | -- | -- | -- | -- +className | String | - | className of component | N +style | Object | - | CSS(Cascading Style Sheets),Typescript:`React.CSSProperties` | N +alt | String | - | \- | N +error | TNode | - | Typescript:`string \| TNode`。[see more ts definition](https://github.com/Tencent/tdesign-mobile-react/blob/develop/src/common.ts) | N +fallback | String | - | display `fallback` image on `src` loading failed. you can also use `error` to define more complex error content | N +fit | String | fill | options: contain/cover/fill/none/scale-down | N +lazy | Boolean | false | \- | N +loading | TNode | - | Typescript:`string \| TNode`。[see more ts definition](https://github.com/Tencent/tdesign-mobile-react/blob/develop/src/common.ts) | N +position | String | center | \- | N +referrerpolicy | String | - | attribute of ``, [MDN Definition](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Referrer-Policy)。options: no-referrer/no-referrer-when-downgrade/origin/origin-when-cross-origin/same-origin/strict-origin/strict-origin-when-cross-origin/unsafe-url | N +shape | String | square | options: circle/round/square | N +src | String | - | \- | N +srcset | Object | - | for `.avif` and `.webp` image url, load `srcset` before `src`。Typescript:`ImageSrcset` `interface ImageSrcset { 'image/avif': string; 'image/webp': string; }`。[see more ts definition](https://github.com/Tencent/tdesign-mobile-react/tree/develop/src/image/type.ts) | N +onError | Function | | Typescript:`(context: { e: ImageEvent }) => void`
trigger on image load failed | N +onLoad | Function | | Typescript:`(context: { e: ImageEvent }) => void`
trigger on image loaded | N diff --git a/src/image/image.md b/src/image/image.md index 43aefeef..60d2e854 100644 --- a/src/image/image.md +++ b/src/image/image.md @@ -4,17 +4,20 @@ ### Image Props -| 名称 | 类型 | 默认值 | 说明 | 必传 | -| --------- | -------- | ------ | ------------------------------------------------------------------------------------------------------------------------------------------------- | ---- | -| className | String | - | 类名 | N | -| style | Object | - | 样式,TS 类型:`React.CSSProperties` | N | -| alt | String | - | 图片描述 | N | -| error | TElement | - | 自定义加载失败状态下的图片内容。TS 类型:`TNode`。[通用类型定义](https://github.com/Tencent/tdesign-mobile-react/blob/develop/src/common.ts) | N | -| fit | String | fill | 图片填充模式。可选项:contain/cover/fill/none/scale-down | N | -| lazy | Boolean | false | 是否开启图片懒加载 | N | -| loading | TElement | - | 自定义加载中状态下的图片内容。TS 类型:`TNode`。[通用类型定义](https://github.com/Tencent/tdesign-mobile-react/blob/develop/src/common.ts) | N | -| position | String | center | 等同于原生的 object-position 属性,可选值为 top right bottom left 或 string,可以自定义任何 px 或者百分比 | N | -| shape | String | circle | 图片圆角类型。可选项:circle/round/square | N | -| src | String | - | 图片链接 | N | -| onError | Function | | TS 类型:`() => void`
图片加载失败时触发 | N | -| onLoad | Function | | TS 类型:`() => void`
图片加载完成时触发 | N | +名称 | 类型 | 默认值 | 描述 | 必传 +-- | -- | -- | -- | -- +className | String | - | 类名 | N +style | Object | - | 样式,TS 类型:`React.CSSProperties` | N +alt | String | - | 图片描述 | N +error | TNode | - | 自定义图片加载失败状态下的显示内容。TS 类型:`string \| TNode`。[通用类型定义](https://github.com/Tencent/tdesign-mobile-react/blob/develop/src/common.ts) | N +fallback | String | - | 图片加载失败时,显示当前链接设置的图片地址。如果要使用组件图标或完全自定义加载失败时显示的内容,请更为使用 `error` | N +fit | String | fill | 图片填充模式。可选项:contain/cover/fill/none/scale-down | N +lazy | Boolean | false | 是否开启图片懒加载 | N +loading | TNode | - | 自定义加载中状态的图片内容,如:“加载中”。TS 类型:`string \| TNode`。[通用类型定义](https://github.com/Tencent/tdesign-mobile-react/blob/develop/src/common.ts) | N +position | String | center | 等同于原生的 object-position 属性,可选值为 top right bottom left 或 string,可以自定义任何单位,px 或者 百分比 | N +referrerpolicy | String | - | `` 标签的原生属性,[MDN 定义](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Referrer-Policy)。可选项:no-referrer/no-referrer-when-downgrade/origin/origin-when-cross-origin/same-origin/strict-origin/strict-origin-when-cross-origin/unsafe-url | N +shape | String | square | 图片圆角类型。可选项:circle/round/square | N +src | String | - | 图片链接 | N +srcset | Object | - | 图片链接集合,用于支持特殊格式的图片,如 `.avif` 和 `.webp`。会优先加载 `srcset` 中的图片格式,浏览器不支持的情况下,加载 `src` 设置的图片地址。TS 类型:`ImageSrcset` `interface ImageSrcset { 'image/avif': string; 'image/webp': string; }`。[详细类型定义](https://github.com/Tencent/tdesign-mobile-react/tree/develop/src/image/type.ts) | N +onError | Function | | TS 类型:`(context: { e: ImageEvent }) => void`
图片加载失败时触发 | N +onLoad | Function | | TS 类型:`(context: { e: ImageEvent }) => void`
图片加载完成时触发 | N diff --git a/src/image/style/index.js b/src/image/style/index.js index c8428f3c..4c65c1c8 100644 --- a/src/image/style/index.js +++ b/src/image/style/index.js @@ -1 +1 @@ -import '../../_common/style/mobile/components/image/_index.less'; +import '../../_common/style/mobile/components/image/v2/_index.less'; diff --git a/src/image/type.ts b/src/image/type.ts index eae64c26..305603da 100644 --- a/src/image/type.ts +++ b/src/image/type.ts @@ -4,7 +4,7 @@ * 该文件为脚本自动生成文件,请勿随意修改。如需修改请联系 PMC * */ -import { TElement } from '../common'; +import { TNode, ImageEvent } from '../common'; export interface TdImageProps { /** @@ -13,9 +13,14 @@ export interface TdImageProps { */ alt?: string; /** - * 自定义加载失败状态下的图片内容 + * 自定义图片加载失败状态下的显示内容 */ - error?: TElement; + error?: TNode; + /** + * 图片加载失败时,显示当前链接设置的图片地址。如果要使用组件图标或完全自定义加载失败时显示的内容,请更为使用 `error` + * @default '' + */ + fallback?: string; /** * 图片填充模式 * @default fill @@ -27,17 +32,29 @@ export interface TdImageProps { */ lazy?: boolean; /** - * 自定义加载中状态下的图片内容 + * 自定义加载中状态的图片内容,如:“加载中” */ - loading?: TElement; + loading?: TNode; /** - * 等同于原生的 object-position 属性,可选值为 top right bottom left 或 string,可以自定义任何px或者百分比 + * 等同于原生的 object-position 属性,可选值为 top right bottom left 或 string,可以自定义任何单位,px 或者 百分比 * @default center */ position?: string; + /** + * `` 标签的原生属性,[MDN 定义](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Referrer-Policy) + */ + referrerpolicy?: + | 'no-referrer' + | 'no-referrer-when-downgrade' + | 'origin' + | 'origin-when-cross-origin' + | 'same-origin' + | 'strict-origin' + | 'strict-origin-when-cross-origin' + | 'unsafe-url'; /** * 图片圆角类型 - * @default circle + * @default square */ shape?: 'circle' | 'round' | 'square'; /** @@ -45,12 +62,21 @@ export interface TdImageProps { * @default '' */ src?: string; + /** + * 图片链接集合,用于支持特殊格式的图片,如 `.avif` 和 `.webp`。会优先加载 `srcset` 中的图片格式,浏览器不支持的情况下,加载 `src` 设置的图片地址 + */ + srcset?: ImageSrcset; /** * 图片加载失败时触发 */ - onError?: () => void; + onError?: (context: { e: ImageEvent }) => void; /** * 图片加载完成时触发 */ - onLoad?: () => void; + onLoad?: (context: { e: ImageEvent }) => void; +} + +export interface ImageSrcset { + 'image/avif': string; + 'image/webp': string; } diff --git a/src/index.ts b/src/index.ts index d65a3061..de363141 100644 --- a/src/index.ts +++ b/src/index.ts @@ -5,6 +5,7 @@ export * from './button'; export * from './divider'; export * from './fab'; export * from './progress'; +export * from './link'; /** * 导航(5个) diff --git a/src/indexes/Indexes.tsx b/src/indexes/Indexes.tsx index cb8525de..fbb3940f 100644 --- a/src/indexes/Indexes.tsx +++ b/src/indexes/Indexes.tsx @@ -1,4 +1,4 @@ -import React, { FC, forwardRef, useState, MouseEvent, TouchEvent, useRef, useEffect } from 'react'; +import React, { useState, MouseEvent, TouchEvent, useRef, useEffect } from 'react'; import isFunction from 'lodash/isFunction'; import throttle from 'lodash/throttle'; import { Cell, CellGroup } from '../cell'; @@ -10,7 +10,7 @@ const topOffset = 40; // 滑动选中高亮的顶部偏移(px) export interface IndexesProps extends TdIndexesProps, StyledProps {} -const Indexes: FC = forwardRef((props) => { +const Indexes: React.FC = (props) => { const { height, list, onSelect, style } = props; const { classPrefix } = useConfig(); @@ -141,6 +141,6 @@ const Indexes: FC = forwardRef((props) => {
); -}); +}; export default Indexes; diff --git a/src/input/Input.tsx b/src/input/Input.tsx index ba71a22d..b18c157a 100644 --- a/src/input/Input.tsx +++ b/src/input/Input.tsx @@ -1,172 +1,224 @@ -import React, { FC, forwardRef, useRef } from 'react'; -import { CloseCircleFilledIcon } from 'tdesign-icons-react'; -import isFunction from 'lodash/isFunction'; +import React, { forwardRef, useEffect, useImperativeHandle, useRef, useState } from 'react'; +import type { FocusEvent, TouchEvent, CompositionEvent, FormEvent } from 'react'; import classNames from 'classnames'; +import { CloseCircleFilledIcon, BrowseOffIcon, BrowseIcon } from 'tdesign-icons-react'; +import useDefault from 'tdesign-mobile-react/_util/useDefault'; +import parseTNode from 'tdesign-mobile-react/_util/parseTNode'; +import { inputDefaultProps } from './defaultProps'; import { getCharacterLength } from '../_common/js/utils/helper'; -import { TdInputProps } from './type'; import useConfig from '../_util/useConfig'; +import useDefaultProps from '../hooks/useDefaultProps'; +import { TdInputProps } from './type'; +import withNativeProps, { NativeProps } from '../_util/withNativeProps'; -export interface InputProps extends TdInputProps { +export interface InputProps extends TdInputProps, NativeProps { required?: boolean; readonly?: boolean; } -const Input: FC = forwardRef((props, ref) => { +export interface InputRefProps { + focus?: () => void; + blur?: () => void; +} + +const Input = forwardRef((props, ref) => { const { - align = 'left', - autofocus = false, - clearable = false, - disabled = false, - errorMessage = '', - label = '', - maxcharacter = 0, // 半成品 - maxlength = 0, - vertical = false, - name = '', - placeholder = '', + align, + autofocus, + autocomplete, + borderless, + clearable, + clearTrigger, + disabled, + label, + layout, + maxlength, + name, + placeholder, prefixIcon, - // size = 'small', suffix, suffixIcon, - type = 'text', - value = '', - className = '', - defaultValue, - required = false, - readonly = false, + tips, + type, + readonly, onBlur, - onChange, onClear, - onEnter, onFocus, - } = props; + value, + defaultValue, + onChange, + } = useDefaultProps(props, inputDefaultProps); + const [showClear, setShowClear] = useState(false); + const [innerValue, setInnerValue] = useDefault(value, defaultValue, onChange); + const [renderType, setRenderType] = useState(type); + const inputRef = useRef(null); + const focused = useRef(false); + const status = props.status || 'default'; const { classPrefix } = useConfig(); - const prefix = classPrefix; + const rootClassName = `${classPrefix}-input`; + const inputClasses = classNames(`${rootClassName}__control`, { + [`${rootClassName}--${align}`]: align !== 'left', + [`${rootClassName}--${status}`]: status, + [`${rootClassName}__control--disabled`]: disabled, + }); + const rootClasses = classNames(`${rootClassName}`, { + [`${rootClassName}--layout-${layout}`]: layout, + [`${rootClassName}--border`]: borderless, + }); + const resultMaxLength = !isNaN(+maxlength) ? +maxlength : -1; - const compositionRef = useRef(false); + useImperativeHandle(ref, () => ({ + focus, + blur, + })); - function handleChange(e: React.ChangeEvent | React.CompositionEvent) { - let { value } = e.currentTarget; - if (maxcharacter !== 0 && !compositionRef.current) { - const res = getCharacterLength(value, maxcharacter) as { - length: number; - characters: string; - }; - value = res.characters; + useEffect(() => { + const computeShowClear = () => { + if (disabled || readonly) { + return false; + } + if (clearable) { + return clearTrigger === 'always' || (clearTrigger === 'focus' && focused.current); + } + return false; + }; + setShowClear(computeShowClear()); + }, [clearTrigger, clearable, disabled, readonly]); + + useEffect(() => { + if (autofocus) { + focus(); } - isFunction(onChange) && !readonly && onChange(value, { e }); + }, [autofocus]); + + useEffect(() => { + setRenderType(type); + }, [type]); + + function focus() { + focused.current = true; + inputRef.current?.focus(); } - function handleBlur(e: React.FocusEvent) { - const { value } = e.currentTarget; - isFunction(onBlur) && onBlur(value, { e }); + function blur() { + focused.current = false; + inputRef.current?.blur(); } - function handleEnter(e: React.KeyboardEvent) { - if (e.keyCode === 13 || e.key === 'Enter' || e.charCode === 13 || e.which === 13) { - const { value } = e.currentTarget; - isFunction(onEnter) && onEnter(value, { e }); + const inputValueChangeHandle = (e: FormEvent) => { + const { value } = e.target as HTMLInputElement; + const { allowInputOverMax, maxcharacter } = props; + if (!allowInputOverMax && maxcharacter && !Number.isNaN(maxcharacter)) { + const { characters } = getCharacterLength(value, maxcharacter) as { + length: number; + characters: string; + }; + setInnerValue(characters); + } else { + setInnerValue(value); } - } + }; - function handleFocus(e: React.FocusEvent) { - const { value } = e.currentTarget; - isFunction(onFocus) && onFocus(value, { e }); - } + const handleInput = (e: FormEvent) => { + // 中文输入的时候inputType是insertCompositionText所以中文输入的时候禁止触发。 + if (e instanceof InputEvent) { + const checkInputType = e.inputType && e.inputType === 'insertCompositionText'; + if (e.isComposing || checkInputType) return; + } + inputValueChangeHandle(e); + }; - function handleClear(e: React.MouseEvent) { - isFunction(onChange) && !readonly && onChange(''); - isFunction(onClear) && onClear({ e }); - } + const handleClear = (e: TouchEvent) => { + e.preventDefault(); + setInnerValue(''); + focus(); + onClear?.({ e: e as TouchEvent }); + }; - const inputProps: any = {}; - if (maxlength > 0) { - inputProps.maxLength = maxlength; - } - if (defaultValue !== undefined) { - inputProps.defaultValue = defaultValue; - } - if (isFunction(onBlur)) { - inputProps.onBlur = handleBlur; - } - if (isFunction(onEnter)) { - inputProps.onKeyPress = handleEnter; - } - if (isFunction(onFocus)) { - inputProps.onFocus = handleFocus; - } + const handleFocus = (e: FocusEvent) => { + focused.current = true; + onFocus?.(innerValue, { e: e as FocusEvent }); + }; - return ( -
-
-
- {prefixIcon ? prefixIcon : <>} -
- {label && ( -
-
{label}
- {required &&  *} -
- )} + const handleBlur = (e: FocusEvent) => { + focused.current = false; + onBlur?.(innerValue, { e: e as FocusEvent }); + }; + + const handleCompositionend = (e: CompositionEvent) => { + inputValueChangeHandle(e as CompositionEvent); + }; + + const handlePwdIconClick = () => { + if (disabled) { + return; + } + setRenderType((renderType) => (renderType === 'password' ? 'text' : 'password')); + }; + + const renderPrefix = () => ( +
+ {prefixIcon ?
: null} +
{parseTNode(label)}
+
+ ); + + const renderClearable = () => + showClear ? ( +
+
-
-
-
- { - compositionRef.current = true; - }} - onCompositionEnd={(e) => { - compositionRef.current = false; - handleChange(e); - }} - ref={ref} - {...inputProps} - /> - {clearable && ( -
- -
- )} - {suffix &&
{suffix}
} -
- {errorMessage &&
{errorMessage}
} -
-
- {suffixIcon ? suffixIcon : <>} + ) : null; + + const renderSuffix = () => + suffix ?
{parseTNode(suffix)}
: null; + + const renderSuffixIcon = () => { + let tempSuffixIcon = suffixIcon; + if (type === 'password') { + if (renderType === 'password') { + tempSuffixIcon = ; + } else if (renderType === 'text') { + tempSuffixIcon = ; + } + } + return suffixIcon ?
{tempSuffixIcon}
: null; + }; + + const renderTips = () => + tips ?
{parseTNode(tips)}
: null; + + return withNativeProps( + props, +
+ {renderPrefix()} +
+
+ + {renderClearable()} + {renderSuffix()} + {renderSuffixIcon()}
+ {renderTips()}
-
+
, ); }); diff --git a/src/input/_example/align.jsx b/src/input/_example/align.jsx deleted file mode 100644 index d6208344..00000000 --- a/src/input/_example/align.jsx +++ /dev/null @@ -1,45 +0,0 @@ -import React, { useState } from 'react'; -import { Input, CellGroup } from 'tdesign-mobile-react'; - -export default function Base() { - const [value1, setValue1] = useState(''); - const [value2, setValue2] = useState(''); - const [value3, setValue3] = useState(''); - - return ( - <> - - { - setValue1(value); - }} - /> - - - { - setValue2(value); - }} - /> - - - { - setValue3(value); - }} - /> - - - ); -} diff --git a/src/input/_example/align.tsx b/src/input/_example/align.tsx new file mode 100644 index 00000000..fbbff593 --- /dev/null +++ b/src/input/_example/align.tsx @@ -0,0 +1,12 @@ +import React from 'react'; +import { Input } from 'tdesign-mobile-react'; + +export default function Align() { + return ( + <> + + + + + ); +} diff --git a/src/input/_example/banner.tsx b/src/input/_example/banner.tsx new file mode 100644 index 00000000..fc35d8dd --- /dev/null +++ b/src/input/_example/banner.tsx @@ -0,0 +1,7 @@ +import React from 'react'; +import { Input } from 'tdesign-mobile-react'; +import './style/index.less'; + +export default function Banner() { + return ; +} diff --git a/src/input/_example/base.tsx b/src/input/_example/base.tsx new file mode 100644 index 00000000..5ed86881 --- /dev/null +++ b/src/input/_example/base.tsx @@ -0,0 +1,12 @@ +import React from 'react'; +import { Input } from 'tdesign-mobile-react'; + +export default function Base() { + return ( + <> + + + + + ); +} diff --git a/src/input/_example/bordered.tsx b/src/input/_example/bordered.tsx new file mode 100644 index 00000000..b689d5fc --- /dev/null +++ b/src/input/_example/bordered.tsx @@ -0,0 +1,15 @@ +import React from 'react'; +import { Input } from 'tdesign-mobile-react'; +import { ErrorCircleFilledIcon } from 'tdesign-icons-react'; +import './style/index.less'; + +export default function Bordered() { + return ( +
+
标签文字
+ + + +
+ ); +} diff --git a/src/input/_example/custom.tsx b/src/input/_example/custom.tsx new file mode 100644 index 00000000..589904f5 --- /dev/null +++ b/src/input/_example/custom.tsx @@ -0,0 +1,11 @@ +import React from 'react'; +import { Input } from 'tdesign-mobile-react'; +import './style/index.less'; + +export default function Custom() { + return ( +
+ +
+ ); +} diff --git a/src/input/_example/index.jsx b/src/input/_example/index.jsx index 77b41b62..b5544d64 100644 --- a/src/input/_example/index.jsx +++ b/src/input/_example/index.jsx @@ -1,10 +1,16 @@ import React from 'react'; -import TypeDemo from './type'; -import StatusDemo from './status'; -import SpecialDemo from './special'; -import SizeDemo from './size'; -import AlignDemo from './align'; -import LimitDemo from './limit'; +import BaseDemo from './base'; +import MaxLength from './maxLength'; +import Suffix from './suffix'; +import Prefix from './prefix'; +import Special from './special'; +import Status from './status'; +import LabelDemo from './label'; +import Align from './align'; +import Layout from './layout'; +import Banner from './banner'; +import Bordered from './bordered'; +import Custom from './custom'; import TDemoHeader from '../../../site/mobile/components/DemoHeader'; import TDemoBlock from '../../../site/mobile/components/DemoBlock'; import './style/index.less'; @@ -12,30 +18,45 @@ import './style/index.less'; export default function RadioDemo() { return (
- + - - + + - - - + + - - - + + - - - + + + + + - - + + + + + - - + + + + + + + + + + + + + +
); diff --git a/src/input/_example/label.tsx b/src/input/_example/label.tsx new file mode 100644 index 00000000..d8ab9134 --- /dev/null +++ b/src/input/_example/label.tsx @@ -0,0 +1,6 @@ +import React from 'react'; +import { Input } from 'tdesign-mobile-react'; + +export default function Label() { + return ; +} diff --git a/src/input/_example/layout.tsx b/src/input/_example/layout.tsx new file mode 100644 index 00000000..7adc5f96 --- /dev/null +++ b/src/input/_example/layout.tsx @@ -0,0 +1,11 @@ +import React from 'react'; +import { Input } from 'tdesign-mobile-react'; +import { ErrorCircleFilledIcon } from 'tdesign-icons-react'; + +export default function Layout() { + return ( + + + + ); +} diff --git a/src/input/_example/limit.jsx b/src/input/_example/limit.jsx deleted file mode 100644 index 4c8d1eba..00000000 --- a/src/input/_example/limit.jsx +++ /dev/null @@ -1,32 +0,0 @@ -import React, { useState } from 'react'; -import { Input, CellGroup } from 'tdesign-mobile-react'; - -export default function Base() { - const [value1, setValue1] = useState(''); - const [value2, setValue2] = useState(''); - - return ( - <> - - { - setValue1(value); - }} - /> - - - { - setValue2(value); - }} - /> - - - ); -} diff --git a/src/input/_example/maxLength.tsx b/src/input/_example/maxLength.tsx new file mode 100644 index 00000000..ba412d54 --- /dev/null +++ b/src/input/_example/maxLength.tsx @@ -0,0 +1,11 @@ +import React from 'react'; +import { Input } from 'tdesign-mobile-react'; + +export default function MaxLength() { + return ( + <> + + + + ); +} diff --git a/src/input/_example/prefix.tsx b/src/input/_example/prefix.tsx new file mode 100644 index 00000000..d0c6ff57 --- /dev/null +++ b/src/input/_example/prefix.tsx @@ -0,0 +1,12 @@ +import React from 'react'; +import { Input } from 'tdesign-mobile-react'; +import { AppIcon } from 'tdesign-icons-react'; + +export default function Prefix() { + return ( + <> + } /> + } /> + + ); +} diff --git a/src/input/_example/size.jsx b/src/input/_example/size.jsx deleted file mode 100644 index 7cc66279..00000000 --- a/src/input/_example/size.jsx +++ /dev/null @@ -1,33 +0,0 @@ -import React, { useState } from 'react'; -import { Input, CellGroup } from 'tdesign-mobile-react'; - -export default function Base() { - const [value1, setValue1] = useState(''); - const [value2, setValue2] = useState(''); - - return ( - <> - - { - setValue1(value); - }} - /> - - - { - setValue2(value); - }} - /> - - - ); -} diff --git a/src/input/_example/special.jsx b/src/input/_example/special.jsx deleted file mode 100644 index d5bd4af2..00000000 --- a/src/input/_example/special.jsx +++ /dev/null @@ -1,78 +0,0 @@ -import React, { useState } from 'react'; -import { Input, Button, CellGroup } from 'tdesign-mobile-react'; - -export default function Base() { - const [value1, setValue1] = useState('12132131'); - const [value2, setValue2] = useState(''); - const [value3, setValue3] = useState(''); - const [value4, setValue4] = useState(''); - const [value5, setValue5] = useState(''); - - return ( - <> - - { - setValue1(value); - }} - /> - - - { - setValue2(value); - }} - /> - - - - 发送验证码 - - } - value={value3} - onChange={(value) => { - setValue3(value); - }} - /> - - - { - setValue4(value); - }} - className="t-input-suffix-noseparate" - /> - - - { - setValue5(value); - }} - className="t-input-suffix-noseparate" - /> - - - ); -} diff --git a/src/input/_example/special.tsx b/src/input/_example/special.tsx new file mode 100644 index 00000000..8cde7654 --- /dev/null +++ b/src/input/_example/special.tsx @@ -0,0 +1,66 @@ +import React, { useEffect, useState } from 'react'; +import { Image, Input } from 'tdesign-mobile-react'; +import { BrowseOffIcon } from 'tdesign-icons-react'; +import './style/index.less'; + +export default function Special() { + const [phoneNumber, setPhoneNumber] = useState('17600600600'); + const [tips, setTips] = useState(''); + + useEffect(() => { + function isPhoneNumber() { + if (/^[1][3,4,5,7,8,9][0-9]{9}$/.test(phoneNumber)) { + return ''; + } + return 'error'; + } + + setTips(!isPhoneNumber() ? '手机号输入不正确' : ''); + }, [phoneNumber]); + + const handlePhoneNumberChange = (value) => { + setPhoneNumber(value); + }; + + return ( + <> + } + /> + +
+ +
+ } + /> + +
+
发送验证码
+
+ } + /> + + + + ); +} diff --git a/src/input/_example/status.jsx b/src/input/_example/status.jsx deleted file mode 100644 index e065990c..00000000 --- a/src/input/_example/status.jsx +++ /dev/null @@ -1,39 +0,0 @@ -import React, { useState } from 'react'; -import { Input, CellGroup } from 'tdesign-mobile-react'; - -export default function Base() { - const [value1, setValue1] = useState('请输入文字'); - const [value2, setValue2] = useState('一段错误填写的内容'); - const [value3, setValue3] = useState('不可编辑的内容'); - - return ( - - { - setValue1(value); - }} - /> - { - setValue2(value); - }} - /> - { - setValue3(value); - }} - /> - - ); -} diff --git a/src/input/_example/status.tsx b/src/input/_example/status.tsx new file mode 100644 index 00000000..274388df --- /dev/null +++ b/src/input/_example/status.tsx @@ -0,0 +1,13 @@ +import React from 'react'; +import { Input } from 'tdesign-mobile-react'; + +export default function Status() { + const text1 = '已输入文字'; + const text2 = '不可编辑文字'; + return ( + <> + + + + ); +} diff --git a/src/input/_example/style/index.less b/src/input/_example/style/index.less index d46b77e2..d353f61e 100644 --- a/src/input/_example/style/index.less +++ b/src/input/_example/style/index.less @@ -1,22 +1,62 @@ -.t-input-suffix-noseparate { - .t-input__wrap--suffix { - &::after { - border: none; - } - } +.t-input + .t-input { + margin-top: 16px; } -.t-cell-group + .t-cell-group { - margin-top: 16px; +.input-demo { + border-radius: 6px; + margin: 0 16px; } -.demo-group { - .t-cell-group + .t-cell-group { - margin-top: 0; - } +.input-bordered { + background-color: var(--bg-color-demo, #fff); + padding: 16px 16px 24px; + + --td-input-vertical-padding: 12px; - .t-cell-group__title { + &__summary { + color: var(--td-text-color-primary, rgba(0, 0, 0, 0.9)); font-size: 12px; line-height: 20px; + margin-bottom: 8px; + } + + &__input { + border: 1px solid rgba(220, 220, 220, 1); + border-radius: 6px; + } +} + +.input-custom { + padding-bottom: 48rpx; + + --td-input-bg-color: rgba(44, 44, 44, 1); + --td-input-border-color: rgba(75, 75, 75, 1); + --td-input-default-text-color: rgba(255, 255, 255, 1); + --td-input-placeholder-text-color: rgba(255, 255, 255, 0.35); + --td-input-label-text-color: rgba(255, 255, 255, 1); +} + +.input-suffix { + display: flex; + align-items: center; + + &__line { + width: 1px; + height: 24px; + background-color: #f6f6f6; + margin-right: 16px; + } + + &__image { + width: 72px; + height: 36px; + display: block; + margin-top: -6px; + margin-bottom: -6px; + } + + &__verify { + color: rgba(0, 82, 217, 1); + font-size: 16px; } } diff --git a/src/input/_example/suffix.tsx b/src/input/_example/suffix.tsx new file mode 100644 index 00000000..d3c0dd05 --- /dev/null +++ b/src/input/_example/suffix.tsx @@ -0,0 +1,21 @@ +import React from 'react'; +import { Button, Input } from 'tdesign-mobile-react'; +import { InfoCircleFilledIcon, UserAvatarIcon } from 'tdesign-icons-react'; + +export default function Suffix() { + return ( + <> + } /> + + {' 操作按钮 '} + + } + /> + } /> + + ); +} diff --git a/src/input/_example/type.jsx b/src/input/_example/type.jsx deleted file mode 100644 index a64c0930..00000000 --- a/src/input/_example/type.jsx +++ /dev/null @@ -1,80 +0,0 @@ -import React, { useState } from 'react'; -import { InfoCircleFilledIcon } from 'tdesign-icons-react'; -import { Input, CellGroup } from 'tdesign-mobile-react'; - -export default function Base() { - const [value1, setValue1] = useState(''); - const [value2, setValue2] = useState(''); - const [value3, setValue3] = useState(''); - const [value4, setValue4] = useState(''); - const [value5, setValue5] = useState(''); - const [value6, setValue6] = useState(''); - - return ( -
- - { - setValue1(value); - }} - /> - - - - { - setValue2(value); - }} - /> - { - setValue3(value); - }} - /> - - - - { - setValue4(value); - }} - /> - - - - } - value={value5} - onChange={(value) => { - setValue5(value); - }} - /> - - - - { - setValue6(value); - }} - /> - -
- ); -} diff --git a/src/input/defaultProps.ts b/src/input/defaultProps.ts new file mode 100644 index 00000000..cde7ff7b --- /dev/null +++ b/src/input/defaultProps.ts @@ -0,0 +1,21 @@ +/** + * 该文件为脚本自动生成文件,请勿随意修改。如需修改请联系 PMC + * */ + +import { TdInputProps } from './type'; + +export const inputDefaultProps: TdInputProps = { + align: 'left', + allowInputOverMax: false, + autocomplete: undefined, + autofocus: false, + borderless: false, + clearTrigger: 'always', + clearable: false, + disabled: undefined, + layout: 'horizontal', + placeholder: undefined, + readonly: undefined, + status: undefined, + type: 'text', +}; diff --git a/src/input/input.en-US.md b/src/input/input.en-US.md new file mode 100644 index 00000000..b17e7a32 --- /dev/null +++ b/src/input/input.en-US.md @@ -0,0 +1,41 @@ +:: BASE_DOC :: + +## API + +### Input Props + +name | type | default | description | required +-- | -- | -- | -- | -- +className | String | - | className of component | N +style | Object | - | CSS(Cascading Style Sheets),Typescript:`React.CSSProperties` | N +align | String | left | text align type。options: left/center/right | N +allowInputOverMax | Boolean | false | allow to continue input on value length is over `maxlength` or `maxcharacter` | N +autocomplete | String | undefined | attribute of input element, [see here](https://developer.mozilla.org/en-US/docs/Web/HTML/Attributes/autocomplete) | N +autofocus | Boolean | false | autofocus on first rendered | N +borderless | Boolean | false | input without border | N +clearTrigger | String | always | show clear icon, clicked to clear input value。options: always / focus | N +clearable | Boolean | false | show clear icon, clicked to clear input value | N +disabled | Boolean | undefined | make input to be disabled | N +errorMessage | String | - | `deprecated` | N +format | Function | - | input value formatter, `type=number` does not work. if you need to format number, `InputNumber` Component might be better。Typescript:`InputFormatType` `type InputFormatType = (value: InputValue) => string`。[see more ts definition](https://github.com/Tencent/tdesign-mobile-react/tree/develop/src/input/type.ts) | N +label | TNode | - | text on the left of input。Typescript:`string \| TNode`。[see more ts definition](https://github.com/Tencent/tdesign-mobile-react/blob/develop/src/common.ts) | N +layout | String | horizontal | options: vertical/horizontal | N +maxcharacter | Number | - | \- | N +maxlength | String / Number | - | \- | N +name | String | - | \- | N +placeholder | String | undefined | \- | N +prefixIcon | TElement | - | Typescript:`TNode`。[see more ts definition](https://github.com/Tencent/tdesign-mobile-react/blob/develop/src/common.ts) | N +readonly | Boolean | undefined | \- | N +size | String | medium | `deprecated`。options: small/medium。Typescript:`'medium' \| 'small'` | N +status | String | undefined | options: default/success/warning/error | N +suffix | TNode | - | suffix content before suffixIcon。Typescript:`string \| TNode`。[see more ts definition](https://github.com/Tencent/tdesign-mobile-react/blob/develop/src/common.ts) | N +suffixIcon | TElement | - | suffix icon of input。Typescript:`TNode`。[see more ts definition](https://github.com/Tencent/tdesign-mobile-react/blob/develop/src/common.ts) | N +tips | TNode | - | tips on the bottom of input, different `status` can make tips to be different color。Typescript:`string \| TNode`。[see more ts definition](https://github.com/Tencent/tdesign-mobile-react/blob/develop/src/common.ts) | N +type | String | text | type attribute of input element. if you are using `type=number`, `InputNumber` Component might be better。options: text/number/url/tel/password/search/submit/hidden | N +value | String / Number | - | input value。Typescript:`InputValue` `type InputValue = string \| number`。[see more ts definition](https://github.com/Tencent/tdesign-mobile-react/tree/develop/src/input/type.ts) | N +defaultValue | String / Number | - | input value。uncontrolled property。Typescript:`InputValue` `type InputValue = string \| number`。[see more ts definition](https://github.com/Tencent/tdesign-mobile-react/tree/develop/src/input/type.ts) | N +onBlur | Function | | Typescript:`(value: InputValue, context: { e: FocusEvent }) => void`
| N +onChange | Function | | Typescript:`(value: InputValue, context?: { e?: InputEvent \| MouseEvent \| CompositionEvent; trigger: 'input' \| 'initial' \| 'clear' }) => void`
trigger on input value changed | N +onClear | Function | | Typescript:`(context: { e: TouchEvent }) => void`
| N +onFocus | Function | | Typescript:`(value: InputValue, context: { e: FocusEvent }) => void`
| N +onValidate | Function | | Typescript:`(context: { error?: 'exceed-maximum' \| 'below-minimum' }) => void`
trigger on text length being over max length or max character | N diff --git a/src/input/input.md b/src/input/input.md index ce4a5a8e..8d54c489 100644 --- a/src/input/input.md +++ b/src/input/input.md @@ -4,29 +4,38 @@ ### Input Props -名称 | 类型 | 默认值 | 说明 | 必传 +名称 | 类型 | 默认值 | 描述 | 必传 -- | -- | -- | -- | -- className | String | - | 类名 | N style | Object | - | 样式,TS 类型:`React.CSSProperties` | N align | String | left | 文本内容位置,居左/居中/居右。可选项:left/center/right | N +allowInputOverMax | Boolean | false | 超出 `maxlength` 或 `maxcharacter` 之后是否允许继续输入 | N +autocomplete | String | undefined | 是否开启自动填充功能,HTML5 原生属性,[点击查看详情](https://developer.mozilla.org/en-US/docs/Web/HTML/Attributes/autocomplete) | N autofocus | Boolean | false | 自动聚焦 | N +borderless | Boolean | false | 是否开启无边框模式 | N +clearTrigger | String | always | 清空图标触发方式,仅在输入框有值时有效。可选项:always / focus | N clearable | Boolean | false | 是否可清空 | N -disabled | Boolean | false | 是否禁用输入框 | N -errorMessage | String | - | 错误提示文本,值为空不显示 | N -label | TNode | - | 左侧文本。TS 类型:`string | TNode`。[通用类型定义](https://github.com/Tencent/tdesign-mobile-react/blob/develop/src/common.ts) | N +disabled | Boolean | undefined | 是否禁用输入框 | N +errorMessage | String | - | 已废弃。错误提示文本,值为空不显示(废弃属性,如果需要,请更为使用 status 和 tips) | N +format | Function | - | 【开发中】指定输入框展示值的格式。TS 类型:`InputFormatType` `type InputFormatType = (value: InputValue) => string`。[详细类型定义](https://github.com/Tencent/tdesign-mobile-react/tree/develop/src/input/type.ts) | N +label | TNode | - | 左侧文本。TS 类型:`string \| TNode`。[通用类型定义](https://github.com/Tencent/tdesign-mobile-react/blob/develop/src/common.ts) | N +layout | String | horizontal | 标题输入框布局方式。可选项:vertical/horizontal | N maxcharacter | Number | - | 用户最多可以输入的字符个数,一个中文汉字表示两个字符长度。`maxcharacter` 和 `maxlength` 二选一使用 | N -maxlength | Number | - | 用户最多可以输入的文本长度。值小于等于 0 的时候,则不限制输入长度。`maxcharacter` 和 `maxlength` 二选一使用 | N +maxlength | String / Number | - | 用户最多可以输入的文本长度,一个中文等于一个计数长度。默认为空,不限制输入长度。`maxcharacter` 和 `maxlength` 二选一使用 | N name | String | - | 名称 | N placeholder | String | undefined | 占位符 | N prefixIcon | TElement | - | 组件前置图标。TS 类型:`TNode`。[通用类型定义](https://github.com/Tencent/tdesign-mobile-react/blob/develop/src/common.ts) | N -size | String | small | 输入框尺寸。可选项:small/medium。TS 类型:`'medium' | 'small'` | N -suffix | TNode | - | 后置图标前的后置内容。TS 类型:`string | TNode`。[通用类型定义](https://github.com/Tencent/tdesign-mobile-react/blob/develop/src/common.ts) | N +readonly | Boolean | undefined | 只读状态 | N +size | String | medium | 已废弃。输入框尺寸。可选项:small/medium。TS 类型:`'medium' \| 'small'` | N +status | String | undefined | 输入框状态。默认情况会由组件内部根据实际情况呈现,如果文本过长引起的状态变化。可选项:default/success/warning/error | N +suffix | TNode | - | 后置图标前的后置内容。TS 类型:`string \| TNode`。[通用类型定义](https://github.com/Tencent/tdesign-mobile-react/blob/develop/src/common.ts) | N suffixIcon | TElement | - | 组件后置图标。TS 类型:`TNode`。[通用类型定义](https://github.com/Tencent/tdesign-mobile-react/blob/develop/src/common.ts) | N +tips | TNode | - | 输入框下方提示文本,会根据不同的 `status` 呈现不同的样式。TS 类型:`string \| TNode`。[通用类型定义](https://github.com/Tencent/tdesign-mobile-react/blob/develop/src/common.ts) | N type | String | text | 输入框类型。可选项:text/number/url/tel/password/search/submit/hidden | N -value | String / Number | - | 输入框的值。TS 类型:`InputValue`。[详细类型定义](https://github.com/Tencent/tdesign-mobile-react/tree/develop/src/input/type.ts) | N -defaultValue | String / Number | - | 输入框的值。非受控属性。TS 类型:`InputValue`。[详细类型定义](https://github.com/Tencent/tdesign-mobile-react/tree/develop/src/input/type.ts) | N +value | String / Number | - | 输入框的值。TS 类型:`InputValue` `type InputValue = string \| number`。[详细类型定义](https://github.com/Tencent/tdesign-mobile-react/tree/develop/src/input/type.ts) | N +defaultValue | String / Number | - | 输入框的值。非受控属性。TS 类型:`InputValue` `type InputValue = string \| number`。[详细类型定义](https://github.com/Tencent/tdesign-mobile-react/tree/develop/src/input/type.ts) | N onBlur | Function | | TS 类型:`(value: InputValue, context: { e: FocusEvent }) => void`
失去焦点时触发 | N -onChange | Function | | TS 类型:`(value: InputValue, context?: { e?: InputEvent | MouseEvent }) => void`
输入框值发生变化时触发 | N -onClear | Function | | TS 类型:`(context: { e: MouseEvent }) => void`
清空按钮点击时触发 | N -onEnter | Function | | TS 类型:`(value: InputValue, context: { e: KeyboardEvent }) => void`
回车键按下时触发 | N +onChange | Function | | TS 类型:`(value: InputValue, context?: { e?: InputEvent \| MouseEvent \| CompositionEvent; trigger: 'input' \| 'initial' \| 'clear' }) => void`
输入框值发生变化时触发。`trigger=initial` 表示传入的数据不符合预期,组件自动处理后触发 change 告知父组件。如:初始值长度超过 `maxlength` 限制 | N +onClear | Function | | TS 类型:`(context: { e: TouchEvent }) => void`
清空按钮点击时触发 | N onFocus | Function | | TS 类型:`(value: InputValue, context: { e: FocusEvent }) => void`
获得焦点时触发 | N +onValidate | Function | | TS 类型:`(context: { error?: 'exceed-maximum' \| 'below-minimum' }) => void`
字数超出限制时触发 | N diff --git a/src/input/style/index.js b/src/input/style/index.js index 941dda0a..1b672ef0 100644 --- a/src/input/style/index.js +++ b/src/input/style/index.js @@ -1 +1 @@ -import '../../_common/style/mobile/components/input/_index.less'; +import '../../_common/style/mobile/components/input/v2/_index.less'; diff --git a/src/input/type.ts b/src/input/type.ts index 6df26046..fd81e396 100644 --- a/src/input/type.ts +++ b/src/input/type.ts @@ -5,7 +5,7 @@ * */ import { TNode, TElement } from '../common'; -import { MouseEvent, KeyboardEvent, FocusEvent, FormEvent } from 'react'; +import { MouseEvent, FocusEvent, FormEvent, CompositionEvent, TouchEvent } from 'react'; export interface TdInputProps { /** @@ -13,11 +13,30 @@ export interface TdInputProps { * @default left */ align?: 'left' | 'center' | 'right'; + /** + * 超出 `maxlength` 或 `maxcharacter` 之后是否允许继续输入 + * @default false + */ + allowInputOverMax?: boolean; + /** + * 是否开启自动填充功能,HTML5 原生属性,[点击查看详情](https://developer.mozilla.org/en-US/docs/Web/HTML/Attributes/autocomplete) + */ + autocomplete?: string; /** * 自动聚焦 * @default false */ autofocus?: boolean; + /** + * 是否开启无边框模式 + * @default false + */ + borderless?: boolean; + /** + * 清空图标触发方式,仅在输入框有值时有效 + * @default always + */ + clearTrigger?: 'always' | 'focus'; /** * 是否可清空 * @default false @@ -25,26 +44,29 @@ export interface TdInputProps { clearable?: boolean; /** * 是否禁用输入框 - * @default false */ disabled?: boolean; /** - * 错误提示文本,值为空不显示 - * @default '' + * 【开发中】指定输入框展示值的格式 */ - errorMessage?: string; + format?: InputFormatType; /** * 左侧文本 */ label?: TNode; + /** + * 标题输入框布局方式 + * @default horizontal + */ + layout?: 'vertical' | 'horizontal'; /** * 用户最多可以输入的字符个数,一个中文汉字表示两个字符长度。`maxcharacter` 和 `maxlength` 二选一使用 */ maxcharacter?: number; /** - * 用户最多可以输入的文本长度。值小于等于 0 的时候,则不限制输入长度。`maxcharacter` 和 `maxlength` 二选一使用 + * 用户最多可以输入的文本长度,一个中文等于一个计数长度。默认为空,不限制输入长度。`maxcharacter` 和 `maxlength` 二选一使用 */ - maxlength?: number; + maxlength?: string | number; /** * 名称 * @default '' @@ -59,10 +81,13 @@ export interface TdInputProps { */ prefixIcon?: TElement; /** - * 输入框尺寸 - * @default small + * 只读状态 */ - size?: 'medium' | 'small'; + readonly?: boolean; + /** + * 输入框状态。默认情况会由组件内部根据实际情况呈现,如果文本过长引起的状态变化 + */ + status?: 'default' | 'success' | 'warning' | 'error'; /** * 后置图标前的后置内容 */ @@ -71,17 +96,15 @@ export interface TdInputProps { * 组件后置图标 */ suffixIcon?: TElement; + /** + * 输入框下方提示文本,会根据不同的 `status` 呈现不同的样式 + */ + tips?: TNode; /** * 输入框类型 * @default text */ type?: 'text' | 'number' | 'url' | 'tel' | 'password' | 'search' | 'submit' | 'hidden'; - /** - * 是否垂直显示 - * @default false - */ - vertical?: boolean; - /** * 输入框的值 */ @@ -90,34 +113,34 @@ export interface TdInputProps { * 输入框的值,非受控属性 */ defaultValue?: InputValue; - /** - * 传入的class - * @default "" - */ - className?: string; /** * 失去焦点时触发 */ onBlur?: (value: InputValue, context: { e: FocusEvent }) => void; /** - * 输入框值发生变化时触发 + * 输入框值发生变化时触发。`trigger=initial` 表示传入的数据不符合预期,组件自动处理后触发 change 告知父组件。如:初始值长度超过 `maxlength` 限制 */ onChange?: ( value: InputValue, - context?: { e?: FormEvent | MouseEvent }, + context?: { + e?: FormEvent | MouseEvent | CompositionEvent; + trigger: 'input' | 'initial' | 'clear'; + }, ) => void; /** * 清空按钮点击时触发 */ - onClear?: (context: { e: MouseEvent }) => void; - /** - * 回车键按下时触发 - */ - onEnter?: (value: InputValue, context: { e: KeyboardEvent }) => void; + onClear?: (context: { e: TouchEvent }) => void; /** * 获得焦点时触发 */ onFocus?: (value: InputValue, context: { e: FocusEvent }) => void; + /** + * 字数超出限制时触发 + */ + onValidate?: (context: { error?: 'exceed-maximum' | 'below-minimum' }) => void; } +export type InputFormatType = (value: InputValue) => string; + export type InputValue = string | number; diff --git a/src/link/Link.tsx b/src/link/Link.tsx new file mode 100644 index 00000000..425c9290 --- /dev/null +++ b/src/link/Link.tsx @@ -0,0 +1,67 @@ +import classNames from 'classnames'; +import React from 'react'; +import useConfig from '../_util/useConfig'; +import { TdLinkProps } from './type'; +import { StyledProps } from '../common'; +import parseTNode from '../_util/parseTNode'; +import useDefaultProps from '../hooks/useDefaultProps'; +import { linkDefaultProps } from './defaultProps'; + +export interface LinkProps extends TdLinkProps, StyledProps {} + +const Link = React.forwardRef((props, ref) => { + const { + children, + content, + className, + underline, + prefixIcon, + suffixIcon, + theme, + disabled, + hover, + onClick, + href, + size, + ...otherProps + } = useDefaultProps(props, linkDefaultProps); + + const { classPrefix } = useConfig(); + + const childNode = content || children; + + const handleClick = (e: React.MouseEvent) => { + if (disabled) { + return; + } + onClick?.(e); + }; + + return ( + + {prefixIcon && {parseTNode(prefixIcon)}} + {childNode && {parseTNode(childNode)}} + {suffixIcon && {parseTNode(suffixIcon)}} + + ); +}); + +Link.displayName = 'Link'; + +export default Link; diff --git a/src/link/_example/base.tsx b/src/link/_example/base.tsx new file mode 100644 index 00000000..8b1341cd --- /dev/null +++ b/src/link/_example/base.tsx @@ -0,0 +1,13 @@ +import React from 'react'; +import { Link } from 'tdesign-mobile-react'; + +import './style/index.less'; + +export default function Base() { + return ( +
+ 跳转链接 + 跳转链接 +
+ ); +} diff --git a/src/link/_example/index.tsx b/src/link/_example/index.tsx new file mode 100644 index 00000000..88a10704 --- /dev/null +++ b/src/link/_example/index.tsx @@ -0,0 +1,41 @@ +import React from 'react'; +import TDemoBlock from '../../../site/mobile/components/DemoBlock'; +import TDemoHeader from '../../../site/mobile/components/DemoHeader'; +import BaseDemo from './base'; +import ThemeDemo from './theme'; +import SizeDemo from './linkSize'; +import UnderlineDemo from './underline'; +import PrefixDemo from './prefix'; +import SuffixDemo from './suffix'; +import StatusDemo from './status'; + +import './style/index.less'; + +export default function LinkDemo() { + return ( +
+ + + + + + + + + + + + + + + + + + + + + + +
+ ); +} diff --git a/src/link/_example/linkSize.tsx b/src/link/_example/linkSize.tsx new file mode 100644 index 00000000..f0a77530 --- /dev/null +++ b/src/link/_example/linkSize.tsx @@ -0,0 +1,18 @@ +import React from 'react'; +import { Link } from 'tdesign-mobile-react'; + +export default function Size() { + return ( +
+ + S跳转链接 + + + M跳转链接 + + + L跳转链接 + +
+ ); +} diff --git a/src/link/_example/prefix.tsx b/src/link/_example/prefix.tsx new file mode 100644 index 00000000..7a1a617f --- /dev/null +++ b/src/link/_example/prefix.tsx @@ -0,0 +1,16 @@ +import React from 'react'; +import { LinkIcon } from 'tdesign-icons-react'; +import { Link } from 'tdesign-mobile-react'; + +export default function Prefix() { + return ( +
+ }> + 跳转链接 + + }> + 跳转链接 + +
+ ); +} diff --git a/src/link/_example/status.tsx b/src/link/_example/status.tsx new file mode 100644 index 00000000..303b4c46 --- /dev/null +++ b/src/link/_example/status.tsx @@ -0,0 +1,31 @@ +import React from 'react'; +import { Link } from 'tdesign-mobile-react'; +import { JumpIcon } from 'tdesign-icons-react'; + +import './style/index.less'; + +export default function Status() { + return ( + <> +
+ } disabled> + 跳转链接 + + } disabled> + 跳转链接 + + } disabled> + 跳转链接 + +
+
+ } disabled> + 跳转链接 + + } disabled> + 跳转链接 + +
+ + ); +} diff --git a/src/link/_example/style/index.less b/src/link/_example/style/index.less new file mode 100644 index 00000000..bcb05463 --- /dev/null +++ b/src/link/_example/style/index.less @@ -0,0 +1,8 @@ +.demo-content { + height: 48px; + background-color: var(--bg-color-demo, #fff); + display: flex; + justify-content: space-around; + margin-bottom: 6.4vw; + align-items: center; +} diff --git a/src/link/_example/suffix.tsx b/src/link/_example/suffix.tsx new file mode 100644 index 00000000..e0b2e7cc --- /dev/null +++ b/src/link/_example/suffix.tsx @@ -0,0 +1,16 @@ +import React from 'react'; +import { JumpIcon } from 'tdesign-icons-react'; +import { Link } from 'tdesign-mobile-react'; + +export default function Suffix() { + return ( +
+ }> + 跳转链接 + + }> + 跳转链接 + +
+ ); +} diff --git a/src/link/_example/theme.tsx b/src/link/_example/theme.tsx new file mode 100644 index 00000000..5028e8ba --- /dev/null +++ b/src/link/_example/theme.tsx @@ -0,0 +1,29 @@ +import React from 'react'; +import { Link } from 'tdesign-mobile-react'; +import { JumpIcon } from 'tdesign-icons-react'; + +import './style/index.less'; + +export default function Theme() { + return ( + <> +
+ }> + 跳转链接 + + }>跳转链接 + }> + 跳转链接 + +
+
+ }> + 跳转链接 + + }> + 跳转链接 + +
+ + ); +} diff --git a/src/link/_example/underline.tsx b/src/link/_example/underline.tsx new file mode 100644 index 00000000..d53b79d1 --- /dev/null +++ b/src/link/_example/underline.tsx @@ -0,0 +1,15 @@ +import React from 'react'; +import { Link } from 'tdesign-mobile-react'; + +export default function Underline() { + return ( +
+ + 跳转链接 + + + 跳转链接 + +
+ ); +} diff --git a/src/link/defaultProps.ts b/src/link/defaultProps.ts new file mode 100755 index 00000000..940972e1 --- /dev/null +++ b/src/link/defaultProps.ts @@ -0,0 +1,7 @@ +/** + * 该文件为脚本自动生成文件,请勿随意修改。如需修改请联系 PMC + * */ + +import { TdLinkProps } from './type'; + +export const linkDefaultProps: TdLinkProps = { disabled: undefined, size: 'medium', theme: 'default' }; diff --git a/src/link/index.ts b/src/link/index.ts new file mode 100644 index 00000000..982e5c1e --- /dev/null +++ b/src/link/index.ts @@ -0,0 +1,8 @@ +import _Link from './Link'; + +import './style/index.js'; + +export type { LinkProps } from './Link'; + +export const Link = _Link; +export default Link; diff --git a/src/link/link.en-US.md b/src/link/link.en-US.md new file mode 100644 index 00000000..ada84f8d --- /dev/null +++ b/src/link/link.en-US.md @@ -0,0 +1,23 @@ +:: BASE_DOC :: + +## API + + +### Link Props + +name | type | default | description | required +-- | -- | -- | -- | -- +className | String | - | className of component | N +style | Object | - | CSS(Cascading Style Sheets),Typescript:`React.CSSProperties` | N +children | TNode | - | Typescript:`string \| TNode`。[see more ts definition](https://github.com/Tencent/tdesign-react/blob/develop/src/common.ts) | N +content | TNode | - | Typescript:`string \| TNode`。[see more ts definition](https://github.com/Tencent/tdesign-mobile-react/blob/develop/src/common.ts) | N +disabled | Boolean | undefined | make link to be disabled | N +hover | Boolean | - | \- | N +href | String | - | \- | N +prefixIcon | TElement | - | Typescript:`TNode`。[see more ts definition](https://github.com/Tencent/tdesign-mobile-react/blob/develop/src/common.ts) | N +size | String | medium | options: small/medium/large。Typescript:`SizeEnum`。[see more ts definition](https://github.com/Tencent/tdesign-mobile-react/blob/develop/src/common.ts) | N +suffixIcon | TElement | - | Typescript:`TNode`。[see more ts definition](https://github.com/Tencent/tdesign-mobile-react/blob/develop/src/common.ts) | N +target | String | - | target is an attribute of `` | N +theme | String | default | options: default/primary/danger/warning/success | N +underline | Boolean | - | \- | N +onClick | Function | | Typescript:`(e: MouseEvent) => void`
click event, it won't trigger when it's disabled | N diff --git a/src/link/link.md b/src/link/link.md new file mode 100644 index 00000000..f3883768 --- /dev/null +++ b/src/link/link.md @@ -0,0 +1,23 @@ +:: BASE_DOC :: + +## API + + +### Link Props + +名称 | 类型 | 默认值 | 描述 | 必传 +-- | -- | -- | -- | -- +className | String | - | 类名 | N +style | Object | - | 样式,TS 类型:`React.CSSProperties` | N +children | TNode | - | 链接内容,同 content。TS 类型:`string \| TNode`。[通用类型定义](https://github.com/Tencent/tdesign-react/blob/develop/src/common.ts) | N +content | TNode | - | 链接内容。TS 类型:`string \| TNode`。[通用类型定义](https://github.com/Tencent/tdesign-mobile-react/blob/develop/src/common.ts) | N +disabled | Boolean | undefined | 禁用链接。优先级:Link.disabled > Form.disabled | N +hover | Boolean | - | 是否开启点击反馈 | N +href | String | - | 跳转链接 | N +prefixIcon | TElement | - | 前置图标。TS 类型:`TNode`。[通用类型定义](https://github.com/Tencent/tdesign-mobile-react/blob/develop/src/common.ts) | N +size | String | medium | 尺寸。可选项:small/medium/large。TS 类型:`SizeEnum`。[通用类型定义](https://github.com/Tencent/tdesign-mobile-react/blob/develop/src/common.ts) | N +suffixIcon | TElement | - | 后置图标。TS 类型:`TNode`。[通用类型定义](https://github.com/Tencent/tdesign-mobile-react/blob/develop/src/common.ts) | N +target | String | - | 跳转方式,如:当前页面打开、新页面打开等,同 HTML 属性 target 含义相同 | N +theme | String | default | 组件风格,依次为默认色、品牌色、危险色、警告色、成功色。可选项:default/primary/danger/warning/success | N +underline | Boolean | - | 是否显示链接下划线 | N +onClick | Function | | TS 类型:`(e: MouseEvent) => void`
点击事件,禁用状态不会触发点击事件 | N diff --git a/src/link/style/css.js b/src/link/style/css.js new file mode 100644 index 00000000..6a9a4b13 --- /dev/null +++ b/src/link/style/css.js @@ -0,0 +1 @@ +import './index.css'; diff --git a/src/link/style/index.js b/src/link/style/index.js new file mode 100644 index 00000000..7da1071d --- /dev/null +++ b/src/link/style/index.js @@ -0,0 +1 @@ +import '../../_common/style/mobile/components/link/v2/_index.less'; diff --git a/src/link/type.ts b/src/link/type.ts new file mode 100644 index 00000000..d271ce24 --- /dev/null +++ b/src/link/type.ts @@ -0,0 +1,63 @@ +/* eslint-disable */ + +/** + * 该文件为脚本自动生成文件,请勿随意修改。如需修改请联系 PMC + * */ + +import { TNode, TElement, SizeEnum } from '../common'; +import { MouseEvent } from 'react'; + +export interface TdLinkProps { + /** + * 链接内容,同 content + */ + children?: TNode; + /** + * 链接内容 + */ + content?: TNode; + /** + * 禁用链接。优先级:Link.disabled > Form.disabled + */ + disabled?: boolean; + /** + * 是否开启点击反馈 + */ + hover?: boolean; + /** + * 跳转链接 + * @default '' + */ + href?: string; + /** + * 前置图标 + */ + prefixIcon?: TElement; + /** + * 尺寸 + * @default medium + */ + size?: SizeEnum; + /** + * 后置图标 + */ + suffixIcon?: TElement; + /** + * 跳转方式,如:当前页面打开、新页面打开等,同 HTML 属性 target 含义相同 + * @default '' + */ + target?: string; + /** + * 组件风格,依次为默认色、品牌色、危险色、警告色、成功色 + * @default default + */ + theme?: 'default' | 'primary' | 'danger' | 'warning' | 'success'; + /** + * 是否显示链接下划线 + */ + underline?: boolean; + /** + * 点击事件,禁用状态不会触发点击事件 + */ + onClick?: (e: MouseEvent) => void; +} diff --git a/src/loading/Loading.tsx b/src/loading/Loading.tsx index 57639a7a..a11012ff 100644 --- a/src/loading/Loading.tsx +++ b/src/loading/Loading.tsx @@ -1,4 +1,4 @@ -import React, { forwardRef, useEffect, useMemo, useRef, useState } from 'react'; +import React, { useEffect, useMemo, useRef, useState } from 'react'; import classNames from 'classnames'; import { TdLoadingProps } from './type'; import { loadingDefaultProps } from './defaultProps'; @@ -12,7 +12,7 @@ import { usePrefixClass } from '../hooks/useClass'; export interface LoadingProps extends TdLoadingProps, StyledProps {} -const Loading = forwardRef((props) => { +const Loading: React.FC = (props) => { const { className, style, @@ -164,7 +164,7 @@ const Loading = forwardRef((props) => {
) ); -}); +}; Loading.displayName = 'Loading'; diff --git a/src/loading/_example/style/index.less b/src/loading/_example/style/index.less index 119e5c34..e818acbe 100644 --- a/src/loading/_example/style/index.less +++ b/src/loading/_example/style/index.less @@ -1,10 +1,10 @@ .loading-demo--flex { display: flex; align-items: center; -} -.t-loading { - margin-right: 64px; + .t-loading { + margin-right: 64px; + } } .loading-demo { diff --git a/src/notice-bar/NoticeBar.tsx b/src/notice-bar/NoticeBar.tsx index 7575b820..0db0c021 100644 --- a/src/notice-bar/NoticeBar.tsx +++ b/src/notice-bar/NoticeBar.tsx @@ -1,4 +1,4 @@ -import React, { forwardRef, useCallback, useContext, useEffect, useMemo, useRef, useState } from 'react'; +import React, { useCallback, useContext, useEffect, useMemo, useRef, useState } from 'react'; import { InfoCircleFilledIcon, CheckCircleFilledIcon, CloseCircleFilledIcon } from 'tdesign-icons-react'; import cls from 'classnames'; import { ConfigContext } from '../config-provider'; @@ -97,7 +97,7 @@ function useAnimationSettingValue() { }; } -const NoticeBar = forwardRef((props) => { +const NoticeBar: React.FC = (props) => { const { classPrefix } = useContext(ConfigContext); const { content, @@ -309,7 +309,7 @@ const NoticeBar = forwardRef((props) => { ); -}); +}; NoticeBar.displayName = 'NoticeBar'; diff --git a/src/overlay/Overlay.tsx b/src/overlay/Overlay.tsx index c2f95ba1..348b14a6 100644 --- a/src/overlay/Overlay.tsx +++ b/src/overlay/Overlay.tsx @@ -1,4 +1,4 @@ -import React, { forwardRef, useRef, useMemo } from 'react'; +import React, { useRef, useMemo } from 'react'; import classNames from 'classnames'; import { CSSTransition } from 'react-transition-group'; import { StyledProps } from '../common'; @@ -11,7 +11,7 @@ import { usePrefixClass } from '../hooks/useClass'; export interface OverlayProps extends TdOverlayProps, StyledProps {} -const Overlay = forwardRef((props) => { +const Overlay: React.FC = (props) => { const overlayClass = usePrefixClass('overlay'); const overlayRef = useRef(); @@ -48,7 +48,7 @@ const Overlay = forwardRef((props) => { ); -}); +}; Overlay.displayName = 'Overlay'; diff --git a/src/skeleton/Skeleton.tsx b/src/skeleton/Skeleton.tsx index 404c10c5..fb15c4ba 100644 --- a/src/skeleton/Skeleton.tsx +++ b/src/skeleton/Skeleton.tsx @@ -1,4 +1,4 @@ -import React, { forwardRef, useState, useEffect } from 'react'; +import React, { useState, useEffect } from 'react'; import classNames from 'classnames'; import isNumber from 'lodash/isNumber'; import isArray from 'lodash/isArray'; @@ -25,7 +25,7 @@ const ThemeMap: Record = { paragraph: [1, 1, 1, { width: '55%' }], }; -const Skeleton = forwardRef((props) => { +const Skeleton: React.FC = (props) => { const skeletonClass = usePrefixClass('skeleton'); const { className, style, children, animation, delay, loading, rowCol, theme } = useDefaultProps( props, @@ -132,7 +132,7 @@ const Skeleton = forwardRef((props) => { {childrenContent} ); -}); +}; Skeleton.displayName = 'Skeleton'; diff --git a/test/snap/__snapshots__/csr.test.jsx.snap b/test/snap/__snapshots__/csr.test.jsx.snap index 0a91d394..fe16d4e4 100644 --- a/test/snap/__snapshots__/csr.test.jsx.snap +++ b/test/snap/__snapshots__/csr.test.jsx.snap @@ -3427,6 +3427,4147 @@ exports[`csr snapshot test > csr test src/icon/_example/single.tsx 1`] = ` `; +exports[`csr snapshot test > csr test src/image/_example/base.tsx 1`] = ` +
+
+
+ 不同填充模式的图片 +
+
+ 提供 fill、contain、cover、none、scale-down 5 种填充类型。 +
+
+
+

+ fill +

+
+
+
+
+
+
+
+
+
+
+ +
+
+
+

+ contain +

+
+
+
+
+
+
+
+
+
+
+ +
+
+
+

+ cover +

+
+
+
+
+
+
+
+
+
+
+ +
+
+
+

+ none +

+
+
+
+
+
+
+
+
+
+
+ +
+
+
+

+ scale-down +

+
+
+
+
+
+
+
+
+
+
+ +
+
+
+
+
+`; + +exports[`csr snapshot test > csr test src/image/_example/index.tsx 1`] = ` +
+
+

+ Image 图片 +

+

+ 用于展示图片素材 +

+
+
+
+

+ 01 组件类型 +

+
+
+
+
+ 不同填充模式的图片 +
+
+ 提供 fill、contain、cover、none、scale-down 5 种填充类型。 +
+
+
+

+ fill +

+
+
+
+
+
+
+
+
+
+
+ +
+
+
+

+ contain +

+
+
+
+
+
+
+
+
+
+
+ +
+
+
+

+ cover +

+
+
+
+
+
+
+
+
+
+
+ +
+
+
+

+ none +

+
+
+
+
+
+
+
+
+
+
+ +
+
+
+

+ scale-down +

+
+
+
+
+
+
+
+
+
+
+ +
+
+
+
+
+
+ 不同填充位置的图片 +
+
+ 当图片过大时,提供显示图片的局部左侧对齐、或右侧对齐的不同位置。 +
+
+
+

+ cover center +

+
+
+
+
+
+
+
+
+
+
+ +
+
+
+

+ cover left +

+
+
+
+
+
+
+
+
+
+
+ +
+
+
+

+ cover right +

+
+
+
+
+
+
+
+
+
+
+ +
+
+
+

+ cover top +

+
+
+
+
+
+
+
+
+
+
+ +
+
+
+

+ cover bottom +

+
+
+
+
+
+
+
+
+
+
+ +
+
+
+

+ contain top +

+
+
+
+
+
+
+
+
+
+
+ +
+
+
+

+ contain bottom +

+
+
+
+
+
+
+
+
+
+
+ +
+
+
+

+ contain center +

+
+
+
+
+
+
+
+
+
+
+ +
+
+
+

+ contain left +

+
+
+
+
+
+
+
+
+
+
+ +
+
+
+

+ contain right +

+
+
+
+
+
+
+
+
+
+
+ +
+
+
+
+
+
+ 不同形状的图片 +
+
+ 提供方形、圆角方形、圆角 3 种形状。 当图片长宽不相等时,无法使用 circle 展示一个正圆。 +
+
+
+

+ 方形 +

+
+
+
+
+
+
+
+
+
+
+ +
+
+
+

+ 圆角方形 +

+
+
+
+
+
+
+
+
+
+
+ +
+
+
+

+ 圆形 +

+
+
+
+
+
+
+
+
+
+
+ 一张图片 +
+
+
+
+
+
+
+
+

+ 02 组件状态 +

+
+
+
+
+

+ 加载默认提示 +

+
+
+
+
+
+
+
+
+
+
+ +
+
+
+

+ 加载自定义提示 +

+
+
+
+ + +
+ + +
+ + + + + +
+
+

+ 失败默认提示 +

+
+
+
+
+
+
+
+
+
+
+ +
+
+
+

+ 失败自定义提示 +

+
+
+
+
+
+
+
+
+
+
+ +
+
+
+
+
+
+`; + +exports[`csr snapshot test > csr test src/image/_example/position.tsx 1`] = ` +
+
+
+ 不同填充位置的图片 +
+
+ 当图片过大时,提供显示图片的局部左侧对齐、或右侧对齐的不同位置。 +
+
+
+

+ cover center +

+
+
+
+
+
+
+
+
+
+
+ +
+
+
+

+ cover left +

+
+
+
+
+
+
+
+
+
+
+ +
+
+
+

+ cover right +

+
+
+
+
+
+
+
+
+
+
+ +
+
+
+

+ cover top +

+
+
+
+
+
+
+
+
+
+
+ +
+
+
+

+ cover bottom +

+
+
+
+
+
+
+
+
+
+
+ +
+
+
+

+ contain top +

+
+
+
+
+
+
+
+
+
+
+ +
+
+
+

+ contain bottom +

+
+
+
+
+
+
+
+
+
+
+ +
+
+
+

+ contain center +

+
+
+
+
+
+
+
+
+
+
+ +
+
+
+

+ contain left +

+
+
+
+
+
+
+
+
+
+
+ +
+
+
+

+ contain right +

+
+
+
+
+
+
+
+
+
+
+ +
+
+
+
+
+`; + +exports[`csr snapshot test > csr test src/image/_example/shape.tsx 1`] = ` +
+
+
+ 不同形状的图片 +
+
+ 提供方形、圆角方形、圆角 3 种形状。 当图片长宽不相等时,无法使用 circle 展示一个正圆。 +
+
+
+

+ 方形 +

+
+
+
+
+
+
+
+
+
+
+ +
+
+
+

+ 圆角方形 +

+
+
+
+
+
+
+
+
+
+
+ +
+
+
+

+ 圆形 +

+
+
+
+
+
+
+
+
+
+
+ 一张图片 +
+
+
+
+
+`; + +exports[`csr snapshot test > csr test src/image/_example/status.tsx 1`] = ` +
+
+
+

+ 加载默认提示 +

+
+
+
+
+
+
+
+
+
+
+ +
+
+
+

+ 加载自定义提示 +

+
+
+
+ + +
+ + +
+ + + + + +
+
+

+ 失败默认提示 +

+
+
+
+
+
+
+
+
+
+
+ +
+
+
+

+ 失败自定义提示 +

+
+
+
+
+
+
+
+
+
+
+ +
+
+
+
+`; + +exports[`csr snapshot test > csr test src/input/_example/align.tsx 1`] = ` +
+
+
+
+ 左对齐 +
+
+
+
+ +
+
+
+
+
+
+ 居中 +
+
+
+
+ +
+
+
+
+
+
+ 右对齐 +
+
+
+
+ +
+
+
+
+`; + +exports[`csr snapshot test > csr test src/input/_example/banner.tsx 1`] = ` +
+
+
+
+ 标签文字 +
+
+
+
+ +
+
+
+
+`; + +exports[`csr snapshot test > csr test src/input/_example/base.tsx 1`] = ` +
+
+
+
+ 标签文字 +
+
+
+
+ +
+
+
+
+
+
+ 标签文字 +
+
+
+
+ +
+
+
+
+
+
+
+
+
+ +
+
+
+
+`; + +exports[`csr snapshot test > csr test src/input/_example/bordered.tsx 1`] = ` +
+
+
+ 标签文字 +
+
+
+
+
+
+
+ +
+
+
+
+
+`; + +exports[`csr snapshot test > csr test src/input/_example/custom.tsx 1`] = ` +
+
+
+
+
+ 标签文字 +
+
+
+
+ +
+
+
+
+
+`; + +exports[`csr snapshot test > csr test src/input/_example/label.tsx 1`] = ` +
+
+
+
+ 标签超长时最多十个字 +
+
+
+
+ +
+
+
+
+`; + +exports[`csr snapshot test > csr test src/input/_example/layout.tsx 1`] = ` +
+
+
+
+ 标签文字 +
+
+
+
+ +
+
+
+
+`; + +exports[`csr snapshot test > csr test src/input/_example/maxLength.tsx 1`] = ` +
+
+
+
+ 标签文字 +
+
+
+
+ +
+
+ 最大输入10个字符 +
+
+
+
+
+
+ 标签文字 +
+
+
+
+ +
+
+ 最大输入10个字符,汉字算两个 +
+
+
+
+`; + +exports[`csr snapshot test > csr test src/input/_example/prefix.tsx 1`] = ` +
+
+
+
+
+ 标签文字 +
+
+
+
+ +
+
+
+
+
+
+
+
+
+
+ +
+
+
+
+`; + +exports[`csr snapshot test > csr test src/input/_example/special.tsx 1`] = ` +
+
+
+
+ 输入密码 +
+
+
+
+ +
+ + + +
+
+
+
+
+
+
+ 验证码 +
+
+
+
+ +
+
+
+
+
+
+
+
+
+
+
+
+
+ +
+
+
+
+
+
+
+
+
+ 手机号 +
+
+
+
+ +
+
+
+
+ 发送验证码 +
+
+
+
+
+ 手机号输入不正确 +
+
+
+
+
+
+ 价格 +
+
+
+
+ +
+ 元 +
+
+
+
+
+
+
+ 数量 +
+
+
+
+ +
+ 个 +
+
+
+
+
+`; + +exports[`csr snapshot test > csr test src/input/_example/status.tsx 1`] = ` +
+
+
+
+ 标签文字 +
+
+
+
+ +
+
+ 辅助说明 +
+
+
+
+
+
+ 不可编辑 +
+
+
+
+ +
+
+
+
+`; + +exports[`csr snapshot test > csr test src/input/_example/suffix.tsx 1`] = ` +
+
+
+
+ 标签文字 +
+
+
+
+ +
+ + + +
+
+
+
+
+
+
+ 标签文字 +
+
+
+
+ +
+ +
+
+
+
+
+
+
+ 标签文字 +
+
+
+
+ +
+ + + +
+
+
+
+
+`; + +exports[`csr snapshot test > csr test src/link/_example/base.tsx 1`] = ` + +`; + +exports[`csr snapshot test > csr test src/link/_example/index.tsx 1`] = ` +
+
+
+

+ Link 链接 +

+

+ 当功能使用图标即可表意清楚时,可使用纯图标悬浮按钮,例如:添加、发布。 +

+
+
+
+

+ 01 组件类型 +

+

+ 基础文字链接 +

+
+ +
+
+
+

+ 下划线文字链接 +

+
+ +
+
+
+

+ 前置图标文字链接 +

+
+ +
+
+
+

+ 后置图标文字链接 +

+
+ +
+ + +
+
+

+ 03 组件样式 +

+

+ 链接尺寸 +

+
+ +
+
+
+`; + +exports[`csr snapshot test > csr test src/link/_example/linkSize.tsx 1`] = ` + +`; + +exports[`csr snapshot test > csr test src/link/_example/prefix.tsx 1`] = ` + +`; + +exports[`csr snapshot test > csr test src/link/_example/status.tsx 1`] = ` + +`; + +exports[`csr snapshot test > csr test src/link/_example/suffix.tsx 1`] = ` + +`; + +exports[`csr snapshot test > csr test src/link/_example/theme.tsx 1`] = ` + +`; + +exports[`csr snapshot test > csr test src/link/_example/underline.tsx 1`] = ` + +`; + exports[`csr snapshot test > csr test src/loading/_example/attach.tsx 1`] = `
csr test src/result/_example/custom.tsx 1`] = ` class="t-result__thumb" >
- - - +
+
+
+
+
+
@@ -6356,28 +10506,37 @@ exports[`csr snapshot test > csr test src/result/_example/index.tsx 1`] = ` class="t-result__thumb" >
- - - +
+
+
+
+
+
@@ -8793,6 +12952,56 @@ exports[`ssr snapshot test > ssr test src/icon/_example/index.tsx 1`] = `"
ssr test src/icon/_example/single.tsx 1`] = `"

"`; +exports[`ssr snapshot test > ssr test src/image/_example/base.tsx 1`] = `"
不同填充模式的图片
提供 fill、contain、cover、none、scale-down 5 种填充类型。

fill

contain

cover

none

scale-down

"`; + +exports[`ssr snapshot test > ssr test src/image/_example/index.tsx 1`] = `"

Image 图片

用于展示图片素材

01 组件类型

不同填充模式的图片
提供 fill、contain、cover、none、scale-down 5 种填充类型。

fill

contain

cover

none

scale-down

不同填充位置的图片
当图片过大时,提供显示图片的局部左侧对齐、或右侧对齐的不同位置。

cover center

cover left

cover right

cover top

cover bottom

contain top

contain bottom

contain center

contain left

contain right

不同形状的图片
提供方形、圆角方形、圆角 3 种形状。 当图片长宽不相等时,无法使用 circle 展示一个正圆。

方形

圆角方形

圆形

一张图片

02 组件状态

加载默认提示

加载自定义提示

失败默认提示

失败自定义提示

"`; + +exports[`ssr snapshot test > ssr test src/image/_example/position.tsx 1`] = `"
不同填充位置的图片
当图片过大时,提供显示图片的局部左侧对齐、或右侧对齐的不同位置。

cover center

cover left

cover right

cover top

cover bottom

contain top

contain bottom

contain center

contain left

contain right

"`; + +exports[`ssr snapshot test > ssr test src/image/_example/shape.tsx 1`] = `"
不同形状的图片
提供方形、圆角方形、圆角 3 种形状。 当图片长宽不相等时,无法使用 circle 展示一个正圆。

方形

圆角方形

圆形

一张图片
"`; + +exports[`ssr snapshot test > ssr test src/image/_example/status.tsx 1`] = `"

加载默认提示

加载自定义提示

失败默认提示

失败自定义提示

"`; + +exports[`ssr snapshot test > ssr test src/input/_example/align.tsx 1`] = `"
左对齐
居中
右对齐
"`; + +exports[`ssr snapshot test > ssr test src/input/_example/banner.tsx 1`] = `"
标签文字
"`; + +exports[`ssr snapshot test > ssr test src/input/_example/base.tsx 1`] = `"
标签文字
标签文字
"`; + +exports[`ssr snapshot test > ssr test src/input/_example/bordered.tsx 1`] = `"
标签文字
"`; + +exports[`ssr snapshot test > ssr test src/input/_example/custom.tsx 1`] = `"
标签文字
"`; + +exports[`ssr snapshot test > ssr test src/input/_example/label.tsx 1`] = `"
标签超长时最多十个字
"`; + +exports[`ssr snapshot test > ssr test src/input/_example/layout.tsx 1`] = `"
标签文字
"`; + +exports[`ssr snapshot test > ssr test src/input/_example/maxLength.tsx 1`] = `"
标签文字
最大输入10个字符
标签文字
最大输入10个字符,汉字算两个
"`; + +exports[`ssr snapshot test > ssr test src/input/_example/prefix.tsx 1`] = `"
标签文字
"`; + +exports[`ssr snapshot test > ssr test src/input/_example/special.tsx 1`] = `"
输入密码
验证码
手机号
发送验证码
价格
数量
"`; + +exports[`ssr snapshot test > ssr test src/input/_example/status.tsx 1`] = `"
标签文字
辅助说明
不可编辑
"`; + +exports[`ssr snapshot test > ssr test src/input/_example/suffix.tsx 1`] = `"
标签文字
标签文字
标签文字
"`; + +exports[`ssr snapshot test > ssr test src/link/_example/base.tsx 1`] = `""`; + +exports[`ssr snapshot test > ssr test src/link/_example/index.tsx 1`] = `"

Link 链接

当功能使用图标即可表意清楚时,可使用纯图标悬浮按钮,例如:添加、发布。

01 组件类型

基础文字链接

下划线文字链接

前置图标文字链接

后置图标文字链接

03 组件样式

链接尺寸

"`; + +exports[`ssr snapshot test > ssr test src/link/_example/linkSize.tsx 1`] = `""`; + +exports[`ssr snapshot test > ssr test src/link/_example/prefix.tsx 1`] = `""`; + +exports[`ssr snapshot test > ssr test src/link/_example/status.tsx 1`] = `""`; + +exports[`ssr snapshot test > ssr test src/link/_example/suffix.tsx 1`] = `""`; + +exports[`ssr snapshot test > ssr test src/link/_example/theme.tsx 1`] = `""`; + +exports[`ssr snapshot test > ssr test src/link/_example/underline.tsx 1`] = `""`; + exports[`ssr snapshot test > ssr test src/loading/_example/attach.tsx 1`] = `"
Hello, I\`'m Alice. I\`'m going to be a front-end developer.
"`; exports[`ssr snapshot test > ssr test src/loading/_example/base.tsx 1`] = `"
"`; @@ -8833,9 +13042,9 @@ exports[`ssr snapshot test > ssr test src/progress/_example/plump.tsx 1`] = `" ssr test src/progress/_example/transition.tsx 1`] = `"
88%
"`; -exports[`ssr snapshot test > ssr test src/result/_example/custom.tsx 1`] = `"
自定义结果
描述文字
"`; +exports[`ssr snapshot test > ssr test src/result/_example/custom.tsx 1`] = `"
自定义结果
描述文字
"`; -exports[`ssr snapshot test > ssr test src/result/_example/index.tsx 1`] = `"

Result 结果

结果反馈

01类型

不同结果反馈

成功状态
描述文字
失败状态
描述文字
警示状态
描述文字
默认状态
描述文字

自定义结果

自定义结果
描述文字

页面位置展示

"`; +exports[`ssr snapshot test > ssr test src/result/_example/index.tsx 1`] = `"

Result 结果

结果反馈

01类型

不同结果反馈

成功状态
描述文字
失败状态
描述文字
警示状态
描述文字
默认状态
描述文字

自定义结果

自定义结果
描述文字

页面位置展示

"`; exports[`ssr snapshot test > ssr test src/result/_example/theme.tsx 1`] = `"
成功状态
描述文字
失败状态
描述文字
警示状态
描述文字
默认状态
描述文字
"`; diff --git a/test/snap/__snapshots__/ssr.test.jsx.snap b/test/snap/__snapshots__/ssr.test.jsx.snap index 10456527..f0d7165d 100644 --- a/test/snap/__snapshots__/ssr.test.jsx.snap +++ b/test/snap/__snapshots__/ssr.test.jsx.snap @@ -32,6 +32,56 @@ exports[`ssr snapshot test > ssr test src/icon/_example/index.tsx 1`] = `"
ssr test src/icon/_example/single.tsx 1`] = `"

"`; +exports[`ssr snapshot test > ssr test src/image/_example/base.tsx 1`] = `"
不同填充模式的图片
提供 fill、contain、cover、none、scale-down 5 种填充类型。

fill

contain

cover

none

scale-down

"`; + +exports[`ssr snapshot test > ssr test src/image/_example/index.tsx 1`] = `"

Image 图片

用于展示图片素材

01 组件类型

不同填充模式的图片
提供 fill、contain、cover、none、scale-down 5 种填充类型。

fill

contain

cover

none

scale-down

不同填充位置的图片
当图片过大时,提供显示图片的局部左侧对齐、或右侧对齐的不同位置。

cover center

cover left

cover right

cover top

cover bottom

contain top

contain bottom

contain center

contain left

contain right

不同形状的图片
提供方形、圆角方形、圆角 3 种形状。 当图片长宽不相等时,无法使用 circle 展示一个正圆。

方形

圆角方形

圆形

一张图片

02 组件状态

加载默认提示

加载自定义提示

失败默认提示

失败自定义提示

"`; + +exports[`ssr snapshot test > ssr test src/image/_example/position.tsx 1`] = `"
不同填充位置的图片
当图片过大时,提供显示图片的局部左侧对齐、或右侧对齐的不同位置。

cover center

cover left

cover right

cover top

cover bottom

contain top

contain bottom

contain center

contain left

contain right

"`; + +exports[`ssr snapshot test > ssr test src/image/_example/shape.tsx 1`] = `"
不同形状的图片
提供方形、圆角方形、圆角 3 种形状。 当图片长宽不相等时,无法使用 circle 展示一个正圆。

方形

圆角方形

圆形

一张图片
"`; + +exports[`ssr snapshot test > ssr test src/image/_example/status.tsx 1`] = `"

加载默认提示

加载自定义提示

失败默认提示

失败自定义提示

"`; + +exports[`ssr snapshot test > ssr test src/input/_example/align.tsx 1`] = `"
左对齐
居中
右对齐
"`; + +exports[`ssr snapshot test > ssr test src/input/_example/banner.tsx 1`] = `"
标签文字
"`; + +exports[`ssr snapshot test > ssr test src/input/_example/base.tsx 1`] = `"
标签文字
标签文字
"`; + +exports[`ssr snapshot test > ssr test src/input/_example/bordered.tsx 1`] = `"
标签文字
"`; + +exports[`ssr snapshot test > ssr test src/input/_example/custom.tsx 1`] = `"
标签文字
"`; + +exports[`ssr snapshot test > ssr test src/input/_example/label.tsx 1`] = `"
标签超长时最多十个字
"`; + +exports[`ssr snapshot test > ssr test src/input/_example/layout.tsx 1`] = `"
标签文字
"`; + +exports[`ssr snapshot test > ssr test src/input/_example/maxLength.tsx 1`] = `"
标签文字
最大输入10个字符
标签文字
最大输入10个字符,汉字算两个
"`; + +exports[`ssr snapshot test > ssr test src/input/_example/prefix.tsx 1`] = `"
标签文字
"`; + +exports[`ssr snapshot test > ssr test src/input/_example/special.tsx 1`] = `"
输入密码
验证码
手机号
发送验证码
价格
数量
"`; + +exports[`ssr snapshot test > ssr test src/input/_example/status.tsx 1`] = `"
标签文字
辅助说明
不可编辑
"`; + +exports[`ssr snapshot test > ssr test src/input/_example/suffix.tsx 1`] = `"
标签文字
标签文字
标签文字
"`; + +exports[`ssr snapshot test > ssr test src/link/_example/base.tsx 1`] = `""`; + +exports[`ssr snapshot test > ssr test src/link/_example/index.tsx 1`] = `"

Link 链接

当功能使用图标即可表意清楚时,可使用纯图标悬浮按钮,例如:添加、发布。

01 组件类型

基础文字链接

下划线文字链接

前置图标文字链接

后置图标文字链接

03 组件样式

链接尺寸

"`; + +exports[`ssr snapshot test > ssr test src/link/_example/linkSize.tsx 1`] = `""`; + +exports[`ssr snapshot test > ssr test src/link/_example/prefix.tsx 1`] = `""`; + +exports[`ssr snapshot test > ssr test src/link/_example/status.tsx 1`] = `""`; + +exports[`ssr snapshot test > ssr test src/link/_example/suffix.tsx 1`] = `""`; + +exports[`ssr snapshot test > ssr test src/link/_example/theme.tsx 1`] = `""`; + +exports[`ssr snapshot test > ssr test src/link/_example/underline.tsx 1`] = `""`; + exports[`ssr snapshot test > ssr test src/loading/_example/attach.tsx 1`] = `"
Hello, I\`'m Alice. I\`'m going to be a front-end developer.
"`; exports[`ssr snapshot test > ssr test src/loading/_example/base.tsx 1`] = `"
"`; @@ -72,9 +122,9 @@ exports[`ssr snapshot test > ssr test src/progress/_example/plump.tsx 1`] = `" ssr test src/progress/_example/transition.tsx 1`] = `"
88%
"`; -exports[`ssr snapshot test > ssr test src/result/_example/custom.tsx 1`] = `"
自定义结果
描述文字
"`; +exports[`ssr snapshot test > ssr test src/result/_example/custom.tsx 1`] = `"
自定义结果
描述文字
"`; -exports[`ssr snapshot test > ssr test src/result/_example/index.tsx 1`] = `"

Result 结果

结果反馈

01类型

不同结果反馈

成功状态
描述文字
失败状态
描述文字
警示状态
描述文字
默认状态
描述文字

自定义结果

自定义结果
描述文字

页面位置展示

"`; +exports[`ssr snapshot test > ssr test src/result/_example/index.tsx 1`] = `"

Result 结果

结果反馈

01类型

不同结果反馈

成功状态
描述文字
失败状态
描述文字
警示状态
描述文字
默认状态
描述文字

自定义结果

自定义结果
描述文字

页面位置展示

"`; exports[`ssr snapshot test > ssr test src/result/_example/theme.tsx 1`] = `"
成功状态
描述文字
失败状态
描述文字
警示状态
描述文字
默认状态
描述文字
"`; diff --git a/tsconfig.json b/tsconfig.json index 3fea2cbb..87c3593c 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -11,7 +11,6 @@ "lib": ["esnext", "dom"], "importHelpers": true, "allowSyntheticDefaultImports": true, - "suppressImplicitAnyIndexErrors": true, "baseUrl": "./", "paths": { "tdesign-mobile-react": ["src"],