Merge pull request #507 from smartxworks/feat/arco

Add NumberInput、Tag、Carousel component
This commit is contained in:
tanbowensg 2022-07-11 11:41:02 +08:00 committed by GitHub
commit cc3f699407
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 441 additions and 0 deletions

View File

@ -0,0 +1,90 @@
import { Carousel as BaseCarousel } from '@arco-design/web-react';
import { implementRuntimeComponent } from '@sunmao-ui/runtime';
import { css } from '@emotion/css';
import { Type, Static } from '@sinclair/typebox';
import { FALLBACK_METADATA, getComponentProps } from '../sunmao-helper';
import { CarouselPropsSpec as BaseCarouselPropsSpec } from '../generated/types/Carousel';
import { useRef, useEffect } from 'react';
import { CarouselHandle } from '@arco-design/web-react/es/Carousel/interface';
const InputPropsSpec = Type.Object({
...BaseCarouselPropsSpec,
});
const InputStateSpec = Type.Object({
value: Type.Number(),
});
const defaultCarouselStyle = css`
height: 240px;
`;
const exampleProperties: Static<typeof InputPropsSpec> = {
imageSrc: [
'//p1-arco.byteimg.com/tos-cn-i-uwbnlip3yd/cd7a1aaea8e1c5e3d26fe2591e561798.png~tplv-uwbnlip3yd-webp.webp',
'//p1-arco.byteimg.com/tos-cn-i-uwbnlip3yd/6480dbc69be1b5de95010289787d64f1.png~tplv-uwbnlip3yd-webp.webp',
'//p1-arco.byteimg.com/tos-cn-i-uwbnlip3yd/0265a04fddbd77a19602a15d9d55d797.png~tplv-uwbnlip3yd-webp.webp',
'//p1-arco.byteimg.com/tos-cn-i-uwbnlip3yd/24e0dd27418d2291b65db1b21aa62254.png~tplv-uwbnlip3yd-webp.webp',
],
indicatorPosition: 'bottom',
indicatorType: 'dot',
showArrow: 'always',
direction: 'horizontal',
animation: 'slide',
autoPlay: false,
autoPlayInterval: 3000,
autoPlayHoverToPause: true,
moveSpeed: 500,
timingFunc: 'cubic-bezier(0.34, 0.69, 0.1, 1)',
};
export const Carousel = implementRuntimeComponent({
version: 'arco/v1',
metadata: {
...FALLBACK_METADATA,
name: 'carousel',
displayName: 'Carousel',
exampleProperties,
annotations: {
category: 'Data Display',
},
},
spec: {
properties: InputPropsSpec,
state: InputStateSpec,
methods: {},
slots: {},
styleSlots: ['carousel', 'image'],
events: ['onChange', 'onBlur', 'onFocus'],
},
})(props => {
const { getElement, customStyle } = props;
const { imageSrc, autoPlay, autoPlayHoverToPause, autoPlayInterval, ...cProps } =
getComponentProps(props);
const ref = useRef<CarouselHandle>(null as any);
useEffect(() => {
const ele = ref.current?.dom;
if (getElement && ele) {
getElement(ele);
}
}, [getElement, ref]);
return (
<BaseCarousel
carousel={ref}
autoPlay={
autoPlay && { interval: autoPlayInterval, hoverToPause: autoPlayHoverToPause }
}
className={css(customStyle?.carousel, defaultCarouselStyle)}
{...cProps}
>
{imageSrc.map((src, idx) => {
return (
<div className={css(customStyle?.image)} key={idx}>
<img style={{ width: '100%' }} src={src} />
</div>
);
})}
</BaseCarousel>
);
});

View File

