From a87a089acfdb4b915401137cfbddd0b7d307976c Mon Sep 17 00:00:00 2001 From: chenos Date: Mon, 10 Jan 2022 19:22:21 +0800 Subject: [PATCH] feat: client v0.6 (#150) * v0.6 * update... * feat: improve code * improve code * action & form * update... * improve code * improve code * improve code * designable * update * update... * api client * RecordProvider * collection manager * update... * update api client * update use request * update * update doc * test cases for compose * docs: improve documentation --- .umirc.ts | 4 + docs/index.md | 21 - package.json | 3 + packages/client/contributing.md | 61 ++ packages/client/intro.md | 854 ++++++++++++++++ packages/client/package.json | 19 +- packages/client/src/acl/ACLProvider.tsx | 13 + .../client/src/acl/RolePermissionManager.tsx | 1 + packages/client/src/acl/index.md | 12 + packages/client/src/acl/index.tsx | 2 + packages/client/src/action/Action.Drawer.tsx | 53 + packages/client/src/action/Action.tsx | 34 + packages/client/src/action/context.tsx | 3 + packages/client/src/action/demos/demo1.tsx | 66 ++ packages/client/src/action/hooks.ts | 27 + packages/client/src/action/index.md | 33 + packages/client/src/action/index.tsx | 3 + packages/client/src/action/types.ts | 16 + packages/client/src/admin-layout/index.md | 27 + packages/client/src/admin-layout/index.tsx | 12 + .../client/src/antd-config-provider/index.md | 10 + .../client/src/antd-config-provider/index.tsx | 10 + packages/client/src/api-client/APIClient.ts | 62 ++ .../src/api-client/APIClientProvider.tsx | 12 + .../api-client/__tests__/APIClient.test.tsx | 26 + packages/client/src/api-client/context.ts | 4 + .../client/src/api-client/demos/demo1.tsx | 24 + packages/client/src/api-client/hooks/index.ts | 3 + .../src/api-client/hooks/useAPIClient.ts | 6 + .../client/src/api-client/hooks/useRequest.ts | 36 + .../src/api-client/hooks/useResource.ts | 7 + packages/client/src/api-client/index.md | 139 +++ packages/client/src/api-client/index.tsx | 3 + .../__snapshots__/compose.test.tsx.snap | 77 ++ .../application/__tests__/compose.test.tsx | 95 ++ packages/client/src/application/compose.tsx | 18 + .../client/src/application/demos/Hello.tsx | 20 + .../demos/RouteSchemaComponent.tsx | 7 + .../client/src/application/demos/demo1.tsx | 23 + .../client/src/application/demos/routes.ts | 29 + packages/client/src/application/index.md | 14 + packages/client/src/application/index.tsx | 1 + packages/client/src/auth-layout/index.md | 9 + packages/client/src/auth-layout/index.tsx | 10 + .../client/src/block-item/demos/demo1.tsx | 86 ++ packages/client/src/block-item/index.md | 12 + packages/client/src/block-item/index.tsx | 12 + packages/client/src/calendar/index.md | 8 + packages/client/src/card-item/index.md | 10 + packages/client/src/card-item/index.tsx | 13 + packages/client/src/cascader/index.md | 8 + packages/client/src/chart/index.md | 8 + packages/client/src/checkbox/index.md | 8 + .../collection-manager/CollectionField.tsx | 42 + .../CollectionFieldProvider.tsx | 16 + .../CollectionManagerProvider.tsx | 12 + .../collection-manager/CollectionProvider.tsx | 14 + .../client/src/collection-manager/context.ts | 11 + .../src/collection-manager/demos/demo2.tsx | 124 +++ .../src/collection-manager/demos/demo3.tsx | 67 ++ .../src/collection-manager/hooks/index.ts | 3 + .../collection-manager/hooks/useCollection.ts | 18 + .../hooks/useCollectionField.ts | 17 + .../hooks/useCollectionManager.ts | 11 + .../client/src/collection-manager/index.md | 144 +++ .../client/src/collection-manager/index.tsx | 7 + .../collection-manager/interfaces/index.ts | 0 .../client/src/collection-manager/types.ts | 23 + packages/client/src/color-select/index.md | 8 + packages/client/src/current-user/index.md | 9 + packages/client/src/current-user/index.tsx | 3 + packages/client/src/date-picker/index.md | 8 + packages/client/src/dnd-context/index.md | 8 + packages/client/src/dnd-context/index.tsx | 29 + packages/client/src/document-title/index.md | 8 + packages/client/src/document-title/index.tsx | 3 + packages/client/src/filter/index.md | 8 + packages/client/src/form-item/index.md | 10 + packages/client/src/form-item/index.tsx | 11 + packages/client/src/form/Form.tsx | 58 ++ packages/client/src/form/demos/demo1.tsx | 54 + packages/client/src/form/demos/demo2.tsx | 47 + packages/client/src/form/index.md | 14 + packages/client/src/form/index.tsx | 1 + packages/client/src/grid/demos/demo1.tsx | 124 +++ packages/client/src/grid/index.md | 10 + packages/client/src/grid/index.tsx | 19 + packages/client/src/i18n/index.md | 10 + packages/client/src/i18n/index.ts | 54 + packages/client/src/icon-picker/index.md | 8 + packages/client/src/index.tsx | 26 +- packages/client/src/input-number/index.md | 8 + packages/client/src/input/index.md | 8 + packages/client/src/kanban/index.md | 8 + packages/client/src/locale/en_US.json | 280 +++++ packages/client/src/locale/zh_CN.json | 280 +++++ packages/client/src/markdown/index.md | 8 + packages/client/src/menu/index.md | 19 + packages/client/src/password/index.md | 8 + packages/client/src/radio/index.md | 8 + packages/client/src/record-picker/index.md | 8 + packages/client/src/record-provider/index.md | 30 + packages/client/src/record-provider/index.tsx | 13 + .../client/src/route-switch/RouteSwitch.tsx | 59 ++ .../src/route-switch/RouteSwitchProvider.tsx | 8 + .../__tests__/RouteSwitch.test.tsx | 32 + .../__snapshots__/RouteSwitch.test.tsx.snap | 9 + packages/client/src/route-switch/context.ts | 8 + .../client/src/route-switch/demos/demo1.tsx | 31 + packages/client/src/route-switch/hooks.ts | 15 + packages/client/src/route-switch/index.md | 10 + packages/client/src/route-switch/index.tsx | 5 + packages/client/src/route-switch/types.ts | 33 + packages/client/src/row-selection/index.md | 8 + .../components/RecursionComponent.tsx | 34 + .../components/SchemaComponent.tsx | 31 + .../components/SchemaComponentProvider.tsx | 44 + .../SchemaOptionsExpressionScopeProvider.tsx | 17 + .../src/schema-component/components/index.tsx | 4 + .../client/src/schema-component/context.ts | 4 + .../src/schema-component/demos/demo1.tsx | 83 ++ .../src/schema-component/demos/demo3.tsx | 65 ++ .../src/schema-component/hooks/index.ts | 3 + .../src/schema-component/hooks/useAttach.ts | 21 + .../schema-component/hooks/useDesignable.tsx | 278 +++++ .../schema-component/hooks/useFieldProps.ts | 18 + packages/client/src/schema-component/index.md | 82 ++ .../client/src/schema-component/index.tsx | 4 + packages/client/src/schema-component/types.ts | 38 + .../client/src/schema-initializer/index.md | 48 + packages/client/src/select/index.md | 8 + packages/client/src/settings-form/index.md | 8 + packages/client/src/sub-table/index.md | 8 + packages/client/src/system-settings/index.md | 15 + packages/client/src/system-settings/index.tsx | 3 + packages/client/src/table/index.md | 16 + packages/client/src/tabs/index.md | 11 + packages/client/src/time-picker/index.md | 8 + packages/client/src/tree-select/index.md | 8 + packages/client/src/upload/index.md | 8 + packages/client/tsconfig.build.json | 4 +- packages/client/tsconfig.json | 3 + tsconfig.build.json | 1 + tsconfig.jest.json | 1 + tsconfig.json | 1 + yarn.lock | 964 +++++++++++++++++- 146 files changed, 5799 insertions(+), 51 deletions(-) create mode 100644 packages/client/contributing.md create mode 100644 packages/client/intro.md create mode 100644 packages/client/src/acl/ACLProvider.tsx create mode 100644 packages/client/src/acl/RolePermissionManager.tsx create mode 100644 packages/client/src/acl/index.md create mode 100644 packages/client/src/acl/index.tsx create mode 100644 packages/client/src/action/Action.Drawer.tsx create mode 100644 packages/client/src/action/Action.tsx create mode 100644 packages/client/src/action/context.tsx create mode 100644 packages/client/src/action/demos/demo1.tsx create mode 100644 packages/client/src/action/hooks.ts create mode 100644 packages/client/src/action/index.md create mode 100644 packages/client/src/action/index.tsx create mode 100644 packages/client/src/action/types.ts create mode 100644 packages/client/src/admin-layout/index.md create mode 100644 packages/client/src/admin-layout/index.tsx create mode 100644 packages/client/src/antd-config-provider/index.md create mode 100644 packages/client/src/antd-config-provider/index.tsx create mode 100644 packages/client/src/api-client/APIClient.ts create mode 100644 packages/client/src/api-client/APIClientProvider.tsx create mode 100644 packages/client/src/api-client/__tests__/APIClient.test.tsx create mode 100644 packages/client/src/api-client/context.ts create mode 100644 packages/client/src/api-client/demos/demo1.tsx create mode 100644 packages/client/src/api-client/hooks/index.ts create mode 100644 packages/client/src/api-client/hooks/useAPIClient.ts create mode 100644 packages/client/src/api-client/hooks/useRequest.ts create mode 100644 packages/client/src/api-client/hooks/useResource.ts create mode 100644 packages/client/src/api-client/index.md create mode 100644 packages/client/src/api-client/index.tsx create mode 100644 packages/client/src/application/__tests__/__snapshots__/compose.test.tsx.snap create mode 100644 packages/client/src/application/__tests__/compose.test.tsx create mode 100644 packages/client/src/application/compose.tsx create mode 100644 packages/client/src/application/demos/Hello.tsx create mode 100644 packages/client/src/application/demos/RouteSchemaComponent.tsx create mode 100644 packages/client/src/application/demos/demo1.tsx create mode 100644 packages/client/src/application/demos/routes.ts create mode 100644 packages/client/src/application/index.md create mode 100644 packages/client/src/application/index.tsx create mode 100644 packages/client/src/auth-layout/index.md create mode 100644 packages/client/src/auth-layout/index.tsx create mode 100644 packages/client/src/block-item/demos/demo1.tsx create mode 100644 packages/client/src/block-item/index.md create mode 100644 packages/client/src/block-item/index.tsx create mode 100644 packages/client/src/calendar/index.md create mode 100644 packages/client/src/card-item/index.md create mode 100644 packages/client/src/card-item/index.tsx create mode 100644 packages/client/src/cascader/index.md create mode 100644 packages/client/src/chart/index.md create mode 100644 packages/client/src/checkbox/index.md create mode 100644 packages/client/src/collection-manager/CollectionField.tsx create mode 100644 packages/client/src/collection-manager/CollectionFieldProvider.tsx create mode 100644 packages/client/src/collection-manager/CollectionManagerProvider.tsx create mode 100644 packages/client/src/collection-manager/CollectionProvider.tsx create mode 100644 packages/client/src/collection-manager/context.ts create mode 100644 packages/client/src/collection-manager/demos/demo2.tsx create mode 100644 packages/client/src/collection-manager/demos/demo3.tsx create mode 100644 packages/client/src/collection-manager/hooks/index.ts create mode 100644 packages/client/src/collection-manager/hooks/useCollection.ts create mode 100644 packages/client/src/collection-manager/hooks/useCollectionField.ts create mode 100644 packages/client/src/collection-manager/hooks/useCollectionManager.ts create mode 100644 packages/client/src/collection-manager/index.md create mode 100644 packages/client/src/collection-manager/index.tsx create mode 100644 packages/client/src/collection-manager/interfaces/index.ts create mode 100644 packages/client/src/collection-manager/types.ts create mode 100644 packages/client/src/color-select/index.md create mode 100644 packages/client/src/current-user/index.md create mode 100644 packages/client/src/current-user/index.tsx create mode 100644 packages/client/src/date-picker/index.md create mode 100644 packages/client/src/dnd-context/index.md create mode 100644 packages/client/src/dnd-context/index.tsx create mode 100644 packages/client/src/document-title/index.md create mode 100644 packages/client/src/document-title/index.tsx create mode 100644 packages/client/src/filter/index.md create mode 100644 packages/client/src/form-item/index.md create mode 100644 packages/client/src/form-item/index.tsx create mode 100644 packages/client/src/form/Form.tsx create mode 100644 packages/client/src/form/demos/demo1.tsx create mode 100644 packages/client/src/form/demos/demo2.tsx create mode 100644 packages/client/src/form/index.md create mode 100644 packages/client/src/form/index.tsx create mode 100644 packages/client/src/grid/demos/demo1.tsx create mode 100644 packages/client/src/grid/index.md create mode 100644 packages/client/src/grid/index.tsx create mode 100644 packages/client/src/i18n/index.md create mode 100644 packages/client/src/i18n/index.ts create mode 100644 packages/client/src/icon-picker/index.md create mode 100644 packages/client/src/input-number/index.md create mode 100644 packages/client/src/input/index.md create mode 100644 packages/client/src/kanban/index.md create mode 100644 packages/client/src/locale/en_US.json create mode 100644 packages/client/src/locale/zh_CN.json create mode 100644 packages/client/src/markdown/index.md create mode 100644 packages/client/src/menu/index.md create mode 100644 packages/client/src/password/index.md create mode 100644 packages/client/src/radio/index.md create mode 100644 packages/client/src/record-picker/index.md create mode 100644 packages/client/src/record-provider/index.md create mode 100644 packages/client/src/record-provider/index.tsx create mode 100644 packages/client/src/route-switch/RouteSwitch.tsx create mode 100644 packages/client/src/route-switch/RouteSwitchProvider.tsx create mode 100644 packages/client/src/route-switch/__tests__/RouteSwitch.test.tsx create mode 100644 packages/client/src/route-switch/__tests__/__snapshots__/RouteSwitch.test.tsx.snap create mode 100644 packages/client/src/route-switch/context.ts create mode 100644 packages/client/src/route-switch/demos/demo1.tsx create mode 100644 packages/client/src/route-switch/hooks.ts create mode 100644 packages/client/src/route-switch/index.md create mode 100644 packages/client/src/route-switch/index.tsx create mode 100644 packages/client/src/route-switch/types.ts create mode 100644 packages/client/src/row-selection/index.md create mode 100644 packages/client/src/schema-component/components/RecursionComponent.tsx create mode 100644 packages/client/src/schema-component/components/SchemaComponent.tsx create mode 100644 packages/client/src/schema-component/components/SchemaComponentProvider.tsx create mode 100644 packages/client/src/schema-component/components/SchemaOptionsExpressionScopeProvider.tsx create mode 100644 packages/client/src/schema-component/components/index.tsx create mode 100644 packages/client/src/schema-component/context.ts create mode 100644 packages/client/src/schema-component/demos/demo1.tsx create mode 100644 packages/client/src/schema-component/demos/demo3.tsx create mode 100644 packages/client/src/schema-component/hooks/index.ts create mode 100644 packages/client/src/schema-component/hooks/useAttach.ts create mode 100644 packages/client/src/schema-component/hooks/useDesignable.tsx create mode 100644 packages/client/src/schema-component/hooks/useFieldProps.ts create mode 100644 packages/client/src/schema-component/index.md create mode 100644 packages/client/src/schema-component/index.tsx create mode 100644 packages/client/src/schema-component/types.ts create mode 100644 packages/client/src/schema-initializer/index.md create mode 100644 packages/client/src/select/index.md create mode 100644 packages/client/src/settings-form/index.md create mode 100644 packages/client/src/sub-table/index.md create mode 100644 packages/client/src/system-settings/index.md create mode 100644 packages/client/src/system-settings/index.tsx create mode 100644 packages/client/src/table/index.md create mode 100644 packages/client/src/tabs/index.md create mode 100644 packages/client/src/time-picker/index.md create mode 100644 packages/client/src/tree-select/index.md create mode 100644 packages/client/src/upload/index.md diff --git a/.umirc.ts b/.umirc.ts index d6c6d78ef..bd2a7be7b 100644 --- a/.umirc.ts +++ b/.umirc.ts @@ -6,5 +6,9 @@ export default defineConfig({ logo: 'https://user-images.githubusercontent.com/9554297/83762004-a0761b00-a6a9-11ea-83b4-9c8ff721d4b8.png', outputPath: 'docs-dist', mode: 'site', + resolve: { + includes: ['docs', 'packages/client'], + }, + hash: true, // more config: https://d.umijs.org/config }); diff --git a/docs/index.md b/docs/index.md index 85f6100c8..e69de29bb 100644 --- a/docs/index.md +++ b/docs/index.md @@ -1,21 +0,0 @@ ---- -hero: - title: umilib - desc: umilib site example - actions: - - text: Getting Started - link: /components -features: - - icon: https://gw.alipayobjects.com/zos/bmw-prod/881dc458-f20b-407b-947a-95104b5ec82b/k79dm8ih_w144_h144.png - title: Feature 1 - desc: Balabala - - icon: https://gw.alipayobjects.com/zos/bmw-prod/d60657df-0822-4631-9d7c-e7a869c2f21c/k79dmz3q_w126_h126.png - title: Feature 2 - desc: Balabala - - icon: https://gw.alipayobjects.com/zos/bmw-prod/d1ee0c6f-5aed-4a45-a507-339a4bfe076c/k7bjsocq_w144_h144.png - title: Feature 3 - desc: Balabala -footer: Open-source MIT Licensed | Copyright © 2020
Powered by [dumi](https://d.umijs.org) ---- - -## Hello umilib! diff --git a/package.json b/package.json index 36ca89ff4..bd9820b30 100644 --- a/package.json +++ b/package.json @@ -9,6 +9,7 @@ "bootstrap": "lerna bootstrap", "clean": "rimraf -rf packages/*/{lib,esm,dist} && lerna clean", "build": "lerna run build", + "build-docs": "dumi build", "test": "jest", "lint": "eslint ." }, @@ -17,6 +18,7 @@ "@types/react-dom": "^17.0.0" }, "devDependencies": { + "@testing-library/react": "^12.1.2", "@types/jest": "^26.0.0", "@types/koa": "^2.13.4", "@types/koa-bodyparser": "^4.3.4", @@ -26,6 +28,7 @@ "@types/react-dom": "^17.0.0", "@typescript-eslint/eslint-plugin": "^4.9.1", "@typescript-eslint/parser": "^4.8.2", + "antd": "^4.16.11", "cross-env": "^5.2.0", "dotenv": "^10.0.0", "dumi": "^1.1.33", diff --git a/packages/client/contributing.md b/packages/client/contributing.md new file mode 100644 index 000000000..515749f6e --- /dev/null +++ b/packages/client/contributing.md @@ -0,0 +1,61 @@ +--- +toc: menu +--- + +# 参与贡献 + +客户端的模块都在 `src` 目录下,各自模块独立。 + +## 客户端模块 + +最小单元模块化,一个完整的模块包含: + +```bash +|- /__tests__/ # 测试文件目录 +|- /demos/ # demo 目录 +|- index.ts # 最好不要直接在 index.ts 文件里写代码,index 文件只负责 export +|- index.md # 文档,默认为英文 +|- index.zh-CN.md # 中文文档,可缺失,可以先都写到 index.md 里 +``` + +## 测试 + +详细文档见 [@testing-library/react](https://testing-library.com/docs/react-testing-library/intro/) + +```tsx | pure +import React from 'react'; +import { render } from '@testing-library/react'; +import { compose } from '../'; + +describe('compose', () => { + it('case 1', () => { + const A: React.FC = (props) => ( +
+

A

+ {props.children} +
+ ); + const App = compose(A)(); + const { container } = render(); + expect(container).toMatchSnapshot(); + }); +}); +``` + +## Demo + +组件 Demo 见 [dumi](https://d.umijs.org/guide/basic#write-component-demo),可以直接写在文档里,如: + +
+```jsx
+import React from 'react';
+
+export default () => 

Hello NocoBase!

; +``` +
+ +也可以引用 demo 文件 + +```markdown + +``` diff --git a/packages/client/intro.md b/packages/client/intro.md new file mode 100644 index 000000000..d66076b69 --- /dev/null +++ b/packages/client/intro.md @@ -0,0 +1,854 @@ +--- +order: 1 +--- + +# 客户端内核 + + + +示例: + +```tsx | pure +const app = new Application(); + +app.use([MemoryRouter, { initialEntries: ['/'] }]); + +app.use(({ children }) => { + const location = useLocation(); + if (location.pathname === '/hello') { + return
Hello NocoBase!
; + } + return children; +}); + +export default app.compose(); +``` + +## RouteSwitch + +稍微复杂的应用都会用到路由来管理前端的页面,如下: + +```jsx +/** + * defaultShowCode: true + * title: Router + */ +import React from 'react'; +import { Route, Switch, Link, MemoryRouter as Router } from 'react-router-dom'; + +const Home = () =>

Home

; +const About = () =>

About

; + +const App = () => ( + + Home, About + + + + + + + + + +); + +export default App; +``` + +上述例子,组件经由路由转发,`/` 转发给 `Home`,`/about` 转发给 `About`。这种 JSX 的写法,对于熟悉 JSX 的开发来说,十分便捷,但需要开发来编写和维护,不符合 NocoBase 低代码、无代码的设计理念。所以将 Route 做了封装和配置化改造,如下: + +```tsx +/** + * defaultShowCode: true + * title: RouteSwitch + */ +import React from 'react'; +import { Link, MemoryRouter as Router } from 'react-router-dom'; +import { RouteRedirectProps, RouteSwitchProvider, RouteSwitch } from '@nocobase/client'; + +const Home = () =>

Home

; +const About = () =>

About

; + +const routes: RouteRedirectProps[] = [ + { + type: 'route', + path: '/', + exact: true, + component: 'Home', + }, + { + type: 'route', + path: '/about', + component: 'About', + }, +]; + +export default () => { + return ( + + + Home, About + + + + ); +}; +``` + +- 由 RouteSwitchProvider 配置 components,由开发编写,以 Layout 或 Template 的方式提供给 RouteSwitch 使用。 +- 由 RouteSwitch 配置 routes,JSON 的方式,可以由后端获取,方便后续的动态化、无代码的支持。 + +## SchemaComponent + +路由可以通过 JSON 的方式配置,可以注册诸多可供路由使用的组件模板,以方便各种场景支持,但是这些组件还是需要开发编写和维护,所以进一步将组件抽象,转换成配置化的方式。如: + +```tsx +/** + * defaultShowCode: true + * title: Schema Component + */ +import React from 'react'; +import { ISchema } from '@formily/react'; +import { SchemaComponentProvider, SchemaComponent } from '@nocobase/client'; + +const schema: ISchema = { + name: 'hello', + 'x-component': 'Hello', + 'x-component-props': { + name: 'World', + }, +}; + +const Hello = ({ name }) =>

Hello {name}!

