refactor(component): input component (#2275)

This commit is contained in:
Himself65 2023-05-09 10:39:39 +08:00 committed by GitHub
parent cba3293326
commit 53db6a6e9d
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 97 additions and 70 deletions

View File

@ -3,7 +3,6 @@ export * from './styles';
export * from './ui/breadcrumbs'; export * from './ui/breadcrumbs';
export * from './ui/button'; export * from './ui/button';
export * from './ui/confirm'; export * from './ui/confirm';
export * from './ui/divider';
export * from './ui/empty'; export * from './ui/empty';
export * from './ui/input'; export * from './ui/input';
export * from './ui/layout'; export * from './ui/layout';

View File

@ -1,9 +0,0 @@
import MuiDivider from '@mui/material/Divider';
import { styled } from '../../styles';
export const Divider = styled(MuiDivider)(() => {
return {
borderColor: 'var(--affine-border-color)',
};
});

View File

@ -1,7 +1,7 @@
import type { SvgIconProps } from '@mui/material/SvgIcon';
import SvgIcon from '@mui/material/SvgIcon'; import SvgIcon from '@mui/material/SvgIcon';
import { memo } from 'react';
export const EmptySvg = (_props: SvgIconProps) => { export const EmptySvg = memo(function EmptySvg() {
return ( return (
<SvgIcon <SvgIcon
width="200" width="200"
@ -411,4 +411,4 @@ export const EmptySvg = (_props: SvgIconProps) => {
</defs> </defs>
</SvgIcon> </SvgIcon>
); );
}; });

View File

@ -0,0 +1,34 @@
import { createVar, style } from '@vanilla-extract/css';
export const heightVar = createVar('heightVar');
export const widthVar = createVar('widthVar');
export const inputStyle = style({
vars: {
[heightVar]: 'unset',
[widthVar]: '100%',
},
width: widthVar,
height: heightVar,
lineHeight: '22px',
padding: '8px 12px',
color: 'var(--affine-text-primary-color)',
border: '1px solid',
borderColor: 'var(--affine-border-color)', // TODO: check out disableColor,
backgroundColor: 'var(--affine-white)',
borderRadius: '10px',
selectors: {
'&[data-no-border="true"]': {
border: 'unset',
},
'&[data-disabled="true"]': {
color: 'var(--affine-text-disable-color)',
},
'&::placeholder': {
color: 'var(--affine-placeholder-color)',
},
'&:focus': {
borderColor: 'var(--affine-primary-color)',
},
},
});

View File

@ -0,0 +1,39 @@
import { expect } from '@storybook/jest';
import type { Meta, StoryFn } from '@storybook/react';
import { userEvent, within } from '@storybook/testing-library';
import { Input } from '.';
export default {
title: 'AFFiNE/Input',
component: Input,
} satisfies Meta<typeof Input>;
export const Basic: StoryFn<typeof Input> = () => {
return <Input data-testid="test-input" defaultValue="test" />;
};
Basic.play = async ({ canvasElement }) => {
const element = within(canvasElement);
const item = element.getByTestId('test-input') as HTMLInputElement;
expect(item).toBeTruthy();
expect(item.value).toBe('test');
userEvent.clear(item);
userEvent.type(item, 'test 2');
expect(item.value).toBe('test 2');
};
export const DynamicHeight: StoryFn<typeof Input> = () => {
return <Input width={200} data-testid="test-input" />;
};
DynamicHeight.play = async ({ canvasElement }) => {
const element = within(canvasElement);
const item = element.getByTestId('test-input') as HTMLInputElement;
expect(item).toBeTruthy();
expect(item.getBoundingClientRect().width).toBe(200);
};
export const NoBorder: StoryFn<typeof Input> = () => {
return <Input noBorder={true} data-testid="test-input" />;
};

View File

@ -1,14 +1,16 @@
import { assignInlineVars } from '@vanilla-extract/dynamic';
import clsx from 'clsx';
import type { import type {
ChangeEventHandler,
CSSProperties, CSSProperties,
FocusEventHandler, FocusEventHandler,
ForwardedRef, ForwardedRef,
HTMLAttributes, HTMLAttributes,
InputHTMLAttributes,
KeyboardEventHandler, KeyboardEventHandler,
} from 'react'; } from 'react';
import { forwardRef, useEffect, useState } from 'react'; import { forwardRef, useCallback } from 'react';
import { StyledInput } from './style'; import { heightVar, inputStyle, widthVar } from './index.css';
type inputProps = { type inputProps = {
value?: string; value?: string;
@ -27,39 +29,35 @@ type inputProps = {
export const Input = forwardRef<HTMLInputElement, inputProps>(function Input( export const Input = forwardRef<HTMLInputElement, inputProps>(function Input(
{ {
disabled, disabled,
value: valueProp, value,
placeholder, placeholder,
maxLength, maxLength,
minLength, minLength,
height, height,
width, width,
onChange, onChange,
onBlur,
onKeyDown,
noBorder = false, noBorder = false,
...otherProps ...otherProps
}: inputProps, }: inputProps,
ref: ForwardedRef<HTMLInputElement> ref: ForwardedRef<HTMLInputElement>
) { ) {
const [value, setValue] = useState<string>(valueProp || ''); const handleChange = useCallback<ChangeEventHandler<HTMLInputElement>>(
const handleChange: InputHTMLAttributes<HTMLInputElement>['onChange'] = e => {
const { value } = e.target;
setValue(value);
onChange && onChange(value);
};
const handleBlur: InputHTMLAttributes<HTMLInputElement>['onBlur'] = e => {
onBlur && onBlur(e);
};
const handleKeyDown: InputHTMLAttributes<HTMLInputElement>['onKeyDown'] =
e => { e => {
onKeyDown && onKeyDown(e); const { value } = e.target;
}; onChange && onChange(value);
useEffect(() => { },
setValue(valueProp || ''); [onChange]
}, [valueProp]); );
return ( return (
<StyledInput <input
className={clsx(inputStyle, otherProps.className)}
style={assignInlineVars({
[widthVar]: width ? `${width}px` : '100%',
[heightVar]: height ? `${height}px` : 'unset',
})}
data-no-border={noBorder}
data-disabled={disabled}
ref={ref} ref={ref}
value={value} value={value}
disabled={disabled} disabled={disabled}
@ -68,10 +66,7 @@ export const Input = forwardRef<HTMLInputElement, inputProps>(function Input(
maxLength={maxLength} maxLength={maxLength}
minLength={minLength} minLength={minLength}
onChange={handleChange} onChange={handleChange}
onBlur={handleBlur}
onKeyDown={handleKeyDown}
height={height} height={height}
noBorder={noBorder}
{...otherProps} {...otherProps}
/> />
); );

View File

@ -1,31 +0,0 @@
import type { CSSProperties } from 'react';
import { styled } from '../../styles';
export const StyledInput = styled('input')<{
disabled?: boolean;
value?: string;
width?: CSSProperties['width'];
height?: CSSProperties['height'];
noBorder?: boolean;
}>(({ width, disabled, height, noBorder }) => {
return {
width: width || '100%',
height,
lineHeight: '22px',
padding: '8px 12px',
color: disabled
? 'var(--affine-text-disable-color)'
: 'var(--affine-text-primary-color)',
border: noBorder ? 'unset' : `1px solid`,
borderColor: 'var(--affine-border-color)', // TODO: check out disableColor,
backgroundColor: 'var(--affine-white)',
borderRadius: '10px',
'&::placeholder': {
color: 'var(--affine-placeholder-color)',
},
'&:focus': {
borderColor: 'var(--affine-primary-color)',
},
};
});