Skip to content

Commit

Permalink
Merge pull request #136
Browse files Browse the repository at this point in the history
[Issue-134] Component - Field
  • Loading branch information
saltict authored Feb 13, 2023
2 parents 4040131 + 07f281e commit a68086a
Show file tree
Hide file tree
Showing 6 changed files with 379 additions and 0 deletions.
87 changes: 87 additions & 0 deletions components/field/Field.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
import classNames from 'classnames';
import React from 'react';
import type { PresetBarShapeType } from '../_util/shapes';
import { ConfigContext } from '../config-provider';
import { NoFormStyle } from '../form/context';
import { NoCompactStyle } from '../space/Compact';
import useStyle from './style';
import Typography from '../typography';

export type SelectModalSize = 'small' | 'medium';
export interface FieldProps {
content: React.ReactNode;
prefixCls?: string;
className?: string;
size?: SelectModalSize;
shape?: PresetBarShapeType;
placeholder?: string;
background?: 'default' | 'transparent';
width?: number | string;
label?: string;
prefix?: React.ReactNode;
suffix?: React.ReactNode;
maxLine?: number;
}

const DEFAULT_PLACEHOLDER = 'Placeholder';

const Field = (props: FieldProps): JSX.Element => {
const { getPrefixCls } = React.useContext(ConfigContext);

const {
prefixCls: customizePrefixCls,
className,
shape = 'default',
background = 'default',
width = '100%',
label = '',
suffix,
prefix,
size: inputSize = 'medium',
content,
placeholder,
maxLine = 1,
} = props;

const prefixCls = getPrefixCls('field', customizePrefixCls);
// Style
const [wrapSSR, hashId] = useStyle(prefixCls);

return wrapSSR(
<NoCompactStyle>
<NoFormStyle status override>
<div
className={classNames(
hashId,
className,
`${prefixCls}-container`,
`${prefixCls}-border-${shape}`,
`${prefixCls}-bg-${background}`,
`${prefixCls}-size-${inputSize}`,
{
[`${prefixCls}-with-label`]: label,
[`${prefixCls}-placeholder`]: !content,
},
)}
style={{ width }}
>
{label && <div className={classNames(`${prefixCls}-label`)}>{label}</div>}
<div className={classNames(`${prefixCls}-wrapper`)}>
{prefix}
<div className={classNames(`${prefixCls}-content-wrapper`)}>
<Typography.Paragraph
className={classNames(`${prefixCls}-content`)}
ellipsis={{ rows: maxLine }}
>
{content || placeholder || DEFAULT_PLACEHOLDER}
</Typography.Paragraph>
</div>
{suffix}
</div>
</div>
</NoFormStyle>
</NoCompactStyle>,
);
};

export default Field;
9 changes: 9 additions & 0 deletions components/field/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
import OriginField from './Field';

export type { FieldProps } from './Field';

type FieldType = typeof OriginField;

const Field = OriginField as FieldType;

export default Field;
155 changes: 155 additions & 0 deletions components/field/stories/field.stories.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,155 @@
import React, { useMemo } from 'react';
import type { ComponentStory, ComponentMeta } from '@storybook/react';
import SwAvatar from '../../sw-avatar';
import Field from '../index';
import type { FieldProps } from '../index';

interface WrapperProps extends FieldProps {
suffixType: number;
prefixType: number;
}

const icon = <SwAvatar value="" identPrefix={42} isAllAccount size={20} />;

const Wrapper = ({ suffixType = 1, prefixType = 0, ...args }: WrapperProps) => {
const additionalProps = useMemo((): Pick<FieldProps, 'prefix' | 'suffix'> => {
const result: Pick<FieldProps, 'prefix' | 'suffix'> = {};

switch (prefixType) {
case 1:
result.prefix = icon;
break;
default:
break;
}

switch (suffixType) {
case 2:
result.suffix = icon;
break;
default:
break;
}

return result;
}, [suffixType, prefixType]);

return (
<div style={{ display: 'flex', flexDirection: 'column', gap: 16 }}>
<Field {...args} {...additionalProps} />
</div>
);
};

export default {
title: 'Basic Components/Field',
component: Wrapper,
// More on argTypes: https://storybook.js.org/docs/react/api/argtypes
argTypes: {
title: {
type: 'string',
},
placeholder: {
type: 'string',
},
label: {
type: 'string',
if: {
arg: 'withLabel',
eq: true,
},
},
shape: {
control: 'radio',
options: ['default', 'square', 'round'],
},
background: {
control: 'radio',
options: ['default', 'transparent'],
},
size: {
control: 'select',
options: ['small', 'medium'],
if: {
arg: 'label',
eq: '',
},
},
disabled: {
type: 'boolean',
if: {
arg: 'withDisabled',
eq: true,
},
},
withLabel: {
control: false,
},
suffixType: {
control: false,
},
prefixType: {
control: false,
},
maxLine: {
type: 'number',
defaultValue: 1,
},
},
// @ts-ignore
} as ComponentMeta<typeof Wrapper>;