; + +export default function App() { + return ( + + + + ) +}; +``` + +可以通过 schema 方式配置的组件,称之为 schema 组件。在 SchemaComponentProvider 里注册各种 JSX 组件,编写相应的 schema,再通过 SchemaComponent 渲染。SchemaComponent 的 schema 就是 Formily 的 [Schema](https://react.formilyjs.org/zh-CN/api/shared/schema)。实际上 SchemaComponent 就是 Formily 的 [SchemaField](https://react.formilyjs.org/zh-CN/api/components/schema-field),之所以叫 SchemaComponent,是因为 SchemaComponent 可用于构建页面的各个部分,不局限于表单场景。 + +**思维转换:** + +虽然 Formily 的核心是致力于解决表单的复杂问题,但是随着不断的演变,已经不局限在表单层面了。Formily 核心提供了 Form 和 Field 两个非常重要的模型,Form 提供了路径系统和联动模型也同样适用于页面视图,Field 实际上也可以理解为组件,分为有值组件和无值组件两类,有值组件例如 Input、Select 等,无值组件例如 Drawer、Button 等。有值组件的数值又可以分不同类型:String、Number、Boolean、Object、Array 等等,无值组件没有数值,所以用 Void 表示,和 Formily 的 Field、ArrayField、ObjectField、VoidField 都对应上了。 + +为了适应动态的配置化表单解决方案,Formily 又提炼了 Schema 协议(DSL),这个协议完全适用于描述组件模型,用类 JSON Schema 的语法描述组件结构和对应的数值类型,这个 Schema 也是 SchemaComponent 的重要组成部分。 + +- Schema 是一个树结构,多个节点以树形结构连接起来,其中的一个 property 表示的就是其中的一个 Schema 节点。 +- 单 Schema 节点(不包括 properties)由核心 `x-component`、包装器 `x-decorator`、设计器 `x-designable` 三个组件构成。 + - `x-component` 核心组件 + - `x-decorator` 包装器,不同场景中,同一个核心组件,可能使用不同的包装器,如 FormItem、CardItem、BlockItem、Editable 等 + - `x-designable` 节点设计器(NocoBase 的扩展参数),一般为当前 schema 节点的配置表单。与 Formily 提供的 Designable 解决方案不同,`x-designable` 直接作用于当前 schema 节点,使用和配置不分离。 + +理论上,很多现有组件都可以直接转为 schema 组件,但是并不一定好用。以 Drawer 为例,常规 JSX 的写法一般是这样的: + +```tsx +/** + * defaultShowCode: true + * title: JSX Drawer + */ +import React, { useState } from 'react'; +import { Drawer, Button } from 'antd'; + +const App: React.FC = () => { + const [visible, setVisible] = useState(false); + const showDrawer = () => { + setVisible(true); + }; + const onClose = () => { + setVisible(false); + }; + return ( + <> + + 关闭 + } + > +

Some contents...

+

Some contents...

+

Some contents...

+
+ + ); +}; + +export default App; +``` + +将组件转换成 schema,如果 1:1 转换是这样的: + +```tsx +/** + * defaultShowCode: true + * title: Drawer Schema + */ +import React, { useMemo } from 'react'; +import { SchemaComponentProvider, SchemaComponent } from '@nocobase/client'; +import { Drawer as AntdDrawer, Button } from 'antd'; +import { createForm } from '@formily/core'; +import { RecursionField } from '@formily/react'; + +const Drawer = (props) => { + const { footerSchema, ...others } = props; + return ( + + } + {...others} + /> + ); +}; + +const schema = { + type: 'object', + properties: { + b1: { + type: 'void', + 'x-component': 'Button', + 'x-component-props': { + children: 'Open', + type: 'primary', + onClick: '{{showDrawer}}', + }, + }, + d1: { + type: 'void', + 'x-component': 'Drawer', + 'x-component-props': { + title: 'Basic Drawer', + onClose: '{{onClose}}', + footerSchema: { + type: 'object', + properties: { + fb1: { + type: 'void', + 'x-component': 'Button', + 'x-component-props': { + children: 'Close', + onClick: '{{onClose}}', + }, + }, + }, + }, + }, + }, + }, +}; + +export default function App() { + const form = useMemo(() => createForm(), []); + const showDrawer = () => { + form.query('d1').take((field) => { + field.componentProps.visible = true; + }); + }; + const onClose = () => { + form.query('d1').take((field) => { + field.componentProps.visible = false; + }); + }; + return ( + + + + ); +} +``` + +这个例子讲述了怎么将组件转换为可 Schema 配置,虽然达成了某种效果,但并不是一个很好的示例。 + +- 一个 property 就是一个 Schema 节点,Drawer 的 Schema 由平行的两个 schema 节点组成,不利于管理; +- 需要额外的自定义 scope 支持 drawer 组件 visible 的状态管理,而且这里自定义的 scope 复用性差; +- footer 需要特殊处理。在 x-component-props 里加了个 footerSchema 参数。但这个 footerSchema 并不是一个常规的 schema 节点,因为不是在 properties 里,不利于后端 schema 存储的统一规划; +- 删除 drawer,需要删除两个 schema 节点; +- 后端如何输出 drawer 这部分的 schema 也非常不方便,因为 drawer 由平行的两个节点组成。 + +为了解决上述问题,从结构上做了一些改良: + +```ts +{ + type: 'object', + properties: { + a1: { + 'x-component': 'Action', + title: 'Open', + properties: { + d1: { + 'x-component': 'Action.Drawer', + title: 'Drawer Title', + properties: { + c1: { + 'x-content': 'Hello', + }, + f1: { + 'x-component': 'Action.Drawer.Footer', + properties: { + a1: { + 'x-component': 'Action', + title: 'Close', + 'x-component-props': { + useAction: '{{ useCloseAction }}', + }, + }, + }, + }, + }, + }, + }, + }, + }, +} +``` + +以上示例,自定义了一个 Action 组件,用于配置按钮操作,又扩展了 Action.Drawer 和 Action.Drawer.Footer 两个特殊节点,分别用于配置抽屉弹框和抽屉的 footer。以上 schema 是个标准的组件树结构,层次十分分明。组件树的各个节点层次分明,schema 的增删改查就完全是标准流程了。 + +- 查询 Drawer 的 schema,只需要把 a1 节点的 json 全部输出就可以。 +- 修改各个节点和子节点都可以单节点独立处理,逻辑一致。 +- 删除时,直接删除不需要的节点就可以了。 +- 有利于扩展,比如继续增加 Action.Modal、Action.Modal.Footer 两个节点用于配置对话框。 + +Action.Drawer 完整的例子如下: + +```tsx +/** + * title: Action.Drawer + */ +import React, { createContext, useContext, useMemo, useState } from 'react'; +import { createPortal } from 'react-dom'; +import { Button, Drawer } from 'antd'; +import { SchemaComponentProvider, SchemaComponent } from '@nocobase/client'; +import { observer, RecursionField, useField, useFieldSchema, ISchema } from '@formily/react'; + +const VisibleContext = createContext(null); + +const useA = () => { + return { + async run() {}, + }; +}; + +function useCloseAction() { + const [, setVisible] = useContext(VisibleContext); + return { + async run() { + setVisible(false); + }, + }; +} + +const Action: any = observer((props: any) => { + const { useAction = useA, onClick, ...others } = props; + const [visible, setVisible] = useState(false); + const schema = useFieldSchema(); + const field = useField(); + const { run } = useAction(); + return ( + + + + + ); +}); + +Action.Drawer = observer((props: any) => { + const [visible, setVisible] = useContext(VisibleContext); + const schema = useFieldSchema(); + const field = useField(); + return ( + <> + {createPortal( + setVisible(false)} + footer={ + { + return s['x-component'] === 'Action.Drawer.Footer'; + }} + /> + } + > + { + return s['x-component'] !== 'Action.Drawer.Footer'; + }} + /> + , + document.body, + )} + + ); +}); + +Action.Drawer.Footer = observer((props: any) => { + const field = useField(); + const schema = useFieldSchema(); + return ; +}); + +const schema: ISchema = { + type: 'object', + properties: { + a1: { + 'x-component': 'Action', + 'x-component-props': { + type: 'primary', + }, + title: 'Open', + properties: { + d1: { + 'x-component': 'Action.Drawer', + title: 'Drawer Title', + properties: { + c1: { + 'x-content': 'Hello', + }, + f1: { + 'x-component': 'Action.Drawer.Footer', + properties: { + a1: { + 'x-component': 'Action', + title: 'Close', + 'x-component-props': { + useAction: '{{ useCloseAction }}', + }, + }, + }, + }, + }, + }, + }, + }, + }, +}; + +export default function App() { + return ( + + + + ); +} +``` + +## RouteSwitch + SchemaComponent + +当路由和组件都可以配置之后,可以进一步将二者结合,例子如下: + +```tsx +/** + * defaultShowCode: true + * title: RouteSwitch + SchemaComponent + */ +import React, { useMemo } from 'react'; +import { Link, MemoryRouter as Router } from 'react-router-dom'; +import { + RouteRedirectProps, + RouteSwitchProvider, + RouteSwitch, + useRoute, + SchemaComponentProvider, + SchemaComponent, + useDesignable, +} from '@nocobase/client'; +import { Spin, Button } from 'antd'; +import { observer, Schema } from '@formily/react'; + +const Hello = observer(({ name }) => { + const { patch, remove } = useDesignable(); + return ( +
+

Hello {name}!

+ +
+ ) +}); + +const RouteSchemaComponent = (props) => { + const route = useRoute(); + return +} + +const routes: RouteRedirectProps[] = [ + { + type: 'route', + path: '/', + exact: true, + component: 'RouteSchemaComponent', + schema: { + name: 'home', + 'x-component': 'Hello', + 'x-component-props': { + name: 'Home', + }, + }, + }, + { + type: 'route', + path: '/about', + component: 'RouteSchemaComponent', + schema: { + name: 'home', + 'x-component': 'Hello', + 'x-component-props': { + name: 'About', + }, + }, + }, +]; + +export default () => { + return ( + + + + Home, About + + + + + ); +}; +``` + +以上例子实现了路由和组件层面的配置化,在开发层面配置了两个组件: + +- `` 简易的可以在路由里配置 schema 的方案 +- `` 自定义的 Schema 组件 + +为了让大家更加能感受到 Schema 组件的不一样之处,例子添加了一个简易的随机更新 `x-component-props.name` 值的按钮,当路由切换后,更新后的 name 并不会被重置。这也是 Schema 组件的 Designable 的能力,可以任意的动态更新 schema 配置,实时更新,实时渲染。 + +## Designable + +SchemaComponent 基于 Formily 的 SchemaField,Formily 提供了 [Designable](https://github.com/alibaba/designable) 来解决 Schema 的配置问题,但是这套方案: + +- 需要维护两套代码,以 antd 为例,需要同时维护 @formily/antd 和 @designable/formily-antd 两套代码 +- 使用和设计分离,在设计器界面表单无法正常工作 + +另辟蹊径,NocoBase 构想了一种更为便捷的配置方案,使用和配置也可以兼顾,只需要维护一套代码。为此,提炼了一个简易的 `useDesignable()` Hook,可用于任意 Schema 组件中,动态配置 Schema,实时更新,实时渲染。 + +Hook API: + +```ts +const { + designable, // 是否可以配置 + patch, // 更新当前节点配置 + remove, // 移除当前节点 + insertAdjacent, // 在当前节点的相邻位置插入,四个位置:beforeBegin、afterBegin、beforeEnd、afterEnd + insertBeforeBegin, // 在当前节点的前面插入 + insertAfterBegin, // 在当前节点的第一个子节点前面插入 + insertBeforeEnd, // 在当前节点的最后一个子节点后面 + insertAfterEnd, // 在当前节点的后面 +} = useDesignable(); + +const schema = { + 'x-component': 'Hello', +}; + +// 在当前节点的前面插入 +insertBeforeBegin(schema); +// 等同于 +insertAdjacent('beforeBegin', schema); + +// 在当前节点的第一个子节点前面插入 +insertAfterBegin(schema); +// 等同于 +insertAdjacent('afterBegin', schema); + +// 在当前节点的最后一个子节点后面 +insertBeforeEnd(schema); +// 等同于 +insertAdjacent('beforeEnd', schema); + +// 在当前节点的后面 +insertAfterEnd(schema); +// 等同于 +insertAdjacent('afterEnd', schema); +``` + +insertAdjacent 的几个插入的位置: + +```ts +{ + properties: { + // beforeBegin 在当前节点的前面插入 + node1: { + properties: { + // afterBegin 在当前节点的第一个子节点前面插入 + // ... + // beforeEnd 在当前节点的最后一个子节点后面 + }, + }, + // afterEnd 在当前节点的后面 + }, +} +``` + +并不是所有场景都能使用 hook,所以提供了 `createDesignable()` 方法(实际上 `useDesignable()` 也是基于它来实现): + +```ts +const dn = createDesignable({ + current: schema, +}); + +dn.on('afterInsertAdjacent', (position, schema) => { + +}); + +dn.insertAfterEnd(schema); +``` + +相关例子如下: + + + +insertAdjacent 操作不仅可以用于新增节点,也可以用于现有节点的位置移动,如以下拖拽排序的例子: + +```tsx +/** + * title: 拖拽排序 + */ +import React from 'react'; +import { uid } from '@formily/shared'; +import { observer, useField, useFieldSchema } from '@formily/react'; +import { DndContext, DragEndEvent, useDraggable, useDroppable } from '@dnd-kit/core'; +import { SchemaComponent, SchemaComponentProvider, createDesignable, useDesignable } from '@nocobase/client'; + +const useDragEnd = () => { + const { refresh } = useDesignable(); + + return ({ active, over }: DragEndEvent) => { + const activeSchema = active?.data?.current?.schema; + const overSchema = over?.data?.current?.schema; + + if (!activeSchema || !overSchema) { + return; + } + + const dn = createDesignable({ + current: overSchema, + }); + + dn.on('afterInsertAdjacent', refresh); + dn.insertBeforeBeginOrAfterEnd(activeSchema); + }; +}; + +const Page = observer((props) => { + return {props.children}; +}); + +function Draggable(props) { + const { attributes, listeners, setNodeRef, transform } = useDraggable({ + id: props.id, + data: props.data, + }); + const style = transform + ? { + transform: `translate3d(${transform.x}px, ${transform.y}px, 0)`, + } + : undefined; + + return ( + + ); +} + +function Droppable(props) { + const { isOver, setNodeRef } = useDroppable({ + id: props.id, + data: props.data, + }); + const style = { + color: isOver ? 'green' : undefined, + }; + + return ( +
+ {props.children} +
+ ); +} + +const Block = observer((props) => { + const field = useField(); + const fieldSchema = useFieldSchema(); + return ( + +
+ Block {fieldSchema.name}{' '} + + Drag + +
+
+ ); +}); + +export default function App() { + return ( + + + + ); +} +``` + +## APIClient + +在 WEB 应用里,客户端请求无处不在。为了便于客户端请求,提供的 API 有: + +- APIClient:客户端 SDK +- APIClientProvider:提供 APIClient 实例的 Context,全局共享 +- useRequest():需要结合 APIClientProvider 来使用 +- useApiClient():获取到当前配置的 apiClient 实例 + +```tsx | pure +const api = new APIClient({ + request, // 将 request 抛出去,方便各种自定义适配 +}); +api.request(options); +api.resource(name); + + + {/* children */} + +``` + +useRequest() 需要结合 APIClientProvider 一起使用,是对 ahooks 的 useRequest 的封装,支持 resource 请求。 + +```ts +const { data, loading } = useRequest(); +``` + + +## Providers + +客户端的扩展以 Providers 的形式存在,提供各种可供组件使用的 Context,可全局也可以局部使用。上文我们已经介绍了核心的三个 Providers: + +- RouteSwitchProvider,提供配置路由所需的 Layout 和 Template 组件 +- SchemaComponentProvider,提供配置 Schema 所需的各种组件 +- ApiClientProvider,提供客户端 SDK + +除此之外,还有: + +- Router,实际也是 Provider,提供 History 的 Context,对应的有 BrowserRouter,HashRouter、MemoryRouter、NativeRouter、StaticRouter 几种可选方案 +- AntdConfigProvider,为 antd 组件提供统一的全局化配置 +- I18nextProvider,提供国际化解决方案 +- ACLProvider,提供权限配置,plugin-acl 的前端模块 +- CollectionManagerProvider,提供全局的数据表配置,plugin-collection-manager 的前端模块 +- SystemSettingsProvider,提供系统设置,plugin-system-settings 的前端模块 +- 其他扩展 + +多个 Providers 需要嵌套使用: + +```tsx | pure + + + + {...} + + + +``` + +但是这样的方式不利于 Providers 的管理和扩展,为此提炼了 `compose()` 函数用于配置多个 providers,如下: + + + +## Application + +上文例子的 Providers 还是差点意思,再进一步封装改造: + +```tsx | pure +const app = new Application({}); + +app.use(ApiClientProvider); +app.use([SchemaComponentProvider, { components: { Hello } }]); +app.use((props) => { + return ( +
+ Home,About + +
+ ); +}); + +app.mount('#root'); +// 等于 +ReactDOM.render(, document.getElementById('root')); +``` + +对比 NocoBase Server Application 中间件的核心实现: + +```ts +app.use((ctx, next) => {}); +const ctx = this.createContext(req, res) +await compose(app.middleware)(ctx); +await respond(ctx); +``` + +通过 app.use() 方法注册各种中间件插件,最后由 compose 来处理中间件,如果有需要也可以往 app.context 里添加各种东西待用。前端在处理 Provider 时也是类似的机制,这也是为什么客户端的扩展是以 Provider 的形式存在的原因。 + +从例子来看,以 Provider 的形式扩展是个不错的方案,但是还有两个问题没有解决: + +- Provider 的顺序怎么处理 +- 如何动态的加载前端模块 + +未完待续... \ No newline at end of file diff --git a/packages/client/package.json b/packages/client/package.json index f7cde6b3b..237b06645 100644 --- a/packages/client/package.json +++ b/packages/client/package.json @@ -16,18 +16,33 @@ "engines": { "npm": ">=3.0.0" }, + "dependencies": { + "@dnd-kit/core": "^4.0.3", + "@dnd-kit/sortable": "^5.1.0", + "@emotion/css": "^11.7.1", + "@formily/antd": "^2.0.7", + "@formily/core": "^2.0.7", + "@formily/react": "^2.0.7", + "ahooks": "^3.0.5", + "axios": "^0.24.0", + "i18next": "^21.6.0", + "react-i18next": "^11.15.1" + }, "peerDependencies": { "@types/react": ">=16.8.0 || >=17.0.0", "@types/react-dom": ">=16.8.0 || >=17.0.0", "antd": "^4.0.0", "react": ">=16.8.0 || >=17.0.0", "react-dom": ">=16.8.0", - "react-is": ">=16.8.0 || >=17.0.0" + "react-is": ">=16.8.0 || >=17.0.0", + "react-router-dom": "^5.2.0" }, "scripts": { "build": "rimraf -rf lib esm dist && npm run build:cjs && npm run build:esm", "build:cjs": "tsc --project tsconfig.build.json", "build:esm": "tsc --project tsconfig.build.json --module es2015 --outDir esm" }, - "dependencies": {} + "devDependencies": { + "axios-mock-adapter": "^1.20.0" + } } diff --git a/packages/client/src/acl/ACLProvider.tsx b/packages/client/src/acl/ACLProvider.tsx new file mode 100644 index 000000000..8d6a58951 --- /dev/null +++ b/packages/client/src/acl/ACLProvider.tsx @@ -0,0 +1,13 @@ +import React, { createContext, useContext } from 'react'; + +export const ACLContext = createContext(null); + +export function ACLProvider() { + return ( + + + + ) +} + +export default ACLProvider; diff --git a/packages/client/src/acl/RolePermissionManager.tsx b/packages/client/src/acl/RolePermissionManager.tsx new file mode 100644 index 000000000..455d32241 --- /dev/null +++ b/packages/client/src/acl/RolePermissionManager.tsx @@ -0,0 +1 @@ +export function RoleManager() {} diff --git a/packages/client/src/acl/index.md b/packages/client/src/acl/index.md new file mode 100644 index 000000000..2d68c8fc2 --- /dev/null +++ b/packages/client/src/acl/index.md @@ -0,0 +1,12 @@ +--- +nav: + title: Client + path: /client +group: + title: Client + path: /client +--- + +# ACL 待定 + +访问控制列表,plugin-acl 的前端模块 diff --git a/packages/client/src/acl/index.tsx b/packages/client/src/acl/index.tsx new file mode 100644 index 000000000..332e3cb46 --- /dev/null +++ b/packages/client/src/acl/index.tsx @@ -0,0 +1,2 @@ +export * from './ACLProvider'; +export * from './RolePermissionManager'; \ No newline at end of file diff --git a/packages/client/src/action/Action.Drawer.tsx b/packages/client/src/action/Action.Drawer.tsx new file mode 100644 index 000000000..bf7c26a52 --- /dev/null +++ b/packages/client/src/action/Action.Drawer.tsx @@ -0,0 +1,53 @@ +import React, { useContext } from 'react'; +import { createPortal } from 'react-dom'; +import { Drawer } from 'antd'; +import { VisibleContext } from './context'; +import { ComposedActionDrawer } from './types'; +import { observer, RecursionField, useField, useFieldSchema } from '@formily/react'; + +export const ActionDrawer: ComposedActionDrawer = observer((props) => { + const [visible, setVisible] = useContext(VisibleContext); + const schema = useFieldSchema(); + const field = useField(); + return ( + <> + {createPortal( + setVisible(false)} + footer={ + { + return s['x-component'] === 'Action.Drawer.Footer'; + }} + /> + } + > + { + return s['x-component'] !== 'Action.Drawer.Footer'; + }} + /> + , + document.body, + )} + + ); +}); + +ActionDrawer.Footer = observer(() => { + const field = useField(); + const schema = useFieldSchema(); + return ; +}); + +export default ActionDrawer; diff --git a/packages/client/src/action/Action.tsx b/packages/client/src/action/Action.tsx new file mode 100644 index 000000000..a04d80ecf --- /dev/null +++ b/packages/client/src/action/Action.tsx @@ -0,0 +1,34 @@ +import React, { useState } from 'react'; +import { Button, ButtonProps } from 'antd'; +import { observer, RecursionField, useField, useFieldSchema } from '@formily/react'; +import { useA } from './hooks'; +import { VisibleContext } from './context'; +import { ComposedAction } from './types'; +import { ActionDrawer } from './Action.Drawer'; + +export const Action: ComposedAction = observer((props) => { + const { useAction = useA, onClick, ...others } = props; + const [visible, setVisible] = useState(false); + const schema = useFieldSchema(); + const field = useField(); + const { run } = useAction(); + return ( + + + + + ); +}); + +Action.Drawer = ActionDrawer; + +export default Action; diff --git a/packages/client/src/action/context.tsx b/packages/client/src/action/context.tsx new file mode 100644 index 000000000..4d3d8bacd --- /dev/null +++ b/packages/client/src/action/context.tsx @@ -0,0 +1,3 @@ +import { createContext } from 'react'; + +export const VisibleContext = createContext(null); diff --git a/packages/client/src/action/demos/demo1.tsx b/packages/client/src/action/demos/demo1.tsx new file mode 100644 index 000000000..253835c01 --- /dev/null +++ b/packages/client/src/action/demos/demo1.tsx @@ -0,0 +1,66 @@ +import React from 'react'; +import { observer, ISchema, useForm } from '@formily/react'; +import { SchemaComponent, SchemaComponentProvider, Form, Action, useActionVisible } from '@nocobase/client'; +import { FormItem, Input } from '@formily/antd'; +import 'antd/dist/antd.css'; + +const useCloseAction = () => { + const { setVisible } = useActionVisible(); + const form = useForm(); + return { + async run() { + setVisible(false); + form.submit((values) => { + console.log(values); + }); + }, + }; +}; + +const schema: ISchema = { + type: 'object', + properties: { + action1: { + 'x-component': 'Action', + 'x-component-props': { + type: 'primary', + }, + type: 'void', + title: 'Open', + properties: { + drawer1: { + 'x-component': 'Action.Drawer', + type: 'void', + title: 'Drawer Title', + properties: { + hello1: { + 'x-content': 'Hello', + title: 'T1', + }, + footer1: { + 'x-component': 'Action.Drawer.Footer', + type: 'void', + properties: { + close1: { + title: 'Close', + 'x-component': 'Action', + 'x-component-props': { + useAction: '{{ useCloseAction }}', + }, + }, + }, + }, + }, + }, + }, + }, + }, +}; + +export default observer(() => { + return ( + + + + ); +}); diff --git a/packages/client/src/action/hooks.ts b/packages/client/src/action/hooks.ts new file mode 100644 index 000000000..4dc749972 --- /dev/null +++ b/packages/client/src/action/hooks.ts @@ -0,0 +1,27 @@ +import { useForm } from '@formily/react'; +import { useContext } from 'react'; +import { VisibleContext } from './context'; + +export const useA = () => { + return { + async run() {}, + }; +}; + +export const useActionVisible = () => { + const [visible, setVisible] = useContext(VisibleContext); + return { visible, setVisible }; +}; + +export const useCloseAction = () => { + const [, setVisible] = useContext(VisibleContext); + const form = useForm(); + return { + async run() { + setVisible(false); + form.submit((values) => { + console.log(values); + }); + }, + }; +}; diff --git a/packages/client/src/action/index.md b/packages/client/src/action/index.md new file mode 100644 index 000000000..449647801 --- /dev/null +++ b/packages/client/src/action/index.md @@ -0,0 +1,33 @@ +--- +nav: + path: /client +group: + title: Schema Components + path: /schema-components +--- + +# Action 待定 + +## Nodes + +已确定的节点: + +- Action +- Action.URL +- Action.Link +- Action.Drawer +- Action.Drawer.Footer +- Action.Modal +- Action.Modal.Footer +- Action.Popover + +不确定的节点: + +- Action.Group +- Action.Dropdown +- Action.Window +- ActionBar + +## Examples + + diff --git a/packages/client/src/action/index.tsx b/packages/client/src/action/index.tsx new file mode 100644 index 000000000..685a31103 --- /dev/null +++ b/packages/client/src/action/index.tsx @@ -0,0 +1,3 @@ +export * from './Action'; +export * from './context'; +export * from './hooks'; diff --git a/packages/client/src/action/types.ts b/packages/client/src/action/types.ts new file mode 100644 index 000000000..4c4121a58 --- /dev/null +++ b/packages/client/src/action/types.ts @@ -0,0 +1,16 @@ +import { ButtonProps, DrawerProps } from 'antd'; + +export type ActionProps = ButtonProps & { + useAction?: () => { + run(): Promise; + }; +}; + +export type ComposedAction = React.FC & { + Drawer?: ComposedActionDrawer; + [key: string]: any; +}; + +export type ComposedActionDrawer = React.FC & { + Footer?: React.FC; +}; diff --git a/packages/client/src/admin-layout/index.md b/packages/client/src/admin-layout/index.md new file mode 100644 index 000000000..b98d998ec --- /dev/null +++ b/packages/client/src/admin-layout/index.md @@ -0,0 +1,27 @@ +--- +nav: + path: /client +group: + title: Route Components + path: /route-components +--- + +# AdminLayout 待定 + +结构 + +- Layout +- Layout.Header + - SiteTitle + - Menu(SchemaComponent) + - PluginActionBar + - Designable.Action(引用) + - CollectionManager.Action(引用) + - ACL.Action(引用) + - SystemSettings.Action(引用) + - CurrentUser.Dropdown(引用) +- Layout.Sider + - SideMenu(随 Menu 联动的) +- Layout.Content + - PageTitle + - SchemaComponent diff --git a/packages/client/src/admin-layout/index.tsx b/packages/client/src/admin-layout/index.tsx new file mode 100644 index 000000000..ff2f94b2b --- /dev/null +++ b/packages/client/src/admin-layout/index.tsx @@ -0,0 +1,12 @@ +import React from 'react'; + +export function AdminLayout(props: any) { + + return ( +
+ +
+ ); +} + +export default AdminLayout; diff --git a/packages/client/src/antd-config-provider/index.md b/packages/client/src/antd-config-provider/index.md new file mode 100644 index 000000000..8ec194f78 --- /dev/null +++ b/packages/client/src/antd-config-provider/index.md @@ -0,0 +1,10 @@ +--- +nav: + path: /client +group: + path: /client +--- + +# AntdConfigProvider + +为 antd 组件提供统一的全局化配置 \ No newline at end of file diff --git a/packages/client/src/antd-config-provider/index.tsx b/packages/client/src/antd-config-provider/index.tsx new file mode 100644 index 000000000..4cb2df6cd --- /dev/null +++ b/packages/client/src/antd-config-provider/index.tsx @@ -0,0 +1,10 @@ +import React, { createContext } from 'react'; +import { I18nextProvider, useTranslation } from 'react-i18next'; +import { ConfigProvider, Spin } from 'antd'; +import enUS from 'antd/lib/locale/en_US'; +import zhCN from 'antd/lib/locale/zh_CN'; + +export function AntdConfigProvider(props) { + const { i18n } = useTranslation(); + return {props.children}; +} diff --git a/packages/client/src/api-client/APIClient.ts b/packages/client/src/api-client/APIClient.ts new file mode 100644 index 000000000..d3bd46fa7 --- /dev/null +++ b/packages/client/src/api-client/APIClient.ts @@ -0,0 +1,62 @@ +import axios, { Axios, AxiosInstance, AxiosResponse, AxiosRequestConfig } from 'axios'; + +export interface ActionParams { + [key: string]: any; +} + +type ResourceActionOptions

= { + resource?: string; + resourceOf?: any; + action?: string; + params?: P; +}; + +export interface IResource { + list?: (params?: ActionParams) => Promise; + get?: (params?: ActionParams) => Promise; + create?: (params?: ActionParams) => Promise; + update?: (params?: ActionParams) => Promise; + destroy?: (params?: ActionParams) => Promise; +} + +export class APIClient { + axios: AxiosInstance; + + constructor(instance?: AxiosInstance | AxiosRequestConfig) { + if (typeof instance === 'function') { + this.axios = instance; + } else { + this.axios = axios.create(instance); + } + } + + request, D = any>(config: AxiosRequestConfig | ResourceActionOptions): Promise { + const { resource, resourceOf, action, params } = config as any; + if (resource) { + return this.resource(resource, resourceOf)[action](params); + } + return this.axios.request(config); + } + + resource(name: string, of?: any): IResource { + const target = {}; + const handler = { + get: (_: any, actionName: string) => { + let url = name.split('.').join(`/${of || '_'}/`); + url += `:${actionName}`; + const config: AxiosRequestConfig = { url }; + if (['get', 'list'].includes(actionName)) { + config['method'] = 'get'; + } else { + config['method'] = 'post'; + } + return (params?: ActionParams) => { + config[config.method === 'get' ? 'params' : 'data'] = { __params__: params }; + console.log({ config }); + return this.request(config); + }; + }, + }; + return new Proxy(target, handler); + } +} diff --git a/packages/client/src/api-client/APIClientProvider.tsx b/packages/client/src/api-client/APIClientProvider.tsx new file mode 100644 index 000000000..29bd5c465 --- /dev/null +++ b/packages/client/src/api-client/APIClientProvider.tsx @@ -0,0 +1,12 @@ +import React from 'react'; +import { APIClient } from './APIClient'; +import { APIClientContext } from './context'; + +export interface APIClientProviderProps { + apiClient: APIClient; +} + +export const APIClientProvider: React.FC = (props) => { + const { apiClient, children } = props; + return {children}; +}; diff --git a/packages/client/src/api-client/__tests__/APIClient.test.tsx b/packages/client/src/api-client/__tests__/APIClient.test.tsx new file mode 100644 index 000000000..d9c912622 --- /dev/null +++ b/packages/client/src/api-client/__tests__/APIClient.test.tsx @@ -0,0 +1,26 @@ +import axios from 'axios'; +import { APIClient } from '../APIClient'; + +describe('APIClient', () => { + describe('axios', () => { + it('case 1', () => { + const apiClient = new APIClient(); + expect(apiClient.axios).toBeDefined(); + expect(typeof apiClient.axios).toBe('function'); + expect(typeof apiClient.axios.request).toBe('function'); + }); + + it('case 2', () => { + const apiClient = new APIClient({ + baseURL: 'http://localhost/api/', + }); + expect(apiClient.axios.defaults.baseURL).toBe('http://localhost/api/'); + }); + + it('case 3', () => { + const instance = axios.create(); + const apiClient = new APIClient(instance); + expect(apiClient.axios).toBe(instance); + }); + }) +}); diff --git a/packages/client/src/api-client/context.ts b/packages/client/src/api-client/context.ts new file mode 100644 index 000000000..71b104c49 --- /dev/null +++ b/packages/client/src/api-client/context.ts @@ -0,0 +1,4 @@ +import { createContext } from 'react'; +import { APIClient } from './APIClient'; + +export const APIClientContext = createContext(new APIClient()); diff --git a/packages/client/src/api-client/demos/demo1.tsx b/packages/client/src/api-client/demos/demo1.tsx new file mode 100644 index 000000000..09a09cd5f --- /dev/null +++ b/packages/client/src/api-client/demos/demo1.tsx @@ -0,0 +1,24 @@ +import React from 'react'; +import MockAdapter from 'axios-mock-adapter'; +import { APIClient, APIClientProvider, useRequest, compose } from '@nocobase/client'; + +const apiClient = new APIClient(); + +const mock = new MockAdapter(apiClient.axios); + +mock.onGet('/users:get').reply(200, { + data: { id: 1, name: 'John Smith' }, +}); + +const providers = [ + [APIClientProvider, { apiClient }] +]; + +export default compose(...providers)(() => { + const { data } = useRequest({ + resource: 'users', + action: 'get', + params: {}, + }); + return

{data?.name}
; +}); diff --git a/packages/client/src/api-client/hooks/index.ts b/packages/client/src/api-client/hooks/index.ts new file mode 100644 index 000000000..078c89886 --- /dev/null +++ b/packages/client/src/api-client/hooks/index.ts @@ -0,0 +1,3 @@ +export * from './useAPIClient'; +export * from './useRequest'; +export * from './useResource'; diff --git a/packages/client/src/api-client/hooks/useAPIClient.ts b/packages/client/src/api-client/hooks/useAPIClient.ts new file mode 100644 index 000000000..d0566beb8 --- /dev/null +++ b/packages/client/src/api-client/hooks/useAPIClient.ts @@ -0,0 +1,6 @@ +import { useContext } from 'react'; +import { APIClientContext } from '../context'; + +export function useAPIClient() { + return useContext(APIClientContext); +} diff --git a/packages/client/src/api-client/hooks/useRequest.ts b/packages/client/src/api-client/hooks/useRequest.ts new file mode 100644 index 000000000..d67bced78 --- /dev/null +++ b/packages/client/src/api-client/hooks/useRequest.ts @@ -0,0 +1,36 @@ +import { useContext } from 'react'; +import { AxiosRequestConfig } from 'axios'; +import { Options } from 'ahooks/lib/useRequest/src/types'; +import { default as useReq } from 'ahooks/lib/useRequest'; +import { APIClientContext } from '../context'; + +type FunctionService = (...args: any[]) => Promise; + +type ResourceActionOptions

= { + resource?: string; + resourceOf?: any; + action?: string; + params?: P; +}; + +export function useRequest

( + service: AxiosRequestConfig

| ResourceActionOptions

| FunctionService, + options?: Options, +) { + const api = useContext(APIClientContext); + if (typeof service === 'function') { + return useReq(service, options); + } + return useReq(async () => { + const { url, resource, resourceOf, action, params } = service as any; + if (url) { + const response = await api.request(service); + return response?.data; + } + if (resource) { + const response = await api.resource(resource, resourceOf)[action](params); + return response?.data?.data; + } + return; + }, options); +} diff --git a/packages/client/src/api-client/hooks/useResource.ts b/packages/client/src/api-client/hooks/useResource.ts new file mode 100644 index 000000000..46ee4636e --- /dev/null +++ b/packages/client/src/api-client/hooks/useResource.ts @@ -0,0 +1,7 @@ +import { useContext } from 'react'; +import { APIClientContext } from '../context'; + +export function useResource(name: string, of?: string | number) { + const apiClient = useContext(APIClientContext); + return apiClient.resource(name, of); +} diff --git a/packages/client/src/api-client/index.md b/packages/client/src/api-client/index.md new file mode 100644 index 000000000..0a511795f --- /dev/null +++ b/packages/client/src/api-client/index.md @@ -0,0 +1,139 @@ +--- +nav: + path: /client +group: + path: /client +--- + +# APIClient + +## APIClient + +```ts +class APIClient { + // axios 实例 + axios: AxiosInstance; + // 构造器 + constructor(instance?: AxiosInstance | AxiosRequestConfig); + // 客户端请求,支持 AxiosRequestConfig 和 ResourceActionOptions + request, D = any>(config: AxiosRequestConfig | ResourceActionOptions): Promise; + // 获取资源 + resource(name: string, of?: any): R; +} +``` + +示例 + +```ts +import axios from 'axios'; + +// 不传参时,内部直接创建 axios 实例 +const apiClient = new APIClient(); + +// 提供 AxiosRequestConfig 配置参数 +const apiClient = new APIClient({ + baseURL: '', +}); + +// 提供 AxiosInstance +const instance = axios.create({ + baseURL: '', +}); +const apiClient = new APIClient(instance); +``` + +## APIClientProvider + +提供 APIClient 实例的上下文。 + +```tsx | pure +const apiClient = new APIClient(); + + +``` + +## useAPIClient + +获取当前上下文的 APIClient 实例。 + +```ts +const apiClient = useAPIClient(); +``` + +## useRequest + +```ts +function useRequest

( + service: AxiosRequestConfig

| ResourceActionOptions

| FunctionService, + options?: Options, +); +``` + +支持 `axios.request(config)`,config 详情查看 [axios](https://github.com/axios/axios#request-config) + +```ts +const { data, loading, refresh } = useRequest({ url: '/users' }); +``` + +或者是 NocoBase 的 resource & action 请求: + +```ts +const { data } = useRequest({ + resource: 'users', + action: 'get', + params: {}, +}); +``` + +例子如下: + + + +也可以是自定义的异步函数: + +```ts +const { data, loading, refresh } = useRequest(() => Promise.resolve({})); +``` + +更多用法查看 ahooks 的 [useRequest()](https://ahooks.js.org/hooks/use-request/index) + +## useResource + +```ts +function useResource(name: string, of?: string | number): IResource; +``` + +资源是 NocoBase 的核心概念,包括: + +- 独立资源,如 `posts` +- 关系资源,如 `posts.tags` `posts.user` `posts.comments` + +资源 URI + +```bash +# 独立资源,文章 +/api/posts +# 关系资源,文章 ID=1 的评论 +/api/posts/1/comments +``` + +通过 APIClient 获取资源 + +```ts +const api = new APIClient(); + +api.resource('posts'); +api.resource('posts.comments', 1); +``` + +useResource 用法: + +```ts +const resource = useResource('posts'); +const resource = useResource('posts.comments', 1); +``` + +resource 的实际场景用例参见: + +- [useCollection()](collection-manager#usecollection) +- [useCollectionField()](collection-manager#usecollectionfield) diff --git a/packages/client/src/api-client/index.tsx b/packages/client/src/api-client/index.tsx new file mode 100644 index 000000000..f00e1fdad --- /dev/null +++ b/packages/client/src/api-client/index.tsx @@ -0,0 +1,3 @@ +export * from './hooks'; +export * from './APIClient'; +export * from './APIClientProvider'; diff --git a/packages/client/src/application/__tests__/__snapshots__/compose.test.tsx.snap b/packages/client/src/application/__tests__/__snapshots__/compose.test.tsx.snap new file mode 100644 index 000000000..fc780b082 --- /dev/null +++ b/packages/client/src/application/__tests__/__snapshots__/compose.test.tsx.snap @@ -0,0 +1,77 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`compose case 1 1`] = ` +

+
+

+ A +

+
+
+`; + +exports[`compose case 2 1`] = ` +
+
+

+ A +

+
+

+ B +

+
+
+
+`; + +exports[`compose case 3 1`] = ` +
+
+

+ A +

+
+
+`; + +exports[`compose case 4 1`] = ` +
+
+

+ A +

+
+

+ B +

+
+

+ C +

+
+
+
+
+`; + +exports[`compose case 5 1`] = ` +
+
+

+ A +

+
+

+ B + 1 +

+
+

+ C +

