refactor: remove error-fallback and __builtins__ from plugin-core

This commit is contained in:
sealday 2024-03-18 10:48:28 +08:00
parent dbd5622f27
commit 8d580b72b2
14 changed files with 0 additions and 427 deletions

View File

@ -1,3 +0,0 @@
export * from './useConfig';
export * from './usePrefixCls';
export * from './useToken';

View File

@ -1,5 +0,0 @@
import { ConfigProvider } from 'antd';
import { useContext } from 'react';
const { ConfigContext } = ConfigProvider;
export const useConfig = () => useContext(ConfigContext);

View File

@ -1,17 +0,0 @@
import { ConfigProvider } from 'antd';
import { useContext } from 'react';
export const usePrefixCls = (
tag?: string,
props?: {
prefixCls?: string;
},
) => {
const { getPrefixCls } = useContext(ConfigProvider.ConfigContext) || {};
if ('ConfigContext' in ConfigProvider) {
return getPrefixCls?.(tag, props?.prefixCls) || '';
} else {
const prefix = props?.prefixCls ?? 'ant-';
return `${prefix}${tag ?? ''}`;
}
};

View File

@ -1,13 +0,0 @@
import { theme } from 'antd';
import { CustomToken } from '../style';
interface Result extends ReturnType<typeof theme.useToken> {
token: CustomToken;
}
const useToken = () => {
const result = theme.useToken();
return result as Result;
};
export { useToken };

View File

@ -1,4 +0,0 @@
export * from './hooks';
export * from './loading';
export * from './portal';
export * from './style';

View File

@ -1,14 +0,0 @@
import { message } from 'antd';
export const loading = async (title: React.ReactNode = 'Loading...', processor: () => Promise<any>) => {
let hide: any = null;
const loading = setTimeout(() => {
hide = message.loading(title);
}, 100);
try {
return await processor();
} finally {
hide?.();
clearTimeout(loading);
}
};

View File

@ -1,63 +0,0 @@
import { Observer, ReactFC } from '@formily/react';
import { observable } from '@formily/reactive';
import React, { Fragment } from 'react';
import { createPortal } from 'react-dom';
import { render as reactRender, unmount as reactUnmount } from './render';
export interface IPortalProps {
id?: string | symbol;
}
const PortalMap = observable(new Map<string | symbol, React.ReactNode>());
export const createPortalProvider = (id: string | symbol) => {
const Portal: ReactFC<IPortalProps> = (props) => {
if (props.id && !PortalMap.has(props.id)) {
PortalMap.set(props.id, null);
}
return (
<Fragment>
{props.children}
<Observer>
{() => {
if (!props.id) return <></>;
const portal = PortalMap.get(props.id);
if (portal) return createPortal(portal, document.body);
return <></>;
}}
</Observer>
</Fragment>
);
};
Portal.defaultProps = {
id,
};
return Portal;
};
export function createPortalRoot<T extends React.ReactNode>(host: HTMLElement, id: string) {
function render(renderer?: () => T) {
if (PortalMap.has(id)) {
PortalMap.set(id, renderer?.());
} else if (host) {
reactRender(<Fragment>{renderer?.()}</Fragment>, host);
}
}
function unmount() {
if (PortalMap.has(id)) {
PortalMap.set(id, null);
}
if (host) {
const unmountResult = reactUnmount(host);
if (unmountResult && host.parentNode) {
host.parentNode?.removeChild(host);
}
}
}
return {
render,
unmount,
};
}

View File

