Skip to content

Commit 9abbaa6

Browse files
committed
feat(ui): add notification component
1 parent 3305f22 commit 9abbaa6

58 files changed

Lines changed: 1821 additions & 695 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

package.json

Lines changed: 33 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -23,82 +23,83 @@
2323
"build:executors": "tsc --project tools/tsconfig.json",
2424
"release": "standard-version",
2525
"prepare": "husky install && chmod ug+x .husky/*",
26-
"prepublishOnly": "nx build ui"
26+
"prepublishOnly": "nx build ui",
27+
"check-update": "yarn upgrade-interactive --latest"
2728
},
2829
"dependencies": {
29-
"core-js": "^3.19.1",
30-
"i18next": "^21.5.3",
30+
"core-js": "^3.20.1",
31+
"i18next": "^21.6.4",
3132
"immer": "^9.0.7",
3233
"lodash": "^4.17.21",
3334
"react": "18.0.0-rc.0",
3435
"react-dom": "18.0.0-rc.0",
35-
"react-i18next": "^11.14.3",
36-
"react-router-dom": "^6.0.2",
36+
"react-i18next": "^11.15.2",
37+
"react-router-dom": "^6.2.1",
3738
"regenerator-runtime": "^0.13.9",
3839
"rfs": "^9.0.6",
39-
"rxjs": "^7.4.0",
40+
"rxjs": "^7.5.1",
4041
"tslib": "^2.3.1"
4142
},
4243
"devDependencies": {
43-
"@commitlint/cli": "^15.0.0",
44-
"@commitlint/config-conventional": "^15.0.0",
45-
"@nrwl/cli": "^13.3.1",
46-
"@nrwl/cypress": "^13.3.1",
47-
"@nrwl/eslint-plugin-nx": "^13.3.1",
48-
"@nrwl/jest": "^13.3.1",
49-
"@nrwl/linter": "^13.3.1",
50-
"@nrwl/nx-cloud": "latest",
51-
"@nrwl/react": "^13.3.1",
52-
"@nrwl/tao": "^13.3.1",
53-
"@nrwl/web": "^13.3.1",
54-
"@nrwl/workspace": "^13.3.1",
44+
"@commitlint/cli": "^16.0.1",
45+
"@commitlint/config-conventional": "^16.0.0",
46+
"@nrwl/cli": "^13.4.1",
47+
"@nrwl/cypress": "^13.4.1",
48+
"@nrwl/eslint-plugin-nx": "^13.4.1",
49+
"@nrwl/jest": "^13.4.1",
50+
"@nrwl/linter": "^13.4.1",
51+
"@nrwl/nx-cloud": "13.0.1",
52+
"@nrwl/react": "^13.4.1",
53+
"@nrwl/tao": "^13.4.1",
54+
"@nrwl/web": "^13.4.1",
55+
"@nrwl/workspace": "^13.4.1",
5556
"@testing-library/jest-dom": "^5.16.1",
5657
"@testing-library/react": "13.0.0-alpha.5",
5758
"@testing-library/react-hooks": "^7.0.2",
5859
"@types/enzyme": "^3.10.10",
5960
"@types/fs-extra": "^9.0.13",
60-
"@types/jest": "^27.0.3",
61+
"@types/jest": "^27.4.0",
6162
"@types/lodash": "^4.14.177",
6263
"@types/marked": "^3.0.1",
63-
"@types/node": "^16.11.10",
64-
"@types/react": "^17.0.37",
64+
"@types/node": "^17.0.5",
65+
"@types/react": "^17.0.38",
6566
"@types/react-dom": "^17.0.11",
66-
"@typescript-eslint/eslint-plugin": "^5.4.0",
67-
"@typescript-eslint/parser": "^5.4.0",
68-
"babel-jest": "^27.3.1",
69-
"cypress": "^9.1.0",
67+
"@typescript-eslint/eslint-plugin": "^5.8.1",
68+
"@typescript-eslint/parser": "^5.8.1",
69+
"babel-jest": "^27.4.5",
70+
"cypress": "^9.2.0",
7071
"dotenv": "^10.0.0",
7172
"enzyme": "^3.11.0",
7273
"enzyme-adapter-react-16": "^1.15.6",
73-
"eslint": "^8.2.0",
74+
"eslint": "^8.5.0",
7475
"eslint-config-prettier": "^8.3.0",
7576
"eslint-plugin-cypress": "^2.12.1",
7677
"eslint-plugin-import": "^2.25.3",
7778
"eslint-plugin-jsx-a11y": "^6.5.1",
7879
"eslint-plugin-markdown": "^2.2.1",
7980
"eslint-plugin-prettier": "^4.0.0",
80-
"eslint-plugin-react": "^7.27.1",
81+
"eslint-plugin-react": "^7.28.0",
8182
"eslint-plugin-react-hooks": "^4.3.0",
8283
"fs-extra": "^10.0.0",
8384
"highlight.js": "^11.3.1",
8485
"husky": "^7.0.4",
85-
"jest": "^27.3.1",
86+
"jest": "^27.4.5",
8687
"marked": "^3.0.4",
8788
"postcss-html": "^1.3.0",
8889
"postcss-markdown": "^1.2.0",
8990
"prettier": "^2.5.0",
9091
"react-test-renderer": "^17.0.2",
9192
"rxjs-for-await": "^1.0.0",
92-
"sass": "^1.43.5",
93+
"sass": "^1.45.2",
9394
"standard-version": "^9.3.2",
94-
"stylelint": "^14.1.0",
95+
"stylelint": "^14.2.0",
9596
"stylelint-config-prettier": "^9.0.3",
9697
"stylelint-config-rational-order": "^0.1.2",
9798
"stylelint-config-recommended-scss": "^5.0.2",
9899
"stylelint-config-standard": "^24.0.0",
99100
"stylelint-order": "^5.0.0",
100-
"stylelint-scss": "^4.0.0",
101-
"ts-jest": "^27.0.7",
101+
"stylelint-scss": "^4.1.0",
102+
"ts-jest": "^27.1.2",
102103
"ts-node": "^10.4.0",
103104
"typescript": "~4.5.2",
104105
"yaml-front-matter": "^4.1.1"

packages/site/project.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
"outputs": ["{options.outputPath}"],
1616
"defaultConfiguration": "production",
1717
"options": {
18+
"compiler": "babel",
1819
"deployUrl": "/",
1920
"outputPath": "dist/packages/site",
2021
"index": "packages/site/src/index.html",

packages/site/src/app/App.tsx

Lines changed: 11 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,8 @@
11
import React, { useCallback, useEffect, useMemo, useState } from 'react';
22
import { useTranslation } from 'react-i18next';
3+
import { useLocation } from 'react-router-dom';
34

4-
import { DConfigRoot } from '@react-devui/ui';
5+
import { DRoot, NotificationService } from '@react-devui/ui';
56
import { useAsync } from '@react-devui/ui/hooks';
67

78
import { environment } from '../environments/environment';
@@ -55,6 +56,11 @@ export function App() {
5556
}
5657
}, [asyncCapture, mainEl]);
5758