@ -0,0 +1,97 @@
import { InputNumber } from '@arco-design/web-react';
import { implementRuntimeComponent } from '@sunmao-ui/runtime';
import { css } from '@emotion/css';
import { Type, Static } from '@sinclair/typebox';
import { FALLBACK_METADATA, getComponentProps } from '../sunmao-helper';
import { NumberInputPropsSpec as BaseNumberInputPropsSpec } from '../generated/types/NumberInput';
import { useEffect, useRef } from 'react';
import { RefInputType } from '@arco-design/web-react/es/Input/interface';
import { useStateValue } from 'src/hooks/useStateValue';
const InputPropsSpec = Type.Object({
...BaseNumberInputPropsSpec,
});
const InputStateSpec = Type.Object({
value: Type.Number(),
});
const exampleProperties: Static<typeof InputPropsSpec> = {
defaultValue: 1,
disabled: false,
placeholder: 'please input',
error: false,
size: 'default',
buttonMode: false,
min: 0,
max: 5,
readOnly: false,
step: 1,
precision: 1,
updateWhenDefaultValueChanges: false,
};
export const NumberInput = implementRuntimeComponent({
version: 'arco/v1',
metadata: {
...FALLBACK_METADATA,
name: 'numberInput',
displayName: 'Number Input',
exampleProperties,
annotations: {
category: 'Data Entry',
},
},
spec: {
properties: InputPropsSpec,
state: InputStateSpec,
methods: {},
slots: {
prefix: { slotProps: Type.Object({}) },
suffix: { slotProps: Type.Object({}) },
},
styleSlots: ['input'],
events: ['onChange', 'onBlur', 'onFocus'],
},
})(props => {
const { getElement, slotsElements, customStyle, callbackMap, mergeState } = props;
const { buttonMode, defaultValue, updateWhenDefaultValueChanges, ...cProps } =
getComponentProps(props);
const [value, setValue] = useStateValue(
defaultValue,
mergeState,
updateWhenDefaultValueChanges
);
const ref = useRef<RefInputType | null>(null);
useEffect(() => {
const ele = ref.current?.dom;
if (getElement && ele) {
getElement(ele);
}
}, [getElement, ref]);
return (
<InputNumber
ref={ref}
className={css(customStyle?.input)}
onChange={value => {
setValue(value);
mergeState({
value,
});
callbackMap?.onChange?.();
}}
onBlur={() => {
callbackMap?.onBlur?.();
}}
onFocus={() => {
callbackMap?.onFocus?.();
}}
value={value}
{...cProps}
prefix={slotsElements.prefix ? slotsElements.prefix({}) : null}
suffix={slotsElements.suffix ? slotsElements.suffix({}) : null}
mode={buttonMode ? 'button' : 'embed'}
/>
);
});

View File

@ -0,0 +1,92 @@
import { Tag as BaseTag } from '@arco-design/web-react';
import { implementRuntimeComponent } from '@sunmao-ui/runtime';
import { css } from '@emotion/css';
import { Type, Static } from '@sinclair/typebox';
import { FALLBACK_METADATA, getComponentProps } from '../sunmao-helper';
import { TagPropsSpec as BaseTagPropsSpec } from '../generated/types/Tag';
import { useEffect, useState } from 'react';
const TagPropsSpec = Type.Object(BaseTagPropsSpec);
const TagStateSpec = Type.Object({
checked: Type.Boolean(),
});
const exampleProperties: Static<typeof TagPropsSpec> = {
content: 'tag',
closable: false,
checkable: false,
defaultChecked: false,
color: '',
size: 'large',
bordered: false,
defaultVisible: true,
};
export const Tag = implementRuntimeComponent({
version: 'arco/v1',
metadata: {
...FALLBACK_METADATA,
name: 'tag',
displayName: 'Tag',
exampleProperties,
annotations: {
category: 'Data Display',
},
},
spec: {
properties: TagPropsSpec,
state: TagStateSpec,
methods: {},
slots: {
content: {
slotProps: Type.Object({}),
},
icon: {
slotProps: Type.Object({}),
},
},
styleSlots: ['content'],
events: ['onCheck', 'onClose'],
},
})(props => {
const { content, defaultChecked, defaultVisible, checkable, ...cProps } =
getComponentProps(props);
const { slotsElements, customStyle, elementRef, callbackMap, mergeState } = props;
const [checked, setChecked] = useState<boolean | undefined>(defaultChecked);
const [visible, setVisible] = useState(defaultVisible);
useEffect(() => {
if (!checkable) {
setChecked(undefined);
mergeState({ checked: undefined });
} else {
setChecked(defaultChecked);
mergeState({ checked: defaultChecked });
}
}, [checkable, defaultChecked, mergeState, setChecked]);
return (
<BaseTag
checked={checked}
className={css(customStyle?.content)}
ref={elementRef}
checkable={checkable}
visible={visible}
onCheck={() => {
setChecked(prev => !prev);
mergeState({ checked: !checked });
callbackMap?.onCheck?.();
}}
onClose={() => {
setVisible(false);
setChecked(undefined);
mergeState({ checked: undefined });
callbackMap?.onClose?.();
}}
icon={slotsElements.icon ? slotsElements.icon({}) : null}
{...cProps}
>
{(slotsElements.content && slotsElements.content({})) || content}
</BaseTag>
);
});

View File

