Skip to content

Commit cf2bf43

Browse files
committed
Fix: Default value was not inherited when property value was undefined or null
1 parent 72a7470 commit cf2bf43

File tree

6 files changed

+3923
-3320
lines changed

6 files changed

+3923
-3320
lines changed

packages/core/src/index.ts

+13-7
Original file line numberDiff line numberDiff line change
@@ -5,12 +5,12 @@ type Param<T> = string
55
| Record<string, boolean>
66
| [string, { [key in keyof T]?: T[key] }]
77
| {
8-
[key in keyof T]?: T[key] extends string | undefined
9-
? Record<string, string>
10-
: T[key] extends boolean | undefined
11-
? string
12-
: (Record<string, string> | string)
13-
}
8+
[key in keyof T]?: T[key] extends string | undefined
9+
? Record<string, string>
10+
: T[key] extends boolean | undefined
11+
? string
12+
: (Record<string, string> | string)
13+
}
1414
| ((valueByProp: T) => any)
1515
type ReturnType<T> = { default?: Partial<T> } & ((valueByProp?: T) => string)
1616

@@ -26,7 +26,13 @@ function cv<T extends Record<string, string | number | boolean>>(...params: Arra
2626
function cv<T extends Record<string, string | number | boolean>>(firstParam: TemplateStringsArray, ...params: Array<Param<T>>): ReturnType<T>
2727
function cv<T extends Record<string, string | number | boolean>>(firstParam: TemplateStringsArray | Param<T>, ...params: Array<Param<T>>): ReturnType<T> {
2828
return function getClassNames(valueByProp: T = {} as any) {
29-
const mergedValueByProp = Object.assign({}, (getClassNames as ReturnType<T>).default, valueByProp)
29+
// 如果 valueByProps 中的屬性是 undefined 或是 null,則使用 default 中的值
30+
const defaultProps = (getClassNames as ReturnType<T>).default
31+
const mergedValueByProp: any = defaultProps ? Object.assign({}, defaultProps) : {}
32+
for (const eachProp in valueByProp) {
33+
const eachDefaultValue = defaultProps?.[eachProp]
34+
mergedValueByProp[eachProp] = valueByProp[eachProp] ?? eachDefaultValue
35+
}
3036
const isTemplateLiteral = Array.isArray(firstParam) && 'raw' in firstParam
3137
const classesConditions: [string, Record<string, string | number | boolean>][] = []
3238
const valuesByProp: Record<string, Record<string, string>> = {}

packages/core/tests/test.ts

+15
Original file line numberDiff line numberDiff line change
@@ -58,4 +58,19 @@ test('literal function', () => {
5858
expect(literalBtn()).toBe('inline-flex rounded top:30 left:40 font:semibold color: bg:blue fg:white bg:blue-55:hover text:14 p:5|15')
5959
expect(literalBtn({ intent: 'secondary', size: 'sm', color: 'red' })).toBe('inline-flex rounded top:30 left:40 font:semibold color:red bg:white fg:slate-30 bg:slate-90:hover text:14 p:5|15')
6060
expect(literalBtn({ intent: 'primary', size: 'md', color: 'red' })).toBe('inline-flex rounded top:30 left:40 font:semibold color:red uppercase bg:blue fg:white bg:blue-55:hover text:16 p:10|25')
61+
})
62+
63+
test('extend default', () => {
64+
const style = cv<any>('block', {
65+
$type: {
66+
a: 'bg:red',
67+
b: 'bg:blue'
68+
}
69+
})
70+
style.default = {
71+
$type: 'a'
72+
}
73+
expect(style()).toBe('block bg:red')
74+
expect(style({ $type: undefined })).toBe('block bg:red')
75+
expect(style({ $type: 'b' })).toBe('block bg:blue')
6176
})
+7
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
import { test, expect } from '@playwright/experimental-ct-react'
2+
import Element from './DefaultProps'
3+
4+
test('element', async ({ mount }) =>
5+
await expect(await mount(<Element $type={undefined} />))
6+
.toHaveClass('fg:white bg:red')
7+
)

packages/react/e2e/DefaultProps.tsx

+14
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
import styled from '../src';
2+
3+
const Element = styled.div('fg:white', {
4+
$type: {
5+
a: 'bg:red',
6+
b: 'bg:blue'
7+
}
8+
})
9+
10+
Element.default = {
11+
$type: 'a'
12+
}
13+
14+
export default Element

packages/react/src/index.tsx

+8-1
Original file line numberDiff line numberDiff line change
@@ -64,7 +64,14 @@ function handle<K extends IntrinsicElementsKeys | React.ComponentType<any>, E ex
6464
const generateFunctionComponent = (defaultClassNames: TemplateStringsArray, ...params: any[]) => {
6565
const newTagParams: TagParams = [...(tagParams || []), [defaultClassNames, params]]
6666
const component = forwardRef<K, MasterComponentProps<K, E>>((props, ref) => {
67-
props = Object.assign({}, component.default, props)
67+
const resolvedProps: any = component.default ? Object.assign({}, component.default) : {}
68+
for (const propKey in props) {
69+
const propValue = props[propKey]
70+
if (propValue !== undefined && propValue !== null) {
71+
resolvedProps[propKey] = propValue
72+
}
73+
}
74+
props = resolvedProps
6875
const classNames: string[] = []
6976
const classesConditions: [string, Record<string, string | number | boolean>][] = []
7077
let valuesByProp: Record<string, string | Record<string, string>>

0 commit comments

Comments
 (0)