-
Notifications
You must be signed in to change notification settings - Fork 22
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
6 changed files
with
920 additions
and
357 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Large diffs are not rendered by default.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,58 @@ | ||
import React from 'react' | ||
import { defineComponent } from './defineComponent' | ||
import { render } from '@testing-library/react' | ||
|
||
describe('defineComponent', () => { | ||
test('默认转发 ref', () => { | ||
const Button = defineComponent< | ||
{ id?: number; kind: string }, | ||
HTMLDivElement | ||
>({ | ||
defaultProps: { | ||
id: 0, | ||
}, | ||
component: function Button(props, ref) { | ||
return <div ref={ref} data-testid='button' /> | ||
}, | ||
}) | ||
const buttonRef = React.createRef<HTMLDivElement>() | ||
const { queryByTestId } = render(<Button ref={buttonRef} kind='primary' />) | ||
expect(queryByTestId('button')).toBe(buttonRef.current) | ||
}) | ||
|
||
test('不转发 ref', () => { | ||
const Button = defineComponent< | ||
{ id?: number; kind: string }, | ||
HTMLDivElement | ||
>({ | ||
defaultProps: { | ||
id: 0, | ||
}, | ||
forwardRef: false, | ||
component: function Button(props) { | ||
return <div data-testid='button2'>{props.kind}</div> | ||
}, | ||
}) | ||
const { queryByTestId } = render(<Button kind='primary' />) | ||
expect(queryByTestId('button2')!.innerHTML).toBe('primary') | ||
}) | ||
|
||
test('组件的展示名称默认为组件函数的名称', () => { | ||
const Button = defineComponent({ | ||
component: function Button() { | ||
return null | ||
}, | ||
}) | ||
expect(Button.displayName).toBe('Button') | ||
}) | ||
|
||
test('可以通过选项 displayName 设置组件的展示名称', () => { | ||
const Button = defineComponent({ | ||
displayName: 'XButton', | ||
component: function Button() { | ||
return null | ||
}, | ||
}) | ||
expect(Button.displayName).toBe('XButton') | ||
}) | ||
}) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,95 @@ | ||
import React from 'react' | ||
import { Defined, OptionalKeys, RequiredBy } from '../types' | ||
|
||
/** | ||
* 定义组件的选项。 | ||
*/ | ||
export type DefineComponentOptions< | ||
/** | ||
* 组件属性。 | ||
*/ | ||
TProps extends Record<string, any>, | ||
/** | ||
* 是否转发 ref。 | ||
*/ | ||
TForwardRef extends boolean, | ||
/** | ||
* 要转发的 ref。 | ||
*/ | ||
TRef extends any = never | ||
> = ([OptionalKeys<TProps>] extends [never] | ||
? { | ||
/** | ||
* 可选属性的默认值。 | ||
*/ | ||
defaultProps?: never | ||
} | ||
: { | ||
/** | ||
* 可选属性的默认值。 | ||
*/ | ||
defaultProps: { | ||
[K in OptionalKeys<TProps>]: Defined<TProps[K]> | ||
} | ||
}) & | ||
(TForwardRef extends true | ||
? { | ||
/** | ||
* 是否转发 ref。 | ||
*/ | ||
forwardRef?: true | ||
} | ||
: { | ||
/** | ||
* 是否转发 ref。 | ||
*/ | ||
forwardRef: false | ||
}) & { | ||
/** | ||
* 组件展示名称。 | ||
*/ | ||
displayName?: string | ||
/** | ||
* 组件。 | ||
*/ | ||
component: TForwardRef extends true | ||
? React.ForwardRefRenderFunction<TRef, RequiredBy<TProps, keyof TProps>> | ||
: React.FC<RequiredBy<TProps, keyof TProps>> | ||
} | ||
|
||
/** | ||
* 定义组件。 | ||
* | ||
* @param options 选项 | ||
*/ | ||
export function defineComponent< | ||
TProps extends Record<string, any>, | ||
TRef extends any = any | ||
>( | ||
options: DefineComponentOptions<TProps, true, TRef>, | ||
): React.ForwardRefExoticComponent< | ||
React.PropsWithoutRef<TProps> & React.RefAttributes<TRef> | ||
> | ||
|
||
/** | ||
* 定义组件。 | ||
* | ||
* @param options 选项 | ||
*/ | ||
export function defineComponent< | ||
TProps extends Record<string, any>, | ||
TRef extends any = any | ||
>(options: DefineComponentOptions<TProps, false>): React.FC<TProps> | ||
|
||
export function defineComponent( | ||
options: DefineComponentOptions<any, any, any>, | ||
): any { | ||
const forwardRef = options.forwardRef ?? true | ||
const displayName = options.displayName ?? options.component.name | ||
const component = forwardRef | ||
? React.forwardRef(options.component as any) | ||
: options.component | ||
component.displayName = displayName | ||
component.defaultProps = options.defaultProps | ||
return component | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters