@servicetitan/notifications 25.9.0 → 26.1.0
Sign up to get free protection for your applications and to get access to all the features.
- package/dist/components/__tests__/container.test.d.ts +2 -0
- package/dist/components/__tests__/container.test.d.ts.map +1 -0
- package/dist/components/__tests__/container.test.js +59 -0
- package/dist/components/__tests__/container.test.js.map +1 -0
- package/dist/components/container.d.ts +2 -2
- package/dist/components/container.d.ts.map +1 -1
- package/dist/components/container.js +19 -31
- package/dist/components/container.js.map +1 -1
- package/dist/components/notifications.d.ts +2 -2
- package/dist/components/notifications.d.ts.map +1 -1
- package/dist/components/shadow-dom.d.ts +2 -2
- package/dist/components/shadow-dom.d.ts.map +1 -1
- package/dist/components/shadow-dom.js.map +1 -1
- package/package.json +15 -13
- package/src/components/__tests__/container.test.tsx +71 -0
- package/src/components/container.tsx +26 -41
- package/src/components/notifications.tsx +2 -2
- package/src/components/shadow-dom.tsx +2 -2
@@ -0,0 +1 @@
|
|
1
|
+
{"version":3,"file":"container.test.d.ts","sourceRoot":"","sources":["../../../src/components/__tests__/container.test.tsx"],"names":[],"mappings":"AAAA,OAAO,2BAA2B,CAAC"}
|
@@ -0,0 +1,59 @@
|
|
1
|
+
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
2
|
+
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
3
|
+
return new (P || (P = Promise))(function (resolve, reject) {
|
4
|
+
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
5
|
+
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
6
|
+
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
7
|
+
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
8
|
+
});
|
9
|
+
};
|
10
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
11
|
+
import '@testing-library/jest-dom';
|
12
|
+
import { render, waitFor, within } from '@testing-library/react';
|
13
|
+
import { Container } from '../container';
|
14
|
+
describe('[notifications] Container', () => {
|
15
|
+
beforeEach(() => {
|
16
|
+
var _a;
|
17
|
+
(_a = document.getElementById('servicetitan-notifications')) === null || _a === void 0 ? void 0 : _a.remove();
|
18
|
+
});
|
19
|
+
const subject = (children) => {
|
20
|
+
return render(_jsx(Container, { children: children }));
|
21
|
+
};
|
22
|
+
test('renders #servicetitan-notifications.initialized > .ToastGroup', () => __awaiter(void 0, void 0, void 0, function* () {
|
23
|
+
subject();
|
24
|
+
yield waitFor(() => expect(document.querySelectorAll('#servicetitan-notifications.initialized > .ToastGroup')).toHaveLength(1));
|
25
|
+
}));
|
26
|
+
test('renders children within .ToastGroup', () => __awaiter(void 0, void 0, void 0, function* () {
|
27
|
+
subject(_jsx("button", { children: "Foo" }));
|
28
|
+
yield waitFor(() => {
|
29
|
+
expect(within(document.querySelector('#servicetitan-notifications.initialized > .ToastGroup')).getByRole('button', { name: 'Foo' })).toBeInTheDocument();
|
30
|
+
});
|
31
|
+
}));
|
32
|
+
describe('when #servicetitan-notifications already exists', () => {
|
33
|
+
let container;
|
34
|
+
beforeEach(() => {
|
35
|
+
container = document.createElement('div');
|
36
|
+
container.setAttribute('id', 'servicetitan-notifications');
|
37
|
+
document.body.appendChild(container);
|
38
|
+
});
|
39
|
+
test('creates .ToastGroup within existing container', () => __awaiter(void 0, void 0, void 0, function* () {
|
40
|
+
subject();
|
41
|
+
yield waitFor(() => {
|
42
|
+
expect(container.querySelectorAll('.ToastGroup')).toHaveLength(1);
|
43
|
+
});
|
44
|
+
}));
|
45
|
+
describe('when .ToastGroup already exists', () => {
|
46
|
+
let toastGroup;
|
47
|
+
beforeEach(() => {
|
48
|
+
toastGroup = document.createElement('div');
|
49
|
+
toastGroup.classList.add('ToastGroup');
|
50
|
+
container.appendChild(toastGroup);
|
51
|
+
});
|
52
|
+
test('renders children inside existing ToastGroup', () => {
|
53
|
+
subject(_jsx("button", { children: "Baz" }));
|
54
|
+
expect(within(toastGroup).getByRole('button', { name: 'Baz' })).toBeInTheDocument();
|
55
|
+
});
|
56
|
+
});
|
57
|
+
});
|
58
|
+
});
|
59
|
+
//# sourceMappingURL=container.test.js.map
|
@@ -0,0 +1 @@
|
|
1
|
+
{"version":3,"file":"container.test.js","sourceRoot":"","sources":["../../../src/components/__tests__/container.test.tsx"],"names":[],"mappings":";;;;;;;;;;AAAA,OAAO,2BAA2B,CAAC;AACnC,OAAO,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,MAAM,wBAAwB,CAAC;AAGjE,OAAO,EAAE,SAAS,EAAE,MAAM,cAAc,CAAC;AAEzC,QAAQ,CAAC,2BAA2B,EAAE,GAAG,EAAE;IACvC,UAAU,CAAC,GAAG,EAAE;;QACZ,MAAA,QAAQ,CAAC,cAAc,CAAC,4BAA4B,CAAC,0CAAE,MAAM,EAAE,CAAC;IACpE,CAAC,CAAC,CAAC;IAEH,MAAM,OAAO,GAAG,CAAC,QAAoB,EAAE,EAAE;QACrC,OAAO,MAAM,CAAC,KAAC,SAAS,cAAE,QAAQ,GAAa,CAAC,CAAC;IACrD,CAAC,CAAC;IAEF,IAAI,CAAC,+DAA+D,EAAE,GAAS,EAAE;QAC7E,OAAO,EAAE,CAAC;QAEV,MAAM,OAAO,CAAC,GAAG,EAAE,CACf,MAAM,CACF,QAAQ,CAAC,gBAAgB,CAAC,uDAAuD,CAAC,CACrF,CAAC,YAAY,CAAC,CAAC,CAAC,CACpB,CAAC;IACN,CAAC,CAAA,CAAC,CAAC;IAEH,IAAI,CAAC,qCAAqC,EAAE,GAAS,EAAE;QACnD,OAAO,CAAC,mCAAoB,CAAC,CAAC;QAE9B,MAAM,OAAO,CAAC,GAAG,EAAE;YACf,MAAM,CACF,MAAM,CACF,QAAQ,CAAC,aAAa,CAAC,uDAAuD,CAAE,CACnF,CAAC,SAAS,CAAC,QAAQ,EAAE,EAAE,IAAI,EAAE,KAAK,EAAE,CAAC,CACzC,CAAC,iBAAiB,EAAE,CAAC;QAC1B,CAAC,CAAC,CAAC;IACP,CAAC,CAAA,CAAC,CAAC;IAEH,QAAQ,CAAC,iDAAiD,EAAE,GAAG,EAAE;QAC7D,IAAI,SAAsB,CAAC;QAE3B,UAAU,CAAC,GAAG,EAAE;YACZ,SAAS,GAAG,QAAQ,CAAC,aAAa,CAAC,KAAK,CAAC,CAAC;YAC1C,SAAS,CAAC,YAAY,CAAC,IAAI,EAAE,4BAA4B,CAAC,CAAC;YAC3D,QAAQ,CAAC,IAAI,CAAC,WAAW,CAAC,SAAS,CAAC,CAAC;QACzC,CAAC,CAAC,CAAC;QAEH,IAAI,CAAC,+CAA+C,EAAE,GAAS,EAAE;YAC7D,OAAO,EAAE,CAAC;YAEV,MAAM,OAAO,CAAC,GAAG,EAAE;gBACf,MAAM,CAAC,SAAS,CAAC,gBAAgB,CAAC,aAAa,CAAC,CAAC,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC;YACtE,CAAC,CAAC,CAAC;QACP,CAAC,CAAA,CAAC,CAAC;QAEH,QAAQ,CAAC,iCAAiC,EAAE,GAAG,EAAE;YAC7C,IAAI,UAAuB,CAAC;YAE5B,UAAU,CAAC,GAAG,EAAE;gBACZ,UAAU,GAAG,QAAQ,CAAC,aAAa,CAAC,KAAK,CAAC,CAAC;gBAC3C,UAAU,CAAC,SAAS,CAAC,GAAG,CAAC,YAAY,CAAC,CAAC;gBACvC,SAAS,CAAC,WAAW,CAAC,UAAU,CAAC,CAAC;YACtC,CAAC,CAAC,CAAC;YAEH,IAAI,CAAC,6CAA6C,EAAE,GAAG,EAAE;gBACrD,OAAO,CAAC,mCAAoB,CAAC,CAAC;gBAE9B,MAAM,CAAC,MAAM,CAAC,UAAU,CAAC,CAAC,SAAS,CAAC,QAAQ,EAAE,EAAE,IAAI,EAAE,KAAK,EAAE,CAAC,CAAC,CAAC,iBAAiB,EAAE,CAAC;YACxF,CAAC,CAAC,CAAC;QACP,CAAC,CAAC,CAAC;IACP,CAAC,CAAC,CAAC;AACP,CAAC,CAAC,CAAC"}
|
@@ -1,3 +1,3 @@
|
|
1
|
-
import { FC } from 'react';
|
2
|
-
export declare const Container: FC
|
1
|
+
import { FC, PropsWithChildren } from 'react';
|
2
|
+
export declare const Container: FC<PropsWithChildren>;
|
3
3
|
//# sourceMappingURL=container.d.ts.map
|
@@ -1 +1 @@
|
|
1
|
-
{"version":3,"file":"container.d.ts","sourceRoot":"","sources":["../../src/components/container.tsx"],"names":[],"mappings":"
|
1
|
+
{"version":3,"file":"container.d.ts","sourceRoot":"","sources":["../../src/components/container.tsx"],"names":[],"mappings":"AACA,OAAO,EAAE,EAAE,EAAY,iBAAiB,EAAuB,MAAM,OAAO,CAAC;AAK7E,eAAO,MAAM,SAAS,EAAE,EAAE,CAAC,iBAAiB,CAwB3C,CAAC"}
|
@@ -1,38 +1,26 @@
|
|
1
|
-
import { jsx as _jsx } from "react/jsx-runtime";
|
2
|
-
import { useState, useEffect } from 'react';
|
3
|
-
import { render, createPortal } from 'react-dom';
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
4
2
|
import { Toast } from '@servicetitan/design-system';
|
3
|
+
import { Fragment, useEffect, useState } from 'react';
|
4
|
+
import { createPortal } from 'react-dom';
|
5
5
|
import { createElement } from '../create-element';
|
6
6
|
export const Container = ({ children }) => {
|
7
|
-
|
8
|
-
|
9
|
-
|
7
|
+
const [container] = useState(() => {
|
8
|
+
var _a;
|
9
|
+
return ((_a = document.getElementById('servicetitan-notifications')) !== null && _a !== void 0 ? _a : document.body.appendChild(createElement('div', { id: 'servicetitan-notifications' })));
|
10
|
+
});
|
11
|
+
const [toastGroup, setToastGroup] = useState(() => findToastGroup(container));
|
12
|
+
const [foundGroup] = useState(() => !!toastGroup);
|
10
13
|
useEffect(() => {
|
11
|
-
if (!
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
container.classList.add('initialized');
|
16
|
-
});
|
17
|
-
container.classList.add('initializing');
|
14
|
+
if (!toastGroup) {
|
15
|
+
setToastGroup(findToastGroup(container));
|
16
|
+
// This stops old code running in MFE from rendering duplicate Toast.Group
|
17
|
+
container.classList.add('initialized');
|
18
18
|
}
|
19
|
-
|
20
|
-
|
21
|
-
observer = new MutationObserver(() => {
|
22
|
-
var _a;
|
23
|
-
if (container.classList.contains('initialized')) {
|
24
|
-
setTarget((_a = container.getElementsByClassName('ToastGroup')[0]) !== null && _a !== void 0 ? _a : null);
|
25
|
-
observer.disconnect();
|
26
|
-
}
|
27
|
-
});
|
28
|
-
observer.observe(container, {
|
29
|
-
attributeFilter: ['class'],
|
30
|
-
});
|
31
|
-
}
|
32
|
-
return () => {
|
33
|
-
observer === null || observer === void 0 ? void 0 : observer.disconnect();
|
34
|
-
};
|
35
|
-
}, [container, target]);
|
36
|
-
return target ? createPortal(children, target) : null;
|
19
|
+
}, [container, toastGroup]);
|
20
|
+
return (_jsxs(Fragment, { children: [foundGroup ? null : _jsx(Toast.Group, { portal: container }), toastGroup ? createPortal(children, toastGroup) : null] }));
|
37
21
|
};
|
22
|
+
function findToastGroup(parent) {
|
23
|
+
var _a;
|
24
|
+
return (_a = parent.getElementsByClassName('ToastGroup')[0]) !== null && _a !== void 0 ? _a : null;
|
25
|
+
}
|
38
26
|
//# sourceMappingURL=container.js.map
|
@@ -1 +1 @@
|
|
1
|
-
{"version":3,"file":"container.js","sourceRoot":"","sources":["../../src/components/container.tsx"],"names":[],"mappings":";AAAA,OAAO,EAAE,
|
1
|
+
{"version":3,"file":"container.js","sourceRoot":"","sources":["../../src/components/container.tsx"],"names":[],"mappings":";AAAA,OAAO,EAAE,KAAK,EAAE,MAAM,6BAA6B,CAAC;AACpD,OAAO,EAAM,QAAQ,EAAqB,SAAS,EAAE,QAAQ,EAAE,MAAM,OAAO,CAAC;AAC7E,OAAO,EAAE,YAAY,EAAE,MAAM,WAAW,CAAC;AAEzC,OAAO,EAAE,aAAa,EAAE,MAAM,mBAAmB,CAAC;AAElD,MAAM,CAAC,MAAM,SAAS,GAA0B,CAAC,EAAE,QAAQ,EAAE,EAAE,EAAE;IAC7D,MAAM,CAAC,SAAS,CAAC,GAAG,QAAQ,CAAC,GAAG,EAAE;;QAC9B,OAAO,CACH,MAAA,QAAQ,CAAC,cAAc,CAAC,4BAA4B,CAAC,mCACrD,QAAQ,CAAC,IAAI,CAAC,WAAW,CAAC,aAAa,CAAC,KAAK,EAAE,EAAE,EAAE,EAAE,4BAA4B,EAAE,CAAC,CAAC,CACxF,CAAC;IACN,CAAC,CAAC,CAAC;IACH,MAAM,CAAC,UAAU,EAAE,aAAa,CAAC,GAAG,QAAQ,CAAC,GAAG,EAAE,CAAC,cAAc,CAAC,SAAS,CAAC,CAAC,CAAC;IAC9E,MAAM,CAAC,UAAU,CAAC,GAAG,QAAQ,CAAC,GAAG,EAAE,CAAC,CAAC,CAAC,UAAU,CAAC,CAAC;IAElD,SAAS,CAAC,GAAG,EAAE;QACX,IAAI,CAAC,UAAU,EAAE;YACb,aAAa,CAAC,cAAc,CAAC,SAAS,CAAC,CAAC,CAAC;YACzC,0EAA0E;YAC1E,SAAS,CAAC,SAAS,CAAC,GAAG,CAAC,aAAa,CAAC,CAAC;SAC1C;IACL,CAAC,EAAE,CAAC,SAAS,EAAE,UAAU,CAAC,CAAC,CAAC;IAE5B,OAAO,CACH,MAAC,QAAQ,eACJ,UAAU,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,KAAC,KAAK,CAAC,KAAK,IAAC,MAAM,EAAE,SAAS,GAAI,EACtD,UAAU,CAAC,CAAC,CAAC,YAAY,CAAC,QAAQ,EAAE,UAAU,CAAC,CAAC,CAAC,CAAC,IAAI,IAChD,CACd,CAAC;AACN,CAAC,CAAC;AAEF,SAAS,cAAc,CAAC,MAAmB;;IACvC,OAAO,MAAA,MAAM,CAAC,sBAAsB,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC,mCAAI,IAAI,CAAC;AAClE,CAAC"}
|
@@ -1,7 +1,7 @@
|
|
1
|
-
import { FC } from 'react';
|
1
|
+
import { FC, PropsWithChildren } from 'react';
|
2
2
|
import { interfaces } from '@servicetitan/react-ioc';
|
3
3
|
import { NotificationsApi } from '../api/notifications.api';
|
4
|
-
export interface NotificationsProps {
|
4
|
+
export interface NotificationsProps extends PropsWithChildren<{}> {
|
5
5
|
apiService?: interfaces.Newable<NotificationsApi>;
|
6
6
|
}
|
7
7
|
export declare const Notifications: FC<NotificationsProps>;
|
@@ -1 +1 @@
|
|
1
|
-
{"version":3,"file":"notifications.d.ts","sourceRoot":"","sources":["../../src/components/notifications.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAE,EAAE,EAAE,MAAM,OAAO,CAAC;
|
1
|
+
{"version":3,"file":"notifications.d.ts","sourceRoot":"","sources":["../../src/components/notifications.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAE,EAAE,EAAE,iBAAiB,EAAE,MAAM,OAAO,CAAC;AAE9C,OAAO,EAAY,UAAU,EAAE,MAAM,yBAAyB,CAAC;AAE/D,OAAO,EACH,gBAAgB,EAGnB,MAAM,0BAA0B,CAAC;AAelC,MAAM,WAAW,kBAAmB,SAAQ,iBAAiB,CAAC,EAAE,CAAC;IAC7D,UAAU,CAAC,EAAE,UAAU,CAAC,OAAO,CAAC,gBAAgB,CAAC,CAAC;CACrD;AAED,eAAO,MAAM,aAAa,EAAE,EAAE,CAAC,kBAAkB,CAWhD,CAAC"}
|
@@ -1,3 +1,3 @@
|
|
1
|
-
import { FC } from 'react';
|
2
|
-
export declare const ShadowDOM: FC
|
1
|
+
import { FC, PropsWithChildren } from 'react';
|
2
|
+
export declare const ShadowDOM: FC<PropsWithChildren>;
|
3
3
|
//# sourceMappingURL=shadow-dom.d.ts.map
|
@@ -1 +1 @@
|
|
1
|
-
{"version":3,"file":"shadow-dom.d.ts","sourceRoot":"","sources":["../../src/components/shadow-dom.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAY,EAAE,EAAE,MAAM,OAAO,CAAC;
|
1
|
+
{"version":3,"file":"shadow-dom.d.ts","sourceRoot":"","sources":["../../src/components/shadow-dom.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAY,EAAE,EAAE,iBAAiB,EAAE,MAAM,OAAO,CAAC;AAmBxD,eAAO,MAAM,SAAS,EAAE,EAAE,CAAC,iBAAiB,CAiC3C,CAAC"}
|
@@ -1 +1 @@
|
|
1
|
-
{"version":3,"file":"shadow-dom.js","sourceRoot":"","sources":["../../src/components/shadow-dom.tsx"],"names":[],"mappings":";AAAA,OAAO,EAAE,QAAQ,
|
1
|
+
{"version":3,"file":"shadow-dom.js","sourceRoot":"","sources":["../../src/components/shadow-dom.tsx"],"names":[],"mappings":";AAAA,OAAO,EAAE,QAAQ,EAAyB,MAAM,OAAO,CAAC;AACxD,OAAO,EAAE,YAAY,EAAE,MAAM,WAAW,CAAC;AAEzC,OAAO,cAAc,MAAM,kCAAkC,CAAC;AAE9D,OAAO,EAAE,cAAc,EAAE,MAAM,oBAAoB,CAAC;AAEpD,SAAS,UAAU,CAAC,GAAW,EAAE,MAAkB;IAC/C,MAAM,OAAO,GAAG,QAAQ,CAAC,aAAa,CAAC,MAAM,CAAC,CAAC;IAE/C,OAAO,CAAC,IAAI,GAAG,GAAG,CAAC;IACnB,OAAO,CAAC,GAAG,GAAG,YAAY,CAAC;IAC3B,OAAO,CAAC,WAAW,GAAG,WAAW,CAAC;IAClC,OAAO,CAAC,MAAM,GAAG,MAAM,CAAC;IACxB,OAAO,CAAC,OAAO,GAAG,MAAM,CAAC;IAEzB,OAAO,OAAO,CAAC;AACnB,CAAC;AAED,MAAM,CAAC,MAAM,SAAS,GAA0B,CAAC,EAAE,QAAQ,EAAE,EAAE,EAAE;IAC7D,MAAM,CAAC,MAAM,EAAE,SAAS,CAAC,GAAG,QAAQ,CAAiB,IAAI,CAAC,CAAC;IAC3D,MAAM,CAAC,MAAM,EAAE,SAAS,CAAC,GAAG,QAAQ,CAAC,KAAK,CAAC,CAAC;IAC5C,MAAM,WAAW,GAAG,cAAc,EAAE,CAAC;IAErC,MAAM,SAAS,GAAG,CAAC,OAA8B,EAAE,EAAE;QACjD,IAAI,CAAC,OAAO,IAAI,MAAM,EAAE;YACpB,OAAO;SACV;QAED,IAAI,WAAW,GAAG,CAAC,CAAC;QACpB,IAAI,YAAY,GAAG,CAAC,CAAC;QACrB,MAAM,IAAI,GAAG,OAAO,CAAC,YAAY,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,CAAC,CAAC;QAEpD,MAAM,UAAU,GAAG,GAAG,EAAE;YACpB,YAAY,EAAE,CAAC;YAEf,IAAI,YAAY,KAAK,WAAW,EAAE;gBAC9B,SAAS,CAAC,IAAI,CAAC,CAAC;aACnB;QACL,CAAC,CAAC;QAEF,KAAK,MAAM,GAAG,IAAI,WAAW,EAAE;YAC3B,IAAI,CAAC,MAAM,CAAC,UAAU,CAAC,GAAG,EAAE,UAAU,CAAC,CAAC,CAAC;YACzC,WAAW,EAAE,CAAC;SACjB;QAED,cAAc,CAAC,IAAI,CAAC,CAAC;QAErB,SAAS,CAAC,IAAI,CAAC,WAAW,CAAC,QAAQ,CAAC,aAAa,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;IAC/D,CAAC,CAAC;IAEF,OAAO,4BAAK,GAAG,EAAE,SAAS,gBAAG,MAAM,IAAI,MAAM,CAAC,CAAC,CAAC,YAAY,CAAC,QAAQ,EAAE,MAAM,CAAC,CAAC,CAAC,CAAC,IAAI,IAAO,CAAC;AACjG,CAAC,CAAC"}
|
package/package.json
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
{
|
2
2
|
"name": "@servicetitan/notifications",
|
3
|
-
"version": "
|
3
|
+
"version": "26.1.0",
|
4
4
|
"description": "",
|
5
5
|
"homepage": "https://docs.st.dev/docs/frontend/notifications-center",
|
6
6
|
"repository": {
|
@@ -21,18 +21,20 @@
|
|
21
21
|
"react-shadow-dom-retarget-events": "~1.1.0"
|
22
22
|
},
|
23
23
|
"devDependencies": {
|
24
|
-
"@servicetitan/design-system": "
|
25
|
-
"@servicetitan/log-service": "
|
26
|
-
"@servicetitan/react-ioc": "^
|
27
|
-
"@servicetitan/web-components": "^
|
28
|
-
"@
|
24
|
+
"@servicetitan/design-system": "~13.4.5",
|
25
|
+
"@servicetitan/log-service": "^23.2.1",
|
26
|
+
"@servicetitan/react-ioc": "^23.2.1",
|
27
|
+
"@servicetitan/web-components": "^23.2.1",
|
28
|
+
"@testing-library/jest-dom": "^6.4.2",
|
29
|
+
"@testing-library/react": "^14.2.1",
|
30
|
+
"@types/react": "~18.2.55",
|
29
31
|
"@types/react-router": "~5.1.17",
|
30
32
|
"@types/react-shadow-dom-retarget-events": "~1.0.0",
|
31
33
|
"axios": "~0.27.2",
|
32
34
|
"mobx": "~6.6.0",
|
33
|
-
"mobx-react": "~7.5.
|
34
|
-
"react": "~
|
35
|
-
"react-dom": "~
|
35
|
+
"mobx-react": "~7.5.1",
|
36
|
+
"react": "~18.2.0",
|
37
|
+
"react-dom": "~18.2.0",
|
36
38
|
"react-router-dom": "~5.3.0"
|
37
39
|
},
|
38
40
|
"peerDependencies": {
|
@@ -42,9 +44,9 @@
|
|
42
44
|
"@servicetitan/web-components": ">21.0.0",
|
43
45
|
"axios": "~0.27.2",
|
44
46
|
"mobx": "~6.6.0",
|
45
|
-
"mobx-react": "
|
46
|
-
"react": "
|
47
|
-
"react-dom": "
|
47
|
+
"mobx-react": ">=7.5.1",
|
48
|
+
"react": ">=17.0.2",
|
49
|
+
"react-dom": ">=17.0.2",
|
48
50
|
"react-router-dom": ">=5.3.0 <7.0.0"
|
49
51
|
},
|
50
52
|
"publishConfig": {
|
@@ -53,5 +55,5 @@
|
|
53
55
|
"cli": {
|
54
56
|
"webpack": false
|
55
57
|
},
|
56
|
-
"gitHead": "
|
58
|
+
"gitHead": "a859628bb29f8f17153e2a4e23bb38f14f447b10"
|
57
59
|
}
|
@@ -0,0 +1,71 @@
|
|
1
|
+
import '@testing-library/jest-dom';
|
2
|
+
import { render, waitFor, within } from '@testing-library/react';
|
3
|
+
import { ReactNode } from 'react';
|
4
|
+
|
5
|
+
import { Container } from '../container';
|
6
|
+
|
7
|
+
describe('[notifications] Container', () => {
|
8
|
+
beforeEach(() => {
|
9
|
+
document.getElementById('servicetitan-notifications')?.remove();
|
10
|
+
});
|
11
|
+
|
12
|
+
const subject = (children?: ReactNode) => {
|
13
|
+
return render(<Container>{children}</Container>);
|
14
|
+
};
|
15
|
+
|
16
|
+
test('renders #servicetitan-notifications.initialized > .ToastGroup', async () => {
|
17
|
+
subject();
|
18
|
+
|
19
|
+
await waitFor(() =>
|
20
|
+
expect(
|
21
|
+
document.querySelectorAll('#servicetitan-notifications.initialized > .ToastGroup')
|
22
|
+
).toHaveLength(1)
|
23
|
+
);
|
24
|
+
});
|
25
|
+
|
26
|
+
test('renders children within .ToastGroup', async () => {
|
27
|
+
subject(<button>Foo</button>);
|
28
|
+
|
29
|
+
await waitFor(() => {
|
30
|
+
expect(
|
31
|
+
within(
|
32
|
+
document.querySelector('#servicetitan-notifications.initialized > .ToastGroup')!
|
33
|
+
).getByRole('button', { name: 'Foo' })
|
34
|
+
).toBeInTheDocument();
|
35
|
+
});
|
36
|
+
});
|
37
|
+
|
38
|
+
describe('when #servicetitan-notifications already exists', () => {
|
39
|
+
let container: HTMLElement;
|
40
|
+
|
41
|
+
beforeEach(() => {
|
42
|
+
container = document.createElement('div');
|
43
|
+
container.setAttribute('id', 'servicetitan-notifications');
|
44
|
+
document.body.appendChild(container);
|
45
|
+
});
|
46
|
+
|
47
|
+
test('creates .ToastGroup within existing container', async () => {
|
48
|
+
subject();
|
49
|
+
|
50
|
+
await waitFor(() => {
|
51
|
+
expect(container.querySelectorAll('.ToastGroup')).toHaveLength(1);
|
52
|
+
});
|
53
|
+
});
|
54
|
+
|
55
|
+
describe('when .ToastGroup already exists', () => {
|
56
|
+
let toastGroup: HTMLElement;
|
57
|
+
|
58
|
+
beforeEach(() => {
|
59
|
+
toastGroup = document.createElement('div');
|
60
|
+
toastGroup.classList.add('ToastGroup');
|
61
|
+
container.appendChild(toastGroup);
|
62
|
+
});
|
63
|
+
|
64
|
+
test('renders children inside existing ToastGroup', () => {
|
65
|
+
subject(<button>Baz</button>);
|
66
|
+
|
67
|
+
expect(within(toastGroup).getByRole('button', { name: 'Baz' })).toBeInTheDocument();
|
68
|
+
});
|
69
|
+
});
|
70
|
+
});
|
71
|
+
});
|
@@ -1,50 +1,35 @@
|
|
1
|
-
import { useState, useEffect, FC } from 'react';
|
2
|
-
import { render, createPortal } from 'react-dom';
|
3
|
-
|
4
1
|
import { Toast } from '@servicetitan/design-system';
|
2
|
+
import { FC, Fragment, PropsWithChildren, useEffect, useState } from 'react';
|
3
|
+
import { createPortal } from 'react-dom';
|
5
4
|
|
6
5
|
import { createElement } from '../create-element';
|
7
6
|
|
8
|
-
export const Container: FC = ({ children }) => {
|
9
|
-
const container =
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
);
|
7
|
+
export const Container: FC<PropsWithChildren> = ({ children }) => {
|
8
|
+
const [container] = useState(() => {
|
9
|
+
return (
|
10
|
+
document.getElementById('servicetitan-notifications') ??
|
11
|
+
document.body.appendChild(createElement('div', { id: 'servicetitan-notifications' }))
|
12
|
+
);
|
13
|
+
});
|
14
|
+
const [toastGroup, setToastGroup] = useState(() => findToastGroup(container));
|
15
|
+
const [foundGroup] = useState(() => !!toastGroup);
|
16
16
|
|
17
17
|
useEffect(() => {
|
18
|
-
if (
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
render(<Toast.Group portal={container} />, container, () => {
|
23
|
-
container.classList.remove('initializing');
|
24
|
-
container.classList.add('initialized');
|
25
|
-
});
|
26
|
-
container.classList.add('initializing');
|
27
|
-
}
|
28
|
-
|
29
|
-
let observer: MutationObserver;
|
30
|
-
|
31
|
-
if (!target) {
|
32
|
-
observer = new MutationObserver(() => {
|
33
|
-
if (container.classList.contains('initialized')) {
|
34
|
-
setTarget(container.getElementsByClassName('ToastGroup')[0] ?? null);
|
35
|
-
observer.disconnect();
|
36
|
-
}
|
37
|
-
});
|
38
|
-
|
39
|
-
observer.observe(container, {
|
40
|
-
attributeFilter: ['class'],
|
41
|
-
});
|
18
|
+
if (!toastGroup) {
|
19
|
+
setToastGroup(findToastGroup(container));
|
20
|
+
// This stops old code running in MFE from rendering duplicate Toast.Group
|
21
|
+
container.classList.add('initialized');
|
42
22
|
}
|
23
|
+
}, [container, toastGroup]);
|
43
24
|
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
25
|
+
return (
|
26
|
+
<Fragment>
|
27
|
+
{foundGroup ? null : <Toast.Group portal={container} />}
|
28
|
+
{toastGroup ? createPortal(children, toastGroup) : null}
|
29
|
+
</Fragment>
|
30
|
+
);
|
50
31
|
};
|
32
|
+
|
33
|
+
function findToastGroup(parent: HTMLElement) {
|
34
|
+
return parent.getElementsByClassName('ToastGroup')[0] ?? null;
|
35
|
+
}
|
@@ -1,4 +1,4 @@
|
|
1
|
-
import { FC } from 'react';
|
1
|
+
import { FC, PropsWithChildren } from 'react';
|
2
2
|
|
3
3
|
import { Provider, interfaces } from '@servicetitan/react-ioc';
|
4
4
|
|
@@ -21,7 +21,7 @@ import {
|
|
21
21
|
import { DefaultNotification } from './default-notification';
|
22
22
|
import { NotificationsUnwrapped } from './notifications-unwrapped';
|
23
23
|
|
24
|
-
export interface NotificationsProps {
|
24
|
+
export interface NotificationsProps extends PropsWithChildren<{}> {
|
25
25
|
apiService?: interfaces.Newable<NotificationsApi>;
|
26
26
|
}
|
27
27
|
|
@@ -1,4 +1,4 @@
|
|
1
|
-
import { useState, FC } from 'react';
|
1
|
+
import { useState, FC, PropsWithChildren } from 'react';
|
2
2
|
import { createPortal } from 'react-dom';
|
3
3
|
|
4
4
|
import retargetEvents from 'react-shadow-dom-retarget-events';
|
@@ -17,7 +17,7 @@ function createLink(url: string, onLoad: () => void) {
|
|
17
17
|
return element;
|
18
18
|
}
|
19
19
|
|
20
|
-
export const ShadowDOM: FC = ({ children }) => {
|
20
|
+
export const ShadowDOM: FC<PropsWithChildren> = ({ children }) => {
|
21
21
|
const [target, setTarget] = useState<Element | null>(null);
|
22
22
|
const [loaded, setLoaded] = useState(false);
|
23
23
|
const styleSheets = useStyleSheets();
|