@ -0,0 +1,62 @@
import { Type } from '@sinclair/typebox';
import { Category } from '../../constants/category';
import { StringUnion } from '../../sunmao-helper';
export const CarouselPropsSpec = {
imageSrc: Type.Array(Type.String(), {
title: 'Image Src',
category: Category.Basic,
}),
indicatorType: StringUnion(['dot', 'line', 'slider'], {
title: 'Indicator Type',
category: Category.Basic,
}),
indicatorPosition: StringUnion(['left', 'right', 'top', 'bottom', 'outer'], {
title: 'Indicator Type',
category: Category.Basic,
}),
direction: StringUnion(['vertical', 'horizontal'], {
title: 'Direction',
category: Category.Basic,
}),
showArrow: StringUnion(['always', 'hover', 'never'], {
title: 'Show Arrow',
category: Category.Behavior,
}),
animation: StringUnion(['slide', 'card', 'fade'], {
title: 'Animation',
category: Category.Behavior,
}),
moveSpeed: Type.Number({
title: 'Move Speed',
category: Category.Behavior,
}),
trigger: Type.Optional(
StringUnion(['click', 'hover'], {
title: 'Trigger',
category: Category.Behavior,
})
),
autoPlay: Type.Boolean({
title: 'Auto Play',
category: Category.Behavior,
}),
autoPlayInterval: Type.Optional(
Type.Number({
title: 'Auto Play Interval',
category: Category.Behavior,
conditions: [{ key: 'autoPlay', value: true }],
})
),
autoPlayHoverToPause: Type.Optional(
Type.Boolean({
title: 'Auto Play Hover To Pause',
category: Category.Behavior,
conditions: [{ key: 'autoPlay', value: true }],
})
),
timingFunc: Type.String({
title: 'Timing Func',
category: Category.Behavior,
}),
};

View File

@ -0,0 +1,54 @@
import { Type } from '@sinclair/typebox';
import { StringUnion } from '../../sunmao-helper';
import { Category } from '../../constants/category';
export const NumberInputPropsSpec = {
defaultValue: Type.Number({
title: 'Default Value',
category: Category.Basic,
}),
updateWhenDefaultValueChanges: Type.Boolean({
title: 'Update When Default Value Changes',
category: Category.Basic,
}),
min: Type.Number({
title: 'Min',
category: Category.Basic,
}),
max: Type.Number({
title: 'Max',
category: Category.Basic,
}),
placeholder: Type.String({
title: 'Placeholder',
category: Category.Behavior,
}),
disabled: Type.Boolean({
title: 'Disabled',
category: Category.Behavior,
}),
buttonMode: Type.Boolean({
title: 'Button Mode',
category: Category.Behavior,
}),
precision: Type.Number({
title: 'Precision',
category: Category.Behavior,
}),
step: Type.Number({
title: 'Step',
category: Category.Behavior,
}),
size: StringUnion(['default', 'mini', 'small', 'large'], {
title: 'Size',
category: Category.Style,
}),
readOnly: Type.Boolean({
title: 'Read Only',
category: Category.Behavior,
}),
error: Type.Boolean({
title: 'Error',
category: Category.Behavior,
}),
};

View File

@ -0,0 +1,40 @@
import { Type } from '@sinclair/typebox';
import { Category } from '../../constants/category';
import { StringUnion } from '../../sunmao-helper';
export const TagPropsSpec = {
content: Type.String({
title: 'Content',
category: Category.Basic,
}),
closable: Type.Boolean({
title: 'Closable',
category: Category.Behavior,
}),
checkable: Type.Boolean({
title: 'Checkable',
category: Category.Behavior,
}),
defaultChecked: Type.Boolean({
title: 'Default Checked',
category: Category.Behavior,
conditions: [{ key: 'checkable', value: true }],
}),
defaultVisible: Type.Boolean({
title: 'Default Visible',
category: Category.Behavior,
}),
color: Type.String({
title: 'Color',
category: Category.Style,
widget: 'core/v1/color',
}),
size: StringUnion(['large', 'medium', 'default', 'small'], {
title: 'Size',
category: Category.Style,
}),
bordered: Type.Boolean({
title: 'Bordered',
category: Category.Style,
}),
};

View File

@ -31,6 +31,7 @@ import { Alert } from './components/Alert';
import { Link } from './components/Link';
import { Switch } from './components/Switch';
import { PasswordInput } from './components/PasswordInput';
import { NumberInput } from './components/NumberInput';
import { TextArea } from './components/TextArea';
import { Tabs } from './components/Tabs';
import { FormControl } from './components/Form/FormControl';
@ -39,11 +40,14 @@ import { Row, Col } from './components/Grid';
import { Slider } from './components/Slider';
import { DatePicker } from './components/DatePicker';
import { TimePicker } from './components/TimePicker';
import { Carousel } from './components/Carousel';
import { Tag } from './components/Tag';
import './style.css';
import { MessageUtilMethodFactory } from './methods/Message';
export const components: SunmaoLib['components'] = [
Tag,
Table,
Pagination,
Steps,
@ -86,6 +90,8 @@ export const components: SunmaoLib['components'] = [
Slider,
DatePicker,
TimePicker,
NumberInput,
Carousel,
];
export const traits: SunmaoLib['traits'] = [];
export const modules: SunmaoLib['modules'] = [];