@ -1,89 +0,0 @@
import { ReactElement } from 'react';
import * as ReactDOM from 'react-dom';
import type { Root } from 'react-dom/client';
// 移植自rc-util: https://github.com/react-component/util/blob/master/src/React/render.ts
type CreateRoot = (container: ContainerType) => Root;
// Let compiler not to search module usage
const fullClone = {
...ReactDOM,
} as typeof ReactDOM & {
__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED?: {
usingClientEntryPoint?: boolean;
};
createRoot?: CreateRoot;
};
const { version, render: reactRender, unmountComponentAtNode } = fullClone;
let createRoot: CreateRoot;
try {
const mainVersion = Number((version || '').split('.')[0]);
if (mainVersion >= 18 && fullClone.createRoot) {
// eslint-disable-next-line @typescript-eslint/no-var-requires
createRoot = fullClone.createRoot;
}
} catch (e) {
// Do nothing;
}
function toggleWarning(skip: boolean) {
const { __SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED } = fullClone;
if (
__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED &&
typeof __SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED === 'object'
) {
__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED.usingClientEntryPoint = skip;
}
}
const MARK = '__antd_mobile_root__';
// ========================== Render ==========================
type ContainerType = (Element | DocumentFragment) & {
[MARK]?: Root;
};
function legacyRender(node: ReactElement, container: ContainerType) {
reactRender(node, container);
}
function concurrentRender(node: ReactElement, container: ContainerType) {
toggleWarning(true);
const root = container[MARK] || createRoot(container);
toggleWarning(false);
root.render(node);
container[MARK] = root;
}
export function render(node: ReactElement, container: ContainerType) {
if (createRoot as unknown) {
concurrentRender(node, container);
return;
}
legacyRender(node, container);
}
// ========================== Unmount =========================
function legacyUnmount(container: ContainerType) {
return unmountComponentAtNode(container);
}
async function concurrentUnmount(container: ContainerType) {
// Delay to unmount to avoid React 18 sync warning
return Promise.resolve().then(() => {
container[MARK]?.unmount();
delete container[MARK];
});
}
export function unmount(container: ContainerType) {
if (createRoot as unknown) {
return concurrentUnmount(container);
}
return legacyUnmount(container);
}

View File

@ -1,130 +0,0 @@
import type { CSSInterpolation, CSSObject } from '@ant-design/cssinjs';
import { useStyleRegister } from '@ant-design/cssinjs';
import { merge } from '@formily/shared';
import type { ComponentTokenMap, GlobalToken } from 'antd/es/theme/interface';
import { AliasToken } from 'antd/es/theme/internal';
import { useConfig, usePrefixCls, useToken } from './hooks';
export interface CustomToken extends AliasToken {
/** 顶部导航栏主色 */
colorPrimaryHeader: string;
/** 导航栏背景色 */
colorBgHeader: string;
/** 导航栏菜单背景色悬浮态 */
colorBgHeaderMenuHover: string;
/** 导航栏菜单背景色激活态 */
colorBgHeaderMenuActive: string;
/** 导航栏菜单文本色 */
colorTextHeaderMenu: string;
/** 导航栏菜单文本色悬浮态 */
colorTextHeaderMenuHover: string;
/** 导航栏菜单文本色激活态 */
colorTextHeaderMenuActive: string;
/** UI 配置色 */
colorSettings: string;
/** 鼠标悬浮时显示的背景色 */
colorBgSettingsHover: string;
/** 鼠标悬浮时显示的边框色 */
colorBorderSettingsHover: string;
}
export type OverrideComponent = keyof ComponentTokenMap | string;
export interface StyleInfo {
hashId: string;
prefixCls: string;
rootPrefixCls: string;
iconPrefixCls: string;
}
export type TokenWithCommonCls<T> = T & {
/** Wrap component class with `.` prefix */
componentCls: string;
/** Origin prefix which do not have `.` prefix */
prefixCls: string;
/** Wrap icon class with `.` prefix */
iconCls: string;
/** Wrap ant prefixCls class with `.` prefix */
antCls: string;
};
export type GenerateStyle<
ComponentToken extends object = TokenWithCommonCls<GlobalToken>,
ReturnType = CSSInterpolation,
> = (token: ComponentToken, options?: any) => ReturnType;
export const genCommonStyle = (token: any, componentPrefixCls: string): CSSObject => {
const { fontFamily, fontSize } = token;
const rootPrefixSelector = `[class^="${componentPrefixCls}"], [class*=" ${componentPrefixCls}"]`;
return {
[rootPrefixSelector]: {
fontFamily,
fontSize,
boxSizing: 'border-box',
'&::before, &::after': {
boxSizing: 'border-box',
},
[rootPrefixSelector]: {
boxSizing: 'border-box',
'&::before, &::after': {
boxSizing: 'border-box',
},
},
},
};
};
export type UseComponentStyleResult = {
wrapSSR: ReturnType<typeof useStyleRegister>;
hashId: string;
componentCls: string;
rootPrefixCls: string;
};
export const genStyleHook = <ComponentName extends OverrideComponent>(
component: ComponentName,
styleFn: (token: TokenWithCommonCls<CustomToken>, props: any, info: StyleInfo) => CSSInterpolation,
) => {
return (props?: any): UseComponentStyleResult => {
const { theme, token, hashId } = useToken();
const { getPrefixCls, iconPrefixCls } = useConfig();
const prefixCls = usePrefixCls(component);
const rootPrefixCls = getPrefixCls();
return {
wrapSSR: useStyleRegister(
{
theme: theme as any,
token,
hashId,
path: ['formily-antd', component, prefixCls, iconPrefixCls],
},
() => {
const componentCls = `.${prefixCls}`;
const mergedToken: TokenWithCommonCls<CustomToken> = merge(token, {
componentCls,
prefixCls,
iconCls: `.${iconPrefixCls}`,
antCls: `.${rootPrefixCls}`,
});
const styleInterpolation = styleFn(mergedToken, props, {
hashId,
prefixCls,
rootPrefixCls,
iconPrefixCls,
});
return [genCommonStyle(token, prefixCls), styleInterpolation];
},
),
hashId,
componentCls: prefixCls,
rootPrefixCls,
};
};
};

