Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix(badge): 四端适配 #2620

Merged
merged 21 commits into from
Nov 11, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 0 additions & 1 deletion scripts/rn/copy-file.js
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,6 @@ const removeFile = async (url) => {
}

const modify = (fileUrl, importStatement) => {
// if(!fse.ensureFileSync(fileUrl)) return
fse.readFile(fileUrl, 'utf8').then((content) => {
let modifiedContent = content
modifiedContent = [importStatement, modifiedContent.slice(0)].join('')
Expand Down
2 changes: 1 addition & 1 deletion src/config.json
Original file line number Diff line number Diff line change
Expand Up @@ -716,7 +716,7 @@
"author": "dsj"
},
{
"version": "2.0.0",
"version": "3.0.0",
"name": "Badge",
"type": "component",
"cName": "徽标",
Expand Down
4 changes: 2 additions & 2 deletions src/packages/badge/__test__/__snapshots__/badge.spec.tsx.snap
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ exports[`should match custom icon 1`] = `
class="nut-badge"
>
<div
class="nut-badge-icon"
class="nut-badge-content nut-badge-icon"
>
<svg
aria-labelledby="Checklist"
Expand All @@ -33,7 +33,7 @@ exports[`should match snapshot 1`] = `
>
<div
class="nut-badge-content nut-badge-sup nut-badge-one"
style="top: 4px; right: 8px;"
style="top: -4px; right: 8px;"
>
8
</div>
Expand Down
8 changes: 4 additions & 4 deletions src/packages/badge/__test__/badge.spec.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -35,15 +35,15 @@ test('should match top、right: bad number', () => {
})

test('should match top、right: have px', () => {
const { container } = render(<Badge value={10} top="-10px" right="0" />)
const { container } = render(<Badge value={10} top="-10" right="0" />)
const badgeContent = container.querySelectorAll('.nut-badge-content')[0]
expect(badgeContent).toHaveStyle({ top: '-10px', right: '0px' })
expect(badgeContent).toHaveStyle({ top: '10px', right: '0px' })
})

test('should match top、right: float', () => {
const { container } = render(<Badge value={10} top="-10.8px" right="0.5px" />)
const { container } = render(<Badge value={10} top="-10.8" right="0.5px" />)
const badgeContent = container.querySelectorAll('.nut-badge-content')[0]
expect(badgeContent).toHaveStyle({ top: '-10.8px', right: '0.5px' })
expect(badgeContent).toHaveStyle({ top: '10.8px', right: '0.5px' })
})

test('should match custom color', () => {
Expand Down
39 changes: 22 additions & 17 deletions src/packages/badge/badge.harmony.css
Original file line number Diff line number Diff line change
@@ -1,15 +1,20 @@
.nut-badge {
position: relative;
display: inline-block;
display: inline-flex;
width: auto;
/* #ifdef harmony */
min-width: 1px;
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

应该写 min-width:1px; #ifndef harmony min-width:auto。因为组件库纯H5 和 多端同一套样式文件。

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

已修改

/* #endif */
/* #ifndef harmony */
min-width: auto;
/* #endif */
}
.nut-badge-icon {
position: absolute;
display: flex;
justify-content: center;
align-items: center;
background: linear-gradient(135deg, #FF0F23 0%, #FF0F23 100%);
top: -10%;
right: -15%;
background: linear-gradient(135deg, #ff475d 0%, #ff0f23 100%);
padding: 3px;
text-align: center;
border: 0px solid #ffffff;
Expand All @@ -27,7 +32,12 @@
display: flex;
justify-content: center;
align-items: center;
background: linear-gradient(135deg, #FF0F23 0%, #FF0F23 100%);
/* #ifdef harmony */
background: #ff0f23;
/* #endif */
/* #ifndef harmony */
background: linear-gradient(135deg, #ff475d 0%, #ff0f23 100%);
/* #endif */
color: #fff;
padding: 0 4px;
font-size: 10px;
Expand All @@ -45,7 +55,9 @@
padding: 0;
}
.nut-badge-content {
transform: translateY(-50%) translateX(100%);
/* #ifndef rn */
transform: translateX(100%);
/* #endif */
}
.nut-badge-dot {
width: 7px;
Expand All @@ -54,15 +66,8 @@
border-radius: 7px;
padding: 0;
}

[dir=rtl] .nut-badge-icon,
.nut-rtl .nut-badge-icon {
right: auto;
left: -15%;
}
[dir=rtl] .nut-badge-content {
transform: translateY(-50%) translateX(-100%);
}
.nut-rtl .nut-badge-content {
transform: translateY(-50%) translateX(-100%);
.nut-badge-outline {
background: #ffffff;
border: 1px solid #ff0f23;
color: #ff0f23;
}
42 changes: 18 additions & 24 deletions src/packages/badge/badge.scss
Original file line number Diff line number Diff line change
@@ -1,15 +1,19 @@
.nut-badge {
position: relative;
display: inline-block;

display: inline-flex;
width: auto;
/* #ifdef harmony */
min-width: 1px;
/* #endif */
/* #ifndef harmony */
min-width: auto;
/* #endif */
&-icon {
position: absolute;
display: flex;
justify-content: center;
align-items: center;
background: $badge-background-color;
top: -10%;
right: -15%;
padding: $badge-icon-padding;
text-align: center;
border: $badge-border;
Expand All @@ -29,7 +33,12 @@
display: flex;
justify-content: center;
align-items: center;
/* #ifdef harmony */
background: $color-primary;
/* #endif */
/* #ifndef harmony */
background: $badge-background-color;
/* #endif */
color: $badge-color;
padding: $badge-padding;
font-size: $badge-font-size;
Expand All @@ -49,7 +58,9 @@
}

&-content {
/* #ifndef rn */
transform: $badge-content-transform;
/* #endif */
}

&-dot {
Expand All @@ -61,25 +72,8 @@
}

&-outline {
.nut-badge-content {
background: $color-primary-text;
border: 1px solid $color-primary;
color: $color-primary;
}
}
}

[dir='rtl'] .nut-badge,
.nut-rtl .nut-badge {
&-icon {
right: auto;
left: -15%;
}

&-content {
transform: var(
--nutui-badge-content-transform,
translateY(-50%) translateX(-100%)
);
background: $color-primary-text;
border: 1px solid $color-primary;
color: $color-primary;
}
}
89 changes: 67 additions & 22 deletions src/packages/badge/badge.taro.tsx
Original file line number Diff line number Diff line change
@@ -1,8 +1,18 @@
import React, { CSSProperties, FunctionComponent, ReactNode } from 'react'
import React, {
CSSProperties,
FunctionComponent,
ReactNode,
useEffect,
useRef,
useState,
} from 'react'
import classNames from 'classnames'
import { View } from '@tarojs/components'
import { BasicComponent, ComponentDefaults } from '@/utils/typings'
import { useRtl } from '@/packages/configprovider/index.taro'
import pxTransform from '@/utils/px-transform'
import { getRectByTaro } from '@/utils/get-rect-by-taro'
import { harmony, rn } from '@/utils/platform-taro'

export type BadgeFill = 'solid' | 'outline'
export interface BadgeProps extends BasicComponent {
Expand Down Expand Up @@ -42,9 +52,10 @@ export const Badge: FunctionComponent<Partial<BadgeProps>> = (props) => {
...props,
}
const classPrefix = 'nut-badge'
const classes = classNames(classPrefix, className, {
[`${classPrefix}-${fill}`]: fill === 'outline',
})
const isHarmony = harmony()
const classes = classNames(classPrefix, className)
const badgeRef = useRef(null)
const [contentStyle, setContentStyle] = useState({})

function content() {
if (dot || typeof value === 'object' || value === 0) return null
Expand All @@ -66,41 +77,75 @@ export const Badge: FunctionComponent<Partial<BadgeProps>> = (props) => {
if (typeof value === 'string' && value) return value
}

const contentClasses = classNames(
{ [`${classPrefix}-dot`]: dot },
`${classPrefix}-content`,
{ [`${classPrefix}-sup`]: isNumber() || isString() || dot },
{
[`${classPrefix}-one`]:
typeof content() === 'string' && `${content()}`?.length === 1,
const contentClasses = classNames(`${classPrefix}-content`, {
[`${classPrefix}-sup`]: isNumber() || isString() || dot,
[`${classPrefix}-one`]:
typeof content() === 'string' && `${content()}`?.length === 1,
[`${classPrefix}-dot`]: dot,
[`${classPrefix}-${fill}`]: fill === 'outline',
})

useEffect(() => {
if (badgeRef.current) {
getPositionStyle()
}
)
const getStyle = () => {
}, [])
const getPositionStyle = async () => {
const style: CSSProperties = {}
style.top = `${Number(top) || parseFloat(String(top)) || 0}px`
const dir = rtl ? 'left' : 'right'
style[dir] = `${Number(right) || parseFloat(String(right)) || 0}px`
style.top = pxTransform(-Number(top) || 0)
if (rn()) {
const reacts = await getRectByTaro(badgeRef.current)
style.left =
reacts?.width && reacts?.width > Number(right)
? pxTransform(reacts.width - Number(right))
: 0
} else {
const dir = rtl ? 'left' : 'right'
style[dir] = isHarmony
? pxTransform(Number(right))
: `${Number(right) || parseFloat(String(right)) || 0}px`
}
setContentStyle(style)
}

Comment on lines +93 to +109
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

建议简化平台特定的定位逻辑

当前的定位逻辑较为复杂,建议将平台特定的逻辑提取到单独的函数中。

+const calculateRNPosition = async (ref: any, right: string | number) => {
+  const reacts = await getRectByTaro(ref)
+  return reacts?.width && reacts?.width > Number(right)
+    ? pxTransform(reacts.width - Number(right))
+    : 0
+}

+const calculateHarmonyPosition = (right: string | number, rtl: boolean) => {
+  const dir = rtl ? 'left' : 'right'
+  return {
+    [dir]: isHarmony
+      ? pxTransform(Number(right))
+      : `${Number(right) || parseFloat(String(right)) || 0}px`
+  }
+}

 const getPositionStyle = async () => {
   const style: CSSProperties = {}
   style.top = pxTransform(-Number(top) || 0)
   if (rn()) {
-    // ... RN specific logic
+    style.left = await calculateRNPosition(badgeRef.current, right)
   } else {
-    // ... Harmony specific logic
+    Object.assign(style, calculateHarmonyPosition(right, rtl))
   }
   setContentStyle(style)
 }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
const getPositionStyle = async () => {
const style: CSSProperties = {}
style.top = `${Number(top) || parseFloat(String(top)) || 0}px`
const dir = rtl ? 'left' : 'right'
style[dir] = `${Number(right) || parseFloat(String(right)) || 0}px`
style.top = pxTransform(-Number(top) || 0)
if (rn()) {
const reacts = await getRectByTaro(badgeRef.current)
style.left =
reacts?.width && reacts?.width > Number(right)
? pxTransform(reacts.width - Number(right))
: 0
} else {
const dir = rtl ? 'left' : 'right'
style[dir] = isHarmony
? pxTransform(Number(right))
: `${Number(right) || parseFloat(String(right)) || 0}px`
}
setContentStyle(style)
}
const calculateRNPosition = async (ref: any, right: string | number) => {
const reacts = await getRectByTaro(ref)
return reacts?.width && reacts?.width > Number(right)
? pxTransform(reacts.width - Number(right))
: 0
}
const calculateHarmonyPosition = (right: string | number, rtl: boolean) => {
const dir = rtl ? 'left' : 'right'
return {
[dir]: isHarmony
? pxTransform(Number(right))
: `${Number(right) || parseFloat(String(right)) || 0}px`
}
}
const getPositionStyle = async () => {
const style: CSSProperties = {}
style.top = pxTransform(-Number(top) || 0)
if (rn()) {
style.left = await calculateRNPosition(badgeRef.current, right)
} else {
Object.assign(style, calculateHarmonyPosition(right, rtl))
}
setContentStyle(style)
}

const getStyle = () => {
const style: CSSProperties = {}
if (color) {
if (fill === 'outline') {
style.color = color
style.background = '#fff'
isHarmony
? (style.backgroundColor = '#fff')
: (style.background = '#fff')
if (!color?.includes('gradient')) {
style.border = `1px solid ${color}`
style.borderColor = color
}
} else {
style.color = '#fff'
style.background = color
isHarmony ? (style.backgroundColor = color) : (style.background = color)
}
Comment on lines +111 to +124
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

优化样式赋值逻辑

根据静态分析工具的提示,当前的样式赋值逻辑中存在表达式赋值,这可能导致代码难以理解。建议重构为更清晰的条件语句。

 const getStyle = () => {
   const style: CSSProperties = {}
   if (color) {
     if (fill === 'outline') {
       style.color = color
-      isHarmony
-        ? (style.backgroundColor = '#fff')
-        : (style.background = '#fff')
+      if (isHarmony) {
+        style.backgroundColor = '#fff'
+      } else {
+        style.background = '#fff'
+      }
       if (!color?.includes('gradient')) {
         style.borderColor = color
       }
     } else {
       style.color = '#fff'
-      isHarmony ? (style.backgroundColor = color) : (style.background = color)
+      if (isHarmony) {
+        style.backgroundColor = color
+      } else {
+        style.background = color
+      }
     }
   }
   return style
 }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
const getStyle = () => {
const style: CSSProperties = {}
if (color) {
if (fill === 'outline') {
style.color = color
style.background = '#fff'
isHarmony
? (style.backgroundColor = '#fff')
: (style.background = '#fff')
if (!color?.includes('gradient')) {
style.border = `1px solid ${color}`
style.borderColor = color
}
} else {
style.color = '#fff'
style.background = color
isHarmony ? (style.backgroundColor = color) : (style.background = color)
const getStyle = () => {
const style: CSSProperties = {}
if (color) {
if (fill === 'outline') {
style.color = color
if (isHarmony) {
style.backgroundColor = '#fff'
} else {
style.background = '#fff'
}
if (!color?.includes('gradient')) {
style.borderColor = color
}
} else {
style.color = '#fff'
if (isHarmony) {
style.backgroundColor = color
} else {
style.background = color
}
}
}
return style
}
🧰 Tools
🪛 Biome

[error] 117-117: The assignment should not be in an expression.

The use of assignments in expressions is confusing.
Expressions are often considered as side-effect free.

(lint/suspicious/noAssignInExpressions)


[error] 118-118: The assignment should not be in an expression.

The use of assignments in expressions is confusing.
Expressions are often considered as side-effect free.

(lint/suspicious/noAssignInExpressions)


[error] 124-124: The assignment should not be in an expression.

The use of assignments in expressions is confusing.
Expressions are often considered as side-effect free.

(lint/suspicious/noAssignInExpressions)


[error] 124-124: The assignment should not be in an expression.

The use of assignments in expressions is confusing.
Expressions are often considered as side-effect free.

(lint/suspicious/noAssignInExpressions)

}
return style
}

return (
<View className={classes} style={style}>
{isIcon() && <View className={`${classPrefix}-icon`}>{value}</View>}
<View className={classes} style={style} ref={badgeRef}>
{isIcon() && (
<View
className={classNames(`${classPrefix}-content`, {
[`${classPrefix}-icon`]: true,
[`${classPrefix}-icon-rtl`]: rtl,
})}
style={contentStyle}
>
{value}
</View>
)}
{children}
{!isIcon() && (
<View className={contentClasses} style={getStyle()}>
<View
className={contentClasses}
style={{ ...contentStyle, ...getStyle() }}
>
{content()}
</View>
)}
Expand Down
29 changes: 18 additions & 11 deletions src/packages/badge/badge.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -66,18 +66,16 @@ export const Badge: FunctionComponent<Partial<BadgeProps>> = (props) => {
if (typeof value === 'string' && value) return value
}

const contentClasses = classNames(
{ [`${classPrefix}-dot`]: dot },
`${classPrefix}-content`,
{ [`${classPrefix}-sup`]: isNumber() || isString() || dot },
{
[`${classPrefix}-one`]:
typeof content() === 'string' && `${content()}`?.length === 1,
}
)
const contentClasses = classNames(`${classPrefix}-content`, {
[`${classPrefix}-sup`]: isNumber() || isString() || dot,
[`${classPrefix}-one`]:
typeof content() === 'string' && `${content()}`?.length === 1,
[`${classPrefix}-dot`]: dot,
[`${classPrefix}-${fill}`]: fill === 'outline',
})
const getStyle = () => {
const style: CSSProperties = {}
style.top = `${Number(top) || parseFloat(String(top)) || 0}px`
style.top = `${Number(-top) || parseFloat(String(-top)) || 0}px`
const dir = rtl ? 'left' : 'right'
style[dir] = `${Number(right) || parseFloat(String(right)) || 0}px`

Expand All @@ -97,7 +95,16 @@ export const Badge: FunctionComponent<Partial<BadgeProps>> = (props) => {
}
return (
<div className={classes} style={style}>
{isIcon() && <div className={`${classPrefix}-icon`}>{value}</div>}
{isIcon() && (
<div
className={classNames(`${classPrefix}-content`, {
[`${classPrefix}-icon`]: true,
[`${classPrefix}-icon-rtl`]: rtl,
})}
>
{value}
</div>
)}
{children}
{!isIcon() && (
<div className={contentClasses} style={getStyle()}>
Expand Down
Loading
Loading