59+
const location = useLocation();
60+
useEffect(() => {
61+
NotificationService.closeAll(false);
62+
}, [location]);
63+
5864
const contextValue = useMemo<AppContextData>(
5965
() => ({
6066
menuOpen,
@@ -79,15 +85,15 @@ export function App() {
7985
);
8086

8187
return (
82-
<AppContext.Provider value={contextValue}>
83-
<DConfigRoot content="main .app-route-article" i18n={{ lang: i18n.language as 'en-US' | 'zh-Hant' }} icons={icons}>
88+
<DRoot i18n={{ lang: i18n.language as 'en-US' | 'zh-Hant' }} icons={icons} contentSelector="main .app-route-article">
89+
<AppContext.Provider value={contextValue}>
8490
<AppHeader />
8591
<AppSidebar />
8692
<main ref={mainRef} className="app-main">
8793
<AppRoutes />
8894
</main>
89-
</DConfigRoot>
90-
</AppContext.Provider>
95+
</AppContext.Provider>
96+
</DRoot>
9197
);
9298
}
9399

packages/site/src/app/components/route/RouteArticle.scss

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -18,10 +18,6 @@
1818
z-index: 910;
1919

2020
width: 168px;
21-
22-
.d-anchor-link__link {
23-
padding: 4px 0;
24-
}
2521
}
2622

2723
.app-route-article__anchor-conatiner {

packages/site/src/app/routes/components/Interface.md

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -76,7 +76,8 @@ Extend `React.HTMLAttributes<HTMLDivElement>`.
7676
<!-- prettier-ignore-start -->
7777
| Property | Description | Type | Default |
7878
| --- | --- | --- | --- |
79-
| dCloseIcon | Set the icon of the close button, `null` means hide the button | React.ReactNode | - |
79+
| dClosable | Can be closed | boolean | false |
80+
| dCloseIcon | Custom close icon | React.ReactNode | - |
8081
| dExtraIcons | Add some extra action buttons | React.ReactNode[] | - |
8182
| onClose | Callback when the close button is clicked | `() => void` | - |
8283
<!-- prettier-ignore-end -->

packages/site/src/app/routes/components/Interface.zh-Hant.md

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -76,7 +76,8 @@ interface DTransitionStateList {
7676
<!-- prettier-ignore-start -->
7777
| 参数 | 说明 | 类型 | 默认值 |
7878
| --- | --- | --- | --- |
79-
| dCloseIcon | 设置关闭按钮的图标, `null` 表示隐藏按钮 | React.ReactNode | - |
79+
| dClosable | 是否可关闭 | boolean | false |
80+
| dCloseIcon | 设置关闭按钮的图标 | React.ReactNode | - |
8081
| dExtraIcons | 添加一些额外的操作按钮 | React.ReactNode[] | - |
8182
| onClose | 点击关闭按钮的回调 | `() => void` | - |
8283
<!-- prettier-ignore-end -->

packages/site/src/app/styles/_app.scss

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -190,10 +190,15 @@ h3 {
190190
.app-component-route-article__demos {
191191
section[id^='Button'],
192192
section[id^='Dropdown'],
193-
section[id^='Tooltip'] {
193+
section[id^='Tooltip'],
194+
section[id^='Notification'] {
194195
.d-button {
195196
margin-right: 8px;
196197
margin-bottom: 12px;
198+
199+
&.d-button--block {
200+
margin-right: 0;
201+
}
197202
}
198203

199204
.d-button-group {
@@ -232,8 +237,6 @@ h3 {
232237

233238
background-color: var(--d-color-primary);
234239

235-
@include font-size(0.8rem);
236-
237240
& + &,
238241
& + .app-demo-drag-placeholder,
239242
.app-demo-drag-placeholder + & {
Lines changed: 84 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,84 @@
1+
import { useCallback, useEffect, useRef } from 'react';
2+
3+
import { useAsync } from '../../hooks';
4+
5+
export interface DAlertDialogProps extends React.HTMLAttributes<HTMLDivElement> {
6+
dHidden: boolean;
7+
dDuration: number;
8+
dDialogRef?: React.LegacyRef<HTMLDivElement>;
9+
onClose?: () => void;
10+
}
11+
12+
export function DAlertDialog(props: DAlertDialogProps) {
13+
const { dHidden, dDuration, dDialogRef, onClose, children, onKeyDown, onMouseEnter, onMouseLeave, ...restProps } = props;
14+
15+
const dataRef = useRef<{ clearTid: (() => void) | null }>({
16+
clearTid: null,
17+
});
18+
19+
const asyncCapture = useAsync();
20+
21+
const handleKeyDown = useCallback<React.KeyboardEventHandler<HTMLDivElement>>(
22+
(e) => {
23+
onKeyDown?.(e);
24+
25+
if (e.code === 'Escape') {
26+
dataRef.current.clearTid && dataRef.current.clearTid();
27+
onClose?.();
28+
}
29+
},
30+
[onClose, onKeyDown]
31+
);
32+
33+
const handleMouseEnter = useCallback<React.MouseEventHandler<HTMLDivElement>>(
34+
(e) => {
35+
onMouseEnter?.(e);
36+
37+
dataRef.current.clearTid && dataRef.current.clearTid();
38+
},
39+
[onMouseEnter]
40+
);
41+
42+
const handleMouseLeave = useCallback<React.MouseEventHandler<HTMLDivElement>>(
43+
(e) => {
44+
onMouseLeave?.(e);
45+
46+
if (dDuration > 0) {
47+
dataRef.current.clearTid && dataRef.current.clearTid();
48+
dataRef.current.clearTid = asyncCapture.setTimeout(() => {
49+
onClose?.();
50+
}, dDuration * 1000);
51+
}
52+
},
53+
[asyncCapture, dDuration, onClose, onMouseLeave]
54+
);
55+
56+
useEffect(() => {
57+
if (dDuration > 0) {
58+
dataRef.current.clearTid && dataRef.current.clearTid();
59+
dataRef.current.clearTid = asyncCapture.setTimeout(() => {
60+
onClose?.();
61+
}, dDuration * 1000);
62+
}
63+
// eslint-disable-next-line react-hooks/exhaustive-deps
64+
}, []);
65+
66+
return (
67+
// eslint-disable-next-line react/jsx-no-useless-fragment
68+
<>
69+
{!dHidden && (
70+
<div
71+
{...restProps}
72+
ref={dDialogRef}
73+
role="alertdialog"
74+
aria-modal="true"
75+
onKeyDown={handleKeyDown}
76+
onMouseEnter={handleMouseEnter}
77+
onMouseLeave={handleMouseLeave}
78+
>
79+
{children}
80+
</div>
81+
)}
82+
</>
83+
);
84+
}
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
export * from './AlertDialog';

packages/ui/src/components/_dialog/Dialog.tsx

Lines changed: 1 addition & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -5,29 +5,23 @@ import { getClassName, mergeStyle } from '../../utils';
55
import { DMask } from './Mask';
66

77
export interface DDialogProps extends React.HTMLAttributes<HTMLDivElement> {
8-
dId: string;
98
dVisible: boolean;
109
dHidden: boolean;
11-
dContentProps?: React.HTMLAttributes<HTMLDivElement>;
1210
dMask?: boolean;
1311
dMaskClosable?: boolean;
1412
dDestroy?: boolean;
1513
dDialogRef?: React.LegacyRef<HTMLDivElement>;
16-
dDialogContentRef?: React.LegacyRef<HTMLDivElement>;
1714
onClose?: () => void;
1815
}
1916

2017
export function DDialog(props: DDialogProps) {
2118
const {
22-
dId,
2319
dVisible,
2420
dHidden,
25-
dContentProps,
2621
dMask = true,
2722
dMaskClosable = true,
2823
dDestroy = false,
2924
dDialogRef,
30-
dDialogContentRef,
3125
onClose,
3226
className,
3327
style,
@@ -70,18 +64,9 @@ export function DDialog(props: DDialogProps) {
7064
style={mergeStyle(style, { display: dHidden ? 'none' : undefined })}
7165
role="dialog"
7266
aria-modal="true"
73-
aria-describedby={`${dPrefix}dialog-content-${dId}`}
7467
>
7568
{dMask && <DMask dVisible={dVisible} onClose={handleMaskClose} />}
76-
<div
77-
{...dContentProps}
78-
ref={dDialogContentRef}
79-
id={`${dPrefix}dialog-content-${dId}`}
80-
className={getClassName(dContentProps?.className, `${dPrefix}dialog__content`)}
81-
tabIndex={-1}
82-
>
83-
{children}
84-
</div>
69+
{children}
8570
</div>
8671
)}
8772
</>

0 commit comments

Comments
 (0)