@brendanbank/atrium-host-bundle-utils 0.15.2 → 0.15.3
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/react/index.d.ts +45 -0
- package/dist/react/index.d.ts.map +1 -1
- package/dist/react/index.js +94 -1
- package/dist/react/index.js.map +1 -1
- package/package.json +2 -2
package/dist/react/index.d.ts
CHANGED
|
@@ -83,4 +83,49 @@ export declare function usePerm(): (code: string) => boolean;
|
|
|
83
83
|
/** Convenience: does the signed-in user hold the named role? Returns
|
|
84
84
|
* `false` while loading and when signed out, mirroring `usePerm`. */
|
|
85
85
|
export declare function useRole(code: string): boolean;
|
|
86
|
+
/** Snapshot of atrium's current router location, mirrored on
|
|
87
|
+
* `window.location`. The fields match react-router's `Location` shape
|
|
88
|
+
* so a host already familiar with `useLocation()` reads the same
|
|
89
|
+
* contract here. */
|
|
90
|
+
export type AtriumLocation = {
|
|
91
|
+
pathname: string;
|
|
92
|
+
search: string;
|
|
93
|
+
hash: string;
|
|
94
|
+
};
|
|
95
|
+
/** Subscribe to atrium's react-router location changes from inside a
|
|
96
|
+
* host bundle's React tree. Returns `{ pathname, search, hash }`
|
|
97
|
+
* mirroring `window.location`, and re-renders the calling component
|
|
98
|
+
* whenever atrium navigates — including in-place navigations
|
|
99
|
+
* (`navigate('/?focus=booking:42')` while already on `/`) where the
|
|
100
|
+
* host's wrapper element doesn't remount.
|
|
101
|
+
*
|
|
102
|
+
* Bridges the `atrium:locationchange` CustomEvent atrium dispatches
|
|
103
|
+
* on `window` through `useSyncExternalStore`, so multiple subscribers
|
|
104
|
+
* in the same tree share one event listener and the snapshot is
|
|
105
|
+
* referentially stable when nothing changed.
|
|
106
|
+
*
|
|
107
|
+
* ```tsx
|
|
108
|
+
* function FocusDrawer() {
|
|
109
|
+
* const { search } = useAtriumLocation();
|
|
110
|
+
* const focus = new URLSearchParams(search).get('focus');
|
|
111
|
+
* return focus ? <BookingDetail id={focus} /> : null;
|
|
112
|
+
* }
|
|
113
|
+
* ```
|
|
114
|
+
*
|
|
115
|
+
* Hosts that don't use React (or want to handle navigation outside a
|
|
116
|
+
* component) can subscribe directly:
|
|
117
|
+
* `window.addEventListener('atrium:locationchange', e => …)`. The
|
|
118
|
+
* event's `detail` carries the same `{pathname, search, hash}` shape.
|
|
119
|
+
*
|
|
120
|
+
* Available on atrium 0.15.3+. On older atrium images the hook still
|
|
121
|
+
* works but only reflects the initial `window.location` — the SPA
|
|
122
|
+
* doesn't dispatch the event, so in-place navigations won't trigger
|
|
123
|
+
* updates. Hosts that need to support pre-0.15.3 atrium can read
|
|
124
|
+
* `window.__ATRIUM_VERSION__` and fall back to `useLocation()` from a
|
|
125
|
+
* wrapper that remounts on route swaps. */
|
|
126
|
+
export declare function useAtriumLocation(): AtriumLocation;
|
|
127
|
+
/** Test-only: drop the cached snapshot so the next `getSnapshot` reads
|
|
128
|
+
* `window.location` fresh. Production code never calls this — the
|
|
129
|
+
* cache is updated by the event subscription. */
|
|
130
|
+
export declare function __resetAtriumLocationCacheForTests(): void;
|
|
86
131
|
//# sourceMappingURL=index.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/react/index.ts"],"names":[],"mappings":"AAGA;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,OAAO,
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/react/index.ts"],"names":[],"mappings":"AAGA;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,OAAO,EAOL,KAAK,SAAS,EACf,MAAM,OAAO,CAAC;AACf,OAAO,EAGL,KAAK,WAAW,EAChB,KAAK,cAAc,EACpB,MAAM,uBAAuB,CAAC;AAE/B,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,gCAAgC,CAAC;AAElE,YAAY,EAAE,WAAW,EAAE,MAAM,gCAAgC,CAAC;AAClE,OAAO,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AAEvC,UAAU,kBAAkB;IAC1B,gBAAgB,EAAE,MAAM,OAAO,CAAC,WAAW,GAAG,IAAI,CAAC,CAAC;CACrD;AAmBD,MAAM,WAAW,mBAAmB;IAClC;;;kDAG8C;IAC9C,MAAM,CAAC,EAAE,WAAW,CAAC;IACrB;;;sBAGkB;IAClB,gBAAgB,CAAC,EAAE,MAAM,OAAO,CAAC,WAAW,GAAG,IAAI,CAAC,CAAC;IACrD,QAAQ,EAAE,SAAS,CAAC;CACrB;AAED;;;qCAGqC;AACrC,wBAAgB,cAAc,CAAC,EAC7B,MAAM,EACN,gBAAgB,EAChB,QAAQ,GACT,EAAE,mBAAmB,2MAYrB;AAED;;iEAEiE;AACjE,eAAO,MAAM,YAAY,2BAA4B,CAAC;AAmBtD;;;;;;;;8BAQ8B;AAC9B,wBAAgB,KAAK,IAAI,cAAc,CAAC,WAAW,GAAG,IAAI,CAAC,CAQ1D;AAED;;iBAEiB;AACjB,wBAAgB,cAAc,IAAI,cAAc,CAAC,WAAW,GAAG,IAAI,CAAC,CAEnE;AAED;;;;;;;;;;;;;;;GAeG;AACH,wBAAgB,OAAO,IAAI,CAAC,IAAI,EAAE,MAAM,KAAK,OAAO,CAMnD;AAED;sEACsE;AACtE,wBAAgB,OAAO,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAG7C;AAED;;;qBAGqB;AACrB,MAAM,MAAM,cAAc,GAAG;IAC3B,QAAQ,EAAE,MAAM,CAAC;IACjB,MAAM,EAAE,MAAM,CAAC;IACf,IAAI,EAAE,MAAM,CAAC;CACd,CAAC;AA4DF;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;4CA8B4C;AAC5C,wBAAgB,iBAAiB,IAAI,cAAc,CAMlD;AAED;;kDAEkD;AAClD,wBAAgB,kCAAkC,IAAI,IAAI,CAEzD"}
|
package/dist/react/index.js
CHANGED
|
@@ -21,7 +21,7 @@
|
|
|
21
21
|
* intended state — atrium clears its cache on logout via `qc.clear()`,
|
|
22
22
|
* and a shared client would lose host queries the user still wants.
|
|
23
23
|
*/
|
|
24
|
-
import { createContext, createElement, useCallback, useContext, useMemo, } from 'react';
|
|
24
|
+
import { createContext, createElement, useCallback, useContext, useMemo, useSyncExternalStore, } from 'react';
|
|
25
25
|
import { QueryClientProvider, useQuery, } from '@tanstack/react-query';
|
|
26
26
|
export { __atrium_t__ } from '../i18n';
|
|
27
27
|
const ME_CONTEXT_PATH = '/users/me/context';
|
|
@@ -120,4 +120,97 @@ export function useRole(code) {
|
|
|
120
120
|
const { data: me } = useMe();
|
|
121
121
|
return (me?.roles ?? []).includes(code);
|
|
122
122
|
}
|
|
123
|
+
const ATRIUM_LOCATION_EVENT = 'atrium:locationchange';
|
|
124
|
+
const SSR_LOCATION = {
|
|
125
|
+
pathname: '/',
|
|
126
|
+
search: '',
|
|
127
|
+
hash: '',
|
|
128
|
+
};
|
|
129
|
+
// Module-level cache so `useSyncExternalStore.getSnapshot` returns a
|
|
130
|
+
// referentially-stable object across renders — re-creating it every
|
|
131
|
+
// call would cause React to tear-loop the subscriber. The cache is
|
|
132
|
+
// refreshed only when an `atrium:locationchange` event lands or, on
|
|
133
|
+
// the first read, lazily from `window.location`.
|
|
134
|
+
let cachedLocation = null;
|
|
135
|
+
function readWindowLocation() {
|
|
136
|
+
if (typeof window === 'undefined')
|
|
137
|
+
return SSR_LOCATION;
|
|
138
|
+
return {
|
|
139
|
+
pathname: window.location.pathname,
|
|
140
|
+
search: window.location.search,
|
|
141
|
+
hash: window.location.hash,
|
|
142
|
+
};
|
|
143
|
+
}
|
|
144
|
+
function getLocationSnapshot() {
|
|
145
|
+
if (cachedLocation === null)
|
|
146
|
+
cachedLocation = readWindowLocation();
|
|
147
|
+
return cachedLocation;
|
|
148
|
+
}
|
|
149
|
+
function getServerLocationSnapshot() {
|
|
150
|
+
return SSR_LOCATION;
|
|
151
|
+
}
|
|
152
|
+
function subscribeLocation(onChange) {
|
|
153
|
+
if (typeof window === 'undefined')
|
|
154
|
+
return () => { };
|
|
155
|
+
const handler = (e) => {
|
|
156
|
+
const detail = e
|
|
157
|
+
.detail;
|
|
158
|
+
if (detail &&
|
|
159
|
+
typeof detail.pathname === 'string' &&
|
|
160
|
+
typeof detail.search === 'string' &&
|
|
161
|
+
typeof detail.hash === 'string') {
|
|
162
|
+
cachedLocation = {
|
|
163
|
+
pathname: detail.pathname,
|
|
164
|
+
search: detail.search,
|
|
165
|
+
hash: detail.hash,
|
|
166
|
+
};
|
|
167
|
+
}
|
|
168
|
+
else {
|
|
169
|
+
cachedLocation = readWindowLocation();
|
|
170
|
+
}
|
|
171
|
+
onChange();
|
|
172
|
+
};
|
|
173
|
+
window.addEventListener(ATRIUM_LOCATION_EVENT, handler);
|
|
174
|
+
return () => window.removeEventListener(ATRIUM_LOCATION_EVENT, handler);
|
|
175
|
+
}
|
|
176
|
+
/** Subscribe to atrium's react-router location changes from inside a
|
|
177
|
+
* host bundle's React tree. Returns `{ pathname, search, hash }`
|
|
178
|
+
* mirroring `window.location`, and re-renders the calling component
|
|
179
|
+
* whenever atrium navigates — including in-place navigations
|
|
180
|
+
* (`navigate('/?focus=booking:42')` while already on `/`) where the
|
|
181
|
+
* host's wrapper element doesn't remount.
|
|
182
|
+
*
|
|
183
|
+
* Bridges the `atrium:locationchange` CustomEvent atrium dispatches
|
|
184
|
+
* on `window` through `useSyncExternalStore`, so multiple subscribers
|
|
185
|
+
* in the same tree share one event listener and the snapshot is
|
|
186
|
+
* referentially stable when nothing changed.
|
|
187
|
+
*
|
|
188
|
+
* ```tsx
|
|
189
|
+
* function FocusDrawer() {
|
|
190
|
+
* const { search } = useAtriumLocation();
|
|
191
|
+
* const focus = new URLSearchParams(search).get('focus');
|
|
192
|
+
* return focus ? <BookingDetail id={focus} /> : null;
|
|
193
|
+
* }
|
|
194
|
+
* ```
|
|
195
|
+
*
|
|
196
|
+
* Hosts that don't use React (or want to handle navigation outside a
|
|
197
|
+
* component) can subscribe directly:
|
|
198
|
+
* `window.addEventListener('atrium:locationchange', e => …)`. The
|
|
199
|
+
* event's `detail` carries the same `{pathname, search, hash}` shape.
|
|
200
|
+
*
|
|
201
|
+
* Available on atrium 0.15.3+. On older atrium images the hook still
|
|
202
|
+
* works but only reflects the initial `window.location` — the SPA
|
|
203
|
+
* doesn't dispatch the event, so in-place navigations won't trigger
|
|
204
|
+
* updates. Hosts that need to support pre-0.15.3 atrium can read
|
|
205
|
+
* `window.__ATRIUM_VERSION__` and fall back to `useLocation()` from a
|
|
206
|
+
* wrapper that remounts on route swaps. */
|
|
207
|
+
export function useAtriumLocation() {
|
|
208
|
+
return useSyncExternalStore(subscribeLocation, getLocationSnapshot, getServerLocationSnapshot);
|
|
209
|
+
}
|
|
210
|
+
/** Test-only: drop the cached snapshot so the next `getSnapshot` reads
|
|
211
|
+
* `window.location` fresh. Production code never calls this — the
|
|
212
|
+
* cache is updated by the event subscription. */
|
|
213
|
+
export function __resetAtriumLocationCacheForTests() {
|
|
214
|
+
cachedLocation = null;
|
|
215
|
+
}
|
|
123
216
|
//# sourceMappingURL=index.js.map
|
package/dist/react/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/react/index.ts"],"names":[],"mappings":"AAAA,kCAAkC;AAClC,wCAAwC;AAExC;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,OAAO,EACL,aAAa,EACb,aAAa,EACb,WAAW,EACX,UAAU,EACV,OAAO,
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/react/index.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@brendanbank/atrium-host-bundle-utils",
|
|
3
|
-
"version": "0.15.
|
|
3
|
+
"version": "0.15.3",
|
|
4
4
|
"description": "Runtime helpers, Vite preset, and React hooks for atrium host bundles. Wraps the dual-tree mount pattern, the host-bundle Vite library config, and the /users/me/context hook so a host's main.tsx is ~10 lines of registration calls.",
|
|
5
5
|
"license": "BSD-2-Clause",
|
|
6
6
|
"type": "module",
|
|
@@ -25,7 +25,7 @@
|
|
|
25
25
|
}
|
|
26
26
|
},
|
|
27
27
|
"dependencies": {
|
|
28
|
-
"@brendanbank/atrium-host-types": "0.15.
|
|
28
|
+
"@brendanbank/atrium-host-types": "0.15.3"
|
|
29
29
|
},
|
|
30
30
|
"peerDependencies": {
|
|
31
31
|
"@tanstack/react-query": "^5.0.0",
|