Merge pull request #432 from webzard-io/feat/arco

Feat/arco
This commit is contained in:
tanbowensg 2022-06-06 14:51:27 +08:00 committed by GitHub
commit 5910e9d2d7
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
10 changed files with 457 additions and 97 deletions

View File

@ -28,7 +28,7 @@
"prepublish": "npm run build && npm run typings"
},
"dependencies": {
"@arco-design/web-react": "^2.29.0",
"@arco-design/web-react": "^2.34.0",
"@emotion/css": "^11.7.1",
"@sinclair/typebox": "^0.21.2",
"@sunmao-ui/core": "^0.6.0",

View File

@ -11,6 +11,7 @@ import {
DisabledTimeFunc,
DisabledTimeProps,
} from '@arco-design/web-react/es/DatePicker/interface';
import React from 'react';
const DatePickerPropsSpec = Type.Object(BaseDatePickerPropsSpec);
const DatePickerStateSpec = Type.Object({
@ -30,6 +31,9 @@ const RangePicker = BaseDatePicker.RangePicker;
const exampleProperties: Static<typeof DatePickerPropsSpec> = {
disabled: false,
useUtcOffset: false,
utcOffset: 0,
timezone: '',
placeholder: 'Please Select',
position: 'bl',
dayStartOfWeek: 0,
@ -94,71 +98,72 @@ export const DatePicker = implementRuntimeComponent({
disabledRangeTime,
disabledDate,
range,
placeholder,
utcOffset,
useUtcOffset,
rangePlaceholder,
rangeDisabled,
type,
panelOnly,
clearRangeOnReselect,
showTime,
...cProps
} = getComponentProps(props);
const { elementRef, customStyle, slotsElements, callbackMap, mergeState } = props;
const Picker = DatePickerType[type];
const triggerElement = slotsElements.triggerElement && slotsElements.triggerElement({});
const pickerProps = {
showTime: type === 'date' ? showTime : undefined,
extra: slotsElements.footer && slotsElements.footer({}),
utcOffset: useUtcOffset ? utcOffset : undefined,
triggerElement: triggerElement
? (triggerElement as React.ReactNode[])[0]
: panelOnly
? null
: undefined,
disabledDate: (current: Dayjs) => getDisabledDate(current, disabledDate),
onChange: (dateString: string | string[], date: Dayjs | Dayjs[]) => {
mergeState({
date,
dateString,
});
callbackMap?.onChange?.();
},
onVisibleChange: (visible: boolean | undefined) => {
mergeState({ visible });
callbackMap?.onVisibleChange?.();
},
...cProps,
};
return (
<span ref={elementRef} className={css(customStyle?.content)}>
{range ? (
<RangePicker
{...pickerProps}
disabledTime={(date, type) =>
getDisabledRangeTime(date, type, disabledRangeTime!)
}
disabledDate={current => getDisabledDate(current, disabledDate)}
extra={slotsElements.footer}
triggerElement={panelOnly ? null : slotsElements.triggerElement}
mode={type}
placeholder={rangePlaceholder?.length === 0 ? undefined : rangePlaceholder}
clearRangeOnReselect={clearRangeOnReselect}
{...cProps}
disabled={rangeDisabled}
onChange={(dateString, date) => {
mergeState({
date,
dateString,
});
callbackMap?.onChange?.();
}}
onVisibleChange={visible => {
mergeState({ visible });
callbackMap?.onVisibleChange?.();
}}
/>
) : (
<Picker
{...pickerProps}
disabledTime={date => getDisabledTime(date, disabledTime)}
disabledDate={current => getDisabledDate(current, disabledDate)}
extra={slotsElements.footer}
triggerElement={panelOnly ? null : slotsElements.triggerElement}
placeholder={placeholder}
{...cProps}
onChange={(dateString, date) => {
mergeState({
date,
dateString,
});
callbackMap?.onChange?.();
}}
onVisibleChange={visible => {
mergeState({ visible });
callbackMap?.onVisibleChange?.();
}}
/>
)}
</span>
);
});
export type Dayjs = Parameters<DisabledTimeFunc>[0];
function getDisabledDate(
date: Parameters<DisabledTimeFunc>[0],
date: Dayjs,
disabledDate: Static<typeof BaseDatePickerPropsSpec.disabledDate>
) {
if (disabledDate.disabledType === 'after') {
@ -167,6 +172,7 @@ function getDisabledDate(
if (disabledDate.disabledType === 'before') {
return date!.isBefore(disabledDate.date);
}
// TODO support year, month, and week
if (disabledDate.disabledType === 'range') {
if (!disabledDate.dateRange || !Array.isArray(disabledDate.dateRange)) {
return false;
@ -181,8 +187,8 @@ function getDisabledDate(
return false;
}
function getDisabledTime(
date: Parameters<DisabledTimeFunc>[0],
export function getDisabledTime(
date: Dayjs,
range: Static<typeof BaseDatePickerPropsSpec.disabledTime>
): DisabledTimeProps {
const result: DisabledTimeProps = {};
@ -197,8 +203,8 @@ function getDisabledTime(
return result;
}
function getDisabledRangeTime(
date: Parameters<DisabledTimeFunc>[0],
export function getDisabledRangeTime(
date: Dayjs,
type: 'start' | 'end',
range: Static<typeof RangePickerPropsSpec.disabledRangeTime>
): DisabledTimeProps {

View File

@ -120,6 +120,7 @@ export const exampleProperties: Static<typeof TablePropsSpec> = {
link: `link${Math.random() > 0.5 ? '-A' : '-B'}`,
salary: Math.floor(Math.random() * 1000),
})),
checkCrossPage: true,
pagination: {
enablePagination: true,
pageSize: 6,
@ -157,20 +158,19 @@ export const Table = implementRuntimeComponent({
methods: {},
slots: {},
styleSlots: ['content'],
events: [
'onRowClick',
'onSearch',
'onSelect',
'onSelectAll',
'onPageChange',
'onFilter',
'onSort',
'onChange',
],
events: ['onRowClick', 'onSearch', 'onPageChange', 'onFilter', 'onSort', 'onChange'],
},
})(props => {
const { getElement, callbackMap, app, mergeState, customStyle, services, component } =
props;
const {
getElement,
checkCrossPage,
callbackMap,
app,
mergeState,
customStyle,
services,
component,
} = props;
const ref = useRef<TableInstance | null>(null);
const { pagination, rowClick, useDefaultFilter, useDefaultSort, data, ...cProps } =
@ -188,7 +188,6 @@ export const Table = implementRuntimeComponent({
const rowSelectionType = rowSelectionTypeMap[cProps.rowSelectionType];
const [selectedRowKeys, setSelectedRowKeys] = useState<string[]>([]);
const [currentPage, setCurrentPage] = useStateValue<number>(
defaultCurrent ?? 1,
mergeState,
@ -233,23 +232,13 @@ export const Table = implementRuntimeComponent({
}, [data, sortRule]);
const currentPageData = useMemo(() => {
if (enablePagination) {
if (enablePagination && useCustomPagination) {
// If the `useCustomPagination` is true, then no pagination will be done and data over the pagesize will be sliced
// Otherwise it will automatically paginate on the front end based on the current page
if (useCustomPagination) {
return sortedData?.slice(0, pageSize);
} else {
return sortedData?.slice((currentPage - 1) * pageSize!, currentPage * pageSize!);
}
return sortedData?.slice(0, pageSize);
}
return sortedData;
}, [pageSize, currentPage, sortedData, enablePagination, useCustomPagination]);
useEffect(() => {
mergeState({
selectedRowKeys,
});
}, [selectedRowKeys, mergeState]);
}, [pageSize, sortedData, enablePagination, useCustomPagination]);
useEffect(() => {
setColumns(
@ -448,18 +437,14 @@ export const Table = implementRuntimeComponent({
onChange={handleChange}
rowSelection={{
type: rowSelectionType,
selectedRowKeys,
onChange(selectedRowKeys) {
setSelectedRowKeys(selectedRowKeys as string[]);
},
onSelect: (selected, record, selectedRows) => {
selected && mergeState({ selectedRow: record });
mergeState({ selectedRows });
callbackMap?.onSelect?.();
},
onSelectAll(selected, selectedRows) {
mergeState({ selectedRows });
callbackMap?.onSelectAll?.();
checkCrossPage: checkCrossPage,
// This option is required to achieve multi-selection across pages when customizing paging
preserveSelectedRowKeys: useCustomPagination ? checkCrossPage : undefined,
onChange(selectedRowKeys, selectedRows) {
mergeState({
selectedRowKeys: selectedRowKeys as string[],
selectedRows,
});
},
}}
onRow={

View File

@ -0,0 +1,123 @@
import { TimePicker as BaseTimePicker } 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 { TimePickerPropsSpec as BaseTimePickerPropsSpec } from '../generated/types/TimePicker';
import { Dayjs } from './DatePicker';
const TimePickerPropsSpec = Type.Object(BaseTimePickerPropsSpec);
const TimePickerStateSpec = Type.Object({
visible: Type.Boolean(),
time: Type.Any(),
timeString: Type.Union([Type.Array(Type.String()), Type.String()]),
});
const exampleProperties: Static<typeof TimePickerPropsSpec> = {
disabled: false,
disableConfirm: false,
hideDisabledOptions: false,
step: {
hour: 1,
minute: 1,
second: 1,
},
showNowBtn: true,
placeholder: 'Please Select',
position: 'bl',
format: 'HH:mm:ss',
allowClear: false,
defaultValue: '18:24:23',
rangeDefaultValue: ['09:24:53', '18:44:33'],
range: false,
size: 'default',
use12Hours: false,
disabledTime: {
disabledHours: [0, 1, 2],
disabledMinutes: new Array(30).fill(0).map((e, i) => i),
disabledSeconds: [10],
},
rangePlaceholder: ['Start date', 'End Date'],
useUtcOffset: false,
order: false,
utcOffset: 0,
timezone: '',
};
const RangePicker = BaseTimePicker.RangePicker;
export const TimePicker = implementRuntimeComponent({
version: 'arco/v1',
metadata: {
...FALLBACK_METADATA,
name: 'timePicker',
displayName: 'TimePicker',
exampleProperties,
annotations: {
category: 'Display',
},
},
spec: {
properties: TimePickerPropsSpec,
state: TimePickerStateSpec,
methods: {},
slots: {
footer: {
slotProps: Type.Object({}),
},
triggerElement: {
slotProps: Type.Object({}),
},
},
styleSlots: ['content'],
events: ['onChange', 'onClear', 'onVisibleChange'],
},
})(props => {
const {
range,
disabledTime,
useUtcOffset,
utcOffset,
rangeDefaultValue,
rangePlaceholder,
...cProps
} = getComponentProps(props);
const { elementRef, customStyle, slotsElements, callbackMap, mergeState } = props;
const pickerProps = {
extra: slotsElements.footer,
utcOffset: useUtcOffset ? utcOffset : undefined,
onChange: (timeString: string | string[], time: Dayjs | Dayjs[]) => {
mergeState({
time,
timeString,
});
callbackMap?.onChange?.();
},
...getDisabledTime(disabledTime),
...cProps,
};
return (
<span ref={elementRef} className={css(customStyle?.content)}>
{range ? (
<RangePicker
{...pickerProps}
defaultValue={rangeDefaultValue}
placeholder={rangePlaceholder}
/>
) : (
<BaseTimePicker {...pickerProps} />
)}
</span>
);
});
function getDisabledTime(
disabledTime: Static<typeof BaseTimePickerPropsSpec.disabledTime>
) {
return {
disabledHours: () => disabledTime.disabledHours,
disabledMinutes: () => disabledTime.disabledMinutes,
disabledSeconds: () => disabledTime.disabledSeconds,
};
}

View File

@ -169,11 +169,19 @@ export const DatePickerPropsSpec = {
category: Category.Behavior,
weight: 98,
}),
showTime: Type.Boolean({
title: 'Show Time',
category: Category.Behavior,
weight: 97,
}),
showTime: Type.Optional(
Type.Boolean({
title: 'Show Time',
category: Category.Behavior,
conditions: [
{
key: 'type',
value: 'date',
},
],
weight: 97,
})
),
disabledDate: Type.Object(DisabledDateSpec, {
title: 'Disabled Date',
category: Category.Behavior,
@ -211,5 +219,23 @@ export const DatePickerPropsSpec = {
title: 'Size',
category: Category.Layout,
}),
timezone: Type.String({
title: 'Timezone',
category: Category.Behavior,
}),
useUtcOffset: Type.Boolean({
title: 'Open UTC Offset',
category: Category.Behavior,
}),
utcOffset: Type.Number({
title: 'UTC Offset',
category: Category.Behavior,
conditions: [
{
key: 'useUtcOffset',
value: true,
},
],
}),
...RangePickerPropsSpec,
};

View File

@ -262,7 +262,7 @@ export const ColumnSpec = Type.Object({
export const TablePropsSpec = Type.Object({
data: Type.Array(Type.Any(), {
title: 'Default Data',
title: 'Data',
category: Category.Data,
weight: 0,
widget: 'core/v1/expression',
@ -327,15 +327,20 @@ export const TablePropsSpec = Type.Object({
category: Category.Layout,
weight: 10,
}),
rowSelectionType: StringUnion(['multiple', 'single', 'disable'], {
title: 'Row Selection Type',
category: Category.Basic,
}),
rowClick: Type.Boolean({
title: 'Row Click',
category: Category.Basic,
description: 'If on, the table can be selected without setting the rowSelectionType',
}),
checkCrossPage: Type.Boolean({
title: 'Check Cross Page',
category: Category.Basic,
description: 'Whether the checkboxes in multi-select mode cross pages',
}),
rowSelectionType: StringUnion(['multiple', 'single', 'disable'], {
title: 'Row Selection Type',
category: Category.Basic,
}),
loading: Type.Boolean({
title: 'Show Loading',
category: Category.Basic,

View File

@ -0,0 +1,168 @@
import { Type } from '@sinclair/typebox';
import { Category } from '../../constants/category';
import { StringUnion } from '../../sunmao-helper';
import { CoreWidgetName, CORE_VERSION } from '@sunmao-ui/editor-sdk';
const expressionWidget = `${CORE_VERSION}/${CoreWidgetName.Expression}`;
const DisabledTimeSpec = {
disabledHours: Type.Array(Type.Number(), {
title: 'Disabled Hours',
widget: expressionWidget,
}),
disabledMinutes: Type.Array(Type.Number(), {
title: 'Disabled Minutes',
widget: expressionWidget,
}),
disabledSeconds: Type.Array(Type.Number(), {
title: 'Disabled Seconds',
widget: expressionWidget,
}),
};
export const RangePickerPropsSpec = {
rangeDefaultValue: Type.Array(Type.Any(), {
title: 'Default Value',
category: Category.Basic,
conditions: [
{
key: 'range',
value: true,
},
],
widget: expressionWidget,
}),
rangePlaceholder: Type.Optional(
Type.Array(Type.String(), {
title: 'Placeholder',
category: Category.Basic,
widget: expressionWidget,
conditions: [
{
key: 'range',
value: true,
},
],
})
),
order: Type.Boolean({
title: 'Order',
description: 'Whether the start and end times are automatically sorted',
category: Category.Behavior,
conditions: [
{
key: 'range',
value: true,
},
],
}),
};
export const TimePickerPropsSpec = {
range: Type.Boolean({
title: 'Range',
category: Category.Basic,
weight: 100,
}),
defaultValue: Type.Any({
title: 'Default Value',
category: Category.Basic,
conditions: [
{
key: 'range',
value: false,
},
],
}),
disabled: Type.Boolean({
title: 'Disabled',
category: Category.Behavior,
}),
allowClear: Type.Boolean({
title: 'Allow Clear',
category: Category.Behavior,
}),
disableConfirm: Type.Boolean({
title: 'Disable Confirm',
category: Category.Behavior,
description: '',
}),
hideDisabledOptions: Type.Boolean({
title: 'Hide Disabled Options',
category: Category.Behavior,
description: '',
}),
use12Hours: Type.Boolean({
title: 'Use 12 Hours',
category: Category.Behavior,
}),
format: Type.String({
title: 'Format',
category: Category.Basic,
description: ' Date format, refer to dayjs',
}),
step: Type.Object(
{
hour: Type.Number({
title: 'Hour',
}),
minute: Type.Number({
title: 'Minute',
}),
second: Type.Number({
title: 'Second',
}),
},
{
title: 'Step',
category: Category.Behavior,
widget: expressionWidget,
description: 'Set the hour/minute/second selection interval',
}
),
position: StringUnion(['top', 'tl', 'tr', 'bottom', 'bl', 'br'], {
title: 'Position',
category: Category.Layout,
}),
placeholder: Type.String({
title: 'Placeholder',
category: Category.Basic,
conditions: [
{
key: 'range',
value: false,
},
],
}),
disabledTime: Type.Object(DisabledTimeSpec, {
title: 'Disabled Time',
category: Category.Behavior,
description: '',
}),
timezone: Type.String({
title: 'Timezone',
category: Category.Behavior,
}),
useUtcOffset: Type.Boolean({
title: 'Open UTC Offset',
category: Category.Behavior,
}),
utcOffset: Type.Number({
title: 'UTC Offset',
category: Category.Behavior,
conditions: [
{
key: 'useUtcOffset',
value: true,
},
],
}),
showNowBtn: Type.Boolean({
title: 'Show Now Button',
category: Category.Behavior,
}),
size: StringUnion(['mini', 'small', 'default', 'large'], {
title: 'Size',
category: Category.Layout,
}),
...RangePickerPropsSpec,
};

View File

@ -38,8 +38,10 @@ import { Descriptions } from './components/Descriptions';
import { Row, Col } from './components/Grid';
import { Slider } from './components/Slider';
import { DatePicker } from './components/DatePicker';
import { TimePicker } from './components/TimePicker';
import './style.css';
import { MessageUtilMethodFactory } from './methods/Message';
export const components: SunmaoLib['components'] = [
Table,
@ -83,12 +85,15 @@ export const components: SunmaoLib['components'] = [
Col,
Slider,
DatePicker,
TimePicker,
];
export const traits: SunmaoLib['traits'] = [];
export const modules: SunmaoLib['modules'] = [];
export const utilMethods: SunmaoLib['utilMethods'] = [MessageUtilMethodFactory];
export const ArcoDesignLib: SunmaoLib = {
components,
traits,
modules,
utilMethods,
};

View File

@ -0,0 +1,44 @@
import { implementUtilMethod } from '@sunmao-ui/runtime';
import { Type } from '@sinclair/typebox';
import { Message as BaseMessage } from '@arco-design/web-react';
import { StringUnion } from '@sunmao-ui/shared';
const ParameterSpec = Type.Object({
type: StringUnion(['info', 'success', 'warning', 'error', 'normal', 'loading'], {
defaultValue: 'info',
}),
content: Type.String({
defaultValue: 'info',
}),
position: StringUnion(['top', 'bottom'], {
defaultValue: 'top',
}),
closable: Type.Boolean({
defaultValue: false,
}),
duration: Type.Number({ defaultValue: 1000 }),
});
export const MessageUtilMethodFactory = () => {
const Message = implementUtilMethod({
version: 'arco/v1',
metadata: {
name: 'message',
},
spec: {
parameters: ParameterSpec,
},
})(parameters => {
const { type, content, duration, ...rest } = parameters;
const Message = BaseMessage[type];
Message({
className: type,
content,
duration,
...rest,
});
});
return [Message];
};

View File

@ -16,15 +16,15 @@
dependencies:
color "^3.1.3"
"@arco-design/web-react@^2.29.0":
version "2.29.2"
resolved "https://registry.npmjs.org/@arco-design/web-react/-/web-react-2.29.2.tgz"
integrity sha512-nDMIWfuvYKlxc8lFBtaLPPDURtAJLmXu77r0KCH0Y6GB3S8mUQb7hs0hCC/K+1Pp5yzuVr05ESrEYovM8O5AvQ==
"@arco-design/web-react@^2.34.0":
version "2.34.0"
resolved "https://registry.yarnpkg.com/@arco-design/web-react/-/web-react-2.34.0.tgz#e30a2ea0076385c6a3baf16225de142fe00e17b1"
integrity sha512-mcUq3n2O/juh1Hk9R6fzvEqvfmUvq/VD03FAJ0vHBhASTzH3ThFMFubE5yTTz+dUN2QuPVuSGFSeQR1jXcOE/g==
dependencies:
"@arco-design/color" "^0.4.0"
"@babel/runtime" "^7.5.5"
b-tween "^0.3.3"
b-validate "^1.3.4"
b-validate "^1.4.0"
compute-scroll-into-view "^1.0.17"
dayjs "^1.10.5"
lodash "^4.17.21"
@ -4306,12 +4306,10 @@ b-tween@^0.3.3:
resolved "https://registry.npmjs.org/b-tween/-/b-tween-0.3.3.tgz"
integrity sha512-oEHegcRpA7fAuc9KC4nktucuZn2aS8htymCPcP3qkEGPqiBH+GfqtqoG2l7LxHngg6O0HFM7hOeOYExl1Oz4ZA==
b-validate@^1.3.4:
version "1.3.4"
resolved "https://registry.npmjs.org/b-validate/-/b-validate-1.3.4.tgz"
integrity sha512-7Bj+KFUcxk6c+qc3HiCR20qMOlHJmb7NSrVAS1amryVUT+7GTNqCp2Qk4XZP8XD3MBfZSqon/XlxNhHnxyB8ng==
dependencies:
lodash.isequal "^4.5.0"
b-validate@^1.4.0:
version "1.4.0"
resolved "https://registry.yarnpkg.com/b-validate/-/b-validate-1.4.0.tgz#3214c8c21a04724fcca328dcdd7f0f32d61a29b5"
integrity sha512-oSXHKWXisRFuHnmNr5QXsg9JoyUTRCfBbM4hAcAqDjAO1jeV7aQXTkzS7O2WVDDHlnGeqH7v5Im4Z+eKU1x5Mw==
babel-jest@^27.1.0, babel-jest@^27.2.1, babel-jest@^27.3.1:
version "27.3.1"
@ -8262,7 +8260,7 @@ lodash.debounce@^4.0.8:
resolved "https://registry.npmjs.org/lodash.debounce/-/lodash.debounce-4.0.8.tgz"
integrity sha1-gteb/zCmfEAF/9XiUVMArZyk168=
lodash.isequal@^4.0.0, lodash.isequal@^4.5.0:
lodash.isequal@^4.0.0:
version "4.5.0"
resolved "https://registry.npmjs.org/lodash.isequal/-/lodash.isequal-4.5.0.tgz"
integrity sha1-QVxEePK8wwEgwizhDtMib30+GOA=