- handleStarIndexChange(allowHalf ? index - 0.5 : index)
+ handleStarIndexChange(useRtl ? index : halfIndex)
}
/>
handleStarIndexChange(index)}
+ onClick={() =>
+ handleStarIndexChange(useRtl ? halfIndex : index)
+ }
/>
);
diff --git a/packages/arcodesign/components/rate/style/index.less b/packages/arcodesign/components/rate/style/index.less
index 43cdf6e8..a2d55c71 100644
--- a/packages/arcodesign/components/rate/style/index.less
+++ b/packages/arcodesign/components/rate/style/index.less
@@ -38,6 +38,10 @@
&.half-active {
position: absolute;
z-index: 1;
+
+ [dir="rtl"] & {
+ transform: scaleX(-1);
+ }
}
}
diff --git a/packages/arcodesign/components/skeleton/README.en-US.md b/packages/arcodesign/components/skeleton/README.en-US.md
new file mode 100644
index 00000000..eb0527ba
--- /dev/null
+++ b/packages/arcodesign/components/skeleton/README.en-US.md
@@ -0,0 +1,101 @@
+### Data Display
+
+# Skeleton
+
+Display a set of placeholder graphics during content loading
+
+======
+
+> Props
+
+|Property|Description|Type|DefaultValue|
+|----------|-------------|------|------|
+|title|Show title placeholder|boolean \| SkeletonTitleProps|true|
+|paragraph|Show paragraph placeholder|boolean \| SkeletonParagraphProps|true|
+|avatar|Show Avatar placeholder|boolean \| SkeletonAvatarProps|false|
+|grid|Show Grid placeholder\. When it's value is present, the paragraph, avatar or title placeholder will not be displayed, and four columns will be displayed by default|boolean \| SkeletonGridProps|false|
+|showAnimation|Show loading effect|boolean|true|
+|animation|Animation of loading effect, 'gradient' and 'breath' effects are optional|"gradient" \| "breath"|"gradient"|
+|animationGradientColor|Highlight color of gradient animation|string|"rgba(0, 0, 0, 0.04)"|
+|backgroundColor|Background color of skeleton item|string|"#F7F8FA"|
+|children|Children element|ReactNode|null|
+|className|Custom classname|string|""|
+|style|Custom stylesheet|CSSProperties|{}|
+
+> Refs
+
+|Property|Description|Type|
+|----------|-------------|------|
+|dom|The outer DOM element of the component|HTMLDivElement|
+
+> Skeleton.Node
+
+|Property|Description|Type|DefaultValue|
+|----------|-------------|------|------|
+|children|Custom component content|ReactNode|null|
+|className|Custom classname|string|""|
+|style|Custom stylesheet|CSSProperties|{}|
+
+> Skeleton.Title
+
+|Property|Description|Type|DefaultValue|
+|----------|-------------|------|------|
+|width|The width of title|ReactText|"40%"|
+|className|Custom classname|string|""|
+|style|Custom stylesheet|CSSProperties|{}|
+
+> Skeleton.Paragraph
+
+|Property|Description|Type|DefaultValue|
+|----------|-------------|------|------|
+|rows|Number of lines for paragraph|number|3|
+|width|The width of paragraph\. If width is an Array, it corresponds to the width of each line, otherwise it indicates the width of the last line|string \| number \| ReactText\[\]|"60%"|
+|className|Custom classname|string|""|
+|style|Custom stylesheet|CSSProperties|{}|
+
+> Skeleton.Avatar
+
+|Property|Description|Type|DefaultValue|
+|----------|-------------|------|------|
+|className|Custom classname|string|""|
+|style|Custom stylesheet|CSSProperties|{}|
+
+> Skeleton.Grid
+
+|Property|Description|Type|DefaultValue|
+|----------|-------------|------|------|
+|columns|columns of grid|number|4|
+|className|Custom classname|string|""|
+|style|Custom stylesheet|CSSProperties|{}|
+
+> SkeletonTitleProps
+
+|Property|Description|Type|DefaultValue|
+|----------|-------------|------|------|
+|width|The width of title|ReactText|"40%"|
+|className|Custom classname|string|""|
+|style|Custom stylesheet|CSSProperties|{}|
+
+> SkeletonParagraphProps
+
+|Property|Description|Type|DefaultValue|
+|----------|-------------|------|------|
+|rows|Number of lines for paragraph|number|3|
+|width|The width of paragraph\. If width is an Array, it corresponds to the width of each line, otherwise it indicates the width of the last line|string \| number \| ReactText\[\]|"60%"|
+|className|Custom classname|string|""|
+|style|Custom stylesheet|CSSProperties|{}|
+
+> SkeletonAvatarProps
+
+|Property|Description|Type|DefaultValue|
+|----------|-------------|------|------|
+|className|Custom classname|string|""|
+|style|Custom stylesheet|CSSProperties|{}|
+
+> SkeletonGridProps
+
+|Property|Description|Type|DefaultValue|
+|----------|-------------|------|------|
+|columns|columns of grid|number|4|
+|className|Custom classname|string|""|
+|style|Custom stylesheet|CSSProperties|{}|
diff --git a/packages/arcodesign/components/skeleton/README.md b/packages/arcodesign/components/skeleton/README.md
new file mode 100644
index 00000000..0a4852aa
--- /dev/null
+++ b/packages/arcodesign/components/skeleton/README.md
@@ -0,0 +1,101 @@
+### 信息展示
+
+# 骨架屏 Skeleton
+
+在内容加载过程中展示一组占位图形。
+
+======
+
+> 属性/Props
+
+|参数|描述|类型|默认值|
+|----------|-------------|------|------|
+|title|是否显示标题占位图|boolean \| SkeletonTitleProps|true|
+|paragraph|是否显示段落占位图|boolean \| SkeletonParagraphProps|true|
+|avatar|是否显示头像占位图|boolean \| SkeletonAvatarProps|false|
+|grid|是否显示金刚位占位图(如该参数非空时,默认展示四列金刚位,且不展示标题/段落/头像占位符)|boolean \| SkeletonGridProps|false|
+|showAnimation|是否展示动画效果|boolean|true|
+|animation|加载动画效果,可选“扫光”、“呼吸”两种效果|"gradient" \| "breath"|"gradient"|
+|animationGradientColor|扫光动效高光颜色|string|"rgba(0, 0, 0, 0.04)"|
+|backgroundColor|占位块背景色|string|"#F7F8FA"|
+|children|子元素|ReactNode|null|
+|className|自定义类名|string|""|
+|style|自定义样式|CSSProperties|{}|
+
+> 引用/Refs
+
+|参数|描述|类型|
+|----------|-------------|------|
+|dom|最外层 DOM 元素|HTMLDivElement|
+
+> Skeleton.Node
+
+|参数|描述|类型|默认值|
+|----------|-------------|------|------|
+|children|自定义组件内容|ReactNode|null|
+|className|自定义类名|string|""|
+|style|自定义样式|CSSProperties|{}|
+
+> Skeleton.Title
+
+|参数|描述|类型|默认值|
+|----------|-------------|------|------|
+|width|标题占位图宽度|ReactText|"40%"|
+|className|自定义类名|string|""|
+|style|自定义样式|CSSProperties|{}|
+
+> Skeleton.Paragraph
+
+|参数|描述|类型|默认值|
+|----------|-------------|------|------|
+|rows|段落占位图的行数|number|3|
+|width|段落占位图宽度,若为数组格式对应每行宽度,否则表示最后一行的宽度|string \| number \| ReactText\[\]|"60%"|
+|className|自定义类名|string|""|
+|style|自定义样式|CSSProperties|{}|
+
+> Skeleton.Avatar
+
+|参数|描述|类型|默认值|
+|----------|-------------|------|------|
+|className|自定义类名|string|""|
+|style|自定义样式|CSSProperties|{}|
+
+> Skeleton.Grid
+
+|参数|描述|类型|默认值|
+|----------|-------------|------|------|
+|columns|金刚位列数|number|4|
+|className|自定义类名|string|""|
+|style|自定义样式|CSSProperties|{}|
+
+> SkeletonTitleProps
+
+|参数|描述|类型|默认值|
+|----------|-------------|------|------|
+|width|标题占位图宽度|ReactText|"40%"|
+|className|自定义类名|string|""|
+|style|自定义样式|CSSProperties|{}|
+
+> SkeletonParagraphProps
+
+|参数|描述|类型|默认值|
+|----------|-------------|------|------|
+|rows|段落占位图的行数|number|3|
+|width|段落占位图宽度,若为数组格式对应每行宽度,否则表示最后一行的宽度|string \| number \| ReactText\[\]|"60%"|
+|className|自定义类名|string|""|
+|style|自定义样式|CSSProperties|{}|
+
+> SkeletonAvatarProps
+
+|参数|描述|类型|默认值|
+|----------|-------------|------|------|
+|className|自定义类名|string|""|
+|style|自定义样式|CSSProperties|{}|
+
+> SkeletonGridProps
+
+|参数|描述|类型|默认值|
+|----------|-------------|------|------|
+|columns|金刚位列数|number|4|
+|className|自定义类名|string|""|
+|style|自定义样式|CSSProperties|{}|
diff --git a/packages/arcodesign/components/skeleton/__ast__/index.ast.json b/packages/arcodesign/components/skeleton/__ast__/index.ast.json
new file mode 100644
index 00000000..2a021601
--- /dev/null
+++ b/packages/arcodesign/components/skeleton/__ast__/index.ast.json
@@ -0,0 +1,1007 @@
+{
+ "description": "在内容加载过程中展示一组占位图形。",
+ "descriptionTags": {
+ "en": "Display a set of placeholder graphics during content loading",
+ "type": "信息展示",
+ "type_en": "Data Display",
+ "name": "骨架屏",
+ "name_en": "Skeleton"
+ },
+ "displayName": "Skeleton",
+ "methods": [],
+ "props": {
+ "title": {
+ "defaultValue": {
+ "value": "true"
+ },
+ "description": "是否显示标题占位图\n@en Show title placeholder",
+ "name": "title",
+ "tags": {
+ "en": "Show title placeholder",
+ "default": "true"
+ },
+ "descWithTags": "是否显示标题占位图",
+ "parent": {
+ "fileName": "arcom-github/packages/arcodesign/components/skeleton/type.ts",
+ "name": "SkeletonProps"
+ },
+ "required": false,
+ "type": {
+ "name": "boolean | SkeletonTitleProps"
+ }
+ },
+ "paragraph": {
+ "defaultValue": {
+ "value": "true"
+ },
+ "description": "是否显示段落占位图\n@en Show paragraph placeholder",
+ "name": "paragraph",
+ "tags": {
+ "en": "Show paragraph placeholder",
+ "default": "true"
+ },
+ "descWithTags": "是否显示段落占位图",
+ "parent": {
+ "fileName": "arcom-github/packages/arcodesign/components/skeleton/type.ts",
+ "name": "SkeletonProps"
+ },
+ "required": false,
+ "type": {
+ "name": "boolean | SkeletonParagraphProps"
+ }
+ },
+ "avatar": {
+ "defaultValue": {
+ "value": "false"
+ },
+ "description": "是否显示头像占位图\n@en Show Avatar placeholder",
+ "name": "avatar",
+ "tags": {
+ "en": "Show Avatar placeholder",
+ "default": "false"
+ },
+ "descWithTags": "是否显示头像占位图",
+ "parent": {
+ "fileName": "arcom-github/packages/arcodesign/components/skeleton/type.ts",
+ "name": "SkeletonProps"
+ },
+ "required": false,
+ "type": {
+ "name": "boolean | SkeletonAvatarProps"
+ }
+ },
+ "grid": {
+ "defaultValue": {
+ "value": "false"
+ },
+ "description": "是否显示金刚位占位图(如该参数非空时,默认展示四列金刚位,且不展示标题/段落/头像占位符)\n@en Show Grid placeholder. When it's value is present, the paragraph, avatar or title placeholder will not be displayed, and four columns will be displayed by default",
+ "name": "grid",
+ "tags": {
+ "en": "Show Grid placeholder. When it's value is present, the paragraph, avatar or title placeholder will not be displayed, and four columns will be displayed by default",
+ "default": "false"
+ },
+ "descWithTags": "是否显示金刚位占位图(如该参数非空时,默认展示四列金刚位,且不展示标题/段落/头像占位符)",
+ "parent": {
+ "fileName": "arcom-github/packages/arcodesign/components/skeleton/type.ts",
+ "name": "SkeletonProps"
+ },
+ "required": false,
+ "type": {
+ "name": "boolean | SkeletonGridProps"
+ }
+ },
+ "showAnimation": {
+ "defaultValue": {
+ "value": "true"
+ },
+ "description": "是否展示动画效果\n@en Show loading effect",
+ "name": "showAnimation",
+ "tags": {
+ "en": "Show loading effect",
+ "default": "true"
+ },
+ "descWithTags": "是否展示动画效果",
+ "parent": {
+ "fileName": "arcom-github/packages/arcodesign/components/skeleton/type.ts",
+ "name": "SkeletonProps"
+ },
+ "required": false,
+ "type": {
+ "name": "boolean"
+ }
+ },
+ "animation": {
+ "defaultValue": {
+ "value": "\"gradient\""
+ },
+ "description": "加载动画效果,可选“扫光”、“呼吸”两种效果\n@en Animation of loading effect, 'gradient' and 'breath' effects are optional",
+ "name": "animation",
+ "tags": {
+ "en": "Animation of loading effect, 'gradient' and 'breath' effects are optional",
+ "default": "\"gradient\""
+ },
+ "descWithTags": "加载动画效果,可选“扫光”、“呼吸”两种效果",
+ "parent": {
+ "fileName": "arcom-github/packages/arcodesign/components/skeleton/type.ts",
+ "name": "SkeletonProps"
+ },
+ "required": false,
+ "type": {
+ "name": "enum",
+ "raw": "\"gradient\" | \"breath\"",
+ "value": [
+ {
+ "value": "\"gradient\""
+ },
+ {
+ "value": "\"breath\""
+ }
+ ]
+ }
+ },
+ "animationGradientColor": {
+ "defaultValue": {
+ "value": "\"rgba(0, 0, 0, 0.04)\""
+ },
+ "description": "扫光动效高光颜色\n@en Highlight color of gradient animation",
+ "name": "animationGradientColor",
+ "tags": {
+ "en": "Highlight color of gradient animation",
+ "default": "\"rgba(0, 0, 0, 0.04)\""
+ },
+ "descWithTags": "扫光动效高光颜色",
+ "parent": {
+ "fileName": "arcom-github/packages/arcodesign/components/skeleton/type.ts",
+ "name": "SkeletonProps"
+ },
+ "required": false,
+ "type": {
+ "name": "string"
+ }
+ },
+ "backgroundColor": {
+ "defaultValue": {
+ "value": "\"#F7F8FA\""
+ },
+ "description": "占位块背景色\n@en Background color of skeleton item",
+ "name": "backgroundColor",
+ "tags": {
+ "en": "Background color of skeleton item",
+ "default": "\"#F7F8FA\""
+ },
+ "descWithTags": "占位块背景色",
+ "parent": {
+ "fileName": "arcom-github/packages/arcodesign/components/skeleton/type.ts",
+ "name": "SkeletonProps"
+ },
+ "required": false,
+ "type": {
+ "name": "string"
+ }
+ },
+ "children": {
+ "defaultValue": {
+ "value": "null"
+ },
+ "description": "子元素\n@en Children element",
+ "name": "children",
+ "tags": {
+ "en": "Children element",
+ "default": "null"
+ },
+ "descWithTags": "子元素",
+ "parent": {
+ "fileName": "arcom-github/packages/arcodesign/components/skeleton/type.ts",
+ "name": "SkeletonProps"
+ },
+ "required": false,
+ "type": {
+ "name": "ReactNode"
+ }
+ },
+ "className": {
+ "defaultValue": {
+ "value": "\"\""
+ },
+ "description": "自定义类名\n@en Custom classname",
+ "name": "className",
+ "tags": {
+ "en": "Custom classname",
+ "default": "\"\""
+ },
+ "descWithTags": "自定义类名",
+ "parent": {
+ "fileName": "arcom-github/packages/arcodesign/components/_helpers/type.ts",
+ "name": "SimpleBaseProps"
+ },
+ "required": false,
+ "type": {
+ "name": "string"
+ }
+ },
+ "style": {
+ "defaultValue": {
+ "value": "{}"
+ },
+ "description": "自定义样式\n@en Custom stylesheet",
+ "name": "style",
+ "tags": {
+ "en": "Custom stylesheet",
+ "default": "{}"
+ },
+ "descWithTags": "自定义样式",
+ "parent": {
+ "fileName": "arcom-github/packages/arcodesign/components/_helpers/type.ts",
+ "name": "SimpleBaseProps"
+ },
+ "required": false,
+ "type": {
+ "name": "CSSProperties"
+ }
+ },
+ "ref": {
+ "defaultValue": null,
+ "description": "",
+ "name": "ref",
+ "tags": {},
+ "descWithTags": "",
+ "parent": {
+ "fileName": "arcom-github/node_modules/@types/react/index.d.ts",
+ "name": "RefAttributes"
+ },
+ "required": false,
+ "type": {
+ "name": "Ref
"
+ }
+ }
+ },
+ "deps": {
+ "SkeletonTitleProps": {
+ "width": {
+ "name": "width",
+ "required": false,
+ "description": "标题占位图宽度\n@en The width of title",
+ "defaultValue": {
+ "value": "\"40%\""
+ },
+ "type": {
+ "name": "ReactText"
+ },
+ "tags": {
+ "en": "The width of title",
+ "default": "\"40%\""
+ },
+ "descWithTags": "标题占位图宽度"
+ },
+ "className": {
+ "name": "className",
+ "required": false,
+ "description": "自定义类名\n@en Custom classname",
+ "defaultValue": {
+ "value": "\"\""
+ },
+ "type": {
+ "name": "string"
+ },
+ "tags": {
+ "en": "Custom classname",
+ "default": "\"\""
+ },
+ "descWithTags": "自定义类名"
+ },
+ "style": {
+ "name": "style",
+ "required": false,
+ "description": "自定义样式\n@en Custom stylesheet",
+ "defaultValue": {
+ "value": "{}"
+ },
+ "type": {
+ "name": "CSSProperties"
+ },
+ "tags": {
+ "en": "Custom stylesheet",
+ "default": "{}"
+ },
+ "descWithTags": "自定义样式"
+ }
+ },
+ "SkeletonParagraphProps": {
+ "rows": {
+ "name": "rows",
+ "required": false,
+ "description": "段落占位图的行数\n@en Number of lines for paragraph",
+ "defaultValue": {
+ "value": "3"
+ },
+ "type": {
+ "name": "number"
+ },
+ "tags": {
+ "en": "Number of lines for paragraph",
+ "default": "3"
+ },
+ "descWithTags": "段落占位图的行数"
+ },
+ "width": {
+ "name": "width",
+ "required": false,
+ "description": "段落占位图宽度,若为数组格式对应每行宽度,否则表示最后一行的宽度\n@en The width of paragraph. If width is an Array, it corresponds to the width of each line, otherwise it indicates the width of the last line",
+ "defaultValue": {
+ "value": "\"60%\""
+ },
+ "type": {
+ "name": "string | number | ReactText[]"
+ },
+ "tags": {
+ "en": "The width of paragraph. If width is an Array, it corresponds to the width of each line, otherwise it indicates the width of the last line",
+ "default": "\"60%\""
+ },
+ "descWithTags": "段落占位图宽度,若为数组格式对应每行宽度,否则表示最后一行的宽度"
+ },
+ "className": {
+ "name": "className",
+ "required": false,
+ "description": "自定义类名\n@en Custom classname",
+ "defaultValue": {
+ "value": "\"\""
+ },
+ "type": {
+ "name": "string"
+ },
+ "tags": {
+ "en": "Custom classname",
+ "default": "\"\""
+ },
+ "descWithTags": "自定义类名"
+ },
+ "style": {
+ "name": "style",
+ "required": false,
+ "description": "自定义样式\n@en Custom stylesheet",
+ "defaultValue": {
+ "value": "{}"
+ },
+ "type": {
+ "name": "CSSProperties"
+ },
+ "tags": {
+ "en": "Custom stylesheet",
+ "default": "{}"
+ },
+ "descWithTags": "自定义样式"
+ }
+ },
+ "SkeletonAvatarProps": {
+ "className": {
+ "name": "className",
+ "required": false,
+ "description": "自定义类名\n@en Custom classname",
+ "defaultValue": {
+ "value": "\"\""
+ },
+ "type": {
+ "name": "string"
+ },
+ "tags": {
+ "en": "Custom classname",
+ "default": "\"\""
+ },
+ "descWithTags": "自定义类名"
+ },
+ "style": {
+ "name": "style",
+ "required": false,
+ "description": "自定义样式\n@en Custom stylesheet",
+ "defaultValue": {
+ "value": "{}"
+ },
+ "type": {
+ "name": "CSSProperties"
+ },
+ "tags": {
+ "en": "Custom stylesheet",
+ "default": "{}"
+ },
+ "descWithTags": "自定义样式"
+ }
+ },
+ "SkeletonGridProps": {
+ "columns": {
+ "name": "columns",
+ "required": false,
+ "description": "金刚位列数\n@en columns of grid",
+ "defaultValue": {
+ "value": "4"
+ },
+ "type": {
+ "name": "number"
+ },
+ "tags": {
+ "en": "columns of grid",
+ "default": "4"
+ },
+ "descWithTags": "金刚位列数"
+ },
+ "className": {
+ "name": "className",
+ "required": false,
+ "description": "自定义类名\n@en Custom classname",
+ "defaultValue": {
+ "value": "\"\""
+ },
+ "type": {
+ "name": "string"
+ },
+ "tags": {
+ "en": "Custom classname",
+ "default": "\"\""
+ },
+ "descWithTags": "自定义类名"
+ },
+ "style": {
+ "name": "style",
+ "required": false,
+ "description": "自定义样式\n@en Custom stylesheet",
+ "defaultValue": {
+ "value": "{}"
+ },
+ "type": {
+ "name": "CSSProperties"
+ },
+ "tags": {
+ "en": "Custom stylesheet",
+ "default": "{}"
+ },
+ "descWithTags": "自定义样式"
+ }
+ },
+ "SkeletonRef": {
+ "dom": {
+ "name": "dom",
+ "required": true,
+ "description": "最外层 DOM 元素\n@en The outer DOM element of the component",
+ "defaultValue": null,
+ "type": {
+ "name": "HTMLDivElement"
+ },
+ "tags": {
+ "en": "The outer DOM element of the component"
+ },
+ "descWithTags": "最外层 DOM 元素"
+ }
+ }
+ },
+ "depComps": {
+ "Node": {
+ "description": "",
+ "descriptionTags": {},
+ "displayName": "SkeletonNode",
+ "methods": [],
+ "props": {
+ "children": {
+ "defaultValue": {
+ "value": "null"
+ },
+ "description": "自定义组件内容\n@en Custom component content",
+ "name": "children",
+ "tags": {
+ "en": "Custom component content",
+ "default": "null"
+ },
+ "descWithTags": "自定义组件内容",
+ "parent": {
+ "fileName": "arcom-github/packages/arcodesign/components/_helpers/type.ts",
+ "name": "BaseProps"
+ },
+ "required": false,
+ "type": {
+ "name": "ReactNode"
+ }
+ },
+ "className": {
+ "defaultValue": {
+ "value": "\"\""
+ },
+ "description": "自定义类名\n@en Custom classname",
+ "name": "className",
+ "tags": {
+ "en": "Custom classname",
+ "default": "\"\""
+ },
+ "descWithTags": "自定义类名",
+ "parent": {
+ "fileName": "arcom-github/packages/arcodesign/components/_helpers/type.ts",
+ "name": "SimpleBaseProps"
+ },
+ "required": false,
+ "type": {
+ "name": "string"
+ }
+ },
+ "style": {
+ "defaultValue": {
+ "value": "{}"
+ },
+ "description": "自定义样式\n@en Custom stylesheet",
+ "name": "style",
+ "tags": {
+ "en": "Custom stylesheet",
+ "default": "{}"
+ },
+ "descWithTags": "自定义样式",
+ "parent": {
+ "fileName": "arcom-github/packages/arcodesign/components/_helpers/type.ts",
+ "name": "SimpleBaseProps"
+ },
+ "required": false,
+ "type": {
+ "name": "CSSProperties"
+ }
+ },
+ "ref": {
+ "defaultValue": null,
+ "description": "",
+ "name": "ref",
+ "tags": {},
+ "descWithTags": "",
+ "parent": {
+ "fileName": "arcom-github/node_modules/@types/react/index.d.ts",
+ "name": "RefAttributes"
+ },
+ "required": false,
+ "type": {
+ "name": "Ref"
+ }
+ }
+ },
+ "deps": {
+ "SkeletonRef": {
+ "dom": {
+ "name": "dom",
+ "required": true,
+ "description": "最外层 DOM 元素\n@en The outer DOM element of the component",
+ "defaultValue": null,
+ "type": {
+ "name": "HTMLDivElement"
+ },
+ "tags": {
+ "en": "The outer DOM element of the component"
+ },
+ "descWithTags": "最外层 DOM 元素"
+ }
+ }
+ },
+ "depComps": {},
+ "typeNameInfo": {
+ "props": "BaseProps",
+ "ref": "SkeletonRef"
+ }
+ },
+ "Title": {
+ "description": "",
+ "descriptionTags": {},
+ "displayName": "SkeletonTitle",
+ "methods": [],
+ "props": {
+ "width": {
+ "defaultValue": {
+ "value": "\"40%\""
+ },
+ "description": "标题占位图宽度\n@en The width of title",
+ "name": "width",
+ "tags": {
+ "en": "The width of title",
+ "default": "\"40%\""
+ },
+ "descWithTags": "标题占位图宽度",
+ "parent": {
+ "fileName": "arcom-github/packages/arcodesign/components/skeleton/type.ts",
+ "name": "SkeletonTitleProps"
+ },
+ "required": false,
+ "type": {
+ "name": "ReactText"
+ }
+ },
+ "className": {
+ "defaultValue": {
+ "value": "\"\""
+ },
+ "description": "自定义类名\n@en Custom classname",
+ "name": "className",
+ "tags": {
+ "en": "Custom classname",
+ "default": "\"\""
+ },
+ "descWithTags": "自定义类名",
+ "parent": {
+ "fileName": "arcom-github/packages/arcodesign/components/_helpers/type.ts",
+ "name": "SimpleBaseProps"
+ },
+ "required": false,
+ "type": {
+ "name": "string"
+ }
+ },
+ "style": {
+ "defaultValue": {
+ "value": "{}"
+ },
+ "description": "自定义样式\n@en Custom stylesheet",
+ "name": "style",
+ "tags": {
+ "en": "Custom stylesheet",
+ "default": "{}"
+ },
+ "descWithTags": "自定义样式",
+ "parent": {
+ "fileName": "arcom-github/packages/arcodesign/components/_helpers/type.ts",
+ "name": "SimpleBaseProps"
+ },
+ "required": false,
+ "type": {
+ "name": "CSSProperties"
+ }
+ },
+ "ref": {
+ "defaultValue": null,
+ "description": "",
+ "name": "ref",
+ "tags": {},
+ "descWithTags": "",
+ "parent": {
+ "fileName": "arcom-github/node_modules/@types/react/index.d.ts",
+ "name": "RefAttributes"
+ },
+ "required": false,
+ "type": {
+ "name": "Ref"
+ }
+ }
+ },
+ "deps": {
+ "SkeletonRef": {
+ "dom": {
+ "name": "dom",
+ "required": true,
+ "description": "最外层 DOM 元素\n@en The outer DOM element of the component",
+ "defaultValue": null,
+ "type": {
+ "name": "HTMLDivElement"
+ },
+ "tags": {
+ "en": "The outer DOM element of the component"
+ },
+ "descWithTags": "最外层 DOM 元素"
+ }
+ }
+ },
+ "depComps": {},
+ "typeNameInfo": {
+ "props": "SkeletonTitleProps",
+ "ref": "SkeletonRef"
+ }
+ },
+ "Paragraph": {
+ "description": "",
+ "descriptionTags": {},
+ "displayName": "SkeletonParagraph",
+ "methods": [],
+ "props": {
+ "rows": {
+ "defaultValue": {
+ "value": "3"
+ },
+ "description": "段落占位图的行数\n@en Number of lines for paragraph",
+ "name": "rows",
+ "tags": {
+ "en": "Number of lines for paragraph",
+ "default": "3"
+ },
+ "descWithTags": "段落占位图的行数",
+ "parent": {
+ "fileName": "arcom-github/packages/arcodesign/components/skeleton/type.ts",
+ "name": "SkeletonParagraphProps"
+ },
+ "required": false,
+ "type": {
+ "name": "number"
+ }
+ },
+ "width": {
+ "defaultValue": {
+ "value": "\"60%\""
+ },
+ "description": "段落占位图宽度,若为数组格式对应每行宽度,否则表示最后一行的宽度\n@en The width of paragraph. If width is an Array, it corresponds to the width of each line, otherwise it indicates the width of the last line",
+ "name": "width",
+ "tags": {
+ "en": "The width of paragraph. If width is an Array, it corresponds to the width of each line, otherwise it indicates the width of the last line",
+ "default": "\"60%\""
+ },
+ "descWithTags": "段落占位图宽度,若为数组格式对应每行宽度,否则表示最后一行的宽度",
+ "parent": {
+ "fileName": "arcom-github/packages/arcodesign/components/skeleton/type.ts",
+ "name": "SkeletonParagraphProps"
+ },
+ "required": false,
+ "type": {
+ "name": "string | number | ReactText[]"
+ }
+ },
+ "className": {
+ "defaultValue": {
+ "value": "\"\""
+ },
+ "description": "自定义类名\n@en Custom classname",
+ "name": "className",
+ "tags": {
+ "en": "Custom classname",
+ "default": "\"\""
+ },
+ "descWithTags": "自定义类名",
+ "parent": {
+ "fileName": "arcom-github/packages/arcodesign/components/_helpers/type.ts",
+ "name": "SimpleBaseProps"
+ },
+ "required": false,
+ "type": {
+ "name": "string"
+ }
+ },
+ "style": {
+ "defaultValue": {
+ "value": "{}"
+ },
+ "description": "自定义样式\n@en Custom stylesheet",
+ "name": "style",
+ "tags": {
+ "en": "Custom stylesheet",
+ "default": "{}"
+ },
+ "descWithTags": "自定义样式",
+ "parent": {
+ "fileName": "arcom-github/packages/arcodesign/components/_helpers/type.ts",
+ "name": "SimpleBaseProps"
+ },
+ "required": false,
+ "type": {
+ "name": "CSSProperties"
+ }
+ },
+ "ref": {
+ "defaultValue": null,
+ "description": "",
+ "name": "ref",
+ "tags": {},
+ "descWithTags": "",
+ "parent": {
+ "fileName": "arcom-github/node_modules/@types/react/index.d.ts",
+ "name": "RefAttributes"
+ },
+ "required": false,
+ "type": {
+ "name": "Ref"
+ }
+ }
+ },
+ "deps": {
+ "SkeletonRef": {
+ "dom": {
+ "name": "dom",
+ "required": true,
+ "description": "最外层 DOM 元素\n@en The outer DOM element of the component",
+ "defaultValue": null,
+ "type": {
+ "name": "HTMLDivElement"
+ },
+ "tags": {
+ "en": "The outer DOM element of the component"
+ },
+ "descWithTags": "最外层 DOM 元素"
+ }
+ }
+ },
+ "depComps": {},
+ "typeNameInfo": {
+ "props": "SkeletonParagraphProps",
+ "ref": "SkeletonRef"
+ }
+ },
+ "Avatar": {
+ "description": "",
+ "descriptionTags": {},
+ "displayName": "SkeletonAvatar",
+ "methods": [],
+ "props": {
+ "className": {
+ "defaultValue": {
+ "value": "\"\""
+ },
+ "description": "自定义类名\n@en Custom classname",
+ "name": "className",
+ "tags": {
+ "en": "Custom classname",
+ "default": "\"\""
+ },
+ "descWithTags": "自定义类名",
+ "parent": {
+ "fileName": "arcom-github/packages/arcodesign/components/_helpers/type.ts",
+ "name": "SimpleBaseProps"
+ },
+ "required": false,
+ "type": {
+ "name": "string"
+ }
+ },
+ "style": {
+ "defaultValue": {
+ "value": "{}"
+ },
+ "description": "自定义样式\n@en Custom stylesheet",
+ "name": "style",
+ "tags": {
+ "en": "Custom stylesheet",
+ "default": "{}"
+ },
+ "descWithTags": "自定义样式",
+ "parent": {
+ "fileName": "arcom-github/packages/arcodesign/components/_helpers/type.ts",
+ "name": "SimpleBaseProps"
+ },
+ "required": false,
+ "type": {
+ "name": "CSSProperties"
+ }
+ },
+ "ref": {
+ "defaultValue": null,
+ "description": "",
+ "name": "ref",
+ "tags": {},
+ "descWithTags": "",
+ "parent": {
+ "fileName": "arcom-github/node_modules/@types/react/index.d.ts",
+ "name": "RefAttributes"
+ },
+ "required": false,
+ "type": {
+ "name": "Ref"
+ }
+ }
+ },
+ "deps": {
+ "SkeletonRef": {
+ "dom": {
+ "name": "dom",
+ "required": true,
+ "description": "最外层 DOM 元素\n@en The outer DOM element of the component",
+ "defaultValue": null,
+ "type": {
+ "name": "HTMLDivElement"
+ },
+ "tags": {
+ "en": "The outer DOM element of the component"
+ },
+ "descWithTags": "最外层 DOM 元素"
+ }
+ }
+ },
+ "depComps": {},
+ "typeNameInfo": {
+ "props": "SimpleBaseProps",
+ "ref": "SkeletonRef"
+ }
+ },
+ "Grid": {
+ "description": "",
+ "descriptionTags": {},
+ "displayName": "SkeletonGrid",
+ "methods": [],
+ "props": {
+ "columns": {
+ "defaultValue": {
+ "value": "4"
+ },
+ "description": "金刚位列数\n@en columns of grid",
+ "name": "columns",
+ "tags": {
+ "en": "columns of grid",
+ "default": "4"
+ },
+ "descWithTags": "金刚位列数",
+ "parent": {
+ "fileName": "arcom-github/packages/arcodesign/components/skeleton/type.ts",
+ "name": "SkeletonGridProps"
+ },
+ "required": false,
+ "type": {
+ "name": "number"
+ }
+ },
+ "className": {
+ "defaultValue": {
+ "value": "\"\""
+ },
+ "description": "自定义类名\n@en Custom classname",
+ "name": "className",
+ "tags": {
+ "en": "Custom classname",
+ "default": "\"\""
+ },
+ "descWithTags": "自定义类名",
+ "parent": {
+ "fileName": "arcom-github/packages/arcodesign/components/_helpers/type.ts",
+ "name": "SimpleBaseProps"
+ },
+ "required": false,
+ "type": {
+ "name": "string"
+ }
+ },
+ "style": {
+ "defaultValue": {
+ "value": "{}"
+ },
+ "description": "自定义样式\n@en Custom stylesheet",
+ "name": "style",
+ "tags": {
+ "en": "Custom stylesheet",
+ "default": "{}"
+ },
+ "descWithTags": "自定义样式",
+ "parent": {
+ "fileName": "arcom-github/packages/arcodesign/components/_helpers/type.ts",
+ "name": "SimpleBaseProps"
+ },
+ "required": false,
+ "type": {
+ "name": "CSSProperties"
+ }
+ },
+ "ref": {
+ "defaultValue": null,
+ "description": "",
+ "name": "ref",
+ "tags": {},
+ "descWithTags": "",
+ "parent": {
+ "fileName": "arcom-github/node_modules/@types/react/index.d.ts",
+ "name": "RefAttributes"
+ },
+ "required": false,
+ "type": {
+ "name": "Ref"
+ }
+ }
+ },
+ "deps": {
+ "SkeletonRef": {
+ "dom": {
+ "name": "dom",
+ "required": true,
+ "description": "最外层 DOM 元素\n@en The outer DOM element of the component",
+ "defaultValue": null,
+ "type": {
+ "name": "HTMLDivElement"
+ },
+ "tags": {
+ "en": "The outer DOM element of the component"
+ },
+ "descWithTags": "最外层 DOM 元素"
+ }
+ }
+ },
+ "depComps": {},
+ "typeNameInfo": {
+ "props": "SkeletonGridProps",
+ "ref": "SkeletonRef"
+ }
+ }
+ },
+ "typeNameInfo": {
+ "props": "SkeletonProps",
+ "ref": "SkeletonRef"
+ },
+ "isDefaultExport": true
+}
\ No newline at end of file
diff --git a/packages/arcodesign/components/skeleton/__test__/__snapshots__/index.spec.js.snap b/packages/arcodesign/components/skeleton/__test__/__snapshots__/index.spec.js.snap
new file mode 100644
index 00000000..149464ba
--- /dev/null
+++ b/packages/arcodesign/components/skeleton/__test__/__snapshots__/index.spec.js.snap
@@ -0,0 +1,574 @@
+// Jest Snapshot v1, https://goo.gl/fbAQLP
+
+exports[`skeleton demo test skeleton demo: animation.md renders correctly 1`] = `
+
+`;
+
+exports[`skeleton demo test skeleton demo: avatar.md renders correctly 1`] = `
+
+`;
+
+exports[`skeleton demo test skeleton demo: custom.md renders correctly 1`] = `
+
+`;
+
+exports[`skeleton demo test skeleton demo: grid.md renders correctly 1`] = `
+
+`;
+
+exports[`skeleton demo test skeleton demo: index.md renders correctly 1`] = `
+
+`;
diff --git a/packages/arcodesign/components/skeleton/__test__/index.spec.js b/packages/arcodesign/components/skeleton/__test__/index.spec.js
new file mode 100644
index 00000000..c47d753d
--- /dev/null
+++ b/packages/arcodesign/components/skeleton/__test__/index.spec.js
@@ -0,0 +1,78 @@
+import React from 'react';
+import { mount } from 'enzyme';
+import demoTest from '../../../tests/demoTest';
+import mountTest from '../../../tests/mountTest';
+import { defaultContext } from '../../context-provider';
+import Skeleton from '..';
+
+demoTest('skeleton');
+
+mountTest(Skeleton, 'Skeleton');
+
+const prefix = `${defaultContext.prefixCls}-skeleton`;
+
+describe('Skeleton', () => {
+ it('should render correctly when set ref', () => {
+ const ref = React.createRef();
+ const titleRef = React.createRef();
+ const paragraphRef = React.createRef();
+ const avatarRef = React.createRef();
+ const nodeRef = React.createRef();
+ mount(
+
+
+
+
+
+
+
+ ,
+ );
+ expect(ref.current.dom).not.toBeUndefined();
+ expect(titleRef.current.dom).not.toBeUndefined();
+ expect(paragraphRef.current.dom).not.toBeUndefined();
+ expect(avatarRef.current.dom).not.toBeUndefined();
+ expect(nodeRef.current.dom).not.toBeUndefined();
+ });
+ it('should render correctly when set avatar', () => {
+ const comp = mount();
+ expect(comp.find(`.${prefix}-avatar`).length).toBe(1);
+ });
+ it('should render correctly when set grid', () => {
+ const comp = mount();
+ expect(comp.find(`.${prefix}-grid-item`).length).toBe(5);
+ });
+ it('should render correctly when set children', () => {
+ const comp = mount(
+
+
+
+
+ ,
+ );
+ expect(comp.find(`.${prefix}-node`).length).toBe(1);
+ expect(comp.find(`.${prefix}-title`).length).toBe(1);
+ expect(comp.find(`.${prefix}-paragraph`).length).toBe(1);
+ });
+ it('should render correctly when set animation', () => {
+ const comp = mount(
+
+
+
+
+ ,
+ );
+ expect(comp.find(`.${prefix}-animation-gradient`).length).toBe(5);
+ expect(comp.find(`.${prefix}-animation-breath`).length).toBe(0);
+ comp.setProps({
+ animation: 'breath',
+ });
+ expect(comp.find(`.${prefix}-animation-gradient`).length).toBe(0);
+ expect(comp.find(`.${prefix}-animation-breath`).length).toBe(5);
+ comp.setProps({
+ showAnimation: false,
+ });
+ expect(comp.find(`.${prefix}-animation-gradient`).length).toBe(0);
+ expect(comp.find(`.${prefix}-animation-breath`).length).toBe(0);
+ });
+});
diff --git a/packages/arcodesign/components/skeleton/demo/animation.md b/packages/arcodesign/components/skeleton/demo/animation.md
new file mode 100644
index 00000000..12abd610
--- /dev/null
+++ b/packages/arcodesign/components/skeleton/demo/animation.md
@@ -0,0 +1,39 @@
+## 动效 @en{Animation}
+
+#### 5
+
+```js
+import { Cell, Checkbox, Radio, Skeleton, Switch } from '@arco-design/mobile-react';
+
+const options = [
+ { label: 'gradient', value: 'gradient' },
+ { label: 'breath', value: 'breath' },
+];
+
+const color = 'rgba(0, 0, 0, 4%)';
+
+export default function SkeletonDemo() {
+ const [type, setType] = React.useState('gradient');
+ const [checked, setChecked] = React.useState(true);
+ return (
+
+
+
+
+ |
+ {checked && (
+
+
+ |
+ )}
+
+
+
+ );
+}
+```
diff --git a/packages/arcodesign/components/skeleton/demo/avatar.md b/packages/arcodesign/components/skeleton/demo/avatar.md
new file mode 100644
index 00000000..05165490
--- /dev/null
+++ b/packages/arcodesign/components/skeleton/demo/avatar.md
@@ -0,0 +1,11 @@
+## 含头像 @en{With avatar}
+
+#### 2
+
+```js
+import { Skeleton } from '@arco-design/mobile-react';
+
+export default function SkeletonDemo() {
+ return ;
+}
+```
diff --git a/packages/arcodesign/components/skeleton/demo/custom.md b/packages/arcodesign/components/skeleton/demo/custom.md
new file mode 100644
index 00000000..a79d378f
--- /dev/null
+++ b/packages/arcodesign/components/skeleton/demo/custom.md
@@ -0,0 +1,46 @@
+## 独立节点自由组合 @en{Custom}
+
+#### 5
+
+```js
+import { Cell, Skeleton, Switch } from '@arco-design/mobile-react';
+
+export default function SkeletonDemo() {
+ const [loading, setLoading] = React.useState(true);
+ return (
+
+
+
+
+ |
+
+ {loading ? (
+
+
+
+
+
+
+ ) : (
+
actual content
+ )}
+
+ );
+}
+```
diff --git a/packages/arcodesign/components/skeleton/demo/grid.md b/packages/arcodesign/components/skeleton/demo/grid.md
new file mode 100644
index 00000000..7bbb9fe8
--- /dev/null
+++ b/packages/arcodesign/components/skeleton/demo/grid.md
@@ -0,0 +1,11 @@
+## 金刚区 @en{Grid}
+
+#### 3
+
+```js
+import { Skeleton } from '@arco-design/mobile-react';
+
+export default function SkeletonDemo() {
+ return ;
+}
+```
diff --git a/packages/arcodesign/components/skeleton/demo/index.md b/packages/arcodesign/components/skeleton/demo/index.md
new file mode 100644
index 00000000..3d033861
--- /dev/null
+++ b/packages/arcodesign/components/skeleton/demo/index.md
@@ -0,0 +1,11 @@
+## 基础用法 @en{Basic}
+
+#### 1
+
+```js
+import { Skeleton } from '@arco-design/mobile-react';
+
+export default function SkeletonDemo() {
+ return ;
+}
+```
diff --git a/packages/arcodesign/components/skeleton/demo/style/mobile.less b/packages/arcodesign/components/skeleton/demo/style/mobile.less
new file mode 100644
index 00000000..366ec254
--- /dev/null
+++ b/packages/arcodesign/components/skeleton/demo/style/mobile.less
@@ -0,0 +1,13 @@
+@import '../../../../style/mixin.less';
+
+#demo-skeleton {
+ .arcodesign-mobile-demo-content {
+ .arco-cell-group {
+ margin-bottom: 0.32rem;
+ }
+ .arco-cell {
+ margin-left: 0;
+ padding-right: 0;
+ }
+ }
+}
diff --git a/packages/arcodesign/components/skeleton/elements.tsx b/packages/arcodesign/components/skeleton/elements.tsx
new file mode 100644
index 00000000..48dfa65d
--- /dev/null
+++ b/packages/arcodesign/components/skeleton/elements.tsx
@@ -0,0 +1,278 @@
+import React, {
+ Ref,
+ forwardRef,
+ useContext,
+ useEffect,
+ useImperativeHandle,
+ useRef,
+ useState,
+} from 'react';
+import { cls, isArray, nextTick } from '@arco-design/mobile-utils';
+import { useListenResize } from '../_helpers';
+import { GlobalContext } from '../context-provider';
+import {
+ SkeletonAvatarProps,
+ SkeletonGridProps,
+ SkeletonNodeProps,
+ SkeletonParagraphProps,
+ SkeletonRef,
+ SkeletonTitleProps,
+} from './type';
+import { SkeletonContext } from './skeleton-context';
+
+const calcOffset = (dom?: HTMLElement | null, useRtl?: boolean) => {
+ if (!dom) {
+ return 0;
+ }
+ if (useRtl) {
+ return dom.offsetLeft - dom.offsetTop;
+ }
+ return dom.offsetLeft + dom.offsetTop;
+};
+
+function useOffset | T[]>(
+ dom?: K,
+ useRtl?: boolean,
+) {
+ const [offset, setOffset] = useState();
+ const calcLayout = () => {
+ const isList = Array.isArray(dom);
+ if (
+ !(isList ? (dom as T[]).length > 0 : (dom as React.MutableRefObject)?.current)
+ ) {
+ return;
+ }
+ setOffset(
+ isList
+ ? (dom as T[]).map(item => calcOffset(item, useRtl))
+ : calcOffset((dom as React.MutableRefObject).current, useRtl),
+ );
+ };
+
+ useEffect(() => {
+ nextTick(() => {
+ calcLayout();
+ });
+ }, [dom, useRtl]);
+
+ useListenResize(calcLayout);
+ return offset as K extends T[] ? number[] : number;
+}
+
+export const SkeletonNode = forwardRef((props: SkeletonNodeProps, ref: Ref) => {
+ const { className = '', style, children } = props;
+ const { useRtl, prefixCls } = useContext(GlobalContext);
+ const { backgroundColor, showAnimation, animation } = useContext(SkeletonContext);
+ const domRef = useRef(null);
+ const isGradientAnimation = showAnimation && animation === 'gradient';
+ const offset = useOffset(isGradientAnimation ? domRef : undefined, useRtl);
+
+ useImperativeHandle(ref, () => ({
+ dom: domRef.current,
+ }));
+
+ return (
+
+ {children}
+ {isGradientAnimation && offset !== undefined && (
+
+ )}
+
+ );
+});
+
+export const SkeletonTitle = forwardRef((props: SkeletonTitleProps, ref: Ref) => {
+ const { className = '', style, width = '40%' } = props;
+ const { useRtl, prefixCls } = useContext(GlobalContext);
+ const { backgroundColor, showAnimation, animation } = useContext(SkeletonContext);
+ const domRef = useRef(null);
+ const isGradientAnimation = showAnimation && animation === 'gradient';
+ const offset = useOffset(isGradientAnimation ? domRef : undefined, useRtl);
+
+ useImperativeHandle(ref, () => ({
+ dom: domRef.current,
+ }));
+
+ return (
+
+ {isGradientAnimation && offset !== undefined && (
+
+ )}
+
+ );
+});
+
+export const SkeletonParagraph = forwardRef(
+ (props: SkeletonParagraphProps, ref: Ref) => {
+ const { className = '', style, rows = 3, width = '60%' } = props;
+ const { useRtl, prefixCls } = useContext(GlobalContext);
+ const { backgroundColor, showAnimation, animation } = useContext(SkeletonContext);
+ const domRef = useRef(null);
+ const lineDomRefs = useRef([]);
+ const isGradientAnimation = showAnimation && animation === 'gradient';
+ const offsets = useOffset(isGradientAnimation ? lineDomRefs.current : undefined, useRtl);
+
+ useImperativeHandle(ref, () => ({
+ dom: domRef.current,
+ }));
+
+ const getWidth = (idx: number) => {
+ if (isArray(width)) {
+ return width[idx];
+ }
+ if (rows - 1 === idx) {
+ return width;
+ }
+ return undefined;
+ };
+
+ return (
+
+ {Array.from(new Array(rows)).map((_, idx) => (
+
el && (lineDomRefs.current[idx] = el)}
+ >
+ {isGradientAnimation && offsets !== undefined && (
+
+ )}
+
+ ))}
+
+ );
+ },
+);
+
+export const SkeletonAvatar = forwardRef((props: SkeletonAvatarProps, ref: Ref) => {
+ const { className = '', style } = props;
+ const { useRtl, prefixCls } = useContext(GlobalContext);
+ const { backgroundColor, showAnimation, animation } = useContext(SkeletonContext);
+ const domRef = useRef(null);
+ const isGradientAnimation = showAnimation && animation === 'gradient';
+ const offset = useOffset(isGradientAnimation ? domRef : undefined, useRtl);
+
+ useImperativeHandle(ref, () => ({
+ dom: domRef.current,
+ }));
+
+ return (
+
+ {isGradientAnimation && offset !== undefined && (
+
+ )}
+
+ );
+});
+
+export const SkeletonGrid = forwardRef((props: SkeletonGridProps, ref: Ref) => {
+ const { className = '', style, columns = 4 } = props;
+ const { useRtl, prefixCls } = useContext(GlobalContext);
+ const { backgroundColor, showAnimation, animation } = useContext(SkeletonContext);
+ const domRef = useRef(null);
+ const iconDomRefs = useRef([]);
+ const textDomRefs = useRef([]);
+ const isGradientAnimation = showAnimation && animation === 'gradient';
+ const iconOffsets = useOffset(isGradientAnimation ? iconDomRefs.current : undefined, useRtl);
+ const textOffsets = useOffset(isGradientAnimation ? textDomRefs.current : undefined, useRtl);
+
+ useImperativeHandle(ref, () => ({
+ dom: domRef.current,
+ }));
+
+ return (
+
+ {Array.from(new Array(columns)).map((_, idx) => (
+
+
el && (iconDomRefs.current[idx] = el)}
+ >
+ {isGradientAnimation && iconOffsets !== undefined && (
+
+ )}
+
+
el && (textDomRefs.current[idx] = el)}
+ >
+ {isGradientAnimation && textOffsets !== undefined && (
+
+ )}
+
+
+ ))}
+
+ );
+});
diff --git a/packages/arcodesign/components/skeleton/index.tsx b/packages/arcodesign/components/skeleton/index.tsx
new file mode 100644
index 00000000..a1f3e683
--- /dev/null
+++ b/packages/arcodesign/components/skeleton/index.tsx
@@ -0,0 +1,94 @@
+import React, { useRef, forwardRef, Ref, useImperativeHandle, useContext } from 'react';
+import { cls, componentWrapper } from '@arco-design/mobile-utils';
+import { GlobalContext } from '../context-provider';
+import { SkeletonProps, SkeletonRef } from './type';
+import {
+ SkeletonAvatar as Avatar,
+ SkeletonGrid as Grid,
+ SkeletonNode as Node,
+ SkeletonParagraph as Paragraph,
+ SkeletonTitle as Title,
+} from './elements';
+import { SkeletonContext } from './skeleton-context';
+
+function getComponentProps(prop?: T | boolean): T | {} {
+ if (prop && typeof prop === 'object') {
+ return prop;
+ }
+ return {};
+}
+
+const Skeleton = forwardRef((props: SkeletonProps, ref: Ref) => {
+ const {
+ className = '',
+ style,
+ children,
+ title = true,
+ paragraph = true,
+ avatar = false,
+ grid,
+ showAnimation = true,
+ animation = 'gradient',
+ animationGradientColor,
+ backgroundColor,
+ } = props;
+ const domRef = useRef(null);
+ const { prefixCls } = useContext(GlobalContext);
+
+ useImperativeHandle(ref, () => ({
+ dom: domRef.current,
+ }));
+
+ const isGrid = !!grid;
+ const hasTitle = !!title;
+ const hasParagraph = !!paragraph;
+ const hasAvatar = !!avatar;
+ const content = isGrid ? (
+
+ ) : (
+ <>
+ {hasAvatar && }
+ {(hasTitle || hasParagraph) && (
+
+ {hasTitle &&
}
+ {hasParagraph &&
}
+
+ )}
+ >
+ );
+
+ return (
+
+
+ {content}
+ {children}
+
+
+ );
+});
+
+/**
+ * 在内容加载过程中展示一组占位图形。
+ * @en Display a set of placeholder graphics during content loading
+ * @type 信息展示
+ * @type_en Data Display
+ * @name 骨架屏
+ * @name_en Skeleton
+ */
+export default componentWrapper(Skeleton, {
+ Node,
+ Title,
+ Paragraph,
+ Avatar,
+ Grid,
+});
diff --git a/packages/arcodesign/components/skeleton/skeleton-context.tsx b/packages/arcodesign/components/skeleton/skeleton-context.tsx
new file mode 100644
index 00000000..81cb0107
--- /dev/null
+++ b/packages/arcodesign/components/skeleton/skeleton-context.tsx
@@ -0,0 +1,7 @@
+import React from 'react';
+import { SkeletonContextParams, SkeletonProps } from './type';
+
+export const SkeletonContext = React.createContext({
+ showAnimation: true,
+ animation: 'gradient' as SkeletonProps['animation'],
+});
diff --git a/packages/arcodesign/components/skeleton/style/index.less b/packages/arcodesign/components/skeleton/style/index.less
new file mode 100644
index 00000000..1a6788fc
--- /dev/null
+++ b/packages/arcodesign/components/skeleton/style/index.less
@@ -0,0 +1,147 @@
+@import '../../../style/mixin.less';
+
+.@{prefix}-skeleton {
+ position: relative;
+ .use-var(color, skeleton-gradient-animation-color);
+}
+
+.@{prefix}-skeleton-title {
+ .use-var(height, skeleton-title-height);
+}
+
+.@{prefix}-skeleton-paragraph {
+ &-line {
+ width: 100%;
+ .use-var(height, skeleton-paragraph-height);
+ }
+
+ &-line + &-line {
+ .use-var(margin-top, skeleton-paragraph-margin-top);
+ }
+}
+
+.@{prefix}-skeleton-avatar.@{prefix}-skeleton-item {
+ .use-var(width, skeleton-avatar-size);
+ .use-var(height, skeleton-avatar-size);
+ border-radius: 100%;
+ transform: translateZ(0);
+}
+
+.@{prefix}-skeleton-content {
+ width: 100%;
+
+ .@{prefix}-skeleton-title + .@{prefix}-skeleton-paragraph {
+ .use-var(margin-top, skeleton-large-gutter);
+ }
+}
+
+.@{prefix}-skeleton-with-avatar {
+ display: flex;
+ align-items: flex-start;
+
+ .@{prefix}-skeleton-avatar {
+ flex: none;
+ }
+
+ .@{prefix}-skeleton-content {
+ .@{prefix}-skeleton-title {
+ .use-var(margin-top, skeleton-medium-gutter);
+ }
+ }
+
+ .@{prefix}-skeleton-avatar + .@{prefix}-skeleton-content {
+ .use-var-with-rtl(margin-left, skeleton-medium-gutter);
+ }
+}
+
+.@{prefix}-skeleton-grid {
+ display: flex;
+ justify-content: space-between;
+ width: 100%;
+
+ &-item {
+ display: flex;
+ flex-direction: column;
+ align-items: center;
+ }
+ &-icon {
+ .use-var(width, skeleton-grid-icon-size);
+ .use-var(height, skeleton-grid-icon-size);
+ }
+ &-text {
+ .use-var(margin-top, skeleton-medium-gutter);
+ .use-var(width, skeleton-grid-text-width);
+ .use-var(height, skeleton-grid-text-height);
+ }
+}
+
+.@{prefix}-skeleton-node {
+ display: inline-block;
+}
+
+.@{prefix}-skeleton-item {
+ position: relative;
+ overflow: hidden;
+ .use-var(border-radius, skeleton-border-radius);
+ .use-var(background-color, skeleton-background-color);
+}
+
+.@{prefix}-skeleton-animation-item {
+ position: absolute;
+ width: 100vw;
+ height: 100%;
+ top: 0;
+ left: 0;
+ background-image: linear-gradient(
+ 90deg,
+ rgba(255, 255, 255, 0) 35%,
+ currentColor 50%,
+ rgba(255, 255, 255, 0) 65%
+ );
+ transform-origin: top left;
+ animation-name: skeleton-gradient;
+ animation-iteration-count: infinite;
+ .use-var(animation-timing-function, skeleton-gradient-animation-timing-function);
+ .use-var(animation-duration, skeleton-gradient-animation-duration);
+ [dir="rtl"] & {
+ animation-name: skeleton-gradient-reverse;
+ }
+}
+.@{prefix}-skeleton-animation-breath {
+ animation: skeleton-breath linear infinite;
+ .use-var(animation-duration, skeleton-breath-animation-duration);
+}
+
+@keyframes skeleton-gradient {
+ 0% {
+ transform: translateX(-65%) skewX(-45deg);
+ }
+
+ 100% {
+ transform: translateX(135%) skewX(-45deg);
+ }
+}
+
+@keyframes skeleton-gradient-reverse {
+ 0% {
+ transform: translateX(65%) skewX(45deg);
+ }
+
+ 100% {
+ transform: translateX(-135%) skewX(45deg);
+ }
+}
+
+@keyframes skeleton-breath {
+ 0% {
+ opacity: 1;
+ }
+
+ 50% {
+ .use-var(opacity, skeleton-breath-opacity);
+ }
+
+ 100% {
+ opacity: 1;
+ }
+}
diff --git a/packages/arcodesign/components/skeleton/style/index.ts b/packages/arcodesign/components/skeleton/style/index.ts
new file mode 100644
index 00000000..d33b50ec
--- /dev/null
+++ b/packages/arcodesign/components/skeleton/style/index.ts
@@ -0,0 +1,3 @@
+import '../../../style/public.less';
+import '../../avatar/style';
+import './index.less';
diff --git a/packages/arcodesign/components/skeleton/type.ts b/packages/arcodesign/components/skeleton/type.ts
new file mode 100644
index 00000000..ad6bad5b
--- /dev/null
+++ b/packages/arcodesign/components/skeleton/type.ts
@@ -0,0 +1,109 @@
+import { BaseProps, SimpleBaseProps } from '../_helpers';
+
+export interface SkeletonProps extends SimpleBaseProps {
+ /**
+ * 是否显示标题占位图
+ * @en Show title placeholder
+ * @default true
+ */
+ title?: boolean | SkeletonTitleProps;
+ /**
+ * 是否显示段落占位图
+ * @en Show paragraph placeholder
+ * @default true
+ */
+ paragraph?: boolean | SkeletonParagraphProps;
+ /**
+ * 是否显示头像占位图
+ * @en Show Avatar placeholder
+ * @default false
+ */
+ avatar?: boolean | SkeletonAvatarProps;
+ /**
+ * 是否显示金刚位占位图(如该参数非空时,默认展示四列金刚位,且不展示标题/段落/头像占位符)
+ * @en Show Grid placeholder. When it's value is present, the paragraph, avatar or title placeholder will not be displayed, and four columns will be displayed by default
+ * @default false
+ */
+ grid?: boolean | SkeletonGridProps;
+ /**
+ * 是否展示动画效果
+ * @en Show loading effect
+ * @default true
+ */
+ showAnimation?: boolean;
+ /**
+ * 加载动画效果,可选“扫光”、“呼吸”两种效果
+ * @en Animation of loading effect, 'gradient' and 'breath' effects are optional
+ * @default "gradient"
+ */
+ animation?: 'gradient' | 'breath';
+ /**
+ * 扫光动效高光颜色
+ * @en Highlight color of gradient animation
+ * @default "rgba(0, 0, 0, 0.04)"
+ */
+ animationGradientColor?: string;
+ /**
+ * 占位块背景色
+ * @en Background color of skeleton item
+ * @default "#F7F8FA"
+ */
+ backgroundColor?: string;
+ /**
+ * 子元素
+ * @en Children element
+ * @default null
+ */
+ children?: React.ReactNode;
+}
+
+export interface SkeletonTitleProps extends SimpleBaseProps {
+ /**
+ * 标题占位图宽度
+ * @en The width of title
+ * @default "40%"
+ */
+ width?: number | string;
+}
+
+export interface SkeletonParagraphProps extends SimpleBaseProps {
+ /**
+ * 段落占位图的行数
+ * @en Number of lines for paragraph
+ * @default 3
+ */
+ rows?: number;
+ /**
+ * 段落占位图宽度,若为数组格式对应每行宽度,否则表示最后一行的宽度
+ * @en The width of paragraph. If width is an Array, it corresponds to the width of each line, otherwise it indicates the width of the last line
+ * @default "60%"
+ */
+ width?: number | string | Array;
+}
+
+export interface SkeletonAvatarProps extends SimpleBaseProps {}
+
+export interface SkeletonGridProps extends SimpleBaseProps {
+ /**
+ * 金刚位列数
+ * @en columns of grid
+ * @default 4
+ */
+ columns?: number;
+}
+
+export interface SkeletonNodeProps extends BaseProps {}
+
+export interface SkeletonRef {
+ /**
+ * 最外层 DOM 元素
+ * @en The outer DOM element of the component
+ */
+ dom: HTMLDivElement | null;
+}
+
+export interface SkeletonContextParams {
+ backgroundColor?: string;
+ showAnimation: boolean;
+ animation: SkeletonProps['animation'];
+}
diff --git a/packages/arcodesign/components/slider/popover.tsx b/packages/arcodesign/components/slider/popover.tsx
index 2c566e5b..07c79594 100644
--- a/packages/arcodesign/components/slider/popover.tsx
+++ b/packages/arcodesign/components/slider/popover.tsx
@@ -1,4 +1,4 @@
-import React, { useContext, ReactNode } from 'react';
+import React, { useContext, ReactNode, useRef } from 'react';
import Transition from '../transition';
import { GlobalContext } from '../context-provider';
@@ -12,11 +12,22 @@ export function Popover({
children: ReactNode;
}) {
const { prefixCls = '' } = useContext(GlobalContext);
+ const domRef = useRef(null);
return (
-
-
+
+
diff --git a/packages/arcodesign/components/stepper/demo/default.md b/packages/arcodesign/components/stepper/demo/default.md
index 59ccd4e3..b09bbc50 100644
--- a/packages/arcodesign/components/stepper/demo/default.md
+++ b/packages/arcodesign/components/stepper/demo/default.md
@@ -15,7 +15,7 @@ export default function StepperDemo() {
-
+
|
);
diff --git a/packages/arcodesign/components/stepper/hooks/useButtonClick.tsx b/packages/arcodesign/components/stepper/hooks/useButtonClick.tsx
index 625c71f2..a9d97a81 100644
--- a/packages/arcodesign/components/stepper/hooks/useButtonClick.tsx
+++ b/packages/arcodesign/components/stepper/hooks/useButtonClick.tsx
@@ -31,12 +31,10 @@ export default function useButtonClick(
onAddButtonClick,
onMinusButtonClick,
} = params;
- const [minusButtonDisable, setMinusButtonDisable] = useState(
- () => actualInputValue === min || disabled,
- );
- const [addButtonDisable, setAddButtonDisable] = useState(
- () => actualInputValue === max || disabled,
- );
+ const minusDisable = actualInputValue <= min || disabled;
+ const [minusButtonDisable, setMinusButtonDisable] = useState(minusDisable);
+ const addDisable = actualInputValue >= max || disabled;
+ const [addButtonDisable, setAddButtonDisable] = useState(addDisable);
const handleMinusButtonClick = (e: React.MouseEvent) => {
if (minusButtonDisable) {
@@ -63,9 +61,9 @@ export default function useButtonClick(
// 当前值改变时,更新按钮状态
// Changes button status when value changed
useEffect(() => {
- setMinusButtonDisable(actualInputValue <= min);
- setAddButtonDisable(actualInputValue >= max);
- }, [actualInputValue]);
+ setMinusButtonDisable(minusDisable);
+ setAddButtonDisable(addDisable);
+ }, [minusDisable, addDisable]);
return {
minusButtonDisable,
diff --git a/packages/arcodesign/components/sticky/README.en-US.md b/packages/arcodesign/components/sticky/README.en-US.md
index 4ddf0679..20379aeb 100644
--- a/packages/arcodesign/components/sticky/README.en-US.md
+++ b/packages/arcodesign/components/sticky/README.en-US.md
@@ -33,6 +33,7 @@ Sticky layout component, The sticky-to-top effect of the element relative to the
|----------|-------------|------|
|dom|The outermost element DOM|HTMLDivElement|
|recalculatePosition|In the local scrolling mode, if there is nested scrolling outside the container, this method can be actively called to make the sticky element actively update the fixed position|() =\> void|
+|updatePlaceholderLayout|Manually update the height of the placeholder|() =\> void|
> StickyEventPayload
diff --git a/packages/arcodesign/components/sticky/README.md b/packages/arcodesign/components/sticky/README.md
index e4f42590..48d88e6e 100644
--- a/packages/arcodesign/components/sticky/README.md
+++ b/packages/arcodesign/components/sticky/README.md
@@ -33,6 +33,7 @@
|----------|-------------|------|
|dom|最外层元素 DOM|HTMLDivElement|
|recalculatePosition|局部滚动模式下,如果容器外部还有嵌套滚动,可主动调用此方法,让 sticky 的元素主动更新 fixed 位置|() =\> void|
+|updatePlaceholderLayout|手动更新占位模块的高度|() =\> void|
> StickyEventPayload
diff --git a/packages/arcodesign/components/sticky/__ast__/index.ast.json b/packages/arcodesign/components/sticky/__ast__/index.ast.json
index ca103a61..9a8baa18 100644
--- a/packages/arcodesign/components/sticky/__ast__/index.ast.json
+++ b/packages/arcodesign/components/sticky/__ast__/index.ast.json
@@ -423,6 +423,19 @@
"en": "In the local scrolling mode, if there is nested scrolling outside the container, this method can be actively called to make the sticky element actively update the fixed position"
},
"descWithTags": "局部滚动模式下,如果容器外部还有嵌套滚动,可主动调用此方法,让 sticky 的元素主动更新 fixed 位置"
+ },
+ "updatePlaceholderLayout": {
+ "name": "updatePlaceholderLayout",
+ "required": true,
+ "description": "手动更新占位模块的高度\n@en Manually update the height of the placeholder",
+ "defaultValue": null,
+ "type": {
+ "name": "() => void"
+ },
+ "tags": {
+ "en": "Manually update the height of the placeholder"
+ },
+ "descWithTags": "手动更新占位模块的高度"
}
}
},
diff --git a/packages/arcodesign/components/sticky/index.tsx b/packages/arcodesign/components/sticky/index.tsx
index a55ba1c4..861171fe 100644
--- a/packages/arcodesign/components/sticky/index.tsx
+++ b/packages/arcodesign/components/sticky/index.tsx
@@ -31,6 +31,11 @@ export interface StickyRef {
* @en In the local scrolling mode, if there is nested scrolling outside the container, this method can be actively called to make the sticky element actively update the fixed position
*/
recalculatePosition: () => void;
+ /**
+ * 手动更新占位模块的高度
+ * @en Manually update the height of the placeholder
+ */
+ updatePlaceholderLayout: () => void;
}
export interface StickyEventPayload {
@@ -300,6 +305,23 @@ const Sticky = forwardRef((props: StickyProps, ref: Ref) => {
framePendingRef.current = true;
}, [containerEventHandler]);
+ const updatePlaceholderLayoutInner = useCallback(() => {
+ if (placeholderRef.current) {
+ const contentHeight = contentCalculateHeightRef.current;
+ // 当元素吸顶时,默认有一个占位的元素占住该元素的位置,避免布局产生抖动
+ // @en When an element is sticky to the top, a placeholder element occupies the element's position by default to avoid jitter in the layout
+ placeholderRef.current.style.height = `${isStickyRef.current ? contentHeight : 0}px`;
+ }
+ }, []);
+
+ const updatePlaceholderLayout = useCallback(() => {
+ if (contentRef.current) {
+ const contentClientRect = contentRef.current.getBoundingClientRect();
+ contentCalculateHeightRef.current = contentClientRect.height;
+ }
+ updatePlaceholderLayoutInner();
+ }, []);
+
useEffect(() => {
const containerEle = getActualContainer(getContainer) as HTMLElement;
@@ -326,13 +348,7 @@ const Sticky = forwardRef((props: StickyProps, ref: Ref) => {
}, [getContainer, getScrollContainer, recalculatePosition]);
useEffect(() => {
- if (placeholderRef.current) {
- // 当元素吸顶时,默认有一个占位的元素占住该元素的位置,避免布局产生抖动
- // @en When an element is sticky to the top, a placeholder element occupies the element's position by default to avoid jitter in the layout
- placeholderRef.current.style.height = `${
- isStickyRef.current ? contentCalculateHeightRef.current : 0
- }px`;
- }
+ updatePlaceholderLayoutInner();
}, [isSticky, wasSticky]);
useImperativeHandle(
@@ -340,8 +356,9 @@ const Sticky = forwardRef((props: StickyProps, ref: Ref) => {
() => ({
dom: contentRef.current,
recalculatePosition,
+ updatePlaceholderLayout,
}),
- [recalculatePosition],
+ [recalculatePosition, updatePlaceholderLayout],
);
const computedStyle = useMemo(
diff --git a/packages/arcodesign/components/style.ts b/packages/arcodesign/components/style.ts
index b486c534..bdb044de 100644
--- a/packages/arcodesign/components/style.ts
+++ b/packages/arcodesign/components/style.ts
@@ -1,35 +1,32 @@
import '../style/public.less';
-import './button/style';
+import './tabs/style';
+import './sticky/style';
+import './load-more/style';
+import './cell/style';
import './action-sheet/style';
import './avatar/style';
import './badge/style';
+import './button/style';
import './carousel/style';
-import './cell/style';
import './checkbox/style';
import './circle-progress/style';
import './collapse/style';
import './context-provider/style';
import './count-down/style';
import './date-picker/style';
-import './divider/style';
import './dialog/style';
+import './divider/style';
import './dropdown/style';
import './dropdown-menu/style';
import './ellipsis/style';
import './form/style';
-import './input/style';
-import './textarea/style';
-import './radio/style';
-import './image-picker/style';
-import './rate/style';
-import './slider/style';
import './grid/style';
import './image/style';
-import './show-monitor/style';
+import './image-picker/style';
import './image-preview/style';
import './index-bar/style';
+import './input/style';
import './keyboard/style';
-import './load-more/style';
import './loading/style';
import './masking/style';
import './nav-bar/style';
@@ -44,15 +41,19 @@ import './popup-swiper/style';
import './portal/style';
import './progress/style';
import './pull-refresh/style';
+import './radio/style';
+import './rate/style';
import './search-bar/style';
+import './skeleton/style';
+import './show-monitor/style';
+import './slider/style';
import './stepper/style';
import './steps/style';
-import './sticky/style';
import './swipe-action/style';
import './swipe-load/style';
import './switch/style';
import './tab-bar/style';
-import './tabs/style';
import './tag/style';
+import './textarea/style';
import './toast/style';
import './transition/style';
diff --git a/packages/arcodesign/components/switch/index.tsx b/packages/arcodesign/components/switch/index.tsx
index f38de812..60517fa2 100644
--- a/packages/arcodesign/components/switch/index.tsx
+++ b/packages/arcodesign/components/switch/index.tsx
@@ -1,6 +1,14 @@
-import React, { useState, useEffect, forwardRef, Ref, useImperativeHandle, useRef } from 'react';
+import React, {
+ useState,
+ useEffect,
+ forwardRef,
+ Ref,
+ useImperativeHandle,
+ useRef,
+ useContext,
+} from 'react';
import { cls, componentWrapper } from '@arco-design/mobile-utils';
-import { ContextLayout } from '../context-provider';
+import { ContextLayout, GlobalContext } from '../context-provider';
import { useSystem } from '../_helpers';
interface SwitchText {
@@ -98,6 +106,7 @@ export interface SwitchRef {
}
const Switch = forwardRef((props: SwitchProps, ref: Ref) => {
+ const { useRtl } = useContext(GlobalContext);
const system = useSystem();
const {
className,
@@ -153,15 +162,17 @@ const Switch = forwardRef((props: SwitchProps, ref: Ref) => {
}
const touchEndX = e.changedTouches && e.changedTouches[0] ? e.changedTouches[0].clientX : 0;
const distance = touchEndX - touchStartX;
+ const swipeRight = useRtl ? distance < 0 : distance > 0;
+ const swipeLeft = useRtl ? distance > 0 : distance < 0;
let newChecked = false;
// 右滑打开
// @en Swipe right to open
- if (distance > 0) {
+ if (swipeRight) {
newChecked = true;
// 左滑关闭
// @en Swipe left to close
- } else if (distance < 0) {
+ } else if (swipeLeft) {
newChecked = false;
// 点击时取反
// @en Invert on clicking
diff --git a/packages/arcodesign/components/switch/style/index.less b/packages/arcodesign/components/switch/style/index.less
index a4e62cdf..54bc4d15 100644
--- a/packages/arcodesign/components/switch/style/index.less
+++ b/packages/arcodesign/components/switch/style/index.less
@@ -33,17 +33,23 @@
&.checked {
.use-var(background-color, switch-android-checked-background);
.@{prefix}-switch-text {
- right: auto;
- .use-var(left, switch-android-text-gap-size);
+ .set-prop-with-rtl(right, auto);
+ .use-var-with-rtl(left, switch-android-text-gap-size);
}
.@{prefix}-switch-inner {
.use-var(transform, switch-android-checked-inner-transform);
+ [dir="rtl"] & {
+ .use-var(transform, switch-android-checked-inner-transform, "rotate(180deg)");
+ }
}
}
.@{prefix}-switch-inner {
.use-var(width, switch-android-inner-diameter-size);
.use-var(height, switch-android-inner-diameter-size);
.use-var(box-shadow, switch-android-inner-box-shadow);
+ [dir="rtl"] & {
+ transform: rotate(180deg);
+ }
}
&.disabled {
@@ -58,7 +64,7 @@
}
.@{prefix}-switch-text {
.use-var(font-size, switch-android-text-font-size);
- .use-var(right, switch-android-text-gap-size);
+ .use-var-with-rtl(right, switch-android-text-gap-size);
}
}
@@ -80,12 +86,15 @@
&.checked {
.use-var(background-color, switch-ios-checked-background);
.@{prefix}-switch-text {
- right: auto;
- .use-var(left, switch-ios-text-gap-size);
+ .set-prop-with-rtl(right, auto);
+ .use-var-with-rtl(left, switch-ios-text-gap-size);
}
.@{prefix}-switch-inner {
.use-var(transform, switch-ios-checked-inner-transform);
.use-var(box-shadow, switch-ios-inner-box-shadow);
+ [dir="rtl"] & {
+ .use-var(transform, switch-ios-checked-inner-transform, "rotate(180deg)");
+ }
}
}
@@ -94,12 +103,15 @@
}
.@{prefix}-switch-text {
.use-var(font-size, switch-ios-text-font-size);
- .use-var(right, switch-ios-text-gap-size);
+ .use-var-with-rtl(right, switch-ios-text-gap-size);
}
.@{prefix}-switch-inner {
.use-var(width, switch-ios-inner-diameter-size);
.use-var(height, switch-ios-inner-diameter-size);
.onepx-border-var(all, switch-ios-inner-border-color, 50%);
+ [dir="rtl"] & {
+ transform: rotate(180deg);
+ }
}
&.disabled {
@@ -127,7 +139,7 @@
&-inner {
position: relative;
- left: 0;
+ .set-prop-with-rtl(left, 0);
top: 0;
display: flex;
align-items: center;
diff --git a/packages/arcodesign/components/tabs/FAQ.md b/packages/arcodesign/components/tabs/FAQ.md
index 2d7a1fdb..9dfdfd4c 100644
--- a/packages/arcodesign/components/tabs/FAQ.md
+++ b/packages/arcodesign/components/tabs/FAQ.md
@@ -6,4 +6,4 @@ onAfterChange 的调用是发生在动画执行后,很多 state 的更新在
## tabs 怎么配合 sticky 组件实现一个复杂的交互页面
-可以参考 [sticky-tabs](/#/components/sticky-tabs) 复合组件使用
+可以参考 [sticky-tabs](#/composite-components/sticky-tabs) 复合组件使用
diff --git a/packages/arcodesign/components/tabs/demo/style/mobile.less b/packages/arcodesign/components/tabs/demo/style/mobile.less
index dd2cd57d..4af7084d 100644
--- a/packages/arcodesign/components/tabs/demo/style/mobile.less
+++ b/packages/arcodesign/components/tabs/demo/style/mobile.less
@@ -24,7 +24,7 @@
.demo-tabs-add-extra {
position: absolute;
- right: 0;
+ .set-prop-with-rtl(right, 0);
top: 0;
background: linear-gradient(270deg, #fff 66.04%, rgba(255, 255, 255, 0) 105%);
.rem(width, 64);
@@ -36,6 +36,10 @@
align-items: center;
justify-content: flex-end;
font-weight: bold;
+ [dir="rtl"] & {
+ justify-content: flex-start;
+ transform: rotate(180deg);
+ }
}
.demo-tab-custom-bar {
diff --git a/packages/arcodesign/components/tabs/index.tsx b/packages/arcodesign/components/tabs/index.tsx
index e90b9860..a9f2c8fb 100644
--- a/packages/arcodesign/components/tabs/index.tsx
+++ b/packages/arcodesign/components/tabs/index.tsx
@@ -7,9 +7,10 @@ import React, {
useState,
useEffect,
useCallback,
+ useContext,
} from 'react';
-import { cls, nextTick } from '@arco-design/mobile-utils';
-import { ContextLayout } from '../context-provider';
+import { cls, nextTick, getOffset } from '@arco-design/mobile-utils';
+import { ContextLayout, GlobalContext } from '../context-provider';
import TabCell from './tab-cell';
import TabPane from './tab-pane';
import {
@@ -110,6 +111,7 @@ const Tabs = forwardRef((props: TabsProps, ref: Ref) => {
tabBarStopPropagation = true,
swipeEnergySaving = false,
} = props;
+ const { useRtl } = useContext(GlobalContext);
const domRef = useRef(null);
const cellRef = useRef(null);
const paneRef = useRef(null);
@@ -142,6 +144,8 @@ const Tabs = forwardRef((props: TabsProps, ref: Ref) => {
swipeable &&
tabDirection === 'vertical' &&
tabs.length > 1;
+ const horizontalUseRtl = tabDirection === 'vertical' && useRtl;
+ const rtlRatio = horizontalUseRtl ? -1 : 1;
useImperativeHandle(ref, () => ({
dom: domRef.current,
@@ -264,6 +268,7 @@ const Tabs = forwardRef((props: TabsProps, ref: Ref) => {
const posDisY = touchMoveY - touchStartYRef.current;
const absDisX = Math.abs(posDisX);
const absDisY = Math.abs(posDisY);
+ const comparedDis = posDisX * rtlRatio;
if (scrollingRef.current === null) {
scrollingRef.current = absDisX < absDisY;
}
@@ -278,12 +283,12 @@ const Tabs = forwardRef((props: TabsProps, ref: Ref) => {
return;
}
if (
- (activeIndexRef.current === 0 && posDisX > 0) ||
- (activeIndexRef.current === tabs.length - 1 && posDisX < 0)
+ (activeIndexRef.current === 0 && comparedDis > 0) ||
+ (activeIndexRef.current === tabs.length - 1 && comparedDis < 0)
) {
if (!touchStoppedRef.current && absDisX > stopTouchThreshold) {
touchStoppedRef.current = true;
- onTouchStopped && onTouchStopped(posDisX >= 0 ? -1 : 1);
+ onTouchStopped && onTouchStopped(comparedDis >= 0 ? -1 : 1);
}
setDistance(0);
return;
@@ -339,9 +344,10 @@ const Tabs = forwardRef((props: TabsProps, ref: Ref) => {
(Math.abs(dis) > maxSlice && Math.abs(dis) > distanceToChangeTab) ||
Math.abs(speed) > speedToChangeTab;
let newIndex = index;
- if (dis > 0 && needJump) {
+ const comparedDis = dis * rtlRatio;
+ if (comparedDis > 0 && needJump) {
newIndex = index - 1;
- } else if (dis < 0 && needJump) {
+ } else if (comparedDis < 0 && needJump) {
newIndex = index + 1;
}
nextTick(() => {
@@ -363,9 +369,10 @@ const Tabs = forwardRef((props: TabsProps, ref: Ref) => {
}
function updateLayout() {
+ const { width, height } = getOffset(domRef.current);
cellRef.current && cellRef.current.resetUnderlineStyle();
- setWrapWidth(domRef.current ? domRef.current.offsetWidth : 0);
- setWrapHeight(domRef.current ? domRef.current.offsetHeight : 0);
+ setWrapWidth(width || domRef.current?.offsetWidth || 0);
+ setWrapHeight(height || domRef.current?.offsetHeight || 0);
paneRef.current && paneRef.current.setCurrentHeight();
}
@@ -483,6 +490,7 @@ const Tabs = forwardRef((props: TabsProps, ref: Ref) => {
autoHeight={autoHeight}
onScroll={onScroll}
swipeEnergySaving={swipeEnergySaving}
+ rtlRatio={rtlRatio}
{...commonProps}
/>
diff --git a/packages/arcodesign/components/tabs/style/index.less b/packages/arcodesign/components/tabs/style/index.less
index f964f72b..440c68d5 100644
--- a/packages/arcodesign/components/tabs/style/index.less
+++ b/packages/arcodesign/components/tabs/style/index.less
@@ -310,12 +310,8 @@
&:not(.custom) {
- &.line {
- .use-var(margin-right, tabs-tab-bar-line-gutter);
-
- &.last {
- margin-right: 0;
- }
+ &.line:not(.last) {
+ .use-var-with-rtl(margin-right, tabs-tab-bar-line-gutter);
}
&.line,
@@ -337,17 +333,17 @@
}
&:not(:last-child) {
- .use-var(border-right, tabs-tab-bar-card-color, 1PX solid);
+ .use-var-with-rtl(border-right, tabs-tab-bar-card-color, 1PX solid);
}
&:first-of-type {
- .use-var(border-top-left-radius, tabs-tab-bar-card-border-radius);
- .use-var(border-bottom-left-radius, tabs-tab-bar-card-border-radius);
+ .use-var-with-rtl(border-top-left-radius, tabs-tab-bar-card-border-radius);
+ .use-var-with-rtl(border-bottom-left-radius, tabs-tab-bar-card-border-radius);
}
&:last-of-type {
- .use-var(border-top-right-radius, tabs-tab-bar-card-border-radius);
- .use-var(border-bottom-right-radius, tabs-tab-bar-card-border-radius);
+ .use-var-with-rtl(border-top-right-radius, tabs-tab-bar-card-border-radius);
+ .use-var-with-rtl(border-bottom-right-radius, tabs-tab-bar-card-border-radius);
}
}
@@ -361,14 +357,13 @@
&.tag,
&.tag-divide {
- .use-var(margin-right, tabs-tab-bar-tag-gutter);
.use-var(padding, tabs-tab-bar-tag-padding);
.rem(border-radius, 100);
.use-var(background, tabs-tab-bar-tag-background);
.use-var(color, tabs-tab-bar-tag-text-color);
- &.last {
- margin-right: 0;
+ &:not(.last) {
+ .use-var-with-rtl(margin-right, tabs-tab-bar-tag-gutter);
}
&.active {
diff --git a/packages/arcodesign/components/tabs/tab-cell-underline.tsx b/packages/arcodesign/components/tabs/tab-cell-underline.tsx
index c448b3c0..9ca31fe5 100644
--- a/packages/arcodesign/components/tabs/tab-cell-underline.tsx
+++ b/packages/arcodesign/components/tabs/tab-cell-underline.tsx
@@ -2,6 +2,7 @@ import React, {
CSSProperties,
forwardRef,
Ref,
+ useContext,
useEffect,
useImperativeHandle,
useMemo,
@@ -11,6 +12,7 @@ import React, {
import { addCssKeyframes, cls, nextTick, removeCssStyleDom } from '@arco-design/mobile-utils';
import { TabCellUnderlineProps, TabCellUnderlineRef, UnderlineStyle } from './type';
import { getStyleWithVendor, useRefState, useSystem } from '../_helpers';
+import { GlobalContext } from '../context-provider';
const TabCellUnderline = forwardRef(
(props: TabCellUnderlineProps, ref: Ref) => {
@@ -37,6 +39,7 @@ const TabCellUnderline = forwardRef(
getTabRect,
getTabCenterLeft,
} = props;
+ const { useRtl } = useContext(GlobalContext);
const [underlineStyle, setUnderlineStyle] = useState({});
const [caterpillar, caterpillarRef, setCaterpillar] = useRefState(false);
const [caterpillarDelay, setCaterpillarDelay] = useState(0);
@@ -46,6 +49,7 @@ const TabCellUnderline = forwardRef(
const isVertical = tabDirection === 'vertical';
const maxScaleWithDefault = caterpillarMaxScale || 2;
const translateZStr = translateZ ? ' translateZ(0)' : '';
+ const rtlRatio = isVertical && useRtl ? -1 : 1;
useImperativeHandle(
ref,
@@ -159,10 +163,11 @@ const TabCellUnderline = forwardRef(
}
function getDescIndex() {
- if (distance > 0) {
+ const comparedDis = distance * rtlRatio;
+ if (comparedDis > 0) {
return activeIndex - 1;
}
- if (distance < 0) {
+ if (comparedDis < 0) {
return activeIndex + 1;
}
return activeIndex;
@@ -182,7 +187,8 @@ const TabCellUnderline = forwardRef(
const currentLeft = getLineLeft(activeIndex);
const descIndex = getDescIndex();
const descLeft = getLineLeft(descIndex);
- const moveRatio = wrapWidth ? distance / wrapWidth : 0;
+ const comparedDis = distance * rtlRatio;
+ const moveRatio = wrapWidth ? comparedDis / wrapWidth : 0;
const leftOffset = moveRatio * (currentLeft - descLeft);
const direc = isVertical ? 'X' : 'Y';
const transStyle: CSSProperties =
@@ -206,7 +212,7 @@ const TabCellUnderline = forwardRef(
const widthOffset = moveRatio * (currentWidth - descWidth);
adaptiveStyle = {
[isVertical ? 'width' : 'height']:
- distance > 0 ? currentWidth - widthOffset : currentWidth + widthOffset,
+ comparedDis > 0 ? currentWidth - widthOffset : currentWidth + widthOffset,
willChange: 'width',
};
adaptiveOuterStyle = isVertical ? { width: 'auto' } : { height: 'auto' };
@@ -223,7 +229,7 @@ const TabCellUnderline = forwardRef(
return {
outer: {
transform: `translate${direc}(${
- distance > 0 ? currentLeft - leftOffset : currentLeft + leftOffset
+ comparedDis > 0 ? currentLeft - leftOffset : currentLeft + leftOffset
}px)${translateZStr}`,
...outerSize,
...adaptiveOuterStyle,
diff --git a/packages/arcodesign/components/tabs/tab-cell.tsx b/packages/arcodesign/components/tabs/tab-cell.tsx
index f9ad1da9..e8052c4b 100644
--- a/packages/arcodesign/components/tabs/tab-cell.tsx
+++ b/packages/arcodesign/components/tabs/tab-cell.tsx
@@ -6,11 +6,13 @@ import React, {
useState,
useEffect,
CSSProperties,
+ useContext,
} from 'react';
import { cls, scrollWithAnimation, nextTick } from '@arco-design/mobile-utils';
import { TabData, TabCellProps, TabCellRef, TabCellUnderlineRef, OffsetRect } from './type';
import { useSystem } from '../_helpers';
import TabCellUnderline from './tab-cell-underline';
+import { GlobalContext } from '../context-provider';
const TabCell = forwardRef((props: TabCellProps, ref: Ref) => {
const {
@@ -62,6 +64,7 @@ const TabCell = forwardRef((props: TabCellProps, ref: Ref) => {
tabBarStopPropagation,
} = props;
const prefix = `${prefixCls}-tab-cell`;
+ const { useRtl } = useContext(GlobalContext);
const domRef = useRef(null);
const underlineRef = useRef(null);
const allCellRectRef = useRef([]);
@@ -252,14 +255,16 @@ const TabCell = forwardRef((props: TabCellProps, ref: Ref) => {
if (!isVertical) {
return {};
}
+ const marginStart = useRtl ? 'marginRight' : 'marginLeft';
+ const marginEnd = useRtl ? 'marginLeft' : 'marginRight';
if (index === 0) {
return {
- marginRight: cellGutter,
- marginLeft: getCellPadding('left'),
+ [marginEnd]: cellGutter,
+ [marginStart]: getCellPadding('left'),
};
}
return {
- marginRight: index === tabs.length - 1 ? void 0 : cellGutter,
+ [marginEnd]: index === tabs.length - 1 ? void 0 : cellGutter,
};
}
diff --git a/packages/arcodesign/components/tabs/tab-pane.tsx b/packages/arcodesign/components/tabs/tab-pane.tsx
index 6befab76..5369213b 100644
--- a/packages/arcodesign/components/tabs/tab-pane.tsx
+++ b/packages/arcodesign/components/tabs/tab-pane.tsx
@@ -45,6 +45,7 @@ const TabPane = forwardRef((props: TabPaneProps, ref: Ref) => {
swipeEnergySaving,
changeIndex,
onScroll,
+ rtlRatio,
} = props;
const domRef = useRef(null);
const panesRef = useRef<(HTMLDivElement | null)[]>([]);
@@ -224,7 +225,7 @@ const TabPane = forwardRef((props: TabPaneProps, ref: Ref) => {
? {
width: `${100 * panes.length}%`,
transform: `translateX(${
- distance - wrapWidth * activeIndex
+ distance - wrapWidth * activeIndex * rtlRatio
}px)${translateStr}`,
}
: {
@@ -263,7 +264,7 @@ const TabPane = forwardRef((props: TabPaneProps, ref: Ref) => {
tabDirection === 'vertical'
? {
transform: `translateX(${
- distance - wrapWidth * (activeIndex - index)
+ distance - wrapWidth * (activeIndex - index) * rtlRatio
}px)${translateStr}`,
}
: {
diff --git a/packages/arcodesign/components/tabs/type.ts b/packages/arcodesign/components/tabs/type.ts
index 9c86f124..a801f50d 100644
--- a/packages/arcodesign/components/tabs/type.ts
+++ b/packages/arcodesign/components/tabs/type.ts
@@ -654,6 +654,7 @@ export interface TabPaneProps
paneTrans: boolean;
swipeable: boolean;
changeIndex: (newIndex: number, from?: string) => void;
+ rtlRatio: number;
}
export interface TabPaneRef {
diff --git a/packages/arcodesign/components/toast/index.tsx b/packages/arcodesign/components/toast/index.tsx
index 45bb0324..e02922b1 100644
--- a/packages/arcodesign/components/toast/index.tsx
+++ b/packages/arcodesign/components/toast/index.tsx
@@ -147,6 +147,7 @@ const Toast = forwardRef((props: ToastProps, ref: Ref) => {
} = props;
const closeTimerRef = useRef();
const domRef = useRef(null);
+ const wrapDomRef = useRef(null);
const isInitialMount = useRef(false);
const hasType = type && type !== 'info';
@@ -214,6 +215,7 @@ const Toast = forwardRef((props: ToastProps, ref: Ref) => {
'no-event': !disableBodyTouch,
})}
onClick={handleClickMask}
+ ref={wrapDomRef}
>
) => {
className={cls(`${prefixCls}-toast`, 'all-border-box', className)}
ref={domRef}
>
-
+
{renderComponent(`${prefixCls}-toast`)}
diff --git a/packages/arcodesign/components/transition/demo/index.md b/packages/arcodesign/components/transition/demo/index.md
index fab332b5..e43f2ba1 100644
--- a/packages/arcodesign/components/transition/demo/index.md
+++ b/packages/arcodesign/components/transition/demo/index.md
@@ -7,6 +7,7 @@ import { Transition, Cell } from '@arco-design/mobile-react';
export default function TransitionDemo() {
const [visible, setVisible] = React.useState(false);
+ const domRef = React.useRef();
return (<>
setVisible(true)} />
@@ -17,10 +18,12 @@ export default function TransitionDemo() {
type="fade"
mountOnEnter={true}
unmountOnExit={true}
+ nodeRef={domRef}
>
setVisible(false)}
+ ref={domRef}
>
|
>);
diff --git a/packages/arcodesign/package-lock.json b/packages/arcodesign/package-lock.json
index 274c5e7b..00df8547 100644
--- a/packages/arcodesign/package-lock.json
+++ b/packages/arcodesign/package-lock.json
@@ -1,12 +1,12 @@
{
"name": "@arco-design/mobile-react",
- "version": "2.27.4",
+ "version": "2.28.2",
"lockfileVersion": 2,
"requires": true,
"packages": {
"": {
"name": "@arco-design/mobile-react",
- "version": "2.25.3",
+ "version": "2.27.4",
"license": "ISC",
"dependencies": {
"@arco-design/transformable": "^1.0.0",
diff --git a/packages/arcodesign/package.json b/packages/arcodesign/package.json
index dfbf6444..a2f90246 100644
--- a/packages/arcodesign/package.json
+++ b/packages/arcodesign/package.json
@@ -1,6 +1,6 @@
{
"name": "@arco-design/mobile-react",
- "version": "2.27.4",
+ "version": "2.28.2",
"description": "",
"main": "cjs/index.js",
"module": "esm/index.js",
@@ -15,7 +15,7 @@
"author": "taoyiyue@bytedance.com",
"license": "ISC",
"dependencies": {
- "@arco-design/mobile-utils": "2.15.4",
+ "@arco-design/mobile-utils": "2.16.2",
"@arco-design/transformable": "^1.0.0",
"lodash.throttle": "^4.1.1",
"resize-observer-polyfill": "^1.5.1"
@@ -28,12 +28,26 @@
"jest": "^25.3.0"
},
"peerDependencies": {
+ "@types/react": ">=16.9.0",
+ "@types/react-dom": ">=16.9.0",
+ "@types/react-transition-group": ">=4.3.0",
"react": ">=16.9.0",
"react-dom": ">=16.9.0",
"react-transition-group": ">=4.3.0"
},
+ "peerDependenciesMeta": {
+ "@types/react": {
+ "optional": true
+ },
+ "@types/react-dom": {
+ "optional": true
+ },
+ "@types/react-transition-group": {
+ "optional": true
+ }
+ },
"publishConfig": {
"access": "public"
},
- "gitHead": "1ae5c477f0f78e51fd883214b25923a4dcfea8bb"
+ "gitHead": "f923a5d573d8af95e6b158614f8e7d8184afc481"
}
diff --git a/packages/arcodesign/tokens/app/arcodesign/default/css-variables.less b/packages/arcodesign/tokens/app/arcodesign/default/css-variables.less
index 9f16beae..4b1ea3e3 100644
--- a/packages/arcodesign/tokens/app/arcodesign/default/css-variables.less
+++ b/packages/arcodesign/tokens/app/arcodesign/default/css-variables.less
@@ -793,4 +793,20 @@
--divider-right-width: ~`pxtorem(28)`;
--divider-content-padding: ~`pxtorem(12)`;
--divider-padding: ~`pxtorem(16)`;
+ --skeleton-border-radius: ~`pxtorem(0)`;
+ --skeleton-background-color: #F2F3F5;
+ --skeleton-gradient-animation-color: rgba(255, 255, 255, 0.6);
+ --skeleton-breath-opacity: 0.4;
+ --skeleton-gradient-animation-timing-function: cubic-bezier(0.42, 0, 0.58, 1);
+ --skeleton-gradient-animation-duration: 1.5s;
+ --skeleton-breath-animation-duration: 1.5s;
+ --skeleton-title-height: ~`pxtorem(16)`;
+ --skeleton-paragraph-height: ~`pxtorem(16)`;
+ --skeleton-paragraph-margin-top: ~`pxtorem(12)`;
+ --skeleton-avatar-size: ~`pxtorem(32)`;
+ --skeleton-grid-icon-size: ~`pxtorem(32)`;
+ --skeleton-grid-text-width: ~`pxtorem(64)`;
+ --skeleton-grid-text-height: ~`pxtorem(16)`;
+ --skeleton-medium-gutter: ~`pxtorem(8)`;
+ --skeleton-large-gutter: ~`pxtorem(20)`;
}
diff --git a/packages/arcodesign/tokens/app/arcodesign/default/index.d.ts b/packages/arcodesign/tokens/app/arcodesign/default/index.d.ts
index 69b0c649..5f111f56 100644
--- a/packages/arcodesign/tokens/app/arcodesign/default/index.d.ts
+++ b/packages/arcodesign/tokens/app/arcodesign/default/index.d.ts
@@ -792,6 +792,22 @@ export interface ArcodesignToken extends Record
{
'divider-right-width': string;
'divider-content-padding': string;
'divider-padding': string;
+ 'skeleton-border-radius': string;
+ 'skeleton-background-color': string;
+ 'skeleton-gradient-animation-color': string;
+ 'skeleton-breath-opacity': string;
+ 'skeleton-gradient-animation-timing-function': string;
+ 'skeleton-gradient-animation-duration': string;
+ 'skeleton-breath-animation-duration': string;
+ 'skeleton-title-height': string;
+ 'skeleton-paragraph-height': string;
+ 'skeleton-paragraph-margin-top': string;
+ 'skeleton-avatar-size': string;
+ 'skeleton-grid-icon-size': string;
+ 'skeleton-grid-text-width': string;
+ 'skeleton-grid-text-height': string;
+ 'skeleton-medium-gutter': string;
+ 'skeleton-large-gutter': string;
}
declare const tokens: ArcodesignToken;
export default tokens;
\ No newline at end of file
diff --git a/packages/arcodesign/tokens/app/arcodesign/default/index.js b/packages/arcodesign/tokens/app/arcodesign/default/index.js
index f48a7f69..bdbb81a6 100644
--- a/packages/arcodesign/tokens/app/arcodesign/default/index.js
+++ b/packages/arcodesign/tokens/app/arcodesign/default/index.js
@@ -803,7 +803,23 @@ var tokens = {
"divider-left-width": "0.56rem",
"divider-right-width": "0.56rem",
"divider-content-padding": "0.24rem",
- "divider-padding": "0.32rem"
+ "divider-padding": "0.32rem",
+ "skeleton-border-radius": "0",
+ "skeleton-background-color": "#F2F3F5",
+ "skeleton-gradient-animation-color": "rgba(255, 255, 255, 0.6)",
+ "skeleton-breath-opacity": "0.4",
+ "skeleton-gradient-animation-timing-function": "cubic-bezier(0.42, 0, 0.58, 1)",
+ "skeleton-gradient-animation-duration": "1.5s",
+ "skeleton-breath-animation-duration": "1.5s",
+ "skeleton-title-height": "0.32rem",
+ "skeleton-paragraph-height": "0.32rem",
+ "skeleton-paragraph-margin-top": "0.24rem",
+ "skeleton-avatar-size": "0.64rem",
+ "skeleton-grid-icon-size": "0.64rem",
+ "skeleton-grid-text-width": "1.28rem",
+ "skeleton-grid-text-height": "0.32rem",
+ "skeleton-medium-gutter": "0.16rem",
+ "skeleton-large-gutter": "0.4rem"
};
var _default = tokens;
exports["default"] = _default;
\ No newline at end of file
diff --git a/packages/arcodesign/tokens/app/arcodesign/default/index.json b/packages/arcodesign/tokens/app/arcodesign/default/index.json
index 43a012d4..a1f18333 100644
--- a/packages/arcodesign/tokens/app/arcodesign/default/index.json
+++ b/packages/arcodesign/tokens/app/arcodesign/default/index.json
@@ -6629,6 +6629,196 @@
"en": "Size of the rounded corners of the square SearchBar"
}
},
+ "skeletonAvatarSize": {
+ "cssKey": "skeleton-avatar-size",
+ "desc": "骨架屏头像大小",
+ "override": "",
+ "value": "~`pxtorem(32)`",
+ "jsValue": "@getRem@32",
+ "staticValue": "0.64rem",
+ "localeDesc": {
+ "ch": "骨架屏头像大小",
+ "en": "Skeleton avatar size"
+ }
+ },
+ "skeletonBackgroundColor": {
+ "cssKey": "skeleton-background-color",
+ "desc": "骨架屏元素背景色",
+ "override": "",
+ "value": "#F2F3F5",
+ "jsValue": "#F2F3F5",
+ "staticValue": "#F2F3F5",
+ "localeDesc": {
+ "ch": "骨架屏元素背景色",
+ "en": "Skeleton element background color"
+ }
+ },
+ "skeletonBorderRadius": {
+ "cssKey": "skeleton-border-radius",
+ "desc": "骨架屏元素圆角",
+ "override": "",
+ "value": "~`pxtorem(0)`",
+ "jsValue": "@getRem@0",
+ "staticValue": "0",
+ "localeDesc": {
+ "ch": "骨架屏元素圆角",
+ "en": "Skeleton element border radius"
+ }
+ },
+ "skeletonBreathAnimationDuration": {
+ "cssKey": "skeleton-breath-animation-duration",
+ "desc": "骨架屏呼吸动效时间",
+ "override": "",
+ "value": "1.5s",
+ "jsValue": "1.5s",
+ "staticValue": "1.5s",
+ "localeDesc": {
+ "ch": "骨架屏呼吸动效时间",
+ "en": "Skeleton element breath animation duration"
+ }
+ },
+ "skeletonBreathOpacity": {
+ "cssKey": "skeleton-breath-opacity",
+ "desc": "骨架屏呼吸动效透明度",
+ "override": "",
+ "value": "0.4",
+ "jsValue": "0.4",
+ "staticValue": "0.4",
+ "localeDesc": {
+ "ch": "骨架屏呼吸动效透明度",
+ "en": "Skeleton element breath animation opacity"
+ }
+ },
+ "skeletonGradientAnimationColor": {
+ "cssKey": "skeleton-gradient-animation-color",
+ "desc": "骨架屏扫光动效高亮色",
+ "override": "",
+ "value": "rgba(255, 255, 255, 0.6)",
+ "jsValue": "rgba(255, 255, 255, 0.6)",
+ "staticValue": "rgba(255, 255, 255, 0.6)",
+ "localeDesc": {
+ "ch": "骨架屏扫光动效高亮色",
+ "en": "Skeleton element gradient animation highlight color"
+ }
+ },
+ "skeletonGradientAnimationDuration": {
+ "cssKey": "skeleton-gradient-animation-duration",
+ "desc": "骨架屏扫光动效时间",
+ "override": "",
+ "value": "1.5s",
+ "jsValue": "1.5s",
+ "staticValue": "1.5s",
+ "localeDesc": {
+ "ch": "骨架屏扫光动效时间",
+ "en": "Skeleton element gradient animation duration"
+ }
+ },
+ "skeletonGradientAnimationTimingFunction": {
+ "cssKey": "skeleton-gradient-animation-timing-function",
+ "desc": "骨架屏扫光动效曲线",
+ "override": "",
+ "value": "cubic-bezier(0.42, 0, 0.58, 1)",
+ "jsValue": "cubic-bezier(0.42, 0, 0.58, 1)",
+ "staticValue": "cubic-bezier(0.42, 0, 0.58, 1)",
+ "localeDesc": {
+ "ch": "骨架屏扫光动效曲线",
+ "en": "Skeleton element gradient animation timing function"
+ }
+ },
+ "skeletonGridIconSize": {
+ "cssKey": "skeleton-grid-icon-size",
+ "desc": "骨架屏金刚位图标区宽度",
+ "override": "",
+ "value": "~`pxtorem(32)`",
+ "jsValue": "@getRem@32",
+ "staticValue": "0.64rem",
+ "localeDesc": {
+ "ch": "骨架屏金刚位图标区宽度",
+ "en": "Skeleton grid item icon width"
+ }
+ },
+ "skeletonGridTextHeight": {
+ "cssKey": "skeleton-grid-text-height",
+ "desc": "骨架屏金刚位文字区高度",
+ "override": "",
+ "value": "~`pxtorem(16)`",
+ "jsValue": "@getRem@16",
+ "staticValue": "0.32rem",
+ "localeDesc": {
+ "ch": "骨架屏金刚位文字区高度",
+ "en": "Skeleton grid item text height"
+ }
+ },
+ "skeletonGridTextWidth": {
+ "cssKey": "skeleton-grid-text-width",
+ "desc": "骨架屏金刚位文字区宽度",
+ "override": "",
+ "value": "~`pxtorem(64)`",
+ "jsValue": "@getRem@64",
+ "staticValue": "1.28rem",
+ "localeDesc": {
+ "ch": "骨架屏金刚位文字区宽度",
+ "en": "Skeleton grid item text width"
+ }
+ },
+ "skeletonLargeGutter": {
+ "cssKey": "skeleton-large-gutter",
+ "desc": "骨架屏元素外边距,大尺寸",
+ "override": "",
+ "value": "~`pxtorem(20)`",
+ "jsValue": "@getRem@20",
+ "staticValue": "0.4rem",
+ "localeDesc": {
+ "ch": "骨架屏元素外边距,大尺寸"
+ }
+ },
+ "skeletonMediumGutter": {
+ "cssKey": "skeleton-medium-gutter",
+ "desc": "骨架屏元素外边距,中尺寸",
+ "override": "",
+ "value": "~`pxtorem(8)`",
+ "jsValue": "@getRem@8",
+ "staticValue": "0.16rem",
+ "localeDesc": {
+ "ch": "骨架屏元素外边距,中尺寸"
+ }
+ },
+ "skeletonParagraphHeight": {
+ "cssKey": "skeleton-paragraph-height",
+ "desc": "骨架屏段落行高度",
+ "override": "",
+ "value": "~`pxtorem(16)`",
+ "jsValue": "@getRem@16",
+ "staticValue": "0.32rem",
+ "localeDesc": {
+ "ch": "骨架屏段落行高度",
+ "en": "Skeleton paragraph line height"
+ }
+ },
+ "skeletonParagraphMarginTop": {
+ "cssKey": "skeleton-paragraph-margin-top",
+ "desc": "骨架屏各段落行间距",
+ "override": "",
+ "value": "~`pxtorem(12)`",
+ "jsValue": "@getRem@12",
+ "staticValue": "0.24rem",
+ "localeDesc": {
+ "ch": "骨架屏各段落行间距",
+ "en": "Margin top between skeleton paragraph lines"
+ }
+ },
+ "skeletonTitleHeight": {
+ "cssKey": "skeleton-title-height",
+ "desc": "骨架屏标题高度",
+ "override": "",
+ "value": "~`pxtorem(16)`",
+ "jsValue": "@getRem@16",
+ "staticValue": "0.32rem",
+ "localeDesc": {
+ "ch": "骨架屏标题高度",
+ "en": "Skeleton title height"
+ }
+ },
"sliderHasMarkPaddingBottom": {
"cssKey": "slider-has-mark-padding-bottom",
"desc": "slider 有标记时的底部内边距",
diff --git a/packages/arcodesign/tokens/app/arcodesign/default/index.less b/packages/arcodesign/tokens/app/arcodesign/default/index.less
index 9c3860b9..dc2ab27c 100644
--- a/packages/arcodesign/tokens/app/arcodesign/default/index.less
+++ b/packages/arcodesign/tokens/app/arcodesign/default/index.less
@@ -792,4 +792,20 @@
@divider-right-width: ~`pxtorem(28)`;
@divider-content-padding: ~`pxtorem(12)`;
@divider-padding: ~`pxtorem(16)`;
+@skeleton-border-radius: ~`pxtorem(0)`;
+@skeleton-background-color: #F2F3F5;
+@skeleton-gradient-animation-color: rgba(255, 255, 255, 0.6);
+@skeleton-breath-opacity: 0.4;
+@skeleton-gradient-animation-timing-function: cubic-bezier(0.42, 0, 0.58, 1);
+@skeleton-gradient-animation-duration: 1.5s;
+@skeleton-breath-animation-duration: 1.5s;
+@skeleton-title-height: ~`pxtorem(16)`;
+@skeleton-paragraph-height: ~`pxtorem(16)`;
+@skeleton-paragraph-margin-top: ~`pxtorem(12)`;
+@skeleton-avatar-size: ~`pxtorem(32)`;
+@skeleton-grid-icon-size: ~`pxtorem(32)`;
+@skeleton-grid-text-width: ~`pxtorem(64)`;
+@skeleton-grid-text-height: ~`pxtorem(16)`;
+@skeleton-medium-gutter: ~`pxtorem(8)`;
+@skeleton-large-gutter: ~`pxtorem(20)`;
diff --git a/packages/arcodesign/tokens/src/arcodesign/default/index.js b/packages/arcodesign/tokens/src/arcodesign/default/index.js
index 1fcd953f..1a4d7d2d 100644
--- a/packages/arcodesign/tokens/src/arcodesign/default/index.js
+++ b/packages/arcodesign/tokens/src/arcodesign/default/index.js
@@ -4018,6 +4018,84 @@ function getCompTokens() {
* @en Top and Bottom padding of divider
*/
dividerPadding: getRem(16),
+ /**
+ * 骨架屏元素圆角
+ * @en Skeleton element border radius
+ */
+ skeletonBorderRadius: getRem(0),
+ /**
+ * 骨架屏元素背景色
+ * @en Skeleton element background color
+ */
+ skeletonBackgroundColor: '#F2F3F5',
+ /**
+ * 骨架屏扫光动效高亮色
+ * @en Skeleton element gradient animation highlight color
+ */
+ skeletonGradientAnimationColor: 'rgba(255, 255, 255, 0.6)',
+ /**
+ * 骨架屏呼吸动效透明度
+ * @en Skeleton element breath animation opacity
+ */
+ skeletonBreathOpacity: '0.4',
+ /**
+ * 骨架屏扫光动效曲线
+ * @en Skeleton element gradient animation timing function
+ */
+ skeletonGradientAnimationTimingFunction: 'cubic-bezier(0.42, 0, 0.58, 1)',
+ /**
+ * 骨架屏扫光动效时间
+ * @en Skeleton element gradient animation duration
+ */
+ skeletonGradientAnimationDuration: '1.5s',
+ /**
+ * 骨架屏呼吸动效时间
+ * @en Skeleton element breath animation duration
+ */
+ skeletonBreathAnimationDuration: '1.5s',
+ /**
+ * 骨架屏标题高度
+ * @en Skeleton title height
+ */
+ skeletonTitleHeight: getRem(16),
+ /**
+ * 骨架屏段落行高度
+ * @en Skeleton paragraph line height
+ */
+ skeletonParagraphHeight: getRem(16),
+ /**
+ * 骨架屏各段落行间距
+ * @en Margin top between skeleton paragraph lines
+ */
+ skeletonParagraphMarginTop: getRem(12),
+ /**
+ * 骨架屏头像大小
+ * @en Skeleton avatar size
+ */
+ skeletonAvatarSize: getRem(32),
+ /**
+ * 骨架屏金刚位图标区宽度
+ * @en Skeleton grid item icon width
+ */
+ skeletonGridIconSize: getRem(32),
+ /**
+ * 骨架屏金刚位文字区宽度
+ * @en Skeleton grid item text width
+ */
+ skeletonGridTextWidth: getRem(64),
+ /**
+ * 骨架屏金刚位文字区高度
+ * @en Skeleton grid item text height
+ */
+ skeletonGridTextHeight: getRem(16),
+ /**
+ * 骨架屏元素外边距,中尺寸
+ */
+ skeletonMediumGutter: getRem(8),
+ /**
+ * 骨架屏元素外边距,大尺寸
+ */
+ skeletonLargeGutter: getRem(20),
};
}
diff --git a/packages/common-widgets/CHANGELOG.md b/packages/common-widgets/CHANGELOG.md
index 10860c5e..3ef250b3 100644
--- a/packages/common-widgets/CHANGELOG.md
+++ b/packages/common-widgets/CHANGELOG.md
@@ -3,6 +3,56 @@
All notable changes to this project will be documented in this file.
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
+## [2.16.2](https://github.com/arco-design/arco-design-mobile/compare/@arco-design/mobile-utils@2.16.1...@arco-design/mobile-utils@2.16.2) (2023-08-07)
+
+
+### Bug Fixes
+
+* `Form` bind this in form-item ([#148](https://github.com/arco-design/arco-design-mobile/issues/148)) ([5616d53](https://github.com/arco-design/arco-design-mobile/commit/5616d537b921b009df61addccf966c5e9363a0cb))
+
+
+
+
+
+## [2.16.1](https://github.com/arco-design/arco-design-mobile/compare/@arco-design/mobile-utils@2.16.0...@arco-design/mobile-utils@2.16.1) (2023-08-02)
+
+
+### Bug Fixes
+
+* add [@types](https://github.com/types) to peerDependencies ([42f3d5a](https://github.com/arco-design/arco-design-mobile/commit/42f3d5ab19144702d7c371c6cbd1aa031a690abe))
+
+
+
+
+
+# [2.16.0](https://github.com/arco-design/arco-design-mobile/compare/@arco-design/mobile-utils@2.15.5...@arco-design/mobile-utils@2.16.0) (2023-07-14)
+
+
+### Bug Fixes
+
+* `Collapse` update with the latest opened ([#140](https://github.com/arco-design/arco-design-mobile/issues/140)) ([b963787](https://github.com/arco-design/arco-design-mobile/commit/b96378761557f4d90f09f789f662e9d3588c3cbd))
+* `ImagePreview` fix scroll through ([ea3f9bc](https://github.com/arco-design/arco-design-mobile/commit/ea3f9bc5d0980f70c81e2de99084e0a11187b3c1))
+
+
+### Features
+
+* RTL support for `Badge`, `Button`, `Cell`, `Checkbox`, `Form`, `Radio`, `Rate`, `Switch` and `Tabs` ([#135](https://github.com/arco-design/arco-design-mobile/issues/135)) ([97de976](https://github.com/arco-design/arco-design-mobile/commit/97de976ba514ec0f48103bd4f0c535ebceb8981a))
+
+
+
+
+
+## [2.15.5](https://github.com/arco-design/arco-design-mobile/compare/@arco-design/mobile-utils@2.15.4...@arco-design/mobile-utils@2.15.5) (2023-07-04)
+
+
+### Bug Fixes
+
+* error caught when using "getComputedStyle" ([#129](https://github.com/arco-design/arco-design-mobile/issues/129)) ([daa8f67](https://github.com/arco-design/arco-design-mobile/commit/daa8f67961d9d2751a14c0c3f7759b54fe0579cb))
+
+
+
+
+
## [2.15.4](https://github.com/arco-design/arco-design-mobile/compare/@arco-design/mobile-utils@2.15.3...@arco-design/mobile-utils@2.15.4) (2023-05-19)
**Note:** Version bump only for package @arco-design/mobile-utils
diff --git a/packages/common-widgets/package-lock.json b/packages/common-widgets/package-lock.json
index 4764a776..c476511d 100644
--- a/packages/common-widgets/package-lock.json
+++ b/packages/common-widgets/package-lock.json
@@ -1,12 +1,12 @@
{
"name": "@arco-design/mobile-utils",
- "version": "2.15.4",
+ "version": "2.16.2",
"lockfileVersion": 2,
"requires": true,
"packages": {
"": {
"name": "@arco-design/mobile-utils",
- "version": "2.15.4",
+ "version": "2.16.0",
"license": "ISC",
"dependencies": {
"es6-promise": "^4.2.8"
diff --git a/packages/common-widgets/package.json b/packages/common-widgets/package.json
index 849d17a5..b6b2167a 100644
--- a/packages/common-widgets/package.json
+++ b/packages/common-widgets/package.json
@@ -1,6 +1,6 @@
{
"name": "@arco-design/mobile-utils",
- "version": "2.15.4",
+ "version": "2.16.2",
"description": "",
"main": "cjs/index.js",
"module": "esm/index.js",
@@ -13,7 +13,7 @@
"publishConfig": {
"access": "public"
},
- "gitHead": "1ae5c477f0f78e51fd883214b25923a4dcfea8bb",
+ "gitHead": "f923a5d573d8af95e6b158614f8e7d8184afc481",
"dependencies": {
"es6-promise": "^4.2.8"
}
diff --git a/packages/common-widgets/style/mixin.less b/packages/common-widgets/style/mixin.less
index b36cee72..64559abc 100644
--- a/packages/common-widgets/style/mixin.less
+++ b/packages/common-widgets/style/mixin.less
@@ -258,6 +258,12 @@
@margin-right: margin-left;
@padding-left: padding-right;
@padding-right: padding-left;
+ @border-right: border-left;
+ @border-left: border-right;
+ @border-top-left-radius: border-top-right-radius;
+ @border-bottom-left-radius: border-bottom-right-radius;
+ @border-top-right-radius: border-top-left-radius;
+ @border-bottom-right-radius: border-bottom-left-radius;
}
@property-name: @property-map[@@origin-property];
}
@@ -331,7 +337,6 @@
.process-title-color-with-config {
color: @color;
}
-
.finish-tail-color-with-config::before,
.finish-tail-color-with-config::after,
.process-tail-color-with-config::before,
diff --git a/packages/common-widgets/utils/dom.ts b/packages/common-widgets/utils/dom.ts
index b9a2079c..a2f5afc2 100644
--- a/packages/common-widgets/utils/dom.ts
+++ b/packages/common-widgets/utils/dom.ts
@@ -43,7 +43,7 @@ export function freeEleScroll(
* @param parentEl 父节点
* @param childrenEl 子节点
*/
-export const isContains = (parentEl: HTMLElement | null, childrenEl: HTMLElement | null) => {
+export function isContains(parentEl: HTMLElement | null, childrenEl: HTMLElement | null) {
if (!parentEl || !childrenEl) return false;
if (parentEl.contains) {
return parentEl.contains(childrenEl);
@@ -56,7 +56,7 @@ export const isContains = (parentEl: HTMLElement | null, childrenEl: HTMLElement
parent = parent.parentNode as HTMLElement;
}
return false;
-};
+}
export function execRAF(fn) {
try {
@@ -74,7 +74,7 @@ export function scrollWithAnimation(
bezier: [number, number, number, number] = [0.34, 0.69, 0.1, 1],
type: 'by' | 'to' = 'to',
) {
- const targetTop = Math.max(0, type === 'by' ? initTop + target : target);
+ const targetTop = type === 'by' ? initTop + target : target;
const start = Date.now();
const fn = () => {
const p = (Date.now() - start) / duration;
@@ -429,3 +429,11 @@ export function convertCssDuration(ele: HTMLElement, property: string) {
}
return 0;
}
+
+export function safeGetComputedStyle(element: HTMLElement) {
+ try {
+ return window.getComputedStyle(element);
+ } catch (e) {
+ return {} as CSSStyleDeclaration;
+ }
+}
diff --git a/packages/common-widgets/utils/is.ts b/packages/common-widgets/utils/is.ts
index e547d6ea..38787365 100644
--- a/packages/common-widgets/utils/is.ts
+++ b/packages/common-widgets/utils/is.ts
@@ -34,7 +34,7 @@ export function isEmptyArray(obj: Array): boolean {
return isArray(obj) && !obj?.length;
}
-export const isDeepEqual = (obj: any, sub: any): boolean => {
+export function isDeepEqual(obj: any, sub: any): boolean {
if (typeof obj !== 'object' || typeof sub !== 'object' || obj === null || sub === null) {
return obj === sub;
}
@@ -49,4 +49,4 @@ export const isDeepEqual = (obj: any, sub: any): boolean => {
if (!isDeepEqual(obj[key], sub[key])) return false;
}
return true;
-};
+}
diff --git a/scripts/sites/plugins/DemoGeneratePlugin/generate-demo.js b/scripts/sites/plugins/DemoGeneratePlugin/generate-demo.js
index 36a01ccb..5368907f 100644
--- a/scripts/sites/plugins/DemoGeneratePlugin/generate-demo.js
+++ b/scripts/sites/plugins/DemoGeneratePlugin/generate-demo.js
@@ -11,7 +11,7 @@ const compositeCompFolder = 'sites/mobile/pages/composite-comp';
const compositeFolder = 'sites/composite-comp';
const srcFolder = 'packages/arcodesign';
const packageName = '@arco-design/mobile-react';
-const compFolder = path.join(srcFolder, 'components');
+const compFolder = path.posix.join(srcFolder, 'components');
const compPath = path.join(rootPath, compFolder);
const sitePath = path.join(rootPath, siteFolder);
const compositeCompPath = path.join(rootPath, compositeCompFolder);
@@ -25,7 +25,7 @@ function renderSource({ comp, demoName, depsCompSet, language, compileEnv, demoP
const reg = new RegExp(packageName, 'g');
let order = 0;
-
+
renderer.code = code => {
const filename = `_${utils.getCompName(demoName)}`;
const content = `import React from 'react';
@@ -165,9 +165,9 @@ function generateSiteDemo({
return new Promise((resolve) => {
// 内部工具js不处理
if (/^_/.test(comp)) {
- return resolve()
+ return resolve();
}
-
+
depsCompSet.add(comp);
const docPath = path.join(sitePath, comp);
@@ -181,7 +181,7 @@ function generateSiteDemo({
}
const demoSource = [];
let importStr = `import React from 'react';\n`;
-
+
demos.forEach(name => {
if (name.indexOf('.md') < 0) {
return resolve();
@@ -256,7 +256,7 @@ function generateSiteDemo({
});
Promise.all(promises).then(() => {
- console.log(`>>> Generate ${language} demo files finished`);
+ console.log(`>>> Generate ${language} demo files finished`);
});
if (!compileComps.length) {
@@ -343,9 +343,9 @@ function generateSiteCompositeDemo({
demoCompSet.add(comp);
}
});
-
+
demoSource.sort((a, b) => a.order - b.order);
-
+
const demoStylePath = path.join(demoPath, 'style');
if (fs.existsSync(demoStylePath)) {
const styles = fs.readdirSync(demoStylePath);
@@ -379,7 +379,7 @@ function generateSiteCompositeDemo({
});
Promise.all(promises).then(() => {
- console.log(`>>> Generate ${language} composite demo files finished`)
+ console.log(`>>> Generate ${language} composite demo files finished`);
});
[...demoCompSet].map(e => {
@@ -389,7 +389,7 @@ function generateSiteCompositeDemo({
compDocsImportStr += `import ${importName} from './${e}${tsxFileSuffix ? `/index${tsxFileSuffix}` : ''}';\n`;
compDocsStr += ` '${route}': ${importName},\n`;
});
-const docEntryStr = `${compDocsImportStr}
+ const docEntryStr = `${compDocsImportStr}
const docs = {\n${compDocsStr}};
export default docs;
@@ -431,4 +431,4 @@ function generateDemo({
}
}
-module.exports = generateDemo;
\ No newline at end of file
+module.exports = generateDemo;
diff --git a/sites/composite-comp/sticky-tabs/sticky-tab-css.md b/sites/composite-comp/sticky-tabs/sticky-tab-css.md
new file mode 100644
index 00000000..33697291
--- /dev/null
+++ b/sites/composite-comp/sticky-tabs/sticky-tab-css.md
@@ -0,0 +1,57 @@
+## 使用 position: sticky 替换 Sticky @en{Replace Sticky with position: sticky}
+
+当使用 sticky tabs 复合组件时,安卓机型经常会出现 tabBar 闪动的情况,可以通过 css 实现 sticky 的方式去优化性能
+注意:sticky css 属性兼容性有待考证;arco 已验证安卓5.1.1 vivoX7 支持;iPhone6plus ios 11.2.5不支持
+
+```js
+import { Tabs, Sticky, Portal } from '@arco-design/mobile-react';
+
+const tabData = [
+ { title: 'Example 1' },
+ { title: 'Example 2' },
+ { title: 'Example 3' },
+];
+
+export default function StickyTabsCss() {
+ const tabBarRef = React.useRef(null);
+
+ const supportsCSS = (attribute, value) => {
+ if (window && window.CSS) {
+ if (typeof value === 'undefined') {
+ return window.CSS.supports(attribute);
+ }
+ return window.CSS.supports(attribute, value);
+ }
+
+ const elem = document.createElement('div');
+ if (attribute in elem.style) {
+ elem.style[attribute] = value;
+ return elem.style[attribute] === value;
+ }
+ return false;
+ };
+
+ return (
+
+
+ placeholder placeholder placeholder placeholder placeholder placeholder placeholder placeholder placeholder placeholder placeholder placeholder
+
+
+
+ supportsCSS('position', 'sticky') ? (
+ tabBarRef.current}>{TabBar}
+ ) : (
+ document.getElementById('sticky-tabs-wrapper-css')} topOffset={0}>{TabBar}
+ )}
+ >
+ content 1
+ content 2
+ content 3
+
+
+ );
+}
+```
diff --git a/sites/composite-comp/sticky-tabs/style/mobile.less b/sites/composite-comp/sticky-tabs/style/mobile.less
index 59abda11..a2248e51 100644
--- a/sites/composite-comp/sticky-tabs/style/mobile.less
+++ b/sites/composite-comp/sticky-tabs/style/mobile.less
@@ -1,7 +1,8 @@
@import "../../../../packages/arcodesign/style/mixin.less";
#sticky-tabs-wrapper-position,
-#sticky-tabs-wrapper-hide {
+#sticky-tabs-wrapper-hide,
+#sticky-tabs-wrapper-css {
height: 500px;
overflow: scroll;
@@ -17,3 +18,12 @@
}
}
+#sticky-tabs-wrapper-css {
+ overflow: visible;
+
+ .sticky-tabs-wrapper-css-nav-bar {
+ position: sticky;
+ background: #fff;
+ top: 44px;
+ }
+}
diff --git a/sites/pc/static/md/qa.en-US.md b/sites/pc/static/md/qa.en-US.md
index dc4fa424..aebcc1df 100644
--- a/sites/pc/static/md/qa.en-US.md
+++ b/sites/pc/static/md/qa.en-US.md
@@ -41,4 +41,12 @@ import { ContextProvider } from '@arco-design/mobile-react';
return (
)"
-```
\ No newline at end of file
+```
+
+## Q:When using methods such as Toast.toast to call components, the configuration passed to ContextProvider cannot be received?
+
+The component called by the method is not a subcomponent under the root node of the page, so the configuration of ContextProvider needs to be passed to the method, such as: `Toast.toast({ content: 'Tips' }, { prefixCls: 'aa' })`. (Supported after `2.24.0`)
+
+## Q: AutoFocus does not work when using Input/Textarea/SearchBar
+
+autoFocus is not supported on some models, the bottom layer of the component can only try focus, but whether it can focus or not depends on the model
diff --git a/sites/pc/static/md/qa.md b/sites/pc/static/md/qa.md
index 298ea3ad..8992d801 100644
--- a/sites/pc/static/md/qa.md
+++ b/sites/pc/static/md/qa.md
@@ -45,4 +45,8 @@ return (
## Q:用 Toast.toast 等方法调用组件时,接不到传给 ContextProvider 的配置?
-使用方法调用的组件不是页面根节点下的子组件,因此需将 ContextProvider 的配置传给方法,如:`Toast.toast({ content: 'Tips' }, { prefixCls: 'aa' })`。(`2.24.0`之后支持)
\ No newline at end of file
+使用方法调用的组件不是页面根节点下的子组件,因此需将 ContextProvider 的配置传给方法,如:`Toast.toast({ content: 'Tips' }, { prefixCls: 'aa' })`。(`2.24.0`之后支持)
+
+## Q:使用 Input/Textarea/SearchBar 的 autoFocus 不生效
+
+autoFocus 在一些机型上是不支持的,组件底层只能尝试 focus,但是到底能不能聚焦还得看机型