mirror of
https://github.com/toeverything/AFFiNE.git
synced 2024-12-24 06:02:51 +03:00
refactor(component): input component (#2275)
This commit is contained in:
parent
cba3293326
commit
53db6a6e9d
@ -3,7 +3,6 @@ export * from './styles';
|
||||
export * from './ui/breadcrumbs';
|
||||
export * from './ui/button';
|
||||
export * from './ui/confirm';
|
||||
export * from './ui/divider';
|
||||
export * from './ui/empty';
|
||||
export * from './ui/input';
|
||||
export * from './ui/layout';
|
||||
|
@ -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)',
|
||||
};
|
||||
});
|
@ -1,7 +1,7 @@
|
||||
import type { SvgIconProps } 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 (
|
||||
<SvgIcon
|
||||
width="200"
|
||||
@ -411,4 +411,4 @@ export const EmptySvg = (_props: SvgIconProps) => {
|
||||
</defs>
|
||||
</SvgIcon>
|
||||
);
|
||||
};
|
||||
});
|
||||
|
34
packages/component/src/ui/input/index.css.ts
Normal file
34
packages/component/src/ui/input/index.css.ts
Normal 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)',
|
||||
},
|
||||
},
|
||||
});
|
39
packages/component/src/ui/input/index.stories.tsx
Normal file
39
packages/component/src/ui/input/index.stories.tsx
Normal 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" />;
|
||||
};
|
@ -1,14 +1,16 @@
|
||||
import { assignInlineVars } from '@vanilla-extract/dynamic';
|
||||
import clsx from 'clsx';
|
||||
import type {
|
||||
ChangeEventHandler,
|
||||
CSSProperties,
|
||||
FocusEventHandler,
|
||||
ForwardedRef,
|
||||
HTMLAttributes,
|
||||
InputHTMLAttributes,
|
||||
KeyboardEventHandler,
|
||||
} 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 = {
|
||||
value?: string;
|
||||
@ -27,39 +29,35 @@ type inputProps = {
|
||||
export const Input = forwardRef<HTMLInputElement, inputProps>(function Input(
|
||||
{
|
||||
disabled,
|
||||
value: valueProp,
|
||||
value,
|
||||
placeholder,
|
||||
maxLength,
|
||||
minLength,
|
||||
height,
|
||||
width,
|
||||
onChange,
|
||||
onBlur,
|
||||
onKeyDown,
|
||||
noBorder = false,
|
||||
...otherProps
|
||||
}: inputProps,
|
||||
ref: ForwardedRef<HTMLInputElement>
|
||||
) {
|
||||
const [value, setValue] = useState<string>(valueProp || '');
|
||||
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'] =
|
||||
const handleChange = useCallback<ChangeEventHandler<HTMLInputElement>>(
|
||||
e => {
|
||||
onKeyDown && onKeyDown(e);
|
||||
};
|
||||
useEffect(() => {
|
||||
setValue(valueProp || '');
|
||||
}, [valueProp]);
|
||||
const { value } = e.target;
|
||||
onChange && onChange(value);
|
||||
},
|
||||
[onChange]
|
||||
);
|
||||
|
||||
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}
|
||||
value={value}
|
||||
disabled={disabled}
|
||||
@ -68,10 +66,7 @@ export const Input = forwardRef<HTMLInputElement, inputProps>(function Input(
|
||||
maxLength={maxLength}
|
||||
minLength={minLength}
|
||||
onChange={handleChange}
|
||||
onBlur={handleBlur}
|
||||
onKeyDown={handleKeyDown}
|
||||
height={height}
|
||||
noBorder={noBorder}
|
||||
{...otherProps}
|
||||
/>
|
||||
);
|
||||
|
@ -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)',
|
||||
},
|
||||
};
|
||||
});
|
Loading…
Reference in New Issue
Block a user