Browse Source

feat : new components app (#39046)

* feat : new components app

* feat: update app

* feat: update app

* feat: update app

* feat: update app

* feat: update app

* feat: update app

* feat: update app

* feat: update style

* feat: update style

* feat: update style

* feat: add style

* chore: code clean

* feat: add prefixCls

* chore: update snapshot

* chore: update snapshot

* chore: update snapshot

* test: image test

* Update components/app/index.zh-CN.md

Co-authored-by: afc163 <afc163@gmail.com>

* feat : update for reviewer

* feat: update

* feat: update

* feat: update snap

Co-authored-by: MadCcc <1075746765@qq.com>
Co-authored-by: afc163 <afc163@gmail.com>
pull/39356/head
黑雨 2 years ago
committed by GitHub
parent
commit
db4ee53ffa
No known key found for this signature in database GPG Key ID: 4AEE18F83AFDEB23
  1. 1
      components/__tests__/__snapshots__/index.test.ts.snap
  2. 46
      components/app/__tests__/__snapshots__/demo-extend.test.ts.snap
  3. 46
      components/app/__tests__/__snapshots__/demo.test.ts.snap
  4. 17
      components/app/__tests__/__snapshots__/index.test.tsx.snap
  5. 3
      components/app/__tests__/demo-extend.test.ts
  6. 3
      components/app/__tests__/demo.test.ts
  7. 5
      components/app/__tests__/image.test.ts
  8. 33
      components/app/__tests__/index.test.tsx
  9. 19
      components/app/context.ts
  10. 7
      components/app/demo/message.md
  11. 24
      components/app/demo/message.tsx
  12. 7
      components/app/demo/modal.md
  13. 27
      components/app/demo/modal.tsx
  14. 7
      components/app/demo/notification.md
  15. 28
      components/app/demo/notification.tsx
  16. 43
      components/app/index.en-US.md
  17. 60
      components/app/index.tsx
  18. 45
      components/app/index.zh-CN.md
  19. 22
      components/app/style/index.tsx
  20. 1
      components/index.tsx
  21. 6
      components/style/index.tsx
  22. 2
      components/theme/interface/components.ts
  23. 2
      components/theme/util/genComponentStyleHook.ts
  24. 1
      tests/__snapshots__/index.test.ts.snap
  25. 5
      tests/shared/imageTest.tsx

1
components/__tests__/__snapshots__/index.test.ts.snap

@ -5,6 +5,7 @@ exports[`antd exports modules correctly 1`] = `
"Affix",
"Alert",
"Anchor",
"App",
"AutoComplete",
"Avatar",
"BackTop",

46
components/app/__tests__/__snapshots__/demo-extend.test.ts.snap

@ -0,0 +1,46 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`renders ./components/app/demo/message.tsx extend context correctly 1`] = `
<div
class="ant-app"
>
<button
class="ant-btn ant-btn-primary"
type="button"
>
<span>
Open message
</span>
</button>
</div>
`;
exports[`renders ./components/app/demo/modal.tsx extend context correctly 1`] = `
<div
class="ant-app"
>
<button
class="ant-btn ant-btn-primary"
type="button"
>
<span>
Open modal
</span>
</button>
</div>
`;
exports[`renders ./components/app/demo/notification.tsx extend context correctly 1`] = `
<div
class="ant-app"
>
<button
class="ant-btn ant-btn-primary"
type="button"
>
<span>
Open notification
</span>
</button>
</div>
`;

46
components/app/__tests__/__snapshots__/demo.test.ts.snap

@ -0,0 +1,46 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`renders ./components/app/demo/message.tsx correctly 1`] = `
<div
class="ant-app"
>
<button
class="ant-btn ant-btn-primary"
type="button"
>
<span>
Open message
</span>
</button>
</div>
`;
exports[`renders ./components/app/demo/modal.tsx correctly 1`] = `
<div
class="ant-app"
>
<button
class="ant-btn ant-btn-primary"
type="button"
>
<span>
Open modal
</span>
</button>
</div>
`;
exports[`renders ./components/app/demo/notification.tsx correctly 1`] = `
<div
class="ant-app"
>
<button
class="ant-btn ant-btn-primary"
type="button"
>
<span>
Open notification
</span>
</button>
</div>
`;

17
components/app/__tests__/__snapshots__/index.test.tsx.snap

@ -0,0 +1,17 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`App rtl render component should be rendered correctly in RTL direction 1`] = `
<div
class="ant-app"
/>
`;
exports[`App single 1`] = `
<div
class="ant-app"
>
<div>
Hello World
</div>
</div>
`;

3
components/app/__tests__/demo-extend.test.ts

@ -0,0 +1,3 @@
import { extendTest } from '../../../tests/shared/demoTest';
extendTest('app');

3
components/app/__tests__/demo.test.ts

@ -0,0 +1,3 @@
import demoTest from '../../../tests/shared/demoTest';
demoTest('app');

5
components/app/__tests__/image.test.ts

@ -0,0 +1,5 @@
import { imageDemoTest } from '../../../tests/shared/imageTest';
describe('app', () => {
imageDemoTest('app');
});

33
components/app/__tests__/index.test.tsx

@ -0,0 +1,33 @@
import React from 'react';
import App from '..';
import mountTest from '../../../tests/shared/mountTest';
import rtlTest from '../../../tests/shared/rtlTest';
import { render } from '../../../tests/utils';
describe('App', () => {
mountTest(App);
rtlTest(App);
it('single', () => {
// Sub page
const MyPage = () => {
const { message } = App.useApp();
React.useEffect(() => {
message.success('Good!');
}, [message]);
return <div>Hello World</div>;
};
// Entry component
const MyApp = () => (
<App>
<MyPage />
</App>
);
const { getByText, container } = render(<MyApp />);
expect(getByText('Hello World')).toBeTruthy();
expect(container.firstChild).toMatchSnapshot();
});
});

19
components/app/context.ts

@ -0,0 +1,19 @@
import React from 'react';
import type { MessageInstance } from '../message/interface';
import type { NotificationInstance } from '../notification/interface';
import type { ModalStaticFunctions } from '../modal/confirm';
type ModalType = Omit<ModalStaticFunctions, 'warn'>;
export interface useAppProps {
message: MessageInstance;
notification: NotificationInstance;
modal: ModalType;
}
const AppContext = React.createContext<useAppProps>({
message: {} as MessageInstance,
notification: {} as NotificationInstance,
modal: {} as ModalType,
});
export default AppContext;

7
components/app/demo/message.md

@ -0,0 +1,7 @@
## zh-CN
获取 `message` 静态方法.
## en-US
Static method for `message`.

24
components/app/demo/message.tsx

@ -0,0 +1,24 @@
import React from 'react';
import { App, Button } from 'antd';
// Sub page
const MyPage = () => {
const { message } = App.useApp();
const showMessage = () => {
message.success('Success!');
};
return (
<Button type="primary" onClick={showMessage}>
Open message
</Button>
);
};
// Entry component
export default () => (
<App>
<MyPage />
</App>
);

7
components/app/demo/modal.md

@ -0,0 +1,7 @@
## zh-CN
获取 `modal` 静态方法.
## en-US
Static method for `modal`.

27
components/app/demo/modal.tsx

@ -0,0 +1,27 @@
import React from 'react';
import { App, Button } from 'antd';
// Sub page
const MyPage = () => {
const { modal } = App.useApp();
const showModal = () => {
modal.warning({
title: 'This is a warning message',
content: 'some messages...some messages...',
});
};
return (
<Button type="primary" onClick={showModal}>
Open modal
</Button>
);
};
// Entry component
export default () => (
<App>
<MyPage />
</App>
);

7
components/app/demo/notification.md

@ -0,0 +1,7 @@
## zh-CN
获取 `notification` 静态方法.
## en-US
Static method for `notification`.

28
components/app/demo/notification.tsx

@ -0,0 +1,28 @@
import React from 'react';
import { App, Button } from 'antd';
// Sub page
const MyPage = () => {
const { notification } = App.useApp();
const showNotification = () => {
notification.info({
message: `Notification topLeft`,
description: 'Hello, Ant Design!!',
placement: 'topLeft',
});
};
return (
<Button type="primary" onClick={showNotification}>
Open notification
</Button>
);
};
// Entry component
export default () => (
<App>
<MyPage />
</App>
);

43
components/app/index.en-US.md

@ -0,0 +1,43 @@
---
category: Components
group: Other
title: App
cover: https://gw.alipayobjects.com/zos/bmw-prod/cc3fcbfa-bf5b-4c8c-8a3d-c3f8388c75e8.svg
demo:
cols: 2
---
New App Component which provide global style & static function replacement.
## When To Use
Static function in React 18 concurrent mode will not well support. In v5, we recommend to use hooks for the static replacement. But it will make user manual work on define this.
## Examples
<!-- prettier-ignore -->
<code src="./demo/message.tsx">message</code>
<code src="./demo/notification.tsx">notification</code>
<code src="./demo/modal.tsx">modal</code>
## How to use
```javascript
import React from 'react';
import { App } from 'antd';
const MyPage = () => {
const { message, notification, modal } = App.useApp();
message.success('Good!');
notification.info({ message: 'Good' });
modal.warning({ title: 'Good' });
// ....
// other message,notification,modal static function
return <div>Hello word</div>;
};
const MyApp = () => (
<App>
<MyPage />
</App>
);
```

60
components/app/index.tsx

@ -0,0 +1,60 @@
import React, { useContext } from 'react';
import type { ReactNode } from 'react';
import classNames from 'classnames';
import type { ConfigConsumerProps } from '../config-provider';
import { ConfigContext } from '../config-provider';
import useStyle from './style';
import useMessage from '../message/useMessage';
import useNotification from '../notification/useNotification';
import useModal from '../modal/useModal';
import AppContext from './context';
import type { useAppProps } from './context';
export type AppProps = {
className?: string;
prefixCls?: string;
children?: ReactNode;
};
const useApp: () => useAppProps = () => React.useContext(AppContext);
const App: React.ForwardRefRenderFunction<HTMLDivElement, AppProps> & {
useApp: () => useAppProps;
} = (props) => {
const { prefixCls: customizePrefixCls, children, className } = props;
const { getPrefixCls } = useContext<ConfigConsumerProps>(ConfigContext);
const prefixCls = getPrefixCls('app', customizePrefixCls);
const [wrapSSR, hashId] = useStyle(prefixCls);
const customClassName = classNames(hashId, prefixCls, className);
const [messageApi, messageContextHolder] = useMessage();
const [notificationApi, notificationContextHolder] = useNotification();
const [ModalApi, ModalContextHolder] = useModal();
const memoizedContextValue = React.useMemo(
() => ({
message: messageApi,
notification: notificationApi,
modal: ModalApi,
}),
[messageApi, notificationApi, ModalApi],
);
return wrapSSR(
<AppContext.Provider value={memoizedContextValue}>
<div className={customClassName}>
{ModalContextHolder}
{messageContextHolder}
{notificationContextHolder}
{children}
</div>
</AppContext.Provider>,
);
};
if (process.env.NODE_ENV !== 'production') {
App.displayName = 'App';
}
App.useApp = useApp;
export default App;

45
components/app/index.zh-CN.md

@ -0,0 +1,45 @@
---
category: Components
subtitle: 包裹组件
group: 其他
title: App
cover: https://gw.alipayobjects.com/zos/bmw-prod/cc3fcbfa-bf5b-4c8c-8a3d-c3f8388c75e8.svg
demo:
cols: 2
---
新的包裹组件,提供重置样式和提供消费上下文的默认环境。
## 何时使用
- 提供可消费 React context 的 `message.xxx`、`Modal.xxx`、`notification.xxx` 的静态方法,可以简化 useMessage 等方法需要手动植入 `contextHolder` 的问题。
- 提供基于 `.ant-app` 的默认重置样式,解决原生元素没有 antd 规范样式的问题。
## 代码演示
<!-- prettier-ignore -->
<code src="./demo/message.tsx">message</code>
<code src="./demo/notification.tsx">notification</code>
<code src="./demo/modal.tsx">modal</code>
## How to use
```javascript
import React from 'react';
import { App } from 'antd';
const MyPage = () => {
const { message, notification, modal } = App.useApp();
message.success('Good!');
notification.info({ message: 'Good' });
modal.warning({ title: 'Good' });
// ....
// other message,notification,modal static function
return <div>Hello word</div>;
};
const MyApp = () => (
<App>
<MyPage />
</App>
);
```

22
components/app/style/index.tsx

@ -0,0 +1,22 @@
import type { FullToken, GenerateStyle } from '../../theme/internal';
import { genComponentStyleHook } from '../../theme/internal';
export type ComponentToken = {};
interface AppToken extends FullToken<'App'> {}
// =============================== Base ===============================
const genBaseStyle: GenerateStyle<AppToken> = (token) => {
const { componentCls, colorText, fontSize, lineHeight, fontFamily } = token;
return {
[componentCls]: {
color: colorText,
fontSize,
lineHeight,
fontFamily,
},
};
};
// ============================== Export ==============================
export default genComponentStyleHook('App', (token) => [genBaseStyle(token)]);

1
components/index.tsx

@ -135,6 +135,7 @@ export { default as Tooltip } from './tooltip';
export type { TooltipProps } from './tooltip';
export { default as Tour } from './tour';
export type { TourProps, TourStepProps } from './tour/interface';
export { default as App } from './app';
export { default as Transfer } from './transfer';
export type { TransferProps } from './transfer';
export { default as Tree } from './tree';

6
components/style/index.tsx

@ -103,15 +103,11 @@ export const genLinkStyle = (token: DerivativeToken): CSSObject => ({
},
});
export const genCommonStyle = (token: DerivativeToken, componentPrefixCls: string): CSSObject => {
const { fontFamily, fontSize } = token;
export const genCommonStyle = (componentPrefixCls: string): CSSObject => {
const rootPrefixSelector = `[class^="${componentPrefixCls}"], [class*=" ${componentPrefixCls}"]`;
return {
[rootPrefixSelector]: {
fontFamily,
fontSize,
boxSizing: 'border-box',
'&::before, &::after': {

2
components/theme/interface/components.ts

@ -47,6 +47,7 @@ import type { ComponentToken as TypographyComponentToken } from '../../typograph
import type { ComponentToken as UploadComponentToken } from '../../upload/style';
import type { ComponentToken as TourComponentToken } from '../../tour/style';
import type { ComponentToken as QRCodeComponentToken } from '../../qrcode/style';
import type { ComponentToken as AppComponentToken } from '../../app/style';
export interface ComponentTokenMap {
Affix?: {};
@ -110,4 +111,5 @@ export interface ComponentTokenMap {
Progress?: ProgressComponentToken;
Tour?: TourComponentToken;
QRCode?: QRCodeComponentToken;
App?: AppComponentToken;
}

2
components/theme/util/genComponentStyleHook.ts

@ -87,7 +87,7 @@ export default function genComponentStyleHook<ComponentName extends OverrideComp
overrideComponentToken: token[component],
});
flush(component, mergedComponentToken);
return [genCommonStyle(token, prefixCls), styleInterpolation];
return [genCommonStyle(prefixCls), styleInterpolation];
},
),
hashId,

1
tests/__snapshots__/index.test.ts.snap

@ -5,6 +5,7 @@ exports[`antd dist files exports modules correctly 1`] = `
"Affix",
"Alert",
"Anchor",
"App",
"AutoComplete",
"Avatar",
"BackTop",

5
tests/shared/imageTest.tsx

@ -7,6 +7,7 @@ import glob from 'glob';
import { configureToMatchImageSnapshot } from 'jest-image-snapshot';
import MockDate from 'mockdate';
import ReactDOMServer from 'react-dom/server';
import { App } from '../../components';
const toMatchImageSnapshot = configureToMatchImageSnapshot({
customSnapshotsDir: `${process.cwd()}/imageSnapshots`,
@ -35,7 +36,9 @@ export default function imageTest(component: React.ReactElement) {
const cache = createCache();
const html = ReactDOMServer.renderToString(
<StyleProvider cache={cache}>{component}</StyleProvider>,
<App>
<StyleProvider cache={cache}>{component}</StyleProvider>,
</App>,
);
const styleStr = extractStyle(cache);

Loading…
Cancel
Save