View File

@ -1,45 +0,0 @@
import { Button, Result, Typography } from 'antd';
import React, { FC } from 'react';
import { FallbackProps, useErrorBoundary } from 'react-error-boundary';
import { Trans, useTranslation } from 'react-i18next';
const { Paragraph, Text, Link } = Typography;
export const ErrorFallback: FC<FallbackProps> = ({ error }) => {
const { resetBoundary } = useErrorBoundary();
const { t } = useTranslation();
const subTitle = (
<Trans>
{'This is likely a NocoBase internals bug. Please open an issue at '}
<Link href="https://github.com/nocobase/nocobase/issues" target="_blank">
here
</Link>
</Trans>
);
return (
<div style={{ backgroundColor: 'white' }}>
<Result
style={{ maxWidth: '60vw', margin: 'auto' }}
status="error"
title={t('Render Failed')}
subTitle={subTitle}
extra={[
<Button type="primary" key="feedback" href="https://github.com/nocobase/nocobase/issues" target="_blank">
{t('Feedback')}
</Button>,
<Button key="try" onClick={resetBoundary}>
{t('Try again')}
</Button>,
]}
>
<Paragraph copyable>
<Text type="danger" style={{ whiteSpace: 'pre-line', textAlign: 'center' }}>
{error.stack}
</Text>
</Paragraph>
</Result>
</div>
);
};

View File

@ -1,18 +0,0 @@
import React from 'react';
import { render, screen } from 'testUtils';
import App1 from '../demos/demo1';
describe('ErrorFallback', () => {
it('should render correctly', () => {
render(<App1 />);
expect(screen.getByText(/render failed/i)).toBeInTheDocument();
expect(screen.getByText(/this is likely a nocobase internals bug\. please open an issue at/i)).toBeInTheDocument();
expect(screen.getByRole('link', { name: /feedback/i })).toBeInTheDocument();
expect(screen.getByText(/try again/i)).toBeInTheDocument();
expect(screen.getByText(/error: error message/i)).toBeInTheDocument();
// 底部复制按钮
expect(document.querySelector('.ant-typography-copy')).toBeInTheDocument();
});
});

View File

@ -1,15 +0,0 @@
import React from 'react';
import { ErrorBoundary } from 'react-error-boundary';
import { ErrorFallback } from '../ErrorFallback';
const App = () => {
throw new Error('error message');
};
export default () => {
return (
<ErrorBoundary FallbackComponent={ErrorFallback} onError={console.error}>
<App />
</ErrorBoundary>
);
};

View File

@ -1,10 +0,0 @@
---
group:
title: Schema Components
---
# ErrorFallback
## Example
<code src="./demos/demo1.tsx"></code>

View File

@ -1 +0,0 @@
export * from './ErrorFallback';