+
+
+
+
+`; diff --git a/packages/client/src/application/__tests__/compose.test.tsx b/packages/client/src/application/__tests__/compose.test.tsx new file mode 100644 index 000000000..fc91b801d --- /dev/null +++ b/packages/client/src/application/__tests__/compose.test.tsx @@ -0,0 +1,95 @@ +import React from 'react'; +import { render } from '@testing-library/react'; +import { compose } from '../'; + +describe('compose', () => { + it('case 1', () => { + const A: React.FC = (props) => ( +
+

A

+ {props.children} +
+ ); + const App = compose(A)(); + const { container } = render(); + expect(container).toMatchSnapshot(); + }); + + it('case 2', () => { + const A: React.FC = (props) => ( +
+

A

+ {props.children} +
+ ); + const B: React.FC = (props) => ( +
+

B

+ {props.children} +
+ ); + const App = compose(A)(B); + const { container } = render(); + expect(container).toMatchSnapshot(); + }); + + it('case 3', () => { + const A: React.FC = (props) => ( +
+

A

+ {props.children} +
+ ); + const App = compose([A])(); + const { container } = render(); + expect(container).toMatchSnapshot(); + }); + + it('case 4', () => { + const A: React.FC = (props) => ( +
+

A

+ {props.children} +
+ ); + const B: React.FC = (props) => ( +
+

B

+ {props.children} +
+ ); + const C: React.FC = (props) => ( +
+

C

+ {props.children} +
+ ); + const App = compose(A, B)(C); + const { container } = render(); + expect(container).toMatchSnapshot(); + }); + + it('case 5', () => { + const A: React.FC = (props) => ( +
+

A {props.name}

+ {props.children} +
+ ); + const B: React.FC = (props) => ( +
+

B {props.name}

+ {props.children} +
+ ); + const C: React.FC = (props) => ( +
+

C

+ {props.children} +
+ ); + const App = compose(A, [B, { name: '1' }])(C); + const { container } = render(); + expect(container).toMatchSnapshot(); + }); +}); diff --git a/packages/client/src/application/compose.tsx b/packages/client/src/application/compose.tsx new file mode 100644 index 000000000..db5aa3651 --- /dev/null +++ b/packages/client/src/application/compose.tsx @@ -0,0 +1,18 @@ +import React from 'react'; + +const Blank = ({ children }) => children || null; + +export const compose = (...components: any[]) => { + const Root = [...components, Blank].reduce((parent, child) => { + const [Parent, parentProps] = Array.isArray(parent) ? parent : [parent]; + const [Child, childProps] = Array.isArray(child) ? child : [child]; + return ({ children }) => ( + + {children} + + ); + }); + return (LastChild?: any) => (props?: any) => { + return {LastChild && }; + }; +}; diff --git a/packages/client/src/application/demos/Hello.tsx b/packages/client/src/application/demos/Hello.tsx new file mode 100644 index 000000000..fe6340ecb --- /dev/null +++ b/packages/client/src/application/demos/Hello.tsx @@ -0,0 +1,20 @@ +import React from 'react'; +import { useDesignable } from '@nocobase/client'; +import { Button } from 'antd'; +import { observer } from '@formily/react'; + +export const Hello: React.FC = observer(({ name }) => { + const { patch, remove } = useDesignable(); + return ( +
+

Hello {name}!

+ +
+ ); +}); diff --git a/packages/client/src/application/demos/RouteSchemaComponent.tsx b/packages/client/src/application/demos/RouteSchemaComponent.tsx new file mode 100644 index 000000000..4b7c7e6ac --- /dev/null +++ b/packages/client/src/application/demos/RouteSchemaComponent.tsx @@ -0,0 +1,7 @@ +import React from 'react'; +import { SchemaComponent, useRoute } from '@nocobase/client'; + +export const RouteSchemaComponent = () => { + const route = useRoute(); + return ; +}; diff --git a/packages/client/src/application/demos/demo1.tsx b/packages/client/src/application/demos/demo1.tsx new file mode 100644 index 000000000..96b32685f --- /dev/null +++ b/packages/client/src/application/demos/demo1.tsx @@ -0,0 +1,23 @@ +import React from 'react'; +import { Link, MemoryRouter } from 'react-router-dom'; +import { RouteSwitchProvider, RouteSwitch, SchemaComponentProvider, compose } from '@nocobase/client'; +import { Hello } from './Hello'; +import { RouteSchemaComponent } from './RouteSchemaComponent'; +import routes from './routes'; + +const providers = [ + [MemoryRouter, { initialEntries: ['/'] }], + [SchemaComponentProvider, { components: { Hello } }], + [RouteSwitchProvider, { components: { RouteSchemaComponent } }], +]; + +const App = compose(...providers)(() => { + return ( +
+ Home,About + +
+ ); +}); + +export default App; diff --git a/packages/client/src/application/demos/routes.ts b/packages/client/src/application/demos/routes.ts new file mode 100644 index 000000000..ebd757075 --- /dev/null +++ b/packages/client/src/application/demos/routes.ts @@ -0,0 +1,29 @@ +import { RouteRedirectProps } from '@nocobase/client'; + +export default [ + { + type: 'route', + path: '/', + exact: true, + component: 'RouteSchemaComponent', + schema: { + name: 'home', + 'x-component': 'Hello', + 'x-component-props': { + name: 'Home', + }, + }, + }, + { + type: 'route', + path: '/about', + component: 'RouteSchemaComponent', + schema: { + name: 'home', + 'x-component': 'Hello', + 'x-component-props': { + name: 'About', + }, + }, + }, +] as Array; diff --git a/packages/client/src/application/index.md b/packages/client/src/application/index.md new file mode 100644 index 000000000..c44a0818a --- /dev/null +++ b/packages/client/src/application/index.md @@ -0,0 +1,14 @@ +--- +nav: + path: /client +group: + path: /client +--- + +# Application 待定 + + + +## compose + + \ No newline at end of file diff --git a/packages/client/src/application/index.tsx b/packages/client/src/application/index.tsx new file mode 100644 index 000000000..ce4e4b8a5 --- /dev/null +++ b/packages/client/src/application/index.tsx @@ -0,0 +1 @@ +export * from './compose'; diff --git a/packages/client/src/auth-layout/index.md b/packages/client/src/auth-layout/index.md new file mode 100644 index 000000000..88363138b --- /dev/null +++ b/packages/client/src/auth-layout/index.md @@ -0,0 +1,9 @@ +--- +nav: + path: /client +group: + path: /route-components +--- + +# AuthLayout + diff --git a/packages/client/src/auth-layout/index.tsx b/packages/client/src/auth-layout/index.tsx new file mode 100644 index 000000000..ce3a24797 --- /dev/null +++ b/packages/client/src/auth-layout/index.tsx @@ -0,0 +1,10 @@ +import React from 'react'; + +export function AuthLayout(props: any) { + return ( +
+

NocoBase

+ {props.children} +
+ ); +} diff --git a/packages/client/src/block-item/demos/demo1.tsx b/packages/client/src/block-item/demos/demo1.tsx new file mode 100644 index 000000000..f462d1525 --- /dev/null +++ b/packages/client/src/block-item/demos/demo1.tsx @@ -0,0 +1,86 @@ +import React from 'react'; +import { uid } from '@formily/shared'; +import { observer, useField, useFieldSchema } from '@formily/react'; +import { useDraggable, useDroppable } from '@dnd-kit/core'; +import { SchemaComponent, SchemaComponentProvider, BlockItem, DndContext } from '@nocobase/client'; + +function Draggable(props) { + const { attributes, listeners, setNodeRef, transform } = useDraggable({ + id: props.id, + data: props.data, + }); + const style = transform + ? { + transform: `translate3d(${transform.x}px, ${transform.y}px, 0)`, + } + : undefined; + + return ( + + ); +} + +function Droppable(props) { + const { isOver, setNodeRef } = useDroppable({ + id: props.id, + data: props.data, + }); + const style = { + color: isOver ? 'green' : undefined, + }; + + return ( +
+ {props.children} +
+ ); +} + +const Block = observer((props) => { + const fieldSchema = useFieldSchema(); + const field = useField(); + return ( + +
+ Block {fieldSchema.name} + + Drag + +
+
+ ); +}); + +export default function App() { + return ( + + + + ); +} diff --git a/packages/client/src/block-item/index.md b/packages/client/src/block-item/index.md new file mode 100644 index 000000000..3a038aac6 --- /dev/null +++ b/packages/client/src/block-item/index.md @@ -0,0 +1,12 @@ +--- +nav: + path: /client +group: + path: /schema-components +--- + +# BlockItem 待定 + +普通的装饰器(Decorator)组件,无特殊 UI 效果,一般用在 x-decorator 中。用于提供区块的管理,如拖拽功能、当前节点的 SettingsForm。CardItem 和 FormItem 组件都是基于 BlockItem 实现,也具备以上相同功能。 + + diff --git a/packages/client/src/block-item/index.tsx b/packages/client/src/block-item/index.tsx new file mode 100644 index 000000000..d34fa5037 --- /dev/null +++ b/packages/client/src/block-item/index.tsx @@ -0,0 +1,12 @@ +import React from 'react'; +import { useDesignable } from '../schema-component'; + +export const BlockItem: React.FC = (props) => { + const { DesignableBar } = useDesignable(); + return ( +
+ {props.children} + +
+ ); +}; diff --git a/packages/client/src/calendar/index.md b/packages/client/src/calendar/index.md new file mode 100644 index 000000000..c77d221b9 --- /dev/null +++ b/packages/client/src/calendar/index.md @@ -0,0 +1,8 @@ +--- +nav: + path: /client +group: + path: /schema-components +--- + +# Calendar 待定 diff --git a/packages/client/src/card-item/index.md b/packages/client/src/card-item/index.md new file mode 100644 index 000000000..f39d74065 --- /dev/null +++ b/packages/client/src/card-item/index.md @@ -0,0 +1,10 @@ +--- +nav: + path: /client +group: + path: /schema-components +--- + +# CardItem + +卡片装饰器。除此之外,也继承了 BlockItem 的功能。 \ No newline at end of file diff --git a/packages/client/src/card-item/index.tsx b/packages/client/src/card-item/index.tsx new file mode 100644 index 000000000..ae00a8a51 --- /dev/null +++ b/packages/client/src/card-item/index.tsx @@ -0,0 +1,13 @@ +import React from 'react'; +import { Card } from 'antd'; +import { BlockItem } from '../block-item'; + +export const CardItem: React.FC = (props) => { + return ( + + + {props.children} + + + ); +}; diff --git a/packages/client/src/cascader/index.md b/packages/client/src/cascader/index.md new file mode 100644 index 000000000..f0c79efbd --- /dev/null +++ b/packages/client/src/cascader/index.md @@ -0,0 +1,8 @@ +--- +nav: + path: /client +group: + path: /schema-components +--- + +# Cascader diff --git a/packages/client/src/chart/index.md b/packages/client/src/chart/index.md new file mode 100644 index 000000000..561232252 --- /dev/null +++ b/packages/client/src/chart/index.md @@ -0,0 +1,8 @@ +--- +nav: + path: /client +group: + path: /schema-components +--- + +# Chart 待定 diff --git a/packages/client/src/checkbox/index.md b/packages/client/src/checkbox/index.md new file mode 100644 index 000000000..ac53a9e0b --- /dev/null +++ b/packages/client/src/checkbox/index.md @@ -0,0 +1,8 @@ +--- +nav: + path: /client +group: + path: /schema-components +--- + +# Checkbox diff --git a/packages/client/src/collection-manager/CollectionField.tsx b/packages/client/src/collection-manager/CollectionField.tsx new file mode 100644 index 000000000..a3361e53e --- /dev/null +++ b/packages/client/src/collection-manager/CollectionField.tsx @@ -0,0 +1,42 @@ +import React, { useContext, useEffect } from 'react'; +import { connect, SchemaOptionsContext, useField, useFieldSchema, useForm } from '@formily/react'; +import { useCollectionField } from './hooks'; +import { CollectionFieldProvider } from './CollectionFieldProvider'; +import { Field, FormPath } from '@formily/core'; + +// TODO: 初步适配 +const InternalField: React.FC = (props) => { + const field = useField(); + const fieldSchema = useFieldSchema(); + const { uiSchema } = useCollectionField(); + const options = useContext(SchemaOptionsContext); + const component = FormPath.getIn(options?.components, uiSchema['x-component']); + const setFieldProps = (key, value) => { + field[key] = typeof field[key] === 'undefined' ? value : field[key]; + }; + const setRequired = () => { + if (typeof fieldSchema['required'] === 'undefined') { + field.required = !!uiSchema['required']; + } + }; + // TODO: 初步适配 + useEffect(() => { + setFieldProps('title', uiSchema.title); + setFieldProps('description', uiSchema.description); + setFieldProps('initialValue', uiSchema.default); + setRequired(); + field.component = [component, uiSchema['x-component-props']]; + }, [uiSchema.title, uiSchema.description, uiSchema.required]); + return React.createElement(component, props); +}; + +export const CollectionField = connect((props) => { + const fieldSchema = useFieldSchema(); + return ( + + + + ); +}); + +export default CollectionField; diff --git a/packages/client/src/collection-manager/CollectionFieldProvider.tsx b/packages/client/src/collection-manager/CollectionFieldProvider.tsx new file mode 100644 index 000000000..441b5ef4b --- /dev/null +++ b/packages/client/src/collection-manager/CollectionFieldProvider.tsx @@ -0,0 +1,16 @@ +import React from 'react'; +import { merge } from '@formily/shared'; +import { useCollection } from './hooks'; +import { CollectionFieldOptions } from './types'; +import { CollectionFieldContext } from './context'; +import { SchemaKey } from '@formily/react'; + +export const CollectionFieldProvider: React.FC<{ name?: SchemaKey; field?: CollectionFieldOptions }> = (props) => { + const { name, field, children } = props; + const { getField } = useCollection(); + return ( + + {children} + + ); +}; diff --git a/packages/client/src/collection-manager/CollectionManagerProvider.tsx b/packages/client/src/collection-manager/CollectionManagerProvider.tsx new file mode 100644 index 000000000..78af714d5 --- /dev/null +++ b/packages/client/src/collection-manager/CollectionManagerProvider.tsx @@ -0,0 +1,12 @@ +import React from 'react'; +import { CollectionManagerOptions } from './types'; +import { CollectionManagerContext } from './context'; + +export const CollectionManagerProvider: React.FC = (props) => { + const { interfaces, collections } = props; + return ( + + {props.children} + + ); +}; diff --git a/packages/client/src/collection-manager/CollectionProvider.tsx b/packages/client/src/collection-manager/CollectionProvider.tsx new file mode 100644 index 000000000..4e0077688 --- /dev/null +++ b/packages/client/src/collection-manager/CollectionProvider.tsx @@ -0,0 +1,14 @@ +import React from 'react'; +import { useCollectionManager } from './hooks'; +import { CollectionOptions } from './types'; +import { CollectionContext } from './context'; + +export const CollectionProvider: React.FC<{ name?: string; collection: CollectionOptions }> = (props) => { + const { name, collection, children } = props; + const { get } = useCollectionManager(); + return ( + + {children} + + ); +}; diff --git a/packages/client/src/collection-manager/context.ts b/packages/client/src/collection-manager/context.ts new file mode 100644 index 000000000..581428314 --- /dev/null +++ b/packages/client/src/collection-manager/context.ts @@ -0,0 +1,11 @@ +import { createContext } from 'react'; +import { CollectionFieldOptions, CollectionManagerOptions, CollectionOptions } from './types'; + +export const CollectionManagerContext = createContext({ + collections: [], + interfaces: {}, +}); + +export const CollectionContext = createContext({}); + +export const CollectionFieldContext = createContext({}); diff --git a/packages/client/src/collection-manager/demos/demo2.tsx b/packages/client/src/collection-manager/demos/demo2.tsx new file mode 100644 index 000000000..1b9c3992b --- /dev/null +++ b/packages/client/src/collection-manager/demos/demo2.tsx @@ -0,0 +1,124 @@ +import React from 'react'; +import { observer, ISchema, useForm } from '@formily/react'; +import { + SchemaComponent, + SchemaComponentProvider, + Form, + Action, + CollectionProvider, + CollectionField, +} from '@nocobase/client'; +import 'antd/dist/antd.css'; +import { FormItem, Input } from '@formily/antd'; + +export default observer(() => { + const collection = { + name: 'tests', + fields: [ + { + type: 'string', + name: 'title1', + interface: 'input', + uiSchema: { + title: 'Title1', + type: 'string', + 'x-component': 'Input', + required: true, + description: 'description1', + } as ISchema, + }, + { + type: 'string', + name: 'title2', + interface: 'input', + uiSchema: { + title: 'Title2', + type: 'string', + 'x-component': 'Input', + description: 'description', + default: 'ttt', + }, + }, + { + type: 'string', + name: 'title3', + }, + ], + }; + + const schema: ISchema = { + type: 'object', + properties: { + form1: { + type: 'void', + 'x-component': 'Form', + properties: { + // 字段 title1 直接使用全局提供的 uiSchema + title1: { + 'x-component': 'CollectionField', + 'x-decorator': 'FormItem', + default: '111', + }, + // 等同于 + // title1: { + // type: 'string', + // title: 'Title', + // required: true, + // 'x-component': 'Input', + // 'x-decorator': 'FormItem', + // }, + title2: { + 'x-component': 'CollectionField', + 'x-decorator': 'FormItem', + title: 'Title4', // 覆盖全局已定义的 Title2 + required: true, // 扩展的配置参数 + description: 'description4', + }, + // 等同于 + // title2: { + // type: 'string', + // title: 'Title22', + // required: true, + // 'x-component': 'Input', + // 'x-decorator': 'FormItem', + // }, + // 字段 title3 没有提供 uiSchema,自行处理 + title3: { + 'x-component': 'Input', + 'x-decorator': 'FormItem', + title: 'Title3', + required: true, + }, + action1: { + // type: 'void', + 'x-component': 'Action', + title: 'Submit', + 'x-component-props': { + type: 'primary', + useAction: '{{ useSubmit }}', + }, + }, + }, + }, + }, + }; + + const useSubmit = () => { + const form = useForm(); + return { + async run() { + form.submit(() => { + console.log(form.values); + }); + }, + }; + }; + + return ( + + + + + + ); +}); diff --git a/packages/client/src/collection-manager/demos/demo3.tsx b/packages/client/src/collection-manager/demos/demo3.tsx new file mode 100644 index 000000000..c1f99ac51 --- /dev/null +++ b/packages/client/src/collection-manager/demos/demo3.tsx @@ -0,0 +1,67 @@ +import React, { useEffect, useState } from 'react'; +import { + APIClient, + APIClientProvider, + CollectionFieldProvider, + CollectionProvider, + compose, + RecordProvider, + useCollectionField, +} from '@nocobase/client'; +import MockAdapter from 'axios-mock-adapter'; + +const apiClient = new APIClient(); + +const mock = new MockAdapter(apiClient.axios); + +mock.onGet('/posts/1/tags:list').reply(200, { + data: [ + { id: 1, name: 'Tag 1' }, + { id: 2, name: 'Tag 2' }, + ], +}); + +const collection = { + name: 'posts', + fields: [ + { + type: 'belongsToMany', + name: 'tags', + targetKey: 'id', + sourceKey: 'id', + foreignKey: 'postId', + otherKey: 'tagId', + }, + ], +}; + +const record = { id: 1 }; + +const providers = [ + // API 客户端 + [APIClientProvider, { apiClient }], + // 提供当前数据表行记录的上下文 + [RecordProvider, { record }], + // 提供数据表配置的上下文 + [CollectionProvider, { collection }], + // 提供字段配置上的下文 + [CollectionFieldProvider, { name: 'tags' }], +]; + +export default compose(...providers)(() => { + const { resource } = useCollectionField(); + const [items, setItems] = useState([]); + useEffect(() => { + // 请求地址为 /posts/1/tags:list + resource.list().then((response) => { + setItems(response?.data?.data); + }); + }, []); + return ( +
+ {items?.map((item, key) => ( +
{item.name}
+ ))} +
+ ); +}); diff --git a/packages/client/src/collection-manager/hooks/index.ts b/packages/client/src/collection-manager/hooks/index.ts new file mode 100644 index 000000000..4317f65d2 --- /dev/null +++ b/packages/client/src/collection-manager/hooks/index.ts @@ -0,0 +1,3 @@ +export * from './useCollection'; +export * from './useCollectionField'; +export * from './useCollectionManager'; diff --git a/packages/client/src/collection-manager/hooks/useCollection.ts b/packages/client/src/collection-manager/hooks/useCollection.ts new file mode 100644 index 000000000..20a18c3ab --- /dev/null +++ b/packages/client/src/collection-manager/hooks/useCollection.ts @@ -0,0 +1,18 @@ +import { useContext } from 'react'; +import { SchemaKey } from '@formily/react'; +import { CollectionFieldOptions } from '../types'; +import { CollectionContext } from '../context'; +import { useAPIClient } from '../../api-client'; + +export const useCollection = () => { + const collection = useContext(CollectionContext); + const api = useAPIClient(); + const resource = api?.resource(collection.name); + return { + ...collection, + resource, + getField(name: SchemaKey): CollectionFieldOptions { + return collection?.fields?.find((field) => field.name === name); + }, + }; +}; diff --git a/packages/client/src/collection-manager/hooks/useCollectionField.ts b/packages/client/src/collection-manager/hooks/useCollectionField.ts new file mode 100644 index 000000000..c2fda1e47 --- /dev/null +++ b/packages/client/src/collection-manager/hooks/useCollectionField.ts @@ -0,0 +1,17 @@ +import { useContext } from 'react'; +import { CollectionFieldContext } from '../context'; +import { useRecord } from '../../record-provider'; +import { useCollection } from './useCollection'; +import { useAPIClient } from '../../api-client'; + +export const useCollectionField = () => { + const collection = useCollection(); + const record = useRecord(); + const api = useAPIClient(); + const ctx = useContext(CollectionFieldContext); + const resource = api?.resource(`${collection?.name || ctx?.collectinName}.${ctx.name}`, record[ctx.sourceKey]); + return { + ...ctx, + resource, + }; +}; diff --git a/packages/client/src/collection-manager/hooks/useCollectionManager.ts b/packages/client/src/collection-manager/hooks/useCollectionManager.ts new file mode 100644 index 000000000..3a6216992 --- /dev/null +++ b/packages/client/src/collection-manager/hooks/useCollectionManager.ts @@ -0,0 +1,11 @@ +import { useContext } from 'react'; +import { CollectionManagerContext } from '../context'; + +export const useCollectionManager = () => { + const { collections } = useContext(CollectionManagerContext); + return { + get(name: string) { + return collections?.find((collection) => collection.name === name); + }, + }; +}; diff --git a/packages/client/src/collection-manager/index.md b/packages/client/src/collection-manager/index.md new file mode 100644 index 000000000..ad827d03d --- /dev/null +++ b/packages/client/src/collection-manager/index.md @@ -0,0 +1,144 @@ +--- +nav: + path: /client +group: + path: /client +--- + +# CollectionManager + +## Components + +### CollectionManagerProvider + +```jsx | pure + +``` + +### CollectionProvider + +```jsx | pure +const collection = { + name: 'tests', + fields: [ + { + type: 'string', + name: 'title', + interface: 'input', + uiSchema: { + type: 'string', + 'x-component': 'Input' + }, + }, + ], +}; + +``` + +如果没有传 collection 参数,从 CollectionManagerProvider 里取对应 name 的 collection。 + +```jsx | pure +const collections = [ + { + name: 'tests', + fields: [ + { + type: 'string', + name: 'title', + interface: 'input', + uiSchema: { + type: 'string', + 'x-component': 'Input' + }, + }, + ], + } +]; + + + +``` + +### CollectionFieldProvider + +```jsx | pure +const field = { + type: 'string', + name: 'title', + interface: 'input', + uiSchema: { + type: 'string', + 'x-component': 'Input' + }, +}; + +``` + +如果没有传 field 参数,从 CollectionProvider 里取对应 name 的 field。 + +```jsx | pure +const collection = { + name: 'tests', + fields: [ + { + type: 'string', + name: 'title', + interface: 'input', + uiSchema: { + type: 'string', + 'x-component': 'Input' + }, + }, + ], +}; + + + +``` + +### CollectionField + +万能字段组件,需要与 `` 搭配使用,仅限于在 Schema 场景使用。从 CollectionProvider 里取对应 name 的 field schema。可通过 CollectionField 所在的 schema 扩展配置。 + +```ts +{ + name: 'title', + 'x-decorator': 'FormItem', + 'x-decorator-props': {}, + 'x-component': 'CollectionField', + 'x-component-props': {}, + properties: {}, +} +``` + + + +## Hooks + +### useCollectionManager() + +与 `` 搭配使用 + +```jsx | pure +const { collections, get } = useCollectionManager(); +``` + +### useCollection() + +与 `` 搭配使用 + +```jsx | pure +const { name, fields, getField, findField, resource } = useCollection(); +``` + +### useCollectionField() + +与 `` 搭配使用 + +```jsx | pure +const { name, uiSchema, resource } = useCollectionField(); +``` + +resource 需要与 `` 搭配使用,用于提供当前数据表行记录的上下文。如: + + diff --git a/packages/client/src/collection-manager/index.tsx b/packages/client/src/collection-manager/index.tsx new file mode 100644 index 000000000..9e8059b38 --- /dev/null +++ b/packages/client/src/collection-manager/index.tsx @@ -0,0 +1,7 @@ +export * from './CollectionFieldProvider'; +export * from './CollectionManagerProvider'; +export * from './CollectionProvider'; +export * from './context'; +export * from './hooks'; +export * from './types'; +export * from './CollectionField'; diff --git a/packages/client/src/collection-manager/interfaces/index.ts b/packages/client/src/collection-manager/interfaces/index.ts new file mode 100644 index 000000000..e69de29bb diff --git a/packages/client/src/collection-manager/types.ts b/packages/client/src/collection-manager/types.ts new file mode 100644 index 000000000..b4f25a2d4 --- /dev/null +++ b/packages/client/src/collection-manager/types.ts @@ -0,0 +1,23 @@ +import { ISchema } from '@formily/react'; + +export interface CollectionManagerOptions { + interfaces?: any; + collections?: any[]; +} + +export interface CollectionOptions { + name?: string; + fields?: any[]; +} + +export interface ICollectionProviderProps { + name?: string; + fields?: any; +} + +export interface CollectionFieldOptions { + name?: any; + collectinName?: string; + sourceKey?: string; // association field + uiSchema?: ISchema; +} diff --git a/packages/client/src/color-select/index.md b/packages/client/src/color-select/index.md new file mode 100644 index 000000000..a5d60247f --- /dev/null +++ b/packages/client/src/color-select/index.md @@ -0,0 +1,8 @@ +--- +nav: + path: /client +group: + path: /schema-components +--- + +# ColorSelect diff --git a/packages/client/src/current-user/index.md b/packages/client/src/current-user/index.md new file mode 100644 index 000000000..b5cc5a50c --- /dev/null +++ b/packages/client/src/current-user/index.md @@ -0,0 +1,9 @@ +--- +nav: + path: /client +group: + title: Client + path: /client +--- + +# CurrentUser 待定 diff --git a/packages/client/src/current-user/index.tsx b/packages/client/src/current-user/index.tsx new file mode 100644 index 000000000..6ceeda644 --- /dev/null +++ b/packages/client/src/current-user/index.tsx @@ -0,0 +1,3 @@ +export function CurrentUser() { + +} diff --git a/packages/client/src/date-picker/index.md b/packages/client/src/date-picker/index.md new file mode 100644 index 000000000..79d312068 --- /dev/null +++ b/packages/client/src/date-picker/index.md @@ -0,0 +1,8 @@ +--- +nav: + path: /client +group: + path: /schema-components +--- + +# DatePicker diff --git a/packages/client/src/dnd-context/index.md b/packages/client/src/dnd-context/index.md new file mode 100644 index 000000000..1b0e02996 --- /dev/null +++ b/packages/client/src/dnd-context/index.md @@ -0,0 +1,8 @@ +--- +nav: + path: /client +group: + path: /schema-components +--- + +# DndContext 待定 diff --git a/packages/client/src/dnd-context/index.tsx b/packages/client/src/dnd-context/index.tsx new file mode 100644 index 000000000..900a4b50b --- /dev/null +++ b/packages/client/src/dnd-context/index.tsx @@ -0,0 +1,29 @@ +import { DndContext as DndKitContext, DragEndEvent } from '@dnd-kit/core'; +import { observer } from '@formily/react'; +import React from 'react'; +import { createDesignable, useDesignable } from '../schema-component'; + +const useDragEnd = () => { + const { refresh } = useDesignable(); + + return ({ active, over }: DragEndEvent) => { + console.log({ active, over }); + const activeSchema = active?.data?.current?.schema; + const overSchema = over?.data?.current?.schema; + + if (!activeSchema || !overSchema) { + return; + } + + const dn = createDesignable({ + current: overSchema, + }); + + dn.on('afterInsertAdjacent', refresh); + dn.insertBeforeBeginOrAfterEnd(activeSchema); + }; +}; + +export const DndContext = observer((props) => { + return {props.children}; +}); diff --git a/packages/client/src/document-title/index.md b/packages/client/src/document-title/index.md new file mode 100644 index 000000000..f580fa079 --- /dev/null +++ b/packages/client/src/document-title/index.md @@ -0,0 +1,8 @@ +--- +nav: + path: /client +group: + path: /client +--- + +# DocumentTitle 待定 diff --git a/packages/client/src/document-title/index.tsx b/packages/client/src/document-title/index.tsx new file mode 100644 index 000000000..dd6687578 --- /dev/null +++ b/packages/client/src/document-title/index.tsx @@ -0,0 +1,3 @@ +export function DocumentTitleProvider() { + +} diff --git a/packages/client/src/filter/index.md b/packages/client/src/filter/index.md new file mode 100644 index 000000000..947c135a5 --- /dev/null +++ b/packages/client/src/filter/index.md @@ -0,0 +1,8 @@ +--- +nav: + path: /client +group: + path: /schema-components +--- + +# Filter diff --git a/packages/client/src/form-item/index.md b/packages/client/src/form-item/index.md new file mode 100644 index 000000000..4de6b3019 --- /dev/null +++ b/packages/client/src/form-item/index.md @@ -0,0 +1,10 @@ +--- +nav: + path: /client +group: + path: /schema-components +--- + +# FormItem + +表单字段装饰器。除此之外,也继承了 BlockItem 的功能。 diff --git a/packages/client/src/form-item/index.tsx b/packages/client/src/form-item/index.tsx new file mode 100644 index 000000000..ae9aa183b --- /dev/null +++ b/packages/client/src/form-item/index.tsx @@ -0,0 +1,11 @@ +import React from 'react'; +import { BlockItem } from '../block-item'; +import { FormItem as FormilyFormItem } from '@formily/antd'; + +export const FormItem: React.FC = (props) => { + return ( + + + + ); +}; diff --git a/packages/client/src/form/Form.tsx b/packages/client/src/form/Form.tsx new file mode 100644 index 000000000..3e6062ac8 --- /dev/null +++ b/packages/client/src/form/Form.tsx @@ -0,0 +1,58 @@ +import React, { useContext, useMemo } from 'react'; +import { toJS } from '@formily/reactive'; +import { createForm, FormPath } from '@formily/core'; +import { + FieldContext, + FormContext, + FormProvider, + observer, + SchemaContext, + SchemaOptionsContext, + useField, + useFieldSchema, +} from '@formily/react'; +import { SchemaComponent, useAttach } from '../schema-component'; + +type ComposedForm = React.FC & { + __NOCOBASE_FORM?: boolean; +}; + +const useFormDecorator = () => { + const field = useField(); + const options = useContext(SchemaOptionsContext); + const decorator = field.decoratorType ? FormPath.getIn(options?.components, field.decoratorType) : null; + return decorator?.__NOCOBASE_FORM ? decorator : null; +}; + +const FormDecorator: React.FC = (props) => { + const { form } = props; + const options = useContext(SchemaOptionsContext); + const field = useField(); + const fieldSchema = useFieldSchema(); + const f = useAttach(form.createVoidField({ ...field.props, basePath: '' })); + const finalComponent = FormPath.getIn(options?.components, field.componentType) ?? field.componentType; + return ( + + + + {React.createElement(finalComponent, toJS(field.componentProps))} + + + + ); +}; + +export const Form: ComposedForm = observer((props) => { + const form = useMemo(() => createForm(), []); + const fieldSchema = useFieldSchema(); + const decorator = useFormDecorator(); + return decorator ? ( + + ) : ( + + + + ); +}); + +Form.__NOCOBASE_FORM = true; diff --git a/packages/client/src/form/demos/demo1.tsx b/packages/client/src/form/demos/demo1.tsx new file mode 100644 index 000000000..ee65ba2df --- /dev/null +++ b/packages/client/src/form/demos/demo1.tsx @@ -0,0 +1,54 @@ +import React from 'react'; +import { observer, ISchema } from '@formily/react'; +import { SchemaComponent, SchemaComponentProvider, Form, Action, useCloseAction } from '@nocobase/client'; +import { FormItem, Input } from '@formily/antd'; +import 'antd/dist/antd.css'; + +export default observer(() => { + const schema: ISchema = { + type: 'object', + properties: { + a1: { + type: 'void', + 'x-component': 'Action', + 'x-component-props': { + type: 'primary', + }, + title: 'Open', + properties: { + d1: { + type: 'void', + 'x-component': 'Action.Drawer', + 'x-decorator': 'Form', + title: 'Drawer Title', + properties: { + field1: { + 'x-component': 'Input', + 'x-decorator': 'FormItem', + title: 'T1', + }, + f1: { + type: 'void', + 'x-component': 'Action.Drawer.Footer', + properties: { + a1: { + 'x-component': 'Action', + title: 'Close', + 'x-component-props': { + useAction: '{{ useCloseAction }}', + }, + }, + }, + }, + }, + }, + }, + }, + }, + }; + return ( + + + + ); +}); diff --git a/packages/client/src/form/demos/demo2.tsx b/packages/client/src/form/demos/demo2.tsx new file mode 100644 index 000000000..ede69eacf --- /dev/null +++ b/packages/client/src/form/demos/demo2.tsx @@ -0,0 +1,47 @@ +import React from 'react'; +import { observer, ISchema, useForm } from '@formily/react'; +import { SchemaComponent, SchemaComponentProvider, Form, Action } from '@nocobase/client'; +import 'antd/dist/antd.css'; +import { FormItem, Input } from '@formily/antd'; + +export default observer(() => { + const schema: ISchema = { + type: 'object', + properties: { + form1: { + type: 'void', + 'x-component': 'Form', + properties: { + field1: { + 'x-component': 'Input', + 'x-decorator': 'FormItem', + title: 'T1', + }, + action1: { + // type: 'void', + 'x-component': 'Action', + title: 'Submit', + 'x-component-props': { + useAction: '{{ useSubmit }}', + }, + }, + }, + }, + }, + }; + + const useSubmit = () => { + const form = useForm(); + return { + async run() { + console.log(form.values); + }, + }; + }; + + return ( + + + + ); +}); diff --git a/packages/client/src/form/index.md b/packages/client/src/form/index.md new file mode 100644 index 000000000..1dac6222d --- /dev/null +++ b/packages/client/src/form/index.md @@ -0,0 +1,14 @@ +--- +nav: + path: /client +group: + path: /schema-components +--- + +# Form + + + +Form 也可以作 decorator 存在,和 Action.Drawer 结合就是 DrawerForm 了。 + + diff --git a/packages/client/src/form/index.tsx b/packages/client/src/form/index.tsx new file mode 100644 index 000000000..b690c60a1 --- /dev/null +++ b/packages/client/src/form/index.tsx @@ -0,0 +1 @@ +export * from './Form'; diff --git a/packages/client/src/grid/demos/demo1.tsx b/packages/client/src/grid/demos/demo1.tsx new file mode 100644 index 000000000..802399ca0 --- /dev/null +++ b/packages/client/src/grid/demos/demo1.tsx @@ -0,0 +1,124 @@ +import React from 'react'; +import { uid } from '@formily/shared'; +import { observer, useFieldSchema } from '@formily/react'; +import { useDraggable, useDroppable } from '@dnd-kit/core'; +import { SchemaComponent, SchemaComponentProvider, Grid } from '@nocobase/client'; + +function Draggable(props) { + const { attributes, listeners, setNodeRef, transform } = useDraggable({ + id: props.id, + data: props.data, + }); + const style = transform + ? { + transform: `translate3d(${transform.x}px, ${transform.y}px, 0)`, + } + : undefined; + + return ( + + ); +} + +function Droppable(props) { + const { isOver, setNodeRef } = useDroppable({ + id: props.id, + data: props.data, + }); + const style = { + color: isOver ? 'green' : undefined, + }; + + return ( +
+ {props.children} +
+ ); +} + +const Block = observer((props) => { + const fieldSchema = useFieldSchema(); + return ( + +
+ Block {fieldSchema.name} + + Drag + +
+
+ ); +}); + +export default function App() { + return ( + + + + ); +} diff --git a/packages/client/src/grid/index.md b/packages/client/src/grid/index.md new file mode 100644 index 000000000..0331d13ba --- /dev/null +++ b/packages/client/src/grid/index.md @@ -0,0 +1,10 @@ +--- +nav: + path: /client +group: + path: /schema-components +--- + +# Grid 待定 + + diff --git a/packages/client/src/grid/index.tsx b/packages/client/src/grid/index.tsx new file mode 100644 index 000000000..d41a66a7c --- /dev/null +++ b/packages/client/src/grid/index.tsx @@ -0,0 +1,19 @@ +import React from 'react'; +import { observer } from '@formily/react'; +import { DndContext } from '../dnd-context'; + +export const Grid: any = observer((props) => { + return ( +
+ {props.children} +
+ ); +}); + +Grid.Row = observer((props) => { + return
{props.children}
; +}); + +Grid.Col = observer((props) => { + return
{props.children}
; +}); diff --git a/packages/client/src/i18n/index.md b/packages/client/src/i18n/index.md new file mode 100644 index 000000000..d743f012e --- /dev/null +++ b/packages/client/src/i18n/index.md @@ -0,0 +1,10 @@ +--- +nav: + path: /client +group: + path: /client +--- + +# I18n + +提供国际化解决方案。 \ No newline at end of file diff --git a/packages/client/src/i18n/index.ts b/packages/client/src/i18n/index.ts new file mode 100644 index 000000000..a1b0539c0 --- /dev/null +++ b/packages/client/src/i18n/index.ts @@ -0,0 +1,54 @@ +import i18next from 'i18next'; +import { initReactI18next } from 'react-i18next'; +import moment from 'moment'; + +const zhCN = require('../locale/zh_CN'); +const enUS = require('../locale/en_US'); +const log = require('debug')('i18next'); + +export const i18n = i18next.createInstance(); + +i18n.use(initReactI18next).init({ + lng: localStorage.getItem('locale') || 'en-US', + debug: false, + defaultNS: 'client', + // parseMissingKeyHandler: (key) => { + // console.log('parseMissingKeyHandler', `'${key}': '${key}',`); + // return key; + // }, + // ns: ['client'], + resources: { + 'en-US': { + client: { + ...enUS, + }, + }, + 'zh-CN': { + client: { + ...zhCN, + }, + }, + }, +}); + +const momentLngs = { + 'en-US': 'en', + 'zh-CN': 'zh-cn', +}; + +function setMomentLng(language) { + const lng = momentLngs[language || 'en-US'] || 'en'; + log(lng); + moment.locale(lng); +} + +setMomentLng(localStorage.getItem('locale')); + +i18n.on('languageChanged', (lng) => { + localStorage.setItem('locale', lng); + setMomentLng(lng); +}); + +// export const t = i18n.t; + +export default i18n; diff --git a/packages/client/src/icon-picker/index.md b/packages/client/src/icon-picker/index.md new file mode 100644 index 000000000..9780ff7bf --- /dev/null +++ b/packages/client/src/icon-picker/index.md @@ -0,0 +1,8 @@ +--- +nav: + path: /client +group: + path: /schema-components +--- + +# IconPicker diff --git a/packages/client/src/index.tsx b/packages/client/src/index.tsx index 0960612ae..5351d6591 100644 --- a/packages/client/src/index.tsx +++ b/packages/client/src/index.tsx @@ -1,5 +1,23 @@ -import React from 'react'; +import debug from 'debug'; +debug.log = console.log.bind(console); -export function Hello() { - return
aaa
; -} +export * from './i18n'; +export * from './acl'; +export * from './admin-layout'; +export * from './antd-config-provider'; +export * from './api-client'; +export * from './auth-layout'; +export * from './collection-manager'; +export * from './current-user'; +export * from './document-title'; +export * from './route-switch'; +export * from './schema-component'; +export * from './system-settings'; +export * from './action'; +export * from './form'; +export * from './form-item'; +export * from './block-item'; +export * from './dnd-context'; +export * from './grid'; +export * from './application'; +export * from './record-provider'; diff --git a/packages/client/src/input-number/index.md b/packages/client/src/input-number/index.md new file mode 100644 index 000000000..ea97fc56a --- /dev/null +++ b/packages/client/src/input-number/index.md @@ -0,0 +1,8 @@ +--- +nav: + path: /client +group: + path: /schema-components +--- + +# InputNumber diff --git a/packages/client/src/input/index.md b/packages/client/src/input/index.md new file mode 100644 index 000000000..a957461fb --- /dev/null +++ b/packages/client/src/input/index.md @@ -0,0 +1,8 @@ +--- +nav: + path: /client +group: + path: /schema-components +--- + +# Input diff --git a/packages/client/src/kanban/index.md b/packages/client/src/kanban/index.md new file mode 100644 index 000000000..cdb9e2afd --- /dev/null +++ b/packages/client/src/kanban/index.md @@ -0,0 +1,8 @@ +--- +nav: + path: /client +group: + path: /schema-components +--- + +# Kanban 待定 diff --git a/packages/client/src/locale/en_US.json b/packages/client/src/locale/en_US.json new file mode 100644 index 000000000..2edf91151 --- /dev/null +++ b/packages/client/src/locale/en_US.json @@ -0,0 +1,280 @@ +{ + "{{count}} filter items_one": "{{count}} filter item", + "{{count}} filter items_other": "{{count}} filter items", + "{{count}} more items_one": "{{count}} more item", + "{{count}} more items_other": "{{count}} more items", + "Delete menu item": "Delete menu item", + "Today": "Today", + "Month": "Month", + "Week": "Week", + "Work week": "Work week", + "Day": "Day", + "Agenda": "Agenda", + "Date": "Date", + "Time": "Time", + "Event": "Event", + "None": "None", + "System settings": "System settings", + "System title": "System title", + "Logo": "Logo", + "Add menu item": "Add menu item", + "Page": "Page", + "Name": "Name", + "Icon": "Icon", + "Group": "Group", + "Link": "Link", + "Edit menu item": "Edit menu item", + "Move to": "Move to", + "Insert left": "Insert left", + "Insert right": "Insert right", + "Insert inner": "Insert inner", + "Delete": "Delete", + "UI editor": "UI editor", + "Collections & Fields": "Collections & Fields", + "Roles & Permissions": "Roles & Permissions", + "Edit profile": "Edit profile", + "Change password": "Change password", + "Old password": "Old password", + "New password": "New password", + "Switch role": "Switch role", + "Super admin": "Super admin", + "Language": "Language", + "Allow sign up": "Allow sign up", + "Sign out": "Sign out", + "Cancel": "Cancel", + "Submit": "Submit", + "Set the data scope": "Set the data scope", + "Data blocks": "Data blocks", + "Table": "Table", + "Form": "Form", + "Select data source": "Select data source", + "Calendar": "Calendar", + "Kanban": "Kanban", + "Select group field": "Select group field", + "Media": "Media", + "Markdown": "Markdown", + "Wysiwyg": "Wysiwyg", + "Charts": "Charts", + "Column chart": "Column chart", + "Bar chart": "Bar chart", + "Line chart": "Line chart", + "Pie chart": "Pie chart", + "Select template": "Select template", + "Action logs": "Action logs", + "Create template": "Create template", + "Edit markdown": "Edit markdown", + "Add block": "Add block", + "Add new": "Add new", + "Add record": "Add record", + "Custom field display name": "Custom field display name", + "Display fields": "Display fields", + "Edit record": "Edit record", + + "Add page": "Add page", + "Add group": "Add group", + "Add link": "Add link", + "Insert above": "Insert above", + "Insert below": "Insert below", + "Save": "Save", + "Delete block": "Delete block", + "Are you sure you want to delete it?": "Are you sure you want to delete it?", + "This is a demo text, **supports Markdown syntax**.": "This is a demo text, **supports Markdown syntax**.", + + "Filter": "Filter", + "Action type": "Action type", + "Actions": "Actions", + "Insert": "Insert", + "Update": "Update", + "View": "View", + "View record": "View record", + + "Data changes": "Data changes", + "Field name": "Field name", + "Before change": "Before change", + "After change": "After change", + + "Delete record": "Delete record", + "Create collection": "Create collection", + "Collection display name": "Collection display name", + "Collection name": "Collection name", + "Randomly generated and can be modified. Support letters, numbers and underscores, must start with an letter.": "Randomly generated and can be modified. Support letters, numbers and underscores, must start with an letter.", + "Storage type": "Storage type", + "Edit": "Edit", + "Edit collection": "Edit collection", + "Configure fields": "Configure fields", + "Edit field": "Edit field", + "Configure fields of {{title}}": "Configure fields of {{title}}", + "Basic": "Basic", + "Single line text": "Single line text", + "Long text": "Long text", + "Phone": "Phone", + "Email": "Email", + "Number": "Number", + "Percent": "Percent", + "Password": "Password", + "Choices": "Choices", + "Checkbox": "Checkbox", + "Single select": "Single select", + "Multiple select": "Multiple select", + "Radio group": "Radio group", + "Checkbox group": "Checkbox group", + "China region": "China region", + "Attachment": "Attachment", + "Date & Time": "Date & Time", + "Datetime": "Datetime", + "Relation": "Relation", + "Link to": "Link to", + "Sub-table": "Sub-table", + "System info": "System info", + "Created at": "Created at", + "Last updated at": "Last updated at", + "Created by": "Created by", + "Last updated by": "Last updated by", + "Add field": "Add field", + "Field display name": "Field display name", + "Field type": "Field type", + + "Date format": "Date format", + "Year/Month/Day": "Year/Month/Day", + "Year-Month-Day": "Year-Month-Day", + "Day/Month/Year": "Day/Month/Year", + "Show time": "Show time", + "Time format": "Time format", + "12 hour": "12 hour", + "24 hour": "24 hour", + + "Meet <1><0>All<1>Any conditions in the group": "Meet <1><0>All<1>Any conditions in the group", + "Add filter": "Add filter", + "Add filter group": "Add filter group", + "is": "is", + "is not": "is not", + "contains": "contains", + "does not contain": "does not contain", + "is empty": "is empty", + "is not empty": "is not empty", + "Display <1><0>10<1>20<2>50<3>100 items per page": "Display <1><0>10<1>20<2>50<3>100 items per page", + "Edit chart": "Edit chart", + "Add text": "Add text", + "Filterable fields": "Filterable fields", + "Edit button": "Edit button", + "Hide": "Hide", + "Enable actions": "Enable actions", + "Export": "Export", + "Customize": "Customize", + "Function": "Function", + "Popup form": "Popup form", + "Flexible popup": "Flexible popup", + "Configure actions": "Configure actions", + "Display order number": "Display order number", + "Enable drag and drop sorting": "Enable drag and drop sorting", + "Triggered when the row is clicked": "Triggered when the row is clicked", + "Add tab": "Add tab", + "Disable tabs": "Disable tabs", + "Details": "Details", + "Edit tab": "Edit tab", + "Relationship blocks": "Relationship blocks", + "Select record": "Select record", + "Display name": "Display name", + "Select icon": "Select icon", + "Custom column name": "Custom column name", + "Edit description": "Edit description", + "Required": "Required", + "Label field": "Label field", + "Default is the ID field": "Default is the ID field", + "Set default sorting rules": "Set default sorting rules", + + "is before": "is before", + "is after": "is after", + "is on or after": "is on or after", + "is on or before": "is on or before", + + "Upload": "Upload", + + "Select level": "Select level", + "Province": "Province", + "City": "City", + "Area": "Area", + "Street": "Street", + "Village": "Village", + "Must select to the last level": "Must select to the last level", + + "Move {{title}} to": "Move {{title}} to", + "Target position": "Target position", + "After": "After", + "Before": "Before", + + "Add {{type}} before \"{{title}}\"": "Add {{type}} before \"{{title}}\"", + "Add {{type}} after \"{{title}}\"": "Add {{type}} after \"{{title}}\"", + "Add {{type}} in \"{{title}}\"": "Add {{type}} in \"{{title}}\"", + + "Original name": "Original name", + "Custom name": "Custom name", + "Custom Title": "Custom Title", + + "Options": "Options", + "Option value": "Option value", + "Option label": "Option label", + "Color": "Color", + "Add option": "Add option", + "Related collection": "Related collection", + "Allow linking to multiple records": "Allow linking to multiple records", + "Allow uploading multiple files": "Allow uploading multiple files", + + "Configure calendar": "Configure calendar", + "Title field": "Title field", + "Start date field": "Start date field", + "End date field": "End date field", + "Navigate": "Navigate", + "Title": "Title", + "Select view": "View", + "Reset": "Reset", + "Export fields": "Export fields", + "Saved successfully": "Saved successfully", + "Templates": "Templates", + "Nickname": "Nickname", + "Sign in": "Sign in", + "Create an account": "Create an account", + "Sign up": "Sign up", + "Confirm password": "Confirm password", + "Log in with an existing account": "Log in with an existing account", + "Password mismatch": "Password mismatch", + "Signed up successfully. It will jump to the login page.": "Signed up successfully. It will jump to the login page.", + + "Users": "Users", + "Roles": "Roles", + "Add role": "Add role", + "Role name": "Role name", + "Configure": "Configure", + "Configure permissions": "Configure permissions", + "Edit role": "Edit role", + + "Action permissions": "Action permissions", + "Menu permissions": "Menu permissions", + + "Menu item name": "Menu item name", + "Allow access": "Allow access", + + "Action name": "Action name", + "Allow action": "Allow action", + "Action scope": "Action scope", + "Operate on new data": "Operate on new data", + "Operate on existing data": "Operate on existing data", + + "Yes": "Yes", + "No": "No", + + "Red": "Red", + "Magenta": "Magenta", + "Volcano": "Volcano", + "Orange": "Orange", + "Gold": "Gold", + "Lime": "Lime", + "Green": "Green", + "Cyan": "Cyan", + "Blue": "Blue", + "Geek Blue": "Geek Blue", + "Purple": "Purple", + "Default": "Default", + "Add card": "Add card", + "edit title": "Edit Title" +} diff --git a/packages/client/src/locale/zh_CN.json b/packages/client/src/locale/zh_CN.json new file mode 100644 index 000000000..d460ed8bd --- /dev/null +++ b/packages/client/src/locale/zh_CN.json @@ -0,0 +1,280 @@ +{ + "Display <1><0>10<1>20<2>50<3>100 items per page": "每页显示 <1><0>10<1>20<2>50<3>100 条", + "Meet <1><0>All<1>Any conditions in the group": "满足组内 <1><0>全部<1>任意 条件", + "Open in<1><0>Modal<1>Drawer<2>Window": "在 <1><0>对话框<1>抽屉<2>窗口 内打开", + "{{count}} filter items": "{{count}} 个筛选项", + "{{count}} more items": "还有 {{count}} 项", + + "Today": "今天", + "Month": "月", + "Week": "周", + "Work week": "工作日", + "Day": "天", + "Agenda": "列表", + "Date": "日期", + "Time": "时间", + "Event": "事件", + "None": "无", + "System settings": "系统设置", + "System title": "系统名称", + "Logo": "Logo", + "Add menu item": "添加菜单项", + "Page": "页面", + "Name": "名称", + "Icon": "图标", + "Group": "分组", + "Link": "链接", + "Edit menu item": "编辑菜单项", + "Move to": "移动到", + "Insert left": "在左边插入", + "Insert right": "在右边插入", + "Insert inner": "在里面插入", + "Delete": "删除", + "UI editor": "界面配置", + "Collections & Fields": "数据表配置", + "Roles & Permissions": "角色和权限", + "Edit profile": "个人资料", + "Change password": "修改密码", + "Old password": "旧密码", + "New password": "新密码", + "Switch role": "切换角色", + "Super admin": "超级管理员", + "Language": "语言设置", + "Allow sign up": "允许注册", + "Sign out": "注销", + "Cancel": "取消", + "Submit": "提交", + "Set the data scope": "设置数据范围", + "Data blocks": "数据区块", + "Table": "表格", + "Form": "表单", + "Select data source": "选择数据源", + "Calendar": "日历", + "Kanban": "看板", + "Select group field": "选择分组字段", + "Media": "多媒体", + "Markdown": "Markdown", + "Wysiwyg": "富文本", + "Charts": "图表", + "Column chart": "柱状图", + "Bar chart": "条形图", + "Line chart": "折线图", + "Pie chart": "饼图", + "Templates": "模板", + "Select template": "选择模板", + "Action logs": "操作日志", + "Create template": "创建模板", + "Edit markdown": "编辑 Markdown", + "Add block": "创建区块", + "Add new": "添加", + "Add record": "添加数据", + "Custom field display name": "自定义字段名称", + "Display fields": "显示字段", + "Edit record": "编辑数据", + "Delete menu item": "删除菜单项", + "Add page": "添加页面", + "Add group": "添加分组", + "Add link": "添加链接", + "Insert above": "在上面插入", + "Insert below": "在下面插入", + "Save": "保存", + "Delete block": "删除区块", + "Are you sure you want to delete it?": "你确定要删除吗?", + "This is a demo text, **supports Markdown syntax**.": "这是一段演示文本,**支持 Markdown 语法**。", + + "Filter": "筛选", + "Action type": "操作类型", + "Actions": "操作", + "Insert": "新增", + "Update": "更新", + "View": "查看", + "View record": "查看数据", + + "Data changes": "数据变更", + "Field name": "字段标识", + "Before change": "变更前", + "After change": "变更后", + + "Delete record": "删除数据", + "Create collection": "创建数据表", + "Collection display name": "数据表名称", + "Collection name": "数据表标识", + "Randomly generated and can be modified. Support letters, numbers and underscores, must start with a letter.": "随机生成,可修改。支持英文、数字和下划线,必须以英文字母开头。", + "Storage type": "存储类型", + "Edit": "编辑", + "Edit collection": "编辑数据表", + "Configure fields": "配置字段", + "Edit field": "编辑字段", + "Configure fields of {{title}}": "「{{title}}」的字段配置", + "Basic": "基本类型", + "Single line text": "单行文本", + "Long text": "多行文本", + "Phone": "手机号码", + "Email": "电子邮箱", + "Number": "数字", + "Percent": "百分比", + "Password": "密码", + "Choices": "选择类型", + "Checkbox": "勾选", + "Single select": "下拉菜单(单选)", + "Multiple select": "下拉菜单(多选)", + "Radio group": "单选框", + "Checkbox group": "复选框", + "China region": "中国行政区", + "Attachment": "附件", + "Date & Time": "日期 & 时间", + "Datetime": "日期", + "Relation": "关系类型", + "Link to": "关联", + "Sub-table": "子表格", + "System info": "系统信息", + "Created at": "创建日期", + "Last updated at": "最后修改日期", + "Created by": "创建人", + "Last updated by": "最后更新日期", + "Add field": "添加字段", + "Field display name": "字段名称", + "Field type": "字段类型", + + "Date format": "日期格式", + "Year/Month/Day": "年/月/日", + "Year-Month-Day": "年-月-日", + "Day/Month/Year": "日/月/年", + "Show time": "显示时间", + "Time format": "时间格式", + "12 hour": "12 小时制", + "24 hour": "24 小时制", + + "Add filter": "添加筛选条件", + "Add filter group": "添加筛选分组", + "is": "等于", + "is not": "不等于", + "contains": "包含", + "does not contain": "不包含", + "is empty": "为空", + "is not empty": "不为空", + "Edit chart": "编辑图表", + "Add text": "添加文本", + "Filterable fields": "可筛选字段", + "Edit button": "编辑按钮", + "Hide": "隐藏", + "Enable actions": "启用操作", + "Export": "导出", + "Customize": "自定义", + "Function": "Function", + "Popup form": "Popup form", + "Flexible popup": "Flexible popup", + "Configure actions": "配置操作", + "Display order number": "显示序号", + "Enable drag and drop sorting": "启用拖拽排序", + "Triggered when the row is clicked": "点击表格行时触发", + "Add tab": "添加标签页", + "Disable tabs": "禁用标签页", + "Details": "详情", + "Edit tab": "编辑标签页", + "Relationship blocks": "关系数据区块", + "Select record": "选择数据", + "Display name": "显示名称", + "Select icon": "选择图标", + "Custom column name": "自定义列名称", + "Edit description": "编辑描述", + "Required": "必填", + "Label field": "标签字段", + "Default is the ID field": "默认为 ID 字段", + "Set default sorting rules": "设置排序规则", + + "is before": "早于", + "is after": "晚于", + "is on or after": "不早于", + "is on or before": "不晚于", + + "Upload": "上传", + + "Select level": "选择层级", + "Province": "省", + "City": "市", + "Area": "区/县", + "Street": "乡镇/街道", + "Village": "村/居委会", + "Must select to the last level": "必须选到最后一级", + + "Move {{title}} to": "将 {{title}} 移动到", + "Target position": "目标位置", + "After": "之后", + "Before": "之前", + + "Add {{type}} before \"{{title}}\"": "在 \"{{title}}\" 前插入{{type}}", + "Add {{type}} after \"{{title}}\"": "在 \"{{title}}\" 前插入{{type}}", + "Add {{type}} in \"{{title}}\"": "在 \"{{title}}\" 里插入{{type}}", + + "Original name": "原名称", + "Custom name": "自定义名称", + "Custom Title": "自定义标题", + + "Options": "选项", + "Option value": "选项值", + "Option label": "选项", + "Color": "颜色", + "Add option": "添加选项", + "Related collection": "关系表", + "Allow linking to multiple records": "允许关联多条记录", + "Allow uploading multiple files": "允许上传多个文件", + + "Configure calendar": "配置日历", + "Title field": "标题字段", + "Start date field": "开始日期字段", + "End date field": "结束日期字段", + "Navigate": "分页", + "Title": "标题", + "Select view": "切换视图", + "Reset": "重置", + "Export fields": "导出字段", + "Saved successfully": "保存成功", + "Nickname": "昵称", + "Sign in": "登录", + "Create an account": "注册账号", + "Sign up": "注册", + "Confirm password": "确认密码", + "Log in with an existing account": "使用已有账号登录", + "Signed up successfully. It will jump to the login page.": "注册成功,将跳转登录页。", + "Password mismatch": "确认密码不匹配", + "Users": "用户", + + "Roles": "角色", + "Add role": "添加角色", + "Role name": "角色名称", + "Configure": "配置", + "Configure permissions": "配置权限", + "Edit role": "编辑角色", + + "Action permissions": "数据表操作权限", + "Menu permissions": "菜单访问权限", + + "Menu item name": "菜单名称", + "Allow access": "允许访问", + + "Action name": "操作名称", + "Allow action": "允许操作", + "Action scope": "可操作数据范围", + "Operate on new data": "对新增数据操作", + "Operate on existing data": "对已有数据操作", + + "Yes": "是", + "No": "否", + + "Red": "薄暮", + "Magenta": "法式洋红", + "Volcano": "火山", + "Orange": "日暮", + "Gold": "金盏花", + "Lime": "青柠", + "Green": "极光绿", + "Cyan": "明青", + "Blue": "拂晓蓝", + "Geek Blue": "极客蓝", + "Purple": "酱紫", + "Default": "默认", + + "Add card": "添加卡片", + "edit title": "修改标题" +} diff --git a/packages/client/src/markdown/index.md b/packages/client/src/markdown/index.md new file mode 100644 index 000000000..300fac5b7 --- /dev/null +++ b/packages/client/src/markdown/index.md @@ -0,0 +1,8 @@ +--- +nav: + path: /client +group: + path: /schema-components +--- + +# Markdown diff --git a/packages/client/src/menu/index.md b/packages/client/src/menu/index.md new file mode 100644 index 000000000..13b263c48 --- /dev/null +++ b/packages/client/src/menu/index.md @@ -0,0 +1,19 @@ +--- +nav: + path: /client +group: + path: /schema-components +--- + +# Menu + +## Nodes + +- Menu +- Menu.ItemGroup +- Menu.Item +- Menu.SubMenu +- Menu.Divider +- Menu.URL +- Menu.Link +- Menu.Action diff --git a/packages/client/src/password/index.md b/packages/client/src/password/index.md new file mode 100644 index 000000000..a25b4f20d --- /dev/null +++ b/packages/client/src/password/index.md @@ -0,0 +1,8 @@ +--- +nav: + path: /client +group: + path: /schema-components +--- + +# Password diff --git a/packages/client/src/radio/index.md b/packages/client/src/radio/index.md new file mode 100644 index 000000000..9f570654f --- /dev/null +++ b/packages/client/src/radio/index.md @@ -0,0 +1,8 @@ +--- +nav: + path: /client +group: + path: /schema-components +--- + +# Radio diff --git a/packages/client/src/record-picker/index.md b/packages/client/src/record-picker/index.md new file mode 100644 index 000000000..3a8d14202 --- /dev/null +++ b/packages/client/src/record-picker/index.md @@ -0,0 +1,8 @@ +--- +nav: + path: /client +group: + path: /schema-components +--- + +# RecordPicker 待定 diff --git a/packages/client/src/record-provider/index.md b/packages/client/src/record-provider/index.md new file mode 100644 index 000000000..2a5e13cbc --- /dev/null +++ b/packages/client/src/record-provider/index.md @@ -0,0 +1,30 @@ +--- +nav: + path: /client +group: + path: /client +--- + +# RecordProvider + +「Record」在这里有着特殊的意义,表示数据表的行记录。 + +## RecordProvider + +提供当前行记录的上下文 + +```tsx | pure + +``` + +## useRecord() + +```ts +interface User { + id: number; + username: string; + password: string; +} + +const record = useRecord(); +``` diff --git a/packages/client/src/record-provider/index.tsx b/packages/client/src/record-provider/index.tsx new file mode 100644 index 000000000..ea2d2f0ae --- /dev/null +++ b/packages/client/src/record-provider/index.tsx @@ -0,0 +1,13 @@ +import { useRequest } from 'ahooks'; +import React, { createContext, useContext } from 'react'; + +export const RecordContext = createContext({}); + +export const RecordProvider: React.FC<{ record: any }> = (props) => { + const { record, children } = props; + return {children}; +}; + +export function useRecord() { + return useContext(RecordContext) as D; +} diff --git a/packages/client/src/route-switch/RouteSwitch.tsx b/packages/client/src/route-switch/RouteSwitch.tsx new file mode 100644 index 000000000..612ce6e3d --- /dev/null +++ b/packages/client/src/route-switch/RouteSwitch.tsx @@ -0,0 +1,59 @@ +import React from 'react'; +import { Redirect, Route, Switch } from 'react-router-dom'; +import { RouteContext } from './context'; +import { useRouteComponent } from './hooks'; +import { RouteSwitchProps } from './types'; + +export function RouteSwitch(props: RouteSwitchProps) { + const { routes = [] } = props; + if (!routes.length) { + return null; + } + return ( + + {routes.map((route, index) => { + if (route.type == 'redirect') { + return ( + + ); + } + if (!route.path && Array.isArray(route.routes)) { + route.path = route.routes.map((r) => r.path) as any; + } + return ( + { + return ( + + + + ); + }} + /> + ); + })} + + ); +} + +function ComponentRenderer(props) { + const Component = useRouteComponent(props?.route?.component); + return ( + + + + ); +} diff --git a/packages/client/src/route-switch/RouteSwitchProvider.tsx b/packages/client/src/route-switch/RouteSwitchProvider.tsx new file mode 100644 index 000000000..35e8b209a --- /dev/null +++ b/packages/client/src/route-switch/RouteSwitchProvider.tsx @@ -0,0 +1,8 @@ +import React from 'react'; +import { RouteSwitchContext } from './context'; +import { RouteSwitchProviderProps } from './types'; + +export function RouteSwitchProvider(props: RouteSwitchProviderProps) { + const { children, components } = props; + return {children}; +} diff --git a/packages/client/src/route-switch/__tests__/RouteSwitch.test.tsx b/packages/client/src/route-switch/__tests__/RouteSwitch.test.tsx new file mode 100644 index 000000000..912692875 --- /dev/null +++ b/packages/client/src/route-switch/__tests__/RouteSwitch.test.tsx @@ -0,0 +1,32 @@ +import React from 'react'; +import { MemoryRouter } from 'react-router-dom'; +import { RouteSwitchProvider, RouteSwitch } from '../'; +import { render } from '@testing-library/react'; + +const Home = () =>

Home

; +const About = () =>

About

; + +describe('route-switch', () => { + it('case 1', () => { + const App = () => { + return ( + + + + + + ); + }; + const { container } = render(); + expect(container).toMatchSnapshot(); + }); +}); diff --git a/packages/client/src/route-switch/__tests__/__snapshots__/RouteSwitch.test.tsx.snap b/packages/client/src/route-switch/__tests__/__snapshots__/RouteSwitch.test.tsx.snap new file mode 100644 index 000000000..6dbaebd5e --- /dev/null +++ b/packages/client/src/route-switch/__tests__/__snapshots__/RouteSwitch.test.tsx.snap @@ -0,0 +1,9 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`route-switch case 1 1`] = ` +
+

