@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.
@@ -0,0 +1,2 @@
1
+ import '@testing-library/jest-dom';
2
+ //# sourceMappingURL=container.test.d.ts.map
@@ -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":"AAAA,OAAO,EAAuB,EAAE,EAAE,MAAM,OAAO,CAAC;AAOhD,eAAO,MAAM,SAAS,EAAE,EA0CvB,CAAC"}
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
- var _a, _b;
8
- const container = (_a = document.getElementById('servicetitan-notifications')) !== null && _a !== void 0 ? _a : document.body.appendChild(createElement('div', { id: 'servicetitan-notifications' }));
9
- const [target, setTarget] = useState((_b = container.getElementsByClassName('ToastGroup')[0]) !== null && _b !== void 0 ? _b : null);
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 (!container.classList.contains('initializing') &&
12
- !container.classList.contains('initialized')) {
13
- render(_jsx(Toast.Group, { portal: container }), container, () => {
14
- container.classList.remove('initializing');
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
- let observer;
20
- if (!target) {
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,QAAQ,EAAE,SAAS,EAAM,MAAM,OAAO,CAAC;AAChD,OAAO,EAAE,MAAM,EAAE,YAAY,EAAE,MAAM,WAAW,CAAC;AAEjD,OAAO,EAAE,KAAK,EAAE,MAAM,6BAA6B,CAAC;AAEpD,OAAO,EAAE,aAAa,EAAE,MAAM,mBAAmB,CAAC;AAElD,MAAM,CAAC,MAAM,SAAS,GAAO,CAAC,EAAE,QAAQ,EAAE,EAAE,EAAE;;IAC1C,MAAM,SAAS,GACX,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,CAAC;IAE1F,MAAM,CAAC,MAAM,EAAE,SAAS,CAAC,GAAG,QAAQ,CAChC,MAAA,SAAS,CAAC,sBAAsB,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC,mCAAI,IAAI,CAC5D,CAAC;IAEF,SAAS,CAAC,GAAG,EAAE;QACX,IACI,CAAC,SAAS,CAAC,SAAS,CAAC,QAAQ,CAAC,cAAc,CAAC;YAC7C,CAAC,SAAS,CAAC,SAAS,CAAC,QAAQ,CAAC,aAAa,CAAC,EAC9C;YACE,MAAM,CAAC,KAAC,KAAK,CAAC,KAAK,IAAC,MAAM,EAAE,SAAS,GAAI,EAAE,SAAS,EAAE,GAAG,EAAE;gBACvD,SAAS,CAAC,SAAS,CAAC,MAAM,CAAC,cAAc,CAAC,CAAC;gBAC3C,SAAS,CAAC,SAAS,CAAC,GAAG,CAAC,aAAa,CAAC,CAAC;YAC3C,CAAC,CAAC,CAAC;YACH,SAAS,CAAC,SAAS,CAAC,GAAG,CAAC,cAAc,CAAC,CAAC;SAC3C;QAED,IAAI,QAA0B,CAAC;QAE/B,IAAI,CAAC,MAAM,EAAE;YACT,QAAQ,GAAG,IAAI,gBAAgB,CAAC,GAAG,EAAE;;gBACjC,IAAI,SAAS,CAAC,SAAS,CAAC,QAAQ,CAAC,aAAa,CAAC,EAAE;oBAC7C,SAAS,CAAC,MAAA,SAAS,CAAC,sBAAsB,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC,mCAAI,IAAI,CAAC,CAAC;oBACrE,QAAQ,CAAC,UAAU,EAAE,CAAC;iBACzB;YACL,CAAC,CAAC,CAAC;YAEH,QAAQ,CAAC,OAAO,CAAC,SAAS,EAAE;gBACxB,eAAe,EAAE,CAAC,OAAO,CAAC;aAC7B,CAAC,CAAC;SACN;QAED,OAAO,GAAG,EAAE;YACR,QAAQ,aAAR,QAAQ,uBAAR,QAAQ,CAAE,UAAU,EAAE,CAAC;QAC3B,CAAC,CAAC;IACN,CAAC,EAAE,CAAC,SAAS,EAAE,MAAM,CAAC,CAAC,CAAC;IAExB,OAAO,MAAM,CAAC,CAAC,CAAC,YAAY,CAAC,QAAQ,EAAE,MAAM,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC;AAC1D,CAAC,CAAC"}
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;AAE3B,OAAO,EAAY,UAAU,EAAE,MAAM,yBAAyB,CAAC;AAE/D,OAAO,EACH,gBAAgB,EAGnB,MAAM,0BAA0B,CAAC;AAelC,MAAM,WAAW,kBAAkB;IAC/B,UAAU,CAAC,EAAE,UAAU,CAAC,OAAO,CAAC,gBAAgB,CAAC,CAAC;CACrD;AAED,eAAO,MAAM,aAAa,EAAE,EAAE,CAAC,kBAAkB,CAWhD,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;AAmBrC,eAAO,MAAM,SAAS,EAAE,EAiCvB,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,EAAM,MAAM,OAAO,CAAC;AACrC,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,GAAO,CAAC,EAAE,QAAQ,EAAE,EAAE,EAAE;IAC1C,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"}
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": "25.9.0",
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": ">=13.2.1",
25
- "@servicetitan/log-service": "~21.6.0",
26
- "@servicetitan/react-ioc": "^21.6.0",
27
- "@servicetitan/web-components": "^21.6.0",
28
- "@types/react": "~17.0.38",
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.0",
34
- "react": "~17.0.2",
35
- "react-dom": "~17.0.2",
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": "~7.5.0",
46
- "react": "~17.0.2",
47
- "react-dom": "~17.0.2",
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": "72d081af4ab3deb72dab7d4fc93a4c2e473b726f"
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
- document.getElementById('servicetitan-notifications') ??
11
- document.body.appendChild(createElement('div', { id: 'servicetitan-notifications' }));
12
-
13
- const [target, setTarget] = useState<Element | null>(
14
- container.getElementsByClassName('ToastGroup')[0] ?? null
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
- !container.classList.contains('initializing') &&
20
- !container.classList.contains('initialized')
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
- return () => {
45
- observer?.disconnect();
46
- };
47
- }, [container, target]);
48
-
49
- return target ? createPortal(children, target) : null;
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();