@servicetitan/hash-browser-router 32.5.0 → 32.7.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/create-hash-browser-history.d.ts +3 -0
- package/dist/create-hash-browser-history.d.ts.map +1 -0
- package/dist/create-hash-browser-history.js +90 -0
- package/dist/create-hash-browser-history.js.map +1 -0
- package/dist/hash-browser-router.d.ts.map +1 -1
- package/dist/hash-browser-router.js +13 -128
- package/dist/hash-browser-router.js.map +1 -1
- package/dist/trigger-sammy-location-change.d.ts +2 -0
- package/dist/trigger-sammy-location-change.d.ts.map +1 -0
- package/dist/trigger-sammy-location-change.js +11 -0
- package/dist/trigger-sammy-location-change.js.map +1 -0
- package/dist/use-history.d.ts +3 -0
- package/dist/use-history.d.ts.map +1 -0
- package/dist/use-history.js +20 -0
- package/dist/use-history.js.map +1 -0
- package/package.json +6 -6
- package/src/__tests__/hash-browser-router.test.tsx +36 -16
- package/src/create-hash-browser-history.ts +108 -0
- package/src/hash-browser-router.tsx +9 -161
- package/src/trigger-sammy-location-change.ts +10 -0
- package/src/use-history.ts +21 -0
- package/dist/singleton-provider.d.ts +0 -8
- package/dist/singleton-provider.d.ts.map +0 -1
- package/dist/singleton-provider.js +0 -18
- package/dist/singleton-provider.js.map +0 -1
- package/src/singleton-provider.tsx +0 -21
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"create-hash-browser-history.d.ts","sourceRoot":"","sources":["../src/create-hash-browser-history.ts"],"names":[],"mappings":"AAAA,OAAO,EACH,0BAA0B,EAE1B,OAAO,EAIV,MAAM,SAAS,CAAC;AAGjB,wBAAgB,wBAAwB,CAAC,OAAO,EAAE,0BAA0B,GAAG,OAAO,CAkErF"}
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
import { createBrowserHistory } from 'history';
|
|
2
|
+
import { triggerSammyLocationChange } from './trigger-sammy-location-change';
|
|
3
|
+
export function createHashBrowserHistory(options) {
|
|
4
|
+
const { basename = '', ...props } = options;
|
|
5
|
+
const parent = createBrowserHistory(props);
|
|
6
|
+
const history = {
|
|
7
|
+
createHref: (location)=>'/#' + basename + parent.createHref(location),
|
|
8
|
+
push: (path, state)=>{
|
|
9
|
+
if (typeof path === 'string') {
|
|
10
|
+
if (path.startsWith('/#')) {
|
|
11
|
+
parent.push(path, state);
|
|
12
|
+
} else {
|
|
13
|
+
parent.push('/#' + basename + path, state);
|
|
14
|
+
}
|
|
15
|
+
} else if (path.hash) {
|
|
16
|
+
parent.push(path);
|
|
17
|
+
} else {
|
|
18
|
+
parent.push(convertHashRouterViewToLocation(path, basename));
|
|
19
|
+
}
|
|
20
|
+
triggerSammyLocationChange();
|
|
21
|
+
},
|
|
22
|
+
replace: (path, state)=>{
|
|
23
|
+
if (typeof path === 'string') {
|
|
24
|
+
if (path.startsWith('/#')) {
|
|
25
|
+
parent.replace(path, state);
|
|
26
|
+
} else {
|
|
27
|
+
parent.replace('/#' + basename + path, state);
|
|
28
|
+
}
|
|
29
|
+
} else if (path.hash) {
|
|
30
|
+
parent.replace(path);
|
|
31
|
+
} else {
|
|
32
|
+
parent.replace(convertHashRouterViewToLocation(path, basename));
|
|
33
|
+
}
|
|
34
|
+
triggerSammyLocationChange();
|
|
35
|
+
},
|
|
36
|
+
block: (prompt)=>{
|
|
37
|
+
if (typeof prompt === 'function') {
|
|
38
|
+
return parent.block((location, action)=>{
|
|
39
|
+
return prompt(convertLocationToHashRouterView(location, basename), action);
|
|
40
|
+
});
|
|
41
|
+
}
|
|
42
|
+
return parent.block(prompt);
|
|
43
|
+
},
|
|
44
|
+
listen: (listener)=>{
|
|
45
|
+
return parent.listen((location, action)=>{
|
|
46
|
+
listener(convertLocationToHashRouterView(location, basename), action);
|
|
47
|
+
});
|
|
48
|
+
},
|
|
49
|
+
get location () {
|
|
50
|
+
return convertLocationToHashRouterView(parent.location, basename);
|
|
51
|
+
},
|
|
52
|
+
set location (l){
|
|
53
|
+
parent.location = l;
|
|
54
|
+
}
|
|
55
|
+
};
|
|
56
|
+
return Object.setPrototypeOf(history, parent);
|
|
57
|
+
}
|
|
58
|
+
function convertHashRouterViewToLocation(location, basename) {
|
|
59
|
+
const { search = '', pathname, ...props } = location;
|
|
60
|
+
const hash = pathname !== undefined ? basename + pathname + search : undefined;
|
|
61
|
+
return {
|
|
62
|
+
...props,
|
|
63
|
+
pathname: '/',
|
|
64
|
+
search: '',
|
|
65
|
+
hash
|
|
66
|
+
};
|
|
67
|
+
}
|
|
68
|
+
function convertLocationToHashRouterView(location, basename) {
|
|
69
|
+
let pathname = location.hash ? stripBasename(location.hash.substring(1), basename) : '/';
|
|
70
|
+
let search = '';
|
|
71
|
+
const index = pathname.indexOf('?');
|
|
72
|
+
if (index >= 0) {
|
|
73
|
+
search = pathname.substring(index);
|
|
74
|
+
pathname = pathname.substring(0, index);
|
|
75
|
+
}
|
|
76
|
+
return {
|
|
77
|
+
...location,
|
|
78
|
+
pathname,
|
|
79
|
+
search,
|
|
80
|
+
hash: ''
|
|
81
|
+
};
|
|
82
|
+
}
|
|
83
|
+
function hasBasename(path, basename) {
|
|
84
|
+
return basename && path.toLowerCase().startsWith(basename.toLowerCase()) && '/?#'.indexOf(path.charAt(basename.length)) !== -1;
|
|
85
|
+
}
|
|
86
|
+
function stripBasename(path, basename) {
|
|
87
|
+
return hasBasename(path, basename) ? path.substring(basename.length) : path;
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
//# sourceMappingURL=create-hash-browser-history.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/create-hash-browser-history.ts"],"sourcesContent":["import {\n BrowserHistoryBuildOptions,\n createBrowserHistory,\n History,\n Location,\n LocationDescriptorObject,\n LocationState,\n} from 'history';\nimport { triggerSammyLocationChange } from './trigger-sammy-location-change';\n\nexport function createHashBrowserHistory(options: BrowserHistoryBuildOptions): History {\n const { basename = '', ...props } = options;\n\n const parent = createBrowserHistory(props);\n\n const history: Omit<History, 'length' | 'action' | 'go' | 'goBack' | 'goForward'> = {\n createHref: location => '/#' + basename + parent.createHref(location),\n\n push: (path, state?: LocationState) => {\n if (typeof path === 'string') {\n if (path.startsWith('/#')) {\n parent.push(path, state);\n } else {\n parent.push('/#' + basename + path, state);\n }\n } else if (path.hash) {\n parent.push(path);\n } else {\n parent.push(convertHashRouterViewToLocation(path, basename));\n }\n\n triggerSammyLocationChange();\n },\n\n replace: (path, state?: LocationState) => {\n if (typeof path === 'string') {\n if (path.startsWith('/#')) {\n parent.replace(path, state);\n } else {\n parent.replace('/#' + basename + path, state);\n }\n } else if (path.hash) {\n parent.replace(path);\n } else {\n parent.replace(convertHashRouterViewToLocation(path, basename));\n }\n\n triggerSammyLocationChange();\n },\n\n block: prompt => {\n if (typeof prompt === 'function') {\n return parent.block((location, action) => {\n return prompt(convertLocationToHashRouterView(location, basename), action);\n });\n }\n\n return parent.block(prompt);\n },\n\n listen: listener => {\n return parent.listen((location, action) => {\n listener(convertLocationToHashRouterView(location, basename), action);\n });\n },\n\n get location() {\n return convertLocationToHashRouterView(parent.location, basename);\n },\n\n set location(l) {\n parent.location = l;\n },\n };\n\n return Object.setPrototypeOf(history, parent);\n}\n\nfunction convertHashRouterViewToLocation(location: LocationDescriptorObject, basename: string) {\n const { search = '', pathname, ...props } = location;\n const hash = pathname !== undefined ? basename + pathname + search : undefined;\n return { ...props, pathname: '/', search: '', hash };\n}\n\nfunction convertLocationToHashRouterView(location: Location, basename: string) {\n let pathname = location.hash ? stripBasename(location.hash.substring(1), basename) : '/';\n let search = '';\n\n const index = pathname.indexOf('?');\n if (index >= 0) {\n search = pathname.substring(index);\n pathname = pathname.substring(0, index);\n }\n\n return { ...location, pathname, search, hash: '' };\n}\n\nfunction hasBasename(path: string, basename: string) {\n return (\n basename &&\n path.toLowerCase().startsWith(basename.toLowerCase()) &&\n '/?#'.indexOf(path.charAt(basename.length)) !== -1\n );\n}\n\nfunction stripBasename(path: string, basename: string) {\n return hasBasename(path, basename) ? path.substring(basename.length) : path;\n}\n"],"names":["createBrowserHistory","triggerSammyLocationChange","createHashBrowserHistory","options","basename","props","parent","history","createHref","location","push","path","state","startsWith","hash","convertHashRouterViewToLocation","replace","block","prompt","action","convertLocationToHashRouterView","listen","listener","l","Object","setPrototypeOf","search","pathname","undefined","stripBasename","substring","index","indexOf","hasBasename","toLowerCase","charAt","length"],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"hash-browser-router.d.ts","sourceRoot":"","sources":["../src/hash-browser-router.tsx"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"hash-browser-router.d.ts","sourceRoot":"","sources":["../src/hash-browser-router.tsx"],"names":[],"mappings":"AAEA,OAAO,EAAE,EAAE,EAAE,MAAM,OAAO,CAAC;AAC3B,OAAO,EAAE,kBAAkB,EAAU,MAAM,kBAAkB,CAAC;AAG9D,eAAO,MAAM,iBAAiB,EAAE,EAAE,CAAC,kBAAkB,CAKnD,CAAC"}
|
|
@@ -1,136 +1,21 @@
|
|
|
1
1
|
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
-
import {
|
|
3
|
-
import { useRef, useEffect } from 'react';
|
|
4
|
-
import { Router } from 'react-router-dom';
|
|
5
|
-
import { useDependencies } from '@servicetitan/react-ioc';
|
|
2
|
+
import { provide } from '@servicetitan/react-ioc';
|
|
6
3
|
import { HistoryManager } from '@servicetitan/web-components';
|
|
7
|
-
import {
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
history,
|
|
18
|
-
historyManager
|
|
19
|
-
]);
|
|
20
|
-
return history;
|
|
21
|
-
}
|
|
22
|
-
const HashBrowserRouterUnwrapped = (props)=>{
|
|
4
|
+
import { Router } from 'react-router-dom';
|
|
5
|
+
import { useHistory } from './use-history';
|
|
6
|
+
export const HashBrowserRouter = provide({
|
|
7
|
+
singletons: [
|
|
8
|
+
{
|
|
9
|
+
provide: HistoryManager,
|
|
10
|
+
inherit: true
|
|
11
|
+
}
|
|
12
|
+
]
|
|
13
|
+
})((props)=>{
|
|
23
14
|
const history = useHistory(props);
|
|
24
|
-
const { children } = props;
|
|
25
15
|
return /*#__PURE__*/ _jsx(Router, {
|
|
26
16
|
history: history,
|
|
27
|
-
|
|
28
|
-
});
|
|
29
|
-
};
|
|
30
|
-
export const HashBrowserRouter = (props)=>/*#__PURE__*/ _jsx(SingletonProvider, {
|
|
31
|
-
provide: HistoryManager,
|
|
32
|
-
children: /*#__PURE__*/ _jsx(HashBrowserRouterUnwrapped, {
|
|
33
|
-
...props
|
|
34
|
-
})
|
|
35
|
-
});
|
|
36
|
-
function createHashBrowserHistory({ basename = '', ...props }) {
|
|
37
|
-
function convertLocationToHashRouterView(l1) {
|
|
38
|
-
let search = '';
|
|
39
|
-
let pathname = l1.hash ? l1.hash.substring(1) : '/';
|
|
40
|
-
if (basename) {
|
|
41
|
-
pathname = stripBasename(pathname, basename);
|
|
42
|
-
}
|
|
43
|
-
const index = pathname.indexOf('?');
|
|
44
|
-
if (index !== -1) {
|
|
45
|
-
search = pathname.substring(index);
|
|
46
|
-
pathname = pathname.substring(0, index);
|
|
47
|
-
}
|
|
48
|
-
return {
|
|
49
|
-
...l1,
|
|
50
|
-
search,
|
|
51
|
-
pathname,
|
|
52
|
-
hash: ''
|
|
53
|
-
};
|
|
54
|
-
}
|
|
55
|
-
const parent = createBrowserHistory(props);
|
|
56
|
-
const history = {
|
|
57
|
-
createHref: (location)=>'/#' + basename + parent.createHref(location),
|
|
58
|
-
push: (path, state)=>{
|
|
59
|
-
if (typeof path === 'string') {
|
|
60
|
-
if (path.startsWith('/#')) {
|
|
61
|
-
parent.push(path, state);
|
|
62
|
-
} else {
|
|
63
|
-
parent.push('/#' + basename + path, state);
|
|
64
|
-
}
|
|
65
|
-
} else {
|
|
66
|
-
if (path.hash) {
|
|
67
|
-
parent.push(path);
|
|
68
|
-
} else {
|
|
69
|
-
parent.push({
|
|
70
|
-
...path,
|
|
71
|
-
pathname: '/',
|
|
72
|
-
hash: path.pathname !== undefined ? basename + path.pathname : undefined
|
|
73
|
-
});
|
|
74
|
-
}
|
|
75
|
-
}
|
|
76
|
-
triggerSammyLocationChange();
|
|
77
|
-
},
|
|
78
|
-
replace: (path, state)=>{
|
|
79
|
-
if (typeof path === 'string') {
|
|
80
|
-
if (path.startsWith('/#')) {
|
|
81
|
-
parent.replace(path, state);
|
|
82
|
-
} else {
|
|
83
|
-
parent.replace('/#' + basename + path, state);
|
|
84
|
-
}
|
|
85
|
-
} else {
|
|
86
|
-
if (path.hash) {
|
|
87
|
-
parent.replace(path);
|
|
88
|
-
} else {
|
|
89
|
-
parent.replace({
|
|
90
|
-
...path,
|
|
91
|
-
pathname: '/',
|
|
92
|
-
hash: path.pathname !== undefined ? basename + path.pathname : undefined
|
|
93
|
-
});
|
|
94
|
-
}
|
|
95
|
-
}
|
|
96
|
-
triggerSammyLocationChange();
|
|
97
|
-
},
|
|
98
|
-
block: (prompt)=>{
|
|
99
|
-
if (typeof prompt === 'function') {
|
|
100
|
-
return parent.block((origLocation, action)=>{
|
|
101
|
-
return prompt(convertLocationToHashRouterView(origLocation), action);
|
|
102
|
-
});
|
|
103
|
-
}
|
|
104
|
-
return parent.block(prompt);
|
|
105
|
-
},
|
|
106
|
-
listen: (listener)=>{
|
|
107
|
-
return parent.listen((origLocation, action)=>{
|
|
108
|
-
listener(convertLocationToHashRouterView(origLocation), action);
|
|
109
|
-
});
|
|
110
|
-
},
|
|
111
|
-
get location () {
|
|
112
|
-
return convertLocationToHashRouterView(parent.location);
|
|
113
|
-
},
|
|
114
|
-
set location (l){
|
|
115
|
-
parent.location = l;
|
|
116
|
-
}
|
|
117
|
-
};
|
|
118
|
-
return Object.setPrototypeOf(history, parent);
|
|
119
|
-
}
|
|
120
|
-
function hasBasename(path, prefix) {
|
|
121
|
-
return path.toLowerCase().indexOf(prefix.toLowerCase()) === 0 && '/?#'.indexOf(path.charAt(prefix.length)) !== -1;
|
|
122
|
-
}
|
|
123
|
-
function stripBasename(path, prefix) {
|
|
124
|
-
return hasBasename(path, prefix) ? path.substring(prefix.length) : path;
|
|
125
|
-
}
|
|
126
|
-
function triggerSammyLocationChange() {
|
|
127
|
-
/*
|
|
128
|
-
* We have to skip ahead `componentWillUnmount` to avoid «race condition»
|
|
129
|
-
* e.g. in the SettingsLayout component "window.app.swap" could be fired after
|
|
130
|
-
* the new Sammy route load and it would hide that page.
|
|
131
|
-
*/ setTimeout(()=>{
|
|
132
|
-
window.dispatchEvent(new HashChangeEvent('hashchange'));
|
|
17
|
+
...props
|
|
133
18
|
});
|
|
134
|
-
}
|
|
19
|
+
});
|
|
135
20
|
|
|
136
21
|
//# sourceMappingURL=hash-browser-router.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/hash-browser-router.tsx"],"sourcesContent":["import {
|
|
1
|
+
{"version":3,"sources":["../src/hash-browser-router.tsx"],"sourcesContent":["import { provide } from '@servicetitan/react-ioc';\nimport { HistoryManager } from '@servicetitan/web-components';\nimport { FC } from 'react';\nimport { BrowserRouterProps, Router } from 'react-router-dom';\nimport { useHistory } from './use-history';\n\nexport const HashBrowserRouter: FC<BrowserRouterProps> = provide({\n singletons: [{ provide: HistoryManager, inherit: true }],\n})(props => {\n const history = useHistory(props);\n return <Router history={history} {...props} />;\n});\n"],"names":["provide","HistoryManager","Router","useHistory","HashBrowserRouter","singletons","inherit","props","history"],"mappings":";AAAA,SAASA,OAAO,QAAQ,0BAA0B;AAClD,SAASC,cAAc,QAAQ,+BAA+B;AAE9D,SAA6BC,MAAM,QAAQ,mBAAmB;AAC9D,SAASC,UAAU,QAAQ,gBAAgB;AAE3C,OAAO,MAAMC,oBAA4CJ,QAAQ;IAC7DK,YAAY;QAAC;YAAEL,SAASC;YAAgBK,SAAS;QAAK;KAAE;AAC5D,GAAGC,CAAAA;IACC,MAAMC,UAAUL,WAAWI;IAC3B,qBAAO,KAACL;QAAOM,SAASA;QAAU,GAAGD,KAAK;;AAC9C,GAAG"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"trigger-sammy-location-change.d.ts","sourceRoot":"","sources":["../src/trigger-sammy-location-change.ts"],"names":[],"mappings":"AAAA,wBAAgB,0BAA0B,SASzC"}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
export function triggerSammyLocationChange() {
|
|
2
|
+
/*
|
|
3
|
+
* We have to skip ahead `componentWillUnmount` to avoid «race condition»
|
|
4
|
+
* e.g. in the SettingsLayout component "window.app.swap" could be fired after
|
|
5
|
+
* the new Sammy route load and it would hide that page.
|
|
6
|
+
*/ setTimeout(()=>{
|
|
7
|
+
window.dispatchEvent(new HashChangeEvent('hashchange'));
|
|
8
|
+
});
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
//# sourceMappingURL=trigger-sammy-location-change.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/trigger-sammy-location-change.ts"],"sourcesContent":["export function triggerSammyLocationChange() {\n /*\n * We have to skip ahead `componentWillUnmount` to avoid «race condition»\n * e.g. in the SettingsLayout component \"window.app.swap\" could be fired after\n * the new Sammy route load and it would hide that page.\n */\n setTimeout(() => {\n window.dispatchEvent(new HashChangeEvent('hashchange'));\n });\n}\n"],"names":["triggerSammyLocationChange","setTimeout","window","dispatchEvent","HashChangeEvent"],"mappings":"AAAA,OAAO,SAASA;IACZ;;;;KAIC,GACDC,WAAW;QACPC,OAAOC,aAAa,CAAC,IAAIC,gBAAgB;IAC7C;AACJ"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"use-history.d.ts","sourceRoot":"","sources":["../src/use-history.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,0BAA0B,EAAE,MAAM,SAAS,CAAC;AAIrD,wBAAgB,UAAU,CAAC,OAAO,EAAE,0BAA0B,sCAc7D"}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { useDependencies } from '@servicetitan/react-ioc';
|
|
2
|
+
import { HistoryManager } from '@servicetitan/web-components';
|
|
3
|
+
import { useEffect, useRef } from 'react';
|
|
4
|
+
import { createHashBrowserHistory } from './create-hash-browser-history';
|
|
5
|
+
export function useHistory(options) {
|
|
6
|
+
const history = useRef(createHashBrowserHistory(options)).current;
|
|
7
|
+
const [historyManager] = useDependencies(HistoryManager);
|
|
8
|
+
useEffect(()=>{
|
|
9
|
+
historyManager.register(history);
|
|
10
|
+
return ()=>{
|
|
11
|
+
historyManager.unregister(history);
|
|
12
|
+
};
|
|
13
|
+
}, [
|
|
14
|
+
history,
|
|
15
|
+
historyManager
|
|
16
|
+
]);
|
|
17
|
+
return history;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
//# sourceMappingURL=use-history.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/use-history.ts"],"sourcesContent":["import { useDependencies } from '@servicetitan/react-ioc';\nimport { HistoryManager } from '@servicetitan/web-components';\nimport { BrowserHistoryBuildOptions } from 'history';\nimport { useEffect, useRef } from 'react';\nimport { createHashBrowserHistory } from './create-hash-browser-history';\n\nexport function useHistory(options: BrowserHistoryBuildOptions) {\n const history = useRef(createHashBrowserHistory(options)).current;\n\n const [historyManager] = useDependencies(HistoryManager);\n\n useEffect(() => {\n historyManager.register(history);\n\n return () => {\n historyManager.unregister(history);\n };\n }, [history, historyManager]);\n\n return history;\n}\n"],"names":["useDependencies","HistoryManager","useEffect","useRef","createHashBrowserHistory","useHistory","options","history","current","historyManager","register","unregister"],"mappings":"AAAA,SAASA,eAAe,QAAQ,0BAA0B;AAC1D,SAASC,cAAc,QAAQ,+BAA+B;AAE9D,SAASC,SAAS,EAAEC,MAAM,QAAQ,QAAQ;AAC1C,SAASC,wBAAwB,QAAQ,gCAAgC;AAEzE,OAAO,SAASC,WAAWC,OAAmC;IAC1D,MAAMC,UAAUJ,OAAOC,yBAAyBE,UAAUE,OAAO;IAEjE,MAAM,CAACC,eAAe,GAAGT,gBAAgBC;IAEzCC,UAAU;QACNO,eAAeC,QAAQ,CAACH;QAExB,OAAO;YACHE,eAAeE,UAAU,CAACJ;QAC9B;IACJ,GAAG;QAACA;QAASE;KAAe;IAE5B,OAAOF;AACX"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@servicetitan/hash-browser-router",
|
|
3
|
-
"version": "32.
|
|
3
|
+
"version": "32.7.0",
|
|
4
4
|
"description": "",
|
|
5
5
|
"repository": {
|
|
6
6
|
"type": "git",
|
|
@@ -15,8 +15,8 @@
|
|
|
15
15
|
"src"
|
|
16
16
|
],
|
|
17
17
|
"devDependencies": {
|
|
18
|
-
"@servicetitan/react-ioc": "32.
|
|
19
|
-
"@servicetitan/web-components": "32.
|
|
18
|
+
"@servicetitan/react-ioc": "32.7.0",
|
|
19
|
+
"@servicetitan/web-components": "32.7.0",
|
|
20
20
|
"@testing-library/dom": "^10.4.1",
|
|
21
21
|
"@testing-library/react": "^16.3.0",
|
|
22
22
|
"@types/history": "~4.7.10",
|
|
@@ -27,8 +27,8 @@
|
|
|
27
27
|
"react-router-dom": "~5.3.0"
|
|
28
28
|
},
|
|
29
29
|
"peerDependencies": {
|
|
30
|
-
"@servicetitan/react-ioc": "32.
|
|
31
|
-
"@servicetitan/web-components": "32.
|
|
30
|
+
"@servicetitan/react-ioc": "32.7.0",
|
|
31
|
+
"@servicetitan/web-components": "32.7.0",
|
|
32
32
|
"history": "~4.10.1",
|
|
33
33
|
"react": ">=17.0.2",
|
|
34
34
|
"react-router-dom": "~5.3.0"
|
|
@@ -39,5 +39,5 @@
|
|
|
39
39
|
"cli": {
|
|
40
40
|
"webpack": false
|
|
41
41
|
},
|
|
42
|
-
"gitHead": "
|
|
42
|
+
"gitHead": "673fb6b56865da309c09f91b4ebf30aaf815a562"
|
|
43
43
|
}
|
|
@@ -80,19 +80,35 @@ describe(`${HashBrowserRouter.name}`, () => {
|
|
|
80
80
|
});
|
|
81
81
|
}
|
|
82
82
|
|
|
83
|
-
beforeEach(() => (location = '/foo'));
|
|
83
|
+
beforeEach(() => (location = '/foo?baz=qux')); // testing location with search
|
|
84
|
+
|
|
85
|
+
function getPathname(url: string) {
|
|
86
|
+
return RegExp(/^([^?]+)/).exec(url)![0];
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
function getSearch(url: string) {
|
|
90
|
+
return RegExp(/(\?.+)$/).exec(url)![0];
|
|
91
|
+
}
|
|
84
92
|
|
|
85
93
|
itPushesAndReplacesWith('/#{location}', {
|
|
86
94
|
url: () => `/#${location}`,
|
|
87
|
-
prompt: () => ({
|
|
95
|
+
prompt: () => ({
|
|
96
|
+
pathname: getPathname(location),
|
|
97
|
+
search: getSearch(location),
|
|
98
|
+
hash: '',
|
|
99
|
+
}),
|
|
88
100
|
});
|
|
89
101
|
|
|
90
102
|
describe('when location starts with "/#"', () => {
|
|
91
|
-
beforeEach(() => (location = '/#bar'));
|
|
103
|
+
beforeEach(() => (location = '/#bar?baz=qux'));
|
|
92
104
|
|
|
93
105
|
itPushesAndReplacesWith('location', {
|
|
94
106
|
url: () => `${location}`,
|
|
95
|
-
prompt: () => ({
|
|
107
|
+
prompt: () => ({
|
|
108
|
+
pathname: getPathname(location).replace('/#', ''),
|
|
109
|
+
search: getSearch(location),
|
|
110
|
+
hash: '',
|
|
111
|
+
}),
|
|
96
112
|
});
|
|
97
113
|
});
|
|
98
114
|
|
|
@@ -101,18 +117,22 @@ describe(`${HashBrowserRouter.name}`, () => {
|
|
|
101
117
|
|
|
102
118
|
itPushesAndReplacesWith('"/#{basename}{location}"', {
|
|
103
119
|
url: () => `/#${props.basename}${location}`,
|
|
104
|
-
prompt: () => ({
|
|
120
|
+
prompt: () => ({
|
|
121
|
+
pathname: getPathname(location),
|
|
122
|
+
search: getSearch(location),
|
|
123
|
+
hash: '',
|
|
124
|
+
}),
|
|
105
125
|
});
|
|
106
126
|
});
|
|
107
127
|
|
|
108
128
|
describe('with location object', () => {
|
|
109
|
-
beforeEach(() => (locationObj = { pathname: '/foo?baz=qux' }));
|
|
129
|
+
beforeEach(() => (locationObj = { pathname: '/foo', search: '?baz=qux' }));
|
|
110
130
|
|
|
111
|
-
itPushesAndReplacesWith('"/#{location.pathname}"', {
|
|
112
|
-
url: () => `/#${locationObj.pathname}`,
|
|
131
|
+
itPushesAndReplacesWith('"/#{location.pathname}{location.search}"', {
|
|
132
|
+
url: () => `/#${locationObj.pathname}${locationObj.search}`,
|
|
113
133
|
prompt: () => ({
|
|
114
|
-
pathname:
|
|
115
|
-
search:
|
|
134
|
+
pathname: locationObj.pathname,
|
|
135
|
+
search: locationObj.search,
|
|
116
136
|
hash: '',
|
|
117
137
|
}),
|
|
118
138
|
});
|
|
@@ -120,8 +140,8 @@ describe(`${HashBrowserRouter.name}`, () => {
|
|
|
120
140
|
describe('when location includes a hash', () => {
|
|
121
141
|
beforeEach(() => (locationObj.hash = '#bar'));
|
|
122
142
|
|
|
123
|
-
itPushesAndReplacesWith('location', {
|
|
124
|
-
url: () => `${locationObj.pathname}${locationObj.hash}`,
|
|
143
|
+
itPushesAndReplacesWith('/#{location.pathname}{location.search}{location.hash}', {
|
|
144
|
+
url: () => `${locationObj.pathname}${locationObj.search}${locationObj.hash}`,
|
|
125
145
|
prompt: () => ({
|
|
126
146
|
pathname: `${locationObj.hash!.replace('#', '')}`,
|
|
127
147
|
search: '',
|
|
@@ -133,11 +153,11 @@ describe(`${HashBrowserRouter.name}`, () => {
|
|
|
133
153
|
describe('with a basename', () => {
|
|
134
154
|
beforeEach(() => (props.basename = '/baz'));
|
|
135
155
|
|
|
136
|
-
itPushesAndReplacesWith('"/#{basename}{location.pathname}', {
|
|
137
|
-
url: () => `/#${props.basename}${locationObj.pathname}`,
|
|
156
|
+
itPushesAndReplacesWith('"/#{basename}{location.pathname}{location.search}', {
|
|
157
|
+
url: () => `/#${props.basename}${locationObj.pathname}${locationObj.search}`,
|
|
138
158
|
prompt: () => ({
|
|
139
|
-
pathname:
|
|
140
|
-
search:
|
|
159
|
+
pathname: locationObj.pathname,
|
|
160
|
+
search: locationObj.search,
|
|
141
161
|
hash: '',
|
|
142
162
|
}),
|
|
143
163
|
});
|
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
import {
|
|
2
|
+
BrowserHistoryBuildOptions,
|
|
3
|
+
createBrowserHistory,
|
|
4
|
+
History,
|
|
5
|
+
Location,
|
|
6
|
+
LocationDescriptorObject,
|
|
7
|
+
LocationState,
|
|
8
|
+
} from 'history';
|
|
9
|
+
import { triggerSammyLocationChange } from './trigger-sammy-location-change';
|
|
10
|
+
|
|
11
|
+
export function createHashBrowserHistory(options: BrowserHistoryBuildOptions): History {
|
|
12
|
+
const { basename = '', ...props } = options;
|
|
13
|
+
|
|
14
|
+
const parent = createBrowserHistory(props);
|
|
15
|
+
|
|
16
|
+
const history: Omit<History, 'length' | 'action' | 'go' | 'goBack' | 'goForward'> = {
|
|
17
|
+
createHref: location => '/#' + basename + parent.createHref(location),
|
|
18
|
+
|
|
19
|
+
push: (path, state?: LocationState) => {
|
|
20
|
+
if (typeof path === 'string') {
|
|
21
|
+
if (path.startsWith('/#')) {
|
|
22
|
+
parent.push(path, state);
|
|
23
|
+
} else {
|
|
24
|
+
parent.push('/#' + basename + path, state);
|
|
25
|
+
}
|
|
26
|
+
} else if (path.hash) {
|
|
27
|
+
parent.push(path);
|
|
28
|
+
} else {
|
|
29
|
+
parent.push(convertHashRouterViewToLocation(path, basename));
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
triggerSammyLocationChange();
|
|
33
|
+
},
|
|
34
|
+
|
|
35
|
+
replace: (path, state?: LocationState) => {
|
|
36
|
+
if (typeof path === 'string') {
|
|
37
|
+
if (path.startsWith('/#')) {
|
|
38
|
+
parent.replace(path, state);
|
|
39
|
+
} else {
|
|
40
|
+
parent.replace('/#' + basename + path, state);
|
|
41
|
+
}
|
|
42
|
+
} else if (path.hash) {
|
|
43
|
+
parent.replace(path);
|
|
44
|
+
} else {
|
|
45
|
+
parent.replace(convertHashRouterViewToLocation(path, basename));
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
triggerSammyLocationChange();
|
|
49
|
+
},
|
|
50
|
+
|
|
51
|
+
block: prompt => {
|
|
52
|
+
if (typeof prompt === 'function') {
|
|
53
|
+
return parent.block((location, action) => {
|
|
54
|
+
return prompt(convertLocationToHashRouterView(location, basename), action);
|
|
55
|
+
});
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
return parent.block(prompt);
|
|
59
|
+
},
|
|
60
|
+
|
|
61
|
+
listen: listener => {
|
|
62
|
+
return parent.listen((location, action) => {
|
|
63
|
+
listener(convertLocationToHashRouterView(location, basename), action);
|
|
64
|
+
});
|
|
65
|
+
},
|
|
66
|
+
|
|
67
|
+
get location() {
|
|
68
|
+
return convertLocationToHashRouterView(parent.location, basename);
|
|
69
|
+
},
|
|
70
|
+
|
|
71
|
+
set location(l) {
|
|
72
|
+
parent.location = l;
|
|
73
|
+
},
|
|
74
|
+
};
|
|
75
|
+
|
|
76
|
+
return Object.setPrototypeOf(history, parent);
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
function convertHashRouterViewToLocation(location: LocationDescriptorObject, basename: string) {
|
|
80
|
+
const { search = '', pathname, ...props } = location;
|
|
81
|
+
const hash = pathname !== undefined ? basename + pathname + search : undefined;
|
|
82
|
+
return { ...props, pathname: '/', search: '', hash };
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
function convertLocationToHashRouterView(location: Location, basename: string) {
|
|
86
|
+
let pathname = location.hash ? stripBasename(location.hash.substring(1), basename) : '/';
|
|
87
|
+
let search = '';
|
|
88
|
+
|
|
89
|
+
const index = pathname.indexOf('?');
|
|
90
|
+
if (index >= 0) {
|
|
91
|
+
search = pathname.substring(index);
|
|
92
|
+
pathname = pathname.substring(0, index);
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
return { ...location, pathname, search, hash: '' };
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
function hasBasename(path: string, basename: string) {
|
|
99
|
+
return (
|
|
100
|
+
basename &&
|
|
101
|
+
path.toLowerCase().startsWith(basename.toLowerCase()) &&
|
|
102
|
+
'/?#'.indexOf(path.charAt(basename.length)) !== -1
|
|
103
|
+
);
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
function stripBasename(path: string, basename: string) {
|
|
107
|
+
return hasBasename(path, basename) ? path.substring(basename.length) : path;
|
|
108
|
+
}
|
|
@@ -1,164 +1,12 @@
|
|
|
1
|
-
import {
|
|
2
|
-
BrowserHistoryBuildOptions,
|
|
3
|
-
History,
|
|
4
|
-
Location,
|
|
5
|
-
LocationState,
|
|
6
|
-
createBrowserHistory,
|
|
7
|
-
} from 'history';
|
|
8
|
-
import { useRef, FC, useEffect } from 'react';
|
|
9
|
-
import { BrowserRouterProps, Router } from 'react-router-dom';
|
|
10
|
-
|
|
11
|
-
import { useDependencies } from '@servicetitan/react-ioc';
|
|
1
|
+
import { provide } from '@servicetitan/react-ioc';
|
|
12
2
|
import { HistoryManager } from '@servicetitan/web-components';
|
|
3
|
+
import { FC } from 'react';
|
|
4
|
+
import { BrowserRouterProps, Router } from 'react-router-dom';
|
|
5
|
+
import { useHistory } from './use-history';
|
|
13
6
|
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
const history = useRef(createHashBrowserHistory(options)).current;
|
|
18
|
-
|
|
19
|
-
const [historyManager] = useDependencies(HistoryManager);
|
|
20
|
-
|
|
21
|
-
useEffect(() => {
|
|
22
|
-
historyManager.register(history);
|
|
23
|
-
|
|
24
|
-
return () => {
|
|
25
|
-
historyManager.unregister(history);
|
|
26
|
-
};
|
|
27
|
-
}, [history, historyManager]);
|
|
28
|
-
|
|
29
|
-
return history;
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
const HashBrowserRouterUnwrapped: FC<BrowserRouterProps> = props => {
|
|
7
|
+
export const HashBrowserRouter: FC<BrowserRouterProps> = provide({
|
|
8
|
+
singletons: [{ provide: HistoryManager, inherit: true }],
|
|
9
|
+
})(props => {
|
|
33
10
|
const history = useHistory(props);
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
return <Router history={history}>{children}</Router>;
|
|
37
|
-
};
|
|
38
|
-
|
|
39
|
-
export const HashBrowserRouter: FC<BrowserRouterProps> = props => (
|
|
40
|
-
<SingletonProvider provide={HistoryManager}>
|
|
41
|
-
<HashBrowserRouterUnwrapped {...props} />
|
|
42
|
-
</SingletonProvider>
|
|
43
|
-
);
|
|
44
|
-
|
|
45
|
-
function createHashBrowserHistory({
|
|
46
|
-
basename = '',
|
|
47
|
-
...props
|
|
48
|
-
}: BrowserHistoryBuildOptions): History {
|
|
49
|
-
function convertLocationToHashRouterView(l: Location): Location {
|
|
50
|
-
let search = '';
|
|
51
|
-
let pathname = l.hash ? l.hash.substring(1) : '/';
|
|
52
|
-
if (basename) {
|
|
53
|
-
pathname = stripBasename(pathname, basename);
|
|
54
|
-
}
|
|
55
|
-
const index = pathname.indexOf('?');
|
|
56
|
-
if (index !== -1) {
|
|
57
|
-
search = pathname.substring(index);
|
|
58
|
-
pathname = pathname.substring(0, index);
|
|
59
|
-
}
|
|
60
|
-
return {
|
|
61
|
-
...l,
|
|
62
|
-
search,
|
|
63
|
-
pathname,
|
|
64
|
-
hash: '',
|
|
65
|
-
};
|
|
66
|
-
}
|
|
67
|
-
|
|
68
|
-
const parent = createBrowserHistory(props);
|
|
69
|
-
|
|
70
|
-
const history: Omit<History, 'length' | 'action' | 'go' | 'goBack' | 'goForward'> = {
|
|
71
|
-
createHref: location => '/#' + basename + parent.createHref(location),
|
|
72
|
-
|
|
73
|
-
push: (path, state?: LocationState) => {
|
|
74
|
-
if (typeof path === 'string') {
|
|
75
|
-
if (path.startsWith('/#')) {
|
|
76
|
-
parent.push(path, state);
|
|
77
|
-
} else {
|
|
78
|
-
parent.push('/#' + basename + path, state);
|
|
79
|
-
}
|
|
80
|
-
} else {
|
|
81
|
-
if (path.hash) {
|
|
82
|
-
parent.push(path);
|
|
83
|
-
} else {
|
|
84
|
-
parent.push({
|
|
85
|
-
...path,
|
|
86
|
-
pathname: '/',
|
|
87
|
-
hash: path.pathname !== undefined ? basename + path.pathname : undefined,
|
|
88
|
-
});
|
|
89
|
-
}
|
|
90
|
-
}
|
|
91
|
-
|
|
92
|
-
triggerSammyLocationChange();
|
|
93
|
-
},
|
|
94
|
-
|
|
95
|
-
replace: (path, state?: LocationState) => {
|
|
96
|
-
if (typeof path === 'string') {
|
|
97
|
-
if (path.startsWith('/#')) {
|
|
98
|
-
parent.replace(path, state);
|
|
99
|
-
} else {
|
|
100
|
-
parent.replace('/#' + basename + path, state);
|
|
101
|
-
}
|
|
102
|
-
} else {
|
|
103
|
-
if (path.hash) {
|
|
104
|
-
parent.replace(path);
|
|
105
|
-
} else {
|
|
106
|
-
parent.replace({
|
|
107
|
-
...path,
|
|
108
|
-
pathname: '/',
|
|
109
|
-
hash: path.pathname !== undefined ? basename + path.pathname : undefined,
|
|
110
|
-
});
|
|
111
|
-
}
|
|
112
|
-
}
|
|
113
|
-
|
|
114
|
-
triggerSammyLocationChange();
|
|
115
|
-
},
|
|
116
|
-
|
|
117
|
-
block: prompt => {
|
|
118
|
-
if (typeof prompt === 'function') {
|
|
119
|
-
return parent.block((origLocation, action) => {
|
|
120
|
-
return prompt(convertLocationToHashRouterView(origLocation), action);
|
|
121
|
-
});
|
|
122
|
-
}
|
|
123
|
-
|
|
124
|
-
return parent.block(prompt);
|
|
125
|
-
},
|
|
126
|
-
|
|
127
|
-
listen: listener => {
|
|
128
|
-
return parent.listen((origLocation, action) => {
|
|
129
|
-
listener(convertLocationToHashRouterView(origLocation), action);
|
|
130
|
-
});
|
|
131
|
-
},
|
|
132
|
-
|
|
133
|
-
get location() {
|
|
134
|
-
return convertLocationToHashRouterView(parent.location);
|
|
135
|
-
},
|
|
136
|
-
set location(l) {
|
|
137
|
-
parent.location = l;
|
|
138
|
-
},
|
|
139
|
-
};
|
|
140
|
-
|
|
141
|
-
return Object.setPrototypeOf(history, parent);
|
|
142
|
-
}
|
|
143
|
-
|
|
144
|
-
function hasBasename(path: string, prefix: string) {
|
|
145
|
-
return (
|
|
146
|
-
path.toLowerCase().indexOf(prefix.toLowerCase()) === 0 &&
|
|
147
|
-
'/?#'.indexOf(path.charAt(prefix.length)) !== -1
|
|
148
|
-
);
|
|
149
|
-
}
|
|
150
|
-
|
|
151
|
-
function stripBasename(path: string, prefix: string) {
|
|
152
|
-
return hasBasename(path, prefix) ? path.substring(prefix.length) : path;
|
|
153
|
-
}
|
|
154
|
-
|
|
155
|
-
function triggerSammyLocationChange() {
|
|
156
|
-
/*
|
|
157
|
-
* We have to skip ahead `componentWillUnmount` to avoid «race condition»
|
|
158
|
-
* e.g. in the SettingsLayout component "window.app.swap" could be fired after
|
|
159
|
-
* the new Sammy route load and it would hide that page.
|
|
160
|
-
*/
|
|
161
|
-
setTimeout(() => {
|
|
162
|
-
window.dispatchEvent(new HashChangeEvent('hashchange'));
|
|
163
|
-
});
|
|
164
|
-
}
|
|
11
|
+
return <Router history={history} {...props} />;
|
|
12
|
+
});
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
export function triggerSammyLocationChange() {
|
|
2
|
+
/*
|
|
3
|
+
* We have to skip ahead `componentWillUnmount` to avoid «race condition»
|
|
4
|
+
* e.g. in the SettingsLayout component "window.app.swap" could be fired after
|
|
5
|
+
* the new Sammy route load and it would hide that page.
|
|
6
|
+
*/
|
|
7
|
+
setTimeout(() => {
|
|
8
|
+
window.dispatchEvent(new HashChangeEvent('hashchange'));
|
|
9
|
+
});
|
|
10
|
+
}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { useDependencies } from '@servicetitan/react-ioc';
|
|
2
|
+
import { HistoryManager } from '@servicetitan/web-components';
|
|
3
|
+
import { BrowserHistoryBuildOptions } from 'history';
|
|
4
|
+
import { useEffect, useRef } from 'react';
|
|
5
|
+
import { createHashBrowserHistory } from './create-hash-browser-history';
|
|
6
|
+
|
|
7
|
+
export function useHistory(options: BrowserHistoryBuildOptions) {
|
|
8
|
+
const history = useRef(createHashBrowserHistory(options)).current;
|
|
9
|
+
|
|
10
|
+
const [historyManager] = useDependencies(HistoryManager);
|
|
11
|
+
|
|
12
|
+
useEffect(() => {
|
|
13
|
+
historyManager.register(history);
|
|
14
|
+
|
|
15
|
+
return () => {
|
|
16
|
+
historyManager.unregister(history);
|
|
17
|
+
};
|
|
18
|
+
}, [history, historyManager]);
|
|
19
|
+
|
|
20
|
+
return history;
|
|
21
|
+
}
|
|
@@ -1,8 +0,0 @@
|
|
|
1
|
-
import { interfaces } from '@servicetitan/react-ioc';
|
|
2
|
-
interface SingletonProviderProps<T> {
|
|
3
|
-
provide: interfaces.Newable<T>;
|
|
4
|
-
children: JSX.Element;
|
|
5
|
-
}
|
|
6
|
-
export declare const SingletonProvider: <T extends any>({ provide, children, }: SingletonProviderProps<T>) => import("react/jsx-runtime").JSX.Element;
|
|
7
|
-
export {};
|
|
8
|
-
//# sourceMappingURL=singleton-provider.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"singleton-provider.d.ts","sourceRoot":"","sources":["../src/singleton-provider.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAqC,MAAM,yBAAyB,CAAC;AAExF,UAAU,sBAAsB,CAAC,CAAC;IAC9B,OAAO,EAAE,UAAU,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC;IAC/B,QAAQ,EAAE,GAAG,CAAC,OAAO,CAAC;CACzB;AAID,eAAO,MAAM,iBAAiB,GAAI,CAAC,SAAS,GAAG,EAAE,wBAG9C,sBAAsB,CAAC,CAAC,CAAC,4CAQ3B,CAAC"}
|
|
@@ -1,18 +0,0 @@
|
|
|
1
|
-
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
-
import { useOptionalDependencies, Provider } from '@servicetitan/react-ioc';
|
|
3
|
-
// Re-use instance if already exists
|
|
4
|
-
// eslint-disable-next-line @typescript-eslint/no-unnecessary-type-constraint
|
|
5
|
-
export const SingletonProvider = ({ provide, children })=>{
|
|
6
|
-
const [instance] = useOptionalDependencies(provide);
|
|
7
|
-
return /*#__PURE__*/ _jsx(Provider, {
|
|
8
|
-
singletons: [
|
|
9
|
-
instance ? {
|
|
10
|
-
provide,
|
|
11
|
-
useValue: instance
|
|
12
|
-
} : provide
|
|
13
|
-
],
|
|
14
|
-
children: children
|
|
15
|
-
});
|
|
16
|
-
};
|
|
17
|
-
|
|
18
|
-
//# sourceMappingURL=singleton-provider.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/singleton-provider.tsx"],"sourcesContent":["import { interfaces, useOptionalDependencies, Provider } from '@servicetitan/react-ioc';\n\ninterface SingletonProviderProps<T> {\n provide: interfaces.Newable<T>;\n children: JSX.Element;\n}\n\n// Re-use instance if already exists\n// eslint-disable-next-line @typescript-eslint/no-unnecessary-type-constraint\nexport const SingletonProvider = <T extends any>({\n provide,\n children,\n}: SingletonProviderProps<T>) => {\n const [instance] = useOptionalDependencies(provide);\n\n return (\n <Provider singletons={[instance ? { provide, useValue: instance } : provide]}>\n {children}\n </Provider>\n );\n};\n"],"names":["useOptionalDependencies","Provider","SingletonProvider","provide","children","instance","singletons","useValue"],"mappings":";AAAA,SAAqBA,uBAAuB,EAAEC,QAAQ,QAAQ,0BAA0B;AAOxF,oCAAoC;AACpC,6EAA6E;AAC7E,OAAO,MAAMC,oBAAoB,CAAgB,EAC7CC,OAAO,EACPC,QAAQ,EACgB;IACxB,MAAM,CAACC,SAAS,GAAGL,wBAAwBG;IAE3C,qBACI,KAACF;QAASK,YAAY;YAACD,WAAW;gBAAEF;gBAASI,UAAUF;YAAS,IAAIF;SAAQ;kBACvEC;;AAGb,EAAE"}
|
|
@@ -1,21 +0,0 @@
|
|
|
1
|
-
import { interfaces, useOptionalDependencies, Provider } from '@servicetitan/react-ioc';
|
|
2
|
-
|
|
3
|
-
interface SingletonProviderProps<T> {
|
|
4
|
-
provide: interfaces.Newable<T>;
|
|
5
|
-
children: JSX.Element;
|
|
6
|
-
}
|
|
7
|
-
|
|
8
|
-
// Re-use instance if already exists
|
|
9
|
-
// eslint-disable-next-line @typescript-eslint/no-unnecessary-type-constraint
|
|
10
|
-
export const SingletonProvider = <T extends any>({
|
|
11
|
-
provide,
|
|
12
|
-
children,
|
|
13
|
-
}: SingletonProviderProps<T>) => {
|
|
14
|
-
const [instance] = useOptionalDependencies(provide);
|
|
15
|
-
|
|
16
|
-
return (
|
|
17
|
-
<Provider singletons={[instance ? { provide, useValue: instance } : provide]}>
|
|
18
|
-
{children}
|
|
19
|
-
</Provider>
|
|
20
|
-
);
|
|
21
|
-
};
|