@servicetitan/hash-browser-router 32.6.0 → 33.0.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.
@@ -0,0 +1,3 @@
1
+ import { BrowserHistoryBuildOptions, History } from 'history';
2
+ export declare function createHashBrowserHistory(options: BrowserHistoryBuildOptions): History;
3
+ //# sourceMappingURL=create-hash-browser-history.d.ts.map
@@ -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":"AAOA,OAAO,EAAU,EAAE,EAAa,MAAM,OAAO,CAAC;AAC9C,OAAO,EAAE,kBAAkB,EAAU,MAAM,kBAAkB,CAAC;AA8B9D,eAAO,MAAM,iBAAiB,EAAE,EAAE,CAAC,kBAAkB,CAIpD,CAAC"}
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 { createBrowserHistory } from 'history';
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 { SingletonProvider } from './singleton-provider';
8
- function useHistory(options) {
9
- const history = useRef(createHashBrowserHistory(options)).current;
10
- const [historyManager] = useDependencies(HistoryManager);
11
- useEffect(()=>{
12
- historyManager.register(history);
13
- return ()=>{
14
- historyManager.unregister(history);
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
- children: children
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 {\n BrowserHistoryBuildOptions,\n History,\n Location,\n LocationState,\n createBrowserHistory,\n} from 'history';\nimport { useRef, FC, useEffect } from 'react';\nimport { BrowserRouterProps, Router } from 'react-router-dom';\n\nimport { useDependencies } from '@servicetitan/react-ioc';\nimport { HistoryManager } from '@servicetitan/web-components';\n\nimport { SingletonProvider } from './singleton-provider';\n\nfunction 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\nconst HashBrowserRouterUnwrapped: FC<BrowserRouterProps> = props => {\n const history = useHistory(props);\n const { children } = props;\n\n return <Router history={history}>{children}</Router>;\n};\n\nexport const HashBrowserRouter: FC<BrowserRouterProps> = props => (\n <SingletonProvider provide={HistoryManager}>\n <HashBrowserRouterUnwrapped {...props} />\n </SingletonProvider>\n);\n\nfunction createHashBrowserHistory({\n basename = '',\n ...props\n}: BrowserHistoryBuildOptions): History {\n function convertLocationToHashRouterView(l: Location): Location {\n let search = '';\n let pathname = l.hash ? l.hash.substring(1) : '/';\n if (basename) {\n pathname = stripBasename(pathname, basename);\n }\n const index = pathname.indexOf('?');\n if (index !== -1) {\n search = pathname.substring(index);\n pathname = pathname.substring(0, index);\n }\n return {\n ...l,\n search,\n pathname,\n hash: '',\n };\n }\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 {\n if (path.hash) {\n parent.push(path);\n } else {\n parent.push({\n ...path,\n pathname: '/',\n hash: path.pathname !== undefined ? basename + path.pathname : undefined,\n });\n }\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 {\n if (path.hash) {\n parent.replace(path);\n } else {\n parent.replace({\n ...path,\n pathname: '/',\n hash: path.pathname !== undefined ? basename + path.pathname : undefined,\n });\n }\n }\n\n triggerSammyLocationChange();\n },\n\n block: prompt => {\n if (typeof prompt === 'function') {\n return parent.block((origLocation, action) => {\n return prompt(convertLocationToHashRouterView(origLocation), action);\n });\n }\n\n return parent.block(prompt);\n },\n\n listen: listener => {\n return parent.listen((origLocation, action) => {\n listener(convertLocationToHashRouterView(origLocation), action);\n });\n },\n\n get location() {\n return convertLocationToHashRouterView(parent.location);\n },\n set location(l) {\n parent.location = l;\n },\n };\n\n return Object.setPrototypeOf(history, parent);\n}\n\nfunction hasBasename(path: string, prefix: string) {\n return (\n path.toLowerCase().indexOf(prefix.toLowerCase()) === 0 &&\n '/?#'.indexOf(path.charAt(prefix.length)) !== -1\n );\n}\n\nfunction stripBasename(path: string, prefix: string) {\n return hasBasename(path, prefix) ? path.substring(prefix.length) : path;\n}\n\nfunction 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":["createBrowserHistory","useRef","useEffect","Router","useDependencies","HistoryManager","SingletonProvider","useHistory","options","history","createHashBrowserHistory","current","historyManager","register","unregister","HashBrowserRouterUnwrapped","props","children","HashBrowserRouter","provide","basename","convertLocationToHashRouterView","l","search","pathname","hash","substring","stripBasename","index","indexOf","parent","createHref","location","push","path","state","startsWith","undefined","triggerSammyLocationChange","replace","block","prompt","origLocation","action","listen","listener","Object","setPrototypeOf","hasBasename","prefix","toLowerCase","charAt","length","setTimeout","window","dispatchEvent","HashChangeEvent"],"mappings":"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"}
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,2 @@
1
+ export declare function triggerSammyLocationChange(): void;
2
+ //# sourceMappingURL=trigger-sammy-location-change.d.ts.map
@@ -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,3 @@
1
+ import { BrowserHistoryBuildOptions } from 'history';
2
+ export declare function useHistory(options: BrowserHistoryBuildOptions): import("history").History<unknown>;
3
+ //# sourceMappingURL=use-history.d.ts.map
@@ -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.6.0",
3
+ "version": "33.0.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.6.0",
19
- "@servicetitan/web-components": "32.6.0",
18
+ "@servicetitan/react-ioc": "33.0.0",
19
+ "@servicetitan/web-components": "33.0.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.6.0",
31
- "@servicetitan/web-components": "32.6.0",
30
+ "@servicetitan/react-ioc": "33.0.0",
31
+ "@servicetitan/web-components": "33.0.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": "c771c468d179a828a75b0316bb9b01f311d13591"
42
+ "gitHead": "31ea85a4348eec3402ac60008c9c2944d34bdbb2"
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: () => ({ pathname: location, search: '', hash: '' }),
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: () => ({ pathname: `${location.replace('/#', '')}`, search: '', hash: '' }),
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: () => ({ pathname: location, search: '', hash: '' }),
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' })); // testing pathname with search params
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: `${locationObj.pathname!.match(/^([^?]+)/)![0]}`,
115
- search: `${locationObj.pathname!.match(/(\?.+)$/)![0]}`,
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: `${locationObj.pathname!.match(/^([^?]+)/)![0]}`,
140
- search: `${locationObj.pathname!.match(/(\?.+)$/)![0]}`,
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
- import { SingletonProvider } from './singleton-provider';
15
-
16
- function useHistory(options: BrowserHistoryBuildOptions) {
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
- const { children } = props;
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
- };