@servicetitan/web-components 34.0.0 → 34.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/common.d.ts +2 -3
- package/dist/common.d.ts.map +1 -1
- package/dist/common.js +0 -4
- package/dist/common.js.map +1 -1
- package/dist/contexts/mfe-data-context.d.ts +2 -8
- package/dist/contexts/mfe-data-context.d.ts.map +1 -1
- package/dist/contexts/mfe-data-context.js.map +1 -1
- package/dist/contexts/tests/mfe-data-context.test.js +26 -0
- package/dist/contexts/tests/mfe-data-context.test.js.map +1 -1
- package/dist/loader.d.ts.map +1 -1
- package/dist/loader.js +6 -5
- package/dist/loader.js.map +1 -1
- package/dist/register.js +4 -4
- package/dist/register.js.map +1 -1
- package/dist/types.d.ts +1 -1
- package/dist/types.d.ts.map +1 -1
- package/dist/types.js.map +1 -1
- package/package.json +12 -12
- package/src/__tests__/loader.test.tsx +2 -3
- package/src/__tests__/register.test.tsx +74 -29
- package/src/common.ts +2 -7
- package/src/contexts/mfe-data-context.ts +2 -14
- package/src/contexts/tests/mfe-data-context.test.tsx +36 -0
- package/src/loader.tsx +17 -21
- package/src/register.tsx +3 -3
- package/src/types.ts +1 -1
package/dist/common.d.ts
CHANGED
|
@@ -22,8 +22,8 @@ export interface Entries {
|
|
|
22
22
|
exposedInstanceDependencies?: ExposedInstanceDependencies;
|
|
23
23
|
eventBus?: EventBus;
|
|
24
24
|
basename?: string;
|
|
25
|
-
onReady
|
|
26
|
-
onDispose
|
|
25
|
+
onReady?: () => void;
|
|
26
|
+
onDispose?: () => void;
|
|
27
27
|
}
|
|
28
28
|
export interface IWebComponent {
|
|
29
29
|
provide(entries: Entries): void;
|
|
@@ -43,6 +43,5 @@ export declare function getJson<T = any>(url: string, { retries, retryDelay, onR
|
|
|
43
43
|
headers: Headers;
|
|
44
44
|
url: string;
|
|
45
45
|
}>;
|
|
46
|
-
export declare function useCancelation(): AbortController;
|
|
47
46
|
export {};
|
|
48
47
|
//# sourceMappingURL=common.d.ts.map
|
package/dist/common.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"common.d.ts","sourceRoot":"","sources":["../src/common.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,SAAS,EAAE,MAAM,oCAAoC,CAAC;AACpE,OAAO,EAAE,GAAG,EAAE,MAAM,2BAA2B,CAAC;AAEhD,OAAO,EAAE,mBAAmB,EAAE,MAAM,6BAA6B,CAAC;
|
|
1
|
+
{"version":3,"file":"common.d.ts","sourceRoot":"","sources":["../src/common.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,SAAS,EAAE,MAAM,oCAAoC,CAAC;AACpE,OAAO,EAAE,GAAG,EAAE,MAAM,2BAA2B,CAAC;AAEhD,OAAO,EAAE,mBAAmB,EAAE,MAAM,6BAA6B,CAAC;AAClE,OAAO,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAC;AACvC,OAAO,EAAE,cAAc,EAAE,MAAM,mBAAmB,CAAC;AAEnD,MAAM,WAAW,2BAA2B;IACxC,YAAY,CAAC,EAAE;QAAE,OAAO,EAAE,MAAM,CAAC;QAAC,SAAS,CAAC,EAAE,SAAS,CAAA;KAAE,CAAC;CAC7D;AAED,eAAO,MAAM,cAAc,uDAAwC,CAAC;AACpE,eAAO,MAAM,0BAA0B,oEAEtC,CAAC;AACF,eAAO,MAAM,mCAAmC,4EAE/C,CAAC;AACF,eAAO,MAAM,sBAAsB,wDAAiD,CAAC;AACrF,eAAO,MAAM,iBAAiB,2DAA+C,CAAC;AAE9E,MAAM,WAAW,OAAO;IACpB,SAAS,CAAC,EAAE,SAAS,CAAC;IACtB,UAAU,CAAC,EAAE,GAAG,CAAC;IACjB,cAAc,CAAC,EAAE,cAAc,CAAC;IAChC,mBAAmB,CAAC,EAAE,mBAAmB,CAAC;IAC1C,2BAA2B,CAAC,EAAE,2BAA2B,CAAC;IAC1D,QAAQ,CAAC,EAAE,QAAQ,CAAC;IACpB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,OAAO,CAAC,EAAE,MAAM,IAAI,CAAC;IACrB,SAAS,CAAC,EAAE,MAAM,IAAI,CAAC;CAC1B;AAED,MAAM,WAAW,aAAa;IAC1B,OAAO,CAAC,OAAO,EAAE,OAAO,GAAG,IAAI,CAAC;CACnC;AAED,MAAM,WAAW,YAAY;IACzB,MAAM,EAAE,MAAM,CAAC;IACf,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;CAChB;AAED,UAAU,cAAe,SAAQ,WAAW;IACxC,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,cAAc,CAAC,CAAC,KAAK,EAAE,YAAY,GAAG,IAAI,CAAC;CAC9C;AAUD,wBAAsB,OAAO,CAAC,CAAC,GAAG,GAAG,EACjC,GAAG,EAAE,MAAM,EACX,EAAE,OAAW,EAAE,UAAiB,EAAE,cAAc,EAAE,GAAG,MAAM,EAAE,GAAE,cAAmB,GACnF,OAAO,CAAC;IAAE,IAAI,EAAE,CAAC,CAAC;IAAC,OAAO,EAAE,OAAO,CAAC;IAAC,GAAG,EAAE,MAAM,CAAA;CAAE,CAAC,CAiDrD"}
|
package/dist/common.js
CHANGED
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
import { symbolToken } from '@servicetitan/react-ioc';
|
|
2
|
-
import { useRef } from 'react';
|
|
3
2
|
export const BASENAME_TOKEN = symbolToken('BASENAME_TOKEN');
|
|
4
3
|
export const EXPOSED_DEPENDENCIES_TOKEN = symbolToken('EXPOSED_DEPENDENCIES_TOKEN');
|
|
5
4
|
export const EXPOSED_INSTANCE_DEPENDENCIES_TOKEN = symbolToken('EXPOSED_INSTANCE_DEPENDENCIES_TOKEN');
|
|
@@ -57,8 +56,5 @@ export async function getJson(url, { retries = 5, retryDelay = 1000, onRequestEr
|
|
|
57
56
|
url: (_response_url = response.url) !== null && _response_url !== void 0 ? _response_url : url
|
|
58
57
|
};
|
|
59
58
|
}
|
|
60
|
-
export function useCancelation() {
|
|
61
|
-
return useRef(new AbortController()).current;
|
|
62
|
-
}
|
|
63
59
|
|
|
64
60
|
//# sourceMappingURL=common.js.map
|
package/dist/common.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/common.ts"],"sourcesContent":["import { type LDService } from '@servicetitan/launchdarkly-service';\nimport { Log } from '@servicetitan/log-service';\nimport { symbolToken } from '@servicetitan/react-ioc';\nimport { ExposedDependencies } from '@servicetitan/startup-utils';\nimport {
|
|
1
|
+
{"version":3,"sources":["../src/common.ts"],"sourcesContent":["import { type LDService } from '@servicetitan/launchdarkly-service';\nimport { Log } from '@servicetitan/log-service';\nimport { symbolToken } from '@servicetitan/react-ioc';\nimport { ExposedDependencies } from '@servicetitan/startup-utils';\nimport { EventBus } from './event-bus';\nimport { HistoryManager } from './history-manager';\n\nexport interface ExposedInstanceDependencies {\n launchDarkly?: { version: string; ldService?: LDService };\n}\n\nexport const BASENAME_TOKEN = symbolToken<string>('BASENAME_TOKEN');\nexport const EXPOSED_DEPENDENCIES_TOKEN = symbolToken<ExposedDependencies>(\n 'EXPOSED_DEPENDENCIES_TOKEN'\n);\nexport const EXPOSED_INSTANCE_DEPENDENCIES_TOKEN = symbolToken<ExposedInstanceDependencies>(\n 'EXPOSED_INSTANCE_DEPENDENCIES_TOKEN'\n);\nexport const IS_WEB_COMPONENT_TOKEN = symbolToken<boolean>('IS_WEB_COMPONENT_TOKEN');\nexport const RENDER_ROOT_TOKEN = symbolToken<ShadowRoot>('RENDER_ROOT_TOKEN');\n\nexport interface Entries {\n ldService?: LDService;\n logService?: Log;\n historyManager?: HistoryManager;\n exposedDependencies?: ExposedDependencies;\n exposedInstanceDependencies?: ExposedInstanceDependencies;\n eventBus?: EventBus;\n basename?: string;\n onReady?: () => void;\n onDispose?: () => void;\n}\n\nexport interface IWebComponent {\n provide(entries: Entries): void;\n}\n\nexport interface GetJsonError {\n status: number;\n body: string;\n json: object;\n}\n\ninterface GetJsonOptions extends RequestInit {\n retries?: number;\n retryDelay?: number;\n onRequestError?(error: GetJsonError): void;\n}\n\nfunction createNetworkError(message: string) {\n const error = new Error(message);\n\n error.name = 'NetworkError';\n\n return error;\n}\n\nexport async function getJson<T = any>(\n url: string,\n { retries = 5, retryDelay = 1000, onRequestError, ...config }: GetJsonOptions = {}\n): Promise<{ data: T; headers: Headers; url: string }> {\n let response: Response;\n try {\n response = await fetch(url, config);\n } catch {\n if (retries > 0 && !config.signal?.aborted) {\n return new Promise((resolve, reject) => {\n const { signal } = config;\n\n const timeoutId = window.setTimeout(() => {\n getJson(url, {\n ...config,\n onRequestError,\n retries: retries - 1,\n retryDelay: retryDelay * 4,\n }).then(resolve, reject);\n }, retryDelay);\n\n const abortHandler = () => {\n window.clearTimeout(timeoutId);\n signal?.removeEventListener('abort', abortHandler);\n reject(signal?.reason);\n };\n\n signal?.addEventListener('abort', abortHandler);\n });\n }\n\n throw createNetworkError(`Failed to fetch: \"${url}\".`);\n }\n\n const responseJSON = await response.json().catch(() => ({}));\n\n if (!response.ok) {\n let message = `Requesting \"${url}\" failed with status code ${response.status}.`;\n\n try {\n message += ` Details: ${await response.text()}.`;\n } catch {} // eslint-disable-line no-empty\n\n onRequestError?.({\n status: response.status,\n json: responseJSON,\n body: await response.text().catch(() => ''),\n });\n throw createNetworkError(message);\n }\n\n return { data: responseJSON, headers: response.headers, url: response.url ?? url };\n}\n"],"names":["symbolToken","BASENAME_TOKEN","EXPOSED_DEPENDENCIES_TOKEN","EXPOSED_INSTANCE_DEPENDENCIES_TOKEN","IS_WEB_COMPONENT_TOKEN","RENDER_ROOT_TOKEN","createNetworkError","message","error","Error","name","getJson","url","retries","retryDelay","onRequestError","config","response","fetch","signal","aborted","Promise","resolve","reject","timeoutId","window","setTimeout","then","abortHandler","clearTimeout","removeEventListener","reason","addEventListener","responseJSON","json","catch","ok","status","text","body","data","headers"],"mappings":"AAEA,SAASA,WAAW,QAAQ,0BAA0B;AAStD,OAAO,MAAMC,iBAAiBD,YAAoB,kBAAkB;AACpE,OAAO,MAAME,6BAA6BF,YACtC,8BACF;AACF,OAAO,MAAMG,sCAAsCH,YAC/C,uCACF;AACF,OAAO,MAAMI,yBAAyBJ,YAAqB,0BAA0B;AACrF,OAAO,MAAMK,oBAAoBL,YAAwB,qBAAqB;AA8B9E,SAASM,mBAAmBC,OAAe;IACvC,MAAMC,QAAQ,IAAIC,MAAMF;IAExBC,MAAME,IAAI,GAAG;IAEb,OAAOF;AACX;AAEA,OAAO,eAAeG,QAClBC,GAAW,EACX,EAAEC,UAAU,CAAC,EAAEC,aAAa,IAAI,EAAEC,cAAc,EAAE,GAAGC,QAAwB,GAAG,CAAC,CAAC;QAiDrBC;IA/C7D,IAAIA;IACJ,IAAI;QACAA,WAAW,MAAMC,MAAMN,KAAKI;IAChC,EAAE,eAAM;YACgBA;QAApB,IAAIH,UAAU,KAAK,GAACG,iBAAAA,OAAOG,MAAM,cAAbH,qCAAAA,eAAeI,OAAO,GAAE;YACxC,OAAO,IAAIC,QAAQ,CAACC,SAASC;gBACzB,MAAM,EAAEJ,MAAM,EAAE,GAAGH;gBAEnB,MAAMQ,YAAYC,OAAOC,UAAU,CAAC;oBAChCf,QAAQC,KAAK;wBACT,GAAGI,MAAM;wBACTD;wBACAF,SAASA,UAAU;wBACnBC,YAAYA,aAAa;oBAC7B,GAAGa,IAAI,CAACL,SAASC;gBACrB,GAAGT;gBAEH,MAAMc,eAAe;oBACjBH,OAAOI,YAAY,CAACL;oBACpBL,mBAAAA,6BAAAA,OAAQW,mBAAmB,CAAC,SAASF;oBACrCL,OAAOJ,mBAAAA,6BAAAA,OAAQY,MAAM;gBACzB;gBAEAZ,mBAAAA,6BAAAA,OAAQa,gBAAgB,CAAC,SAASJ;YACtC;QACJ;QAEA,MAAMtB,mBAAmB,CAAC,kBAAkB,EAAEM,IAAI,EAAE,CAAC;IACzD;IAEA,MAAMqB,eAAe,MAAMhB,SAASiB,IAAI,GAAGC,KAAK,CAAC,IAAO,CAAA,CAAC,CAAA;IAEzD,IAAI,CAAClB,SAASmB,EAAE,EAAE;QACd,IAAI7B,UAAU,CAAC,YAAY,EAAEK,IAAI,0BAA0B,EAAEK,SAASoB,MAAM,CAAC,CAAC,CAAC;QAE/E,IAAI;YACA9B,WAAW,CAAC,UAAU,EAAE,MAAMU,SAASqB,IAAI,GAAG,CAAC,CAAC;QACpD,EAAE,eAAM,CAAC,EAAE,+BAA+B;QAE1CvB,2BAAAA,qCAAAA,eAAiB;YACbsB,QAAQpB,SAASoB,MAAM;YACvBH,MAAMD;YACNM,MAAM,MAAMtB,SAASqB,IAAI,GAAGH,KAAK,CAAC,IAAM;QAC5C;QACA,MAAM7B,mBAAmBC;IAC7B;IAEA,OAAO;QAAEiC,MAAMP;QAAcQ,SAASxB,SAASwB,OAAO;QAAE7B,GAAG,GAAEK,gBAAAA,SAASL,GAAG,cAAZK,2BAAAA,gBAAgBL;IAAI;AACrF"}
|
|
@@ -1,14 +1,8 @@
|
|
|
1
|
-
|
|
2
|
-
type
|
|
3
|
-
[key: string]: JSONPrimitive | JSON[] | JSON;
|
|
4
|
-
};
|
|
5
|
-
export type MFEContextData<T> = {
|
|
6
|
-
[P in keyof T]: T[P] extends JSONPrimitive ? T[P] : T[P] extends (infer U)[] ? MFEContextData<U>[] : T[P] extends JSON ? MFEContextData<T[P]> : never;
|
|
7
|
-
};
|
|
1
|
+
import { JSON, Serializable } from '../types';
|
|
2
|
+
export type MFEContextData<T> = Serializable<T>;
|
|
8
3
|
/**
|
|
9
4
|
* Context used to pass data from the host to the MFEs
|
|
10
5
|
*/
|
|
11
6
|
export declare const MFEDataContext: import("react").Context<JSON>;
|
|
12
7
|
export declare function useMFEDataContext<T extends MFEContextData<T>>(): T;
|
|
13
|
-
export {};
|
|
14
8
|
//# sourceMappingURL=mfe-data-context.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"mfe-data-context.d.ts","sourceRoot":"","sources":["../../src/contexts/mfe-data-context.ts"],"names":[],"mappings":"AAEA,
|
|
1
|
+
{"version":3,"file":"mfe-data-context.d.ts","sourceRoot":"","sources":["../../src/contexts/mfe-data-context.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,IAAI,EAAE,YAAY,EAAE,MAAM,UAAU,CAAC;AAE9C,MAAM,MAAM,cAAc,CAAC,CAAC,IAAI,YAAY,CAAC,CAAC,CAAC,CAAC;AAEhD;;GAEG;AACH,eAAO,MAAM,cAAc,+BAA0B,CAAC;AAEtD,wBAAgB,iBAAiB,CAAC,CAAC,SAAS,cAAc,CAAC,CAAC,CAAC,OAI5D"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/contexts/mfe-data-context.ts"],"sourcesContent":["import { createContext, useContext } from 'react';\n\
|
|
1
|
+
{"version":3,"sources":["../../src/contexts/mfe-data-context.ts"],"sourcesContent":["import { createContext, useContext } from 'react';\n\nimport { JSON, Serializable } from '../types';\n\nexport type MFEContextData<T> = Serializable<T>;\n\n/**\n * Context used to pass data from the host to the MFEs\n */\nexport const MFEDataContext = createContext<JSON>({});\n\nexport function useMFEDataContext<T extends MFEContextData<T>>() {\n const context = useContext(MFEDataContext) as T;\n\n return context;\n}\n"],"names":["createContext","useContext","MFEDataContext","useMFEDataContext","context"],"mappings":"AAAA,SAASA,aAAa,EAAEC,UAAU,QAAQ,QAAQ;AAMlD;;CAEC,GACD,OAAO,MAAMC,iBAAiBF,cAAoB,CAAC,GAAG;AAEtD,OAAO,SAASG;IACZ,MAAMC,UAAUH,WAAWC;IAE3B,OAAOE;AACX"}
|
|
@@ -29,6 +29,32 @@ describe(`[web-components] ${useMFEDataContext.name}`, ()=>{
|
|
|
29
29
|
expect(subject(Wrapper).result.current).toEqual({});
|
|
30
30
|
});
|
|
31
31
|
});
|
|
32
|
+
describe('type definitions', ()=>{
|
|
33
|
+
test('accepts properties typed as JSON', ()=>{
|
|
34
|
+
renderHook(()=>useMFEDataContext());
|
|
35
|
+
});
|
|
36
|
+
test('accepts properties typed as Record<string, JSON>', ()=>{
|
|
37
|
+
renderHook(()=>useMFEDataContext());
|
|
38
|
+
});
|
|
39
|
+
test('accepts primitive properties', ()=>{
|
|
40
|
+
renderHook(()=>useMFEDataContext());
|
|
41
|
+
});
|
|
42
|
+
test('accepts nested objects and arrays', ()=>{
|
|
43
|
+
renderHook(()=>useMFEDataContext());
|
|
44
|
+
});
|
|
45
|
+
test('rejects non-serializable properties', ()=>{
|
|
46
|
+
// @ts-expect-error Type '() => void' is not assignable to type 'never'.
|
|
47
|
+
renderHook(()=>useMFEDataContext());
|
|
48
|
+
// @ts-expect-error Type 'Date' is not assignable to type 'never'.
|
|
49
|
+
renderHook(()=>useMFEDataContext());
|
|
50
|
+
// @ts-expect-error Type 'Map<string, any>' is not assignable to type 'never'.
|
|
51
|
+
renderHook(()=>useMFEDataContext());
|
|
52
|
+
// @ts-expect-error Type 'Set<string>' is not assignable to type 'never'.
|
|
53
|
+
renderHook(()=>useMFEDataContext());
|
|
54
|
+
// @ts-expect-error Type 'symbol' is not assignable to type 'never'.
|
|
55
|
+
renderHook(()=>useMFEDataContext());
|
|
56
|
+
});
|
|
57
|
+
});
|
|
32
58
|
});
|
|
33
59
|
|
|
34
60
|
//# sourceMappingURL=mfe-data-context.test.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../src/contexts/tests/mfe-data-context.test.tsx"],"sourcesContent":["import { renderHook } from '@testing-library/react';\nimport { FC, PropsWithChildren } from 'react';\nimport { MFEDataContext, useMFEDataContext } from '../mfe-data-context';\n\ndescribe(`[web-components] ${useMFEDataContext.name}`, () => {\n const subject = (wrapper?: FC) => renderHook(() => useMFEDataContext(), { wrapper });\n\n describe('when the MFEDataContext is provided by a parent', () => {\n const data = { foo: 'bar' };\n const Wrapper: FC<PropsWithChildren> = ({ children }) => {\n return <MFEDataContext.Provider value={data}>{children}</MFEDataContext.Provider>;\n };\n\n test('returns the context', () => {\n expect(subject(Wrapper).result.current).toEqual(data);\n });\n });\n\n describe('when the MFEDataContext is not provided by a parent', () => {\n const Wrapper: FC<PropsWithChildren> = ({ children }) => {\n return <div>{children}</div>;\n };\n\n test('returns an empty object', () => {\n expect(subject(Wrapper).result.current).toEqual({});\n });\n });\n});\n"],"names":["renderHook","MFEDataContext","useMFEDataContext","describe","name","subject","wrapper","data","foo","Wrapper","children","Provider","value","test","expect","result","current","toEqual","div"],"mappings":";AAAA,SAASA,UAAU,QAAQ,yBAAyB;
|
|
1
|
+
{"version":3,"sources":["../../../src/contexts/tests/mfe-data-context.test.tsx"],"sourcesContent":["import { renderHook } from '@testing-library/react';\nimport { FC, PropsWithChildren } from 'react';\nimport { JSON } from '../../types';\nimport { MFEDataContext, useMFEDataContext } from '../mfe-data-context';\n\ndescribe(`[web-components] ${useMFEDataContext.name}`, () => {\n const subject = (wrapper?: FC) => renderHook(() => useMFEDataContext(), { wrapper });\n\n describe('when the MFEDataContext is provided by a parent', () => {\n const data = { foo: 'bar' };\n const Wrapper: FC<PropsWithChildren> = ({ children }) => {\n return <MFEDataContext.Provider value={data}>{children}</MFEDataContext.Provider>;\n };\n\n test('returns the context', () => {\n expect(subject(Wrapper).result.current).toEqual(data);\n });\n });\n\n describe('when the MFEDataContext is not provided by a parent', () => {\n const Wrapper: FC<PropsWithChildren> = ({ children }) => {\n return <div>{children}</div>;\n };\n\n test('returns an empty object', () => {\n expect(subject(Wrapper).result.current).toEqual({});\n });\n });\n\n describe('type definitions', () => {\n test('accepts properties typed as JSON', () => {\n renderHook(() => useMFEDataContext<{ data: JSON }>());\n });\n\n test('accepts properties typed as Record<string, JSON>', () => {\n renderHook(() => useMFEDataContext<{ metadata: Record<string, JSON> }>());\n });\n\n test('accepts primitive properties', () => {\n renderHook(() => useMFEDataContext<{ name: string; count: number; active: boolean }>());\n });\n\n test('accepts nested objects and arrays', () => {\n renderHook(() => useMFEDataContext<{ nested: { value: number }; list: string[] }>());\n });\n\n test('rejects non-serializable properties', () => {\n // @ts-expect-error Type '() => void' is not assignable to type 'never'.\n renderHook(() => useMFEDataContext<{ callback: () => void }>());\n\n // @ts-expect-error Type 'Date' is not assignable to type 'never'.\n renderHook(() => useMFEDataContext<{ created: Date }>());\n\n // @ts-expect-error Type 'Map<string, any>' is not assignable to type 'never'.\n renderHook(() => useMFEDataContext<{ lookup: Map<string, any> }>());\n\n // @ts-expect-error Type 'Set<string>' is not assignable to type 'never'.\n renderHook(() => useMFEDataContext<{ tags: Set<string> }>());\n\n // @ts-expect-error Type 'symbol' is not assignable to type 'never'.\n renderHook(() => useMFEDataContext<{ id: symbol }>());\n });\n });\n});\n"],"names":["renderHook","MFEDataContext","useMFEDataContext","describe","name","subject","wrapper","data","foo","Wrapper","children","Provider","value","test","expect","result","current","toEqual","div"],"mappings":";AAAA,SAASA,UAAU,QAAQ,yBAAyB;AAGpD,SAASC,cAAc,EAAEC,iBAAiB,QAAQ,sBAAsB;AAExEC,SAAS,CAAC,iBAAiB,EAAED,kBAAkBE,IAAI,EAAE,EAAE;IACnD,MAAMC,UAAU,CAACC,UAAiBN,WAAW,IAAME,qBAAqB;YAAEI;QAAQ;IAElFH,SAAS,mDAAmD;QACxD,MAAMI,OAAO;YAAEC,KAAK;QAAM;QAC1B,MAAMC,UAAiC,CAAC,EAAEC,QAAQ,EAAE;YAChD,qBAAO,KAACT,eAAeU,QAAQ;gBAACC,OAAOL;0BAAOG;;QAClD;QAEAG,KAAK,uBAAuB;YACxBC,OAAOT,QAAQI,SAASM,MAAM,CAACC,OAAO,EAAEC,OAAO,CAACV;QACpD;IACJ;IAEAJ,SAAS,uDAAuD;QAC5D,MAAMM,UAAiC,CAAC,EAAEC,QAAQ,EAAE;YAChD,qBAAO,KAACQ;0BAAKR;;QACjB;QAEAG,KAAK,2BAA2B;YAC5BC,OAAOT,QAAQI,SAASM,MAAM,CAACC,OAAO,EAAEC,OAAO,CAAC,CAAC;QACrD;IACJ;IAEAd,SAAS,oBAAoB;QACzBU,KAAK,oCAAoC;YACrCb,WAAW,IAAME;QACrB;QAEAW,KAAK,oDAAoD;YACrDb,WAAW,IAAME;QACrB;QAEAW,KAAK,gCAAgC;YACjCb,WAAW,IAAME;QACrB;QAEAW,KAAK,qCAAqC;YACtCb,WAAW,IAAME;QACrB;QAEAW,KAAK,uCAAuC;YACxC,wEAAwE;YACxEb,WAAW,IAAME;YAEjB,kEAAkE;YAClEF,WAAW,IAAME;YAEjB,8EAA8E;YAC9EF,WAAW,IAAME;YAEjB,yEAAyE;YACzEF,WAAW,IAAME;YAEjB,oEAAoE;YACpEF,WAAW,IAAME;QACrB;IACJ;AACJ"}
|
package/dist/loader.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"loader.d.ts","sourceRoot":"","sources":["../src/loader.tsx"],"names":[],"mappings":"AAKA,OAAO,EAEH,SAAS,EACT,GAAG,EAQN,MAAM,OAAO,CAAC;AACf,OAAO,EAIH,YAAY,
|
|
1
|
+
{"version":3,"file":"loader.d.ts","sourceRoot":"","sources":["../src/loader.tsx"],"names":[],"mappings":"AAKA,OAAO,EAEH,SAAS,EACT,GAAG,EAQN,MAAM,OAAO,CAAC;AACf,OAAO,EAIH,YAAY,EACf,MAAM,UAAU,CAAC;AAClB,OAAO,EAAE,cAAc,EAAE,MAAM,6BAA6B,CAAC;AAE7D,OAAO,EAAmB,QAAQ,EAAE,MAAM,aAAa,CAAC;AAWxD,MAAM,MAAM,SAAS,GAAG,QAAQ,CAAC;AAEjC,MAAM,MAAM,YAAY,GAAG,WAAW,CAAC,SAAS,CAAC,GAAG,IAAI,CAAC;AAEzD,MAAM,WAAW,uBAAuB,CAAC,CAAC,GAAG,EAAE;IAC3C,GAAG,EAAE,MAAM,CAAC;IACZ,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,uHAAuH;IACvH,IAAI,CAAC,EAAE,cAAc,CAAC,CAAC,CAAC,CAAC;IACzB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,eAAe,CAAC,EAAE,YAAY,CAAC;IAC/B,sBAAsB,CAAC,EAAE,OAAO,CAAC;IACjC,aAAa,CAAC,EAAE,YAAY,CAAC;IAC7B,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,KAAK,CAAC,EAAE,OAAO,GAAG,MAAM,CAAC;IACzB,cAAc,CAAC,CAAC,KAAK,EAAE,YAAY,GAAG,OAAO,CAAC;CACjD;AAED,MAAM,MAAM,WAAW,CAAC,CAAC,IAAI,IAAI,CAC7B,uBAAuB,CAAC,CAAC,CAAC,EACxB,KAAK,GACL,aAAa,GACb,MAAM,GACN,UAAU,GACV,iBAAiB,GACjB,wBAAwB,GACxB,eAAe,GACf,WAAW,GACX,SAAS,GACT,OAAO,GACP,gBAAgB,CACrB,CAAC;AAEF,MAAM,MAAM,eAAe,GAAG,IAAI,CAAC,uBAAuB,EAAE,MAAM,GAAG,WAAW,CAAC,GAAG;IAChF,eAAe,EAAE,MAAM,GAAG,CAAC,OAAO,CAAC;CACtC,CAAC;AAEF,QAAA,MAAM,kBAAkB,GAAI,CAAC,EAAG,OAAO,uBAAuB,CAAC,CAAC,CAAC,EAAE,KAAK,GAAG,CAAC,SAAS,CAAC,4CAsErF,CAAC;AAEF,eAAO,MAAM,MAAM,EAAqC,CAAC,CAAC,GAAG,EAAE,EAC3D,KAAK,EAAE,WAAW,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,GAAG;IAAE,GAAG,CAAC,EAAE,GAAG,CAAC,SAAS,CAAC,CAAA;CAAE,KACxD,UAAU,CAAC,OAAO,kBAAkB,CAAC,CAAC"}
|
package/dist/loader.js
CHANGED
|
@@ -3,7 +3,7 @@ import { ErrorBoundary } from '@servicetitan/error-boundary';
|
|
|
3
3
|
import { Log } from '@servicetitan/log-service';
|
|
4
4
|
import { useOptionalDependencies } from '@servicetitan/react-ioc';
|
|
5
5
|
import { Suspense, forwardRef, lazy, useEffect, useImperativeHandle, useMemo, useRef } from 'react';
|
|
6
|
-
import { EXPOSED_DEPENDENCIES_TOKEN, EXPOSED_INSTANCE_DEPENDENCIES_TOKEN
|
|
6
|
+
import { EXPOSED_DEPENDENCIES_TOKEN, EXPOSED_INSTANCE_DEPENDENCIES_TOKEN } from './common';
|
|
7
7
|
import { Delayed } from './delayed';
|
|
8
8
|
import { EVENT_BUS_TOKEN, EventBus } from './event-bus';
|
|
9
9
|
import { EXPOSED_DEPENDENCIES, EXPOSED_INSTANCE_DEPENDENCIES } from './globals';
|
|
@@ -16,7 +16,6 @@ const UnrestrictedLoader = (props, ref)=>{
|
|
|
16
16
|
const [logService, exposedDependencies = EXPOSED_DEPENDENCIES, eventBus = bus] = useOptionalDependencies(Log, EXPOSED_DEPENDENCIES_TOKEN, EVENT_BUS_TOKEN);
|
|
17
17
|
let [exposedInstanceDependencies = EXPOSED_INSTANCE_DEPENDENCIES] = useOptionalDependencies(EXPOSED_INSTANCE_DEPENDENCIES_TOKEN);
|
|
18
18
|
const [ldService] = useOptionalDependencies((_getLDServiceToken = getLDServiceToken()) !== null && _getLDServiceToken !== void 0 ? _getLDServiceToken : Symbol());
|
|
19
|
-
const cancelation = useCancelation();
|
|
20
19
|
const LoadingFallback = useMemo(()=>{
|
|
21
20
|
const message = `Loading${isLocalHost(src) ? ` ${src}` : ''}...`;
|
|
22
21
|
return getFallback(loadingFallback, message, {
|
|
@@ -38,7 +37,9 @@ const UnrestrictedLoader = (props, ref)=>{
|
|
|
38
37
|
exposedInstanceDependencies,
|
|
39
38
|
ldService
|
|
40
39
|
]);
|
|
41
|
-
const Loader = useMemo(()=>
|
|
40
|
+
const Loader = useMemo(()=>{
|
|
41
|
+
const cancelation = new AbortController();
|
|
42
|
+
return lazyLoader({
|
|
42
43
|
basename,
|
|
43
44
|
cache,
|
|
44
45
|
cancelation,
|
|
@@ -51,10 +52,10 @@ const UnrestrictedLoader = (props, ref)=>{
|
|
|
51
52
|
onRequestError,
|
|
52
53
|
retries,
|
|
53
54
|
src
|
|
54
|
-
})
|
|
55
|
+
});
|
|
56
|
+
}, [
|
|
55
57
|
basename,
|
|
56
58
|
cache,
|
|
57
|
-
cancelation,
|
|
58
59
|
exposedDependencies,
|
|
59
60
|
exposedInstanceDependencies,
|
|
60
61
|
eventBus,
|
package/dist/loader.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/loader.tsx"],"sourcesContent":["import { ErrorBoundary } from '@servicetitan/error-boundary';\nimport { type LDService } from '@servicetitan/launchdarkly-service';\nimport { Log } from '@servicetitan/log-service';\nimport { useOptionalDependencies } from '@servicetitan/react-ioc';\nimport { ExposedDependencies } from '@servicetitan/startup-utils';\nimport {\n ReactElement,\n ReactNode,\n Ref,\n Suspense,\n forwardRef,\n lazy,\n useEffect,\n useImperativeHandle,\n useMemo,\n useRef,\n} from 'react';\nimport {\n EXPOSED_DEPENDENCIES_TOKEN,\n EXPOSED_INSTANCE_DEPENDENCIES_TOKEN,\n ExposedInstanceDependencies,\n GetJsonError,\n useCancelation,\n} from './common';\nimport { MFEContextData } from './contexts/mfe-data-context';\nimport { Delayed } from './delayed';\nimport { EVENT_BUS_TOKEN, EventBus } from './event-bus';\nimport { EXPOSED_DEPENDENCIES, EXPOSED_INSTANCE_DEPENDENCIES } from './globals';\nimport {\n BundleInfo,\n getBundleInfo,\n getLDServiceToken,\n loadScripts,\n validateBundleInfo,\n webComponent,\n} from './utils';\n\nexport type LoaderRef = EventBus;\n\nexport type FallbackNode = NonNullable<ReactNode> | null;\n\nexport interface UnrestrictedLoaderProps<T = {}> {\n src: string;\n fallbackSrc?: string;\n /** Values in the object will be stringified and then parsed before being delivered to the MFE via props or context. */\n data?: MFEContextData<T>;\n basename?: string;\n loadingFallback?: FallbackNode;\n loadingFallbackDelayed?: boolean;\n errorFallback?: FallbackNode;\n className?: string;\n retries?: number;\n isHeadless?: boolean;\n cache?: boolean | number;\n onRequestError?(error: GetJsonError): boolean;\n}\n\nexport type LoaderProps<T> = Pick<\n UnrestrictedLoaderProps<T>,\n | 'src'\n | 'fallbackSrc'\n | 'data'\n | 'basename'\n | 'loadingFallback'\n | 'loadingFallbackDelayed'\n | 'errorFallback'\n | 'className'\n | 'retries'\n | 'cache'\n | 'onRequestError'\n>;\n\nexport type LoaderDataProps = Pick<UnrestrictedLoaderProps, 'data' | 'className'> & {\n LoadingFallback: () => JSX.Element;\n};\n\nconst UnrestrictedLoader = <T,>(props: UnrestrictedLoaderProps<T>, ref: Ref<LoaderRef>) => {\n const { cache = -1, basename, fallbackSrc, isHeadless, onRequestError, retries, src } = props;\n const { loadingFallback, loadingFallbackDelayed = true } = props;\n\n const bus = useEventBus();\n const [logService, exposedDependencies = EXPOSED_DEPENDENCIES, eventBus = bus] =\n useOptionalDependencies(Log, EXPOSED_DEPENDENCIES_TOKEN, EVENT_BUS_TOKEN);\n let [exposedInstanceDependencies = EXPOSED_INSTANCE_DEPENDENCIES] = useOptionalDependencies(\n EXPOSED_INSTANCE_DEPENDENCIES_TOKEN\n );\n const [ldService] = useOptionalDependencies(getLDServiceToken() ?? Symbol());\n const cancelation = useCancelation();\n\n const LoadingFallback = useMemo(() => {\n const message = `Loading${isLocalHost(src) ? ` ${src}` : ''}...`;\n return getFallback(loadingFallback, message, { delayed: loadingFallbackDelayed });\n }, [loadingFallback, loadingFallbackDelayed, src]);\n\n const ErrorFallback = useMemo(() => {\n const message = `Something went wrong${isLocalHost(src) ? ` loading ${src}` : ''}`;\n return getFallback(props.errorFallback, message);\n }, [props.errorFallback, src]);\n\n exposedInstanceDependencies = useMemo(\n () => ensureLDService(exposedInstanceDependencies, ldService),\n [exposedInstanceDependencies, ldService]\n );\n\n const Loader = useMemo(\n () =>\n lazyLoader({\n basename,\n cache,\n cancelation,\n exposedDependencies,\n exposedInstanceDependencies,\n eventBus,\n fallbackSrc,\n isHeadless,\n logService,\n onRequestError,\n retries,\n src,\n }),\n [\n basename,\n cache,\n cancelation,\n exposedDependencies,\n exposedInstanceDependencies,\n eventBus,\n fallbackSrc,\n isHeadless,\n logService,\n onRequestError,\n retries,\n src,\n ]\n );\n\n useImperativeHandle(ref, () => eventBus, [eventBus]);\n\n return (\n <ErrorBoundary moduleName={src} fallback={ErrorFallback}>\n <Suspense fallback={<LoadingFallback />}>\n <Loader\n data={props.data ?? {}}\n className={props.className}\n LoadingFallback={LoadingFallback}\n />\n </Suspense>\n </ErrorBoundary>\n );\n};\n\nexport const Loader = forwardRef(UnrestrictedLoader) as <T = {}>(\n props: LoaderProps<NoInfer<T>> & { ref?: Ref<LoaderRef> }\n) => ReturnType<typeof UnrestrictedLoader>;\n\ntype LazyLoaderProps = UnrestrictedLoaderProps<any> & {\n cancelation: AbortController;\n exposedDependencies?: ExposedDependencies;\n exposedInstanceDependencies?: ExposedInstanceDependencies;\n eventBus: EventBus;\n logService?: Log;\n cache: Required<UnrestrictedLoaderProps<any>>['cache'];\n};\n\nfunction lazyLoader(props: LazyLoaderProps) {\n const { cancelation } = props;\n\n const LazyWebComponent = lazyWebComponent(props);\n\n return (props: LoaderDataProps) => {\n useEffect(() => {\n return () => {\n cancelation.abort();\n };\n }, []);\n\n return (\n <LazyWebComponent\n data={props.data}\n className={props.className}\n LoadingFallback={props.LoadingFallback}\n />\n );\n };\n}\n\nfunction lazyWebComponent(props: LazyLoaderProps) {\n const {\n basename,\n cache,\n cancelation,\n exposedDependencies,\n exposedInstanceDependencies,\n eventBus,\n fallbackSrc,\n isHeadless,\n logService,\n onRequestError,\n retries,\n src,\n } = props;\n\n return lazy<(_: LoaderDataProps) => JSX.Element | null>(async () => {\n let bundleInfo: BundleInfo;\n try {\n bundleInfo = await getBundleInfo({\n cache,\n mainPackageUrl: src,\n fallbackPackageUrl: fallbackSrc,\n isHeadless,\n exposedDependencies,\n exposedInstanceDependencies,\n signal: cancelation.signal,\n retries,\n onRequestError,\n });\n } catch (e) {\n if (cancelation.signal.aborted) {\n return {\n default: () => null,\n };\n }\n\n throw e;\n }\n\n validateBundleInfo(bundleInfo, {\n exposedDependencies,\n exposedInstanceDependencies,\n logService,\n packageUrl: src,\n });\n\n await loadScripts(bundleInfo);\n\n const ldService = bundleInfo.mfeHasCompatibleLaunchDarklyVersion\n ? exposedInstanceDependencies?.launchDarkly?.ldService\n : undefined;\n\n return {\n default: webComponent({\n basename,\n bundleInfo,\n eventBus,\n exposedDependencies,\n exposedInstanceDependencies,\n ldService,\n logService,\n }),\n };\n });\n}\n\nfunction getFallback(\n node: FallbackNode | undefined,\n message: string,\n { delayed = false }: { delayed?: boolean } = {}\n) {\n const fallbackNode = node !== undefined ? (node as ReactElement) : <h2>{message}</h2>;\n return delayed ? () => <Delayed>{fallbackNode}</Delayed> : () => fallbackNode;\n}\n\nfunction isLocalHost(source: string) {\n return ['localhost', '127.0.0.1'].some(host => source.indexOf(host) >= 0);\n}\n\nfunction ensureLDService(\n exposedInstanceDependencies?: ExposedInstanceDependencies,\n ldService?: LDService\n) {\n const launchDarkly = exposedInstanceDependencies?.launchDarkly;\n if (launchDarkly?.version && !launchDarkly.ldService && ldService) {\n return { ...exposedInstanceDependencies, launchDarkly: { ...launchDarkly, ldService } };\n }\n return exposedInstanceDependencies;\n}\n\nfunction useEventBus() {\n return useRef(new EventBus()).current;\n}\n"],"names":["ErrorBoundary","Log","useOptionalDependencies","Suspense","forwardRef","lazy","useEffect","useImperativeHandle","useMemo","useRef","EXPOSED_DEPENDENCIES_TOKEN","EXPOSED_INSTANCE_DEPENDENCIES_TOKEN","useCancelation","Delayed","EVENT_BUS_TOKEN","EventBus","EXPOSED_DEPENDENCIES","EXPOSED_INSTANCE_DEPENDENCIES","getBundleInfo","getLDServiceToken","loadScripts","validateBundleInfo","webComponent","UnrestrictedLoader","props","ref","cache","basename","fallbackSrc","isHeadless","onRequestError","retries","src","loadingFallback","loadingFallbackDelayed","bus","useEventBus","logService","exposedDependencies","eventBus","exposedInstanceDependencies","ldService","Symbol","cancelation","LoadingFallback","message","isLocalHost","getFallback","delayed","ErrorFallback","errorFallback","ensureLDService","Loader","lazyLoader","moduleName","fallback","data","className","LazyWebComponent","lazyWebComponent","abort","bundleInfo","mainPackageUrl","fallbackPackageUrl","signal","e","aborted","default","packageUrl","mfeHasCompatibleLaunchDarklyVersion","launchDarkly","undefined","node","fallbackNode","h2","source","some","host","indexOf","version","current"],"mappings":"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"}
|
|
1
|
+
{"version":3,"sources":["../src/loader.tsx"],"sourcesContent":["import { ErrorBoundary } from '@servicetitan/error-boundary';\nimport { type LDService } from '@servicetitan/launchdarkly-service';\nimport { Log } from '@servicetitan/log-service';\nimport { useOptionalDependencies } from '@servicetitan/react-ioc';\nimport { ExposedDependencies } from '@servicetitan/startup-utils';\nimport {\n ReactElement,\n ReactNode,\n Ref,\n Suspense,\n forwardRef,\n lazy,\n useEffect,\n useImperativeHandle,\n useMemo,\n useRef,\n} from 'react';\nimport {\n EXPOSED_DEPENDENCIES_TOKEN,\n EXPOSED_INSTANCE_DEPENDENCIES_TOKEN,\n ExposedInstanceDependencies,\n GetJsonError,\n} from './common';\nimport { MFEContextData } from './contexts/mfe-data-context';\nimport { Delayed } from './delayed';\nimport { EVENT_BUS_TOKEN, EventBus } from './event-bus';\nimport { EXPOSED_DEPENDENCIES, EXPOSED_INSTANCE_DEPENDENCIES } from './globals';\nimport {\n BundleInfo,\n getBundleInfo,\n getLDServiceToken,\n loadScripts,\n validateBundleInfo,\n webComponent,\n} from './utils';\n\nexport type LoaderRef = EventBus;\n\nexport type FallbackNode = NonNullable<ReactNode> | null;\n\nexport interface UnrestrictedLoaderProps<T = {}> {\n src: string;\n fallbackSrc?: string;\n /** Values in the object will be stringified and then parsed before being delivered to the MFE via props or context. */\n data?: MFEContextData<T>;\n basename?: string;\n loadingFallback?: FallbackNode;\n loadingFallbackDelayed?: boolean;\n errorFallback?: FallbackNode;\n className?: string;\n retries?: number;\n isHeadless?: boolean;\n cache?: boolean | number;\n onRequestError?(error: GetJsonError): boolean;\n}\n\nexport type LoaderProps<T> = Pick<\n UnrestrictedLoaderProps<T>,\n | 'src'\n | 'fallbackSrc'\n | 'data'\n | 'basename'\n | 'loadingFallback'\n | 'loadingFallbackDelayed'\n | 'errorFallback'\n | 'className'\n | 'retries'\n | 'cache'\n | 'onRequestError'\n>;\n\nexport type LoaderDataProps = Pick<UnrestrictedLoaderProps, 'data' | 'className'> & {\n LoadingFallback: () => JSX.Element;\n};\n\nconst UnrestrictedLoader = <T,>(props: UnrestrictedLoaderProps<T>, ref: Ref<LoaderRef>) => {\n const { cache = -1, basename, fallbackSrc, isHeadless, onRequestError, retries, src } = props;\n const { loadingFallback, loadingFallbackDelayed = true } = props;\n\n const bus = useEventBus();\n const [logService, exposedDependencies = EXPOSED_DEPENDENCIES, eventBus = bus] =\n useOptionalDependencies(Log, EXPOSED_DEPENDENCIES_TOKEN, EVENT_BUS_TOKEN);\n let [exposedInstanceDependencies = EXPOSED_INSTANCE_DEPENDENCIES] = useOptionalDependencies(\n EXPOSED_INSTANCE_DEPENDENCIES_TOKEN\n );\n const [ldService] = useOptionalDependencies(getLDServiceToken() ?? Symbol());\n\n const LoadingFallback = useMemo(() => {\n const message = `Loading${isLocalHost(src) ? ` ${src}` : ''}...`;\n return getFallback(loadingFallback, message, { delayed: loadingFallbackDelayed });\n }, [loadingFallback, loadingFallbackDelayed, src]);\n\n const ErrorFallback = useMemo(() => {\n const message = `Something went wrong${isLocalHost(src) ? ` loading ${src}` : ''}`;\n return getFallback(props.errorFallback, message);\n }, [props.errorFallback, src]);\n\n exposedInstanceDependencies = useMemo(\n () => ensureLDService(exposedInstanceDependencies, ldService),\n [exposedInstanceDependencies, ldService]\n );\n\n const Loader = useMemo(() => {\n const cancelation = new AbortController();\n return lazyLoader({\n basename,\n cache,\n cancelation,\n exposedDependencies,\n exposedInstanceDependencies,\n eventBus,\n fallbackSrc,\n isHeadless,\n logService,\n onRequestError,\n retries,\n src,\n });\n }, [\n basename,\n cache,\n exposedDependencies,\n exposedInstanceDependencies,\n eventBus,\n fallbackSrc,\n isHeadless,\n logService,\n onRequestError,\n retries,\n src,\n ]);\n\n useImperativeHandle(ref, () => eventBus, [eventBus]);\n\n return (\n <ErrorBoundary moduleName={src} fallback={ErrorFallback}>\n <Suspense fallback={<LoadingFallback />}>\n <Loader\n data={props.data ?? {}}\n className={props.className}\n LoadingFallback={LoadingFallback}\n />\n </Suspense>\n </ErrorBoundary>\n );\n};\n\nexport const Loader = forwardRef(UnrestrictedLoader) as <T = {}>(\n props: LoaderProps<NoInfer<T>> & { ref?: Ref<LoaderRef> }\n) => ReturnType<typeof UnrestrictedLoader>;\n\ntype LazyLoaderProps = UnrestrictedLoaderProps<any> & {\n cancelation: AbortController;\n exposedDependencies?: ExposedDependencies;\n exposedInstanceDependencies?: ExposedInstanceDependencies;\n eventBus: EventBus;\n logService?: Log;\n cache: Required<UnrestrictedLoaderProps<any>>['cache'];\n};\n\nfunction lazyLoader(props: LazyLoaderProps) {\n const { cancelation } = props;\n\n const LazyWebComponent = lazyWebComponent(props);\n\n return (props: LoaderDataProps) => {\n useEffect(() => {\n return () => {\n cancelation.abort();\n };\n }, []);\n\n return (\n <LazyWebComponent\n data={props.data}\n className={props.className}\n LoadingFallback={props.LoadingFallback}\n />\n );\n };\n}\n\nfunction lazyWebComponent(props: LazyLoaderProps) {\n const {\n basename,\n cache,\n cancelation,\n exposedDependencies,\n exposedInstanceDependencies,\n eventBus,\n fallbackSrc,\n isHeadless,\n logService,\n onRequestError,\n retries,\n src,\n } = props;\n\n return lazy<(_: LoaderDataProps) => JSX.Element | null>(async () => {\n let bundleInfo: BundleInfo;\n try {\n bundleInfo = await getBundleInfo({\n cache,\n mainPackageUrl: src,\n fallbackPackageUrl: fallbackSrc,\n isHeadless,\n exposedDependencies,\n exposedInstanceDependencies,\n signal: cancelation.signal,\n retries,\n onRequestError,\n });\n } catch (e) {\n if (cancelation.signal.aborted) {\n return {\n default: () => null,\n };\n }\n\n throw e;\n }\n\n validateBundleInfo(bundleInfo, {\n exposedDependencies,\n exposedInstanceDependencies,\n logService,\n packageUrl: src,\n });\n\n await loadScripts(bundleInfo);\n\n const ldService = bundleInfo.mfeHasCompatibleLaunchDarklyVersion\n ? exposedInstanceDependencies?.launchDarkly?.ldService\n : undefined;\n\n return {\n default: webComponent({\n basename,\n bundleInfo,\n eventBus,\n exposedDependencies,\n exposedInstanceDependencies,\n ldService,\n logService,\n }),\n };\n });\n}\n\nfunction getFallback(\n node: FallbackNode | undefined,\n message: string,\n { delayed = false }: { delayed?: boolean } = {}\n) {\n const fallbackNode = node !== undefined ? (node as ReactElement) : <h2>{message}</h2>;\n return delayed ? () => <Delayed>{fallbackNode}</Delayed> : () => fallbackNode;\n}\n\nfunction isLocalHost(source: string) {\n return ['localhost', '127.0.0.1'].some(host => source.indexOf(host) >= 0);\n}\n\nfunction ensureLDService(\n exposedInstanceDependencies?: ExposedInstanceDependencies,\n ldService?: LDService\n) {\n const launchDarkly = exposedInstanceDependencies?.launchDarkly;\n if (launchDarkly?.version && !launchDarkly.ldService && ldService) {\n return { ...exposedInstanceDependencies, launchDarkly: { ...launchDarkly, ldService } };\n }\n return exposedInstanceDependencies;\n}\n\nfunction useEventBus() {\n return useRef(new EventBus()).current;\n}\n"],"names":["ErrorBoundary","Log","useOptionalDependencies","Suspense","forwardRef","lazy","useEffect","useImperativeHandle","useMemo","useRef","EXPOSED_DEPENDENCIES_TOKEN","EXPOSED_INSTANCE_DEPENDENCIES_TOKEN","Delayed","EVENT_BUS_TOKEN","EventBus","EXPOSED_DEPENDENCIES","EXPOSED_INSTANCE_DEPENDENCIES","getBundleInfo","getLDServiceToken","loadScripts","validateBundleInfo","webComponent","UnrestrictedLoader","props","ref","cache","basename","fallbackSrc","isHeadless","onRequestError","retries","src","loadingFallback","loadingFallbackDelayed","bus","useEventBus","logService","exposedDependencies","eventBus","exposedInstanceDependencies","ldService","Symbol","LoadingFallback","message","isLocalHost","getFallback","delayed","ErrorFallback","errorFallback","ensureLDService","Loader","cancelation","AbortController","lazyLoader","moduleName","fallback","data","className","LazyWebComponent","lazyWebComponent","abort","bundleInfo","mainPackageUrl","fallbackPackageUrl","signal","e","aborted","default","packageUrl","mfeHasCompatibleLaunchDarklyVersion","launchDarkly","undefined","node","fallbackNode","h2","source","some","host","indexOf","version","current"],"mappings":"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"}
|
package/dist/register.js
CHANGED
|
@@ -80,15 +80,15 @@ export function register(Component, light, options) {
|
|
|
80
80
|
this.styles.elements.push(...this.attachStyles(this.root, styleUrls), ...this.attachStyles(this.portal, styleUrls));
|
|
81
81
|
}
|
|
82
82
|
disconnectedCallback() {
|
|
83
|
-
var
|
|
84
|
-
if (!this.root ||
|
|
83
|
+
var _this_view, _document_body, _this_onDispose, _this;
|
|
84
|
+
if (!this.root || this.root.isConnected) {
|
|
85
85
|
return;
|
|
86
86
|
}
|
|
87
87
|
for (const element of this.styles.elements){
|
|
88
88
|
element.remove();
|
|
89
89
|
}
|
|
90
90
|
(_this_view = this.view) === null || _this_view === void 0 ? void 0 : _this_view.unmount();
|
|
91
|
-
document.body.removeChild(this.portal.host);
|
|
91
|
+
(_document_body = document.body) === null || _document_body === void 0 ? void 0 : _document_body.removeChild(this.portal.host);
|
|
92
92
|
this.root = undefined;
|
|
93
93
|
this.portal = undefined;
|
|
94
94
|
this.portalAnvilContainer = undefined;
|
|
@@ -149,7 +149,7 @@ export function register(Component, light, options) {
|
|
|
149
149
|
for (const [key, value] of Object.entries(entries)){
|
|
150
150
|
this[key] = value;
|
|
151
151
|
}
|
|
152
|
-
if (this.styles.loaded === this.styles.total
|
|
152
|
+
if (this.styles.loaded === this.styles.total) {
|
|
153
153
|
this.render();
|
|
154
154
|
}
|
|
155
155
|
}), _define_property(this, "handleLoad", ()=>{
|
package/dist/register.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/register.tsx"],"sourcesContent":["import { type LDService } from '@servicetitan/launchdarkly-service';\nimport { Log } from '@servicetitan/log-service';\nimport { Provider } from '@servicetitan/react-ioc';\nimport { ExposedDependencies } from '@servicetitan/startup-utils';\nimport { ComponentType, FC, ReactElement, useEffect } from 'react';\nimport {\n BASENAME_TOKEN,\n Entries,\n EXPOSED_DEPENDENCIES_TOKEN,\n EXPOSED_INSTANCE_DEPENDENCIES_TOKEN,\n ExposedInstanceDependencies,\n IS_WEB_COMPONENT_TOKEN,\n IWebComponent,\n RENDER_ROOT_TOKEN,\n} from './common';\nimport { MFEDataContext } from './contexts/mfe-data-context';\nimport { MFEMetadataContext } from './contexts/mfe-metadata-context';\nimport { EVENT_BUS_TOKEN, EventBus } from './event-bus';\nimport { WEB_COMPONENT_NAME } from './globals';\nimport { HistoryManager } from './history-manager';\nimport { render } from './render';\nimport { getElementName, getLDServiceToken } from './utils';\n\nfunction createLink(url: string, onLoad: () => void) {\n const element = document.createElement('link');\n\n element.href = url;\n element.rel = 'stylesheet';\n element.crossOrigin = 'anonymous';\n element.onload = onLoad;\n element.onerror = onLoad;\n\n return element;\n}\n\nconst Placeholder: FC = () => <div style={{ display: 'none' }} />;\n\nexport interface RegisterOptions {\n legacyRoot?: boolean;\n sharedDependenciesNames?: string[];\n}\n\nexport function register(Component: ComponentType, light: boolean, options?: RegisterOptions) {\n class WebComponent extends HTMLElement implements IWebComponent {\n private root?: ShadowRoot;\n private portal?: ShadowRoot;\n private portalAnvilContainer?: HTMLDivElement;\n\n private styles: {\n total: number;\n loaded: number;\n elements: HTMLElement[];\n } = { total: 0, loaded: 0, elements: [] };\n\n private ldService?: LDService;\n private logService?: Log;\n private historyManager?: HistoryManager;\n private exposedDependencies?: ExposedDependencies;\n private exposedInstanceDependencies?: ExposedInstanceDependencies;\n private eventBus?: EventBus;\n private basename?: string;\n private onReady?: () => void;\n private onDispose?: () => void;\n private view?: ReturnType<typeof render>;\n\n connectedCallback() {\n /*\n * connectedCallback can be called when DOM element has moved\n * check that root is still connected to the DOM\n * if that's the case we don't need to reconnect MFE\n */\n if (this.root?.isConnected) {\n return;\n }\n const sharedDependenciesNames = options?.sharedDependenciesNames ?? [];\n const styleUrls = getStyleUrls(light, sharedDependenciesNames, this);\n\n this.styles = {\n total: styleUrls.length * 2,\n loaded: 0,\n elements: [],\n };\n\n this.root = this.shadowRoot ?? this.attachShadow({ mode: 'open' });\n /*\n * Portal shadow dom is created at the bottom of the body in order to be used as\n * the element for the design system components to attach modals and popups to.\n * This element is passed down the tree through context, and used within\n * the design system components.\n */\n const portalElement = document.createElement('div');\n portalElement.setAttribute(\n 'data-mfe-portal-name',\n getElementName({ WebComponent: WEB_COMPONENT_NAME! })\n );\n this.portal = document.body.appendChild(portalElement).attachShadow({ mode: 'open' });\n /*\n * Add element inside of portal so that Anvil 2 can attach modals and popups to it\n * since floating-ui does not support attaching straight to shadow dom\n */\n this.portalAnvilContainer = document.createElement('div');\n this.portal.appendChild(this.portalAnvilContainer);\n\n this.view = render(<Placeholder />, this.root, options);\n\n this.styles.elements.push(\n ...this.attachStyles(this.root, styleUrls),\n ...this.attachStyles(this.portal, styleUrls)\n );\n }\n\n disconnectedCallback() {\n if (!this.root || this.root?.isConnected) {\n return;\n }\n for (const element of this.styles.elements) {\n element.remove();\n }\n\n this.view?.unmount();\n document.body.removeChild(this.portal!.host);\n this.root = undefined;\n this.portal = undefined;\n this.portalAnvilContainer = undefined;\n\n this.onDispose?.();\n }\n\n // Observe changes to the data-mfe-data attribute so that we can re-render when it changes\n static get observedAttributes() {\n return ['data-mfe-data'];\n }\n\n attributeChangedCallback() {\n this.render();\n }\n\n provide = (entries: Entries) => {\n for (const [key, value] of Object.entries(entries)) {\n this[key as keyof IWebComponent] = value;\n }\n\n if (this.styles.loaded === this.styles.total && Object.values(entries).some(v => !!v)) {\n this.render();\n }\n };\n\n private handleLoad = () => {\n this.styles.loaded++;\n\n if (this.styles.loaded === this.styles.total) {\n this.render();\n }\n };\n\n private attachStyles = (node: ShadowRoot, urls: string[]) => {\n const elements: HTMLElement[] = [];\n\n for (const url of urls) {\n const element = createLink(url, this.handleLoad);\n node.appendChild(element);\n elements.push(element);\n }\n\n return elements;\n };\n\n private withAnvil1Providers(children: ReactElement): ReactElement {\n try {\n /**\n * Note, the webpack.IgnorePlugin must be configured to ignore this dependency.\n * @see {@link file://./../../startup/src/webpack/configs/plugins/ignore-plugin/ignore-plugin.ts}\n */\n const { DefaultPortalContext, TablePopupPropsContext } =\n require('@servicetitan/design-system') as typeof import('@servicetitan/design-system');\n return (\n <DefaultPortalContext.Provider value={this.portal as unknown as HTMLElement}>\n <TablePopupPropsContext.Provider\n value={props => ({\n ...props,\n appendTo: this.root as unknown as HTMLElement,\n })}\n >\n {children}\n </TablePopupPropsContext.Provider>\n </DefaultPortalContext.Provider>\n );\n } catch {\n return children;\n }\n }\n\n private withAnvil2Providers(children: ReactElement): ReactElement {\n try {\n /**\n * Note, the webpack.IgnorePlugin must be configured to ignore this dependency.\n * @see {@link file://./../../startup/src/webpack/configs/plugins/ignore-plugin/ignore-plugin.ts}\n */\n const { PortalProvider } =\n require('@servicetitan/anvil2') as typeof import('@servicetitan/anvil2');\n return <PortalProvider root={this.portalAnvilContainer}>{children}</PortalProvider>;\n } catch {\n return children;\n }\n }\n\n private withProviders(children: ReactElement): ReactElement {\n return this.withAnvil2Providers(this.withAnvil1Providers(children));\n }\n\n private render = () => {\n /*\n * Check for this.root first, otherwise we get error when\n * attributeChangedCallback happens on load\n */\n if (this.root) {\n const mfeData = this.dataset.mfeData\n ? /*\n * Data was stringified in order to come through the data-mfe-data attribute\n * So we must JSON.parse it here to get an object back\n */\n JSON.parse(this.dataset.mfeData)\n : /*\n * If mfeData isn't there, then the Host may not be up to date with web-components\n * and is instead passing data through separate data-attributes, so we want to\n * spread all of those instead\n */\n { ...this.dataset };\n\n const metadata = {\n shadowRoot: this.root,\n portalShadowRoot: this.portal!,\n };\n\n this.view?.rerender(\n <Provider\n singletons={[\n { provide: IS_WEB_COMPONENT_TOKEN, useValue: true },\n { provide: RENDER_ROOT_TOKEN, useValue: this.root },\n ]}\n >\n <Provider\n singletons={[\n { provide: Log, useValue: this.logService },\n {\n provide: HistoryManager,\n useValue: this.historyManager,\n },\n {\n provide: EXPOSED_DEPENDENCIES_TOKEN,\n useValue: this.exposedDependencies,\n },\n {\n provide: EXPOSED_INSTANCE_DEPENDENCIES_TOKEN,\n useValue: this.exposedInstanceDependencies,\n },\n { provide: BASENAME_TOKEN, useValue: this.basename },\n { provide: EVENT_BUS_TOKEN, useValue: this.eventBus },\n { provide: getLDServiceToken(), useValue: this.ldService },\n ].filter(\n ({ provide, useValue }) =>\n useValue !== undefined && provide !== undefined\n )}\n >\n <MFEDataContext.Provider value={{ ...mfeData }}>\n <MFEMetadataContext.Provider value={metadata}>\n {this.withProviders(<Component {...mfeData} />)}\n {this.onReady && <RenderCallback callback={this.onReady} />}\n </MFEMetadataContext.Provider>\n </MFEDataContext.Provider>\n </Provider>\n </Provider>\n );\n }\n };\n }\n\n if (!WEB_COMPONENT_NAME) {\n // eslint-disable-next-line no-console\n console.error('\"WEB_COMPONENT_NAME\" is not defined!');\n return;\n }\n\n window.customElements.define(WEB_COMPONENT_NAME, WebComponent);\n}\n\nfunction getStyleUrls(light: boolean, sharedDependenciesNames: string[], el: HTMLElement) {\n function getCssUrl(dependencyName: string, cssFileRegEx: RegExp) {\n if (light && sharedDependenciesNames.includes(dependencyName)) {\n return Array.from(document.getElementsByTagName('link')).find(\n ({ href }) => href && cssFileRegEx.test(href)\n )?.href;\n }\n }\n\n const designSystemUrl = getCssUrl(\n '@servicetitan/design-system',\n /design-system(\\..+)?\\.bundle\\.css/\n );\n const anvil2CssUrl = getCssUrl('@servicetitan/anvil2', /anvil2(\\..+)?\\.bundle\\.css/);\n\n return [\n ...(designSystemUrl ? [designSystemUrl] : []),\n ...(anvil2CssUrl ? [anvil2CssUrl] : []),\n ...(el.hasAttribute('style-urls')\n ? JSON.parse(decodeURIComponent(el.getAttribute('style-urls')!))\n : []),\n ];\n}\n\nfunction RenderCallback({ callback }: { callback: () => void }) {\n // eslint-disable-next-line react-hooks/exhaustive-deps\n useEffect(() => callback(), []);\n return null;\n}\n"],"names":["Log","Provider","useEffect","BASENAME_TOKEN","EXPOSED_DEPENDENCIES_TOKEN","EXPOSED_INSTANCE_DEPENDENCIES_TOKEN","IS_WEB_COMPONENT_TOKEN","RENDER_ROOT_TOKEN","MFEDataContext","MFEMetadataContext","EVENT_BUS_TOKEN","WEB_COMPONENT_NAME","HistoryManager","render","getElementName","getLDServiceToken","createLink","url","onLoad","element","document","createElement","href","rel","crossOrigin","onload","onerror","Placeholder","div","style","display","register","Component","light","options","WebComponent","HTMLElement","connectedCallback","root","isConnected","sharedDependenciesNames","styleUrls","getStyleUrls","styles","total","length","loaded","elements","shadowRoot","attachShadow","mode","portalElement","setAttribute","portal","body","appendChild","portalAnvilContainer","view","push","attachStyles","disconnectedCallback","remove","unmount","removeChild","host","undefined","onDispose","observedAttributes","attributeChangedCallback","withAnvil1Providers","children","DefaultPortalContext","TablePopupPropsContext","require","value","props","appendTo","withAnvil2Providers","PortalProvider","withProviders","ldService","logService","historyManager","exposedDependencies","exposedInstanceDependencies","eventBus","basename","onReady","provide","entries","key","Object","values","some","v","handleLoad","node","urls","mfeData","dataset","JSON","parse","metadata","portalShadowRoot","rerender","singletons","useValue","filter","RenderCallback","callback","console","error","window","customElements","define","el","getCssUrl","dependencyName","cssFileRegEx","includes","Array","from","getElementsByTagName","find","test","designSystemUrl","anvil2CssUrl","hasAttribute","decodeURIComponent","getAttribute"],"mappings":"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"}
|
|
1
|
+
{"version":3,"sources":["../src/register.tsx"],"sourcesContent":["import { type LDService } from '@servicetitan/launchdarkly-service';\nimport { Log } from '@servicetitan/log-service';\nimport { Provider } from '@servicetitan/react-ioc';\nimport { ExposedDependencies } from '@servicetitan/startup-utils';\nimport { ComponentType, FC, ReactElement, useEffect } from 'react';\nimport {\n BASENAME_TOKEN,\n Entries,\n EXPOSED_DEPENDENCIES_TOKEN,\n EXPOSED_INSTANCE_DEPENDENCIES_TOKEN,\n ExposedInstanceDependencies,\n IS_WEB_COMPONENT_TOKEN,\n IWebComponent,\n RENDER_ROOT_TOKEN,\n} from './common';\nimport { MFEDataContext } from './contexts/mfe-data-context';\nimport { MFEMetadataContext } from './contexts/mfe-metadata-context';\nimport { EVENT_BUS_TOKEN, EventBus } from './event-bus';\nimport { WEB_COMPONENT_NAME } from './globals';\nimport { HistoryManager } from './history-manager';\nimport { render } from './render';\nimport { getElementName, getLDServiceToken } from './utils';\n\nfunction createLink(url: string, onLoad: () => void) {\n const element = document.createElement('link');\n\n element.href = url;\n element.rel = 'stylesheet';\n element.crossOrigin = 'anonymous';\n element.onload = onLoad;\n element.onerror = onLoad;\n\n return element;\n}\n\nconst Placeholder: FC = () => <div style={{ display: 'none' }} />;\n\nexport interface RegisterOptions {\n legacyRoot?: boolean;\n sharedDependenciesNames?: string[];\n}\n\nexport function register(Component: ComponentType, light: boolean, options?: RegisterOptions) {\n class WebComponent extends HTMLElement implements IWebComponent {\n private root?: ShadowRoot;\n private portal?: ShadowRoot;\n private portalAnvilContainer?: HTMLDivElement;\n\n private styles: {\n total: number;\n loaded: number;\n elements: HTMLElement[];\n } = { total: 0, loaded: 0, elements: [] };\n\n private ldService?: LDService;\n private logService?: Log;\n private historyManager?: HistoryManager;\n private exposedDependencies?: ExposedDependencies;\n private exposedInstanceDependencies?: ExposedInstanceDependencies;\n private eventBus?: EventBus;\n private basename?: string;\n private onReady?: () => void;\n private onDispose?: () => void;\n private view?: ReturnType<typeof render>;\n\n connectedCallback() {\n /*\n * connectedCallback can be called when DOM element has moved\n * check that root is still connected to the DOM\n * if that's the case we don't need to reconnect MFE\n */\n if (this.root?.isConnected) {\n return;\n }\n const sharedDependenciesNames = options?.sharedDependenciesNames ?? [];\n const styleUrls = getStyleUrls(light, sharedDependenciesNames, this);\n\n this.styles = {\n total: styleUrls.length * 2,\n loaded: 0,\n elements: [],\n };\n\n this.root = this.shadowRoot ?? this.attachShadow({ mode: 'open' });\n /*\n * Portal shadow dom is created at the bottom of the body in order to be used as\n * the element for the design system components to attach modals and popups to.\n * This element is passed down the tree through context, and used within\n * the design system components.\n */\n const portalElement = document.createElement('div');\n portalElement.setAttribute(\n 'data-mfe-portal-name',\n getElementName({ WebComponent: WEB_COMPONENT_NAME! })\n );\n this.portal = document.body.appendChild(portalElement).attachShadow({ mode: 'open' });\n /*\n * Add element inside of portal so that Anvil 2 can attach modals and popups to it\n * since floating-ui does not support attaching straight to shadow dom\n */\n this.portalAnvilContainer = document.createElement('div');\n this.portal.appendChild(this.portalAnvilContainer);\n\n this.view = render(<Placeholder />, this.root, options);\n\n this.styles.elements.push(\n ...this.attachStyles(this.root, styleUrls),\n ...this.attachStyles(this.portal, styleUrls)\n );\n }\n\n disconnectedCallback() {\n if (!this.root || this.root.isConnected) {\n return;\n }\n for (const element of this.styles.elements) {\n element.remove();\n }\n\n this.view?.unmount();\n document.body?.removeChild(this.portal!.host);\n this.root = undefined;\n this.portal = undefined;\n this.portalAnvilContainer = undefined;\n\n this.onDispose?.();\n }\n\n // Observe changes to the data-mfe-data attribute so that we can re-render when it changes\n static get observedAttributes() {\n return ['data-mfe-data'];\n }\n\n attributeChangedCallback() {\n this.render();\n }\n\n provide = (entries: Entries) => {\n for (const [key, value] of Object.entries(entries)) {\n this[key as keyof IWebComponent] = value;\n }\n\n if (this.styles.loaded === this.styles.total) {\n this.render();\n }\n };\n\n private handleLoad = () => {\n this.styles.loaded++;\n\n if (this.styles.loaded === this.styles.total) {\n this.render();\n }\n };\n\n private attachStyles = (node: ShadowRoot, urls: string[]) => {\n const elements: HTMLElement[] = [];\n\n for (const url of urls) {\n const element = createLink(url, this.handleLoad);\n node.appendChild(element);\n elements.push(element);\n }\n\n return elements;\n };\n\n private withAnvil1Providers(children: ReactElement): ReactElement {\n try {\n /**\n * Note, the webpack.IgnorePlugin must be configured to ignore this dependency.\n * @see {@link file://./../../startup/src/webpack/configs/plugins/ignore-plugin/ignore-plugin.ts}\n */\n const { DefaultPortalContext, TablePopupPropsContext } =\n require('@servicetitan/design-system') as typeof import('@servicetitan/design-system');\n return (\n <DefaultPortalContext.Provider value={this.portal as unknown as HTMLElement}>\n <TablePopupPropsContext.Provider\n value={props => ({\n ...props,\n appendTo: this.root as unknown as HTMLElement,\n })}\n >\n {children}\n </TablePopupPropsContext.Provider>\n </DefaultPortalContext.Provider>\n );\n } catch {\n return children;\n }\n }\n\n private withAnvil2Providers(children: ReactElement): ReactElement {\n try {\n /**\n * Note, the webpack.IgnorePlugin must be configured to ignore this dependency.\n * @see {@link file://./../../startup/src/webpack/configs/plugins/ignore-plugin/ignore-plugin.ts}\n */\n const { PortalProvider } =\n require('@servicetitan/anvil2') as typeof import('@servicetitan/anvil2');\n return <PortalProvider root={this.portalAnvilContainer}>{children}</PortalProvider>;\n } catch {\n return children;\n }\n }\n\n private withProviders(children: ReactElement): ReactElement {\n return this.withAnvil2Providers(this.withAnvil1Providers(children));\n }\n\n private render = () => {\n /*\n * Check for this.root first, otherwise we get error when\n * attributeChangedCallback happens on load\n */\n if (this.root) {\n const mfeData = this.dataset.mfeData\n ? /*\n * Data was stringified in order to come through the data-mfe-data attribute\n * So we must JSON.parse it here to get an object back\n */\n JSON.parse(this.dataset.mfeData)\n : /*\n * If mfeData isn't there, then the Host may not be up to date with web-components\n * and is instead passing data through separate data-attributes, so we want to\n * spread all of those instead\n */\n { ...this.dataset };\n\n const metadata = {\n shadowRoot: this.root,\n portalShadowRoot: this.portal!,\n };\n\n this.view?.rerender(\n <Provider\n singletons={[\n { provide: IS_WEB_COMPONENT_TOKEN, useValue: true },\n { provide: RENDER_ROOT_TOKEN, useValue: this.root },\n ]}\n >\n <Provider\n singletons={[\n { provide: Log, useValue: this.logService },\n {\n provide: HistoryManager,\n useValue: this.historyManager,\n },\n {\n provide: EXPOSED_DEPENDENCIES_TOKEN,\n useValue: this.exposedDependencies,\n },\n {\n provide: EXPOSED_INSTANCE_DEPENDENCIES_TOKEN,\n useValue: this.exposedInstanceDependencies,\n },\n { provide: BASENAME_TOKEN, useValue: this.basename },\n { provide: EVENT_BUS_TOKEN, useValue: this.eventBus },\n { provide: getLDServiceToken(), useValue: this.ldService },\n ].filter(\n ({ provide, useValue }) =>\n useValue !== undefined && provide !== undefined\n )}\n >\n <MFEDataContext.Provider value={{ ...mfeData }}>\n <MFEMetadataContext.Provider value={metadata}>\n {this.withProviders(<Component {...mfeData} />)}\n {this.onReady && <RenderCallback callback={this.onReady} />}\n </MFEMetadataContext.Provider>\n </MFEDataContext.Provider>\n </Provider>\n </Provider>\n );\n }\n };\n }\n\n if (!WEB_COMPONENT_NAME) {\n // eslint-disable-next-line no-console\n console.error('\"WEB_COMPONENT_NAME\" is not defined!');\n return;\n }\n\n window.customElements.define(WEB_COMPONENT_NAME, WebComponent);\n}\n\nfunction getStyleUrls(light: boolean, sharedDependenciesNames: string[], el: HTMLElement) {\n function getCssUrl(dependencyName: string, cssFileRegEx: RegExp) {\n if (light && sharedDependenciesNames.includes(dependencyName)) {\n return Array.from(document.getElementsByTagName('link')).find(\n ({ href }) => href && cssFileRegEx.test(href)\n )?.href;\n }\n }\n\n const designSystemUrl = getCssUrl(\n '@servicetitan/design-system',\n /design-system(\\..+)?\\.bundle\\.css/\n );\n const anvil2CssUrl = getCssUrl('@servicetitan/anvil2', /anvil2(\\..+)?\\.bundle\\.css/);\n\n return [\n ...(designSystemUrl ? [designSystemUrl] : []),\n ...(anvil2CssUrl ? [anvil2CssUrl] : []),\n ...(el.hasAttribute('style-urls')\n ? JSON.parse(decodeURIComponent(el.getAttribute('style-urls')!))\n : []),\n ];\n}\n\nfunction RenderCallback({ callback }: { callback: () => void }) {\n // eslint-disable-next-line react-hooks/exhaustive-deps\n useEffect(() => callback(), []);\n return null;\n}\n"],"names":["Log","Provider","useEffect","BASENAME_TOKEN","EXPOSED_DEPENDENCIES_TOKEN","EXPOSED_INSTANCE_DEPENDENCIES_TOKEN","IS_WEB_COMPONENT_TOKEN","RENDER_ROOT_TOKEN","MFEDataContext","MFEMetadataContext","EVENT_BUS_TOKEN","WEB_COMPONENT_NAME","HistoryManager","render","getElementName","getLDServiceToken","createLink","url","onLoad","element","document","createElement","href","rel","crossOrigin","onload","onerror","Placeholder","div","style","display","register","Component","light","options","WebComponent","HTMLElement","connectedCallback","root","isConnected","sharedDependenciesNames","styleUrls","getStyleUrls","styles","total","length","loaded","elements","shadowRoot","attachShadow","mode","portalElement","setAttribute","portal","body","appendChild","portalAnvilContainer","view","push","attachStyles","disconnectedCallback","remove","unmount","removeChild","host","undefined","onDispose","observedAttributes","attributeChangedCallback","withAnvil1Providers","children","DefaultPortalContext","TablePopupPropsContext","require","value","props","appendTo","withAnvil2Providers","PortalProvider","withProviders","ldService","logService","historyManager","exposedDependencies","exposedInstanceDependencies","eventBus","basename","onReady","provide","entries","key","Object","handleLoad","node","urls","mfeData","dataset","JSON","parse","metadata","portalShadowRoot","rerender","singletons","useValue","filter","RenderCallback","callback","console","error","window","customElements","define","el","getCssUrl","dependencyName","cssFileRegEx","includes","Array","from","getElementsByTagName","find","test","designSystemUrl","anvil2CssUrl","hasAttribute","decodeURIComponent","getAttribute"],"mappings":"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"}
|
package/dist/types.d.ts
CHANGED
|
@@ -3,7 +3,7 @@ export type JSON = JSONPrimitive | {
|
|
|
3
3
|
[key: string | number]: JSON;
|
|
4
4
|
} | JSON[];
|
|
5
5
|
export type Serializable<T> = {
|
|
6
|
-
[P in keyof T]: T[P] extends
|
|
6
|
+
[P in keyof T]: T[P] extends JSON ? T[P] : T[P] extends Function | Date | Map<any, any> | Set<any> | symbol ? never : T[P] extends (infer U)[] ? Serializable<U>[] : Serializable<T[P]>;
|
|
7
7
|
};
|
|
8
8
|
export interface Metadata {
|
|
9
9
|
name: string;
|
package/dist/types.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA,MAAM,MAAM,aAAa,GAAG,MAAM,GAAG,MAAM,GAAG,OAAO,GAAG,IAAI,GAAG,SAAS,CAAC;AAEzE,MAAM,MAAM,IAAI,GAAG,aAAa,GAAG;IAAE,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAAA;CAAE,GAAG,IAAI,EAAE,CAAC;AAE7E,MAAM,MAAM,YAAY,CAAC,CAAC,IAAI;KACzB,CAAC,IAAI,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,SAAS,
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA,MAAM,MAAM,aAAa,GAAG,MAAM,GAAG,MAAM,GAAG,OAAO,GAAG,IAAI,GAAG,SAAS,CAAC;AAEzE,MAAM,MAAM,IAAI,GAAG,aAAa,GAAG;IAAE,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAAA;CAAE,GAAG,IAAI,EAAE,CAAC;AAE7E,MAAM,MAAM,YAAY,CAAC,CAAC,IAAI;KACzB,CAAC,IAAI,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,SAAS,IAAI,GAC3B,CAAC,CAAC,CAAC,CAAC,GACJ,CAAC,CAAC,CAAC,CAAC,SAAS,QAAQ,GAAG,IAAI,GAAG,GAAG,CAAC,GAAG,EAAE,GAAG,CAAC,GAAG,GAAG,CAAC,GAAG,CAAC,GAAG,MAAM,GAC9D,KAAK,GACL,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,MAAM,CAAC,CAAC,EAAE,GACtB,YAAY,CAAC,CAAC,CAAC,EAAE,GACjB,YAAY,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;CAC/B,CAAC;AAEF,MAAM,WAAW,QAAQ;IACrB,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,WAAW,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,SAAS,CAAC,CAAC;IACjD,kBAAkB,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAC3C,YAAY,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACtC,WAAW,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE;QAAE,GAAG,EAAE,MAAM,EAAE,CAAC;QAAC,EAAE,EAAE,MAAM,EAAE,CAAA;KAAE,CAAC,CAAC;CACjE"}
|
package/dist/types.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/types.ts"],"sourcesContent":["export type JSONPrimitive = string | number | boolean | null | undefined;\n\nexport type JSON = JSONPrimitive | { [key: string | number]: JSON } | JSON[];\n\nexport type Serializable<T> = {\n [P in keyof T]: T[P] extends
|
|
1
|
+
{"version":3,"sources":["../src/types.ts"],"sourcesContent":["export type JSONPrimitive = string | number | boolean | null | undefined;\n\nexport type JSON = JSONPrimitive | { [key: string | number]: JSON } | JSON[];\n\nexport type Serializable<T> = {\n [P in keyof T]: T[P] extends JSON\n ? T[P]\n : T[P] extends Function | Date | Map<any, any> | Set<any> | symbol\n ? never\n : T[P] extends (infer U)[]\n ? Serializable<U>[]\n : Serializable<T[P]>;\n};\n\nexport interface Metadata {\n name: string;\n version?: string;\n bundledWith?: Record<string, string | undefined>;\n sharedDependencies: Record<string, string>;\n dependencies?: Record<string, string>;\n entrypoints?: Record<string, { css: string[]; js: string[] }>;\n}\n"],"names":[],"mappings":"AAcA,WAOC"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@servicetitan/web-components",
|
|
3
|
-
"version": "34.
|
|
3
|
+
"version": "34.1.0",
|
|
4
4
|
"description": "Framework to build, register, and load Microfrontends into host applications",
|
|
5
5
|
"homepage": "https://docs.st.dev/docs/frontend/uikit/web-components",
|
|
6
6
|
"repository": {
|
|
@@ -16,18 +16,18 @@
|
|
|
16
16
|
"src"
|
|
17
17
|
],
|
|
18
18
|
"dependencies": {
|
|
19
|
-
"@servicetitan/error-boundary": "34.
|
|
20
|
-
"@servicetitan/startup-utils": "34.
|
|
19
|
+
"@servicetitan/error-boundary": "34.1.0",
|
|
20
|
+
"@servicetitan/startup-utils": "34.1.0",
|
|
21
21
|
"lodash.get": "~4.4.2",
|
|
22
22
|
"mitt": "~3.0.1",
|
|
23
|
-
"semver": "~7.7.
|
|
23
|
+
"semver": "~7.7.4"
|
|
24
24
|
},
|
|
25
25
|
"devDependencies": {
|
|
26
|
-
"@servicetitan/anvil2": "^2.0
|
|
26
|
+
"@servicetitan/anvil2": "^2.1.0",
|
|
27
27
|
"@servicetitan/design-system": "~14.5.3",
|
|
28
|
-
"@servicetitan/launchdarkly-service": "34.
|
|
29
|
-
"@servicetitan/log-service": "34.
|
|
30
|
-
"@servicetitan/react-ioc": "34.
|
|
28
|
+
"@servicetitan/launchdarkly-service": "34.1.0",
|
|
29
|
+
"@servicetitan/log-service": "34.1.0",
|
|
30
|
+
"@servicetitan/react-ioc": "34.1.0",
|
|
31
31
|
"@testing-library/dom": "^10.4.1",
|
|
32
32
|
"@testing-library/jest-dom": "^6.9.1",
|
|
33
33
|
"@testing-library/react": "^16.3.2",
|
|
@@ -45,9 +45,9 @@
|
|
|
45
45
|
"peerDependencies": {
|
|
46
46
|
"@servicetitan/anvil2": ">=1.5.0",
|
|
47
47
|
"@servicetitan/design-system": ">=14.5.3",
|
|
48
|
-
"@servicetitan/launchdarkly-service": "34.
|
|
49
|
-
"@servicetitan/log-service": "34.
|
|
50
|
-
"@servicetitan/react-ioc": "34.
|
|
48
|
+
"@servicetitan/launchdarkly-service": "34.1.0",
|
|
49
|
+
"@servicetitan/log-service": "34.1.0",
|
|
50
|
+
"@servicetitan/react-ioc": "34.1.0",
|
|
51
51
|
"history": "~4.10.1",
|
|
52
52
|
"react": ">=17.0.2",
|
|
53
53
|
"react-dom": ">=17.0.2"
|
|
@@ -69,5 +69,5 @@
|
|
|
69
69
|
"cli": {
|
|
70
70
|
"webpack": false
|
|
71
71
|
},
|
|
72
|
-
"gitHead": "
|
|
72
|
+
"gitHead": "660a104c81cce6867a7bb3081ab3f2f0140e403a"
|
|
73
73
|
}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { LD_SERVICE_TOKEN } from '@servicetitan/launchdarkly-service';
|
|
2
2
|
import { Log } from '@servicetitan/log-service';
|
|
3
3
|
import { Provider, ProviderProps } from '@servicetitan/react-ioc';
|
|
4
|
-
import { getVersionMismatches } from '@servicetitan/startup-utils';
|
|
4
|
+
import { ExposedDependencies, getVersionMismatches } from '@servicetitan/startup-utils';
|
|
5
5
|
import '@testing-library/jest-dom';
|
|
6
6
|
import { act, render, screen, waitFor } from '@testing-library/react';
|
|
7
7
|
import { FC, ReactNode, RefObject, useEffect, useRef } from 'react';
|
|
@@ -10,7 +10,6 @@ import {
|
|
|
10
10
|
EXPOSED_DEPENDENCIES_TOKEN,
|
|
11
11
|
EXPOSED_INSTANCE_DEPENDENCIES_TOKEN,
|
|
12
12
|
Entries,
|
|
13
|
-
ExposedDependencies,
|
|
14
13
|
ExposedInstanceDependencies,
|
|
15
14
|
} from '../common';
|
|
16
15
|
import { EVENT_BUS_TOKEN } from '../event-bus';
|
|
@@ -291,7 +290,7 @@ describe('[web-components] Loader', () => {
|
|
|
291
290
|
async function scriptLoadedSetup() {
|
|
292
291
|
const result = subject();
|
|
293
292
|
|
|
294
|
-
await waitFor(() => onloadRef !==
|
|
293
|
+
await waitFor(() => onloadRef !== null);
|
|
295
294
|
act(() => {
|
|
296
295
|
onloadRef!();
|
|
297
296
|
});
|
|
@@ -1,21 +1,16 @@
|
|
|
1
1
|
import '@testing-library/jest-dom';
|
|
2
2
|
import { act, render } from '@testing-library/react';
|
|
3
|
-
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
|
4
|
-
// @ts-ignore because Jest mistakenly complains that "'shadow-dom-testing-library' cannot be imported using this construct".
|
|
5
3
|
import { screen } from 'shadow-dom-testing-library';
|
|
6
|
-
|
|
7
4
|
import { expectStylesInDom, MockComponent, registerComponent } from '../__mocks__';
|
|
8
5
|
import { IWebComponent } from '../common';
|
|
9
6
|
|
|
10
7
|
describe('[web-components] register', () => {
|
|
11
8
|
const baseComponentName = 'mock-app';
|
|
12
9
|
const componentName = `${baseComponentName}-40b38a38`;
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
});
|
|
18
|
-
};
|
|
10
|
+
let props: Record<string, any> | undefined;
|
|
11
|
+
let dataAttrs: Record<string, any> | undefined;
|
|
12
|
+
let onReady: (() => void) | undefined;
|
|
13
|
+
let onDispose: (() => void) | undefined;
|
|
19
14
|
let onloadRefs: Function[];
|
|
20
15
|
|
|
21
16
|
class Page {
|
|
@@ -52,12 +47,20 @@ describe('[web-components] register', () => {
|
|
|
52
47
|
});
|
|
53
48
|
|
|
54
49
|
beforeEach(() => {
|
|
50
|
+
props = undefined;
|
|
51
|
+
dataAttrs = undefined;
|
|
52
|
+
onReady = undefined;
|
|
53
|
+
onDispose = undefined;
|
|
55
54
|
onloadRefs = [];
|
|
56
55
|
});
|
|
57
56
|
|
|
58
|
-
const subject = (
|
|
57
|
+
const subject = () => {
|
|
59
58
|
jest.spyOn(console, 'error').mockImplementation(jest.fn()); // suppress "attempt to unmount root while rendering" error
|
|
60
59
|
|
|
60
|
+
const handleRef = (webComponent: IWebComponent | null) => {
|
|
61
|
+
webComponent?.provide({ onReady, onDispose });
|
|
62
|
+
};
|
|
63
|
+
|
|
61
64
|
const data = props && { 'data-mfe-data': JSON.stringify(props) };
|
|
62
65
|
const Component: any = componentName;
|
|
63
66
|
const renderResult = render(<Component ref={handleRef} {...data} {...dataAttrs} />);
|
|
@@ -71,14 +74,14 @@ describe('[web-components] register', () => {
|
|
|
71
74
|
return renderResult;
|
|
72
75
|
};
|
|
73
76
|
|
|
74
|
-
test('
|
|
75
|
-
subject();
|
|
76
|
-
|
|
77
|
+
test('exposes metadata', () => {
|
|
77
78
|
const metadata = {
|
|
78
79
|
shadowRoot: 'ShadowRoot',
|
|
79
80
|
portalShadowRoot: 'ShadowRoot',
|
|
80
81
|
};
|
|
81
82
|
|
|
83
|
+
subject();
|
|
84
|
+
|
|
82
85
|
Object.entries(metadata).forEach(([name, value]) =>
|
|
83
86
|
expect(
|
|
84
87
|
screen.getByShadowText(`Metadata: ${name}, Value: ${JSON.stringify(value)}`)
|
|
@@ -87,19 +90,21 @@ describe('[web-components] register', () => {
|
|
|
87
90
|
});
|
|
88
91
|
|
|
89
92
|
describe('when component has style urls', () => {
|
|
90
|
-
|
|
93
|
+
const styleUrls = ['foo.css', 'bar.css'];
|
|
91
94
|
|
|
92
95
|
beforeEach(() => {
|
|
93
|
-
|
|
96
|
+
dataAttrs = { 'style-urls': JSON.stringify(styleUrls) };
|
|
94
97
|
});
|
|
95
98
|
|
|
96
99
|
test('loads the styles into the component shadow DOM', () => {
|
|
97
|
-
subject(
|
|
100
|
+
subject();
|
|
101
|
+
|
|
98
102
|
expectStylesInDom(styleUrls, () => Page.componentShadowRoot);
|
|
99
103
|
});
|
|
100
104
|
|
|
101
105
|
test('loads the styles into the portal shadow DOM', () => {
|
|
102
|
-
subject(
|
|
106
|
+
subject();
|
|
107
|
+
|
|
103
108
|
expectStylesInDom(styleUrls, () => Page.portalShadowRoot);
|
|
104
109
|
});
|
|
105
110
|
|
|
@@ -119,7 +124,8 @@ describe('[web-components] register', () => {
|
|
|
119
124
|
});
|
|
120
125
|
|
|
121
126
|
test('loads the styles and design system styles into the component shadow DOM', () => {
|
|
122
|
-
subject(
|
|
127
|
+
subject();
|
|
128
|
+
|
|
123
129
|
expectStylesInDom(
|
|
124
130
|
[...styleUrls, designSystemLink.href],
|
|
125
131
|
() => Page.componentShadowRoot
|
|
@@ -127,7 +133,8 @@ describe('[web-components] register', () => {
|
|
|
127
133
|
});
|
|
128
134
|
|
|
129
135
|
test('loads the styles and design system styles into the portal shadow DOM', () => {
|
|
130
|
-
subject(
|
|
136
|
+
subject();
|
|
137
|
+
|
|
131
138
|
expectStylesInDom(
|
|
132
139
|
[...styleUrls, designSystemLink.href],
|
|
133
140
|
() => Page.portalShadowRoot
|
|
@@ -137,17 +144,19 @@ describe('[web-components] register', () => {
|
|
|
137
144
|
});
|
|
138
145
|
|
|
139
146
|
describe('when component has custom data-attributes', () => {
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
147
|
+
beforeEach(() => {
|
|
148
|
+
props = {
|
|
149
|
+
string: 'foo',
|
|
150
|
+
array: JSON.stringify(['foo', 'bar']),
|
|
151
|
+
object: JSON.stringify({ foo: 'bar' }),
|
|
152
|
+
objectNotStringified: { foo: 'bar' },
|
|
153
|
+
};
|
|
154
|
+
});
|
|
146
155
|
|
|
147
156
|
it('passes data attributes as props', () => {
|
|
148
|
-
subject(
|
|
157
|
+
subject();
|
|
149
158
|
|
|
150
|
-
Object.entries(props).forEach(([name, value]) =>
|
|
159
|
+
Object.entries(props!).forEach(([name, value]) =>
|
|
151
160
|
expect(
|
|
152
161
|
screen.getByShadowText(`Prop: ${name}, Value: ${JSON.stringify(value)}`)
|
|
153
162
|
).toBeInTheDocument()
|
|
@@ -155,9 +164,9 @@ describe('[web-components] register', () => {
|
|
|
155
164
|
});
|
|
156
165
|
|
|
157
166
|
test('useMFEDataContext exposes data attributes', () => {
|
|
158
|
-
subject(
|
|
167
|
+
subject();
|
|
159
168
|
|
|
160
|
-
Object.entries(props).forEach(([name, value]) =>
|
|
169
|
+
Object.entries(props!).forEach(([name, value]) =>
|
|
161
170
|
expect(
|
|
162
171
|
screen.getByShadowText(`Data: ${name}, Value: ${JSON.stringify(value)}`)
|
|
163
172
|
).toBeInTheDocument()
|
|
@@ -167,14 +176,17 @@ describe('[web-components] register', () => {
|
|
|
167
176
|
|
|
168
177
|
test('logs an error when WEB_COMPONENT_NAME is not set', () => {
|
|
169
178
|
const consoleSpy = jest.spyOn(console, 'error').mockImplementation(jest.fn());
|
|
179
|
+
|
|
170
180
|
jest.isolateModules(() => {
|
|
171
181
|
registerComponent(MockComponent, undefined);
|
|
172
182
|
});
|
|
183
|
+
|
|
173
184
|
expect(consoleSpy).toHaveBeenCalledWith('"WEB_COMPONENT_NAME" is not defined!');
|
|
174
185
|
});
|
|
175
186
|
|
|
176
187
|
test('configures the shadow root in PopupPropsContext', () => {
|
|
177
188
|
subject();
|
|
189
|
+
|
|
178
190
|
expect(screen.getByShadowText(/TablePopupPropsContext appendTo:/)).toHaveTextContent(
|
|
179
191
|
/\[object ShadowRoot\]/
|
|
180
192
|
);
|
|
@@ -185,4 +197,37 @@ describe('[web-components] register', () => {
|
|
|
185
197
|
|
|
186
198
|
expect(Page.portalElement).toHaveAttribute('data-mfe-portal-name', baseComponentName);
|
|
187
199
|
});
|
|
200
|
+
|
|
201
|
+
test('does not throw when document body is removed', () => {
|
|
202
|
+
const body = document.body;
|
|
203
|
+
const parentNode = body.parentNode!;
|
|
204
|
+
try {
|
|
205
|
+
subject();
|
|
206
|
+
expect(() => parentNode.removeChild(body)).not.toThrow();
|
|
207
|
+
} finally {
|
|
208
|
+
parentNode.appendChild(body);
|
|
209
|
+
}
|
|
210
|
+
});
|
|
211
|
+
|
|
212
|
+
describe('with onReady callback', () => {
|
|
213
|
+
beforeEach(() => (onReady = jest.fn()));
|
|
214
|
+
|
|
215
|
+
test('calls onReady', () => {
|
|
216
|
+
subject();
|
|
217
|
+
|
|
218
|
+
expect(onReady).toHaveBeenCalled();
|
|
219
|
+
});
|
|
220
|
+
});
|
|
221
|
+
|
|
222
|
+
describe('with onDispose callback', () => {
|
|
223
|
+
beforeEach(() => (onDispose = jest.fn()));
|
|
224
|
+
|
|
225
|
+
test('calls onDispose when element is removed from DOM', () => {
|
|
226
|
+
const { container } = subject();
|
|
227
|
+
|
|
228
|
+
container.parentNode!.removeChild(container);
|
|
229
|
+
|
|
230
|
+
expect(onDispose).toHaveBeenCalled();
|
|
231
|
+
});
|
|
232
|
+
});
|
|
188
233
|
});
|
package/src/common.ts
CHANGED
|
@@ -2,7 +2,6 @@ import { type LDService } from '@servicetitan/launchdarkly-service';
|
|
|
2
2
|
import { Log } from '@servicetitan/log-service';
|
|
3
3
|
import { symbolToken } from '@servicetitan/react-ioc';
|
|
4
4
|
import { ExposedDependencies } from '@servicetitan/startup-utils';
|
|
5
|
-
import { useRef } from 'react';
|
|
6
5
|
import { EventBus } from './event-bus';
|
|
7
6
|
import { HistoryManager } from './history-manager';
|
|
8
7
|
|
|
@@ -28,8 +27,8 @@ export interface Entries {
|
|
|
28
27
|
exposedInstanceDependencies?: ExposedInstanceDependencies;
|
|
29
28
|
eventBus?: EventBus;
|
|
30
29
|
basename?: string;
|
|
31
|
-
onReady
|
|
32
|
-
onDispose
|
|
30
|
+
onReady?: () => void;
|
|
31
|
+
onDispose?: () => void;
|
|
33
32
|
}
|
|
34
33
|
|
|
35
34
|
export interface IWebComponent {
|
|
@@ -109,7 +108,3 @@ export async function getJson<T = any>(
|
|
|
109
108
|
|
|
110
109
|
return { data: responseJSON, headers: response.headers, url: response.url ?? url };
|
|
111
110
|
}
|
|
112
|
-
|
|
113
|
-
export function useCancelation() {
|
|
114
|
-
return useRef(new AbortController()).current;
|
|
115
|
-
}
|
|
@@ -1,20 +1,8 @@
|
|
|
1
1
|
import { createContext, useContext } from 'react';
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
import { JSON, Serializable } from '../types';
|
|
4
4
|
|
|
5
|
-
|
|
6
|
-
type JSON = { [key: string]: JSONPrimitive | JSON[] | JSON };
|
|
7
|
-
|
|
8
|
-
// Type complexity below is required to support Interfaces being used
|
|
9
|
-
export type MFEContextData<T> = {
|
|
10
|
-
[P in keyof T]: T[P] extends JSONPrimitive
|
|
11
|
-
? T[P]
|
|
12
|
-
: T[P] extends (infer U)[]
|
|
13
|
-
? MFEContextData<U>[]
|
|
14
|
-
: T[P] extends JSON
|
|
15
|
-
? MFEContextData<T[P]>
|
|
16
|
-
: never;
|
|
17
|
-
};
|
|
5
|
+
export type MFEContextData<T> = Serializable<T>;
|
|
18
6
|
|
|
19
7
|
/**
|
|
20
8
|
* Context used to pass data from the host to the MFEs
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { renderHook } from '@testing-library/react';
|
|
2
2
|
import { FC, PropsWithChildren } from 'react';
|
|
3
|
+
import { JSON } from '../../types';
|
|
3
4
|
import { MFEDataContext, useMFEDataContext } from '../mfe-data-context';
|
|
4
5
|
|
|
5
6
|
describe(`[web-components] ${useMFEDataContext.name}`, () => {
|
|
@@ -25,4 +26,39 @@ describe(`[web-components] ${useMFEDataContext.name}`, () => {
|
|
|
25
26
|
expect(subject(Wrapper).result.current).toEqual({});
|
|
26
27
|
});
|
|
27
28
|
});
|
|
29
|
+
|
|
30
|
+
describe('type definitions', () => {
|
|
31
|
+
test('accepts properties typed as JSON', () => {
|
|
32
|
+
renderHook(() => useMFEDataContext<{ data: JSON }>());
|
|
33
|
+
});
|
|
34
|
+
|
|
35
|
+
test('accepts properties typed as Record<string, JSON>', () => {
|
|
36
|
+
renderHook(() => useMFEDataContext<{ metadata: Record<string, JSON> }>());
|
|
37
|
+
});
|
|
38
|
+
|
|
39
|
+
test('accepts primitive properties', () => {
|
|
40
|
+
renderHook(() => useMFEDataContext<{ name: string; count: number; active: boolean }>());
|
|
41
|
+
});
|
|
42
|
+
|
|
43
|
+
test('accepts nested objects and arrays', () => {
|
|
44
|
+
renderHook(() => useMFEDataContext<{ nested: { value: number }; list: string[] }>());
|
|
45
|
+
});
|
|
46
|
+
|
|
47
|
+
test('rejects non-serializable properties', () => {
|
|
48
|
+
// @ts-expect-error Type '() => void' is not assignable to type 'never'.
|
|
49
|
+
renderHook(() => useMFEDataContext<{ callback: () => void }>());
|
|
50
|
+
|
|
51
|
+
// @ts-expect-error Type 'Date' is not assignable to type 'never'.
|
|
52
|
+
renderHook(() => useMFEDataContext<{ created: Date }>());
|
|
53
|
+
|
|
54
|
+
// @ts-expect-error Type 'Map<string, any>' is not assignable to type 'never'.
|
|
55
|
+
renderHook(() => useMFEDataContext<{ lookup: Map<string, any> }>());
|
|
56
|
+
|
|
57
|
+
// @ts-expect-error Type 'Set<string>' is not assignable to type 'never'.
|
|
58
|
+
renderHook(() => useMFEDataContext<{ tags: Set<string> }>());
|
|
59
|
+
|
|
60
|
+
// @ts-expect-error Type 'symbol' is not assignable to type 'never'.
|
|
61
|
+
renderHook(() => useMFEDataContext<{ id: symbol }>());
|
|
62
|
+
});
|
|
63
|
+
});
|
|
28
64
|
});
|
package/src/loader.tsx
CHANGED
|
@@ -20,7 +20,6 @@ import {
|
|
|
20
20
|
EXPOSED_INSTANCE_DEPENDENCIES_TOKEN,
|
|
21
21
|
ExposedInstanceDependencies,
|
|
22
22
|
GetJsonError,
|
|
23
|
-
useCancelation,
|
|
24
23
|
} from './common';
|
|
25
24
|
import { MFEContextData } from './contexts/mfe-data-context';
|
|
26
25
|
import { Delayed } from './delayed';
|
|
@@ -85,7 +84,6 @@ const UnrestrictedLoader = <T,>(props: UnrestrictedLoaderProps<T>, ref: Ref<Load
|
|
|
85
84
|
EXPOSED_INSTANCE_DEPENDENCIES_TOKEN
|
|
86
85
|
);
|
|
87
86
|
const [ldService] = useOptionalDependencies(getLDServiceToken() ?? Symbol());
|
|
88
|
-
const cancelation = useCancelation();
|
|
89
87
|
|
|
90
88
|
const LoadingFallback = useMemo(() => {
|
|
91
89
|
const message = `Loading${isLocalHost(src) ? ` ${src}` : ''}...`;
|
|
@@ -102,23 +100,9 @@ const UnrestrictedLoader = <T,>(props: UnrestrictedLoaderProps<T>, ref: Ref<Load
|
|
|
102
100
|
[exposedInstanceDependencies, ldService]
|
|
103
101
|
);
|
|
104
102
|
|
|
105
|
-
const Loader = useMemo(
|
|
106
|
-
()
|
|
107
|
-
|
|
108
|
-
basename,
|
|
109
|
-
cache,
|
|
110
|
-
cancelation,
|
|
111
|
-
exposedDependencies,
|
|
112
|
-
exposedInstanceDependencies,
|
|
113
|
-
eventBus,
|
|
114
|
-
fallbackSrc,
|
|
115
|
-
isHeadless,
|
|
116
|
-
logService,
|
|
117
|
-
onRequestError,
|
|
118
|
-
retries,
|
|
119
|
-
src,
|
|
120
|
-
}),
|
|
121
|
-
[
|
|
103
|
+
const Loader = useMemo(() => {
|
|
104
|
+
const cancelation = new AbortController();
|
|
105
|
+
return lazyLoader({
|
|
122
106
|
basename,
|
|
123
107
|
cache,
|
|
124
108
|
cancelation,
|
|
@@ -131,8 +115,20 @@ const UnrestrictedLoader = <T,>(props: UnrestrictedLoaderProps<T>, ref: Ref<Load
|
|
|
131
115
|
onRequestError,
|
|
132
116
|
retries,
|
|
133
117
|
src,
|
|
134
|
-
|
|
135
|
-
|
|
118
|
+
});
|
|
119
|
+
}, [
|
|
120
|
+
basename,
|
|
121
|
+
cache,
|
|
122
|
+
exposedDependencies,
|
|
123
|
+
exposedInstanceDependencies,
|
|
124
|
+
eventBus,
|
|
125
|
+
fallbackSrc,
|
|
126
|
+
isHeadless,
|
|
127
|
+
logService,
|
|
128
|
+
onRequestError,
|
|
129
|
+
retries,
|
|
130
|
+
src,
|
|
131
|
+
]);
|
|
136
132
|
|
|
137
133
|
useImperativeHandle(ref, () => eventBus, [eventBus]);
|
|
138
134
|
|
package/src/register.tsx
CHANGED
|
@@ -110,7 +110,7 @@ export function register(Component: ComponentType, light: boolean, options?: Reg
|
|
|
110
110
|
}
|
|
111
111
|
|
|
112
112
|
disconnectedCallback() {
|
|
113
|
-
if (!this.root || this.root
|
|
113
|
+
if (!this.root || this.root.isConnected) {
|
|
114
114
|
return;
|
|
115
115
|
}
|
|
116
116
|
for (const element of this.styles.elements) {
|
|
@@ -118,7 +118,7 @@ export function register(Component: ComponentType, light: boolean, options?: Reg
|
|
|
118
118
|
}
|
|
119
119
|
|
|
120
120
|
this.view?.unmount();
|
|
121
|
-
document.body
|
|
121
|
+
document.body?.removeChild(this.portal!.host);
|
|
122
122
|
this.root = undefined;
|
|
123
123
|
this.portal = undefined;
|
|
124
124
|
this.portalAnvilContainer = undefined;
|
|
@@ -140,7 +140,7 @@ export function register(Component: ComponentType, light: boolean, options?: Reg
|
|
|
140
140
|
this[key as keyof IWebComponent] = value;
|
|
141
141
|
}
|
|
142
142
|
|
|
143
|
-
if (this.styles.loaded === this.styles.total
|
|
143
|
+
if (this.styles.loaded === this.styles.total) {
|
|
144
144
|
this.render();
|
|
145
145
|
}
|
|
146
146
|
};
|
package/src/types.ts
CHANGED
|
@@ -3,7 +3,7 @@ export type JSONPrimitive = string | number | boolean | null | undefined;
|
|
|
3
3
|
export type JSON = JSONPrimitive | { [key: string | number]: JSON } | JSON[];
|
|
4
4
|
|
|
5
5
|
export type Serializable<T> = {
|
|
6
|
-
[P in keyof T]: T[P] extends
|
|
6
|
+
[P in keyof T]: T[P] extends JSON
|
|
7
7
|
? T[P]
|
|
8
8
|
: T[P] extends Function | Date | Map<any, any> | Set<any> | symbol
|
|
9
9
|
? never
|