feat: finish calendar component develop (#199)

* feat: add Calendar component into schema components

* feat: add Calendar component into schema components

* feat: modify calendar get data async

* refactor: remove toolbar

* fix: modify calendar

* feat: modify fieldName

* feat: add new task in calendar

* fix: modify calendar component

* feat: add Calendar component into schema components

* feat: modify calendar get data async

* feat: add Calendar component into schema components

* refactor: remove toolbar

* fix: modify calendar

* feat: modify fieldName

* feat: add new task in calendar

* fix: modify calendar component

* fix: modify "useFormItemInitializerFields"

* fix: add data to calendar

* fix: add data to calendar

* fix: add data to calendar

* feat: add remove and edit in calendar

* fix: modify edit and remove in calendar component

* fix: modify edit and remove in calendar component

* fix: modify edit and remove in calendar component

* refactor: refactor event

* feat: add Calendar component into schema components

* feat: modify calendar get data async

* feat: add Calendar component into schema components

* refactor: remove toolbar

* fix: modify calendar

* feat: modify fieldName

* feat: add new task in calendar

* fix: modify calendar component

* feat: add Calendar component into schema components

* feat: modify calendar get data async

* feat: add Calendar component into schema components

* refactor: remove toolbar

* fix: modify calendar

* feat: add new task in calendar

* fix: modify calendar component

* fix: modify "useFormItemInitializerFields"

* fix: add data to calendar

* fix: add data to calendar

* fix: add data to calendar

* feat: add remove and edit in calendar

* fix: modify edit and remove in calendar component

* fix: modify edit and remove in calendar component

* fix: modify edit and remove in calendar component

* refactor: refactor event

* fix: modify conflict

* refactor: change new initializer

Co-authored-by: chenos <chenlinxh@gmail.com>
This commit is contained in:
SemmyWong 2022-02-21 15:31:31 +08:00 committed by GitHub
parent f925922a73
commit 1e3cdf9572
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
28 changed files with 2068 additions and 21 deletions

View File

@ -30,6 +30,7 @@
"i18next": "^21.6.0",
"marked": "^4.0.12",
"react-beautiful-dnd": "^13.1.0",
"react-big-calendar": "^0.38.7",
"react-helmet": "^6.1.0",
"react-i18next": "^11.15.1",
"react-image-lightbox": "^5.1.4",

View File

@ -25,7 +25,7 @@ export function useRequest<P>(
const result = useReq(service, {
...options,
onSuccess(...args) {
options.onSuccess && options.onSuccess(...args);
options.onSuccess?.(...args);
if (options.uid) {
api.services[options.uid] = result;
}
@ -49,7 +49,7 @@ export function useRequest<P>(
{
...options,
onSuccess(...args) {
options.onSuccess && options.onSuccess(...args);
options.onSuccess?.(...args);
if (options.uid) {
api.services[options.uid] = result;
}

View File

@ -12,7 +12,7 @@ export const useCollectionField = () => {
if (!ctx) {
return {} as any;
}
const resourceName = `${ctx?.collectinName || collection?.name}.${ctx.name}`;
const resourceName = `${ctx?.collectionName || collection?.name}.${ctx.name}`;
const resource = api?.resource(resourceName, record[ctx.sourceKey]);
return {
...ctx,

View File

@ -28,8 +28,7 @@ export interface ICollectionProviderProps {
export interface CollectionFieldOptions {
name?: any;
collectinName?: string;
targetKey?: string;
collectionName?: string;
sourceKey?: string; // association field
uiSchema?: ISchema;
}

View File

@ -276,5 +276,6 @@
"Purple": "Purple",
"Default": "Default",
"Add card": "Add card",
"edit title": "Edit Title"
"edit title": "Edit Title",
"turn page": "Turn Page"
}

View File

@ -276,5 +276,6 @@
"Default": "默认",
"Add card": "添加卡片",
"edit title": "修改标题"
"edit title": "修改标题",
"turn page": "翻页"
}

View File

@ -0,0 +1,163 @@
import { observer, useFieldSchema } from '@formily/react';
import { Switch } from 'antd';
import React from 'react';
import { useTranslation } from 'react-i18next';
import { useCollection } from '../../../collection-manager';
import { SchemaInitializer } from '../../../schema-initializer';
import { useDesignable } from '../../hooks';
export const ActionInitializer = observer((props: any) => {
const { name: collectName } = useCollection();
const { t } = useTranslation();
return (
<SchemaInitializer.Button
insertPosition={'beforeEnd'}
style={{ marginLeft: 8 }}
items={[
{
type: 'itemGroup',
title: t('Enable actions'),
children: [
{
type: 'item',
title: t('Today'),
component: InitializeAction,
schema: {
title: t('Today'),
'x-component': 'Calendar.Today',
'x-action': `calendar:today`,
'x-align': 'left',
},
},
{
type: 'item',
title: t('turn page'),
component: InitializeAction,
schema: {
title: t('turn page'),
'x-component': 'Calendar.Nav',
'x-action': `calendar:nav`,
'x-align': 'left',
},
},
{
type: 'item',
title: t('Title'),
component: InitializeAction,
schema: {
title: t('Title'),
'x-component': 'Calendar.Title',
'x-action': `calendar:title`,
'x-align': 'left',
},
},
{
type: 'item',
title: t('Select view'),
component: InitializeAction,
schema: {
title: t('Select view'),
'x-component': 'Calendar.ViewSelect',
'x-action': `calendar:viewSelect`,
'x-align': 'left',
},
},
{
type: 'item',
title: t('Add new'),
component: InitializeAction,
schema: {
title: t('Add new'),
'x-component': 'Action',
'x-component-props': {
type: 'primary',
},
'x-action': `action`,
'x-align': 'right',
properties: {
modal: {
'x-component': 'Action.Drawer',
'x-decorator': 'Form',
type: 'void',
title: 'Drawer Title',
properties: {
grid: {
type: 'void',
'x-component': 'Grid',
'x-item-initializer': 'FormItemInitializer',
},
footer: {
'x-component': 'Action.Drawer.Footer',
type: 'void',
properties: {
ok: {
title: 'submit',
'x-component': 'Action',
'x-component-props': {
useAction: '{{ useSaveAction }}',
type: 'primary',
},
},
close: {
title: 'Close',
'x-component': 'Action',
'x-component-props': {
useAction: '{{ useCloseAction }}',
},
},
},
},
},
},
},
},
},
],
},
]}
>
Configure actions
</SchemaInitializer.Button>
);
});
const useCurrentActionSchema = (action: string) => {
const fieldSchema = useFieldSchema();
const { remove } = useDesignable();
const schema: any = fieldSchema.reduceProperties((buf, s) => {
if (s['x-action'] === action) {
return s;
}
return buf;
});
return {
schema,
exists: !!schema,
remove() {
schema && remove(schema);
},
};
};
const InitializeAction = SchemaInitializer.itemWrap((props) => {
const { item, insert } = props;
const { exists, remove } = useCurrentActionSchema(item.schema['x-action']);
return (
<SchemaInitializer.Item
onClick={() => {
if (exists) {
return remove();
}
insert({
type: 'void',
'x-component': 'Action',
...item.schema,
});
}}
>
<div style={{ display: 'flex', alignItems: 'center', justifyContent: 'space-between' }}>
{item.title} <Switch size={'small'} checked={exists} />
</div>
</SchemaInitializer.Item>
);
});

View File

@ -1,5 +1,185 @@
import React from 'react';
import { LeftOutlined, RightOutlined } from '@ant-design/icons';
import { VoidField } from '@formily/core';
import { observer, RecursionField, Schema, useField, useFieldSchema } from '@formily/react';
import moment from 'moment';
import React, { useState } from 'react';
import { Calendar as BigCalendar, momentLocalizer } from 'react-big-calendar';
import * as dates from 'react-big-calendar/lib/utils/dates';
import { useTranslation } from 'react-i18next';
import { SchemaComponent } from '../..';
import { AsyncDataProvider, useRequest } from '../../../';
import { i18n } from '../../../i18n';
import { ActionBar, ActionContext } from '../action';
import { ActionInitializer } from './ActionInitializer';
import { CalendarContext, ToolbarContext } from './context';
import { Event } from './Event';
import { Filter } from './Filter';
import { FooterActionInitializer } from './FooterActionInitializer';
import { Nav } from './Nav';
import './style.less';
import { Title } from './Title';
import { Today } from './Today';
import type { ToolbarProps } from './types';
import { toEvents } from './utils';
import { ViewSelect } from './ViewSelect';
export const Calendar = () => {
return <div>Calendar</div>;
const localizer = momentLocalizer(moment);
function Toolbar(props: ToolbarProps) {
const fieldSchema = useFieldSchema();
const toolBarSchema: Schema = fieldSchema.reduceProperties((buf, current) => {
if (current['x-component'] === 'Calendar.ActionBar') {
return current;
}
return buf;
}, null);
return (
<ToolbarContext.Provider value={props}>
<RecursionField name={toolBarSchema.name} schema={toolBarSchema} />
</ToolbarContext.Provider>
);
}
const messages: any = {
allDay: '',
previous: (
<div>
<LeftOutlined />
</div>
),
next: (
<div>
<RightOutlined />
</div>
),
today: i18n.t('Today'),
month: i18n.t('Month'),
week: i18n.t('Week'),
work_week: i18n.t('Work week'),
day: i18n.t('Day'),
agenda: i18n.t('Agenda'),
date: i18n.t('Date'),
time: i18n.t('Time'),
event: i18n.t('Event'),
noEventsInRange: i18n.t('None'),
showMore: (count) => i18n.t('{{count}} more items', { count }),
};
const useRequestProps = (props) => {
const { request, dataSource } = props;
if (request) {
return request;
}
return (params: any = {}) => {
return Promise.resolve({
data: dataSource,
});
};
};
const useDefDataSource = (props, options) => {
return useRequest(useRequestProps(props), options);
};
export const Calendar: any = observer((props: any) => {
const {
useDataSource = useDefDataSource,
fieldNames = {
id: 'id',
title: 'title',
start: 'start',
end: 'end',
},
} = props;
const { t } = useTranslation();
const field = useField<VoidField>();
const fieldSchema = useFieldSchema();
const [visible, setVisible] = useState(false);
const [record, setRecord] = useState<any>({});
const result = useDataSource(props, {
uid: fieldSchema['x-uid'],
refreshDeps: [props.dataSource],
onSuccess(data) {
return toEvents(data?.data, fieldNames);
},
});
const eventSchema: Schema = fieldSchema.reduceProperties((buf, current) => {
if (current['x-component'] === 'Calendar.Event') {
return current;
}
return buf;
}, null);
return (
<AsyncDataProvider value={result}>
<CalendarContext.Provider value={{ field, props, record }}>
<div {...props} style={{ height: 700 }}>
<ActionContext.Provider value={{ visible, setVisible }}>
<SchemaComponent memoized name={eventSchema.name} schema={eventSchema as any} />
</ActionContext.Provider>
<BigCalendar
popup
selectable
events={Array.isArray(result?.data?.data) ? result?.data?.data : []}
views={['month', 'week', 'day']}
step={60}
showMultiDayTimes
messages={messages}
onSelectSlot={(slotInfo) => {
console.log('onSelectSlot', slotInfo);
}}
onDoubleClickEvent={(event) => {
console.log('onDoubleClickEvent');
}}
onSelectEvent={(event) => {
const record = result?.data?.data?.find((item) => item.id === event.id);
if (!record) {
return;
}
setRecord(record);
setVisible(true);
console.log('onSelectEvent');
}}
formats={{
monthHeaderFormat: 'Y-M',
agendaDateFormat: 'M-DD',
dayHeaderFormat: 'Y-M-DD',
dayRangeHeaderFormat: ({ start, end }, culture, local) => {
if (dates.eq(start, end, 'month')) {
return local.format(start, 'Y-M', culture);
}
return `${local.format(start, 'Y-M', culture)} - ${local.format(end, 'Y-M', culture)}`;
},
}}
defaultDate={new Date()}
components={{
toolbar: Toolbar,
}}
localizer={localizer}
/>
</div>
</CalendarContext.Provider>
</AsyncDataProvider>
);
});
Calendar.ActionInitializer = ActionInitializer;
Calendar.FooterActionInitializer = FooterActionInitializer;
Calendar.ActionBar = ActionBar;
Calendar.Event = Event;
Calendar.Title = Title;
Calendar.Today = Today;
Calendar.Nav = Nav;
Calendar.ViewSelect = ViewSelect;
Calendar.Filter = Filter;

View File

@ -0,0 +1,6 @@
import { observer } from '@formily/react';
import React from 'react';
export const Event = observer((props) => {
return <>{props.children}</>;
});

View File

@ -0,0 +1,69 @@
import { FormButtonGroup, Submit } from '@formily/antd';
import { createForm } from '@formily/core';
import { FormProvider, observer, useFieldSchema } from '@formily/react';
import { Button, Popover } from 'antd';
import flatten from 'flat';
import React, { useMemo, useState } from 'react';
import { useTranslation } from 'react-i18next';
import { SchemaComponent } from '../../core';
import { useDesignable } from '../../hooks';
import { useCompile } from '../../hooks/useCompile';
import { IconPicker } from '../icon-picker';
export const Filter = observer((props: any) => {
const { t } = useTranslation();
const compile = useCompile();
const { properties } = props;
const { DesignableBar } = useDesignable();
const filedSchema = useFieldSchema();
const form = useMemo(() => createForm(), []);
const [visible, setVisible] = useState(false);
const obj = flatten(form.values.filter || {});
const count = Object.values(obj).filter((i) => (Array.isArray(i) ? i.length : i)).length;
const icon = props.icon || 'FilterOutlined';
filedSchema.mapProperties((p) => {
properties[p.name] = p;
});
return (
<Popover
trigger={['click']}
placement={'bottomLeft'}
visible={visible}
onVisibleChange={setVisible}
content={
<div>
<FormProvider form={form}>
<SchemaComponent
schema={{
type: 'object',
properties: {
filter: {
type: 'object',
'x-component': 'Filter',
properties,
},
},
}}
/>
<FormButtonGroup align={'right'}>
<Submit
onSubmit={() => {
const { filter } = form.values;
console.log('Table.Filter', form.values);
setVisible(false);
}}
>
{t('Submit')}
</Submit>
</FormButtonGroup>
</FormProvider>
</div>
}
>
<Button icon={<IconPicker type={icon} />}>
{count > 0 ? t('{{count}} filter items', { count }) : compile(filedSchema.title)}
<DesignableBar />
</Button>
</Popover>
);
});

View File

@ -0,0 +1,138 @@
import { observer, useFieldSchema } from '@formily/react';
import { Switch } from 'antd';
import React from 'react';
import { useTranslation } from 'react-i18next';
import { useCollection } from '../../../collection-manager';
import { SchemaInitializer } from '../../../schema-initializer';
import { useDesignable } from '../../hooks';
export const FooterActionInitializer = observer((props: any) => {
const { name: collectName } = useCollection();
const { t } = useTranslation();
return (
<SchemaInitializer.Button
insertPosition={'beforeEnd'}
style={{ marginLeft: 8 }}
items={[
{
type: 'itemGroup',
title: t('Enable actions'),
children: [
{
type: 'item',
title: t('Edit'),
component: InitializeAction,
schema: {
title: t('Edit'),
'x-component': 'Action',
'x-component-props': {
useAction: '{{ useEditAction }}',
type: 'primary',
},
'x-action': `calendar:edit`,
'x-align': 'right',
properties: {
modal: {
'x-component': 'Action.Drawer',
'x-decorator': 'Form',
'x-decorator-props': {
useValues: '{{ useValues }}',
},
type: 'void',
title: 'Drawer Title',
properties: {
grid: {
type: 'void',
'x-component': 'Grid',
'x-item-initializer': 'FormItemInitializer',
},
footer: {
'x-component': 'Action.Drawer.Footer',
type: 'void',
properties: {
update: {
title: 'update',
'x-component': 'Action',
'x-component-props': {
useAction: '{{ useUpdateAction }}',
type: 'primary',
},
},
close: {
title: 'Close',
'x-component': 'Action',
'x-component-props': {
useAction: '{{ useCloseAction }}',
},
},
},
},
},
},
},
},
},
{
type: 'item',
title: t('Delete'),
component: InitializeAction,
schema: {
title: t('Delete'),
'x-component': 'Action',
'x-component-props': {
useAction: '{{ useRemoveAction }}',
type: 'danger',
},
'x-action': `calendar:delete`,
'x-align': 'right',
},
},
],
},
]}
>
Configure actions
</SchemaInitializer.Button>
);
});
const useCurrentActionSchema = (action: string) => {
const fieldSchema = useFieldSchema();
const { remove } = useDesignable();
const schema: any = fieldSchema.reduceProperties((buf, s) => {
if (s['x-action'] === action) {
return s;
}
return buf;
});
return {
schema,
exists: !!schema,
remove() {
schema && remove(schema);
},
};
};
const InitializeAction = SchemaInitializer.itemWrap((props) => {
const { item, insert } = props;
const { exists, remove } = useCurrentActionSchema(item.schema['x-action']);
return (
<SchemaInitializer.Item
onClick={() => {
if (exists) {
return remove();
}
insert({
type: 'void',
'x-component': 'Action',
...item.schema,
});
}}
>
<div style={{ display: 'flex', alignItems: 'center', justifyContent: 'space-between' }}>
{item.title} <Switch size={'small'} checked={exists} />
</div>
</SchemaInitializer.Item>
);
});

View File

@ -0,0 +1,19 @@
import { LeftOutlined, RightOutlined } from '@ant-design/icons';
import { observer } from '@formily/react';
import { Button } from 'antd';
import React, { useContext } from 'react';
import { navigate } from 'react-big-calendar/lib/utils/constants';
import { useDesignable } from '../../hooks';
import { ToolbarContext } from './context';
export const Nav = observer((props) => {
const { DesignableBar } = useDesignable();
const { onNavigate } = useContext(ToolbarContext);
return (
<div className="ant-btn-group">
<Button icon={<LeftOutlined />} onClick={() => onNavigate(navigate.PREVIOUS)}></Button>
<Button icon={<RightOutlined />} onClick={() => onNavigate(navigate.NEXT)}></Button>
<DesignableBar />
</div>
);
});

View File

@ -0,0 +1,15 @@
import { observer } from '@formily/react';
import React, { useContext } from 'react';
import { useDesignable } from '../../hooks';
import { ToolbarContext } from './context';
export const Title = observer(() => {
const { DesignableBar } = useDesignable();
const { label } = useContext(ToolbarContext);
return (
<div className="ant-btn-group" style={{ fontSize: '1.75em', fontWeight: 300 }}>
{label}
<DesignableBar />
</div>
);
});

View File

@ -0,0 +1,23 @@
import { observer } from '@formily/react';
import { Button } from 'antd';
import React, { useContext } from 'react';
import { navigate } from 'react-big-calendar/lib/utils/constants';
import { useTranslation } from 'react-i18next';
import { useDesignable } from '../../hooks';
import { ToolbarContext } from './context';
export const Today = observer((props) => {
const { DesignableBar } = useDesignable();
const { onNavigate } = useContext(ToolbarContext);
const { t } = useTranslation();
return (
<Button
onClick={() => {
onNavigate(navigate.TODAY);
}}
>
{t('Today')}
<DesignableBar />
</Button>
);
});

View File

@ -0,0 +1,25 @@
import { observer } from '@formily/react';
import { Select } from 'antd';
import React, { useContext } from 'react';
import { useDesignable } from '../../hooks';
import { ToolbarContext } from './context';
export const ViewSelect = observer((props) => {
const { DesignableBar } = useDesignable();
const {
views,
view,
onView,
localizer: { messages },
} = useContext(ToolbarContext);
return (
<div className="ant-btn-group">
<Select value={view} onChange={onView}>
{views.map((name) => (
<Select.Option value={name}>{messages[name]}</Select.Option>
))}
</Select>
<DesignableBar />
</div>
);
});

View File

@ -0,0 +1,5 @@
import { createContext } from 'react';
import type { ToolbarProps } from './types';
export const ToolbarContext = createContext<ToolbarProps>(null);
export const CalendarContext = createContext(null);

View File

@ -0,0 +1,34 @@
import { uid } from '@formily/shared';
import { APIClient } from '@nocobase/client';
import MockAdapter from 'axios-mock-adapter';
import _ from 'lodash';
export const apiClient = new APIClient();
const mock = new MockAdapter(apiClient.axios);
const sleep = (value: number) => new Promise((resolve) => setTimeout(resolve, value));
mock.onGet('/tasks:list').reply(async (config) => {
// const [{ pageSize }] = config.params;
const pageSize = config.params.pageSize || 10;
const page = config.params.page || 1;
console.log(pageSize, page, config.params);
await sleep(1000);
return [
200,
{
data: _.range(pageSize).map((v) => {
const month = Math.floor(Math.random() * 10 + 1);
const startDate = Math.floor(Math.random() * 20 + 1);
const endDate = startDate + Math.floor(Math.random() * 2 + 1);
return {
id: v + (page - 1) * pageSize,
title: uid(),
start: new Date(2022, month, startDate),
end: new Date(2022, month, endDate),
};
}),
},
];
});

View File

@ -0,0 +1,180 @@
const now = new Date();
export default [
{
id: 0,
title: 'All Day Event very long title',
allDay: true,
start: new Date(2015, 3, 0),
end: new Date(2015, 3, 1),
},
{
id: 1,
title: 'Long Event',
start: new Date(2015, 3, 7),
end: new Date(2015, 3, 10),
},
{
id: 2,
title: 'DTS STARTS',
start: new Date(2016, 2, 13, 0, 0, 0),
end: new Date(2016, 2, 20, 0, 0, 0),
},
{
id: 3,
title: 'DTS ENDS',
start: new Date(2016, 10, 6, 0, 0, 0),
end: new Date(2016, 10, 13, 0, 0, 0),
},
{
id: 4,
title: 'Some Event',
start: new Date(2015, 3, 9, 0, 0, 0),
end: new Date(2015, 3, 10, 0, 0, 0),
},
{
id: 5,
title: 'Conference',
start: new Date(2015, 3, 11),
end: new Date(2015, 3, 13),
desc: 'Big conference for important people',
},
{
id: 6,
title: 'Meeting',
start: new Date(2015, 3, 12, 10, 30, 0, 0),
end: new Date(2015, 3, 12, 12, 30, 0, 0),
desc: 'Pre-meeting meeting, to prepare for the meeting',
},
{
id: 7,
title: 'Lunch',
start: new Date(2015, 3, 12, 12, 0, 0, 0),
end: new Date(2015, 3, 12, 13, 0, 0, 0),
desc: 'Power lunch',
},
{
id: 8,
title: 'Meeting',
start: new Date(2015, 3, 12, 14, 0, 0, 0),
end: new Date(2015, 3, 12, 15, 0, 0, 0),
},
{
id: 9,
title: 'Happy Hour',
start: new Date(2015, 3, 12, 17, 0, 0, 0),
end: new Date(2015, 3, 12, 17, 30, 0, 0),
desc: 'Most important meal of the day',
},
{
id: 10,
title: 'Dinner',
start: new Date(2015, 3, 12, 20, 0, 0, 0),
end: new Date(2015, 3, 12, 21, 0, 0, 0),
},
{
id: 11,
title: 'Planning Meeting with Paige',
start: new Date(2015, 3, 13, 8, 0, 0),
end: new Date(2015, 3, 13, 10, 30, 0),
},
{
id: 11.1,
title: 'Inconvenient Conference Call',
start: new Date(2015, 3, 13, 9, 30, 0),
end: new Date(2015, 3, 13, 12, 0, 0),
},
{
id: 11.2,
title: "Project Kickoff - Lou's Shoes",
start: new Date(2015, 3, 13, 11, 30, 0),
end: new Date(2015, 3, 13, 14, 0, 0),
},
{
id: 11.3,
title: 'Quote Follow-up - Tea by Tina',
start: new Date(2015, 3, 13, 15, 30, 0),
end: new Date(2015, 3, 13, 16, 0, 0),
},
{
id: 12,
title: 'Late Night Event',
start: new Date(2015, 3, 17, 19, 30, 0),
end: new Date(2015, 3, 18, 2, 0, 0),
},
{
id: 12.5,
title: 'Late Same Night Event',
start: new Date(2015, 3, 17, 19, 30, 0),
end: new Date(2015, 3, 17, 23, 30, 0),
},
{
id: 13,
title: 'Multi-day Event',
start: new Date(2015, 3, 20, 19, 30, 0),
end: new Date(2015, 3, 22, 2, 0, 0),
},
{
id: 14,
title: 'Today',
start: new Date(new Date().setHours(new Date().getHours() - 3)),
end: new Date(new Date().setHours(new Date().getHours() + 3)),
},
{
id: 15,
title: 'Point in Time Event',
start: now,
end: now,
},
{
id: 16,
title: 'Video Record',
start: new Date(2015, 3, 14, 15, 30, 0),
end: new Date(2015, 3, 14, 19, 0, 0),
},
{
id: 17,
title: 'Dutch Song Producing',
start: new Date(2015, 3, 14, 16, 30, 0),
end: new Date(2015, 3, 14, 20, 0, 0),
},
{
id: 18,
title: 'Itaewon Halloween Meeting',
start: new Date(2015, 3, 14, 16, 30, 0),
end: new Date(2015, 3, 14, 17, 30, 0),
},
{
id: 19,
title: 'Online Coding Test',
start: new Date(2015, 3, 14, 17, 30, 0),
end: new Date(2015, 3, 14, 20, 30, 0),
},
{
id: 20,
title: 'An overlapped Event',
start: new Date(2015, 3, 14, 17, 0, 0),
end: new Date(2015, 3, 14, 18, 30, 0),
},
{
id: 21,
title: 'Phone Interview',
start: new Date(2015, 3, 14, 17, 0, 0),
end: new Date(2015, 3, 14, 18, 30, 0),
},
{
id: 22,
title: 'Cooking Class',
start: new Date(2015, 3, 14, 17, 30, 0),
end: new Date(2015, 3, 14, 19, 0, 0),
},
{
id: 23,
title: 'Go to the gym',
start: new Date(2015, 3, 14, 18, 30, 0),
end: new Date(2015, 3, 14, 20, 0, 0),
},
];

View File

@ -0,0 +1,282 @@
/**
* title: Calendar
*/
import { useField, useFieldSchema, useForm } from '@formily/react';
import { observable } from '@formily/reactive';
import { uid } from '@formily/shared';
import {
AntdSchemaComponentProvider,
CalendarContext,
CollectionProvider,
SchemaComponent,
SchemaComponentProvider,
SchemaInitializerProvider,
useActionContext,
useAsyncData,
useRequest,
} from '@nocobase/client';
import React, { useContext, useEffect } from 'react';
import defaultValues from './defaultValues';
const dataSource = observable(defaultValues);
const schema = {
type: 'void',
name: 'calendar1',
'x-component': 'Calendar',
'x-component-props': {
dataSource: dataSource,
},
properties: {
toolBar: {
type: 'void',
'x-component': 'Calendar.ActionBar',
'x-action-initializer': 'Calendar.ActionInitializer',
properties: {
today: {
type: 'void',
title: '今天',
'x-component': 'Calendar.Today',
'x-action': 'calendar:today',
'x-align': 'left',
},
nav: {
type: 'void',
title: '翻页',
'x-component': 'Calendar.Nav',
'x-action': 'calendar:nav',
'x-align': 'left',
},
title: {
type: 'void',
title: '标题',
'x-component': 'Calendar.Title',
'x-action': 'calendar:title',
'x-align': 'left',
},
viewSelect: {
type: 'void',
title: '视图切换',
'x-component': 'Calendar.ViewSelect',
'x-action': 'calendar:viewSelect',
'x-align': 'right',
},
// filter: {
// type: 'void',
// title: '过滤',
// 'x-align': 'right',
// 'x-component': 'Calendar.Filter',
// 'x-action': 'calendar:filter',
// },
},
},
event: {
type: 'void',
name: 'event',
'x-component': 'Calendar.Event',
properties: {
modal: {
'x-component': 'Action.Drawer',
'x-decorator': 'Form',
'x-decorator-props': {
useValues: '{{ useValues }}',
},
type: 'void',
title: 'Drawer Title',
properties: {
grid: {
type: 'void',
'x-component': 'Grid',
'x-item-initializer': 'FormItemInitializer',
'x-item-initializer-props': {
readPretty: true,
},
},
footer: {
'x-component': 'Action.Drawer.Footer',
type: 'void',
properties: {
[uid()]: {
title: 'submit',
'x-component': 'ActionBar',
'x-action-initializer': 'Calendar.FooterActionInitializer',
},
},
},
},
},
},
},
},
};
const useSaveAction = () => {
const { setVisible } = useActionContext();
const { refresh: dataRefresh, data } = useAsyncData();
const form = useForm();
const fieldSchema = useFieldSchema();
const field = useField();
return {
async run() {
setVisible(false);
console.log(form.values, fieldSchema, field, data);
dataSource.push({ ...form.values, start: new Date(form.values.start), end: new Date(form.values.end) });
schema['x-component-props']['dataSource'] = dataSource;
dataRefresh();
form.reset();
},
};
};
const useCloseAction = () => {
const { setVisible } = useActionContext();
return {
async run() {
setVisible(false);
},
};
};
const useRemoveAction = () => {
const { refresh: dataRefresh, data } = useAsyncData();
const { record } = useContext(CalendarContext);
const { setVisible } = useActionContext();
return {
async run() {
setVisible(false);
for (let i = 0, iLen = dataSource.length; i < iLen; i++) {
const element = dataSource[i];
if (element.id === record.id) {
dataSource.splice(i, 1);
break;
}
}
schema['x-component-props']['dataSource'] = dataSource;
dataRefresh();
},
};
};
const useEditAction = () => {
const { refresh: dataRefresh, data } = useAsyncData();
const { record } = useContext(CalendarContext);
const { setVisible } = useActionContext();
return {
async run() {
console.log(record);
},
};
};
const useUpdateAction = () => {
const form = useForm();
const { setVisible } = useActionContext();
const { refresh: dataRefresh, data } = useAsyncData();
return {
async run() {
setVisible(false);
console.log(form.values);
const record = form.values;
for (let i = 0, iLen = dataSource.length; i < iLen; i++) {
const element = dataSource[i];
if (element.id === record.id) {
dataSource[i] = { ...record };
break;
}
}
schema['x-component-props']['dataSource'] = dataSource;
form.reset();
},
};
};
const useValues = (options) => {
const { visible } = useActionContext();
const { record } = useContext(CalendarContext);
const result = useRequest(
() =>
Promise.resolve({
data: {
...record,
},
}),
{ ...options, manual: true },
);
useEffect(() => {
if (visible) {
result.run();
}
}, [visible]);
return result;
};
const collection = {
name: 'tests',
fields: [
{
type: 'string',
name: 'id',
interface: 'input',
uiSchema: {
type: 'string',
'x-component': 'Input',
},
},
{
type: 'string',
name: 'title',
interface: 'input',
uiSchema: {
type: 'string',
'x-component': 'Input',
},
},
{
type: 'string',
name: 'start',
interface: 'datetime',
uiSchema: {
type: 'string',
'x-component': 'DatePicker',
'x-component-props': {
dateFormat: 'YYYY-MM-DD',
},
},
},
{
type: 'string',
name: 'end',
interface: 'datetime',
uiSchema: {
type: 'string',
'x-component': 'DatePicker',
'x-component-props': {
dateFormat: 'YYYY-MM-DD',
},
},
},
],
};
export default () => {
return (
<CollectionProvider collection={collection}>
<SchemaComponentProvider
scope={{
useSaveAction,
useCloseAction,
useEditAction,
useUpdateAction,
useValues,
useRemoveAction,
}}
>
<SchemaInitializerProvider>
<AntdSchemaComponentProvider>
<SchemaComponent schema={schema} />
</AntdSchemaComponentProvider>
</SchemaInitializerProvider>
</SchemaComponentProvider>
</CollectionProvider>
);
};

View File

@ -5,4 +5,12 @@ group:
path: /schema-components
---
# Calendar <Badge>待定</Badge>
# Calendar
## Examples
### Calendar
#### Sync Data
<code src="./demos/demo1.tsx" />

View File

@ -1 +1,2 @@
export * from './Calendar';
export * from './context';

View File

@ -0,0 +1,767 @@
@charset "UTF-8";
.rbc-btn {
color: inherit;
font: inherit;
margin: 0;
}
button.rbc-btn {
overflow: visible;
text-transform: none;
-webkit-appearance: button;
cursor: pointer;
}
button[disabled].rbc-btn {
cursor: not-allowed;
}
button.rbc-input::-moz-focus-inner {
border: 0;
padding: 0;
}
.rbc-calendar {
box-sizing: border-box;
display: flex;
flex-direction: column;
align-items: stretch;
height: 100%;
}
.rbc-calendar *,
.rbc-calendar *:before,
.rbc-calendar *:after {
box-sizing: inherit;
}
.rbc-abs-full,
.rbc-row-bg {
overflow: hidden;
position: absolute;
top: 0;
left: 0;
right: 0;
bottom: 0;
}
.rbc-ellipsis,
.rbc-event-label,
.rbc-row-segment .rbc-event-content,
.rbc-show-more {
display: block;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
.rbc-rtl {
direction: rtl;
}
.rbc-off-range {
color: rgba(0, 0, 0, 0.25);
}
.rbc-off-range-bg {
// background: #e6e6e6;
}
.rbc-header {
// font-size: 16px;
overflow: hidden;
flex: 1 0 0%;
text-overflow: ellipsis;
white-space: nowrap;
padding: 4px 12px;
text-align: right;
vertical-align: middle;
// font-weight: 500;
min-height: 32px;
color: rgba(0, 0, 0, 0.85);
margin: 0 4px;
border-bottom: 2px solid #f0f0f0;
}
.rbc-header + .rbc-header {
// border-left: 1px solid #f0f0f0;
}
.rbc-rtl .rbc-header + .rbc-header {
border-left-width: 0;
border-right: 1px solid #f0f0f0;
}
.rbc-header > a,
.rbc-header > a:active,
.rbc-header > a:visited {
color: inherit;
text-decoration: none;
}
.rbc-row-content {
position: relative;
user-select: none;
-webkit-user-select: none;
z-index: 4;
}
.rbc-row-content-scrollable {
display: flex;
flex-direction: column;
height: 100%;
}
.rbc-row-content-scrollable .rbc-row-content-scroll-container {
height: 100%;
overflow-y: scroll;
/* Hide scrollbar for Chrome, Safari and Opera */
-ms-overflow-style: none;
/* IE and Edge */
scrollbar-width: none;
/* Firefox */
}
.rbc-row-content-scrollable .rbc-row-content-scroll-container::-webkit-scrollbar {
display: none;
}
.rbc-toolbar {
display: flex;
flex-wrap: wrap;
justify-content: center;
align-items: center;
margin-bottom: 10px;
font-size: 16px;
}
.rbc-toolbar .rbc-toolbar-label {
flex-grow: 1;
padding: 0 10px;
text-align: center;
}
.rbc-toolbar button {
outline: none;
font-size: 14px;
line-height: 1.5715;
height: 32px;
color: #373a3c;
display: inline-block;
margin: 0;
position: relative;
z-index: 1;
text-align: center;
vertical-align: middle;
background: none;
background-image: none;
border: 1px solid #d9d9d9;
padding: 4px 15px;
border-radius: 2px;
line-height: normal;
white-space: nowrap;
}
.rbc-toolbar button:active,
.rbc-toolbar button.rbc-active {
// background-image: none;
// box-shadow: inset 0 3px 5px rgba(0, 0, 0, 0.125);
// background-color: #e6e6e6;
z-index: 2;
color: #1890ff;
border-color: #1890ff;
}
.rbc-toolbar button:active:hover,
.rbc-toolbar button:active:focus,
.rbc-toolbar button.rbc-active:hover,
.rbc-toolbar button.rbc-active:focus {
// color: #373a3c;
// background-color: #d4d4d4;
// border-color: #8c8c8c;
z-index: 2;
color: #40a9ff;
border-color: #40a9ff;
}
// .rbc-toolbar button:focus {
// color: #373a3c;
// background-color: #e6e6e6;
// border-color: #adadad; }
.rbc-toolbar button:hover {
// color: #373a3c;
// background-color: #e6e6e6;
z-index: 2;
color: #40a9ff;
border-color: #40a9ff;
}
.rbc-btn-group {
display: inline-block;
white-space: nowrap;
}
.rbc-btn-group > button:first-child:not(:last-child) {
border-top-right-radius: 0;
border-bottom-right-radius: 0;
}
.rbc-btn-group > button:last-child:not(:first-child) {
border-top-left-radius: 0;
border-bottom-left-radius: 0;
}
.rbc-rtl .rbc-btn-group > button:first-child:not(:last-child) {
border-radius: 4px;
border-top-left-radius: 0;
border-bottom-left-radius: 0;
}
.rbc-rtl .rbc-btn-group > button:last-child:not(:first-child) {
border-radius: 4px;
border-top-right-radius: 0;
border-bottom-right-radius: 0;
}
.rbc-btn-group > button:not(:first-child):not(:last-child) {
border-radius: 0;
}
.rbc-btn-group button + button {
margin-left: -1px;
}
.rbc-rtl .rbc-btn-group button + button {
margin-left: 0;
margin-right: -1px;
}
.rbc-btn-group + .rbc-btn-group,
.rbc-btn-group + button {
margin-left: 10px;
}
.rbc-event {
border: none;
box-sizing: border-box;
box-shadow: none;
margin: 0;
padding: 2px 5px;
background-color: rgba(240, 240, 240, 0.65);
border-radius: 2px;
// color: #1890ff;
cursor: pointer;
font-size: 12px;
width: 100%;
text-align: left;
&:hover {
background-color: #e6f7ff;
color: #1890ff;
}
}
.rbc-slot-selecting .rbc-event {
cursor: inherit;
pointer-events: none;
}
.rbc-event.rbc-selected {
background-color: #e6f7ff;
color: #1890ff;
}
.rbc-event:focus {
// outline: 5px auto #3b99fc;
}
.rbc-event-label {
font-size: 80%;
}
.rbc-event-overlaps {
box-shadow: -1px 1px 5px 0px rgba(51, 51, 51, 0.5);
}
.rbc-event-continues-prior {
border-top-left-radius: 0;
border-bottom-left-radius: 0;
}
.rbc-event-continues-after {
border-top-right-radius: 0;
border-bottom-right-radius: 0;
}
.rbc-event-continues-earlier {
border-top-left-radius: 0;
border-top-right-radius: 0;
}
.rbc-event-continues-later {
border-bottom-left-radius: 0;
border-bottom-right-radius: 0;
}
.rbc-row {
display: flex;
flex-direction: row;
}
.rbc-row-segment {
padding: 0 4px 1px 4px;
}
.rbc-selected-cell {
background-color: rgba(0, 0, 0, 0.1);
}
.rbc-show-more {
z-index: 4;
font-weight: bold;
font-size: 85%;
height: auto;
line-height: normal;
color: inherit;
padding: 2px 5px;
}
.rbc-month-view {
position: relative;
// border: 1px solid #f0f0f0;
display: flex;
flex-direction: column;
flex: 1 0 0;
width: 100%;
user-select: none;
-webkit-user-select: none;
height: 68vh;
}
.rbc-month-header {
display: flex;
flex-direction: row;
}
.rbc-month-row {
display: flex;
position: relative;
flex-direction: column;
flex: 1 0 0;
flex-basis: 0px;
overflow: hidden;
height: 100%;
}
.rbc-month-row + .rbc-month-row {
// border-top: 1px solid #f0f0f0;
}
.rbc-date-cell {
// cursor: pointer;
flex: 1 1 0;
min-width: 0;
padding-right: 12px;
padding-top: 4px;
text-align: right;
}
.rbc-date-cell.rbc-now a {
// font-weight: bold;
color: #1890ff;
}
.rbc-date-cell > a,
.rbc-date-cell > a:active,
.rbc-date-cell > a:visited {
color: inherit;
text-decoration: none;
}
.rbc-date-cell > a:hover {
color: #1890ff;
}
.rbc-row-bg {
display: flex;
flex-direction: row;
flex: 1 0 0;
overflow: hidden;
}
.rbc-day-bg {
flex: 1 0 0%;
// border-top: 2px solid #f0f0f0;
margin: 0 4px;
&:hover {
background: #f5f5f5;
}
// cursor: pointer;
}
.rbc-month-view {
.rbc-day-bg {
border-top: 2px solid #f0f0f0;
}
.rbc-today {
border-color: #1890ff !important;
background-color: #e6f7ff !important;
}
.rbc-header {
border-bottom: 0 !important;
}
}
.rbc-day-bg + .rbc-day-bg {
// margin-left: 8px;
// border-left: 1px solid #f0f0f0;
}
.rbc-rtl .rbc-day-bg + .rbc-day-bg {
// border-left-width: 0;
// border-right: 1px solid #f0f0f0;
}
.rbc-overlay {
position: absolute;
z-index: 5;
margin-top: 5px;
border-radius: 2px;
// border: 1px solid #e5e5e5;
background-color: #fff;
box-shadow: 0 3px 6px -4px rgba(0, 0, 0, 0.12), 0 6px 16px 0 rgba(0, 0, 0, 0.08), 0 9px 28px 8px rgba(0, 0, 0, 0.05);
padding: 12px 16px;
}
.rbc-overlay > * + * {
margin-top: 1px;
}
.rbc-overlay-header {
font-weight: 500;
min-height: 32px;
border-bottom: 1px solid #f0f0f0;
margin: -12px -16px 12px -16px;
padding: 5px 16px 4px;
}
.rbc-agenda-view {
display: flex;
flex-direction: column;
flex: 1 0 0;
overflow: auto;
}
.rbc-agenda-view table.rbc-agenda-table {
width: 100%;
border: 1px solid #f0f0f0;
border-spacing: 0;
border-collapse: collapse;
}
.rbc-agenda-view table.rbc-agenda-table tbody > tr > td {
padding: 5px 10px;
vertical-align: top;
}
.rbc-agenda-view table.rbc-agenda-table .rbc-agenda-time-cell {
padding-left: 15px;
padding-right: 15px;
text-transform: lowercase;
}
.rbc-agenda-view table.rbc-agenda-table tbody > tr > td + td {
border-left: 1px solid #f0f0f0;
}
.rbc-rtl .rbc-agenda-view table.rbc-agenda-table tbody > tr > td + td {
border-left-width: 0;
border-right: 1px solid #f0f0f0;
}
.rbc-agenda-view table.rbc-agenda-table tbody > tr + tr {
border-top: 1px solid #f0f0f0;
}
.rbc-agenda-view table.rbc-agenda-table thead > tr > th {
padding: 3px 5px;
text-align: left;
border-bottom: 1px solid #f0f0f0;
}
.rbc-rtl .rbc-agenda-view table.rbc-agenda-table thead > tr > th {
text-align: right;
}
.rbc-agenda-time-cell {
text-transform: lowercase;
}
.rbc-agenda-time-cell .rbc-continues-after:after {
content: ' »';
}
.rbc-agenda-time-cell .rbc-continues-prior:before {
content: '« ';
}
.rbc-agenda-date-cell,
.rbc-agenda-time-cell {
white-space: nowrap;
}
.rbc-agenda-event-cell {
width: 100%;
}
.rbc-time-column {
display: flex;
flex-direction: column;
min-height: 100%;
}
.rbc-time-column .rbc-timeslot-group {
flex: 1;
}
.rbc-timeslot-group {
border-bottom: 1px solid #f0f0f0;
min-height: 40px;
line-height: 39px;
display: flex;
flex-flow: column nowrap;
// cursor: pointer;
&:hover {
background: #f0f0f0;
}
}
.rbc-time-gutter,
.rbc-header-gutter {
flex: none;
}
.rbc-label {
padding: 0 5px;
}
.rbc-day-slot {
position: relative;
}
.rbc-day-slot .rbc-events-container {
bottom: 0;
left: 0;
position: absolute;
right: 0;
margin-right: 10px;
top: 0;
}
.rbc-day-slot .rbc-events-container.rbc-rtl {
left: 10px;
right: 0;
}
.rbc-day-slot .rbc-event {
border: 1px solid #265985;
display: flex;
max-height: 100%;
min-height: 20px;
flex-flow: column wrap;
align-items: flex-start;
overflow: hidden;
position: absolute;
}
.rbc-day-slot .rbc-event-label {
flex: none;
padding-right: 5px;
width: auto;
}
.rbc-day-slot .rbc-event-content {
width: 100%;
flex: 1 1 0;
word-wrap: break-word;
line-height: 1;
height: 100%;
min-height: 1em;
}
.rbc-day-slot .rbc-time-slot {
// border-top: 1px solid #f7f7f7;
}
.rbc-time-header-gutter {
line-height: 40px;
}
.rbc-time-header-cell {
min-height: 32px !important;
}
.rbc-calendar.view-week {
.rbc-time-header-cell {
margin-top: -32px;
margin-bottom: 4px;
}
.rbc-time-view {
padding-top: 32px;
border-top: 0;
}
.rbc-header {
padding: 4px 8px;
}
.rbc-time-header-content {
padding: 4px 0;
}
.rbc-time-header-gutter {
padding: 0;
padding-top: 2px;
> div {
border-top: 2px solid #f0f0f0;
padding: 0 5px;
}
}
}
.rbc-time-view-resources .rbc-time-gutter,
.rbc-time-view-resources .rbc-time-header-gutter {
position: sticky;
left: 0;
background-color: white;
border-right: 1px solid #f0f0f0;
z-index: 10;
margin-right: -1px;
}
.rbc-time-view-resources .rbc-time-header {
overflow: hidden;
}
.rbc-time-view-resources .rbc-time-header-content {
min-width: auto;
flex: 1 0 0;
flex-basis: 0px;
}
.rbc-time-view-resources .rbc-time-header-cell-single-day {
display: none;
}
.rbc-time-view-resources .rbc-day-slot {
min-width: 140px;
}
.rbc-time-view-resources .rbc-header,
.rbc-time-view-resources .rbc-day-bg {
width: 140px;
flex: 1 1 0;
flex-basis: 0 px;
}
.rbc-time-header-content + .rbc-time-header-content {
margin-left: -1px;
}
.rbc-time-slot {
flex: 1 0 0;
}
.rbc-time-slot.rbc-now {
font-weight: bold;
}
.rbc-day-header {
text-align: center;
}
.rbc-slot-selection {
z-index: 10;
position: absolute;
background-color: rgba(0, 0, 0, 0.5);
color: white;
font-size: 75%;
width: 100%;
padding: 3px;
}
.rbc-slot-selecting {
cursor: move;
}
.rbc-time-view {
display: flex;
flex-direction: column;
flex: 1;
width: 100%;
border-top: 1px solid #f0f0f0;
min-height: 0;
}
.rbc-time-view .rbc-time-gutter {
white-space: nowrap;
}
.rbc-time-view .rbc-allday-cell {
box-sizing: content-box;
width: 100%;
height: 100%;
position: relative;
}
.rbc-time-view .rbc-allday-cell + .rbc-allday-cell {
border-left: 1px solid #f0f0f0;
}
.rbc-time-view .rbc-allday-events {
position: relative;
z-index: 4;
}
.rbc-time-view .rbc-row {
box-sizing: border-box;
min-height: 20px;
}
.rbc-time-header {
display: flex;
flex: 0 0 auto;
flex-direction: row;
}
.rbc-time-header.rbc-overflowing {
border-right: 1px solid #f0f0f0;
}
.rbc-rtl .rbc-time-header.rbc-overflowing {
border-right-width: 0;
border-left: 1px solid #f0f0f0;
}
.rbc-time-header > .rbc-row:first-child {
border-bottom: 1px solid #f0f0f0;
}
.rbc-time-header > .rbc-row.rbc-row-resource {
border-bottom: 1px solid #f0f0f0;
}
.rbc-time-header-cell-single-day {
display: none;
}
.rbc-time-header-content {
flex: 1;
display: flex;
min-width: 0;
flex-direction: column;
// border-left: 1px solid #f0f0f0;
}
.rbc-rtl .rbc-time-header-content {
border-left-width: 0;
border-right: 1px solid #f0f0f0;
}
.rbc-time-header-content > .rbc-row.rbc-row-resource {
border-bottom: 1px solid #f0f0f0;
flex-shrink: 0;
}
.rbc-time-content {
display: flex;
flex: 1 0 0%;
align-items: flex-start;
width: 100%;
border-top: 1px solid #f0f0f0;
overflow-y: auto;
position: relative;
}
.rbc-time-content > .rbc-time-gutter {
flex: none;
}
.rbc-time-content > * + * > * {
// border-left: 1px solid #f0f0f0;
}
.rbc-rtl .rbc-time-content > * + * > * {
border-left-width: 0;
border-right: 1px solid #f0f0f0;
}
.rbc-time-content > .rbc-day-slot {
width: 100%;
user-select: none;
-webkit-user-select: none;
}
.rbc-current-time-indicator {
position: absolute;
z-index: 3;
left: 0;
right: 0;
height: 1px;
background-color: #74ad31;
pointer-events: none;
}
@media only screen and (max-width: 800px) {
.view-type-calendar .action-buttons {
position: relative !important;
left: 0 !important;
.filter-action-button {
left: 0 !important;
}
}
.rbc-toolbar .rbc-toolbar-label {
position: absolute;
top: 28px;
left: 50%;
transform: translateX(-50%);
}
.rbc-toolbar {
justify-content: space-between !important;
}
.rbc-header {
padding: 4px !important;
}
}

View File

@ -0,0 +1,8 @@
export interface ToolbarProps {
localizer?: any;
label?: any;
view?: any;
views?: any;
onNavigate?: (action: string) => void;
onView?: (view: string) => void;
}

View File

@ -0,0 +1,43 @@
import { get } from 'lodash';
import { i18n } from '../../../i18n';
export const fieldsToFilterColumns = (fields: any[], options: any = {}) => {
// const { fieldNames = [] } = options;
// const properties = {};
// fields.forEach((field, index) => {
// if (fieldNames?.length && !fieldNames.includes(field.name)) {
// return;
// }
// const fieldOption = interfaces.get(field.interface);
// if (!fieldOption?.operations) {
// return;
// }
// properties[`column${index}`] = {
// type: 'void',
// title: field?.uiSchema?.title,
// 'x-component': 'Filter.Column',
// 'x-component-props': {
// operations: fieldOption.operations,
// },
// properties: {
// [field.name]: {
// ...field.uiSchema,
// 'x-decorator': 'FormilyFormItem',
// title: null,
// },
// },
// };
// });
// return properties;
};
export const toEvents = (data: any[], fieldNames: any) => {
return data?.map((item) => {
return {
id: get(item, fieldNames.id || 'id'),
title: get(item, fieldNames.title) || i18n.t('Untitle'),
start: new Date(get(item, fieldNames.start)),
end: new Date(get(item, fieldNames.end || fieldNames.start)),
};
});
};

View File

@ -1,6 +1,5 @@
import { ISchemaFieldProps, RecursionField, Schema } from '@formily/react';
import React, { useContext, useMemo } from 'react';
import { SchemaComponentContext } from '../context';
import { IRecursionFieldProps, ISchemaFieldProps, RecursionField, Schema } from '@formily/react';
import React, { useMemo } from 'react';
import { SchemaComponentOptions } from './SchemaComponentOptions';
function toSchema(schema?: any) {
@ -37,7 +36,7 @@ const MemoizedSchemaComponent = (props: ISchemaFieldProps) => {
return <RecursionSchemaComponent {...others} schema={s} />;
};
export const SchemaComponent = (props: ISchemaFieldProps & { memoized?: boolean }) => {
export const SchemaComponent = (props: (ISchemaFieldProps | IRecursionFieldProps) & { memoized?: boolean }) => {
const { memoized, ...others } = props;
if (memoized) {
return <MemoizedSchemaComponent {...others} />;

View File

@ -7,7 +7,7 @@ import { SchemaInitializer, SchemaInitializerItemOptions } from '../..';
import { useCollection } from '../../../collection-manager';
import { useDesignable } from '../../../schema-component';
const useFormItems = () => {
const useFormItemInitializerFields = () => {
const { name, fields } = useCollection();
return fields?.map((field) => {
return {
@ -127,7 +127,7 @@ export const FormItemInitializer = observer((props: any) => {
{
type: 'itemGroup',
title: t('Display fields'),
children: useFormItems(),
children: useFormItemInitializerFields(),
},
{
type: 'divider',

View File

@ -1,4 +1,3 @@
export * from './SchemaInitializer';
export * from './SchemaInitializerProvider';
export * from './types';

View File

@ -1115,7 +1115,7 @@
dependencies:
regenerator-runtime "^0.13.4"
"@babel/runtime@^7.12.13":
"@babel/runtime@^7.12.13", "@babel/runtime@^7.6.3", "@babel/runtime@^7.8.7":
version "7.17.2"
resolved "https://registry.npmjs.org/@babel/runtime/-/runtime-7.17.2.tgz#66f68591605e59da47523c631416b18508779941"
integrity sha512-hzeyJyMA1YGdJTuWU0e/j4wKXrU4OMFvY2MSlaI9B7VQb0r5cxTE3EAIS2Q7Tn2RIcDkRvTA/v2JsAEhxe99uw==
@ -2963,6 +2963,18 @@
dependencies:
debug "^4.3.1"
"@popperjs/core@^2.5.3":
version "2.11.2"
resolved "https://registry.npmjs.org/@popperjs/core/-/core-2.11.2.tgz#830beaec4b4091a9e9398ac50f865ddea52186b9"
integrity sha512-92FRmppjjqz29VMJ2dn+xdyXZBrMlE42AV6Kq6BwjWV7CNUW1hs2FtxSNLQE+gJhaZ6AAmYuO9y8dshhcBl7vA==
"@restart/hooks@^0.3.25":
version "0.3.27"
resolved "https://registry.npmjs.org/@restart/hooks/-/hooks-0.3.27.tgz#91f356d66d4699a8cd8b3d008402708b6a9dc505"
integrity sha512-s984xV/EapUIfkjlf8wz9weP2O9TNKR96C68FfMEy2bE69+H4cNv3RD4Mf97lW7Htt7PjZrYTjSC8f3SB9VCXw==
dependencies:
dequal "^2.0.2"
"@sinonjs/commons@^1.7.0":
version "1.8.3"
resolved "https://registry.npmjs.org/@sinonjs/commons/-/commons-1.8.3.tgz#3802ddd21a50a949b6721ddd72da36e67e7f1b2d"
@ -3406,7 +3418,7 @@
"@types/history" "*"
"@types/react" "*"
"@types/react@*", "@types/react@^16.9.43", "@types/react@^17.0.0":
"@types/react@*", "@types/react@>=16.9.11", "@types/react@^16.9.43", "@types/react@^17.0.0":
version "17.0.34"
resolved "https://registry.npmjs.org/@types/react/-/react-17.0.34.tgz#797b66d359b692e3f19991b6b07e4b0c706c0102"
integrity sha512-46FEGrMjc2+8XhHXILr+3+/sTe3OfzSPU9YGKILLrUYbQ1CLQC9Daqo1KzENGXAWwrFwiY0l4ZbF20gRvgpWTg==
@ -3475,6 +3487,11 @@
resolved "https://registry.npmjs.org/@types/unist/-/unist-2.0.6.tgz#250a7b16c3b91f672a24552ec64678eeb1d3a08d"
integrity sha512-PBjIUxZHOuj0R15/xuwJYjFi+KZdNFrehocChv4g5hu6aFroHue8m0lBP0POdK2nKzbw0cgV1mws8+V/JAcEkQ==
"@types/warning@^3.0.0":
version "3.0.0"
resolved "https://registry.npmjs.org/@types/warning/-/warning-3.0.0.tgz#0d2501268ad8f9962b740d387c4654f5f8e23e52"
integrity sha1-DSUBJorY+ZYrdA04fEZU9fjiPlI=
"@types/yargs-parser@*":
version "20.2.1"
resolved "https://registry.npmjs.org/@types/yargs-parser/-/yargs-parser-20.2.1.tgz#3b9ce2489919d9e4fea439b76916abc34b2df129"
@ -5326,6 +5343,11 @@ clone@^1.0.2:
resolved "https://registry.npmjs.org/clone/-/clone-1.0.4.tgz#da309cc263df15994c688ca902179ca3c7cd7c7e"
integrity sha1-2jCcwmPfFZlMaIypAheco8fNfH4=
clsx@^1.0.4:
version "1.1.1"
resolved "https://registry.npmjs.org/clsx/-/clsx-1.1.1.tgz#98b3134f9abbdf23b2663491ace13c5c03a73188"
integrity sha512-6/bPho624p3S2pMyvP5kKBPXnI3ufHLObBFCfgx+LkeR5lg2XYy2hqZqUf45ypD8COn2bhgGJSUE+l5dhNBieA==
cmd-shim@^4.1.0:
version "4.1.0"
resolved "https://registry.npmjs.org/cmd-shim/-/cmd-shim-4.1.0.tgz#b3a904a6743e9fede4148c6f3800bf2a08135bdd"
@ -6046,6 +6068,11 @@ data-urls@^2.0.0:
whatwg-mimetype "^2.3.0"
whatwg-url "^8.0.0"
date-arithmetic@^4.1.0:
version "4.1.0"
resolved "https://registry.npmjs.org/date-arithmetic/-/date-arithmetic-4.1.0.tgz#e5d6434e9deb71f79760a37b729e4a515e730ddf"
integrity sha512-QWxYLR5P/6GStZcdem+V1xoto6DMadYWpMXU82ES3/RfR3Wdwr3D0+be7mgOJ+Ov0G9D5Dmb9T17sNLQYj9XOg==
date-fns@2.x:
version "2.27.0"
resolved "https://registry.npmjs.org/date-fns/-/date-fns-2.27.0.tgz#e1ff3c3ddbbab8a2eaadbb6106be2929a5a2d92b"
@ -6374,6 +6401,14 @@ dom-align@^1.7.0:
resolved "https://registry.npmjs.org/dom-align/-/dom-align-1.12.2.tgz#0f8164ebd0c9c21b0c790310493cd855892acd4b"
integrity sha512-pHuazgqrsTFrGU2WLDdXxCFabkdQDx72ddkraZNih1KsMcN5qsRSTR9O4VJRlwTPCPb5COYg3LOfiMHHcPInHg==
dom-helpers@^5.1.0, dom-helpers@^5.2.0:
version "5.2.1"
resolved "https://registry.npmjs.org/dom-helpers/-/dom-helpers-5.2.1.tgz#d9400536b2bf8225ad98fe052e029451ac40e902"
integrity sha512-nRCa7CK3VTrM2NmGkIy4cbK7IZlgBE/PYMn55rrXefr5xXDP0LdtfPnblFDoVdcAfslJ7or6iqAUnx0CCGIWQA==
dependencies:
"@babel/runtime" "^7.8.7"
csstype "^3.0.2"
domain-browser@^1.1.1:
version "1.2.0"
resolved "https://registry.npmjs.org/domain-browser/-/domain-browser-1.2.0.tgz#3d31f50191a6749dd1375a7f522e823d42e54eda"
@ -10250,6 +10285,11 @@ locate-path@^6.0.0:
dependencies:
p-locate "^5.0.0"
lodash-es@^4.17.11:
version "4.17.21"
resolved "https://registry.npmjs.org/lodash-es/-/lodash-es-4.17.21.tgz#43e626c46e6591b7750beb2b50117390c609e3ee"
integrity sha512-mKnC+QJ9pWVzv+C4/U3rRsHapFfHvQFoFB92e52xeyGMcX6/OlIl78je1u8vePzYZSkkogMPJ2yjxxsb89cxyw==
lodash._baseclone@~4.5.0:
version "4.5.7"
resolved "https://registry.npmjs.org/lodash._baseclone/-/lodash._baseclone-4.5.7.tgz#ce42ade08384ef5d62fa77c30f61a46e686f8434"
@ -13697,6 +13737,23 @@ react-beautiful-dnd@^13.1.0:
redux "^4.0.4"
use-memo-one "^1.1.1"
react-big-calendar@^0.38.7:
version "0.38.9"
resolved "https://registry.npmjs.org/react-big-calendar/-/react-big-calendar-0.38.9.tgz#71a4fb578ddaaea2f65c664dbdeca0063be7b1f2"
integrity sha512-Z0yviu6ah5njVfRZxOwM2qnPRJCVuywk68jtjLr6GcCJj5bzhgc9+rkP/FSgbH6aBIWsvcTWw6kGTg5CClX6Ww==
dependencies:
"@babel/runtime" "^7.1.5"
clsx "^1.0.4"
date-arithmetic "^4.1.0"
dom-helpers "^5.1.0"
invariant "^2.2.4"
lodash "^4.17.11"
lodash-es "^4.17.11"
memoize-one "^5.1.1"
prop-types "^15.7.2"
react-overlays "^4.1.1"
uncontrollable "^7.0.0"
react-docgen-typescript-dumi-tmp@^1.22.1-0:
version "1.22.1-0"
resolved "https://registry.npmjs.org/react-docgen-typescript-dumi-tmp/-/react-docgen-typescript-dumi-tmp-1.22.1-0.tgz#6f452de05c5c114a6e1dd60b34930afaa7ae39a0"
@ -13763,7 +13820,7 @@ react-is@^17.0.1, react-is@^17.0.2:
resolved "https://registry.npmjs.org/react-is/-/react-is-17.0.2.tgz#e691d4a8e9c789365655539ab372762b0efb54f0"
integrity sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w==
react-lifecycles-compat@^3.0.0:
react-lifecycles-compat@^3.0.0, react-lifecycles-compat@^3.0.4:
version "3.0.4"
resolved "https://registry.npmjs.org/react-lifecycles-compat/-/react-lifecycles-compat-3.0.4.tgz#4f1a273afdfc8f3488a8c516bfda78f872352362"
integrity sha512-fBASbA6LnOU9dOU2eW7aQ8xmYBSXUIWr+UmF9b1efZBazGNO+rcXT/icdKnYm2pTwcRylVUYwW7H1PHfLekVzA==
@ -13778,6 +13835,20 @@ react-modal@^3.11.1:
react-lifecycles-compat "^3.0.0"
warning "^4.0.3"
react-overlays@^4.1.1:
version "4.1.1"
resolved "https://registry.npmjs.org/react-overlays/-/react-overlays-4.1.1.tgz#0060107cbe1c5171a744ccda3fbf0556d064bc5f"
integrity sha512-WtJifh081e6M24KnvTQoNjQEpz7HoLxqt8TwZM7LOYIkYJ8i/Ly1Xi7RVte87ZVnmqQ4PFaFiNHZhSINPSpdBQ==
dependencies:
"@babel/runtime" "^7.12.1"
"@popperjs/core" "^2.5.3"
"@restart/hooks" "^0.3.25"
"@types/warning" "^3.0.0"
dom-helpers "^5.2.0"
prop-types "^15.7.2"
uncontrollable "^7.0.0"
warning "^4.0.3"
react-redux@^7.2.0:
version "7.2.6"
resolved "https://registry.npmjs.org/react-redux/-/react-redux-7.2.6.tgz#49633a24fe552b5f9caf58feb8a138936ddfe9aa"
@ -16155,6 +16226,16 @@ unbox-primitive@^1.0.1:
has-symbols "^1.0.2"
which-boxed-primitive "^1.0.2"
uncontrollable@^7.0.0:
version "7.2.1"
resolved "https://registry.npmjs.org/uncontrollable/-/uncontrollable-7.2.1.tgz#1fa70ba0c57a14d5f78905d533cf63916dc75738"
integrity sha512-svtcfoTADIB0nT9nltgjujTi7BzVmwjZClOmskKu/E8FW9BXzg9os8OLr4f8Dlnk0rYWJIWr4wv9eKUXiQvQwQ==
dependencies:
"@babel/runtime" "^7.6.3"
"@types/react" ">=16.9.11"
invariant "^2.2.4"
react-lifecycles-compat "^3.0.4"
underscore@^1.13.1:
version "1.13.1"
resolved "https://registry.npmjs.org/underscore/-/underscore-1.13.1.tgz#0c1c6bd2df54b6b69f2314066d65b6cde6fcf9d1"