Skip to content

Commit

Permalink
Fix: Default value was not inherited when property value was undefine…
Browse files Browse the repository at this point in the history
…d or null
  • Loading branch information
1aron committed Dec 2, 2024
1 parent 72a7470 commit cf2bf43
Show file tree
Hide file tree
Showing 6 changed files with 3,923 additions and 3,320 deletions.
20 changes: 13 additions & 7 deletions packages/core/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,12 @@ type Param<T> = string
| Record<string, boolean>
| [string, { [key in keyof T]?: T[key] }]
| {
[key in keyof T]?: T[key] extends string | undefined
? Record<string, string>
: T[key] extends boolean | undefined
? string
: (Record<string, string> | string)
}
[key in keyof T]?: T[key] extends string | undefined
? Record<string, string>
: T[key] extends boolean | undefined
? string
: (Record<string, string> | string)
}
| ((valueByProp: T) => any)
type ReturnType<T> = { default?: Partial<T> } & ((valueByProp?: T) => string)

Expand All @@ -26,7 +26,13 @@ function cv<T extends Record<string, string | number | boolean>>(...params: Arra
function cv<T extends Record<string, string | number | boolean>>(firstParam: TemplateStringsArray, ...params: Array<Param<T>>): ReturnType<T>
function cv<T extends Record<string, string | number | boolean>>(firstParam: TemplateStringsArray | Param<T>, ...params: Array<Param<T>>): ReturnType<T> {
return function getClassNames(valueByProp: T = {} as any) {
const mergedValueByProp = Object.assign({}, (getClassNames as ReturnType<T>).default, valueByProp)
// 如果 valueByProps 中的屬性是 undefined 或是 null,則使用 default 中的值
const defaultProps = (getClassNames as ReturnType<T>).default
const mergedValueByProp: any = defaultProps ? Object.assign({}, defaultProps) : {}
for (const eachProp in valueByProp) {
const eachDefaultValue = defaultProps?.[eachProp]
mergedValueByProp[eachProp] = valueByProp[eachProp] ?? eachDefaultValue
}
const isTemplateLiteral = Array.isArray(firstParam) && 'raw' in firstParam
const classesConditions: [string, Record<string, string | number | boolean>][] = []
const valuesByProp: Record<string, Record<string, string>> = {}
Expand Down
15 changes: 15 additions & 0 deletions packages/core/tests/test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -58,4 +58,19 @@ test('literal function', () => {
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')
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')
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')
})

test('extend default', () => {
const style = cv<any>('block', {
$type: {
a: 'bg:red',
b: 'bg:blue'
}
})
style.default = {
$type: 'a'
}
expect(style()).toBe('block bg:red')
expect(style({ $type: undefined })).toBe('block bg:red')
expect(style({ $type: 'b' })).toBe('block bg:blue')
})
7 changes: 7 additions & 0 deletions packages/react/e2e/DefaultProps.test.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
import { test, expect } from '@playwright/experimental-ct-react'
import Element from './DefaultProps'

test('element', async ({ mount }) =>
await expect(await mount(<Element $type={undefined} />))
.toHaveClass('fg:white bg:red')
)
14 changes: 14 additions & 0 deletions packages/react/e2e/DefaultProps.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
import styled from '../src';

const Element = styled.div('fg:white', {
$type: {
a: 'bg:red',
b: 'bg:blue'
}
})

Element.default = {
$type: 'a'
}

export default Element
9 changes: 8 additions & 1 deletion packages/react/src/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,14 @@ function handle<K extends IntrinsicElementsKeys | React.ComponentType<any>, E ex
const generateFunctionComponent = (defaultClassNames: TemplateStringsArray, ...params: any[]) => {
const newTagParams: TagParams = [...(tagParams || []), [defaultClassNames, params]]
const component = forwardRef<K, MasterComponentProps<K, E>>((props, ref) => {
props = Object.assign({}, component.default, props)
const resolvedProps: any = component.default ? Object.assign({}, component.default) : {}
for (const propKey in props) {
const propValue = props[propKey]
if (propValue !== undefined && propValue !== null) {
resolvedProps[propKey] = propValue
}
}
props = resolvedProps
const classNames: string[] = []
const classesConditions: [string, Record<string, string | number | boolean>][] = []
let valuesByProp: Record<string, string | Record<string, string>>
Expand Down
Loading

0 comments on commit cf2bf43

Please sign in to comment.