// More on component templates: https://storybook.js.org/docs/react/writing-stories/introduction#using-args
// @ts-ignore
const Template: ComponentStory<typeof Wrapper> = ({ ...args }) => <Wrapper {...args} />;

const DEFAULT_ARGS = {
shape: 'default',
background: 'default',
size: 'medium',
placeholder: 'Placeholder',
content:
'Lorem ipsum dolor sit amet, consectetur adipisicing elit. Adipisci amet corporis cumque deleniti dicta distinctio dolores ea est et eveniet ipsam iste molestiae non possimus, recusandae rem sint. Cumque, eum?',
disabled: false,
label: '',
};
export const Default = Template.bind({});

Default.args = {
...DEFAULT_ARGS,
};

export const WithLabel = Template.bind({});

WithLabel.args = {
...DEFAULT_ARGS,
label: 'Label',
withLabel: true,
};
export const CustomSuffix = Template.bind({});

CustomSuffix.args = {
...DEFAULT_ARGS,
suffixType: 2,
label: 'Label',
withLabel: true,
};

export const CustomPrefix = Template.bind({});

CustomPrefix.args = {
...DEFAULT_ARGS,
prefixType: 1,
label: 'Label',
withLabel: true,
};

export const FullCustom = Template.bind({});

FullCustom.args = {
...DEFAULT_ARGS,
suffixType: 2,
prefixType: 1,
label: 'Label',
withLabel: true,
};
123 changes: 123 additions & 0 deletions components/field/style/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,123 @@
import type { FullToken, GenerateStyle } from '../../theme/internal';
import { genComponentStyleHook, mergeToken } from '../../theme/internal';

/** Component only token. Which will handle additional calculation of alias token */
export interface ComponentToken {
// Component token here
}

export interface FieldToken extends FullToken<'Field'> {}
const genFieldStyle: GenerateStyle<FieldToken> = (token) => {
const { componentCls } = token;

return [
{
[`${componentCls}-container`]: {
display: 'flex',
flexDirection: 'column',
gap: 8,
color: token.colorTextTertiary,
lineHeight: token.lineHeightLG,
overflow: 'hidden',
position: 'relative',

[`${componentCls}-wrapper`]: {
display: 'flex',
flexDirection: 'row',
justifyContent: 'space-between',
alignItems: 'center',
gap: 8,
overflow: 'hidden',

[`${componentCls}-content-wrapper`]: {
overflow: 'hidden',
flex: 1,

[`${componentCls}-content`]: {
marginBottom: 0,
color: token.colorText,
},
},
},

[`&${componentCls}-placeholder`]: {
[`${componentCls}-wrapper`]: {
[`${componentCls}-content-wrapper`]: {
[`${componentCls}-content`]: {
color: token.colorTextLight4,
},
},
},
},

[`${componentCls}-label`]: {
fontSize: token.fontSizeSM,
lineHeight: token.lineHeightSM,
color: token.colorTextLight4,
paddingLeft: token.paddingSM,
paddingRight: token.paddingSM,
paddingTop: token.paddingXXS,
top: token.paddingXXS,
whiteSpace: 'nowrap',
textOverflow: 'ellipsis',
overflow: 'hidden',
position: 'relative',
},

// Size

[`&${componentCls}-size-small`]: {
[`${componentCls}-wrapper`]: {
padding: `${token.paddingContentVerticalSM}px ${token.paddingContentHorizontal}px`,
},
},

[`&${componentCls}-size-medium`]: {
[`${componentCls}-wrapper`]: {
padding: `${token.paddingContentVertical}px ${token.paddingContentHorizontal}px`,
},
},

[`&${componentCls}-with-label`]: {
[`${componentCls}-placeholder`]: {
color: token.colorText,
},

[`${componentCls}-wrapper`]: {
padding: `${token.paddingContentVertical - 2}px ${token.paddingSM}px ${
token.paddingContentVertical
}px`,
},
},

// Border
[`&${componentCls}-border-square`]: {
borderRadius: 0,
},

[`&${componentCls}-border-round`]: {
borderRadius: token.controlHeightLG + token.borderRadiusLG,
},

[`&${componentCls}-border-default`]: {
borderRadius: token.borderRadius,
},

// Background
[`&${componentCls}-bg-default`]: {
background: token.colorBgSecondary,
},

[`&${componentCls}-bg-transparent`]: {
background: 'transparent',
},
},
},
];
};

// ============================== Export ==============================
export default genComponentStyleHook('Field', (token) => {
const fieldToken = mergeToken<FieldToken>(token);
return [genFieldStyle(fieldToken)];
});
3 changes: 3 additions & 0 deletions components/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -156,6 +156,9 @@ export { default as QRCode } from './qrcode';
export type { QRCodeProps, QRPropsCanvas } from './qrcode/interface';
export { default as version } from './version';

export { default as Field } from './field';
export type { FieldProps } from './field';

export { default as ActivityIndicator } from './activity-indicator';
export type { ActivityIndicatorProps } from './activity-indicator';
export { default as BackgroundIcon } from './background-icon';
Expand Down
Loading

0 comments on commit a68086a

Please sign in to comment.