mirror of
https://github.com/toeverything/AFFiNE.git
synced 2024-12-24 20:41:49 +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/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';
|
||||||
|
@ -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 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>
|
||||||
);
|
);
|
||||||
};
|
});
|
||||||
|
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 {
|
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}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
|
@ -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