+ Home +

+
+`; diff --git a/packages/client/src/route-switch/context.ts b/packages/client/src/route-switch/context.ts new file mode 100644 index 000000000..a7b71c958 --- /dev/null +++ b/packages/client/src/route-switch/context.ts @@ -0,0 +1,8 @@ +import { createContext } from 'react'; +import { RouteProps } from './types'; + +export const RouteSwitchContext = createContext({ + components: {}, +}); + +export const RouteContext = createContext(null); diff --git a/packages/client/src/route-switch/demos/demo1.tsx b/packages/client/src/route-switch/demos/demo1.tsx new file mode 100644 index 000000000..66b3e08ad --- /dev/null +++ b/packages/client/src/route-switch/demos/demo1.tsx @@ -0,0 +1,31 @@ +import React from 'react'; +import { Link, MemoryRouter as Router } from 'react-router-dom'; +import { RouteRedirectProps, RouteSwitchProvider, RouteSwitch } from '@nocobase/client'; + +const Home = () =>

Home

; +const About = () =>

About

; + +const routes: RouteRedirectProps[] = [ + { + type: 'route', + path: '/', + exact: true, + component: 'Home', + }, + { + type: 'route', + path: '/about', + component: 'About', + }, +]; + +export default () => { + return ( + + + Home, About + + + + ); +}; diff --git a/packages/client/src/route-switch/hooks.ts b/packages/client/src/route-switch/hooks.ts new file mode 100644 index 000000000..1b4ae9b81 --- /dev/null +++ b/packages/client/src/route-switch/hooks.ts @@ -0,0 +1,15 @@ +import { useContext } from 'react'; +import get from 'lodash/get'; +import { RouteContext, RouteSwitchContext } from './context'; + +export function useRouteComponent(name?: string) { + if (!name) { + return () => null; + } + const { components } = useContext(RouteSwitchContext); + return get(components, name) || (() => null); +} + +export function useRoute() { + return useContext(RouteContext); +} diff --git a/packages/client/src/route-switch/index.md b/packages/client/src/route-switch/index.md new file mode 100644 index 000000000..75b0163cf --- /dev/null +++ b/packages/client/src/route-switch/index.md @@ -0,0 +1,10 @@ +--- +nav: + path: /client +group: + path: /client +--- + +# RouteSwitch + + diff --git a/packages/client/src/route-switch/index.tsx b/packages/client/src/route-switch/index.tsx new file mode 100644 index 000000000..c5cfdca7a --- /dev/null +++ b/packages/client/src/route-switch/index.tsx @@ -0,0 +1,5 @@ +export * from './context'; +export * from './hooks'; +export * from './RouteSwitch'; +export * from './RouteSwitchProvider'; +export * from './types'; diff --git a/packages/client/src/route-switch/types.ts b/packages/client/src/route-switch/types.ts new file mode 100644 index 000000000..c15ceb4ca --- /dev/null +++ b/packages/client/src/route-switch/types.ts @@ -0,0 +1,33 @@ +export interface RedirectProps { + type: 'redirect'; + to: any; + path?: string; + exact?: boolean; + strict?: boolean; + push?: boolean; + from?: string; + [key: string]: any; +} + +export interface RouteProps { + type: 'route'; + path?: string | string[]; + exact?: boolean; + strict?: boolean; + sensitive?: boolean; + component?: any; + routes?: RouteProps[]; + [key: string]: any; +} + +export interface RouteSwitchProviderProps { + components?: any; + children?: any; +} + +export type RouteRedirectProps = RedirectProps | RouteProps; + +export interface RouteSwitchProps { + routes?: RouteRedirectProps[]; + components?: any; +} diff --git a/packages/client/src/row-selection/index.md b/packages/client/src/row-selection/index.md new file mode 100644 index 000000000..0182ff47b --- /dev/null +++ b/packages/client/src/row-selection/index.md @@ -0,0 +1,8 @@ +--- +nav: + path: /client +group: + path: /schema-components +--- + +# RowSelection 待定 diff --git a/packages/client/src/schema-component/components/RecursionComponent.tsx b/packages/client/src/schema-component/components/RecursionComponent.tsx new file mode 100644 index 000000000..d8f2a44b6 --- /dev/null +++ b/packages/client/src/schema-component/components/RecursionComponent.tsx @@ -0,0 +1,34 @@ +import React, { createContext, useContext, useEffect, useMemo, useState } from 'react'; +import { uid } from '@formily/shared'; +import { createForm, Form } from '@formily/core'; +import { useCookieState, useUpdateEffect } from 'ahooks'; +import { useTranslation } from 'react-i18next'; +import { + Schema, + FormProvider, + RecursionField, + createSchemaField, + IRecursionFieldProps, + ISchemaFieldProps, + SchemaOptionsContext, + SchemaReactComponents, + SchemaExpressionScopeContext, +} from '@formily/react'; +import { IRecursionComponentProps, ISchemaComponentProvider } from '../types'; +import { SchemaComponentContext } from '../context'; + +export const RecursionComponent: React.FC = (props) => { + const { components, scope } = useContext(SchemaComponentContext); + return ( + + + + + + ); +}; diff --git a/packages/client/src/schema-component/components/SchemaComponent.tsx b/packages/client/src/schema-component/components/SchemaComponent.tsx new file mode 100644 index 000000000..98f19a4c3 --- /dev/null +++ b/packages/client/src/schema-component/components/SchemaComponent.tsx @@ -0,0 +1,31 @@ +import React, { useContext, useEffect, useMemo } from 'react'; +import { Schema, ISchemaFieldProps } from '@formily/react'; +import { SchemaComponentContext } from '../context'; + +function toSchema(schema?: any) { + if (Schema.isSchemaInstance(schema)) { + return schema; + } + if (schema.name) { + return new Schema({ + type: 'object', + properties: { + [schema.name]: schema, + }, + }); + } + return new Schema(schema); +} + +export function SchemaComponent(props: ISchemaFieldProps) { + const { schema: defaultSchema, ...others } = props; + const { reset, SchemaField } = useContext(SchemaComponentContext); + const schema = useMemo(() => toSchema(defaultSchema), []); + // @ts-ignore + // console.log('defaultSchema', JSON.stringify(schema.toJSON())); + // TODO + useEffect(() => { + reset(); + }, [JSON.stringify(defaultSchema)]); + return ; +} diff --git a/packages/client/src/schema-component/components/SchemaComponentProvider.tsx b/packages/client/src/schema-component/components/SchemaComponentProvider.tsx new file mode 100644 index 000000000..19de5c216 --- /dev/null +++ b/packages/client/src/schema-component/components/SchemaComponentProvider.tsx @@ -0,0 +1,44 @@ +import React, { useMemo, useState } from 'react'; +import { uid } from '@formily/shared'; +import { createForm } from '@formily/core'; +import { useCookieState } from 'ahooks'; +import { useTranslation } from 'react-i18next'; +import { FormProvider, createSchemaField } from '@formily/react'; +import { ISchemaComponentProvider } from '../types'; +import { SchemaComponentContext } from '../context'; + +export const SchemaComponentProvider: React.FC = (props) => { + const { components, children } = props; + const [, setUid] = useState(uid()); + const [formId, setFormId] = useState(uid()); + const form = props.form || useMemo(() => createForm(), [formId]); + const { t } = useTranslation(); + const scope = { ...props.scope, t }; + const SchemaField = useMemo( + () => + createSchemaField({ + scope, + components, + }), + [], + ); + const [active, setActive] = useCookieState('useCookieDesignable'); + return ( + setFormId(uid()), + reset: () => setFormId(uid()), + refresh: () => setUid(uid()), + designable: active === 'true', + setDesignable(value) { + setActive(value ? 'true' : 'false'); + }, + }} + > + {children} + + ); +}; diff --git a/packages/client/src/schema-component/components/SchemaOptionsExpressionScopeProvider.tsx b/packages/client/src/schema-component/components/SchemaOptionsExpressionScopeProvider.tsx new file mode 100644 index 000000000..03945faa3 --- /dev/null +++ b/packages/client/src/schema-component/components/SchemaOptionsExpressionScopeProvider.tsx @@ -0,0 +1,17 @@ +import React, { useContext } from 'react'; +import { SchemaOptionsContext, SchemaExpressionScopeContext } from '@formily/react'; +import { SchemaComponentContext } from '../context'; + +export const SchemaOptionsExpressionScopeProvider: React.FC = (props) => { + const { components, scope } = useContext(SchemaComponentContext); + return ( + + {props.children} + + ); +}; diff --git a/packages/client/src/schema-component/components/index.tsx b/packages/client/src/schema-component/components/index.tsx new file mode 100644 index 000000000..f5871b464 --- /dev/null +++ b/packages/client/src/schema-component/components/index.tsx @@ -0,0 +1,4 @@ +export * from './RecursionComponent'; +export * from './SchemaComponent'; +export * from './SchemaComponentProvider'; +export * from './SchemaOptionsExpressionScopeProvider'; diff --git a/packages/client/src/schema-component/context.ts b/packages/client/src/schema-component/context.ts new file mode 100644 index 000000000..e738d8623 --- /dev/null +++ b/packages/client/src/schema-component/context.ts @@ -0,0 +1,4 @@ +import { createContext } from 'react'; +import { ISchemaComponentContext } from './types'; + +export const SchemaComponentContext = createContext({}); diff --git a/packages/client/src/schema-component/demos/demo1.tsx b/packages/client/src/schema-component/demos/demo1.tsx new file mode 100644 index 000000000..22c423ef3 --- /dev/null +++ b/packages/client/src/schema-component/demos/demo1.tsx @@ -0,0 +1,83 @@ +/** + * title: Insert Adjacent + */ +import React from 'react'; +import { SchemaComponentProvider, SchemaComponent, useDesignable } from '@nocobase/client'; +import { observer, Schema, useFieldSchema } from '@formily/react'; +import { Button, Space } from 'antd'; +import { uid } from '@formily/shared'; + +const Hello = observer((props) => { + const { insertAdjacent } = useDesignable(); + const fieldSchema = useFieldSchema(); + return ( +
+

{fieldSchema.name}

+ + + + + + +
{props.children}
+
+ ); +}); + +const Page = observer((props) => { + return
{props.children}
; +}); + +export default function App() { + return ( + + + + ); +} diff --git a/packages/client/src/schema-component/demos/demo3.tsx b/packages/client/src/schema-component/demos/demo3.tsx new file mode 100644 index 000000000..8482a216f --- /dev/null +++ b/packages/client/src/schema-component/demos/demo3.tsx @@ -0,0 +1,65 @@ +import React, { useState } from 'react'; +import {useDroppable, useDraggable} from '@dnd-kit/core'; +import {DndContext} from '@dnd-kit/core'; + +function Draggable(props) { + const {attributes, listeners, setNodeRef, transform} = useDraggable({ + id: props.id, + }); + const style = transform ? { + transform: `translate3d(${transform.x}px, ${transform.y}px, 0)`, + } : undefined; + + + return ( + + ); +} + +function Droppable(props) { + const {isOver, setNodeRef} = useDroppable({ + id: props.id, + }); + const style = { + color: isOver ? 'green' : undefined, + }; + + + return ( +
+ {props.children} +
+ ); +} + +export default function App() { + const containers = ['A', 'B', 'C']; + const [parent, setParent] = useState(null); + const draggableMarkup = ( + Drag me + ); + + return ( + + {parent === null ? draggableMarkup : null} + + {containers.map((id) => ( + // We updated the Droppable component so it would accept an `id` + // prop and pass it to `useDroppable` + + {parent === id ? draggableMarkup : 'Drop here'} + + ))} + + ); + + function handleDragEnd(event) { + const {over} = event; + + // If the item is dropped over a container, set it as the parent + // otherwise reset the parent to `null` + setParent(over ? over.id : null); + } +}; diff --git a/packages/client/src/schema-component/hooks/index.ts b/packages/client/src/schema-component/hooks/index.ts new file mode 100644 index 000000000..3c41670c4 --- /dev/null +++ b/packages/client/src/schema-component/hooks/index.ts @@ -0,0 +1,3 @@ +export * from './useAttach'; +export * from './useDesignable'; +export * from './useFieldProps'; diff --git a/packages/client/src/schema-component/hooks/useAttach.ts b/packages/client/src/schema-component/hooks/useAttach.ts new file mode 100644 index 000000000..fb5b55c86 --- /dev/null +++ b/packages/client/src/schema-component/hooks/useAttach.ts @@ -0,0 +1,21 @@ +import { useRef, useEffect } from 'react'; + +interface IRecycleTarget { + onMount: () => void; + onUnmount: () => void; +} + +export const useAttach = (target: T): T => { + const oldTargetRef = useRef(null); + useEffect(() => { + if (oldTargetRef.current && target !== oldTargetRef.current) { + oldTargetRef.current.onUnmount(); + } + oldTargetRef.current = target; + target.onMount(); + return () => { + target.onUnmount(); + }; + }, [target]); + return target; +}; diff --git a/packages/client/src/schema-component/hooks/useDesignable.tsx b/packages/client/src/schema-component/hooks/useDesignable.tsx new file mode 100644 index 000000000..8064d1689 --- /dev/null +++ b/packages/client/src/schema-component/hooks/useDesignable.tsx @@ -0,0 +1,278 @@ +import React, { useContext } from 'react'; +import { ISchema, Schema, useField, useFieldSchema } from '@formily/react'; +import { SchemaComponentContext } from '../context'; +import set from 'lodash/set'; +import { uid } from '@formily/shared'; + +interface CreateDesignableProps { + current: Schema; +} + +export function createDesignable(options: CreateDesignableProps) { + return new Designable(options); +} + +/** + * + */ +type Position = 'beforeBegin' | 'afterBegin' | 'beforeEnd' | 'afterEnd'; + +const generateUid = (s: ISchema) => { + if (!s['x-uid']) { + s['x-uid'] = uid(); + } + Object.keys(s.properties || {}).forEach((key) => { + generateUid(s.properties[key]); + }); +}; + +export class Designable { + current: Schema; + + events = {}; + + constructor({ current }) { + this.current = current; + } + + prepareProperty(schema: ISchema) { + if (!schema.type) { + schema.type = 'void'; + } + if (!schema.name) { + schema.name = uid(); + } + // x-uid 仅用于后端查询 schema,如果 current 没有 x-uid 不处理 + if (!this.current['x-uid']) { + return; + } + // if (Schema.isSchemaInstance(schema)) { + // return; + // } + generateUid(schema); + } + + on(name: 'afterInsertAdjacent' | 'afterRemove', listener: any) { + if (!this.events[name]) { + this.events[name] = []; + } + this.events[name].push(listener); + } + + emit(name: 'afterInsertAdjacent' | 'afterRemove', ...args) { + if (!this.events[name]) { + return; + } + this.events[name].forEach((fn) => fn.bind(this)(...args)); + } + + insertAdjacent(position: Position, schema: ISchema) { + switch (position) { + case 'beforeBegin': + return this.insertBeforeBegin(schema); + case 'afterBegin': + return this.insertAfterBegin(schema); + case 'beforeEnd': + return this.insertBeforeEnd(schema); + case 'afterEnd': + return this.insertAfterEnd(schema); + } + } + + remove() { + const s = this.current.parent.removeProperty(this.current.name); + this.emit('afterRemove', s); + } + + insertBeforeBeginOrAfterEnd(schema: ISchema) { + if (!Schema.isSchemaInstance(this.current)) { + return; + } + if (!Schema.isSchemaInstance(schema)) { + return; + } + if (this.current.parent !== schema.parent) { + return; + } + let fromIndex = 0; + let toIndex = 0; + this.current.parent.mapProperties((property, key, index) => { + if (this.current.name === key) { + toIndex = index; + } + if (schema.name === key) { + fromIndex = index; + } + }); + return fromIndex > toIndex ? this.insertBeforeBegin(schema) : this.insertAfterEnd(schema); + } + + /** + * Before the current schema itself. + */ + insertBeforeBegin(schema: ISchema) { + if (!Schema.isSchemaInstance(this.current)) { + return; + } + const properties = {}; + let start = false; + + if (Schema.isSchemaInstance(schema)) { + schema.parent.removeProperty(schema.name); + schema.parent = this.current.parent; + } + + this.current.parent.mapProperties((property, key) => { + if (key === this.current.name) { + start = true; + } + if (start) { + properties[key] = property; + this.current.parent.removeProperty(key); + } + }); + + this.prepareProperty(schema); + const s = this.current.parent.addProperty(schema.name, schema); + this.current.parent.setProperties(properties); + this.emit('afterInsertAdjacent', 'beforeBegin', s); + } + + /** + * Just inside the current schema, before its first child. + * + * @param schema + * @returns + */ + insertAfterBegin(schema: ISchema) { + if (!Schema.isSchemaInstance(this.current)) { + return; + } + if (Schema.isSchemaInstance(schema)) { + schema.parent.removeProperty(schema.name); + schema.parent = this.current; + } + const properties = {}; + this.current.mapProperties((schema, key) => { + properties[key] = schema; + }); + this.current.properties = {}; + this.prepareProperty(schema); + const s = this.current.addProperty(schema.name, schema); + this.current.setProperties(properties); + this.emit('afterInsertAdjacent', 'afterBegin', s); + } + + /** + * Just inside the targetElement, after its last child. + * + * @param schema + * @returns + */ + insertBeforeEnd(schema: ISchema) { + if (!Schema.isSchemaInstance(this.current)) { + return; + } + if (Schema.isSchemaInstance(schema)) { + schema.parent.removeProperty(schema.name); + schema.parent = this.current; + } + this.prepareProperty(schema); + const s = this.current.addProperty(schema.name || uid(), schema); + this.emit('afterInsertAdjacent', 'beforeEnd', s); + } + + /** + * After the current schema itself. + */ + insertAfterEnd(schema: ISchema) { + if (!Schema.isSchemaInstance(this.current)) { + return; + } + const properties = {}; + let start = false; + + if (Schema.isSchemaInstance(schema)) { + schema.parent.removeProperty(schema.name); + schema.parent = this.current.parent; + } + + this.current.parent.mapProperties((property, key) => { + if (key === this.current.name) { + start = true; + } + if (start && key !== this.current.name) { + properties[key] = property; + this.current.parent.removeProperty(key); + } + }); + + this.prepareProperty(schema); + const s = this.current.parent.addProperty(schema.name || uid(), schema); + this.current.parent.setProperties(properties); + this.emit('afterInsertAdjacent', 'afterEnd', s); + } +} + +// TODO +export function useDesignable() { + const { designable, refresh, reset } = useContext(SchemaComponentContext); + const DesignableBar = () => { + return <>; + }; + const field = useField(); + const fieldSchema = useFieldSchema(); + const dn = createDesignable({ current: fieldSchema }); + dn.on('afterInsertAdjacent', refresh); + dn.on('afterRemove', refresh); + return { + designable, + reset, + refresh, + DesignableBar, + on: dn.on.bind(dn), + // TODO + patch: (key: ISchema | string, value?: any) => { + const update = (obj: any) => { + Object.keys(obj).forEach((k) => { + const val = obj[k]; + if (k === 'title') { + field.title = val; + fieldSchema['title'] = val; + } + if (k === 'x-component-props') { + Object.keys(val).forEach((i) => { + field.componentProps[i] = val[i]; + fieldSchema['x-component-props'][i] = val[i]; + }); + } + }); + }; + if (typeof key === 'string') { + const obj = {}; + set(obj, key, value); + return update(obj); + } + update(key); + refresh(); + }, + remove() { + dn.remove(); + }, + insertAdjacent(position: Position, schema: ISchema) { + dn.insertAdjacent(position, schema); + }, + insertBeforeBegin(schema: ISchema) { + dn.insertBeforeBegin(schema); + }, + insertAfterBegin(schema: ISchema) { + dn.insertAfterBegin(schema); + }, + insertBeforeEnd(schema: ISchema) { + dn.insertBeforeEnd(schema); + }, + insertAfterEnd(schema: ISchema) { + dn.insertAfterEnd(schema); + }, + }; +} diff --git a/packages/client/src/schema-component/hooks/useFieldProps.ts b/packages/client/src/schema-component/hooks/useFieldProps.ts new file mode 100644 index 000000000..ca494bcb4 --- /dev/null +++ b/packages/client/src/schema-component/hooks/useFieldProps.ts @@ -0,0 +1,18 @@ +import { useContext, useRef } from 'react'; +import { Schema, SchemaExpressionScopeContext, SchemaOptionsContext } from '@formily/react'; + +export const useFieldProps = (schema: Schema) => { + const options = useContext(SchemaOptionsContext); + const scope = useContext(SchemaExpressionScopeContext); + const scopeRef = useRef(); + scopeRef.current = scope; + return schema.toFieldProps({ + ...options, + get scope() { + return { + ...options.scope, + ...scopeRef.current, + }; + }, + }) as any; +}; diff --git a/packages/client/src/schema-component/index.md b/packages/client/src/schema-component/index.md new file mode 100644 index 000000000..4eb18d482 --- /dev/null +++ b/packages/client/src/schema-component/index.md @@ -0,0 +1,82 @@ +--- +nav: + path: /client +group: + path: /client +--- + +# SchemaComponent + +## Components + +### SchemaComponentProvider + +### SchemaComponent + +### RecursionComponent + +## Hooks + +### useDesignable() + +获取当前 schema 节点设计器的 API + +```ts +const { + designable, // 是否可以配置 + patch, // 更新当前节点配置 + remove, // 移除当前节点 + insertAdjacent, // 在某位置插入,四个位置:beforeBegin、afterBegin、beforeEnd、afterEnd + insertBeforeBegin, // 在当前节点的前面插入 + insertAfterBegin, // 在当前节点的第一个子节点前面插入 + insertBeforeEnd, // 在当前节点的最后一个子节点后面 + insertAfterEnd, // 在当前节点的后面 +} = useDesignable(); + +const schema = { + name: uid(), + 'x-component': 'Hello', +}; + +// 在当前节点的前面插入 +insertBeforeBegin(schema); +// 等同于 +insertAdjacent('beforeBegin', schema); + +// 在当前节点的第一个子节点前面插入 +insertAfterBegin(schema); +// 等同于 +insertAdjacent('afterBegin', schema); + +// 在当前节点的最后一个子节点后面 +insertBeforeEnd(schema); +// 等同于 +insertAdjacent('beforeEnd', schema); + +// 在当前节点的后面 +insertAfterEnd(schema); +// 等同于 +insertAdjacent('afterEnd', schema); +``` + +几个插入的位置: + +```ts +{ + properties: { + // beforeBegin 在当前节点的前面插入 + node1: { + properties: { + // afterBegin 在当前节点的第一个子节点前面插入 + // ... + // beforeEnd 在当前节点的最后一个子节点后面 + }, + }, + // afterEnd 在当前节点的后面 + }, +} +``` + +## Examples + + diff --git a/packages/client/src/schema-component/index.tsx b/packages/client/src/schema-component/index.tsx new file mode 100644 index 000000000..27598b243 --- /dev/null +++ b/packages/client/src/schema-component/index.tsx @@ -0,0 +1,4 @@ +export * from './components'; +export * from './context'; +export * from './hooks'; +export * from './types'; diff --git a/packages/client/src/schema-component/types.ts b/packages/client/src/schema-component/types.ts new file mode 100644 index 000000000..d5aad72ce --- /dev/null +++ b/packages/client/src/schema-component/types.ts @@ -0,0 +1,38 @@ +import React, { createContext, useContext, useMemo, useState } from 'react'; +import { uid } from '@formily/shared'; +import { createForm, Form } from '@formily/core'; +import { useCookieState } from 'ahooks'; +import { useTranslation } from 'react-i18next'; +import { + Schema, + FormProvider, + RecursionField, + createSchemaField, + IRecursionFieldProps, + ISchemaFieldProps, + SchemaOptionsContext, + SchemaReactComponents, + SchemaExpressionScopeContext, +} from '@formily/react'; + +export interface ISchemaComponentContext { + scope?: any; + components?: SchemaReactComponents; + refresh?: () => void; + refreshFormId?: () => void; + reset?: () => void; + designable?: boolean; + setDesignable?: (value: boolean) => void; + SchemaField?: React.FC; +} + +export interface ISchemaComponentProvider { + form?: Form; + scope?: any; + components?: SchemaReactComponents; +} + +export interface IRecursionComponentProps extends IRecursionFieldProps { + scope?: any; + components?: SchemaReactComponents; +} diff --git a/packages/client/src/schema-initializer/index.md b/packages/client/src/schema-initializer/index.md new file mode 100644 index 000000000..d6b58c14d --- /dev/null +++ b/packages/client/src/schema-initializer/index.md @@ -0,0 +1,48 @@ +--- +nav: + path: /client +group: + path: /client +--- + +# SchemaInitializer 待定 + +用于配置各种 schema 的初始化 + +```tsx | pure +const actions = { + // 表单可选操作 + FormAction: [], + // 抽屉表单可选操作 + DrawerFormAction: [], + // 对话框表单可选操作 + ModalFormAction: [], + // 详情区块可选操作 + DetailsAction: [], + // 表格区块可选操作 + TableAction: [], + // 表格行可选操作 + TableRowAction: [], + // 日历可选操作 + CalendarAction: [], +}; + +const blocks = { + // 普通页面可添加区块 + Block: [], + // 当前数据页面可添加区块 + RecordBlock: [], + // 可添加的表单项 + FormItem: [], + // 可添加的表格列 + TableColumn: [], +}; + +const initializer = new SchemaInitializer({ actions, blocks }); + +initializer.addActionSchema({}); +initializer.addBlockSchema({}); + + + +``` diff --git a/packages/client/src/select/index.md b/packages/client/src/select/index.md new file mode 100644 index 000000000..bce3c6042 --- /dev/null +++ b/packages/client/src/select/index.md @@ -0,0 +1,8 @@ +--- +nav: + path: /client +group: + path: /schema-components +--- + +# Select 待定 diff --git a/packages/client/src/settings-form/index.md b/packages/client/src/settings-form/index.md new file mode 100644 index 000000000..0ce034ec9 --- /dev/null +++ b/packages/client/src/settings-form/index.md @@ -0,0 +1,8 @@ +--- +nav: + path: /client +group: + path: /client +--- + +# SettingsForm 待定 diff --git a/packages/client/src/sub-table/index.md b/packages/client/src/sub-table/index.md new file mode 100644 index 000000000..71c2879f0 --- /dev/null +++ b/packages/client/src/sub-table/index.md @@ -0,0 +1,8 @@ +--- +nav: + path: /client +group: + path: /schema-components +--- + +# SubTable 待定 diff --git a/packages/client/src/system-settings/index.md b/packages/client/src/system-settings/index.md new file mode 100644 index 000000000..eccd0bf7b --- /dev/null +++ b/packages/client/src/system-settings/index.md @@ -0,0 +1,15 @@ +--- +nav: + path: /client +group: + path: /client +--- + +# SystemSettings 待定 + +## SystemSettingsProvider + +## SystemSettingsAction + +## useSystemSettings + diff --git a/packages/client/src/system-settings/index.tsx b/packages/client/src/system-settings/index.tsx new file mode 100644 index 000000000..d398413d3 --- /dev/null +++ b/packages/client/src/system-settings/index.tsx @@ -0,0 +1,3 @@ +export function SystemSettings() { + +} \ No newline at end of file diff --git a/packages/client/src/table/index.md b/packages/client/src/table/index.md new file mode 100644 index 000000000..ea59c0eef --- /dev/null +++ b/packages/client/src/table/index.md @@ -0,0 +1,16 @@ +--- +nav: + path: /client +group: + path: /schema-components +--- + +# Table 待定 + +- Table +- Table.Column + - Table.SortHandle + - Table.Index +- Table.Pagination +- Table.ActionBar +- Table.Filter diff --git a/packages/client/src/tabs/index.md b/packages/client/src/tabs/index.md new file mode 100644 index 000000000..b97a90eb3 --- /dev/null +++ b/packages/client/src/tabs/index.md @@ -0,0 +1,11 @@ +--- +nav: + path: /client +group: + path: /schema-components +--- + +# Tabs + +- Tabs +- Tabs.TabPane diff --git a/packages/client/src/time-picker/index.md b/packages/client/src/time-picker/index.md new file mode 100644 index 000000000..e9f78211a --- /dev/null +++ b/packages/client/src/time-picker/index.md @@ -0,0 +1,8 @@ +--- +nav: + path: /client +group: + path: /schema-components +--- + +# TimePicker diff --git a/packages/client/src/tree-select/index.md b/packages/client/src/tree-select/index.md new file mode 100644 index 000000000..952499987 --- /dev/null +++ b/packages/client/src/tree-select/index.md @@ -0,0 +1,8 @@ +--- +nav: + path: /client +group: + path: /schema-components +--- + +# TreeSelect diff --git a/packages/client/src/upload/index.md b/packages/client/src/upload/index.md new file mode 100644 index 000000000..78a85f3f2 --- /dev/null +++ b/packages/client/src/upload/index.md @@ -0,0 +1,8 @@ +--- +nav: + path: /client +group: + path: /schema-components +--- + +# Upload diff --git a/packages/client/tsconfig.build.json b/packages/client/tsconfig.build.json index 675427486..509526e2c 100644 --- a/packages/client/tsconfig.build.json +++ b/packages/client/tsconfig.build.json @@ -7,5 +7,5 @@ "target": "es5" }, "include": ["./src/**/*.ts", "./src/**/*.tsx"], - "exclude": ["./src/__tests__/*", "./esm/*", "./lib/*"] -} \ No newline at end of file + "exclude": ["./src/__tests__/*", "./src/*/demos/*", "./esm/*", "./lib/*"] +} diff --git a/packages/client/tsconfig.json b/packages/client/tsconfig.json index e10a5305a..7a3f8d014 100644 --- a/packages/client/tsconfig.json +++ b/packages/client/tsconfig.json @@ -1,5 +1,8 @@ { "extends": "../../tsconfig.json", + "compilerOptions": { + "resolveJsonModule": true + }, "include": ["./src/**/*.ts", "./src/**/*.tsx"], "exclude": ["./esm/*", "./lib/*"] } \ No newline at end of file diff --git a/tsconfig.build.json b/tsconfig.build.json index bd2ed6f61..6e6850961 100644 --- a/tsconfig.build.json +++ b/tsconfig.build.json @@ -1,6 +1,7 @@ { "compilerOptions": { "esModuleInterop": true, + "resolveJsonModule": true, "moduleResolution": "node", "jsx": "react", "module": "commonjs", diff --git a/tsconfig.jest.json b/tsconfig.jest.json index e9472c90a..99237bad7 100644 --- a/tsconfig.jest.json +++ b/tsconfig.jest.json @@ -3,6 +3,7 @@ "compilerOptions": { "jsx": "react", "esModuleInterop": true, + "resolveJsonModule": true, "moduleResolution": "node", "allowJs": true, "module": "commonjs", diff --git a/tsconfig.json b/tsconfig.json index cb065f827..ba9315620 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -11,6 +11,7 @@ "skipLibCheck": true, "sourceMap": true, "inlineSources": true, + "resolveJsonModule": true, "declaration": true, "experimentalDecorators": true, "downlevelIteration": true, diff --git a/yarn.lock b/yarn.lock index e8fd1e521..d748f9391 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2,6 +2,40 @@ # yarn lockfile v1 +"@ant-design/colors@^6.0.0": + version "6.0.0" + resolved "https://registry.npmjs.org/@ant-design/colors/-/colors-6.0.0.tgz#9b9366257cffcc47db42b9d0203bb592c13c0298" + integrity sha512-qAZRvPzfdWHtfameEGP2Qvuf838NhergR35o+EuVyB5XvSA98xod5r4utvi4TJ3ywmevm290g9nsCG5MryrdWQ== + dependencies: + "@ctrl/tinycolor" "^3.4.0" + +"@ant-design/icons-svg@^4.2.1": + version "4.2.1" + resolved "https://registry.npmjs.org/@ant-design/icons-svg/-/icons-svg-4.2.1.tgz#8630da8eb4471a4aabdaed7d1ff6a97dcb2cf05a" + integrity sha512-EB0iwlKDGpG93hW8f85CTJTs4SvMX7tt5ceupvhALp1IF44SeUFOMhKUOYqpsoYWQKAOuTRDMqn75rEaKDp0Xw== + +"@ant-design/icons@^4.0.0", "@ant-design/icons@^4.7.0": + version "4.7.0" + resolved "https://registry.npmjs.org/@ant-design/icons/-/icons-4.7.0.tgz#8c3cbe0a556ba92af5dc7d1e70c0b25b5179af0f" + integrity sha512-aoB4Z7JA431rt6d4u+8xcNPPCrdufSRMUOpxa1ab6mz1JCQZOEVolj2WVs/tDFmN62zzK30mNelEsprLYsSF3g== + dependencies: + "@ant-design/colors" "^6.0.0" + "@ant-design/icons-svg" "^4.2.1" + "@babel/runtime" "^7.11.2" + classnames "^2.2.6" + rc-util "^5.9.4" + +"@ant-design/react-slick@~0.28.1": + version "0.28.4" + resolved "https://registry.npmjs.org/@ant-design/react-slick/-/react-slick-0.28.4.tgz#8b296b87ad7c7ae877f2a527b81b7eebd9dd29a9" + integrity sha512-j9eAHTn7GxbXUFNknJoHS2ceAsqrQi2j8XykjZE1IXCD8kJF+t28EvhBLniDpbOsBk/3kjalnhriTfZcjBHNqg== + dependencies: + "@babel/runtime" "^7.10.4" + classnames "^2.2.5" + json2mq "^0.2.0" + lodash "^4.17.21" + resize-observer-polyfill "^1.5.0" + "@babel/code-frame@7.12.11": version "7.12.11" resolved "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.12.11.tgz#f4ad435aa263db935b8f10f2c552d23fb716a63f" @@ -16,6 +50,13 @@ dependencies: "@babel/highlight" "^7.16.0" +"@babel/code-frame@^7.10.4": + version "7.16.7" + resolved "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.16.7.tgz#44416b6bd7624b998f5b1af5d470856c40138789" + integrity sha512-iAXqUn8IIeBTNd72xsFlgaXHkMBMt6y4HJp1tIaK465CWLT/fG1aqB7ykr95gHHmlBdGbFeWWfyB4NJJ0nmeIg== + dependencies: + "@babel/highlight" "^7.16.7" + "@babel/compat-data@^7.13.11", "@babel/compat-data@^7.16.0": version "7.16.0" resolved "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.16.0.tgz#ea269d7f78deb3a7826c39a4048eecda541ebdaa" @@ -180,6 +221,11 @@ resolved "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.14.5.tgz#5ac822ce97eec46741ab70a517971e443a70c5a9" integrity sha512-/37qQCE3K0vvZKwoK4XU/irIJQdIfCJuhU5eKnNxpFDsOkgFaUAwbv+RYw6eYgsC0E4hS7r5KqGULUogqui0fQ== +"@babel/helper-plugin-utils@^7.16.5": + version "7.16.5" + resolved "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.16.5.tgz#afe37a45f39fce44a3d50a7958129ea5b1a5c074" + integrity sha512-59KHWHXxVA9K4HNF4sbHCf+eJeFe0Te/ZFGqBT4OjXhrwvA04sGfaEGsVTdsjoszq0YTP49RC9UKe5g8uN2RwQ== + "@babel/helper-remap-async-to-generator@^7.16.0": version "7.16.0" resolved "https://registry.npmjs.org/@babel/helper-remap-async-to-generator/-/helper-remap-async-to-generator-7.16.0.tgz#d5aa3b086e13a5fe05238ff40c3a5a0c2dab3ead" @@ -225,6 +271,11 @@ resolved "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.15.7.tgz#220df993bfe904a4a6b02ab4f3385a5ebf6e2389" integrity sha512-K4JvCtQqad9OY2+yTU8w+E82ywk/fe+ELNlt1G8z3bVGlZfn/hOcQQsUhGhW/N+tb3fxK800wLtKOE/aM0m72w== +"@babel/helper-validator-identifier@^7.16.7": + version "7.16.7" + resolved "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.16.7.tgz#e8c602438c4a8195751243da9031d1607d247cad" + integrity sha512-hsEnFemeiW4D08A5gUAZxLBTXpZ39P+a+DGDsHw1yxqyQ/jzFEnxf5uTEGp+3bzAbNOxU1paTgYS4ECU/IgfDw== + "@babel/helper-validator-option@^7.14.5": version "7.14.5" resolved "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.14.5.tgz#6e72a1fff18d5dfcb878e1e62f1a021c4b72d5a3" @@ -258,6 +309,15 @@ chalk "^2.0.0" js-tokens "^4.0.0" +"@babel/highlight@^7.16.7": + version "7.16.7" + resolved "https://registry.npmjs.org/@babel/highlight/-/highlight-7.16.7.tgz#81a01d7d675046f0d96f82450d9d9578bdfd6b0b" + integrity sha512-aKpPMfLvGO3Q97V0qhw/V2SWNWlwfJknuwAunU7wZLSfrM4xTBvg7E5opUVi1kJTBKihE38CPg4nBiqX83PWYw== + dependencies: + "@babel/helper-validator-identifier" "^7.16.7" + chalk "^2.0.0" + js-tokens "^4.0.0" + "@babel/parser@^7.1.0", "@babel/parser@^7.1.6", "@babel/parser@^7.14.7", "@babel/parser@^7.16.0", "@babel/parser@^7.16.3": version "7.16.3" resolved "https://registry.npmjs.org/@babel/parser/-/parser-7.16.3.tgz#271bafcb811080905a119222edbc17909c82261d" @@ -470,6 +530,13 @@ dependencies: "@babel/helper-plugin-utils" "^7.8.0" +"@babel/plugin-syntax-jsx@^7.12.13": + version "7.16.5" + resolved "https://registry.npmjs.org/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.16.5.tgz#bf255d252f78bc8b77a17cadc37d1aa5b8ed4394" + integrity sha512-42OGssv9NPk4QHKVgIHlzeLgPOW5rGgfV5jzG90AhcXXIv6hu/eqj63w4VgvRxdvZY3AlYeDgPiSJ3BqAd1Y6Q== + dependencies: + "@babel/helper-plugin-utils" "^7.16.5" + "@babel/plugin-syntax-logical-assignment-operators@^7.10.4", "@babel/plugin-syntax-logical-assignment-operators@^7.8.3": version "7.10.4" resolved "https://registry.npmjs.org/@babel/plugin-syntax-logical-assignment-operators/-/plugin-syntax-logical-assignment-operators-7.10.4.tgz#ca91ef46303530448b906652bac2e9fe9941f699" @@ -932,6 +999,13 @@ dependencies: regenerator-runtime "^0.13.4" +"@babel/runtime@^7.1.5", "@babel/runtime@^7.10.2", "@babel/runtime@^7.10.4", "@babel/runtime@^7.13.10", "@babel/runtime@^7.14.5", "@babel/runtime@^7.2.0", "@babel/runtime@^7.7.2": + version "7.16.5" + resolved "https://registry.npmjs.org/@babel/runtime/-/runtime-7.16.5.tgz#7f3e34bf8bdbbadf03fbb7b1ea0d929569c9487a" + integrity sha512-TXWihFIS3Pyv5hzR7j6ihmeLkZfrXGxAr5UfSl8CHf+6q/wpiYDkUau0czckpYG8QmnCIuPpdLtuA9VmuGGyMA== + dependencies: + regenerator-runtime "^0.13.4" + "@babel/template@^7.16.0", "@babel/template@^7.3.3": version "7.16.0" resolved "https://registry.npmjs.org/@babel/template/-/template-7.16.0.tgz#d16a35ebf4cd74e202083356fab21dd89363ddd6" @@ -987,6 +1061,123 @@ resolved "https://registry.npmjs.org/@csstools/convert-colors/-/convert-colors-1.4.0.tgz#ad495dc41b12e75d588c6db8b9834f08fa131eb7" integrity sha512-5a6wqoJV/xEdbRNKVo6I4hO3VjyDq//8q2f9I6PBAvMesJHFauXDorcNCsr9RzvsZnaWi5NYCcfyqP1QeFHFbw== +"@ctrl/tinycolor@^3.4.0": + version "3.4.0" + resolved "https://registry.npmjs.org/@ctrl/tinycolor/-/tinycolor-3.4.0.tgz#c3c5ae543c897caa9c2a68630bed355be5f9990f" + integrity sha512-JZButFdZ1+/xAfpguQHoabIXkcqRRKpMrWKBkpEZZyxfY9C1DpADFB8PEqGSTeFr135SaTRfKqGKx5xSCLI7ZQ== + +"@dnd-kit/accessibility@^3.0.0": + version "3.0.0" + resolved "https://registry.npmjs.org/@dnd-kit/accessibility/-/accessibility-3.0.0.tgz#b56e3750414fd907b7d6972b3116aa8f96d07fde" + integrity sha512-QwaQ1IJHQHMMuAGOOYHQSx7h7vMZPfO97aDts8t5N/MY7n2QTDSnW+kF7uRQ1tVBkr6vJ+BqHWG5dlgGvwVjow== + dependencies: + tslib "^2.0.0" + +"@dnd-kit/core@^4.0.3": + version "4.0.3" + resolved "https://registry.npmjs.org/@dnd-kit/core/-/core-4.0.3.tgz#49abe3c9b481b6e07909df1781e88b20f3dd25b0" + integrity sha512-uT1uHZxKx3iEkupmLfknMIvbykMJSetoXXmra6sGGvtWy+OMKrWm3axH2c90+JC/q6qaeKs2znd3Qs8GLnCa5Q== + dependencies: + "@dnd-kit/accessibility" "^3.0.0" + "@dnd-kit/utilities" "^3.0.1" + tslib "^2.0.0" + +"@dnd-kit/sortable@^5.1.0": + version "5.1.0" + resolved "https://registry.npmjs.org/@dnd-kit/sortable/-/sortable-5.1.0.tgz#f30ec12c95ca5aa90e2e4d9ef3dbe16b3eb26d69" + integrity sha512-CPyiUHbTrSYzhddfgdeoX0ERg/dEyVKIWx9+4O6uqpoppo84SXCBHVFiFBRVpQ9wtpsXs7prtUAnAUTcvFQTZg== + dependencies: + "@dnd-kit/utilities" "^3.0.0" + tslib "^2.0.0" + +"@dnd-kit/utilities@^3.0.0", "@dnd-kit/utilities@^3.0.1": + version "3.0.2" + resolved "https://registry.npmjs.org/@dnd-kit/utilities/-/utilities-3.0.2.tgz#24fd796491a85c2904e9c97f1fdb42005df645f2" + integrity sha512-J4WpZXKbLJzBkuALqsIy5KmQr6PQk86ixoPKoixzjWj1+XGE5KdA2vga9Vf43EB/Ewpng+E5SmXVLfTs7ukbhw== + dependencies: + tslib "^2.0.0" + +"@emotion/babel-plugin@^11.7.1": + version "11.7.1" + resolved "https://registry.npmjs.org/@emotion/babel-plugin/-/babel-plugin-11.7.1.tgz#853fc4985d89dab0ea8e17af2858473d1b11be7e" + integrity sha512-K3/6Y+J/sIAjplf3uIteWLhPuOyuMNnE+iyYnTF/m294vc6IL90kTHp7y8ldZYbpKlP17rpOWDKM9DvTcrOmNQ== + dependencies: + "@babel/helper-module-imports" "^7.12.13" + "@babel/plugin-syntax-jsx" "^7.12.13" + "@babel/runtime" "^7.13.10" + "@emotion/hash" "^0.8.0" + "@emotion/memoize" "^0.7.5" + "@emotion/serialize" "^1.0.2" + babel-plugin-macros "^2.6.1" + convert-source-map "^1.5.0" + escape-string-regexp "^4.0.0" + find-root "^1.1.0" + source-map "^0.5.7" + stylis "4.0.13" + +"@emotion/cache@^11.7.1": + version "11.7.1" + resolved "https://registry.npmjs.org/@emotion/cache/-/cache-11.7.1.tgz#08d080e396a42e0037848214e8aa7bf879065539" + integrity sha512-r65Zy4Iljb8oyjtLeCuBH8Qjiy107dOYC6SJq7g7GV5UCQWMObY4SJDPGFjiiVpPrOJ2hmJOoBiYTC7hwx9E2A== + dependencies: + "@emotion/memoize" "^0.7.4" + "@emotion/sheet" "^1.1.0" + "@emotion/utils" "^1.0.0" + "@emotion/weak-memoize" "^0.2.5" + stylis "4.0.13" + +"@emotion/css@^11.7.1": + version "11.7.1" + resolved "https://registry.npmjs.org/@emotion/css/-/css-11.7.1.tgz#516b717340d36b0bbd2304ba7e1a090e866f8acc" + integrity sha512-RUUgPlMZunlc7SE5A6Hg+VWRzb2cU6O9xlV78KCFgcnl25s7Qz/20oQg71iKudpLqk7xj0vhbJlwcJJMT0BOZg== + dependencies: + "@emotion/babel-plugin" "^11.7.1" + "@emotion/cache" "^11.7.1" + "@emotion/serialize" "^1.0.0" + "@emotion/sheet" "^1.0.3" + "@emotion/utils" "^1.0.0" + +"@emotion/hash@^0.8.0": + version "0.8.0" + resolved "https://registry.npmjs.org/@emotion/hash/-/hash-0.8.0.tgz#bbbff68978fefdbe68ccb533bc8cbe1d1afb5413" + integrity sha512-kBJtf7PH6aWwZ6fka3zQ0p6SBYzx4fl1LoZXE2RrnYST9Xljm7WfKJrU4g/Xr3Beg72MLrp1AWNUmuYJTL7Cow== + +"@emotion/memoize@^0.7.4", "@emotion/memoize@^0.7.5": + version "0.7.5" + resolved "https://registry.npmjs.org/@emotion/memoize/-/memoize-0.7.5.tgz#2c40f81449a4e554e9fc6396910ed4843ec2be50" + integrity sha512-igX9a37DR2ZPGYtV6suZ6whr8pTFtyHL3K/oLUotxpSVO2ASaprmAe2Dkq7tBo7CRY7MMDrAa9nuQP9/YG8FxQ== + +"@emotion/serialize@^1.0.0", "@emotion/serialize@^1.0.2": + version "1.0.2" + resolved "https://registry.npmjs.org/@emotion/serialize/-/serialize-1.0.2.tgz#77cb21a0571c9f68eb66087754a65fa97bfcd965" + integrity sha512-95MgNJ9+/ajxU7QIAruiOAdYNjxZX7G2mhgrtDWswA21VviYIRP1R5QilZ/bDY42xiKsaktP4egJb3QdYQZi1A== + dependencies: + "@emotion/hash" "^0.8.0" + "@emotion/memoize" "^0.7.4" + "@emotion/unitless" "^0.7.5" + "@emotion/utils" "^1.0.0" + csstype "^3.0.2" + +"@emotion/sheet@^1.0.3", "@emotion/sheet@^1.1.0": + version "1.1.0" + resolved "https://registry.npmjs.org/@emotion/sheet/-/sheet-1.1.0.tgz#56d99c41f0a1cda2726a05aa6a20afd4c63e58d2" + integrity sha512-u0AX4aSo25sMAygCuQTzS+HsImZFuS8llY8O7b9MDRzbJM0kVJlAz6KNDqcG7pOuQZJmj/8X/rAW+66kMnMW+g== + +"@emotion/unitless@^0.7.5": + version "0.7.5" + resolved "https://registry.npmjs.org/@emotion/unitless/-/unitless-0.7.5.tgz#77211291c1900a700b8a78cfafda3160d76949ed" + integrity sha512-OWORNpfjMsSSUBVrRBVGECkhWcULOAJz9ZW8uK9qgxD+87M7jHRcvh/A96XXNhXTLmKcoYSQtBEX7lHMO7YRwg== + +"@emotion/utils@^1.0.0": + version "1.0.0" + resolved "https://registry.npmjs.org/@emotion/utils/-/utils-1.0.0.tgz#abe06a83160b10570816c913990245813a2fd6af" + integrity sha512-mQC2b3XLDs6QCW+pDQDiyO/EdGZYOygE8s5N5rrzjSI4M3IejPE/JPndCBwRT9z982aqQNi6beWs1UeayrQxxA== + +"@emotion/weak-memoize@^0.2.5": + version "0.2.5" + resolved "https://registry.npmjs.org/@emotion/weak-memoize/-/weak-memoize-0.2.5.tgz#8eed982e2ee6f7f4e44c253e12962980791efd46" + integrity sha512-6U71C2Wp7r5XtFtQzYrW5iKFT67OixrSxjI4MptCHzdSVlgabczzqLe0ZSgnub/5Kp4hSbpDB1tMytZY9pwxxA== + "@eslint/eslintrc@^0.4.3": version "0.4.3" resolved "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-0.4.3.tgz#9e42981ef035beb3dd49add17acb96e8ff6f394c" @@ -1002,6 +1193,100 @@ minimatch "^3.0.4" strip-json-comments "^3.1.1" +"@formily/antd@^2.0.7": + version "2.0.7" + resolved "https://registry.npmjs.org/@formily/antd/-/antd-2.0.7.tgz#9d90e3f47c976719c0f31586b52318e2eed18bcf" + integrity sha512-XLpWxf2gbodDkcUVrUvrB7uqW7rdcHa5v/8uRgXAM/KwRTTez3PU8+nWZGIvm9btEafEjgNVUgvGGcYg/35lIw== + dependencies: + "@ant-design/icons" "^4.0.0" + "@formily/core" "2.0.7" + "@formily/grid" "2.0.7" + "@formily/json-schema" "2.0.7" + "@formily/react" "2.0.7" + "@formily/reactive" "2.0.7" + "@formily/reactive-react" "2.0.7" + "@formily/shared" "2.0.7" + classnames "^2.2.6" + react-sortable-hoc "^1.11.0" + react-sticky-box "^0.9.3" + +"@formily/core@2.0.7", "@formily/core@^2.0.7": + version "2.0.7" + resolved "https://registry.npmjs.org/@formily/core/-/core-2.0.7.tgz#63165cae79dafdd5f92291b16a8d58b854d1ec2d" + integrity sha512-fh6V5kqZ35Qq10aCNjbIcJE0Dwsl0KmcZJi1kNRh4iK45nC9KUeeYp/WtgRLs6yf6MHaCO/GCN3cB/g+fQwf7A== + dependencies: + "@formily/reactive" "2.0.7" + "@formily/shared" "2.0.7" + "@formily/validator" "2.0.7" + +"@formily/grid@2.0.7": + version "2.0.7" + resolved "https://registry.npmjs.org/@formily/grid/-/grid-2.0.7.tgz#e7f8d9a16754a9b3539f3a66c6a7f8bcec4ba224" + integrity sha512-ySja/GiSqO0NoEFuVdCZorWmbtIBGjIIssIU63V5xenpmfPZ+pT2lewtvrVojZJ9qoBRRpqgATTXjzd1XoQujg== + dependencies: + "@formily/reactive" "2.0.7" + "@juggle/resize-observer" "^3.3.1" + +"@formily/json-schema@2.0.7": + version "2.0.7" + resolved "https://registry.npmjs.org/@formily/json-schema/-/json-schema-2.0.7.tgz#3488aa0924b910bb19fc86321c364c891b95bc88" + integrity sha512-4mx0JdBaLPymlZ0vhh2bpelqQDEuaaAKu5mAQ1B8iA9n99DnbPzBUTWVw71fUpXRvOtVuedySlN5VGAfCJJsPA== + dependencies: + "@formily/core" "2.0.7" + "@formily/reactive" "2.0.7" + "@formily/shared" "2.0.7" + +"@formily/path@2.0.7": + version "2.0.7" + resolved "https://registry.npmjs.org/@formily/path/-/path-2.0.7.tgz#43985e696fdd03e302db781a12c555e27a90a289" + integrity sha512-78iiB+Ct8gM71uXH+loekN1ivJ1UxyNNP0wm1RhVd/BKVosvyPrdPZYbVoev/iw3xKfHTu94d8vFdHSd5eTdGA== + +"@formily/react@2.0.7", "@formily/react@^2.0.7": + version "2.0.7" + resolved "https://registry.npmjs.org/@formily/react/-/react-2.0.7.tgz#ceef53d02afd6fd4440bfbd043ef3c9b168a39de" + integrity sha512-5BtXxFaYSY5mV1+VOjP84i4fE7Zfb/3PctWhHNJkbhq0AkMyZ8zICEOkHvxtjlRowoD9oSUXWPBvYyKlUtP7wg== + dependencies: + "@formily/core" "2.0.7" + "@formily/json-schema" "2.0.7" + "@formily/reactive" "2.0.7" + "@formily/reactive-react" "2.0.7" + "@formily/shared" "2.0.7" + "@formily/validator" "2.0.7" + hoist-non-react-statics "^3.3.2" + +"@formily/reactive-react@2.0.7": + version "2.0.7" + resolved "https://registry.npmjs.org/@formily/reactive-react/-/reactive-react-2.0.7.tgz#e86885b803a519a0c87fcc0bbbb76f4266a719ce" + integrity sha512-YzVvKY/eaUfZ7+JuuibkWo6+94KCU3rx9aCExxDA1e15Ozpf/HGaVlZKNaJgGEboRXCcAm6WMAjBdXty3hxmIw== + dependencies: + "@formily/reactive" "2.0.7" + hoist-non-react-statics "^3.3.2" + +"@formily/reactive@2.0.7": + version "2.0.7" + resolved "https://registry.npmjs.org/@formily/reactive/-/reactive-2.0.7.tgz#3ca3e4dedfabfce98885bbc8ec15eb2fba3364a0" + integrity sha512-cXUhcfBGWRCoPrziCCXVRsw3+lJ93fhPDJ2eGFPXMcMXYZ7XpeqQd+9wq+L8GJLYVLAR0k6P93ojc7d9lnS5Vw== + +"@formily/shared@2.0.7": + version "2.0.7" + resolved "https://registry.npmjs.org/@formily/shared/-/shared-2.0.7.tgz#1e62d91accde8f86f48473304f65c3ec386310bd" + integrity sha512-io2DzKd5AQg2lebgO5OkB+AOPYxpxSn92rop5LnavcY+NBOsNLSe5zgZdGcA6w2xqCu4AYlkqPimF5GypI1gxQ== + dependencies: + "@formily/path" "2.0.7" + camel-case "^4.1.1" + lower-case "^2.0.1" + no-case "^3.0.4" + param-case "^3.0.4" + pascal-case "^3.1.1" + upper-case "^2.0.1" + +"@formily/validator@2.0.7": + version "2.0.7" + resolved "https://registry.npmjs.org/@formily/validator/-/validator-2.0.7.tgz#9390ed6b65b55760713c18d187db90b47ab7804d" + integrity sha512-y/+fzGAiqsLotfvUuOggpZbat3e9AREAofnmiCGrik9SMVeRZYZ2LXFJ3ZDqazGFObq4kHHuXEZRFWJnFY3izg== + dependencies: + "@formily/shared" "2.0.7" + "@gar/promisify@^1.0.1": version "1.1.2" resolved "https://registry.npmjs.org/@gar/promisify/-/promisify-1.1.2.tgz#30aa825f11d438671d585bd44e7fd564535fc210" @@ -1222,6 +1507,11 @@ "@types/yargs" "^15.0.0" chalk "^4.0.0" +"@juggle/resize-observer@^3.3.1": + version "3.3.1" + resolved "https://registry.npmjs.org/@juggle/resize-observer/-/resize-observer-3.3.1.tgz#b50a781709c81e10701004214340f25475a171a0" + integrity sha512-zMM9Ds+SawiUkakS7y94Ymqx+S0ORzpG3frZirN3l+UlXUmSUR7hF4wxCVqW+ei94JzV5kt0uXBcoOEAuiydrw== + "@koa/cors@^3.1.0": version "3.1.0" resolved "https://registry.npmjs.org/@koa/cors/-/cors-3.1.0.tgz#618bb073438cfdbd3ebd0e648a76e33b84f3a3b2" @@ -2163,6 +2453,28 @@ dependencies: "@sinonjs/commons" "^1.7.0" +"@testing-library/dom@^8.0.0": + version "8.11.1" + resolved "https://registry.npmjs.org/@testing-library/dom/-/dom-8.11.1.tgz#03fa2684aa09ade589b460db46b4c7be9fc69753" + integrity sha512-3KQDyx9r0RKYailW2MiYrSSKEfH0GTkI51UGEvJenvcoDoeRYs0PZpi2SXqtnMClQvCqdtTTpOfFETDTVADpAg== + dependencies: + "@babel/code-frame" "^7.10.4" + "@babel/runtime" "^7.12.5" + "@types/aria-query" "^4.2.0" + aria-query "^5.0.0" + chalk "^4.1.0" + dom-accessibility-api "^0.5.9" + lz-string "^1.4.4" + pretty-format "^27.0.2" + +"@testing-library/react@^12.1.2": + version "12.1.2" + resolved "https://registry.npmjs.org/@testing-library/react/-/react-12.1.2.tgz#f1bc9a45943461fa2a598bb4597df1ae044cfc76" + integrity sha512-ihQiEOklNyHIpo2Y8FREkyD1QAea054U0MVbwH1m8N9TxeFz+KoJ9LkqoKqJlzx2JDm56DVwaJ1r36JYxZM05g== + dependencies: + "@babel/runtime" "^7.12.5" + "@testing-library/dom" "^8.0.0" + "@tootallnate/once@1": version "1.1.2" resolved "https://registry.npmjs.org/@tootallnate/once/-/once-1.1.2.tgz#ccb91445360179a04e7fe6aff78c00ffc1eeaf82" @@ -2175,6 +2487,11 @@ dependencies: "@types/node" "*" +"@types/aria-query@^4.2.0": + version "4.2.2" + resolved "https://registry.npmjs.org/@types/aria-query/-/aria-query-4.2.2.tgz#ed4e0ad92306a704f9fb132a0cfcf77486dbe2bc" + integrity sha512-HnYpAE1Y6kRyKM/XkEuiRQhTHvkzMBurTHnpFLYLBGPIylZNPs9jJcuOOYWxPLJCSEtmZT0Y8rHDokKN7rRTig== + "@types/babel__core@^7.0.0", "@types/babel__core@^7.1.7": version "7.1.16" resolved "https://registry.npmjs.org/@types/babel__core/-/babel__core-7.1.16.tgz#bc12c74b7d65e82d29876b5d0baf5c625ac58702" @@ -3012,6 +3329,18 @@ aggregate-error@^3.0.0: clean-stack "^2.0.0" indent-string "^4.0.0" +ahooks@^3.0.5: + version "3.0.5" + resolved "https://registry.npmjs.org/ahooks/-/ahooks-3.0.5.tgz#7cf1a057ae147ac02732c3eddb00a793006df9d6" + integrity sha512-/l8HoNPzJVoexChfw7zlRD1/VyX1X7F08AVNnwkRwgufu1AfUd96XcIStrRsmADqMQWllluLRodEzPbcKUGUzQ== + dependencies: + dayjs "^1.9.1" + intersection-observer "^0.12.0" + js-cookie "^3.0.0" + lodash "^4.17.21" + resize-observer-polyfill "^1.5.1" + screenfull "^5.0.0" + ajv-errors@^1.0.0: version "1.0.1" resolved "https://registry.npmjs.org/ajv-errors/-/ajv-errors-1.0.1.tgz#f35986aceb91afadec4102fbd85014950cefa64d" @@ -3141,6 +3470,60 @@ ansi-styles@^4.0.0, ansi-styles@^4.1.0: dependencies: color-convert "^2.0.1" +ansi-styles@^5.0.0: + version "5.2.0" + resolved "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz#07449690ad45777d1924ac2abb2fc8895dba836b" + integrity sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA== + +antd@^4.16.11: + version "4.17.3" + resolved "https://registry.npmjs.org/antd/-/antd-4.17.3.tgz#48e2cfaec75cb414782a16918c0f322af1f2d509" + integrity sha512-enA6rsOAGtw0uN+khzvPoCui9j6m1ZvtAHY2IWC/mOUIwfycC8iuToND9ptAqeNF5yX8RZhFubmcc7Xeqk6wWg== + dependencies: + "@ant-design/colors" "^6.0.0" + "@ant-design/icons" "^4.7.0" + "@ant-design/react-slick" "~0.28.1" + "@babel/runtime" "^7.12.5" + "@ctrl/tinycolor" "^3.4.0" + array-tree-filter "^2.1.0" + classnames "^2.2.6" + copy-to-clipboard "^3.2.0" + lodash "^4.17.21" + memoize-one "^6.0.0" + moment "^2.25.3" + rc-cascader "~2.3.0" + rc-checkbox "~2.3.0" + rc-collapse "~3.1.0" + rc-dialog "~8.6.0" + rc-drawer "~4.4.2" + rc-dropdown "~3.2.0" + rc-field-form "~1.21.0" + rc-image "~5.2.5" + rc-input-number "~7.3.0" + rc-mentions "~1.6.1" + rc-menu "~9.0.12" + rc-motion "^2.4.4" + rc-notification "~4.5.7" + rc-pagination "~3.1.9" + rc-picker "~2.5.17" + rc-progress "~3.1.0" + rc-rate "~2.9.0" + rc-resize-observer "^1.1.0" + rc-select "~13.2.1" + rc-slider "~9.7.4" + rc-steps "~4.1.0" + rc-switch "~3.2.0" + rc-table "~7.19.0" + rc-tabs "~11.10.0" + rc-textarea "~0.3.0" + rc-tooltip "~5.1.1" + rc-tree "~5.3.0" + rc-tree-select "~4.8.0" + rc-trigger "^5.2.10" + rc-upload "~4.3.0" + rc-util "^5.14.0" + scroll-into-view-if-needed "^2.2.25" + any-promise@^1.0.0, any-promise@^1.3.0: version "1.3.0" resolved "https://registry.npmjs.org/any-promise/-/any-promise-1.3.0.tgz#abc6afeedcea52e809cdc0376aed3ce39635d17f" @@ -3215,6 +3598,11 @@ argparse@^1.0.7: dependencies: sprintf-js "~1.0.2" +aria-query@^5.0.0: + version "5.0.0" + resolved "https://registry.npmjs.org/aria-query/-/aria-query-5.0.0.tgz#210c21aaf469613ee8c9a62c7f86525e058db52c" + integrity sha512-V+SM7AbUwJ+EBnB8+DXs0hPZHO0W6pqBcc0dW90OwtVG02PswOu/teuARoLQjdDOH+t9pJgGnW5/Qmouf3gPJg== + arr-diff@^4.0.0: version "4.0.0" resolved "https://registry.npmjs.org/arr-diff/-/arr-diff-4.0.0.tgz#d6461074febfec71e7e15235761a329a5dc7c520" @@ -3261,6 +3649,11 @@ array-includes@^3.1.3, array-includes@^3.1.4: get-intrinsic "^1.1.1" is-string "^1.0.7" +array-tree-filter@^2.1.0: + version "2.1.0" + resolved "https://registry.npmjs.org/array-tree-filter/-/array-tree-filter-2.1.0.tgz#873ac00fec83749f255ac8dd083814b4f6329190" + integrity sha512-4ROwICNlNw/Hqa9v+rk5h22KjmzB1JGTMVKP2AKJBOCgb0yL0ASf0+YvCcLNNwquOHNX48jkeZIJ3a+oOQqKcw== + array-union@^1.0.1: version "1.0.2" resolved "https://registry.npmjs.org/array-union/-/array-union-1.0.2.tgz#9a34410e4f4e3da23dea375be5be70f24778ec39" @@ -3370,11 +3763,16 @@ astral-regex@^2.0.0: async-mutex@^0.3.2: version "0.3.2" - resolved "https://registry.nlark.com/async-mutex/download/async-mutex-0.3.2.tgz#1485eda5bda1b0ec7c8df1ac2e815757ad1831df" - integrity sha1-FIXtpb2hsOx8jfGsLoFXV60YMd8= + resolved "https://registry.npmjs.org/async-mutex/-/async-mutex-0.3.2.tgz#1485eda5bda1b0ec7c8df1ac2e815757ad1831df" + integrity sha512-HuTK7E7MT7jZEh1P9GtRW9+aTWiDWWi9InbZ5hjxrnRa39KS4BW04+xLBhYNS2aXhHUIKZSw3gj4Pn1pj+qGAA== dependencies: tslib "^2.3.1" +async-validator@^4.0.2: + version "4.0.7" + resolved "https://registry.npmjs.org/async-validator/-/async-validator-4.0.7.tgz#034a0fd2103a6b2ebf010da75183bec299247afe" + integrity sha512-Pj2IR7u8hmUEDOwB++su6baaRi+QvsgajuFB9j95foM1N2gy5HM4z60hfusIO0fBPG5uLAEl6yCJr1jNSVugEQ== + asynckit@^0.4.0: version "0.4.0" resolved "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz#c79ed97f7f34cb8f2ba1bc9790bcc366474b4b79" @@ -3428,6 +3826,22 @@ aws4@^1.8.0: resolved "https://registry.npmjs.org/aws4/-/aws4-1.11.0.tgz#d61f46d83b2519250e2784daf5b09479a8b41c59" integrity sha512-xh1Rl34h6Fi1DC2WWKfxUTVqRsNnr6LsKz2+hfwDxQJWmrx8+c7ylaqBMcHfl1U1r2dsifOvKX3LQuLNZ+XSvA== +axios-mock-adapter@^1.20.0: + version "1.20.0" + resolved "https://registry.npmjs.org/axios-mock-adapter/-/axios-mock-adapter-1.20.0.tgz#21f5b4b625306f43e8c05673616719da86e20dcb" + integrity sha512-shZRhTjLP0WWdcvHKf3rH3iW9deb3UdKbdnKUoHmmsnBhVXN3sjPJM6ZvQ2r/ywgvBVQrMnjrSyQab60G1sr2w== + dependencies: + fast-deep-equal "^3.1.3" + is-blob "^2.1.0" + is-buffer "^2.0.5" + +axios@^0.24.0: + version "0.24.0" + resolved "https://registry.npmjs.org/axios/-/axios-0.24.0.tgz#804e6fa1e4b9c5288501dd9dff56a7a0940d20d6" + integrity sha512-Q6cWsys88HoPgAaFAVUb0WpPk0O8iTeisR9IMqy9G8AbO4NlpVknrnQS03zzF9PGAWgO3cgletO3VjV/P7VztA== + dependencies: + follow-redirects "^1.14.4" + babel-core@^7.0.0-bridge.0: version "7.0.0-bridge.0" resolved "https://registry.npmjs.org/babel-core/-/babel-core-7.0.0-bridge.0.tgz#95a492ddd90f9b4e9a4a1da14eb335b87b634ece" @@ -3475,6 +3889,15 @@ babel-plugin-jest-hoist@^26.6.2: "@types/babel__core" "^7.0.0" "@types/babel__traverse" "^7.0.6" +babel-plugin-macros@^2.6.1: + version "2.8.0" + resolved "https://registry.npmjs.org/babel-plugin-macros/-/babel-plugin-macros-2.8.0.tgz#0f958a7cc6556b1e65344465d99111a1e5e10138" + integrity sha512-SEP5kJpfGYqYKpBrj5XU3ahw5p5GOHJ0U5ssOSQ/WBVdwkD2Dzlce95exQTs3jOVWPPKLBN2rlEWkCK7dSmLvg== + dependencies: + "@babel/runtime" "^7.7.2" + cosmiconfig "^6.0.0" + resolve "^1.12.0" + babel-plugin-polyfill-corejs2@^0.2.3: version "0.2.3" resolved "https://registry.npmjs.org/babel-plugin-polyfill-corejs2/-/babel-plugin-polyfill-corejs2-0.2.3.tgz#6ed8e30981b062f8fe6aca8873a37ebcc8cc1c0f" @@ -3897,6 +4320,14 @@ callsites@^3.0.0: resolved "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz#b3630abd8943432f54b3f0519238e33cd7df2f73" integrity sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ== +camel-case@^4.1.1: + version "4.1.2" + resolved "https://registry.npmjs.org/camel-case/-/camel-case-4.1.2.tgz#9728072a954f805228225a6deea6b38461e1bd5a" + integrity sha512-gxGWBrTT1JuMx6R+o5PTXMmUnhnVzLQ9SNutD4YqKtI6ap897t3tKECYla6gCWEkplXnlNybEkZg9GEGxKFCgw== + dependencies: + pascal-case "^3.1.2" + tslib "^2.0.3" + camelcase-css@^2.0.1: version "2.0.1" resolved "https://registry.npmjs.org/camelcase-css/-/camelcase-css-2.0.1.tgz#ee978f6947914cc30c6b44741b6ed1df7f043fd5" @@ -4100,7 +4531,7 @@ class-utils@^0.3.5: isobject "^3.0.0" static-extend "^0.1.1" -classnames@2.x, classnames@^2.2.1, classnames@^2.2.6: +classnames@2.x, classnames@^2.2.1, classnames@^2.2.3, classnames@^2.2.5, classnames@^2.2.6, classnames@^2.3.1: version "2.3.1" resolved "https://registry.npmjs.org/classnames/-/classnames-2.3.1.tgz#dfcfa3891e306ec1dad105d0e88f4417b8535e8e" integrity sha512-OlQdbZ7gLfGarSqxesMesDa5uz7KFbID8Kpq/SxIoNGDqY8lSYs0D+hhtBXhcdB3rcbXArFr7vlHheLk1voeNA== @@ -4307,6 +4738,11 @@ component-emitter@^1.2.1, component-emitter@^1.3.0: resolved "https://registry.npmjs.org/component-emitter/-/component-emitter-1.3.0.tgz#16e4070fba8ae29b679f2215853ee181ab2eabc0" integrity sha512-Rd3se6QB+sO1TwqZjscQrurpEPIfO0/yYnSin6Q/rD3mOutHvUrCAhJub3r90uNb+SESBuE0QYoB90YdfatsRg== +compute-scroll-into-view@^1.0.17: + version "1.0.17" + resolved "https://registry.npmjs.org/compute-scroll-into-view/-/compute-scroll-into-view-1.0.17.tgz#6a88f18acd9d42e9cf4baa6bec7e0522607ab7ab" + integrity sha512-j4dx+Fb0URmzbwwMUrhqWM2BEWHdFGx+qZ9qqASHRPqvTYdqvWnHg0H1hIbcyLnvgnoNAVMlwkepyqM3DaIFUg== + concat-map@0.0.1: version "0.0.1" resolved "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b" @@ -4461,7 +4897,7 @@ conventional-recommended-bump@^6.1.0: meow "^8.0.0" q "^1.5.1" -convert-source-map@^1.4.0, convert-source-map@^1.6.0, convert-source-map@^1.7.0: +convert-source-map@^1.4.0, convert-source-map@^1.5.0, convert-source-map@^1.6.0, convert-source-map@^1.7.0: version "1.8.0" resolved "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.8.0.tgz#f3373c32d21b4d780dd8004514684fb791ca4369" integrity sha512-+OQdjP49zViI/6i7nIJpA8rAl4sV/JdPfU9nZs3VqOwGIgizICvuN2ru6fMd+4llL0tar18UYJXfZ/TWtmhUjA== @@ -4491,6 +4927,13 @@ copy-text-to-clipboard@^2.2.0: resolved "https://registry.npmjs.org/copy-text-to-clipboard/-/copy-text-to-clipboard-2.2.0.tgz#329dd6daf8c42034c763ace567418401764579ae" integrity sha512-WRvoIdnTs1rgPMkgA2pUOa/M4Enh2uzCwdKsOMYNAJiz/4ZvEJgmbF4OmninPmlFdAWisfeh0tH+Cpf7ni3RqQ== +copy-to-clipboard@^3.2.0: + version "3.3.1" + resolved "https://registry.npmjs.org/copy-to-clipboard/-/copy-to-clipboard-3.3.1.tgz#115aa1a9998ffab6196f93076ad6da3b913662ae" + integrity sha512-i13qo6kIHTTpCm8/Wup+0b1mVWETvu2kIMzKoK8FpkLkFxlt0znUAHcMzox+T8sPlqtZXq3CulEjQHsYiGFJUw== + dependencies: + toggle-selection "^1.0.6" + copy-to@^2.0.1: version "2.0.1" resolved "https://registry.npmjs.org/copy-to/-/copy-to-2.0.1.tgz#2680fbb8068a48d08656b6098092bdafc906f4a5" @@ -4534,6 +4977,17 @@ cosmiconfig@^5.0.0: js-yaml "^3.13.1" parse-json "^4.0.0" +cosmiconfig@^6.0.0: + version "6.0.0" + resolved "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-6.0.0.tgz#da4fee853c52f6b1e6935f41c1a2fc50bd4a9982" + integrity sha512-xb3ZL6+L8b9JLLCx3ZdoZy4+2ECphCMo2PwqgP1tlfVq6M6YReyzBJtvWWtbDSpNr9hn96pkCiZqUcFEc+54Qg== + dependencies: + "@types/parse-json" "^4.0.0" + import-fresh "^3.1.0" + parse-json "^5.0.0" + path-type "^4.0.0" + yaml "^1.7.2" + cosmiconfig@^7.0.0: version "7.0.1" resolved "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-7.0.1.tgz#714d756522cace867867ccb4474c5d01bbae5d6d" @@ -4768,6 +5222,11 @@ data-urls@^2.0.0: whatwg-mimetype "^2.3.0" whatwg-url "^8.0.0" +date-fns@2.x: + version "2.27.0" + resolved "https://registry.npmjs.org/date-fns/-/date-fns-2.27.0.tgz#e1ff3c3ddbbab8a2eaadbb6106be2929a5a2d92b" + integrity sha512-sj+J0Mo2p2X1e306MHq282WS4/A8Pz/95GIFcsPNMPMZVI3EUrAdSv90al1k+p74WGLCruMXk23bfEDZa71X9Q== + dateformat@^2.0.0: version "2.2.0" resolved "https://registry.npmjs.org/dateformat/-/dateformat-2.2.0.tgz#4065e2013cf9fb916ddfd82efb506ad4c6769062" @@ -4778,6 +5237,11 @@ dateformat@^3.0.0: resolved "https://registry.npmjs.org/dateformat/-/dateformat-3.0.3.tgz#a6e37499a4d9a9cf85ef5872044d62901c9889ae" integrity sha512-jyCETtSl3VMZMWeRo7iY1FL19ges1t55hMo5yaam4Jrsm5EPL89UQkoQRyiI+Yf4k8r2ZpdngkV8hr1lIdjb3Q== +dayjs@1.x, dayjs@^1.9.1: + version "1.10.7" + resolved "https://registry.npmjs.org/dayjs/-/dayjs-1.10.7.tgz#2cf5f91add28116748440866a0a1d26f3a6ce468" + integrity sha512-P6twpd70BcPK34K26uJ1KT3wlhpuOAPoMwJzpsIWUxHZ7wpmbdZL/hQqBDfz7hGurYSa5PhzdhDHtt319hL3ig== + debug@4, debug@^4.0.0, debug@^4.0.1, debug@^4.1.0, debug@^4.1.1, debug@^4.3.1, debug@^4.3.2: version "4.3.2" resolved "https://registry.npmjs.org/debug/-/debug-4.3.2.tgz#f0a49c18ac8779e31d4a0c6029dfb76873c7428b" @@ -5049,6 +5513,11 @@ doctrine@^3.0.0: dependencies: esutils "^2.0.2" +dom-accessibility-api@^0.5.9: + version "0.5.10" + resolved "https://registry.npmjs.org/dom-accessibility-api/-/dom-accessibility-api-0.5.10.tgz#caa6d08f60388d0bb4539dd75fe458a9a1d0014c" + integrity sha512-Xu9mD0UjrJisTmv7lmVSDMagQcU9R5hwAbxsaAE/35XPnPLJobbuREfV/rraiSaEj/UOvgrzQs66zyTWTlyd+g== + dom-align@^1.7.0: version "1.12.2" resolved "https://registry.npmjs.org/dom-align/-/dom-align-1.12.2.tgz#0f8164ebd0c9c21b0c790310493cd855892acd4b" @@ -5066,6 +5535,14 @@ domexception@^2.0.1: dependencies: webidl-conversions "^5.0.0" +dot-case@^3.0.4: + version "3.0.4" + resolved "https://registry.npmjs.org/dot-case/-/dot-case-3.0.4.tgz#9b2b670d00a431667a8a75ba29cd1b98809ce751" + integrity sha512-Kv5nKlh6yRrdrGvxeJ2e5y2eRUpkUosIW4A2AS38zwSz27zu7ufDwQPi5Jhs3XAlGNetl3bmnGhQsMtkKJnj3w== + dependencies: + no-case "^3.0.4" + tslib "^2.0.3" + dot-prop@^4.2.1: version "4.2.1" resolved "https://registry.npmjs.org/dot-prop/-/dot-prop-4.2.1.tgz#45884194a71fc2cda71cbb4bceb3a4dd2f433ba4" @@ -5922,6 +6399,11 @@ find-cache-dir@^2.0.0: make-dir "^2.0.0" pkg-dir "^3.0.0" +find-root@^1.1.0: + version "1.1.0" + resolved "https://registry.npmjs.org/find-root/-/find-root-1.1.0.tgz#abcfc8ba76f708c42a97b3d685b7e9450bfb9ce4" + integrity sha512-NKfW6bec6GfKc0SGx1e07QZY9PE99u0Bft/0rzSD5k3sO/vwkVUpDUKVm5Gpp5Ue3YfShPFTX2070tDs5kB9Ng== + find-up@^1.0.0: version "1.1.2" resolved "https://registry.npmjs.org/find-up/-/find-up-1.1.2.tgz#6b2e9822b1a2ce0a60ab64d610eccad53cb24d0f" @@ -5985,6 +6467,11 @@ flow-parser@0.*: resolved "https://registry.npmjs.org/flow-parser/-/flow-parser-0.164.0.tgz#455e16fdba12f24aa1d7631adacc524f1977b6ad" integrity sha512-aJWAhnazcz0o8xIbCW5LBTf+tnsAtLwaMSCcRqA15UTkPBY1Vq1vy1WEPKwcWsve5tos5kkOeCXgd/Nal+LUUQ== +follow-redirects@^1.14.4: + version "1.14.6" + resolved "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.14.6.tgz#8cfb281bbc035b3c067d6cd975b0f6ade6e855cd" + integrity sha512-fhUl5EwSJbbl8AR+uYL2KQDxLkdSjZGR36xy46AO7cOMTrCMON6Sa28FmAnC2tRTDbd/Uuzz3aJBv7EBN7JH8A== + for-in@^1.0.2: version "1.0.2" resolved "https://registry.npmjs.org/for-in/-/for-in-1.0.2.tgz#81068d295a8142ec0ac726c6e2200c30fb6d5e80" @@ -6703,7 +7190,7 @@ hmac-drbg@^1.0.1: minimalistic-assert "^1.0.0" minimalistic-crypto-utils "^1.0.1" -hoist-non-react-statics@^3.1.0: +hoist-non-react-statics@^3.1.0, hoist-non-react-statics@^3.3.2: version "3.3.2" resolved "https://registry.npmjs.org/hoist-non-react-statics/-/hoist-non-react-statics-3.3.2.tgz#ece0acaf71d62c2969c2ec59feff42a4b1a85b45" integrity sha512-/gGivxi8JPKWNm/W0jSmzcMPpfpPLc3dY/6GxhX2hQ9iGj3aDfklV4ET7NjKpSinLpJ5vafa9iiGIEZg10SfBw== @@ -6746,11 +7233,18 @@ html-entities@^2.1.0: resolved "https://registry.npmjs.org/html-entities/-/html-entities-2.3.2.tgz#760b404685cb1d794e4f4b744332e3b00dcfe488" integrity sha512-c3Ab/url5ksaT0WyleslpBEthOzWhrjQbg75y7XUsfSzi3Dgzt0l8w5e7DylRn15MTlMMD58dTfzddNS2kcAjQ== -html-escaper@^2.0.0: +html-escaper@^2.0.0, html-escaper@^2.0.2: version "2.0.2" resolved "https://registry.npmjs.org/html-escaper/-/html-escaper-2.0.2.tgz#dfd60027da36a36dfcbe236262c00a5822681453" integrity sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg== +html-parse-stringify@^3.0.1: + version "3.0.1" + resolved "https://registry.npmjs.org/html-parse-stringify/-/html-parse-stringify-3.0.1.tgz#dfc1017347ce9f77c8141a507f233040c59c55d2" + integrity sha512-KknJ50kTInJ7qIScF3jeaFRpMpE8/lfiTdzf/twXyPBLAGrLRTmkz3AdTnKeh40X8k9L2fdYwEp/42WGXIRGcg== + dependencies: + void-elements "3.1.0" + html-void-elements@^1.0.0: version "1.0.5" resolved "https://registry.npmjs.org/html-void-elements/-/html-void-elements-1.0.5.tgz#ce9159494e86d95e45795b166c2021c2cfca4483" @@ -6845,6 +7339,13 @@ i18next@^21.3.2: dependencies: "@babel/runtime" "^7.12.0" +i18next@^21.6.0: + version "21.6.0" + resolved "https://registry.npmjs.org/i18next/-/i18next-21.6.0.tgz#257abf455b24136640a20728b44cf59f60cdeb5c" + integrity sha512-RjNuACL35wWZgtkyMcjcCmK7R72u3P6jTNbGKzrvHGI9M0iK5Vn1DsBIwOByppaXLIbe0viJ79Nz2h8w1UwPoQ== + dependencies: + "@babel/runtime" "^7.12.0" + iconv-lite@0.4.24, iconv-lite@^0.4.15, iconv-lite@^0.4.24, iconv-lite@^0.4.4: version "0.4.24" resolved "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz#2022b4b25fbddc21d2f524974a474aafe733908b" @@ -6906,7 +7407,7 @@ import-fresh@^2.0.0: caller-path "^2.0.0" resolve-from "^3.0.0" -import-fresh@^3.0.0, import-fresh@^3.2.1: +import-fresh@^3.0.0, import-fresh@^3.1.0, import-fresh@^3.2.1: version "3.3.0" resolved "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz#37162c25fcb9ebaa2e6e53d5b4d88ce17d9e0c2b" integrity sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw== @@ -7069,6 +7570,18 @@ internal-slot@^1.0.3: has "^1.0.3" side-channel "^1.0.4" +intersection-observer@^0.12.0: + version "0.12.0" + resolved "https://registry.npmjs.org/intersection-observer/-/intersection-observer-0.12.0.tgz#6c84628f67ce8698e5f9ccf857d97718745837aa" + integrity sha512-2Vkz8z46Dv401zTWudDGwO7KiGHNDkMv417T5ItcNYfmvHR/1qCTVBO9vwH8zZmQ0WkA/1ARwpysR9bsnop4NQ== + +invariant@^2.2.4: + version "2.2.4" + resolved "https://registry.npmjs.org/invariant/-/invariant-2.2.4.tgz#610f3c92c9359ce1db616e538008d23ff35158e6" + integrity sha512-phJfQVBuaJM5raOpJjSfkiD6BpbCE4Ns//LaXl6wGYtUBY83nWS6Rf9tXm2e8VaK60JEjYldbPif/A2B1C2gNA== + dependencies: + loose-envify "^1.0.0" + ip@^1.1.5: version "1.1.5" resolved "https://registry.npmjs.org/ip/-/ip-1.1.5.tgz#bdded70114290828c0a039e72ef25f5aaec4354a" @@ -7120,6 +7633,11 @@ is-binary-path@~2.1.0: dependencies: binary-extensions "^2.0.0" +is-blob@^2.1.0: + version "2.1.0" + resolved "https://registry.npmjs.org/is-blob/-/is-blob-2.1.0.tgz#e36cd82c90653f1e1b930f11baf9c64216a05385" + integrity sha512-SZ/fTft5eUhQM6oF/ZaASFDEdbFVe89Imltn9uZr03wdKMcWNVYSMjQPFtg05QuNkt5l5c135ElvXEQG0rk4tw== + is-boolean-object@^1.1.0: version "1.1.2" resolved "https://registry.npmjs.org/is-boolean-object/-/is-boolean-object-1.1.2.tgz#5c6dc200246dd9321ae4b885a114bb1f75f63719" @@ -7133,7 +7651,7 @@ is-buffer@^1.1.5: resolved "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.6.tgz#efaa2ea9daa0d7ab2ea13a97b2b8ad51fefbe8be" integrity sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w== -is-buffer@^2.0.0: +is-buffer@^2.0.0, is-buffer@^2.0.5: version "2.0.5" resolved "https://registry.npmjs.org/is-buffer/-/is-buffer-2.0.5.tgz#ebc252e400d22ff8d77fa09888821a24a658c191" integrity sha512-i2R6zNFDwgEHJyQUtJEk0XFi1i0dPFn/oqjK3/vPCcDeJvW5NQ83V8QbicfF1SupOaB0h8ntgBC2YiE7dfyctQ== @@ -8067,6 +8585,11 @@ js-base64@^2.5.2: resolved "https://registry.npmjs.org/js-base64/-/js-base64-2.6.4.tgz#f4e686c5de1ea1f867dbcad3d46d969428df98c4" integrity sha512-pZe//GGmwJndub7ZghVHz7vjb2LgC1m8B07Au3eYqeqv9emhESByMXxaEgkUkEqJe87oBbSniGYoQNIBklc7IQ== +js-cookie@^3.0.0: + version "3.0.1" + resolved "https://registry.npmjs.org/js-cookie/-/js-cookie-3.0.1.tgz#9e39b4c6c2f56563708d7d31f6f5f21873a92414" + integrity sha512-+0rgsUXZu4ncpPxRL+lNEptWMOWl9etvPHc/koSRp6MPwpRYAhmk0dUG00J4bxVV3r9uUzfo24wW0knS07SKSw== + "js-tokens@^3.0.0 || ^4.0.0", js-tokens@^4.0.0: version "4.0.0" resolved "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz#19203fb59991df98e3a287050d4647cdeaf32499" @@ -8187,6 +8710,13 @@ json-stringify-safe@^5.0.1, json-stringify-safe@~5.0.1: resolved "https://registry.npmjs.org/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz#1296a2d58fd45f19a0f6ce01d65701e2c735b6eb" integrity sha1-Epai1Y/UXxmg9s4B1lcB4sc1tus= +json2mq@^0.2.0: + version "0.2.0" + resolved "https://registry.npmjs.org/json2mq/-/json2mq-0.2.0.tgz#b637bd3ba9eabe122c83e9720483aeb10d2c904a" + integrity sha1-tje9O6nqvhIsg+lyBIOusQ0skEo= + dependencies: + string-convert "^0.2.0" + json5@2.x, json5@^2.1.2: version "2.2.0" resolved "https://registry.npmjs.org/json5/-/json5-2.2.0.tgz#2dfefe720c6ba525d9ebd909950f0515316c89a3" @@ -8568,7 +9098,7 @@ longest-streak@^2.0.0: resolved "https://registry.npmjs.org/longest-streak/-/longest-streak-2.0.4.tgz#b8599957da5b5dab64dee3fe316fa774597d90e4" integrity sha512-vM6rUVCVUJJt33bnmHiZEvr7wPT78ztX7rojL+LW51bHtLh6HTjx84LA5W4+oa6aKEJA7jJu5LR6vQRBpA5DVg== -loose-envify@^1.1.0, loose-envify@^1.2.0, loose-envify@^1.3.1, loose-envify@^1.4.0: +loose-envify@^1.0.0, loose-envify@^1.1.0, loose-envify@^1.2.0, loose-envify@^1.3.1, loose-envify@^1.4.0: version "1.4.0" resolved "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz#71ee51fa7be4caec1a63839f7e682d8132d30caf" integrity sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q== @@ -8583,6 +9113,13 @@ loud-rejection@^1.0.0: currently-unhandled "^0.4.1" signal-exit "^3.0.0" +lower-case@^2.0.1, lower-case@^2.0.2: + version "2.0.2" + resolved "https://registry.npmjs.org/lower-case/-/lower-case-2.0.2.tgz#6fa237c63dbdc4a82ca0fd882e4722dc5e634e28" + integrity sha512-7fm3l3NAF9WfN6W3JOmf5drwpVqX78JtoGJ3A6W0a6ZnldM41w2fV5D490psKFTpMds8TJse/eHLFFsNHHjHgg== + dependencies: + tslib "^2.0.3" + lowercase-keys@^1.0.0: version "1.0.1" resolved "https://registry.npmjs.org/lowercase-keys/-/lowercase-keys-1.0.1.tgz#6f9e30b47084d971a7c820ff15a6c5167b74c26f" @@ -8873,6 +9410,11 @@ media-typer@0.3.0: resolved "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz#8710d7af0aa626f8fffa1ce00168545263255748" integrity sha1-hxDXrwqmJvj/+hzgAWhUUmMlV0g= +memoize-one@^6.0.0: + version "6.0.0" + resolved "https://registry.npmjs.org/memoize-one/-/memoize-one-6.0.0.tgz#b2591b871ed82948aee4727dc6abceeeac8c1045" + integrity sha512-rkpe71W0N0c0Xz6QD0eJETuWAJGnJ9afsl1srmwPrI+yBCkge5EycXXbYRyvL29zZVUWQCY7InPRCv3GDXuZNw== + memory-fs@^0.5.0: version "0.5.0" resolved "https://registry.npmjs.org/memory-fs/-/memory-fs-0.5.0.tgz#324c01288b88652966d161db77838720845a8e3c" @@ -9274,7 +9816,7 @@ moment-timezone@^0.5.31: dependencies: moment ">= 2.9.0" -"moment@>= 2.9.0", moment@^2.26.0: +"moment@>= 2.9.0", moment@^2.24.0, moment@^2.25.3, moment@^2.26.0: version "2.29.1" resolved "https://registry.npmjs.org/moment/-/moment-2.29.1.tgz#b2be769fa31940be9eeea6469c075e35006fa3d3" integrity sha512-kHmoybcPV8Sqy59DwNDY3Jefr64lK/by/da0ViFcuA4DH0vQg5Q6Ze5VimxkfQNSC+Mls/Kx53s7TjP1RhFEDQ== @@ -9463,6 +10005,14 @@ nice-try@^1.0.4: resolved "https://registry.npmjs.org/nice-try/-/nice-try-1.0.5.tgz#a3378a7696ce7d223e88fc9b764bd7ef1089e366" integrity sha512-1nh45deeb5olNY7eX82BkPO7SSxR5SSYJiPTrTdFUVYwAl8CKMA5N9PjTYkHiRjisVcxcQ1HXdLhx2qxxJzLNQ== +no-case@^3.0.4: + version "3.0.4" + resolved "https://registry.npmjs.org/no-case/-/no-case-3.0.4.tgz#d361fd5c9800f558551a8369fc0dcd4662b6124d" + integrity sha512-fgAN3jGAh+RoxUGZHTSOLJIqUc2wmoBwGR4tbpNAKmmovFoWq0OdRkb0VkldReO2a2iBT/OEulG9XSUc10r3zg== + dependencies: + lower-case "^2.0.2" + tslib "^2.0.3" + node-addon-api@^3.0.0, node-addon-api@^3.1.0: version "3.2.1" resolved "https://registry.npmjs.org/node-addon-api/-/node-addon-api-3.2.1.tgz#81325e0a2117789c0128dab65e7e38f07ceba161" @@ -10205,6 +10755,14 @@ pako@~1.0.5: resolved "https://registry.npmjs.org/pako/-/pako-1.0.11.tgz#6c9599d340d54dfd3946380252a35705a6b992bf" integrity sha512-4hLB8Py4zZce5s4yd9XzopqwVv/yGNhV1Bl8NTmCq1763HeK2+EwVTv+leGeL13Dnh2wfbqowVPXCIO0z4taYw== +param-case@^3.0.4: + version "3.0.4" + resolved "https://registry.npmjs.org/param-case/-/param-case-3.0.4.tgz#7d17fe4aa12bde34d4a77d91acfb6219caad01c5" + integrity sha512-RXlj7zCYokReqWpOPH9oYivUzLYZ5vAPIfEmCTNViosC78F8F0H9y7T7gG2M39ymgutxF5gcFEsyZQSph9Bp3A== + dependencies: + dot-case "^3.0.4" + tslib "^2.0.3" + parent-module@^1.0.0: version "1.0.1" resolved "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz#691d2709e78c79fae3a156622452d00762caaaa2" @@ -10290,6 +10848,14 @@ parseurl@^1.3.2: resolved "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz#9da19e7bee8d12dff0513ed5b76957793bc2e8d4" integrity sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ== +pascal-case@^3.1.1, pascal-case@^3.1.2: + version "3.1.2" + resolved "https://registry.npmjs.org/pascal-case/-/pascal-case-3.1.2.tgz#b48e0ef2b98e205e7c1dae747d0b1508237660eb" + integrity sha512-uWlGT3YSnK9x3BQJaOdcZwrnV6hPpd8jFH1/ucpiLRPh/2zCVJKS19E4GvYHvaCcACn3foXZ0cLB9Wrx1KGe5g== + dependencies: + no-case "^3.0.4" + tslib "^2.0.3" + pascalcase@^0.1.1: version "0.1.1" resolved "https://registry.npmjs.org/pascalcase/-/pascalcase-0.1.1.tgz#b363e55e8006ca6fe21784d2db22bd15d7917f14" @@ -10979,6 +11545,15 @@ pretty-format@^26.0.0, pretty-format@^26.6.2: ansi-styles "^4.0.0" react-is "^17.0.1" +pretty-format@^27.0.2: + version "27.4.6" + resolved "https://registry.npmjs.org/pretty-format/-/pretty-format-27.4.6.tgz#1b784d2f53c68db31797b2348fa39b49e31846b7" + integrity sha512-NblstegA1y/RJW2VyML+3LlpFjzx62cUrtBIKIWDXEDkjNeleA7Od7nrzcs/VLQvAeV4CgSYhrN39DRN88Qi/g== + dependencies: + ansi-regex "^5.0.1" + ansi-styles "^5.0.0" + react-is "^17.0.1" + pretty-quick@^3.1.0: version "3.1.1" resolved "https://registry.npmjs.org/pretty-quick/-/pretty-quick-3.1.1.tgz#93ca4e2dd38cc4e970e3f54a0ead317a25454688" @@ -11057,7 +11632,7 @@ promzard@^0.3.0: dependencies: read "1" -prop-types@^15.6.2, prop-types@^15.7.2: +prop-types@^15.5.7, prop-types@^15.6.2, prop-types@^15.7.2: version "15.7.2" resolved "https://registry.npmjs.org/prop-types/-/prop-types-15.7.2.tgz#52c41e75b8c87e72b9d9360e0206b99dcbffa6c5" integrity sha512-8QQikdH7//R2vurIJSutZ1smHYTcLpRWEOlHnzcWHmBYrOGUysKwSsrC89BCiFj3CbrfJ/nXFdJepOVrY1GCHQ== @@ -11244,7 +11819,58 @@ rc-align@^4.0.0: rc-util "^5.3.0" resize-observer-polyfill "^1.5.1" -rc-dropdown@^3.2.0: +rc-cascader@~2.3.0: + version "2.3.3" + resolved "https://registry.npmjs.org/rc-cascader/-/rc-cascader-2.3.3.tgz#605d04ef469cdd5d892e38cce291157d5a8af941" + integrity sha512-ckD8rKJjS8mdXxylWh1PtIHSFhbj/yf1NimyooqeJlvtLhzRZXIHCj4IuOjwYZ6J1DqoOCCdJfVtc7UeZia38w== + dependencies: + "@babel/runtime" "^7.12.5" + array-tree-filter "^2.1.0" + classnames "^2.3.1" + rc-tree-select "~4.8.0" + rc-trigger "^5.0.4" + rc-util "^5.6.1" + warning "^4.0.1" + +rc-checkbox@~2.3.0: + version "2.3.2" + resolved "https://registry.npmjs.org/rc-checkbox/-/rc-checkbox-2.3.2.tgz#f91b3678c7edb2baa8121c9483c664fa6f0aefc1" + integrity sha512-afVi1FYiGv1U0JlpNH/UaEXdh6WUJjcWokj/nUN2TgG80bfG+MDdbfHKlLcNNba94mbjy2/SXJ1HDgrOkXGAjg== + dependencies: + "@babel/runtime" "^7.10.1" + classnames "^2.2.1" + +rc-collapse@~3.1.0: + version "3.1.2" + resolved "https://registry.npmjs.org/rc-collapse/-/rc-collapse-3.1.2.tgz#76028a811b845d03d9460ccc409c7ea8ad09db14" + integrity sha512-HujcKq7mghk/gVKeI6EjzTbb8e19XUZpakrYazu1MblEZ3Hu3WBMSN4A3QmvbF6n1g7x6lUlZvsHZ5shABWYOQ== + dependencies: + "@babel/runtime" "^7.10.1" + classnames "2.x" + rc-motion "^2.3.4" + rc-util "^5.2.1" + shallowequal "^1.1.0" + +rc-dialog@~8.6.0: + version "8.6.0" + resolved "https://registry.npmjs.org/rc-dialog/-/rc-dialog-8.6.0.tgz#3b228dac085de5eed8c6237f31162104687442e7" + integrity sha512-GSbkfqjqxpZC5/zc+8H332+q5l/DKUhpQr0vdX2uDsxo5K0PhvaMEVjyoJUTkZ3+JstEADQji1PVLVb/2bJeOQ== + dependencies: + "@babel/runtime" "^7.10.1" + classnames "^2.2.6" + rc-motion "^2.3.0" + rc-util "^5.6.1" + +rc-drawer@~4.4.2: + version "4.4.3" + resolved "https://registry.npmjs.org/rc-drawer/-/rc-drawer-4.4.3.tgz#2094937a844e55dc9644236a2d9fba79c344e321" + integrity sha512-FYztwRs3uXnFOIf1hLvFxIQP9MiZJA+0w+Os8dfDh/90X7z/HqP/Yg+noLCIeHEbKln1Tqelv8ymCAN24zPcfQ== + dependencies: + "@babel/runtime" "^7.10.1" + classnames "^2.2.6" + rc-util "^5.7.0" + +rc-dropdown@^3.2.0, rc-dropdown@~3.2.0: version "3.2.0" resolved "https://registry.npmjs.org/rc-dropdown/-/rc-dropdown-3.2.0.tgz#da6c2ada403842baee3a9e909a0b1a91ba3e1090" integrity sha512-j1HSw+/QqlhxyTEF6BArVZnTmezw2LnSmRk6I9W7BCqNCKaRwleRmMMs1PHbuaG8dKHVqP6e21RQ7vPBLVnnNw== @@ -11253,7 +11879,47 @@ rc-dropdown@^3.2.0: classnames "^2.2.6" rc-trigger "^5.0.4" -rc-menu@^9.0.0: +rc-field-form@~1.21.0: + version "1.21.2" + resolved "https://registry.npmjs.org/rc-field-form/-/rc-field-form-1.21.2.tgz#85bda1ee006ae9f1d146e1000337c69b4bb6d101" + integrity sha512-LR/bURt/Tf5g39mb0wtMtQuWn42d/7kEzpzlC5fNC7yaRVmLTtlPP4sBBlaViETM9uZQKLoaB0Pt9Mubhm9gow== + dependencies: + "@babel/runtime" "^7.8.4" + async-validator "^4.0.2" + rc-util "^5.8.0" + +rc-image@~5.2.5: + version "5.2.5" + resolved "https://registry.npmjs.org/rc-image/-/rc-image-5.2.5.tgz#44e6ffc842626827960e7ab72e1c0d6f3a8ce440" + integrity sha512-qUfZjYIODxO0c8a8P5GeuclYXZjzW4hV/5hyo27XqSFo1DmTCs2HkVeQObkcIk5kNsJtgsj1KoPThVsSc/PXOw== + dependencies: + "@babel/runtime" "^7.11.2" + classnames "^2.2.6" + rc-dialog "~8.6.0" + rc-util "^5.0.6" + +rc-input-number@~7.3.0: + version "7.3.4" + resolved "https://registry.npmjs.org/rc-input-number/-/rc-input-number-7.3.4.tgz#674aea98260250287d36e330a7e065b174486e9d" + integrity sha512-W9uqSzuvJUnz8H8vsVY4kx+yK51SsAxNTwr8SNH4G3XqQNocLVmKIibKFRjocnYX1RDHMND9FFbgj2h7E7nvGA== + dependencies: + "@babel/runtime" "^7.10.1" + classnames "^2.2.5" + rc-util "^5.9.8" + +rc-mentions@~1.6.1: + version "1.6.1" + resolved "https://registry.npmjs.org/rc-mentions/-/rc-mentions-1.6.1.tgz#46035027d64aa33ef840ba0fbd411871e34617ae" + integrity sha512-LDzGI8jJVGnkhpTZxZuYBhMz3avcZZqPGejikchh97xPni/g4ht714Flh7DVvuzHQ+BoKHhIjobHnw1rcP8erg== + dependencies: + "@babel/runtime" "^7.10.1" + classnames "^2.2.6" + rc-menu "^9.0.0" + rc-textarea "^0.3.0" + rc-trigger "^5.0.4" + rc-util "^5.0.1" + +rc-menu@^9.0.0, rc-menu@~9.0.12: version "9.0.14" resolved "https://registry.npmjs.org/rc-menu/-/rc-menu-9.0.14.tgz#289bda4a2f6c5ebb3248e2e305d52cf0c73cb9d5" integrity sha512-CIox5mZeLDAi32SlHrV7UeSjv7tmJJhwRyxQtZCKt351w3q59XlL4WMFOmtT9gwIfP9h0XoxdBZUMe/xzkp78A== @@ -11266,7 +11932,7 @@ rc-menu@^9.0.0: rc-util "^5.12.0" shallowequal "^1.1.0" -rc-motion@^2.0.0, rc-motion@^2.0.1, rc-motion@^2.4.1, rc-motion@^2.4.3: +rc-motion@^2.0.0, rc-motion@^2.0.1, rc-motion@^2.2.0, rc-motion@^2.3.0, rc-motion@^2.3.4, rc-motion@^2.4.1, rc-motion@^2.4.3, rc-motion@^2.4.4: version "2.4.4" resolved "https://registry.npmjs.org/rc-motion/-/rc-motion-2.4.4.tgz#e995d5fa24fc93065c24f714857cf2677d655bb0" integrity sha512-ms7n1+/TZQBS0Ydd2Q5P4+wJTSOrhIrwNxLXCZpR7Fa3/oac7Yi803HDALc2hLAKaCTQtw9LmQeB58zcwOsqlQ== @@ -11275,7 +11941,17 @@ rc-motion@^2.0.0, rc-motion@^2.0.1, rc-motion@^2.4.1, rc-motion@^2.4.3: classnames "^2.2.1" rc-util "^5.2.1" -rc-overflow@^1.2.0: +rc-notification@~4.5.7: + version "4.5.7" + resolved "https://registry.npmjs.org/rc-notification/-/rc-notification-4.5.7.tgz#265e6e6a0c1a0fac63d6abd4d832eb8ff31522f1" + integrity sha512-zhTGUjBIItbx96SiRu3KVURcLOydLUHZCPpYEn1zvh+re//Tnq/wSxN4FKgp38n4HOgHSVxcLEeSxBMTeBBDdw== + dependencies: + "@babel/runtime" "^7.10.1" + classnames "2.x" + rc-motion "^2.2.0" + rc-util "^5.0.1" + +rc-overflow@^1.0.0, rc-overflow@^1.2.0: version "1.2.2" resolved "https://registry.npmjs.org/rc-overflow/-/rc-overflow-1.2.2.tgz#95b0222016c0cdbdc0db85f569c262e7706a5f22" integrity sha512-X5kj9LDU1ue5wHkqvCprJWLKC+ZLs3p4He/oxjZ1Q4NKaqKBaYf5OdSzRSgh3WH8kSdrfU8LjvlbWnHgJOEkNQ== @@ -11285,6 +11961,45 @@ rc-overflow@^1.2.0: rc-resize-observer "^1.0.0" rc-util "^5.5.1" +rc-pagination@~3.1.9: + version "3.1.14" + resolved "https://registry.npmjs.org/rc-pagination/-/rc-pagination-3.1.14.tgz#1f7d0342edb80dca0989e4ddbe937b1d4657d88d" + integrity sha512-tcugvxrtPiVU00Uh0IwC8NIUlxa4KtA9pXcaMNJdSHeO2uQqVkHEwllsULTAWRF3zRV2ozo2weP/DRKIUrX+Zg== + dependencies: + "@babel/runtime" "^7.10.1" + classnames "^2.2.1" + +rc-picker@~2.5.17: + version "2.5.19" + resolved "https://registry.npmjs.org/rc-picker/-/rc-picker-2.5.19.tgz#73d07546fac3992f0bfabf2789654acada39e46f" + integrity sha512-u6myoCu/qiQ0vLbNzSzNrzTQhs7mldArCpPHrEI6OUiifs+IPXmbesqSm0zilJjfzrZJLgYeyyOMSznSlh0GKA== + dependencies: + "@babel/runtime" "^7.10.1" + classnames "^2.2.1" + date-fns "2.x" + dayjs "1.x" + moment "^2.24.0" + rc-trigger "^5.0.4" + rc-util "^5.4.0" + shallowequal "^1.1.0" + +rc-progress@~3.1.0: + version "3.1.4" + resolved "https://registry.npmjs.org/rc-progress/-/rc-progress-3.1.4.tgz#66040d0fae7d8ced2b38588378eccb2864bad615" + integrity sha512-XBAif08eunHssGeIdxMXOmRQRULdHaDdIFENQ578CMb4dyewahmmfJRyab+hw4KH4XssEzzYOkAInTLS7JJG+Q== + dependencies: + "@babel/runtime" "^7.10.1" + classnames "^2.2.6" + +rc-rate@~2.9.0: + version "2.9.1" + resolved "https://registry.npmjs.org/rc-rate/-/rc-rate-2.9.1.tgz#e43cb95c4eb90a2c1e0b16ec6614d8c43530a731" + integrity sha512-MmIU7FT8W4LYRRHJD1sgG366qKtSaKb67D0/vVvJYR0lrCuRrCiVQ5qhfT5ghVO4wuVIORGpZs7ZKaYu+KMUzA== + dependencies: + "@babel/runtime" "^7.10.1" + classnames "^2.2.5" + rc-util "^5.0.1" + rc-resize-observer@^1.0.0: version "1.0.1" resolved "https://registry.npmjs.org/rc-resize-observer/-/rc-resize-observer-1.0.1.tgz#ccd0986543ff1bf49f8a581e8ac4bb714ed24dcd" @@ -11295,6 +12010,69 @@ rc-resize-observer@^1.0.0: rc-util "^5.0.0" resize-observer-polyfill "^1.5.1" +rc-resize-observer@^1.1.0: + version "1.1.2" + resolved "https://registry.npmjs.org/rc-resize-observer/-/rc-resize-observer-1.1.2.tgz#214bc5d0de19e0a5fcd7d8352d9c1560dd7531b7" + integrity sha512-Qp+1x6D88FxyWBFRYP95IV9A1o0xlkC6qhiTX3YakE+o86QH9IzC7UVnltwmm4Q8uYH+E3F/HRmEiuxXJECdSw== + dependencies: + "@babel/runtime" "^7.10.1" + classnames "^2.2.1" + rc-util "^5.15.0" + resize-observer-polyfill "^1.5.1" + +rc-select@~13.2.1: + version "13.2.1" + resolved "https://registry.npmjs.org/rc-select/-/rc-select-13.2.1.tgz#d69675f8bc72622a8f3bc024fa21bfee8d56257d" + integrity sha512-L2cJFAjVEeDiNVa/dlOVKE79OUb0J7sUBvWN3Viav3XHcjvv9Ovn4D8J9QhBSlDXeGuczZ81CZI3BbdHD25+Gg== + dependencies: + "@babel/runtime" "^7.10.1" + classnames "2.x" + rc-motion "^2.0.1" + rc-overflow "^1.0.0" + rc-trigger "^5.0.4" + rc-util "^5.9.8" + rc-virtual-list "^3.2.0" + +rc-slider@~9.7.4: + version "9.7.5" + resolved "https://registry.npmjs.org/rc-slider/-/rc-slider-9.7.5.tgz#193141c68e99b1dc3b746daeb6bf852946f5b7f4" + integrity sha512-LV/MWcXFjco1epPbdw1JlLXlTgmWpB9/Y/P2yinf8Pg3wElHxA9uajN21lJiWtZjf5SCUekfSP6QMJfDo4t1hg== + dependencies: + "@babel/runtime" "^7.10.1" + classnames "^2.2.5" + rc-tooltip "^5.0.1" + rc-util "^5.16.1" + shallowequal "^1.1.0" + +rc-steps@~4.1.0: + version "4.1.4" + resolved "https://registry.npmjs.org/rc-steps/-/rc-steps-4.1.4.tgz#0ba82db202d59ca52d0693dc9880dd145b19dc23" + integrity sha512-qoCqKZWSpkh/b03ASGx1WhpKnuZcRWmvuW+ZUu4mvMdfvFzVxblTwUM+9aBd0mlEUFmt6GW8FXhMpHkK3Uzp3w== + dependencies: + "@babel/runtime" "^7.10.2" + classnames "^2.2.3" + rc-util "^5.0.1" + +rc-switch@~3.2.0: + version "3.2.2" + resolved "https://registry.npmjs.org/rc-switch/-/rc-switch-3.2.2.tgz#d001f77f12664d52595b4f6fb425dd9e66fba8e8" + integrity sha512-+gUJClsZZzvAHGy1vZfnwySxj+MjLlGRyXKXScrtCTcmiYNPzxDFOxdQ/3pK1Kt/0POvwJ/6ALOR8gwdXGhs+A== + dependencies: + "@babel/runtime" "^7.10.1" + classnames "^2.2.1" + rc-util "^5.0.1" + +rc-table@~7.19.0: + version "7.19.2" + resolved "https://registry.npmjs.org/rc-table/-/rc-table-7.19.2.tgz#976337a5dace3b8e04bea9554d72bc83aa5ab301" + integrity sha512-NdpnoM50MK02H5/hGOsObfxCvGFUG5cHB9turE5BKJ81T5Ycbq193w5tLhnpILXe//Oanzr47MdMxkUnVGP+qg== + dependencies: + "@babel/runtime" "^7.10.1" + classnames "^2.2.5" + rc-resize-observer "^1.0.0" + rc-util "^5.14.0" + shallowequal "^1.1.0" + rc-tabs@^11.7.1: version "11.10.3" resolved "https://registry.npmjs.org/rc-tabs/-/rc-tabs-11.10.3.tgz#171c33b340b5a83ababe53034c569b0422046781" @@ -11307,6 +12085,47 @@ rc-tabs@^11.7.1: rc-resize-observer "^1.0.0" rc-util "^5.5.0" +rc-tabs@~11.10.0: + version "11.10.5" + resolved "https://registry.npmjs.org/rc-tabs/-/rc-tabs-11.10.5.tgz#53bbb642d04b307f8ce86e318ab99d519507b29b" + integrity sha512-DDuUdV6b9zGRYLtjI5hyejWLKoz1QiLWNgMeBzc3aMeQylZFhTYnFGdDc6HRqj5IYearNTsFPVSA+6VIT8g5cg== + dependencies: + "@babel/runtime" "^7.11.2" + classnames "2.x" + rc-dropdown "^3.2.0" + rc-menu "^9.0.0" + rc-resize-observer "^1.0.0" + rc-util "^5.5.0" + +rc-textarea@^0.3.0, rc-textarea@~0.3.0: + version "0.3.6" + resolved "https://registry.npmjs.org/rc-textarea/-/rc-textarea-0.3.6.tgz#b255a9dd78648033bac8daa281ad95249122420a" + integrity sha512-6esiDE4AG3lqnmCdgAp/nutrZAqZEfRT3K749H8vMzNtxy9JScuMJ9MMtWN2DDQh+LCDvX4dgflaRjDCqtDHWw== + dependencies: + "@babel/runtime" "^7.10.1" + classnames "^2.2.1" + rc-resize-observer "^1.0.0" + rc-util "^5.7.0" + +rc-tooltip@^5.0.1, rc-tooltip@~5.1.1: + version "5.1.1" + resolved "https://registry.npmjs.org/rc-tooltip/-/rc-tooltip-5.1.1.tgz#94178ed162d0252bc4993b725f5dc2ac0fccf154" + integrity sha512-alt8eGMJulio6+4/uDm7nvV+rJq9bsfxFDCI0ljPdbuoygUscbsMYb6EQgwib/uqsXQUvzk+S7A59uYHmEgmDA== + dependencies: + "@babel/runtime" "^7.11.2" + rc-trigger "^5.0.0" + +rc-tree-select@~4.8.0: + version "4.8.0" + resolved "https://registry.npmjs.org/rc-tree-select/-/rc-tree-select-4.8.0.tgz#bcbcfb45553f84a878e4ff037ff00b526a4afa62" + integrity sha512-evuVIF7GHCGDdvISdBWl4ZYmG/8foof/RDtzCu/WFLA1tFKZD77RRC3khEsjh4WgsB0vllLe7j+ODJ7jHRcDRQ== + dependencies: + "@babel/runtime" "^7.10.1" + classnames "2.x" + rc-select "~13.2.1" + rc-tree "~5.3.0" + rc-util "^5.7.0" + rc-tree@^5.2.0: version "5.3.0" resolved "https://registry.npmjs.org/rc-tree/-/rc-tree-5.3.0.tgz#766195ffbd65741000d4caf66980bd474d8ac9a2" @@ -11318,7 +12137,18 @@ rc-tree@^5.2.0: rc-util "^5.0.0" rc-virtual-list "^3.4.1" -rc-trigger@^5.0.4, rc-trigger@^5.1.2: +rc-tree@~5.3.0: + version "5.3.3" + resolved "https://registry.npmjs.org/rc-tree/-/rc-tree-5.3.3.tgz#9a0c7ce2f171829f5aee788b2c644fc307b97794" + integrity sha512-WKblt5P0Co+eWhqG/xcKexZ7ir3UU5PlH4Y0hFd7zBopJMc0p6ysp2hgLK+EgjaJz7FHVJY9k5kpIKuBWHHDNA== + dependencies: + "@babel/runtime" "^7.10.1" + classnames "2.x" + rc-motion "^2.0.1" + rc-util "^5.16.1" + rc-virtual-list "^3.4.1" + +rc-trigger@^5.0.0, rc-trigger@^5.0.4, rc-trigger@^5.1.2, rc-trigger@^5.2.10: version "5.2.10" resolved "https://registry.npmjs.org/rc-trigger/-/rc-trigger-5.2.10.tgz#8a0057a940b1b9027eaa33beec8a6ecd85cce2b1" integrity sha512-FkUf4H9BOFDaIwu42fvRycXMAvkttph9AlbCZXssZDVzz2L+QZ0ERvfB/4nX3ZFPh1Zd+uVGr1DEDeXxq4J1TA== @@ -11329,6 +12159,15 @@ rc-trigger@^5.0.4, rc-trigger@^5.1.2: rc-motion "^2.0.0" rc-util "^5.5.0" +rc-upload@~4.3.0: + version "4.3.3" + resolved "https://registry.npmjs.org/rc-upload/-/rc-upload-4.3.3.tgz#e237aa525e5313fa16f4d04d27f53c2f0e157bb8" + integrity sha512-YoJ0phCRenMj1nzwalXzciKZ9/FAaCrFu84dS5pphwucTC8GUWClcDID/WWNGsLFcM97NqIboDqrV82rVRhW/w== + dependencies: + "@babel/runtime" "^7.10.1" + classnames "^2.2.5" + rc-util "^5.2.0" + rc-util@^5.0.0, rc-util@^5.0.7, rc-util@^5.12.0, rc-util@^5.2.1, rc-util@^5.3.0, rc-util@^5.5.0, rc-util@^5.5.1: version "5.15.0" resolved "https://registry.npmjs.org/rc-util/-/rc-util-5.15.0.tgz#3527bd6c5806cf04476e17a0c7bf094fc8ea4666" @@ -11338,7 +12177,16 @@ rc-util@^5.0.0, rc-util@^5.0.7, rc-util@^5.12.0, rc-util@^5.2.1, rc-util@^5.3.0, react-is "^16.12.0" shallowequal "^1.1.0" -rc-virtual-list@^3.4.1: +rc-util@^5.0.1, rc-util@^5.0.6, rc-util@^5.14.0, rc-util@^5.15.0, rc-util@^5.16.1, rc-util@^5.2.0, rc-util@^5.4.0, rc-util@^5.6.1, rc-util@^5.7.0, rc-util@^5.8.0, rc-util@^5.9.4, rc-util@^5.9.8: + version "5.16.1" + resolved "https://registry.npmjs.org/rc-util/-/rc-util-5.16.1.tgz#374db7cb735512f05165ddc3d6b2c61c21b8b4e3" + integrity sha512-kSCyytvdb3aRxQacS/71ta6c+kBWvM1v8/2h9d/HaNWauc3qB8pLnF20PJ8NajkNN8gb+rR1l0eWO+D4Pz+LLQ== + dependencies: + "@babel/runtime" "^7.12.5" + react-is "^16.12.0" + shallowequal "^1.1.0" + +rc-virtual-list@^3.2.0, rc-virtual-list@^3.4.1: version "3.4.2" resolved "https://registry.npmjs.org/rc-virtual-list/-/rc-virtual-list-3.4.2.tgz#1078327aa7230b5e456d679ed2ce99f3c036ebd1" integrity sha512-OyVrrPvvFcHvV0ssz5EDZ+7Rf5qLat/+mmujjchNw5FfbJWNDwkpQ99EcVE6+FtNRmX9wFa1LGNpZLUTvp/4GQ== @@ -11386,6 +12234,15 @@ react-dom@^17.0.1: object-assign "^4.1.1" scheduler "^0.20.2" +react-i18next@^11.15.1: + version "11.15.1" + resolved "https://registry.npmjs.org/react-i18next/-/react-i18next-11.15.1.tgz#1dec5f2bf2cf7bc5043e9fcb391c9d6e24bb9bfe" + integrity sha512-lnje1uKu5XeM5MLvfbt1oygF+nEIZnpOM4Iu8bkx5ECD4XRYgi3SJDmolrp0EDxDHeK2GgFb+vEEK0hsZ9sjeA== + dependencies: + "@babel/runtime" "^7.14.5" + html-escaper "^2.0.2" + html-parse-stringify "^3.0.1" + react-is@^16.12.0, react-is@^16.6.0, react-is@^16.7.0, react-is@^16.8.1, react-is@^16.8.4: version "16.13.1" resolved "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz#789729a4dc36de2999dc156dd6c1d9c18cea56a4" @@ -11437,6 +12294,23 @@ react-router@5.2.0: tiny-invariant "^1.0.2" tiny-warning "^1.0.0" +react-sortable-hoc@^1.11.0: + version "1.11.0" + resolved "https://registry.npmjs.org/react-sortable-hoc/-/react-sortable-hoc-1.11.0.tgz#fe4022362bbafc4b836f5104b9676608a40a278f" + integrity sha512-v1CDCvdfoR3zLGNp6qsBa4J1BWMEVH25+UKxF/RvQRh+mrB+emqtVHMgZ+WreUiKJoEaiwYoScaueIKhMVBHUg== + dependencies: + "@babel/runtime" "^7.2.0" + invariant "^2.2.4" + prop-types "^15.5.7" + +react-sticky-box@^0.9.3: + version "0.9.3" + resolved "https://registry.npmjs.org/react-sticky-box/-/react-sticky-box-0.9.3.tgz#8450d4cef8e4fdd7b0351520365bc98c97da11af" + integrity sha512-Y/qO7vTqAvXuRR6G6ZCW4fX2Bz0GZRwiiLTVeZN5CVz9wzs37ev0Xj3KSKF/PzF0jifwATivI4t24qXG8rSz4Q== + dependencies: + "@babel/runtime" "^7.1.5" + resize-observer-polyfill "^1.5.1" + react@16.x: version "16.14.0" resolved "https://registry.npmjs.org/react/-/react-16.14.0.tgz#94d776ddd0aaa37da3eda8fc5b6b18a4c9a3114d" @@ -11883,7 +12757,7 @@ require-main-filename@^2.0.0: resolved "https://registry.npmjs.org/require-main-filename/-/require-main-filename-2.0.0.tgz#d0b329ecc7cc0f61649f62215be69af54aa8989b" integrity sha512-NKN5kMDylKuldxYLSUfrbo5Tuzh4hd+2E8NPPX02mZtn1VuREQToYe/ZdlJy+J3uCpfaiGF05e7B8W0iXbQHmg== -resize-observer-polyfill@^1.5.1: +resize-observer-polyfill@^1.5.0, resize-observer-polyfill@^1.5.1: version "1.5.1" resolved "https://registry.npmjs.org/resize-observer-polyfill/-/resize-observer-polyfill-1.5.1.tgz#0e9020dd3d21024458d4ebd27e23e40269810464" integrity sha512-LwZrotdHOo12nQuZlHEmtuXdqGoOD0OhaxopaNFxWzInpEgaLWoVuAMbTzixuosCx2nEG58ngzW3vxdWoxIgdg== @@ -11928,7 +12802,7 @@ resolve-url@^0.2.1: resolved "https://registry.npmjs.org/resolve-url/-/resolve-url-0.2.1.tgz#2c637fe77c893afd2a663fe21aa9080068e2052a" integrity sha1-LGN/53yJOv0qZj/iGqkIAGjiBSo= -resolve@^1.10.0, resolve@^1.10.1, resolve@^1.14.2, resolve@^1.18.1, resolve@^1.20.0: +resolve@^1.10.0, resolve@^1.10.1, resolve@^1.12.0, resolve@^1.14.2, resolve@^1.18.1, resolve@^1.20.0: version "1.20.0" resolved "https://registry.npmjs.org/resolve/-/resolve-1.20.0.tgz#629a013fb3f70755d6f0b7935cc1c2c5378b1975" integrity sha512-wENBPt4ySzg4ybFQW2TT1zMQucPK95HSh/nq2CFTZVOGut2+pQvSsgtda4d26YrYcr067wjbmzOG8byDPBX63A== @@ -12123,6 +12997,18 @@ schema-utils@^3.0.0: ajv "^6.12.5" ajv-keywords "^3.5.2" +screenfull@^5.0.0: + version "5.2.0" + resolved "https://registry.npmjs.org/screenfull/-/screenfull-5.2.0.tgz#6533d524d30621fc1283b9692146f3f13a93d1ba" + integrity sha512-9BakfsO2aUQN2K9Fdbj87RJIEZ82Q9IGim7FqM5OsebfoFC6ZHXgDq/KvniuLTPdeM8wY2o6Dj3WQ7KeQCj3cA== + +scroll-into-view-if-needed@^2.2.25: + version "2.2.28" + resolved "https://registry.npmjs.org/scroll-into-view-if-needed/-/scroll-into-view-if-needed-2.2.28.tgz#5a15b2f58a52642c88c8eca584644e01703d645a" + integrity sha512-8LuxJSuFVc92+0AdNv4QOxRL4Abeo1DgLnGNkn1XlaujPH/3cCFz3QI60r2VNu4obJJROzgnIUw5TKQkZvZI1w== + dependencies: + compute-scroll-into-view "^1.0.17" + sdk-base@^2.0.1: version "2.0.1" resolved "https://registry.npmjs.org/sdk-base/-/sdk-base-2.0.1.tgz#ba40289e8bdf272ed11dd9ea97eaf98e036d24c6" @@ -12445,7 +13331,7 @@ source-map-url@^0.4.0: resolved "https://registry.npmjs.org/source-map-url/-/source-map-url-0.4.1.tgz#0af66605a745a5a2f91cf1bbf8a7afbc283dec56" integrity sha512-cPiFOTLUKvJFIg4SKVScy4ilPPW6rFgMgfuZJPNoDuMs3nC1HbMUycBoJw77xFIp6z1UJQJOfx6C9GMH80DiTw== -source-map@^0.5.0, source-map@^0.5.6: +source-map@^0.5.0, source-map@^0.5.6, source-map@^0.5.7: version "0.5.7" resolved "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz#8a039d2d1021d22d1ea14c80d8ea468ba2ef3fcc" integrity sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w= @@ -12643,6 +13529,11 @@ strict-uri-encode@^2.0.0: resolved "https://registry.npmjs.org/strict-uri-encode/-/strict-uri-encode-2.0.0.tgz#b9c7330c7042862f6b142dc274bbcc5866ce3546" integrity sha1-ucczDHBChi9rFC3CdLvMWGbONUY= +string-convert@^0.2.0: + version "0.2.1" + resolved "https://registry.npmjs.org/string-convert/-/string-convert-0.2.1.tgz#6982cc3049fbb4cd85f8b24568b9d9bf39eeff97" + integrity sha1-aYLMMEn7tM2F+LJFaLnZvznu/5c= + string-length@^4.0.1: version "4.0.2" resolved "https://registry.npmjs.org/string-length/-/string-length-4.0.2.tgz#a8a8dc7bd5c1a82b9b3c8b87e125f66871b6e57a" @@ -12844,6 +13735,11 @@ style-to-object@^0.3.0: dependencies: inline-style-parser "0.1.1" +stylis@4.0.13: + version "4.0.13" + resolved "https://registry.npmjs.org/stylis/-/stylis-4.0.13.tgz#f5db332e376d13cc84ecfe5dace9a2a51d954c91" + integrity sha512-xGPXiFVl4YED9Jh7Euv2V220mriG9u4B2TA6Ybjc1catrstKD2PpIdU3U0RKpkVBC2EhmL/F0sPCr9vrFTNRag== + superagent@^6.1.0: version "6.1.0" resolved "https://registry.npmjs.org/superagent/-/superagent-6.1.0.tgz#09f08807bc41108ef164cfb4be293cebd480f4a6" @@ -13148,6 +14044,11 @@ to-regex@^3.0.1, to-regex@^3.0.2: regex-not "^1.0.2" safe-regex "^1.1.0" +toggle-selection@^1.0.6: + version "1.0.6" + resolved "https://registry.npmjs.org/toggle-selection/-/toggle-selection-1.0.6.tgz#6e45b1263f2017fa0acc7d89d78b15b8bf77da32" + integrity sha1-bkWxJj8gF/oKzH2J14sVuL932jI= + toidentifier@1.0.1: version "1.0.1" resolved "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.1.tgz#3be34321a88a820ed1bd80dfaa33e479fbb8dd35" @@ -13256,7 +14157,7 @@ tslib@^1.8.1, tslib@^1.9.0: resolved "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz#cf2d38bdc34a134bcaf1091c41f6619e2f672d00" integrity sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg== -tslib@^2.0.1, tslib@^2.3.1: +tslib@^2.0.0, tslib@^2.0.1, tslib@^2.0.3, tslib@^2.3.1: version "2.3.1" resolved "https://registry.npmjs.org/tslib/-/tslib-2.3.1.tgz#e8a335add5ceae51aa261d32a490158ef042ef01" integrity sha512-77EbyPPpMz+FRFRuAFlWMtmgUWGe9UOG2Z25NqCwiIjRhOf5iKGuzSe5P2w1laq+FkRy4p+PCuVkJSGkzTEKVw== @@ -13599,6 +14500,13 @@ update-notifier@^2.2.0: semver-diff "^2.0.0" xdg-basedir "^3.0.0" +upper-case@^2.0.1: + version "2.0.2" + resolved "https://registry.npmjs.org/upper-case/-/upper-case-2.0.2.tgz#d89810823faab1df1549b7d97a76f8662bae6f7a" + integrity sha512-KgdgDGJt2TpuwBUIjgG6lzw2GWFRCW9Qkfkiv0DxqHHLYJHmtmdUIKcZd8rHgFSjopVTlw6ggzCm1b8MFQwikg== + dependencies: + tslib "^2.0.3" + uri-js@^4.2.2: version "4.4.1" resolved "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz#9b1a52595225859e55f669d928f88c6c57f2a77e" @@ -13812,6 +14720,11 @@ vm2@^3.9.3: resolved "https://registry.npmjs.org/vm2/-/vm2-3.9.5.tgz#5288044860b4bbace443101fcd3bddb2a0aa2496" integrity sha512-LuCAHZN75H9tdrAiLFf030oW7nJV5xwNMuk1ymOZwopmuK3d2H4L1Kv4+GFHgarKiLfXXLFU+7LDABHnwOkWng== +void-elements@3.1.0: + version "3.1.0" + resolved "https://registry.npmjs.org/void-elements/-/void-elements-3.1.0.tgz#614f7fbf8d801f0bb5f0661f5b2f5785750e4f09" + integrity sha1-YU9/v42AHwu18GYfWy9XhXUOTwk= + vue-eslint-parser@^7.10.0: version "7.11.0" resolved "https://registry.npmjs.org/vue-eslint-parser/-/vue-eslint-parser-7.11.0.tgz#214b5dea961007fcffb2ee65b8912307628d0daf" @@ -13846,6 +14759,13 @@ walker@^1.0.7, walker@~1.0.5: dependencies: makeerror "1.0.12" +warning@^4.0.1: + version "4.0.3" + resolved "https://registry.npmjs.org/warning/-/warning-4.0.3.tgz#16e9e077eb8a86d6af7d64aa1e05fd85b4678ca3" + integrity sha512-rpJyN222KWIvHJ/F53XSZv0Zl/accqHR8et1kpaMTD/fLCRxtV8iX8czMzY7sVZupTI3zcUTg8eycS2kNF9l6w== + dependencies: + loose-envify "^1.0.0" + wcwidth@^1.0.0: version "1.0.1" resolved "https://registry.npmjs.org/wcwidth/-/wcwidth-1.0.1.tgz#f0b0dcf915bc5ff1528afadb2c0e17b532da2fe8" @@ -14149,7 +15069,7 @@ yallist@^4.0.0: resolved "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz#9bb92790d9c0effec63be73519e11a35019a3a72" integrity sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A== -yaml@^1.10.0: +yaml@^1.10.0, yaml@^1.7.2: version "1.10.2" resolved "https://registry.npmjs.org/yaml/-/yaml-1.10.2.tgz#2301c5ffbf12b467de8da2333a459e29e7920e4b" integrity sha512-r3vXyErRCYJ7wg28yvBY5VSoAF8ZvlcW9/BwUzEtUsjvX/DKs24dIkuwjtuprwJJHsbyUbLApepYTR1BN4uHrg==