refactor: client application (#533)
* refactor: client application * feat: application * fix: improve code * fix: app plugin * fix: app plugin * fix: china region plugin
This commit is contained in:
parent
245bd01bd6
commit
3dce31f6a1
@ -3,8 +3,7 @@
|
|||||||
"version": "0.7.0-alpha.83",
|
"version": "0.7.0-alpha.83",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@nocobase/client": "0.7.0-alpha.83",
|
"@nocobase/client": "0.7.0-alpha.83"
|
||||||
"@nocobase/plugin-export": "0.7.0-alpha.83"
|
|
||||||
},
|
},
|
||||||
"repository": {
|
"repository": {
|
||||||
"type": "git",
|
"type": "git",
|
||||||
|
@ -1,10 +0,0 @@
|
|||||||
import { APIClient } from '@nocobase/client';
|
|
||||||
|
|
||||||
const apiClient = new APIClient({
|
|
||||||
baseURL: process.env.API_BASE_URL,
|
|
||||||
headers: {
|
|
||||||
'X-Hostname': window?.location?.hostname,
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
export default apiClient;
|
|
@ -1,3 +0,0 @@
|
|||||||
.title {
|
|
||||||
background: rgb(121, 242, 157);
|
|
||||||
}
|
|
@ -1,128 +1,14 @@
|
|||||||
import {
|
import { Application } from '@nocobase/client';
|
||||||
ACLProvider,
|
|
||||||
ACLShortcut,
|
|
||||||
AdminLayout,
|
|
||||||
AntdConfigProvider,
|
|
||||||
AntdSchemaComponentProvider,
|
|
||||||
APIClientProvider,
|
|
||||||
AuthLayout,
|
|
||||||
BlockSchemaComponentProvider,
|
|
||||||
BlockTemplateDetails,
|
|
||||||
BlockTemplatePage,
|
|
||||||
ChinaRegionProvider,
|
|
||||||
CollectionManagerShortcut,
|
|
||||||
compose,
|
|
||||||
DesignableSwitch,
|
|
||||||
FileStorageShortcut,
|
|
||||||
i18n,
|
|
||||||
MenuItemInitializers,
|
|
||||||
PluginManagerProvider,
|
|
||||||
RemoteDocumentTitleProvider,
|
|
||||||
RemoteRouteSwitchProvider,
|
|
||||||
// RemoteCollectionManagerProvider,
|
|
||||||
RouteSchemaComponent,
|
|
||||||
RouteSwitch,
|
|
||||||
SchemaComponentProvider,
|
|
||||||
SchemaInitializerProvider,
|
|
||||||
SchemaTemplateShortcut,
|
|
||||||
SigninPage,
|
|
||||||
SignupPage,
|
|
||||||
Slate,
|
|
||||||
SystemSettingsProvider,
|
|
||||||
SystemSettingsShortcut,
|
|
||||||
useRoutes,
|
|
||||||
WorkflowPage,
|
|
||||||
WorkflowRouteProvider,
|
|
||||||
WorkflowShortcut
|
|
||||||
} from '@nocobase/client';
|
|
||||||
import { AuditLogsProvider } from '@nocobase/plugin-audit-logs/client';
|
|
||||||
import { ExportPluginProvider } from '@nocobase/plugin-export/client';
|
|
||||||
import { notification } from 'antd';
|
|
||||||
import 'antd/dist/antd.css';
|
|
||||||
import React from 'react';
|
|
||||||
import { I18nextProvider } from 'react-i18next';
|
|
||||||
import { Link, NavLink } from 'react-router-dom';
|
|
||||||
import apiClient from './apiClient';
|
|
||||||
|
|
||||||
apiClient.axios.interceptors.response.use(
|
export const app = new Application({
|
||||||
(response) => response,
|
apiClient: {
|
||||||
(error) => {
|
baseURL: process.env.API_BASE_URL,
|
||||||
const redirectTo = error?.response?.data?.redirectTo;
|
|
||||||
if (redirectTo) {
|
|
||||||
return (window.location.href = redirectTo);
|
|
||||||
}
|
|
||||||
notification.error({
|
|
||||||
message: error?.response?.data?.errors?.map?.((error: any) => {
|
|
||||||
return <div>{error.message}</div>;
|
|
||||||
}),
|
|
||||||
});
|
|
||||||
throw error;
|
|
||||||
},
|
},
|
||||||
);
|
plugins: [
|
||||||
|
require('@nocobase/plugin-china-region/client').default,
|
||||||
const providers = [
|
require('@nocobase/plugin-export/client').default,
|
||||||
// [HashRouter],
|
require('@nocobase/plugin-audit-logs/client').default,
|
||||||
// [MemoryRouter, { initialEntries: ['/'] }],
|
|
||||||
[APIClientProvider, { apiClient }],
|
|
||||||
[I18nextProvider, { i18n }],
|
|
||||||
[AntdConfigProvider, { remoteLocale: true }],
|
|
||||||
[
|
|
||||||
RemoteRouteSwitchProvider,
|
|
||||||
{
|
|
||||||
components: {
|
|
||||||
AuthLayout,
|
|
||||||
AdminLayout,
|
|
||||||
RouteSchemaComponent,
|
|
||||||
SigninPage,
|
|
||||||
SignupPage,
|
|
||||||
WorkflowPage,
|
|
||||||
BlockTemplatePage,
|
|
||||||
BlockTemplateDetails,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
],
|
],
|
||||||
SystemSettingsProvider,
|
|
||||||
[
|
|
||||||
PluginManagerProvider,
|
|
||||||
{
|
|
||||||
components: {
|
|
||||||
ACLShortcut,
|
|
||||||
DesignableSwitch,
|
|
||||||
CollectionManagerShortcut,
|
|
||||||
WorkflowShortcut,
|
|
||||||
SystemSettingsShortcut,
|
|
||||||
SchemaTemplateShortcut,
|
|
||||||
FileStorageShortcut,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
],
|
|
||||||
[SchemaComponentProvider, { components: { Slate, Link, NavLink } }],
|
|
||||||
// RemoteCollectionManagerProvider,
|
|
||||||
[
|
|
||||||
SchemaInitializerProvider,
|
|
||||||
{
|
|
||||||
initializers: {
|
|
||||||
MenuItemInitializers,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
],
|
|
||||||
ExportPluginProvider,
|
|
||||||
AuditLogsProvider,
|
|
||||||
BlockSchemaComponentProvider,
|
|
||||||
AntdSchemaComponentProvider,
|
|
||||||
ACLProvider,
|
|
||||||
ChinaRegionProvider,
|
|
||||||
WorkflowRouteProvider,
|
|
||||||
RemoteDocumentTitleProvider,
|
|
||||||
];
|
|
||||||
|
|
||||||
const App = compose(...providers)(() => {
|
|
||||||
const routes = useRoutes();
|
|
||||||
return (
|
|
||||||
<div>
|
|
||||||
<RouteSwitch routes={routes} />
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
});
|
});
|
||||||
|
|
||||||
export default App;
|
export default app.render();
|
||||||
|
@ -1,172 +0,0 @@
|
|||||||
import { uid } from '@formily/shared';
|
|
||||||
import { APIClient } from '@nocobase/client';
|
|
||||||
import MockAdapter from 'axios-mock-adapter';
|
|
||||||
|
|
||||||
export default (apiClient: APIClient) => {
|
|
||||||
const mock = new MockAdapter(apiClient.axios);
|
|
||||||
|
|
||||||
mock.onGet('/app:getLang').reply(200, {
|
|
||||||
data: { lang: 'en-US' },
|
|
||||||
});
|
|
||||||
|
|
||||||
mock.onGet('/systemSettings:get/1').reply(200, {
|
|
||||||
data: {
|
|
||||||
title: 'NocoBase',
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
const jsonSchema: any = {
|
|
||||||
qqzzjakwkwl: {
|
|
||||||
name: 'qqzzjakwkwl',
|
|
||||||
type: 'void',
|
|
||||||
'x-component': 'Menu',
|
|
||||||
'x-component-props': {
|
|
||||||
mode: 'mix',
|
|
||||||
theme: 'dark',
|
|
||||||
// defaultSelectedUid: 'u8',
|
|
||||||
onSelect: '{{ onSelect }}',
|
|
||||||
sideMenuRefScopeKey: 'sideMenuRef',
|
|
||||||
},
|
|
||||||
properties: {
|
|
||||||
item3: {
|
|
||||||
type: 'void',
|
|
||||||
title: 'SubMenu u3',
|
|
||||||
'x-uid': 'u3',
|
|
||||||
'x-component': 'Menu.SubMenu',
|
|
||||||
'x-component-props': {},
|
|
||||||
properties: {
|
|
||||||
item6: {
|
|
||||||
type: 'void',
|
|
||||||
title: 'SubMenu u6',
|
|
||||||
'x-uid': 'u6',
|
|
||||||
'x-component': 'Menu.SubMenu',
|
|
||||||
'x-component-props': {},
|
|
||||||
properties: {
|
|
||||||
item7: {
|
|
||||||
type: 'void',
|
|
||||||
title: 'Menu Item u7',
|
|
||||||
'x-uid': 'u7',
|
|
||||||
'x-component': 'Menu.Item',
|
|
||||||
'x-component-props': {},
|
|
||||||
},
|
|
||||||
item8: {
|
|
||||||
type: 'void',
|
|
||||||
title: 'Menu Item u8',
|
|
||||||
'x-uid': 'u8',
|
|
||||||
'x-component': 'Menu.Item',
|
|
||||||
'x-component-props': {},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
item4: {
|
|
||||||
type: 'void',
|
|
||||||
title: 'Menu Item u4',
|
|
||||||
'x-uid': 'u4',
|
|
||||||
'x-component': 'Menu.Item',
|
|
||||||
'x-component-props': {},
|
|
||||||
},
|
|
||||||
item5: {
|
|
||||||
type: 'void',
|
|
||||||
title: 'Menu Item u5',
|
|
||||||
'x-uid': 'u5',
|
|
||||||
'x-component': 'Menu.Item',
|
|
||||||
'x-component-props': {},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
item1: {
|
|
||||||
type: 'void',
|
|
||||||
title: 'Menu Item u1',
|
|
||||||
'x-uid': 'u1',
|
|
||||||
'x-component': 'Menu.Item',
|
|
||||||
'x-component-props': {},
|
|
||||||
},
|
|
||||||
item2: {
|
|
||||||
type: 'void',
|
|
||||||
title: 'Menu Item u2',
|
|
||||||
'x-uid': 'u2',
|
|
||||||
'x-component': 'Menu.Item',
|
|
||||||
'x-component-props': {},
|
|
||||||
},
|
|
||||||
item9: {
|
|
||||||
type: 'void',
|
|
||||||
title: 'SubMenu u9',
|
|
||||||
'x-uid': 'u9',
|
|
||||||
'x-component': 'Menu.SubMenu',
|
|
||||||
'x-component-props': {},
|
|
||||||
properties: {
|
|
||||||
item10: {
|
|
||||||
type: 'void',
|
|
||||||
title: 'Menu Item u10',
|
|
||||||
'x-uid': 'u10',
|
|
||||||
'x-component': 'Menu.Item',
|
|
||||||
'x-component-props': {},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
mock.onGet(/\/uiSchemas\:getJsonSchema\/(\w+)/).reply(function (config) {
|
|
||||||
const name = config?.url?.split('/')?.pop();
|
|
||||||
|
|
||||||
if (name && jsonSchema[name]) {
|
|
||||||
return [200, { data: jsonSchema[name] }];
|
|
||||||
}
|
|
||||||
|
|
||||||
const response = {
|
|
||||||
data: {
|
|
||||||
type: 'void',
|
|
||||||
name: name,
|
|
||||||
'x-uid': name,
|
|
||||||
'x-component': 'Page',
|
|
||||||
properties: {
|
|
||||||
[uid()]: {
|
|
||||||
type: 'void',
|
|
||||||
name: 'grid1',
|
|
||||||
'x-component': 'Grid',
|
|
||||||
'x-item-initializer': 'Grid.AddBlockItem',
|
|
||||||
'x-uid': uid(),
|
|
||||||
properties: {},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
};
|
|
||||||
return [200, response];
|
|
||||||
});
|
|
||||||
|
|
||||||
mock.onGet('/routes:getAccessible').reply(200, {
|
|
||||||
data: [
|
|
||||||
{
|
|
||||||
type: 'redirect',
|
|
||||||
from: '/',
|
|
||||||
to: '/admin',
|
|
||||||
exact: true,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
type: 'route',
|
|
||||||
uiSchemaUid: 'qqzzjakwkwl',
|
|
||||||
path: '/admin/:name(.+)?',
|
|
||||||
component: 'AdminLayout',
|
|
||||||
title: 'NocoBase Admin',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
type: 'route',
|
|
||||||
component: 'AuthLayout',
|
|
||||||
routes: [
|
|
||||||
{
|
|
||||||
type: 'route',
|
|
||||||
path: '/signin',
|
|
||||||
component: 'SigninPage',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
type: 'route',
|
|
||||||
path: '/signup',
|
|
||||||
component: 'SignupPage',
|
|
||||||
},
|
|
||||||
],
|
|
||||||
},
|
|
||||||
],
|
|
||||||
});
|
|
||||||
};
|
|
@ -12,6 +12,7 @@
|
|||||||
"strict": true,
|
"strict": true,
|
||||||
"paths": {
|
"paths": {
|
||||||
"@nocobase/plugin-*/client": ["../../plugins/*/src/client"],
|
"@nocobase/plugin-*/client": ["../../plugins/*/src/client"],
|
||||||
|
"@nocobase/utils/client": ["../../core/utils/src/client"],
|
||||||
"@nocobase/*": ["../../core/*/src/"],
|
"@nocobase/*": ["../../core/*/src/"],
|
||||||
"@/*": ["src/*"],
|
"@/*": ["src/*"],
|
||||||
"@@/*": ["src/.umi/*"]
|
"@@/*": ["src/.umi/*"]
|
||||||
|
@ -39,7 +39,6 @@ module.exports = (cli) => {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
await postCheck(opts);
|
await postCheck(opts);
|
||||||
await run('node', [`./packages/${APP_PACKAGE_ROOT}/server/lib/index.js`, 'install', '--silent']);
|
|
||||||
if (opts.dbSync) {
|
if (opts.dbSync) {
|
||||||
await run('node', [`./packages/${APP_PACKAGE_ROOT}/server/lib/index.js`, 'db:sync']);
|
await run('node', [`./packages/${APP_PACKAGE_ROOT}/server/lib/index.js`, 'db:sync']);
|
||||||
}
|
}
|
||||||
|
@ -39,9 +39,6 @@
|
|||||||
"react-js-cron": "^1.4.0",
|
"react-js-cron": "^1.4.0",
|
||||||
"react-quill": "^1.3.5",
|
"react-quill": "^1.3.5",
|
||||||
"react-router-dom": "^5.2.0",
|
"react-router-dom": "^5.2.0",
|
||||||
"slate": "^0.76.1",
|
|
||||||
"slate-history": "^0.66.0",
|
|
||||||
"slate-react": "^0.76.1",
|
|
||||||
"use-deep-compare-effect": "^1.8.1"
|
"use-deep-compare-effect": "^1.8.1"
|
||||||
},
|
},
|
||||||
"peerDependencies": {
|
"peerDependencies": {
|
||||||
|
@ -1,6 +1,31 @@
|
|||||||
import { APIClient as APIClientSDK } from '@nocobase/sdk';
|
import { APIClient as APIClientSDK } from '@nocobase/sdk';
|
||||||
import { Result } from 'ahooks/lib/useRequest/src/types';
|
import { Result } from 'ahooks/lib/useRequest/src/types';
|
||||||
|
import { notification } from 'antd';
|
||||||
|
import React from 'react';
|
||||||
|
|
||||||
export class APIClient extends APIClientSDK {
|
export class APIClient extends APIClientSDK {
|
||||||
services: Record<string, Result<any, any>>;
|
services: Record<string, Result<any, any>>;
|
||||||
|
|
||||||
|
interceptors() {
|
||||||
|
super.interceptors();
|
||||||
|
this.notification();
|
||||||
|
}
|
||||||
|
|
||||||
|
notification() {
|
||||||
|
this.axios.interceptors.response.use(
|
||||||
|
(response) => response,
|
||||||
|
(error) => {
|
||||||
|
const redirectTo = error?.response?.data?.redirectTo;
|
||||||
|
if (redirectTo) {
|
||||||
|
return (window.location.href = redirectTo);
|
||||||
|
}
|
||||||
|
notification.error({
|
||||||
|
message: error?.response?.data?.errors?.map?.((error: any) => {
|
||||||
|
return React.createElement('div', { children: error.message });
|
||||||
|
}),
|
||||||
|
});
|
||||||
|
throw error;
|
||||||
|
},
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
131
packages/core/client/src/application/Application.tsx
Normal file
131
packages/core/client/src/application/Application.tsx
Normal file
@ -0,0 +1,131 @@
|
|||||||
|
import { i18n as i18next } from 'i18next';
|
||||||
|
import React from 'react';
|
||||||
|
import { I18nextProvider } from 'react-i18next';
|
||||||
|
import { Link, NavLink } from 'react-router-dom';
|
||||||
|
import { ACLProvider, ACLShortcut } from '../acl';
|
||||||
|
import { AntdConfigProvider } from '../antd-config-provider';
|
||||||
|
import { APIClient, APIClientProvider } from '../api-client';
|
||||||
|
import { BlockSchemaComponentProvider } from '../block-provider';
|
||||||
|
import { CollectionManagerShortcut } from '../collection-manager';
|
||||||
|
import { RemoteDocumentTitleProvider } from '../document-title';
|
||||||
|
import { FileStorageShortcut } from '../file-manager';
|
||||||
|
import { i18n } from '../i18n';
|
||||||
|
import { PluginManagerProvider } from '../plugin-manager';
|
||||||
|
import {
|
||||||
|
AdminLayout,
|
||||||
|
AuthLayout,
|
||||||
|
RemoteRouteSwitchProvider,
|
||||||
|
RouteSchemaComponent,
|
||||||
|
RouteSwitch,
|
||||||
|
useRoutes
|
||||||
|
} from '../route-switch';
|
||||||
|
import {
|
||||||
|
AntdSchemaComponentProvider,
|
||||||
|
DesignableSwitch,
|
||||||
|
MenuItemInitializers,
|
||||||
|
SchemaComponentProvider
|
||||||
|
} from '../schema-component';
|
||||||
|
import { SchemaInitializerProvider } from '../schema-initializer';
|
||||||
|
import { BlockTemplateDetails, BlockTemplatePage, SchemaTemplateShortcut } from '../schema-templates';
|
||||||
|
import { SystemSettingsProvider, SystemSettingsShortcut } from '../system-settings';
|
||||||
|
import { SigninPage, SignupPage } from '../user';
|
||||||
|
import { WorkflowPage, WorkflowRouteProvider, WorkflowShortcut } from '../workflow';
|
||||||
|
import { compose } from './compose';
|
||||||
|
|
||||||
|
export interface ApplicationOptions {
|
||||||
|
apiClient?: any;
|
||||||
|
i18n?: any;
|
||||||
|
plugins?: any[];
|
||||||
|
}
|
||||||
|
|
||||||
|
export type PluginCallback = () => Promise<any>;
|
||||||
|
|
||||||
|
export class Application {
|
||||||
|
providers = [];
|
||||||
|
mainComponent = null;
|
||||||
|
apiClient: APIClient;
|
||||||
|
i18n: i18next;
|
||||||
|
plugins: PluginCallback[] = [];
|
||||||
|
|
||||||
|
constructor(options: ApplicationOptions) {
|
||||||
|
this.apiClient = new APIClient({
|
||||||
|
baseURL: process.env.API_BASE_URL,
|
||||||
|
headers: {
|
||||||
|
'X-Hostname': window?.location?.hostname,
|
||||||
|
},
|
||||||
|
...options.apiClient,
|
||||||
|
});
|
||||||
|
this.i18n = options.i18n || i18n;
|
||||||
|
this.use(APIClientProvider, { apiClient: this.apiClient });
|
||||||
|
this.use(I18nextProvider, { i18n: this.i18n });
|
||||||
|
this.use(AntdConfigProvider, { remoteLocale: true });
|
||||||
|
this.use(RemoteRouteSwitchProvider, {
|
||||||
|
components: {
|
||||||
|
AuthLayout,
|
||||||
|
AdminLayout,
|
||||||
|
RouteSchemaComponent,
|
||||||
|
SigninPage,
|
||||||
|
SignupPage,
|
||||||
|
WorkflowPage,
|
||||||
|
BlockTemplatePage,
|
||||||
|
BlockTemplateDetails,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
this.use(SystemSettingsProvider);
|
||||||
|
this.use(PluginManagerProvider, {
|
||||||
|
components: {
|
||||||
|
ACLShortcut,
|
||||||
|
DesignableSwitch,
|
||||||
|
CollectionManagerShortcut,
|
||||||
|
WorkflowShortcut,
|
||||||
|
SystemSettingsShortcut,
|
||||||
|
SchemaTemplateShortcut,
|
||||||
|
FileStorageShortcut,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
this.use(SchemaComponentProvider, { components: { Link, NavLink } });
|
||||||
|
this.use(SchemaInitializerProvider, {
|
||||||
|
initializers: {
|
||||||
|
MenuItemInitializers,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
this.use(BlockSchemaComponentProvider);
|
||||||
|
this.use(AntdSchemaComponentProvider);
|
||||||
|
this.use(ACLProvider);
|
||||||
|
this.use(RemoteDocumentTitleProvider);
|
||||||
|
this.use(WorkflowRouteProvider);
|
||||||
|
for (const plugin of options.plugins) {
|
||||||
|
const [component, props] = Array.isArray(plugin) ? plugin : [plugin];
|
||||||
|
this.use(component, props);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
use(component, props?: any) {
|
||||||
|
this.providers.push(props ? [component, props] : component);
|
||||||
|
}
|
||||||
|
|
||||||
|
main(mainComponent: any) {
|
||||||
|
this.mainComponent = mainComponent;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* TODO
|
||||||
|
*/
|
||||||
|
plugin(plugin: PluginCallback) {
|
||||||
|
this.plugins.push(plugin);
|
||||||
|
}
|
||||||
|
|
||||||
|
render() {
|
||||||
|
return compose(...this.providers)(
|
||||||
|
this.mainComponent ||
|
||||||
|
(() => {
|
||||||
|
const routes = useRoutes();
|
||||||
|
return (
|
||||||
|
<div>
|
||||||
|
<RouteSwitch routes={routes} />
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
@ -1,6 +1,6 @@
|
|||||||
import React from 'react';
|
|
||||||
import { render } from '@testing-library/react';
|
import { render } from '@testing-library/react';
|
||||||
import { compose } from '../';
|
import React from 'react';
|
||||||
|
import { compose } from '../compose';
|
||||||
|
|
||||||
describe('compose', () => {
|
describe('compose', () => {
|
||||||
it('case 1', () => {
|
it('case 1', () => {
|
||||||
|
@ -1 +1,3 @@
|
|||||||
|
export * from './Application';
|
||||||
export * from './compose';
|
export * from './compose';
|
||||||
|
|
||||||
|
@ -1,3 +1,4 @@
|
|||||||
|
import 'antd/dist/antd.css';
|
||||||
import './global.less';
|
import './global.less';
|
||||||
|
|
||||||
export * from './acl';
|
export * from './acl';
|
||||||
@ -22,7 +23,7 @@ export * from './schema-initializer';
|
|||||||
export * from './schema-settings';
|
export * from './schema-settings';
|
||||||
export * from './schema-templates';
|
export * from './schema-templates';
|
||||||
export * from './settings-form';
|
export * from './settings-form';
|
||||||
export * from './slate';
|
|
||||||
export * from './system-settings';
|
export * from './system-settings';
|
||||||
export * from './user';
|
export * from './user';
|
||||||
export * from './workflow';
|
export * from './workflow';
|
||||||
|
|
||||||
|
@ -1,6 +1,5 @@
|
|||||||
import { ISchema, useField, useFieldSchema } from '@formily/react';
|
import { ISchema, useField, useFieldSchema } from '@formily/react';
|
||||||
import { isValid } from '@formily/shared';
|
import { isValid, uid } from '@formily/shared';
|
||||||
import { uid } from '@nocobase/utils';
|
|
||||||
import { Menu } from 'antd';
|
import { Menu } from 'antd';
|
||||||
import React, { useEffect, useState } from 'react';
|
import React, { useEffect, useState } from 'react';
|
||||||
import { useTranslation } from 'react-i18next';
|
import { useTranslation } from 'react-i18next';
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
import { FormLayout } from '@formily/antd';
|
import { FormLayout } from '@formily/antd';
|
||||||
import { createForm, Field, onFormInputChange } from '@formily/core';
|
import { createForm, Field, onFormInputChange } from '@formily/core';
|
||||||
import { FieldContext, FormContext, observer, RecursionField, useField, useFieldSchema } from '@formily/react';
|
import { FieldContext, FormContext, observer, RecursionField, useField, useFieldSchema } from '@formily/react';
|
||||||
import { uid } from '@nocobase/utils';
|
import { uid } from '@formily/shared';
|
||||||
import { Spin } from 'antd';
|
import { Spin } from 'antd';
|
||||||
import React, { useEffect, useMemo } from 'react';
|
import React, { useEffect, useMemo } from 'react';
|
||||||
import { useActionContext } from '..';
|
import { useActionContext } from '..';
|
||||||
|
@ -373,11 +373,28 @@ export const CreateActionInitializer = (props) => {
|
|||||||
className: 'nb-action-popup',
|
className: 'nb-action-popup',
|
||||||
},
|
},
|
||||||
properties: {
|
properties: {
|
||||||
grid: {
|
tabs: {
|
||||||
type: 'void',
|
type: 'void',
|
||||||
'x-component': 'Grid',
|
'x-component': 'Tabs',
|
||||||
'x-initializer': 'CreateFormBlockInitializers',
|
'x-component-props': {},
|
||||||
properties: {},
|
'x-initializer': 'TabPaneInitializers',
|
||||||
|
properties: {
|
||||||
|
tab1: {
|
||||||
|
type: 'void',
|
||||||
|
title: '{{t("Add new")}}',
|
||||||
|
'x-component': 'Tabs.TabPane',
|
||||||
|
'x-designer': 'Tabs.Designer',
|
||||||
|
'x-component-props': {},
|
||||||
|
properties: {
|
||||||
|
grid: {
|
||||||
|
type: 'void',
|
||||||
|
'x-component': 'Grid',
|
||||||
|
'x-initializer': 'CreateFormBlockInitializers',
|
||||||
|
properties: {},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
@ -1,258 +0,0 @@
|
|||||||
import { css, cx } from '@emotion/css';
|
|
||||||
import isHotkey from 'is-hotkey';
|
|
||||||
import React, { useCallback, useMemo } from 'react';
|
|
||||||
import { createEditor, Editor, Element as SlateElement, Node, Transforms } from 'slate';
|
|
||||||
import { withHistory } from 'slate-history';
|
|
||||||
import type { ReactEditor } from 'slate-react';
|
|
||||||
import { Editable, Slate, useSlate, withReact } from 'slate-react';
|
|
||||||
import { EllipsisWithTooltip } from '../schema-component/antd/input/EllipsisWithTooltip';
|
|
||||||
import { Button, Icon, Toolbar } from './components';
|
|
||||||
|
|
||||||
const HOTKEYS = {
|
|
||||||
'mod+b': 'bold',
|
|
||||||
'mod+i': 'italic',
|
|
||||||
'mod+u': 'underline',
|
|
||||||
'mod+`': 'code',
|
|
||||||
};
|
|
||||||
|
|
||||||
const LIST_TYPES = ['numbered-list', 'bulleted-list'];
|
|
||||||
const TEXT_ALIGN_TYPES = ['left', 'center', 'right', 'justify'];
|
|
||||||
const DEFAULT_VALUE = [
|
|
||||||
{
|
|
||||||
type: 'paragraph',
|
|
||||||
children: [{ text: '' }],
|
|
||||||
},
|
|
||||||
];
|
|
||||||
|
|
||||||
export const RichText = (props: any) => {
|
|
||||||
const { value, placeholder = '', className, readOnly, autop = true, ellipsis, onChange } = props;
|
|
||||||
const renderElement = useCallback((props) => <Element {...props} />, []);
|
|
||||||
const renderLeaf = useCallback((props) => <Leaf {...props} />, []);
|
|
||||||
const editor = useMemo(() => withHistory(withReact(createEditor() as ReactEditor)), []);
|
|
||||||
const slateValue = useMemo(() => {
|
|
||||||
editor.children = JSON.parse(JSON.stringify(value || DEFAULT_VALUE));
|
|
||||||
Editor.normalize(editor, { force: true });
|
|
||||||
return editor.children;
|
|
||||||
}, [editor, value]);
|
|
||||||
if (readOnly) {
|
|
||||||
const slateContent = (
|
|
||||||
<Slate editor={editor} value={slateValue}>
|
|
||||||
<Editable renderElement={renderElement} renderLeaf={renderLeaf} spellCheck autoFocus readOnly={readOnly} />
|
|
||||||
</Slate>
|
|
||||||
);
|
|
||||||
const slatePlainText = serialize(slateValue);
|
|
||||||
const content = (
|
|
||||||
<EllipsisWithTooltip ellipsis={ellipsis} popoverContent={autop ? slateContent : slatePlainText}>
|
|
||||||
{ellipsis ? slatePlainText : slateContent}
|
|
||||||
</EllipsisWithTooltip>
|
|
||||||
);
|
|
||||||
return content;
|
|
||||||
}
|
|
||||||
return (
|
|
||||||
<div
|
|
||||||
className={cx(
|
|
||||||
className,
|
|
||||||
'slate',
|
|
||||||
css`
|
|
||||||
border: solid 1px #d2d2d2;
|
|
||||||
border-radius: 2px;
|
|
||||||
`,
|
|
||||||
)}
|
|
||||||
>
|
|
||||||
<Slate editor={editor} value={slateValue} onChange={onChange}>
|
|
||||||
<Toolbar>
|
|
||||||
<MarkButton format="bold" icon="format_bold" />
|
|
||||||
<MarkButton format="italic" icon="format_italic" />
|
|
||||||
<MarkButton format="underline" icon="format_underlined" />
|
|
||||||
<MarkButton format="code" icon="code" />
|
|
||||||
<BlockButton format="block-quote" icon="format_quote" />
|
|
||||||
<BlockButton format="numbered-list" icon="format_list_numbered" />
|
|
||||||
<BlockButton format="bulleted-list" icon="format_list_bulleted" />
|
|
||||||
</Toolbar>
|
|
||||||
<div
|
|
||||||
className={css`
|
|
||||||
padding: 5px 11px;
|
|
||||||
`}
|
|
||||||
>
|
|
||||||
<Editable
|
|
||||||
renderElement={renderElement}
|
|
||||||
renderLeaf={renderLeaf}
|
|
||||||
placeholder={placeholder}
|
|
||||||
spellCheck
|
|
||||||
style={{ minHeight: '10em' }}
|
|
||||||
readOnly={readOnly}
|
|
||||||
onKeyDown={(event) => {
|
|
||||||
for (const hotkey in HOTKEYS) {
|
|
||||||
if (isHotkey(hotkey, event as any)) {
|
|
||||||
event.preventDefault();
|
|
||||||
const mark = HOTKEYS[hotkey];
|
|
||||||
toggleMark(editor, mark);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
</Slate>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
const serialize = (nodes) => {
|
|
||||||
return nodes.map((n) => Node.string(n)).join('\n');
|
|
||||||
};
|
|
||||||
const toggleBlock = (editor, format) => {
|
|
||||||
const isActive = isBlockActive(editor, format, TEXT_ALIGN_TYPES.includes(format) ? 'align' : 'type');
|
|
||||||
const isList = LIST_TYPES.includes(format);
|
|
||||||
|
|
||||||
Transforms.unwrapNodes(editor, {
|
|
||||||
match: (n: Node) =>
|
|
||||||
!Editor.isEditor(n) &&
|
|
||||||
SlateElement.isElement(n) &&
|
|
||||||
LIST_TYPES.includes((n as any).type) &&
|
|
||||||
!TEXT_ALIGN_TYPES.includes(format),
|
|
||||||
split: true,
|
|
||||||
});
|
|
||||||
let newProperties: Partial<SlateElement & { align: any; type: string }>;
|
|
||||||
if (TEXT_ALIGN_TYPES.includes(format)) {
|
|
||||||
newProperties = {
|
|
||||||
align: isActive ? undefined : format,
|
|
||||||
};
|
|
||||||
} else {
|
|
||||||
newProperties = {
|
|
||||||
type: isActive ? 'paragraph' : isList ? 'list-item' : format,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
Transforms.setNodes<SlateElement>(editor, newProperties);
|
|
||||||
|
|
||||||
if (!isActive && isList) {
|
|
||||||
const block = { type: format, children: [] };
|
|
||||||
Transforms.wrapNodes(editor, block);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
const toggleMark = (editor, format) => {
|
|
||||||
const isActive = isMarkActive(editor, format);
|
|
||||||
|
|
||||||
if (isActive) {
|
|
||||||
Editor.removeMark(editor, format);
|
|
||||||
} else {
|
|
||||||
Editor.addMark(editor, format, true);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
const isBlockActive = (editor, format, blockType = 'type') => {
|
|
||||||
const { selection } = editor;
|
|
||||||
if (!selection) return false;
|
|
||||||
|
|
||||||
const [match] = Array.from(
|
|
||||||
Editor.nodes(editor, {
|
|
||||||
at: Editor.unhangRange(editor, selection),
|
|
||||||
match: (n) => !Editor.isEditor(n) && SlateElement.isElement(n) && n[blockType] === format,
|
|
||||||
}),
|
|
||||||
);
|
|
||||||
|
|
||||||
return !!match;
|
|
||||||
};
|
|
||||||
|
|
||||||
const isMarkActive = (editor, format) => {
|
|
||||||
const marks = Editor.marks(editor);
|
|
||||||
return marks ? marks[format] === true : false;
|
|
||||||
};
|
|
||||||
|
|
||||||
const Element = ({ attributes, children, element }) => {
|
|
||||||
const style = { textAlign: element.align };
|
|
||||||
switch (element.type) {
|
|
||||||
case 'block-quote':
|
|
||||||
return (
|
|
||||||
<blockquote style={style} {...attributes}>
|
|
||||||
{children}
|
|
||||||
</blockquote>
|
|
||||||
);
|
|
||||||
case 'bulleted-list':
|
|
||||||
return (
|
|
||||||
<ul style={style} {...attributes}>
|
|
||||||
{children}
|
|
||||||
</ul>
|
|
||||||
);
|
|
||||||
case 'heading-one':
|
|
||||||
return (
|
|
||||||
<h1 style={style} {...attributes}>
|
|
||||||
{children}
|
|
||||||
</h1>
|
|
||||||
);
|
|
||||||
case 'heading-two':
|
|
||||||
return (
|
|
||||||
<h2 style={style} {...attributes}>
|
|
||||||
{children}
|
|
||||||
</h2>
|
|
||||||
);
|
|
||||||
case 'list-item':
|
|
||||||
return (
|
|
||||||
<li style={style} {...attributes}>
|
|
||||||
{children}
|
|
||||||
</li>
|
|
||||||
);
|
|
||||||
case 'numbered-list':
|
|
||||||
return (
|
|
||||||
<ol style={style} {...attributes}>
|
|
||||||
{children}
|
|
||||||
</ol>
|
|
||||||
);
|
|
||||||
default:
|
|
||||||
return (
|
|
||||||
<p style={style} {...attributes}>
|
|
||||||
{children}
|
|
||||||
</p>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
const Leaf = ({ attributes, children, leaf }) => {
|
|
||||||
if (leaf.bold) {
|
|
||||||
children = <strong>{children}</strong>;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (leaf.code) {
|
|
||||||
children = <code>{children}</code>;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (leaf.italic) {
|
|
||||||
children = <em>{children}</em>;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (leaf.underline) {
|
|
||||||
children = <u>{children}</u>;
|
|
||||||
}
|
|
||||||
|
|
||||||
return <span {...attributes}>{children}</span>;
|
|
||||||
};
|
|
||||||
|
|
||||||
const BlockButton = ({ format, icon }) => {
|
|
||||||
const editor = useSlate();
|
|
||||||
return (
|
|
||||||
<Button
|
|
||||||
active={isBlockActive(editor, format, TEXT_ALIGN_TYPES.includes(format) ? 'align' : 'type')}
|
|
||||||
onMouseDown={(event) => {
|
|
||||||
event.preventDefault();
|
|
||||||
toggleBlock(editor, format);
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<Icon>{icon}</Icon>
|
|
||||||
</Button>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
const MarkButton = ({ format, icon }) => {
|
|
||||||
const editor = useSlate();
|
|
||||||
return (
|
|
||||||
<Button
|
|
||||||
active={isMarkActive(editor, format)}
|
|
||||||
onMouseDown={(event) => {
|
|
||||||
event.preventDefault();
|
|
||||||
toggleMark(editor, format);
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<Icon>{icon}</Icon>
|
|
||||||
</Button>
|
|
||||||
);
|
|
||||||
};
|
|
@ -1,32 +0,0 @@
|
|||||||
import { Field } from '@formily/core';
|
|
||||||
import { connect, mapProps, mapReadPretty } from '@formily/react';
|
|
||||||
import React from 'react';
|
|
||||||
import { Node } from 'slate';
|
|
||||||
import './index.less';
|
|
||||||
import { RichText } from './RichText';
|
|
||||||
|
|
||||||
export const Slate = () => null;
|
|
||||||
|
|
||||||
const serialize = (nodes) => {
|
|
||||||
return nodes?.map?.((n) => Node.string(n)).join('');
|
|
||||||
};
|
|
||||||
const DEFAULT_VALUE = [
|
|
||||||
{
|
|
||||||
type: 'paragraph',
|
|
||||||
children: [{ text: '' }],
|
|
||||||
},
|
|
||||||
];
|
|
||||||
|
|
||||||
Slate.RichText = connect(
|
|
||||||
RichText,
|
|
||||||
mapProps((props, field: Field) => {
|
|
||||||
// const fieldValue = serialize(field.value)?.trim();
|
|
||||||
// if (!fieldValue) {
|
|
||||||
// field.value = undefined;
|
|
||||||
// }
|
|
||||||
return {
|
|
||||||
...props,
|
|
||||||
};
|
|
||||||
}),
|
|
||||||
mapReadPretty((props: any) => <RichText {...props} readOnly />),
|
|
||||||
);
|
|
@ -1,172 +0,0 @@
|
|||||||
import { css, cx } from '@emotion/css';
|
|
||||||
import React, { PropsWithChildren, Ref } from 'react';
|
|
||||||
import ReactDOM from 'react-dom';
|
|
||||||
|
|
||||||
interface BaseProps {
|
|
||||||
className: string;
|
|
||||||
[key: string]: unknown;
|
|
||||||
}
|
|
||||||
type OrNull<T> = T | null;
|
|
||||||
|
|
||||||
export const Button = React.forwardRef(
|
|
||||||
(
|
|
||||||
{
|
|
||||||
className,
|
|
||||||
active,
|
|
||||||
reversed,
|
|
||||||
...props
|
|
||||||
}: PropsWithChildren<
|
|
||||||
{
|
|
||||||
active: boolean;
|
|
||||||
reversed: boolean;
|
|
||||||
} & BaseProps
|
|
||||||
>,
|
|
||||||
ref: Ref<OrNull<HTMLSpanElement>>,
|
|
||||||
) => (
|
|
||||||
<span
|
|
||||||
{...props}
|
|
||||||
ref={ref}
|
|
||||||
className={cx(
|
|
||||||
className,
|
|
||||||
css`
|
|
||||||
cursor: pointer;
|
|
||||||
color: ${reversed ? (active ? 'white' : '#aaa') : active ? 'black' : '#ccc'};
|
|
||||||
`,
|
|
||||||
)}
|
|
||||||
/>
|
|
||||||
),
|
|
||||||
);
|
|
||||||
|
|
||||||
export const EditorValue = React.forwardRef(
|
|
||||||
(
|
|
||||||
{
|
|
||||||
className,
|
|
||||||
value,
|
|
||||||
...props
|
|
||||||
}: PropsWithChildren<
|
|
||||||
{
|
|
||||||
value: any;
|
|
||||||
} & BaseProps
|
|
||||||
>,
|
|
||||||
ref: Ref<OrNull<null>>,
|
|
||||||
) => {
|
|
||||||
const textLines = value.document.nodes
|
|
||||||
.map((node) => node.text)
|
|
||||||
.toArray()
|
|
||||||
.join('\n');
|
|
||||||
return (
|
|
||||||
<div
|
|
||||||
ref={ref}
|
|
||||||
{...props}
|
|
||||||
className={cx(
|
|
||||||
className,
|
|
||||||
css`
|
|
||||||
margin: 30px -20px 0;
|
|
||||||
`,
|
|
||||||
)}
|
|
||||||
>
|
|
||||||
<div
|
|
||||||
className={css`
|
|
||||||
font-size: 14px;
|
|
||||||
padding: 5px 20px;
|
|
||||||
color: #404040;
|
|
||||||
border-top: 2px solid #eeeeee;
|
|
||||||
background: #f8f8f8;
|
|
||||||
`}
|
|
||||||
>
|
|
||||||
Slate's value as text
|
|
||||||
</div>
|
|
||||||
<div
|
|
||||||
className={css`
|
|
||||||
color: #404040;
|
|
||||||
font: 12px monospace;
|
|
||||||
white-space: pre-wrap;
|
|
||||||
padding: 10px 20px;
|
|
||||||
div {
|
|
||||||
margin: 0 0 0.5em;
|
|
||||||
}
|
|
||||||
`}
|
|
||||||
>
|
|
||||||
{textLines}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
},
|
|
||||||
);
|
|
||||||
|
|
||||||
export const Icon = React.forwardRef(
|
|
||||||
({ className, ...props }: PropsWithChildren<BaseProps>, ref: Ref<OrNull<HTMLSpanElement>>) => (
|
|
||||||
<span
|
|
||||||
{...props}
|
|
||||||
ref={ref}
|
|
||||||
className={cx(
|
|
||||||
'material-icons',
|
|
||||||
className,
|
|
||||||
css`
|
|
||||||
font-size: 18px;
|
|
||||||
vertical-align: text-bottom;
|
|
||||||
`,
|
|
||||||
)}
|
|
||||||
/>
|
|
||||||
),
|
|
||||||
);
|
|
||||||
|
|
||||||
export const Instruction = React.forwardRef(
|
|
||||||
({ className, ...props }: PropsWithChildren<BaseProps>, ref: Ref<OrNull<HTMLDivElement>>) => (
|
|
||||||
<div
|
|
||||||
{...props}
|
|
||||||
ref={ref}
|
|
||||||
className={cx(
|
|
||||||
className,
|
|
||||||
css`
|
|
||||||
white-space: pre-wrap;
|
|
||||||
margin: 0 -20px 10px;
|
|
||||||
padding: 10px 20px;
|
|
||||||
font-size: 14px;
|
|
||||||
background: #f8f8e8;
|
|
||||||
`,
|
|
||||||
)}
|
|
||||||
/>
|
|
||||||
),
|
|
||||||
);
|
|
||||||
|
|
||||||
export const Menu = React.forwardRef(
|
|
||||||
({ className, ...props }: PropsWithChildren<BaseProps>, ref: Ref<OrNull<HTMLDivElement>>) => (
|
|
||||||
<div
|
|
||||||
{...props}
|
|
||||||
ref={ref}
|
|
||||||
className={cx(
|
|
||||||
className,
|
|
||||||
css`
|
|
||||||
& > * {
|
|
||||||
display: inline-block;
|
|
||||||
}
|
|
||||||
& > * + * {
|
|
||||||
margin-left: 15px;
|
|
||||||
}
|
|
||||||
`,
|
|
||||||
)}
|
|
||||||
/>
|
|
||||||
),
|
|
||||||
);
|
|
||||||
|
|
||||||
export const Portal = ({ children }) => {
|
|
||||||
return typeof document === 'object' ? ReactDOM.createPortal(children, document.body) : null;
|
|
||||||
};
|
|
||||||
|
|
||||||
export const Toolbar = React.forwardRef(
|
|
||||||
({ className, ...props }: PropsWithChildren<BaseProps>, ref: Ref<OrNull<HTMLDivElement>>) => (
|
|
||||||
<Menu
|
|
||||||
{...props}
|
|
||||||
ref={ref}
|
|
||||||
className={cx(
|
|
||||||
className,
|
|
||||||
css`
|
|
||||||
position: relative;
|
|
||||||
padding: 5px 11px;
|
|
||||||
background-color: #f3f3f3;
|
|
||||||
`,
|
|
||||||
)}
|
|
||||||
/>
|
|
||||||
),
|
|
||||||
);
|
|
@ -1,27 +0,0 @@
|
|||||||
import { FormItem } from '@formily/antd';
|
|
||||||
import { SchemaComponent, SchemaComponentProvider, Slate } from '@nocobase/client';
|
|
||||||
import React from 'react';
|
|
||||||
|
|
||||||
const schema = {
|
|
||||||
type: 'object',
|
|
||||||
properties: {
|
|
||||||
slate: {
|
|
||||||
type: 'string',
|
|
||||||
'x-decorator': 'FormItem',
|
|
||||||
'x-component': 'Slate.RichText',
|
|
||||||
'x-component-props': {
|
|
||||||
onChange: (value) => {
|
|
||||||
console.log(value);
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
export default () => {
|
|
||||||
return (
|
|
||||||
<SchemaComponentProvider components={{ Slate, FormItem }}>
|
|
||||||
<SchemaComponent schema={schema} />
|
|
||||||
</SchemaComponentProvider>
|
|
||||||
);
|
|
||||||
};
|
|
@ -1,79 +0,0 @@
|
|||||||
import { FormItem } from '@formily/antd';
|
|
||||||
import { SchemaComponent, SchemaComponentProvider, Slate } from '@nocobase/client';
|
|
||||||
import React from 'react';
|
|
||||||
|
|
||||||
let value = [
|
|
||||||
{
|
|
||||||
type: 'heading-one',
|
|
||||||
children: [
|
|
||||||
{
|
|
||||||
text: 'Slate Rich Text Editor',
|
|
||||||
},
|
|
||||||
],
|
|
||||||
},
|
|
||||||
{
|
|
||||||
type: 'block-quote',
|
|
||||||
children: [
|
|
||||||
{
|
|
||||||
text: 'this is based in Slate',
|
|
||||||
},
|
|
||||||
],
|
|
||||||
},
|
|
||||||
{
|
|
||||||
type: 'bulleted-list',
|
|
||||||
children: [
|
|
||||||
{
|
|
||||||
type: 'list-item',
|
|
||||||
children: [
|
|
||||||
{
|
|
||||||
text: 'The editor\'s "schema" was hardcoded and hard to customize. ',
|
|
||||||
},
|
|
||||||
],
|
|
||||||
},
|
|
||||||
{
|
|
||||||
type: 'list-item',
|
|
||||||
children: [
|
|
||||||
{
|
|
||||||
text: 'Transforming the documents programmatically was very convoluted. ',
|
|
||||||
},
|
|
||||||
],
|
|
||||||
},
|
|
||||||
{
|
|
||||||
type: 'list-item',
|
|
||||||
children: [
|
|
||||||
{
|
|
||||||
text: 'Serializing to HTML, Markdown, etc. seemed like an afterthought. ',
|
|
||||||
},
|
|
||||||
],
|
|
||||||
},
|
|
||||||
{
|
|
||||||
type: 'list-item',
|
|
||||||
children: [
|
|
||||||
{
|
|
||||||
text: 'Re-inventing the view layer seemed inefficient and limiting.',
|
|
||||||
},
|
|
||||||
],
|
|
||||||
},
|
|
||||||
],
|
|
||||||
},
|
|
||||||
];
|
|
||||||
const schema = {
|
|
||||||
type: 'object',
|
|
||||||
properties: {
|
|
||||||
read: {
|
|
||||||
type: 'string',
|
|
||||||
'x-read-pretty': true,
|
|
||||||
'x-decorator': 'FormItem',
|
|
||||||
'x-component': 'Slate.RichText',
|
|
||||||
default: value,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
export default () => {
|
|
||||||
return (
|
|
||||||
<SchemaComponentProvider components={{ Slate, FormItem }}>
|
|
||||||
<SchemaComponent schema={schema} />
|
|
||||||
</SchemaComponentProvider>
|
|
||||||
);
|
|
||||||
};
|
|
@ -1,44 +0,0 @@
|
|||||||
/**
|
|
||||||
* title: Input
|
|
||||||
*/
|
|
||||||
import { FormItem } from '@formily/antd';
|
|
||||||
import { SchemaComponent, SchemaComponentProvider, Slate } from '@nocobase/client';
|
|
||||||
import React from 'react';
|
|
||||||
|
|
||||||
const schema = {
|
|
||||||
type: 'object',
|
|
||||||
properties: {
|
|
||||||
input: {
|
|
||||||
title: `Editable1`,
|
|
||||||
'x-decorator': 'FormItem',
|
|
||||||
'x-component': 'Slate.RichText',
|
|
||||||
'x-reactions': {
|
|
||||||
target: '*(input2,read)',
|
|
||||||
fulfill: {
|
|
||||||
state: {
|
|
||||||
value: '{{$self.value}}',
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
input2: {
|
|
||||||
title: `Editable2`,
|
|
||||||
'x-decorator': 'FormItem',
|
|
||||||
'x-component': 'Slate.RichText',
|
|
||||||
},
|
|
||||||
read: {
|
|
||||||
title: `Read pretty`,
|
|
||||||
'x-read-pretty': true,
|
|
||||||
'x-decorator': 'FormItem',
|
|
||||||
'x-component': 'Slate.RichText',
|
|
||||||
},
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
export default () => {
|
|
||||||
return (
|
|
||||||
<SchemaComponentProvider components={{ Slate, FormItem }}>
|
|
||||||
<SchemaComponent schema={schema} />
|
|
||||||
</SchemaComponentProvider>
|
|
||||||
);
|
|
||||||
};
|
|
@ -1,51 +0,0 @@
|
|||||||
@font-face {
|
|
||||||
font-family: 'Material Icons';
|
|
||||||
font-style: normal;
|
|
||||||
font-weight: 400;
|
|
||||||
src: url(./materialicons.woff2) format('woff2');
|
|
||||||
}
|
|
||||||
|
|
||||||
.material-icons {
|
|
||||||
font-family: 'Material Icons';
|
|
||||||
font-weight: normal;
|
|
||||||
font-style: normal;
|
|
||||||
font-size: 24px;
|
|
||||||
line-height: 1;
|
|
||||||
letter-spacing: normal;
|
|
||||||
text-transform: none;
|
|
||||||
display: inline-block;
|
|
||||||
white-space: nowrap;
|
|
||||||
word-wrap: normal;
|
|
||||||
direction: ltr;
|
|
||||||
-webkit-font-feature-settings: 'liga';
|
|
||||||
-webkit-font-smoothing: antialiased;
|
|
||||||
}
|
|
||||||
.ant-formily-item-error .slate {
|
|
||||||
border-color: #ff4d4f !important;
|
|
||||||
}
|
|
||||||
.slate:focus-within {
|
|
||||||
border-color: #40a9ff;
|
|
||||||
box-shadow: 0 0 0 2px rgba(24, 144, 255, 0.2);
|
|
||||||
border-right-width: 1px;
|
|
||||||
outline: 0;
|
|
||||||
}
|
|
||||||
:not(pre) > code {
|
|
||||||
font-family: monospace;
|
|
||||||
background-color: #eee;
|
|
||||||
padding: 3px;
|
|
||||||
}
|
|
||||||
blockquote {
|
|
||||||
border-left: 2px solid #ddd;
|
|
||||||
margin-left: 0;
|
|
||||||
margin-right: 0;
|
|
||||||
padding-left: 10px;
|
|
||||||
color: #aaa;
|
|
||||||
font-style: italic;
|
|
||||||
}
|
|
||||||
|
|
||||||
blockquote[dir='rtl'] {
|
|
||||||
border-left: none;
|
|
||||||
padding-left: 0;
|
|
||||||
padding-right: 10px;
|
|
||||||
border-right: 2px solid #ddd;
|
|
||||||
}
|
|
@ -1,22 +0,0 @@
|
|||||||
---
|
|
||||||
nav:
|
|
||||||
path: /client
|
|
||||||
group:
|
|
||||||
path: /client
|
|
||||||
---
|
|
||||||
|
|
||||||
# Slate
|
|
||||||
|
|
||||||
基于 [slate](https://github.com/ianstormtaylor/slate) 封装。
|
|
||||||
|
|
||||||
## Examples
|
|
||||||
|
|
||||||
### Slate Rich Text Editor
|
|
||||||
|
|
||||||
<code src="./demos/demo1.tsx" />
|
|
||||||
|
|
||||||
### Slate Rich Text Editor is Read Pretty
|
|
||||||
|
|
||||||
<code src="./demos/demo2.tsx" />
|
|
||||||
|
|
||||||
<code src="./demos/demo3.tsx" />
|
|
@ -1 +0,0 @@
|
|||||||
export * from './Slate';
|
|
Binary file not shown.
@ -1,11 +1,11 @@
|
|||||||
import { CloseOutlined, DeleteOutlined } from '@ant-design/icons';
|
import { CloseOutlined, DeleteOutlined } from '@ant-design/icons';
|
||||||
import { css, cx } from '@emotion/css';
|
import { css, cx } from '@emotion/css';
|
||||||
import { ISchema, useForm } from '@formily/react';
|
import { ISchema, useForm } from '@formily/react';
|
||||||
import { Registry } from '@nocobase/utils';
|
import { Registry } from '@nocobase/utils/client';
|
||||||
import { Button, message, Modal, Tag } from 'antd';
|
import { Button, message, Modal, Tag } from 'antd';
|
||||||
import React, { useContext } from 'react';
|
import React, { useContext } from 'react';
|
||||||
import { useTranslation } from 'react-i18next';
|
import { useTranslation } from 'react-i18next';
|
||||||
import { SchemaComponent, useActionContext, useAPIClient, useCollection, useCompile, useRecord, useRequest, useResourceActionContext } from '../..';
|
import { SchemaComponent, useActionContext, useAPIClient, useCompile, useRequest, useResourceActionContext } from '../..';
|
||||||
import { nodeBlockClass, nodeCardClass, nodeClass, nodeHeaderClass, nodeMetaClass, nodeTitleClass } from '../style';
|
import { nodeBlockClass, nodeCardClass, nodeClass, nodeHeaderClass, nodeMetaClass, nodeTitleClass } from '../style';
|
||||||
import { AddButton, useFlowContext } from '../WorkflowCanvas';
|
import { AddButton, useFlowContext } from '../WorkflowCanvas';
|
||||||
|
|
||||||
@ -17,8 +17,6 @@ import parallel from './parallel';
|
|||||||
import query from './query';
|
import query from './query';
|
||||||
import update from './update';
|
import update from './update';
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
export interface Instruction {
|
export interface Instruction {
|
||||||
title: string;
|
title: string;
|
||||||
type: string;
|
type: string;
|
||||||
|
@ -1,9 +1,9 @@
|
|||||||
import React from "react";
|
|
||||||
import { ISchema, useForm } from "@formily/react";
|
|
||||||
import { css, cx } from "@emotion/css";
|
import { css, cx } from "@emotion/css";
|
||||||
import { Registry } from "@nocobase/utils";
|
import { ISchema, useForm } from "@formily/react";
|
||||||
import { useTranslation } from "react-i18next";
|
import { Registry } from "@nocobase/utils/client";
|
||||||
import { message, Tag } from "antd";
|
import { message, Tag } from "antd";
|
||||||
|
import React from "react";
|
||||||
|
import { useTranslation } from "react-i18next";
|
||||||
|
|
||||||
import { SchemaComponent, useActionContext, useAPIClient, useCompile, useResourceActionContext } from '../../';
|
import { SchemaComponent, useActionContext, useAPIClient, useCompile, useResourceActionContext } from '../../';
|
||||||
|
|
||||||
|
@ -181,7 +181,7 @@ export class APIClient {
|
|||||||
if (!this.auth) {
|
if (!this.auth) {
|
||||||
this.auth = new Auth(this);
|
this.auth = new Auth(this);
|
||||||
}
|
}
|
||||||
this.paramsSerializer();
|
this.interceptors();
|
||||||
}
|
}
|
||||||
|
|
||||||
private initStorage(storage?: any) {
|
private initStorage(storage?: any) {
|
||||||
@ -194,7 +194,7 @@ export class APIClient {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
paramsSerializer() {
|
interceptors() {
|
||||||
this.axios.interceptors.request.use((config) => {
|
this.axios.interceptors.request.use((config) => {
|
||||||
config.paramsSerializer = (params) => {
|
config.paramsSerializer = (params) => {
|
||||||
return qs.stringify(params, {
|
return qs.stringify(params, {
|
||||||
|
2
packages/core/utils/client.d.ts
vendored
Normal file
2
packages/core/utils/client.d.ts
vendored
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
// @ts-nocheck
|
||||||
|
export * from './lib/client';
|
12
packages/core/utils/client.js
Normal file
12
packages/core/utils/client.js
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
var _useExportClient = require("./lib/client");
|
||||||
|
|
||||||
|
Object.keys(_useExportClient).forEach(function (key) {
|
||||||
|
if (key === "default" || key === "__esModule") return;
|
||||||
|
if (key in exports && exports[key] === _useExportClient[key]) return;
|
||||||
|
Object.defineProperty(exports, key, {
|
||||||
|
enumerable: true,
|
||||||
|
get: function get() {
|
||||||
|
return _useExportClient[key];
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
2
packages/core/utils/server.d.ts
vendored
Normal file
2
packages/core/utils/server.d.ts
vendored
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
// @ts-nocheck
|
||||||
|
export * from './lib/server';
|
12
packages/core/utils/server.js
Normal file
12
packages/core/utils/server.js
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
var _useExportServer = require("./lib/server");
|
||||||
|
|
||||||
|
Object.keys(_useExportServer).forEach(function (key) {
|
||||||
|
if (key === "default" || key === "__esModule") return;
|
||||||
|
if (key in exports && exports[key] === _useExportServer[key]) return;
|
||||||
|
Object.defineProperty(exports, key, {
|
||||||
|
enumerable: true,
|
||||||
|
get: function get() {
|
||||||
|
return _useExportServer[key];
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
4
packages/core/utils/src/client.ts
Normal file
4
packages/core/utils/src/client.ts
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
export * from './merge';
|
||||||
|
export * from './registry';
|
||||||
|
export * from './uid';
|
||||||
|
|
@ -4,3 +4,4 @@ export * from './mixin/AsyncEmitter';
|
|||||||
export * from './registry';
|
export * from './registry';
|
||||||
export * from './requireModule';
|
export * from './requireModule';
|
||||||
export * from './uid';
|
export * from './uid';
|
||||||
|
|
||||||
|
7
packages/core/utils/src/server.ts
Normal file
7
packages/core/utils/src/server.ts
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
export * from './merge';
|
||||||
|
export * from './mixin';
|
||||||
|
export * from './mixin/AsyncEmitter';
|
||||||
|
export * from './registry';
|
||||||
|
export * from './requireModule';
|
||||||
|
export * from './uid';
|
||||||
|
|
@ -1,3 +1,4 @@
|
|||||||
export * from './AuditLogsBlockInitializer';
|
export * from './AuditLogsBlockInitializer';
|
||||||
export * from './AuditLogsProvider';
|
export * from './AuditLogsProvider';
|
||||||
|
export { AuditLogsProvider as default } from './AuditLogsProvider';
|
||||||
|
|
||||||
|
2
packages/plugins/china-region/client.d.ts
vendored
Executable file
2
packages/plugins/china-region/client.d.ts
vendored
Executable file
@ -0,0 +1,2 @@
|
|||||||
|
// @ts-nocheck
|
||||||
|
export * from './lib/client';
|
12
packages/plugins/china-region/client.js
Executable file
12
packages/plugins/china-region/client.js
Executable file
@ -0,0 +1,12 @@
|
|||||||
|
var _useExportClient = require("./lib/client");
|
||||||
|
|
||||||
|
Object.keys(_useExportClient).forEach(function (key) {
|
||||||
|
if (key === "default" || key === "__esModule") return;
|
||||||
|
if (key in exports && exports[key] === _useExportClient[key]) return;
|
||||||
|
Object.defineProperty(exports, key, {
|
||||||
|
enumerable: true,
|
||||||
|
get: function get() {
|
||||||
|
return _useExportClient[key];
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
@ -10,6 +10,8 @@
|
|||||||
}
|
}
|
||||||
],
|
],
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
"@nocobase/client": "0.7.0-alpha.83",
|
||||||
|
"@nocobase/server": "0.7.0-alpha.83",
|
||||||
"china-division": "^2.4.0"
|
"china-division": "^2.4.0"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
|
2
packages/plugins/china-region/server.d.ts
vendored
Executable file
2
packages/plugins/china-region/server.d.ts
vendored
Executable file
@ -0,0 +1,2 @@
|
|||||||
|
// @ts-nocheck
|
||||||
|
export * from './lib/server';
|
12
packages/plugins/china-region/server.js
Executable file
12
packages/plugins/china-region/server.js
Executable file
@ -0,0 +1,12 @@
|
|||||||
|
var _useExportServer = require('./lib/server');
|
||||||
|
|
||||||
|
Object.keys(_useExportServer).forEach(function (key) {
|
||||||
|
if (key === 'default' || key === '__esModule') return;
|
||||||
|
if (key in exports && exports[key] === _useExportServer[key]) return;
|
||||||
|
Object.defineProperty(exports, key, {
|
||||||
|
enumerable: true,
|
||||||
|
get: function get() {
|
||||||
|
return _useExportServer[key];
|
||||||
|
},
|
||||||
|
});
|
||||||
|
});
|
79
packages/plugins/china-region/src/client/index.tsx
Normal file
79
packages/plugins/china-region/src/client/index.tsx
Normal file
@ -0,0 +1,79 @@
|
|||||||
|
import { ArrayField } from '@formily/core';
|
||||||
|
import { useField } from '@formily/react';
|
||||||
|
import { SchemaComponentOptions, useAPIClient, useRequest } from '@nocobase/client';
|
||||||
|
import React from 'react';
|
||||||
|
|
||||||
|
const useChinaRegionDataSource = (options) => {
|
||||||
|
const field = useField<ArrayField>();
|
||||||
|
const maxLevel = field.componentProps.maxLevel;
|
||||||
|
return useRequest(
|
||||||
|
{
|
||||||
|
resource: 'chinaRegions',
|
||||||
|
action: 'list',
|
||||||
|
params: {
|
||||||
|
sort: 'code',
|
||||||
|
paginate: false,
|
||||||
|
filter: {
|
||||||
|
level: 1,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
...options,
|
||||||
|
onSuccess(data) {
|
||||||
|
options?.onSuccess({
|
||||||
|
data:
|
||||||
|
data?.data?.map((item) => {
|
||||||
|
if (maxLevel !== 1) {
|
||||||
|
item.isLeaf = false;
|
||||||
|
}
|
||||||
|
return item;
|
||||||
|
}) || [],
|
||||||
|
});
|
||||||
|
},
|
||||||
|
},
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
const useChinaRegionLoadData = () => {
|
||||||
|
const api = useAPIClient();
|
||||||
|
const field = useField<ArrayField>();
|
||||||
|
const maxLevel = field.componentProps.maxLevel;
|
||||||
|
return (selectedOptions) => {
|
||||||
|
const targetOption = selectedOptions[selectedOptions.length - 1];
|
||||||
|
if (targetOption?.children?.length > 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
targetOption.loading = true;
|
||||||
|
api
|
||||||
|
.resource('chinaRegions')
|
||||||
|
.list({
|
||||||
|
sort: 'code',
|
||||||
|
paginate: false,
|
||||||
|
filter: {
|
||||||
|
parentCode: targetOption.code,
|
||||||
|
},
|
||||||
|
})
|
||||||
|
.then(({ data }) => {
|
||||||
|
targetOption.loading = false;
|
||||||
|
targetOption.children =
|
||||||
|
data?.data?.map((item) => {
|
||||||
|
if (maxLevel > item.level) {
|
||||||
|
item.isLeaf = false;
|
||||||
|
}
|
||||||
|
return item;
|
||||||
|
}) || [];
|
||||||
|
field.dataSource = [...field.dataSource];
|
||||||
|
});
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
export const ChinaRegionProvider = (props) => {
|
||||||
|
return (
|
||||||
|
<SchemaComponentOptions scope={{ useChinaRegionDataSource, useChinaRegionLoadData }}>
|
||||||
|
{props.children}
|
||||||
|
</SchemaComponentOptions>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default ChinaRegionProvider;
|
@ -2,7 +2,7 @@ import { Plugin } from '@nocobase/server';
|
|||||||
import { areas, cities, provinces } from 'china-division';
|
import { areas, cities, provinces } from 'china-division';
|
||||||
import { resolve } from 'path';
|
import { resolve } from 'path';
|
||||||
|
|
||||||
export class ChinaRegionPlugin extends Plugin {
|
export class PluginChinaRegion extends Plugin {
|
||||||
async install() {
|
async install() {
|
||||||
await this.importData();
|
await this.importData();
|
||||||
}
|
}
|
||||||
@ -69,4 +69,4 @@ export class ChinaRegionPlugin extends Plugin {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export default ChinaRegionPlugin;
|
export default PluginChinaRegion;
|
@ -2,5 +2,6 @@ export * from './ExportActionInitializer';
|
|||||||
export * from './ExportDesigner';
|
export * from './ExportDesigner';
|
||||||
export * from './ExportInitializerProvider';
|
export * from './ExportInitializerProvider';
|
||||||
export * from './ExportPluginProvider';
|
export * from './ExportPluginProvider';
|
||||||
|
export { ExportPluginProvider as default } from './ExportPluginProvider';
|
||||||
export * from './useExportAction';
|
export * from './useExportAction';
|
||||||
|
|
||||||
|
@ -23,6 +23,9 @@
|
|||||||
"@nocobase/plugin-*": [
|
"@nocobase/plugin-*": [
|
||||||
"packages/plugins/*/src"
|
"packages/plugins/*/src"
|
||||||
],
|
],
|
||||||
|
"@nocobase/utils/client": [
|
||||||
|
"packages/core/utils/src/client"
|
||||||
|
],
|
||||||
"@nocobase/*": [
|
"@nocobase/*": [
|
||||||
"packages/core/*/src"
|
"packages/core/*/src"
|
||||||
]
|
]
|
||||||
|
67
yarn.lock
67
yarn.lock
@ -5024,11 +5024,6 @@
|
|||||||
resolved "https://registry.npmjs.org/@types/http-errors/-/http-errors-1.8.1.tgz#e81ad28a60bee0328c6d2384e029aec626f1ae67"
|
resolved "https://registry.npmjs.org/@types/http-errors/-/http-errors-1.8.1.tgz#e81ad28a60bee0328c6d2384e029aec626f1ae67"
|
||||||
integrity sha512-e+2rjEwK6KDaNOm5Aa9wNGgyS9oSZU/4pfSMMPYNOfjvFI0WVXm29+ITRFr6aKDvvKo7uU1jV68MW4ScsfDi7Q==
|
integrity sha512-e+2rjEwK6KDaNOm5Aa9wNGgyS9oSZU/4pfSMMPYNOfjvFI0WVXm29+ITRFr6aKDvvKo7uU1jV68MW4ScsfDi7Q==
|
||||||
|
|
||||||
"@types/is-hotkey@^0.1.1":
|
|
||||||
version "0.1.7"
|
|
||||||
resolved "https://registry.npmmirror.com/@types/is-hotkey/-/is-hotkey-0.1.7.tgz#30ec6d4234895230b576728ef77e70a52962f3b3"
|
|
||||||
integrity sha512-yB5C7zcOM7idwYZZ1wKQ3pTfjA9BbvFqRWvKB46GFddxnJtHwi/b9y84ykQtxQPg5qhdpg4Q/kWU3EGoCTmLzQ==
|
|
||||||
|
|
||||||
"@types/istanbul-lib-coverage@*", "@types/istanbul-lib-coverage@^2.0.0", "@types/istanbul-lib-coverage@^2.0.1":
|
"@types/istanbul-lib-coverage@*", "@types/istanbul-lib-coverage@^2.0.0", "@types/istanbul-lib-coverage@^2.0.1":
|
||||||
version "2.0.3"
|
version "2.0.3"
|
||||||
resolved "https://registry.npmjs.org/@types/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.3.tgz#4ba8ddb720221f432e443bd5f9117fd22cfd4762"
|
resolved "https://registry.npmjs.org/@types/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.3.tgz#4ba8ddb720221f432e443bd5f9117fd22cfd4762"
|
||||||
@ -5129,11 +5124,6 @@
|
|||||||
"@types/koa-compose" "*"
|
"@types/koa-compose" "*"
|
||||||
"@types/node" "*"
|
"@types/node" "*"
|
||||||
|
|
||||||
"@types/lodash@^4.14.149":
|
|
||||||
version "4.14.181"
|
|
||||||
resolved "https://registry.npmmirror.com/@types/lodash/-/lodash-4.14.181.tgz#d1d3740c379fda17ab175165ba04e2d03389385d"
|
|
||||||
integrity sha512-n3tyKthHJbkiWhDZs3DkhkCzt2MexYHXlX0td5iMplyfwketaOeKboEVBqzceH7juqvEg3q5oUoBFxSLu7zFag==
|
|
||||||
|
|
||||||
"@types/lodash@^4.14.177":
|
"@types/lodash@^4.14.177":
|
||||||
version "4.14.177"
|
version "4.14.177"
|
||||||
resolved "https://registry.npmjs.org/@types/lodash/-/lodash-4.14.177.tgz#f70c0d19c30fab101cad46b52be60363c43c4578"
|
resolved "https://registry.npmjs.org/@types/lodash/-/lodash-4.14.177.tgz#f70c0d19c30fab101cad46b52be60363c43c4578"
|
||||||
@ -9275,11 +9265,6 @@ dir-glob@^3.0.1:
|
|||||||
dependencies:
|
dependencies:
|
||||||
path-type "^4.0.0"
|
path-type "^4.0.0"
|
||||||
|
|
||||||
direction@^1.0.3:
|
|
||||||
version "1.0.4"
|
|
||||||
resolved "https://registry.npmmirror.com/direction/-/direction-1.0.4.tgz#2b86fb686967e987088caf8b89059370d4837442"
|
|
||||||
integrity sha512-GYqKi1aH7PJXxdhTeZBFrg8vUBeKXi+cNprXsC1kpJcbcVnV9wBsrOu1cQEdG0WeQwlfHiy3XvnKfIrJ2R0NzQ==
|
|
||||||
|
|
||||||
discontinuous-range@1.0.0:
|
discontinuous-range@1.0.0:
|
||||||
version "1.0.0"
|
version "1.0.0"
|
||||||
resolved "https://registry.npmjs.org/discontinuous-range/-/discontinuous-range-1.0.0.tgz#e38331f0844bba49b9a9cb71c771585aab1bc65a"
|
resolved "https://registry.npmjs.org/discontinuous-range/-/discontinuous-range-1.0.0.tgz#e38331f0844bba49b9a9cb71c771585aab1bc65a"
|
||||||
@ -11910,11 +11895,6 @@ image-size@~0.5.0:
|
|||||||
resolved "https://registry.npmjs.org/image-size/-/image-size-0.5.5.tgz#09dfd4ab9d20e29eb1c3e80b8990378df9e3cb9c"
|
resolved "https://registry.npmjs.org/image-size/-/image-size-0.5.5.tgz#09dfd4ab9d20e29eb1c3e80b8990378df9e3cb9c"
|
||||||
integrity sha1-Cd/Uq50g4p6xw+gLiZA3jfnjy5w=
|
integrity sha1-Cd/Uq50g4p6xw+gLiZA3jfnjy5w=
|
||||||
|
|
||||||
immer@^9.0.6:
|
|
||||||
version "9.0.12"
|
|
||||||
resolved "https://registry.npmmirror.com/immer/-/immer-9.0.12.tgz#2d33ddf3ee1d247deab9d707ca472c8c942a0f20"
|
|
||||||
integrity sha512-lk7UNmSbAukB5B6dh9fnh5D0bJTOFKxVg2cyJWTYrWRfhLrLMBquONcUs3aFq507hNoIZEDDh8lb8UtOizSMhA==
|
|
||||||
|
|
||||||
import-cwd@^2.0.0, import-cwd@^2.1.0:
|
import-cwd@^2.0.0, import-cwd@^2.1.0:
|
||||||
version "2.1.0"
|
version "2.1.0"
|
||||||
resolved "https://registry.npmjs.org/import-cwd/-/import-cwd-2.1.0.tgz#aa6cf36e722761285cb371ec6519f53e2435b0a9"
|
resolved "https://registry.npmjs.org/import-cwd/-/import-cwd-2.1.0.tgz#aa6cf36e722761285cb371ec6519f53e2435b0a9"
|
||||||
@ -12422,11 +12402,6 @@ is-hexadecimal@^1.0.0:
|
|||||||
resolved "https://registry.npmjs.org/is-hexadecimal/-/is-hexadecimal-1.0.4.tgz#cc35c97588da4bd49a8eedd6bc4082d44dcb23a7"
|
resolved "https://registry.npmjs.org/is-hexadecimal/-/is-hexadecimal-1.0.4.tgz#cc35c97588da4bd49a8eedd6bc4082d44dcb23a7"
|
||||||
integrity sha512-gyPJuv83bHMpocVYoqof5VDiZveEoGoFL8m3BXNb2VW8Xs+rz9kqO8LOQ5DH6EsuvilT1ApazU0pyl+ytbPtlw==
|
integrity sha512-gyPJuv83bHMpocVYoqof5VDiZveEoGoFL8m3BXNb2VW8Xs+rz9kqO8LOQ5DH6EsuvilT1ApazU0pyl+ytbPtlw==
|
||||||
|
|
||||||
is-hotkey@^0.1.6:
|
|
||||||
version "0.1.8"
|
|
||||||
resolved "https://registry.npmmirror.com/is-hotkey/-/is-hotkey-0.1.8.tgz#6b1f4b2d0e5639934e20c05ed24d623a21d36d25"
|
|
||||||
integrity sha512-qs3NZ1INIS+H+yeo7cD9pDfwYV/jqRh1JG9S9zYrNudkoUQg7OL7ziXqRKu+InFjUIDoP2o6HIkLYMh1pcWgyQ==
|
|
||||||
|
|
||||||
is-installed-globally@^0.1.0:
|
is-installed-globally@^0.1.0:
|
||||||
version "0.1.0"
|
version "0.1.0"
|
||||||
resolved "https://registry.npmjs.org/is-installed-globally/-/is-installed-globally-0.1.0.tgz#0dfd98f5a9111716dd535dda6492f67bf3d25a80"
|
resolved "https://registry.npmjs.org/is-installed-globally/-/is-installed-globally-0.1.0.tgz#0dfd98f5a9111716dd535dda6492f67bf3d25a80"
|
||||||
@ -20065,13 +20040,6 @@ screenfull@^5.0.0:
|
|||||||
resolved "https://registry.npmjs.org/screenfull/-/screenfull-5.2.0.tgz#6533d524d30621fc1283b9692146f3f13a93d1ba"
|
resolved "https://registry.npmjs.org/screenfull/-/screenfull-5.2.0.tgz#6533d524d30621fc1283b9692146f3f13a93d1ba"
|
||||||
integrity sha512-9BakfsO2aUQN2K9Fdbj87RJIEZ82Q9IGim7FqM5OsebfoFC6ZHXgDq/KvniuLTPdeM8wY2o6Dj3WQ7KeQCj3cA==
|
integrity sha512-9BakfsO2aUQN2K9Fdbj87RJIEZ82Q9IGim7FqM5OsebfoFC6ZHXgDq/KvniuLTPdeM8wY2o6Dj3WQ7KeQCj3cA==
|
||||||
|
|
||||||
scroll-into-view-if-needed@^2.2.20:
|
|
||||||
version "2.2.29"
|
|
||||||
resolved "https://registry.npmmirror.com/scroll-into-view-if-needed/-/scroll-into-view-if-needed-2.2.29.tgz#551791a84b7e2287706511f8c68161e4990ab885"
|
|
||||||
integrity sha512-hxpAR6AN+Gh53AdAimHM6C8oTN1ppwVZITihix+WqalywBeFcQ6LdQP5ABNl26nX8GTEL7VT+b8lKpdqq65wXg==
|
|
||||||
dependencies:
|
|
||||||
compute-scroll-into-view "^1.0.17"
|
|
||||||
|
|
||||||
scroll-into-view-if-needed@^2.2.25:
|
scroll-into-view-if-needed@^2.2.25:
|
||||||
version "2.2.28"
|
version "2.2.28"
|
||||||
resolved "https://registry.npmjs.org/scroll-into-view-if-needed/-/scroll-into-view-if-needed-2.2.28.tgz#5a15b2f58a52642c88c8eca584644e01703d645a"
|
resolved "https://registry.npmjs.org/scroll-into-view-if-needed/-/scroll-into-view-if-needed-2.2.28.tgz#5a15b2f58a52642c88c8eca584644e01703d645a"
|
||||||
@ -20362,36 +20330,6 @@ slash@^3.0.0:
|
|||||||
resolved "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz#6539be870c165adbd5240220dbe361f1bc4d4634"
|
resolved "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz#6539be870c165adbd5240220dbe361f1bc4d4634"
|
||||||
integrity sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==
|
integrity sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==
|
||||||
|
|
||||||
slate-history@^0.66.0:
|
|
||||||
version "0.66.0"
|
|
||||||
resolved "https://registry.npmmirror.com/slate-history/-/slate-history-0.66.0.tgz#ac63fddb903098ceb4c944433e3f75fe63acf940"
|
|
||||||
integrity sha512-6MWpxGQZiMvSINlCbMW43E2YBSVMCMCIwQfBzGssjWw4kb0qfvj0pIdblWNRQZD0hR6WHP+dHHgGSeVdMWzfng==
|
|
||||||
dependencies:
|
|
||||||
is-plain-object "^5.0.0"
|
|
||||||
|
|
||||||
slate-react@^0.76.1:
|
|
||||||
version "0.76.1"
|
|
||||||
resolved "https://registry.npmmirror.com/slate-react/-/slate-react-0.76.1.tgz#a92915b204d84d59cb42d7818dcf48891d072016"
|
|
||||||
integrity sha512-deIhlGp8jUd5eZ8fodJ+Os3Eznk2bGJ4T6FPxzX04gFDCFVgXaYLfy9pObkQHW5XGnHwV3rniAyAtHBxNzrm9Q==
|
|
||||||
dependencies:
|
|
||||||
"@types/is-hotkey" "^0.1.1"
|
|
||||||
"@types/lodash" "^4.14.149"
|
|
||||||
direction "^1.0.3"
|
|
||||||
is-hotkey "^0.1.6"
|
|
||||||
is-plain-object "^5.0.0"
|
|
||||||
lodash "^4.17.4"
|
|
||||||
scroll-into-view-if-needed "^2.2.20"
|
|
||||||
tiny-invariant "1.0.6"
|
|
||||||
|
|
||||||
slate@^0.76.1:
|
|
||||||
version "0.76.1"
|
|
||||||
resolved "https://registry.npmmirror.com/slate/-/slate-0.76.1.tgz#6bc46cb923f3b26fdddb80b2a28142c2d7aa9a0b"
|
|
||||||
integrity sha512-ALsAInU8vUEL65IGWttc1xOzq7KmNtn4XIDxylJnbGXWziKZxxRpL4nL8QHZX553Q1EPmi0w+kWOG+hnLFfcgw==
|
|
||||||
dependencies:
|
|
||||||
immer "^9.0.6"
|
|
||||||
is-plain-object "^5.0.0"
|
|
||||||
tiny-warning "^1.0.3"
|
|
||||||
|
|
||||||
slice-ansi@^4.0.0:
|
slice-ansi@^4.0.0:
|
||||||
version "4.0.0"
|
version "4.0.0"
|
||||||
resolved "https://registry.npmjs.org/slice-ansi/-/slice-ansi-4.0.0.tgz#500e8dd0fd55b05815086255b3195adf2a45fe6b"
|
resolved "https://registry.npmjs.org/slice-ansi/-/slice-ansi-4.0.0.tgz#500e8dd0fd55b05815086255b3195adf2a45fe6b"
|
||||||
@ -21470,11 +21408,6 @@ tiny-emitter@^2.1.0:
|
|||||||
resolved "https://registry.npmmirror.com/tiny-emitter/-/tiny-emitter-2.1.0.tgz#1d1a56edfc51c43e863cbb5382a72330e3555423"
|
resolved "https://registry.npmmirror.com/tiny-emitter/-/tiny-emitter-2.1.0.tgz#1d1a56edfc51c43e863cbb5382a72330e3555423"
|
||||||
integrity sha512-NB6Dk1A9xgQPMoGqC5CVXn123gWyte215ONT5Pp5a0yt4nlEoO1ZWeCwpncaekPHXO60i47ihFnZPiRPjRMq4Q==
|
integrity sha512-NB6Dk1A9xgQPMoGqC5CVXn123gWyte215ONT5Pp5a0yt4nlEoO1ZWeCwpncaekPHXO60i47ihFnZPiRPjRMq4Q==
|
||||||
|
|
||||||
tiny-invariant@1.0.6:
|
|
||||||
version "1.0.6"
|
|
||||||
resolved "https://registry.npmmirror.com/tiny-invariant/-/tiny-invariant-1.0.6.tgz#b3f9b38835e36a41c843a3b0907a5a7b3755de73"
|
|
||||||
integrity sha512-FOyLWWVjG+aC0UqG76V53yAWdXfH8bO6FNmyZOuUrzDzK8DI3/JRY25UD7+g49JWM1LXwymsKERB+DzI0dTEQA==
|
|
||||||
|
|
||||||
tiny-invariant@^1.0.2, tiny-invariant@^1.0.6:
|
tiny-invariant@^1.0.2, tiny-invariant@^1.0.6:
|
||||||
version "1.2.0"
|
version "1.2.0"
|
||||||
resolved "https://registry.npmjs.org/tiny-invariant/-/tiny-invariant-1.2.0.tgz#a1141f86b672a9148c72e978a19a73b9b94a15a9"
|
resolved "https://registry.npmjs.org/tiny-invariant/-/tiny-invariant-1.2.0.tgz#a1141f86b672a9148c72e978a19a73b9b94a15a9"
|
||||||
|
Loading…
Reference in New Issue
Block a user